2023-10-23 13:20:49

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 00/10] Remove obsolete and orphaned wifi drivers

From: Arnd Bergmann <[email protected]>

As discussed previously, a lot of the older wifi drivers are likely
entirely unused, Though we can't know for sure.

As suggested by both Greg and Jakub, let's remove the ones that look
are most likely to have no users left and also get in the way of the
wext cleanup. If anyone is still using any of these, we can revert the
driver removal individually.

I would suggest merging these for net-next after 6.7-rc1 is out, to give
them the maximum amount of time for users to speak up before a release
comes out.

This kills off all pcmcia wifi drivers, and all wext users in
drivers/net/wireless, but not the ps3-gelic-wireless driver in
drivers/net/ethernet, or the staging drivers.

In staging, rtl8192u was already removed in the meantime, while rtl8712
and rtl8192e are apparently still used. I have not been able to find
out whether ks7010 is still in use.

Arnd

Link: https://lore.kernel.org/lkml/[email protected]/


Arnd Bergmann (10):
wifi: libertas: drop 16-bit PCMCIA support
wifi: atmel: remove wext style at76c50x drivers
wifi: remove orphaned cisco/aironet driver
wifi: remove obsolete hostap driver
wifi: remove orphaned zd1201 driver
wifi: remove orphaned orinoco driver
wifi: remove orphaned ray_cs driver
wifi: remove orphaned wl3501 driver
wifi: remove orphaned rndis_wlan driver
[RFC] wifi: remove ipw2100/ipw2200 drivers

.../networking/device_drivers/wifi/index.rst | 20 -
.../device_drivers/wifi/intel/ipw2100.rst | 323 -
.../device_drivers/wifi/intel/ipw2200.rst | 526 -
.../networking/device_drivers/wifi/ray_cs.rst | 165 -
MAINTAINERS | 49 -
drivers/net/wireless/Kconfig | 3 -
drivers/net/wireless/Makefile | 2 -
drivers/net/wireless/atmel/Kconfig | 35 -
drivers/net/wireless/atmel/Makefile | 4 -
drivers/net/wireless/atmel/atmel.c | 4452 ------
drivers/net/wireless/atmel/atmel.h | 31 -
drivers/net/wireless/atmel/atmel_cs.c | 292 -
drivers/net/wireless/atmel/atmel_pci.c | 65 -
drivers/net/wireless/cisco/Kconfig | 59 -
drivers/net/wireless/cisco/Makefile | 3 -
drivers/net/wireless/cisco/airo.c | 8288 -----------
drivers/net/wireless/cisco/airo.h | 10 -
drivers/net/wireless/cisco/airo_cs.c | 218 -
drivers/net/wireless/intel/Kconfig | 1 -
drivers/net/wireless/intel/Makefile | 3 -
drivers/net/wireless/intel/ipw2x00/Kconfig | 195 -
drivers/net/wireless/intel/ipw2x00/Makefile | 15 -
drivers/net/wireless/intel/ipw2x00/ipw.h | 20 -
drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8587 -----------
drivers/net/wireless/intel/ipw2x00/ipw2100.h | 1142 --
drivers/net/wireless/intel/ipw2x00/ipw2200.c | 11965 ----------------
drivers/net/wireless/intel/ipw2x00/ipw2200.h | 1984 ---
drivers/net/wireless/intel/ipw2x00/libipw.h | 1001 --
.../net/wireless/intel/ipw2x00/libipw_geo.c | 179 -
.../wireless/intel/ipw2x00/libipw_module.c | 297 -
.../net/wireless/intel/ipw2x00/libipw_rx.c | 1737 ---
.../net/wireless/intel/ipw2x00/libipw_tx.c | 519 -
.../net/wireless/intel/ipw2x00/libipw_wx.c | 726 -
drivers/net/wireless/intersil/Kconfig | 2 -
drivers/net/wireless/intersil/Makefile | 2 -
drivers/net/wireless/intersil/hostap/Kconfig | 95 -
drivers/net/wireless/intersil/hostap/Makefile | 8 -
drivers/net/wireless/intersil/hostap/hostap.h | 98 -
.../wireless/intersil/hostap/hostap_80211.h | 97 -
.../intersil/hostap/hostap_80211_rx.c | 1116 --
.../intersil/hostap/hostap_80211_tx.c | 554 -
.../net/wireless/intersil/hostap/hostap_ap.c | 3277 -----
.../net/wireless/intersil/hostap/hostap_ap.h | 264 -
.../wireless/intersil/hostap/hostap_common.h | 420 -
.../wireless/intersil/hostap/hostap_config.h | 49 -
.../net/wireless/intersil/hostap/hostap_cs.c | 710 -
.../intersil/hostap/hostap_download.c | 810 --
.../net/wireless/intersil/hostap/hostap_hw.c | 3387 -----
.../wireless/intersil/hostap/hostap_info.c | 509 -
.../wireless/intersil/hostap/hostap_ioctl.c | 3847 -----
.../wireless/intersil/hostap/hostap_main.c | 1123 --
.../net/wireless/intersil/hostap/hostap_pci.c | 445 -
.../net/wireless/intersil/hostap/hostap_plx.c | 617 -
.../wireless/intersil/hostap/hostap_proc.c | 411 -
.../wireless/intersil/hostap/hostap_wlan.h | 1051 --
drivers/net/wireless/intersil/orinoco/Kconfig | 143 -
.../net/wireless/intersil/orinoco/Makefile | 15 -
.../net/wireless/intersil/orinoco/airport.c | 268 -
drivers/net/wireless/intersil/orinoco/cfg.c | 291 -
drivers/net/wireless/intersil/orinoco/cfg.h | 15 -
drivers/net/wireless/intersil/orinoco/fw.c | 387 -
drivers/net/wireless/intersil/orinoco/fw.h | 21 -
.../net/wireless/intersil/orinoco/hermes.c | 778 -
.../net/wireless/intersil/orinoco/hermes.h | 534 -
.../wireless/intersil/orinoco/hermes_dld.c | 477 -
.../wireless/intersil/orinoco/hermes_dld.h | 52 -
.../wireless/intersil/orinoco/hermes_rid.h | 165 -
drivers/net/wireless/intersil/orinoco/hw.c | 1362 --
drivers/net/wireless/intersil/orinoco/hw.h | 60 -
drivers/net/wireless/intersil/orinoco/main.c | 2414 ----
drivers/net/wireless/intersil/orinoco/main.h | 50 -
drivers/net/wireless/intersil/orinoco/mic.c | 89 -
drivers/net/wireless/intersil/orinoco/mic.h | 23 -
.../net/wireless/intersil/orinoco/orinoco.h | 251 -
.../wireless/intersil/orinoco/orinoco_cs.c | 350 -
.../intersil/orinoco/orinoco_nortel.c | 314 -
.../wireless/intersil/orinoco/orinoco_pci.c | 257 -
.../wireless/intersil/orinoco/orinoco_pci.h | 54 -
.../wireless/intersil/orinoco/orinoco_plx.c | 362 -
.../wireless/intersil/orinoco/orinoco_tmd.c | 237 -
.../wireless/intersil/orinoco/orinoco_usb.c | 1787 ---
drivers/net/wireless/intersil/orinoco/scan.c | 259 -
drivers/net/wireless/intersil/orinoco/scan.h | 21 -
.../wireless/intersil/orinoco/spectrum_cs.c | 328 -
drivers/net/wireless/intersil/orinoco/wext.c | 1428 --
drivers/net/wireless/intersil/orinoco/wext.h | 13 -
drivers/net/wireless/legacy/Kconfig | 55 -
drivers/net/wireless/legacy/Makefile | 6 -
drivers/net/wireless/legacy/ray_cs.c | 2824 ----
drivers/net/wireless/legacy/ray_cs.h | 74 -
drivers/net/wireless/legacy/rayctl.h | 734 -
drivers/net/wireless/legacy/rndis_wlan.c | 3760 -----
drivers/net/wireless/legacy/wl3501.h | 615 -
drivers/net/wireless/legacy/wl3501_cs.c | 2036 ---
drivers/net/wireless/marvell/libertas/Kconfig | 7 +-
.../net/wireless/marvell/libertas/Makefile | 1 -
drivers/net/wireless/marvell/libertas/if_cs.c | 957 --
drivers/net/wireless/zydas/Kconfig | 19 -
drivers/net/wireless/zydas/Makefile | 2 -
drivers/net/wireless/zydas/zd1201.c | 1909 ---
drivers/net/wireless/zydas/zd1201.h | 144 -
101 files changed, 1 insertion(+), 87755 deletions(-)
delete mode 100644 Documentation/networking/device_drivers/wifi/index.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/ray_cs.rst
delete mode 100644 drivers/net/wireless/atmel/atmel.c
delete mode 100644 drivers/net/wireless/atmel/atmel.h
delete mode 100644 drivers/net/wireless/atmel/atmel_cs.c
delete mode 100644 drivers/net/wireless/atmel/atmel_pci.c
delete mode 100644 drivers/net/wireless/cisco/Kconfig
delete mode 100644 drivers/net/wireless/cisco/Makefile
delete mode 100644 drivers/net/wireless/cisco/airo.c
delete mode 100644 drivers/net/wireless/cisco/airo.h
delete mode 100644 drivers/net/wireless/cisco/airo_cs.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Kconfig
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Makefile
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_geo.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_module.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_rx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_tx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_wx.c
delete mode 100644 drivers/net/wireless/intersil/hostap/Kconfig
delete mode 100644 drivers/net/wireless/intersil/hostap/Makefile
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ap.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ap.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_common.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_config.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_cs.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_download.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_hw.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_info.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ioctl.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_main.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_pci.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_plx.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_proc.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_wlan.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/Kconfig
delete mode 100644 drivers/net/wireless/intersil/orinoco/Makefile
delete mode 100644 drivers/net/wireless/intersil/orinoco/airport.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/cfg.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/cfg.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/fw.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/fw.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_dld.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_dld.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_rid.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hw.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/hw.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/main.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/main.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/mic.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/mic.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_cs.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_nortel.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_pci.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_pci.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_plx.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_tmd.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_usb.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/scan.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/scan.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/spectrum_cs.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/wext.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/wext.h
delete mode 100644 drivers/net/wireless/legacy/Kconfig
delete mode 100644 drivers/net/wireless/legacy/Makefile
delete mode 100644 drivers/net/wireless/legacy/ray_cs.c
delete mode 100644 drivers/net/wireless/legacy/ray_cs.h
delete mode 100644 drivers/net/wireless/legacy/rayctl.h
delete mode 100644 drivers/net/wireless/legacy/rndis_wlan.c
delete mode 100644 drivers/net/wireless/legacy/wl3501.h
delete mode 100644 drivers/net/wireless/legacy/wl3501_cs.c
delete mode 100644 drivers/net/wireless/marvell/libertas/if_cs.c
delete mode 100644 drivers/net/wireless/zydas/zd1201.c
delete mode 100644 drivers/net/wireless/zydas/zd1201.h

--
2.39.2

Cc: "David S . Miller" <[email protected]>,
Cc: Alexandre Belloni <[email protected]>,
Cc: Arnd Bergmann <[email protected]>
Cc: Claudiu Beznea <[email protected]>,
Cc: Geert Uytterhoeven <[email protected]>
Cc: Geoff Levand <[email protected]>,
Cc: Greg Kroah-Hartman <[email protected]>,
Cc: Jakub Kicinski <[email protected]>,
Cc: Jeff Johnson <[email protected]>
Cc: Johannes Berg <[email protected]>,
Cc: Kalle Valo <[email protected]>
Cc: Larry Finger <[email protected]>,
Cc: Nicolas Ferre <[email protected]>,
Cc: Pavel Machek <[email protected]>,
Cc: Stanislaw Gruszka <[email protected]>
Cc: Gregory Greenman <[email protected]>
Cc: linuxppc-dev <[email protected]>
Cc: <[email protected]>,
Cc: <[email protected]>
Cc: <[email protected]>,
Cc: <[email protected]>,


2023-10-23 13:21:43

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 04/10] wifi: remove obsolete hostap driver

From: Arnd Bergmann <[email protected]>

HostAP is an ISA/PCMCIA style 802.11b driver supporting only
wireless extensions, and some custom ioctls (already removed).
Some devices include a legacy PCI bridge but no DMA.

The driver was marked obsolete in 2016 and is highly unlikely
to still have any users.

Signed-off-by: Arnd Bergmann <[email protected]>
---
MAINTAINERS | 5 -
drivers/net/wireless/intersil/Kconfig | 1 -
drivers/net/wireless/intersil/Makefile | 1 -
drivers/net/wireless/intersil/hostap/Kconfig | 95 -
drivers/net/wireless/intersil/hostap/Makefile | 8 -
drivers/net/wireless/intersil/hostap/hostap.h | 99 -
.../wireless/intersil/hostap/hostap_80211.h | 97 -
.../intersil/hostap/hostap_80211_rx.c | 1116 -----
.../intersil/hostap/hostap_80211_tx.c | 554 ---
.../net/wireless/intersil/hostap/hostap_ap.c | 3277 -------------
.../net/wireless/intersil/hostap/hostap_ap.h | 264 --
.../wireless/intersil/hostap/hostap_common.h | 420 --
.../wireless/intersil/hostap/hostap_config.h | 49 -
.../net/wireless/intersil/hostap/hostap_cs.c | 710 ---
.../intersil/hostap/hostap_download.c | 811 ----
.../net/wireless/intersil/hostap/hostap_hw.c | 3387 --------------
.../wireless/intersil/hostap/hostap_info.c | 509 --
.../wireless/intersil/hostap/hostap_ioctl.c | 4075 -----------------
.../wireless/intersil/hostap/hostap_main.c | 1126 -----
.../net/wireless/intersil/hostap/hostap_pci.c | 445 --
.../net/wireless/intersil/hostap/hostap_plx.c | 617 ---
.../wireless/intersil/hostap/hostap_proc.c | 411 --
.../wireless/intersil/hostap/hostap_wlan.h | 1051 -----
23 files changed, 19128 deletions(-)
delete mode 100644 drivers/net/wireless/intersil/hostap/Kconfig
delete mode 100644 drivers/net/wireless/intersil/hostap/Makefile
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ap.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ap.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_common.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_config.h
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_cs.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_download.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_hw.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_info.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_ioctl.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_main.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_pci.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_plx.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_proc.c
delete mode 100644 drivers/net/wireless/intersil/hostap/hostap_wlan.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 6ee0318468f41..78fa9932ba28f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9521,11 +9521,6 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml
F: drivers/iio/pressure/mprls0025pa.c

-HOST AP DRIVER
-L: [email protected]
-S: Obsolete
-F: drivers/net/wireless/intersil/hostap/
-
HP BIOSCFG DRIVER
M: Jorge Lopez <[email protected]>
L: [email protected]
diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig
index bd6bf70ece03d..f2455ef45d995 100644
--- a/drivers/net/wireless/intersil/Kconfig
+++ b/drivers/net/wireless/intersil/Kconfig
@@ -12,7 +12,6 @@ config WLAN_VENDOR_INTERSIL

if WLAN_VENDOR_INTERSIL

-source "drivers/net/wireless/intersil/hostap/Kconfig"
source "drivers/net/wireless/intersil/orinoco/Kconfig"
source "drivers/net/wireless/intersil/p54/Kconfig"

diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile
index 65281d1b3d852..773147110c54e 100644
--- a/drivers/net/wireless/intersil/Makefile
+++ b/drivers/net/wireless/intersil/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_HERMES) += orinoco/
obj-$(CONFIG_P54_COMMON) += p54/
diff --git a/drivers/net/wireless/intersil/hostap/Kconfig b/drivers/net/wireless/intersil/hostap/Kconfig
deleted file mode 100644
index 2edff8efbcbb1..0000000000000
--- a/drivers/net/wireless/intersil/hostap/Kconfig
+++ /dev/null
@@ -1,95 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config HOSTAP
- tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)"
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select CRYPTO
- select CRYPTO_MICHAEL_MIC
- select CRC32
- select LIB80211
- select LIB80211_CRYPT_WEP
- select LIB80211_CRYPT_TKIP
- select LIB80211_CRYPT_CCMP
- help
- Shared driver code for IEEE 802.11b wireless cards based on
- Intersil Prism2/2.5/3 chipset. This driver supports so called
- Host AP mode that allows the card to act as an IEEE 802.11
- access point.
-
- See <http://hostap.epitest.fi/> for more information about the
- Host AP driver configuration and tools. This site includes
- information and tools (hostapd and wpa_supplicant) for WPA/WPA2
- support.
-
- This option includes the base Host AP driver code that is shared by
- different hardware models. You will also need to enable support for
- PLX/PCI/CS version of the driver to actually use the driver.
-
- The driver can be compiled as a module and it will be called
- hostap.
-
-config HOSTAP_FIRMWARE
- bool "Support downloading firmware images with Host AP driver"
- depends on HOSTAP
- help
- Configure Host AP driver to include support for firmware image
- download. This option by itself only enables downloading to the
- volatile memory, i.e. the card RAM. This option is required to
- support cards that don't have firmware in flash, such as D-Link
- DWL-520 rev E and D-Link DWL-650 rev P.
-
- Firmware image downloading needs a user space tool, prism2_srec.
- It is available from http://hostap.epitest.fi/.
-
-config HOSTAP_FIRMWARE_NVRAM
- bool "Support for non-volatile firmware download"
- depends on HOSTAP_FIRMWARE
- help
- Allow Host AP driver to write firmware images to the non-volatile
- card memory, i.e. flash memory that survives power cycling.
- Enable this option if you want to be able to change card firmware
- permanently.
-
- Firmware image downloading needs a user space tool, prism2_srec.
- It is available from http://hostap.epitest.fi/.
-
-config HOSTAP_PLX
- tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors"
- depends on PCI && HOSTAP && HAS_IOPORT
- help
- Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based
- PCI adaptors.
-
- "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
- driver and its help text includes more information about the Host AP
- driver.
-
- The driver can be compiled as a module and will be named
- hostap_plx.
-
-config HOSTAP_PCI
- tristate "Host AP driver for Prism2.5 PCI adaptors"
- depends on PCI && HOSTAP
- help
- Host AP driver's version for Prism2.5 PCI adaptors.
-
- "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
- driver and its help text includes more information about the Host AP
- driver.
-
- The driver can be compiled as a module and will be named
- hostap_pci.
-
-config HOSTAP_CS
- tristate "Host AP driver for Prism2/2.5/3 PC Cards"
- depends on PCMCIA && HOSTAP
- help
- Host AP driver's version for Prism2/2.5/3 PC Cards.
-
- "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this
- driver and its help text includes more information about the Host AP
- driver.
-
- The driver can be compiled as a module and will be named
- hostap_cs.
diff --git a/drivers/net/wireless/intersil/hostap/Makefile b/drivers/net/wireless/intersil/hostap/Makefile
deleted file mode 100644
index ae3bb73b2d99d..0000000000000
--- a/drivers/net/wireless/intersil/hostap/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \
- hostap_ioctl.o hostap_main.o hostap_proc.o
-obj-$(CONFIG_HOSTAP) += hostap.o
-
-obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o
-obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o
-obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o
diff --git a/drivers/net/wireless/intersil/hostap/hostap.h b/drivers/net/wireless/intersil/hostap/hostap.h
deleted file mode 100644
index c17ab6dbbb538..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_H
-#define HOSTAP_H
-
-#include <linux/ethtool.h>
-#include <linux/kernel.h>
-
-#include "hostap_wlan.h"
-#include "hostap_ap.h"
-
-static const long __maybe_unused freq_list[] = {
- 2412, 2417, 2422, 2427, 2432, 2437, 2442,
- 2447, 2452, 2457, 2462, 2467, 2472, 2484
-};
-#define FREQ_COUNT ARRAY_SIZE(freq_list)
-
-/* hostap.c */
-
-extern struct proc_dir_entry *hostap_proc;
-
-u16 hostap_tx_callback_register(local_info_t *local,
- void (*func)(struct sk_buff *, int ok, void *),
- void *data);
-int hostap_tx_callback_unregister(local_info_t *local, u16 idx);
-int hostap_set_word(struct net_device *dev, int rid, u16 val);
-int hostap_set_string(struct net_device *dev, int rid, const char *val);
-u16 hostap_get_porttype(local_info_t *local);
-int hostap_set_encryption(local_info_t *local);
-int hostap_set_antsel(local_info_t *local);
-int hostap_set_roaming(local_info_t *local);
-int hostap_set_auth_algs(local_info_t *local);
-void hostap_dump_rx_header(const char *name,
- const struct hfa384x_rx_frame *rx);
-void hostap_dump_tx_header(const char *name,
- const struct hfa384x_tx_frame *tx);
-extern const struct header_ops hostap_80211_ops;
-int hostap_80211_get_hdrlen(__le16 fc);
-struct net_device_stats *hostap_get_stats(struct net_device *dev);
-void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int type);
-void hostap_set_multicast_list_queue(struct work_struct *work);
-int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
-int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
-void hostap_cleanup(local_info_t *local);
-void hostap_cleanup_handler(void *data);
-struct net_device * hostap_add_interface(struct local_info *local,
- int type, int rtnl_locked,
- const char *prefix, const char *name);
-void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
- int remove_from_list);
-int prism2_update_comms_qual(struct net_device *dev);
-int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
- u8 *body, size_t bodylen);
-int prism2_sta_deauth(local_info_t *local, u16 reason);
-int prism2_wds_add(local_info_t *local, u8 *remote_addr,
- int rtnl_locked);
-int prism2_wds_del(local_info_t *local, u8 *remote_addr,
- int rtnl_locked, int do_not_remove);
-
-
-/* hostap_ap.c */
-
-int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac);
-int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac);
-void ap_control_flush_macs(struct mac_restrictions *mac_restrictions);
-int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac);
-void ap_control_kickall(struct ap_data *ap);
-void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
- struct lib80211_crypt_data ***crypt);
-int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
- struct iw_quality qual[], int buf_size,
- int aplist);
-int prism2_ap_translate_scan(struct net_device *dev,
- struct iw_request_info *info, char *buffer);
-int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param);
-
-
-/* hostap_proc.c */
-
-void hostap_init_proc(local_info_t *local);
-void hostap_remove_proc(local_info_t *local);
-
-
-/* hostap_info.c */
-
-void hostap_info_init(local_info_t *local);
-void hostap_info_process(local_info_t *local, struct sk_buff *skb);
-
-
-/* hostap_ioctl.c */
-
-extern const struct iw_handler_def hostap_iw_handler_def;
-extern const struct ethtool_ops prism2_ethtool_ops;
-
-int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd);
-
-#endif /* HOSTAP_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211.h b/drivers/net/wireless/intersil/hostap/hostap_80211.h
deleted file mode 100644
index 1452cf6ecb07e..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_80211.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_80211_H
-#define HOSTAP_80211_H
-
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-
-struct hostap_ieee80211_mgmt {
- __le16 frame_control;
- __le16 duration;
- u8 da[6];
- u8 sa[6];
- u8 bssid[6];
- __le16 seq_ctrl;
- union {
- struct {
- __le16 auth_alg;
- __le16 auth_transaction;
- __le16 status_code;
- /* possibly followed by Challenge text */
- u8 variable[0];
- } __packed auth;
- struct {
- __le16 reason_code;
- } __packed deauth;
- struct {
- __le16 capab_info;
- __le16 listen_interval;
- /* followed by SSID and Supported rates */
- u8 variable[0];
- } __packed assoc_req;
- struct {
- __le16 capab_info;
- __le16 status_code;
- __le16 aid;
- /* followed by Supported rates */
- u8 variable[0];
- } __packed assoc_resp, reassoc_resp;
- struct {
- __le16 capab_info;
- __le16 listen_interval;
- u8 current_ap[6];
- /* followed by SSID and Supported rates */
- u8 variable[0];
- } __packed reassoc_req;
- struct {
- __le16 reason_code;
- } __packed disassoc;
- struct {
- } __packed probe_req;
- struct {
- u8 timestamp[8];
- __le16 beacon_int;
- __le16 capab_info;
- /* followed by some of SSID, Supported rates,
- * FH Params, DS Params, CF Params, IBSS Params, TIM */
- u8 variable[0];
- } __packed beacon, probe_resp;
- } u;
-} __packed;
-
-
-#define IEEE80211_MGMT_HDR_LEN 24
-#define IEEE80211_DATA_HDR3_LEN 24
-#define IEEE80211_DATA_HDR4_LEN 30
-
-
-struct hostap_80211_rx_status {
- u32 mac_time;
- u8 signal;
- u8 noise;
- u16 rate; /* in 100 kbps */
-};
-
-/* prism2_rx_80211 'type' argument */
-enum {
- PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC,
- PRISM2_RX_NULLFUNC_ACK
-};
-
-int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, int type);
-void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats);
-void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats);
-
-void hostap_dump_tx_80211(const char *name, struct sk_buff *skb);
-netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-
-#endif /* HOSTAP_80211_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
deleted file mode 100644
index 61be822f90b51..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_80211_rx.c
+++ /dev/null
@@ -1,1116 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/etherdevice.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <net/lib80211.h>
-#include <linux/if_arp.h>
-
-#include "hostap_80211.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char rfc1042_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char bridge_tunnel_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d "
- "jiffies=%ld\n",
- name, rx_stats->signal, rx_stats->noise, rx_stats->rate,
- skb->len, jiffies);
-
- if (skb->len < 2)
- return;
-
- fc = le16_to_cpu(hdr->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- if (skb->len < IEEE80211_DATA_HDR3_LEN) {
- printk("\n");
- return;
- }
-
- printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
- le16_to_cpu(hdr->seq_ctrl));
-
- printk(KERN_DEBUG " A1=%pM", hdr->addr1);
- printk(" A2=%pM", hdr->addr2);
- printk(" A3=%pM", hdr->addr3);
- if (skb->len >= 30)
- printk(" A4=%pM", hdr->addr4);
- printk("\n");
-}
-
-
-/* Send RX frame to netif with 802.11 (and possible prism) header.
- * Called from hardware or software IRQ context. */
-int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, int type)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int hdrlen, phdrlen, head_need, tail_need;
- u16 fc;
- int prism_header, ret;
- struct ieee80211_hdr *fhdr;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (dev->type == ARPHRD_IEEE80211_PRISM) {
- if (local->monitor_type == PRISM2_MONITOR_PRISM) {
- prism_header = 1;
- phdrlen = sizeof(struct linux_wlan_ng_prism_hdr);
- } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */
- prism_header = 2;
- phdrlen = sizeof(struct linux_wlan_ng_cap_hdr);
- }
- } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) {
- prism_header = 3;
- phdrlen = sizeof(struct hostap_radiotap_rx);
- } else {
- prism_header = 0;
- phdrlen = 0;
- }
-
- fhdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(fhdr->frame_control);
-
- if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
- printk(KERN_DEBUG "%s: dropped management frame with header "
- "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS);
- dev_kfree_skb_any(skb);
- return 0;
- }
-
- hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control);
-
- /* check if there is enough room for extra data; if not, expand skb
- * buffer to be large enough for the changes */
- head_need = phdrlen;
- tail_need = 0;
-#ifdef PRISM2_ADD_BOGUS_CRC
- tail_need += 4;
-#endif /* PRISM2_ADD_BOGUS_CRC */
-
- head_need -= skb_headroom(skb);
- tail_need -= skb_tailroom(skb);
-
- if (head_need > 0 || tail_need > 0) {
- if (pskb_expand_head(skb, head_need > 0 ? head_need : 0,
- tail_need > 0 ? tail_need : 0,
- GFP_ATOMIC)) {
- printk(KERN_DEBUG "%s: prism2_rx_80211 failed to "
- "reallocate skb buffer\n", dev->name);
- dev_kfree_skb_any(skb);
- return 0;
- }
- }
-
- /* We now have an skb with enough head and tail room, so just insert
- * the extra data */
-
-#ifdef PRISM2_ADD_BOGUS_CRC
- memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */
-#endif /* PRISM2_ADD_BOGUS_CRC */
-
- if (prism_header == 1) {
- struct linux_wlan_ng_prism_hdr *hdr;
- hdr = skb_push(skb, phdrlen);
- memset(hdr, 0, phdrlen);
- hdr->msgcode = LWNG_CAP_DID_BASE;
- hdr->msglen = sizeof(*hdr);
- memcpy(hdr->devname, dev->name, sizeof(hdr->devname));
-#define LWNG_SETVAL(f,i,s,l,d) \
-hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \
-hdr->f.status = s; hdr->f.len = l; hdr->f.data = d
- LWNG_SETVAL(hosttime, 1, 0, 4, jiffies);
- LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time);
- LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0);
- LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0);
- LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0);
- LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal);
- LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise);
- LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5);
- LWNG_SETVAL(istx, 9, 0, 4, 0);
- LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen);
-#undef LWNG_SETVAL
- } else if (prism_header == 2) {
- struct linux_wlan_ng_cap_hdr *hdr;
- hdr = skb_push(skb, phdrlen);
- memset(hdr, 0, phdrlen);
- hdr->version = htonl(LWNG_CAPHDR_VERSION);
- hdr->length = htonl(phdrlen);
- hdr->mactime = __cpu_to_be64(rx_stats->mac_time);
- hdr->hosttime = __cpu_to_be64(jiffies);
- hdr->phytype = htonl(4); /* dss_dot11_b */
- hdr->channel = htonl(local->channel);
- hdr->datarate = htonl(rx_stats->rate);
- hdr->antenna = htonl(0); /* unknown */
- hdr->priority = htonl(0); /* unknown */
- hdr->ssi_type = htonl(3); /* raw */
- hdr->ssi_signal = htonl(rx_stats->signal);
- hdr->ssi_noise = htonl(rx_stats->noise);
- hdr->preamble = htonl(0); /* unknown */
- hdr->encoding = htonl(1); /* cck */
- } else if (prism_header == 3) {
- struct hostap_radiotap_rx *hdr;
- hdr = skb_push(skb, phdrlen);
- memset(hdr, 0, phdrlen);
- hdr->hdr.it_len = cpu_to_le16(phdrlen);
- hdr->hdr.it_present =
- cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE));
- hdr->tsft = cpu_to_le64(rx_stats->mac_time);
- hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]);
- hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ);
- hdr->rate = rx_stats->rate / 5;
- hdr->dbm_antsignal = rx_stats->signal;
- hdr->dbm_antnoise = rx_stats->noise;
- }
-
- ret = skb->len - phdrlen;
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb_pull(skb, hdrlen);
- if (prism_header)
- skb_pull(skb, phdrlen);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void monitor_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- int len;
-
- len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += len;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static struct prism2_frag_entry *
-prism2_frag_cache_find(local_info_t *local, unsigned int seq,
- unsigned int frag, u8 *src, u8 *dst)
-{
- struct prism2_frag_entry *entry;
- int i;
-
- for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
- entry = &local->frag_cache[i];
- if (entry->skb != NULL &&
- time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
- printk(KERN_DEBUG "%s: expiring fragment cache entry "
- "seq=%u last_frag=%u\n",
- local->dev->name, entry->seq, entry->last_frag);
- dev_kfree_skb(entry->skb);
- entry->skb = NULL;
- }
-
- if (entry->skb != NULL && entry->seq == seq &&
- (entry->last_frag + 1 == frag || frag == -1) &&
- memcmp(entry->src_addr, src, ETH_ALEN) == 0 &&
- memcmp(entry->dst_addr, dst, ETH_ALEN) == 0)
- return entry;
- }
-
- return NULL;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static struct sk_buff *
-prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
-{
- struct sk_buff *skb = NULL;
- u16 sc;
- unsigned int frag, seq;
- struct prism2_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctrl);
- frag = sc & IEEE80211_SCTL_FRAG;
- seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-
- if (frag == 0) {
- /* Reserve enough space to fit maximum frame length */
- skb = dev_alloc_skb(local->dev->mtu +
- sizeof(struct ieee80211_hdr) +
- 8 /* LLC */ +
- 2 /* alignment */ +
- 8 /* WEP */ + ETH_ALEN /* WDS */);
- if (skb == NULL)
- return NULL;
-
- entry = &local->frag_cache[local->frag_next_idx];
- local->frag_next_idx++;
- if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN)
- local->frag_next_idx = 0;
-
- if (entry->skb != NULL)
- dev_kfree_skb(entry->skb);
-
- entry->first_frag_time = jiffies;
- entry->seq = seq;
- entry->last_frag = frag;
- entry->skb = skb;
- memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
- } else {
- /* received a fragment of a frame for which the head fragment
- * should have already been received */
- entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2,
- hdr->addr1);
- if (entry != NULL) {
- entry->last_frag = frag;
- skb = entry->skb;
- }
- }
-
- return skb;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int prism2_frag_cache_invalidate(local_info_t *local,
- struct ieee80211_hdr *hdr)
-{
- u16 sc;
- unsigned int seq;
- struct prism2_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctrl);
- seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
-
- entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1);
-
- if (entry == NULL) {
- printk(KERN_DEBUG "%s: could not invalidate fragment cache "
- "entry (seq=%u)\n",
- local->dev->name, seq);
- return -1;
- }
-
- entry->skb = NULL;
- return 0;
-}
-
-
-static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid,
- u8 *ssid, size_t ssid_len)
-{
- struct list_head *ptr;
- struct hostap_bss_info *bss;
-
- list_for_each(ptr, &local->bss_list) {
- bss = list_entry(ptr, struct hostap_bss_info, list);
- if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
- (ssid == NULL ||
- (ssid_len == bss->ssid_len &&
- memcmp(ssid, bss->ssid, ssid_len) == 0))) {
- list_move(&bss->list, &local->bss_list);
- return bss;
- }
- }
-
- return NULL;
-}
-
-
-static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid,
- u8 *ssid, size_t ssid_len)
-{
- struct hostap_bss_info *bss;
-
- if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) {
- bss = list_entry(local->bss_list.prev,
- struct hostap_bss_info, list);
- list_del(&bss->list);
- local->num_bss_info--;
- } else {
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
- if (bss == NULL)
- return NULL;
- }
-
- memset(bss, 0, sizeof(*bss));
- memcpy(bss->bssid, bssid, ETH_ALEN);
- memcpy(bss->ssid, ssid, ssid_len);
- bss->ssid_len = ssid_len;
- local->num_bss_info++;
- list_add(&bss->list, &local->bss_list);
- return bss;
-}
-
-
-static void __hostap_expire_bss(local_info_t *local)
-{
- struct hostap_bss_info *bss;
-
- while (local->num_bss_info > 0) {
- bss = list_entry(local->bss_list.prev,
- struct hostap_bss_info, list);
- if (!time_after(jiffies, bss->last_update + 60 * HZ))
- break;
-
- list_del(&bss->list);
- local->num_bss_info--;
- kfree(bss);
- }
-}
-
-
-/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so
- * the same routine can be used to parse both of them. */
-static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb,
- int stype)
-{
- struct hostap_ieee80211_mgmt *mgmt;
- int left, chan = 0;
- u8 *pos;
- u8 *ssid = NULL, *wpa = NULL, *rsn = NULL;
- size_t ssid_len = 0, wpa_len = 0, rsn_len = 0;
- struct hostap_bss_info *bss;
-
- if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon))
- return;
-
- mgmt = (struct hostap_ieee80211_mgmt *) skb->data;
- pos = mgmt->u.beacon.variable;
- left = skb->len - (pos - skb->data);
-
- while (left >= 2) {
- if (2 + pos[1] > left)
- return; /* parse failed */
- switch (*pos) {
- case WLAN_EID_SSID:
- ssid = pos + 2;
- ssid_len = pos[1];
- break;
- case WLAN_EID_VENDOR_SPECIFIC:
- if (pos[1] >= 4 &&
- pos[2] == 0x00 && pos[3] == 0x50 &&
- pos[4] == 0xf2 && pos[5] == 1) {
- wpa = pos;
- wpa_len = pos[1] + 2;
- }
- break;
- case WLAN_EID_RSN:
- rsn = pos;
- rsn_len = pos[1] + 2;
- break;
- case WLAN_EID_DS_PARAMS:
- if (pos[1] >= 1)
- chan = pos[2];
- break;
- }
- left -= 2 + pos[1];
- pos += 2 + pos[1];
- }
-
- if (wpa_len > MAX_WPA_IE_LEN)
- wpa_len = MAX_WPA_IE_LEN;
- if (rsn_len > MAX_WPA_IE_LEN)
- rsn_len = MAX_WPA_IE_LEN;
- if (ssid_len > sizeof(bss->ssid))
- ssid_len = sizeof(bss->ssid);
-
- spin_lock(&local->lock);
- bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len);
- if (bss == NULL)
- bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len);
- if (bss) {
- bss->last_update = jiffies;
- bss->count++;
- bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info);
- if (wpa) {
- memcpy(bss->wpa_ie, wpa, wpa_len);
- bss->wpa_ie_len = wpa_len;
- } else
- bss->wpa_ie_len = 0;
- if (rsn) {
- memcpy(bss->rsn_ie, rsn, rsn_len);
- bss->rsn_ie_len = rsn_len;
- } else
- bss->rsn_ie_len = 0;
- bss->chan = chan;
- }
- __hostap_expire_bss(local);
- spin_unlock(&local->lock);
-}
-
-
-static int
-hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, u16 type,
- u16 stype)
-{
- if (local->iw_mode == IW_MODE_MASTER)
- hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data);
-
- if (local->hostapd && type == IEEE80211_FTYPE_MGMT) {
- if (stype == IEEE80211_STYPE_BEACON &&
- local->iw_mode == IW_MODE_MASTER) {
- struct sk_buff *skb2;
- /* Process beacon frames also in kernel driver to
- * update STA(AP) table statistics */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2)
- hostap_rx(skb2->dev, skb2, rx_stats);
- }
-
- /* send management frames to the user space daemon for
- * processing */
- local->apdevstats.rx_packets++;
- local->apdevstats.rx_bytes += skb->len;
- if (local->apdev == NULL)
- return -1;
- prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT);
- return 0;
- }
-
- if (local->iw_mode == IW_MODE_MASTER) {
- if (type != IEEE80211_FTYPE_MGMT &&
- type != IEEE80211_FTYPE_CTL) {
- printk(KERN_DEBUG "%s: unknown management frame "
- "(type=0x%02x, stype=0x%02x) dropped\n",
- skb->dev->name, type >> 2, stype >> 4);
- return -1;
- }
-
- hostap_rx(skb->dev, skb, rx_stats);
- return 0;
- } else if (type == IEEE80211_FTYPE_MGMT &&
- (stype == IEEE80211_STYPE_BEACON ||
- stype == IEEE80211_STYPE_PROBE_RESP)) {
- hostap_rx_sta_beacon(local, skb, stype);
- return -1;
- } else if (type == IEEE80211_FTYPE_MGMT &&
- (stype == IEEE80211_STYPE_ASSOC_RESP ||
- stype == IEEE80211_STYPE_REASSOC_RESP)) {
- /* Ignore (Re)AssocResp silently since these are not currently
- * needed but are still received when WPA/RSN mode is enabled.
- */
- return -1;
- } else {
- printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled"
- " management frame in non-Host AP mode (type=%d:%d)\n",
- skb->dev->name, type >> 2, stype >> 4);
- return -1;
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static struct net_device *prism2_rx_get_wds(local_info_t *local,
- u8 *addr)
-{
- struct hostap_interface *iface = NULL;
- struct list_head *ptr;
-
- read_lock_bh(&local->iface_lock);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type == HOSTAP_INTERFACE_WDS &&
- memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0)
- break;
- iface = NULL;
- }
- read_unlock_bh(&local->iface_lock);
-
- return iface ? iface->dev : NULL;
-}
-
-
-static int
-hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc,
- struct net_device **wds)
-{
- /* FIX: is this really supposed to accept WDS frames only in Master
- * mode? What about Repeater or Managed with WDS frames? */
- if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
- (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) &&
- (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS)))
- return 0; /* not a WDS frame */
-
- /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS)
- * or own non-standard frame with 4th address after payload */
- if (!ether_addr_equal(hdr->addr1, local->dev->dev_addr) &&
- (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff ||
- hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff ||
- hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
- /* RA (or BSSID) is not ours - drop */
- PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with "
- "not own or broadcast %s=%pM\n",
- local->dev->name,
- fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
- hdr->addr1);
- return -1;
- }
-
- /* check if the frame came from a registered WDS connection */
- *wds = prism2_rx_get_wds(local, hdr->addr2);
- if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS &&
- (local->iw_mode != IW_MODE_INFRA ||
- !(local->wds_type & HOSTAP_WDS_AP_CLIENT) ||
- memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) {
- /* require that WDS link has been registered with TA or the
- * frame is from current AP when using 'AP client mode' */
- PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
- "from unknown TA=%pM\n",
- local->dev->name, hdr->addr2);
- if (local->ap && local->ap->autom_ap_wds)
- hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
- return -1;
- }
-
- if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap &&
- hostap_is_sta_assoc(local->ap, hdr->addr2)) {
- /* STA is actually associated with us even though it has a
- * registered WDS link. Assume it is in 'AP client' mode.
- * Since this is a 3-addr frame, assume it is not (bogus) WDS
- * frame and process it like any normal ToDS frame from
- * associated STA. */
- *wds = NULL;
- }
-
- return 0;
-}
-
-
-static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
-{
- struct net_device *dev = local->dev;
- u16 fc, ethertype;
- struct ieee80211_hdr *hdr;
- u8 *pos;
-
- if (skb->len < 24)
- return 0;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
-
- /* check that the frame is unicast frame to us */
- if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr) &&
- ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- /* ToDS frame with own addr BSSID and DA */
- } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- /* FromDS frame with own addr as DA */
- } else
- return 0;
-
- if (skb->len < 24 + 8)
- return 0;
-
- /* check for port access entity Ethernet type */
- pos = skb->data + 24;
- ethertype = (pos[6] << 8) | pos[7];
- if (ethertype == ETH_P_PAE)
- return 1;
-
- return 0;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int
-hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct ieee80211_hdr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
- return 0;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- if (local->tkip_countermeasures &&
- strcmp(crypt->ops->name, "TKIP") == 0) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "received packet from %pM\n",
- local->dev->name, hdr->addr2);
- }
- return -1;
- }
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n",
- local->dev->name, hdr->addr2, res);
- local->comm_tallies.rx_discards_wep_undecryptable++;
- return -1;
- }
-
- return res;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int
-hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
- int keyidx, struct lib80211_crypt_data *crypt)
-{
- struct ieee80211_hdr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
- return 0;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=%pM keyidx=%d)\n",
- local->dev->name, hdr->addr2, keyidx);
- return -1;
- }
-
- return 0;
-}
-
-
-/* All received frames are sent to this function. @skb contains the frame in
- * IEEE 802.11 format, i.e., in the format it was sent over air.
- * This function is called only as a tasklet (software IRQ). */
-void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
- size_t hdrlen;
- u16 fc, type, stype, sc;
- struct net_device *wds = NULL;
- unsigned int frag;
- u8 *payload;
- struct sk_buff *skb2 = NULL;
- u16 ethertype;
- int frame_authorized = 0;
- int from_assoc_ap = 0;
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
- struct lib80211_crypt_data *crypt = NULL;
- void *sta = NULL;
- int keyidx = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
- iface->stats.rx_packets++;
- iface->stats.rx_bytes += skb->len;
-
- /* dev is the master radio device; change this to be the default
- * virtual interface (this may be changed to WDS device below) */
- dev = local->ddev;
- iface = netdev_priv(dev);
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- if (skb->len < 10)
- goto rx_dropped;
-
- fc = le16_to_cpu(hdr->frame_control);
- type = fc & IEEE80211_FCTL_FTYPE;
- stype = fc & IEEE80211_FCTL_STYPE;
- sc = le16_to_cpu(hdr->seq_ctrl);
- frag = sc & IEEE80211_SCTL_FRAG;
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- /* Put this code here so that we avoid duplicating it in all
- * Rx paths. - Jean II */
-#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
- /* If spy monitoring on */
- if (iface->spy_data.spy_number > 0) {
- struct iw_quality wstats;
- wstats.level = rx_stats->signal;
- wstats.noise = rx_stats->noise;
- wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED
- | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(dev, hdr->addr2, &wstats);
- }
-#endif /* IW_WIRELESS_SPY */
- hostap_update_rx_stats(local->ap, hdr, rx_stats);
-
- if (local->iw_mode == IW_MODE_MONITOR) {
- monitor_rx(dev, skb, rx_stats);
- return;
- }
-
- if (local->host_decrypt) {
- int idx = 0;
- if (skb->len >= hdrlen + 3)
- idx = skb->data[hdrlen + 3] >> 6;
- crypt = local->crypt_info.crypt[idx];
- sta = NULL;
-
- /* Use station specific key to override default keys if the
- * receiver address is a unicast address ("individual RA"). If
- * bcrx_sta_key parameter is set, station specific key is used
- * even with broad/multicast targets (this is against IEEE
- * 802.11, but makes it easier to use different keys with
- * stations that do not support WEP key mapping). */
-
- if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key)
- (void) hostap_handle_sta_crypto(local, hdr, &crypt,
- &sta);
-
- /* allow NULL decrypt to indicate an station specific override
- * for default encryption */
- if (crypt && (crypt->ops == NULL ||
- crypt->ops->decrypt_mpdu == NULL))
- crypt = NULL;
-
- if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
-#if 0
- /* This seems to be triggered by some (multicast?)
- * frames from other than current BSS, so just drop the
- * frames silently instead of filling system log with
- * these reports. */
- printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
- " (SA=%pM)\n",
- local->dev->name, hdr->addr2);
-#endif
- local->comm_tallies.rx_discards_wep_undecryptable++;
- goto rx_dropped;
- }
- }
-
- if (type != IEEE80211_FTYPE_DATA) {
- if (type == IEEE80211_FTYPE_MGMT &&
- stype == IEEE80211_STYPE_AUTH &&
- fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt &&
- (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
- {
- printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from %pM\n", dev->name, hdr->addr2);
- /* TODO: could inform hostapd about this so that it
- * could send auth failure report */
- goto rx_dropped;
- }
-
- if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype))
- goto rx_dropped;
- else
- goto rx_exit;
- }
-
- /* Data frame - extract src/dst addresses */
- if (skb->len < IEEE80211_DATA_HDR3_LEN)
- goto rx_dropped;
-
- switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_FROMDS:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr3, ETH_ALEN);
- break;
- case IEEE80211_FCTL_TODS:
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- if (skb->len < IEEE80211_DATA_HDR4_LEN)
- goto rx_dropped;
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr4, ETH_ALEN);
- break;
- default:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- }
-
- if (hostap_rx_frame_wds(local, hdr, fc, &wds))
- goto rx_dropped;
- if (wds)
- skb->dev = dev = wds;
-
- if (local->iw_mode == IW_MODE_MASTER && !wds &&
- (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- local->stadev &&
- memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) {
- /* Frame from BSSID of the AP for which we are a client */
- skb->dev = dev = local->stadev;
- from_assoc_ap = 1;
- }
-
- if ((local->iw_mode == IW_MODE_MASTER ||
- local->iw_mode == IW_MODE_REPEAT) &&
- !from_assoc_ap) {
- switch (hostap_handle_sta_rx(local, dev, skb, rx_stats,
- wds != NULL)) {
- case AP_RX_CONTINUE_NOT_AUTHORIZED:
- frame_authorized = 0;
- break;
- case AP_RX_CONTINUE:
- frame_authorized = 1;
- break;
- case AP_RX_DROP:
- goto rx_dropped;
- case AP_RX_EXIT:
- goto rx_exit;
- }
- }
-
- /* Nullfunc frames may have PS-bit set, so they must be passed to
- * hostap_handle_sta_rx() before being dropped here. */
- if (stype != IEEE80211_STYPE_DATA &&
- stype != IEEE80211_STYPE_DATA_CFACK &&
- stype != IEEE80211_STYPE_DATA_CFPOLL &&
- stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
- if (stype != IEEE80211_STYPE_NULLFUNC)
- printk(KERN_DEBUG "%s: RX: dropped data frame "
- "with no data (type=0x%02x, subtype=0x%02x)\n",
- dev->name, type >> 2, stype >> 4);
- goto rx_dropped;
- }
-
- /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
-
- if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
- goto rx_dropped;
- hdr = (struct ieee80211_hdr *) skb->data;
-
- /* skb: hdr + (possibly fragmented) plaintext payload */
-
- if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) {
- int flen;
- struct sk_buff *frag_skb =
- prism2_frag_cache_get(local, hdr);
- if (!frag_skb) {
- printk(KERN_DEBUG "%s: Rx cannot get skb from "
- "fragment cache (morefrag=%d seq=%u frag=%u)\n",
- dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
- (sc & IEEE80211_SCTL_SEQ) >> 4, frag);
- goto rx_dropped;
- }
-
- flen = skb->len;
- if (frag != 0)
- flen -= hdrlen;
-
- if (frag_skb->tail + flen > frag_skb->end) {
- printk(KERN_WARNING "%s: host decrypted and "
- "reassembled frame did not fit skb\n",
- dev->name);
- prism2_frag_cache_invalidate(local, hdr);
- goto rx_dropped;
- }
-
- if (frag == 0) {
- /* copy first fragment (including full headers) into
- * beginning of the fragment cache skb */
- skb_copy_from_linear_data(skb, skb_put(frag_skb, flen),
- flen);
- } else {
- /* append frame payload to the end of the fragment
- * cache skb */
- skb_copy_from_linear_data_offset(skb, hdrlen,
- skb_put(frag_skb,
- flen), flen);
- }
- dev_kfree_skb(skb);
- skb = NULL;
-
- if (fc & IEEE80211_FCTL_MOREFRAGS) {
- /* more fragments expected - leave the skb in fragment
- * cache for now; it will be delivered to upper layers
- * after all fragments have been received */
- goto rx_exit;
- }
-
- /* this was the last fragment and the frame will be
- * delivered, so remove skb from fragment cache */
- skb = frag_skb;
- hdr = (struct ieee80211_hdr *) skb->data;
- prism2_frag_cache_invalidate(local, hdr);
- }
-
- /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
- * encrypted/authenticated */
-
- if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt))
- goto rx_dropped;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) {
- if (local->ieee_802_1x &&
- hostap_is_eapol_frame(local, skb)) {
- /* pass unencrypted EAPOL frames even if encryption is
- * configured */
- PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing "
- "unencrypted EAPOL frame\n", local->dev->name);
- } else {
- printk(KERN_DEBUG "%s: encryption configured, but RX "
- "frame not encrypted (SA=%pM)\n",
- local->dev->name, hdr->addr2);
- goto rx_dropped;
- }
- }
-
- if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) &&
- !hostap_is_eapol_frame(local, skb)) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: dropped unencrypted RX data "
- "frame from %pM (drop_unencrypted=1)\n",
- dev->name, hdr->addr2);
- }
- goto rx_dropped;
- }
-
- /* skb: hdr + (possible reassembled) full plaintext payload */
-
- payload = skb->data + hdrlen;
- ethertype = (payload[6] << 8) | payload[7];
-
- /* If IEEE 802.1X is used, check whether the port is authorized to send
- * the received frame. */
- if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) {
- if (ethertype == ETH_P_PAE) {
- PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n",
- dev->name);
- if (local->hostapd && local->apdev) {
- /* Send IEEE 802.1X frames to the user
- * space daemon for processing */
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_MGMT);
- local->apdevstats.rx_packets++;
- local->apdevstats.rx_bytes += skb->len;
- goto rx_exit;
- }
- } else if (!frame_authorized) {
- printk(KERN_DEBUG "%s: dropped frame from "
- "unauthorized port (IEEE 802.1X): "
- "ethertype=0x%04x\n",
- dev->name, ethertype);
- goto rx_dropped;
- }
- }
-
- /* convert hdr + possible LLC headers into Ethernet header */
- if (skb->len - hdrlen >= 8 &&
- ((memcmp(payload, rfc1042_header, 6) == 0 &&
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- memcmp(payload, bridge_tunnel_header, 6) == 0)) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation and
- * replace EtherType */
- skb_pull(skb, hdrlen + 6);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- } else {
- __be16 len;
- /* Leave Ethernet header part of hdr and full payload */
- skb_pull(skb, hdrlen);
- len = htons(skb->len);
- memcpy(skb_push(skb, 2), &len, 2);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- }
-
- if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS) &&
- skb->len >= ETH_HLEN + ETH_ALEN) {
- /* Non-standard frame: get addr4 from its bogus location after
- * the payload */
- skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN,
- skb->data + ETH_ALEN,
- ETH_ALEN);
- skb_trim(skb, skb->len - ETH_ALEN);
- }
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
-
- if (local->iw_mode == IW_MODE_MASTER && !wds &&
- local->ap->bridge_packets) {
- if (dst[0] & 0x01) {
- /* copy multicast frame both to the higher layers and
- * to the wireless media */
- local->ap->bridged_multicast++;
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- printk(KERN_DEBUG "%s: skb_clone failed for "
- "multicast frame\n", dev->name);
- } else if (hostap_is_sta_authorized(local->ap, dst)) {
- /* send frame directly to the associated STA using
- * wireless media and not passing to higher layers */
- local->ap->bridged_unicast++;
- skb2 = skb;
- skb = NULL;
- }
- }
-
- if (skb2 != NULL) {
- /* send to wireless media */
- skb2->dev = dev;
- skb2->protocol = cpu_to_be16(ETH_P_802_3);
- skb_reset_mac_header(skb2);
- skb_reset_network_header(skb2);
- /* skb2->network_header += ETH_HLEN; */
- dev_queue_xmit(skb2);
- }
-
- if (skb) {
- skb->protocol = eth_type_trans(skb, dev);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
- }
-
- rx_exit:
- if (sta)
- hostap_handle_sta_release(sta);
- return;
-
- rx_dropped:
- dev_kfree_skb(skb);
-
- dev->stats.rx_dropped++;
- goto rx_exit;
-}
-
-
-EXPORT_SYMBOL(hostap_80211_rx);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c b/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
deleted file mode 100644
index c47da06945c26..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_80211_tx.c
+++ /dev/null
@@ -1,554 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/etherdevice.h>
-
-#include "hostap_80211.h"
-#include "hostap_common.h"
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char rfc1042_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char bridge_tunnel_header[] =
-{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
- name, skb->len, jiffies);
-
- if (skb->len < 2)
- return;
-
- fc = le16_to_cpu(hdr->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- if (skb->len < IEEE80211_DATA_HDR3_LEN) {
- printk("\n");
- return;
- }
-
- printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
- le16_to_cpu(hdr->seq_ctrl));
-
- printk(KERN_DEBUG " A1=%pM", hdr->addr1);
- printk(" A2=%pM", hdr->addr2);
- printk(" A3=%pM", hdr->addr3);
- if (skb->len >= 30)
- printk(" A4=%pM", hdr->addr4);
- printk("\n");
-}
-
-
-/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta)
- * Convert Ethernet header into a suitable IEEE 802.11 header depending on
- * device configuration. */
-netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int need_headroom, need_tailroom = 0;
- struct ieee80211_hdr hdr;
- u16 fc, ethertype = 0;
- enum {
- WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
- } use_wds = WDS_NO;
- u8 *encaps_data;
- int hdr_len, encaps_len, skip_header_bytes;
- int to_assoc_ap = 0;
- struct hostap_skb_tx_data *meta;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (skb->len < ETH_HLEN) {
- printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb "
- "(len=%d)\n", dev->name, skb->len);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- if (local->ddev != dev) {
- use_wds = (local->iw_mode == IW_MODE_MASTER &&
- !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ?
- WDS_OWN_FRAME : WDS_COMPLIANT_FRAME;
- if (dev == local->stadev) {
- to_assoc_ap = 1;
- use_wds = WDS_NO;
- } else if (dev == local->apdev) {
- printk(KERN_DEBUG "%s: prism2_tx: trying to use "
- "AP device with Ethernet net dev\n", dev->name);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- } else {
- if (local->iw_mode == IW_MODE_REPEAT) {
- printk(KERN_DEBUG "%s: prism2_tx: trying to use "
- "non-WDS link in Repeater mode\n", dev->name);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- } else if (local->iw_mode == IW_MODE_INFRA &&
- (local->wds_type & HOSTAP_WDS_AP_CLIENT) &&
- !ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) {
- /* AP client mode: send frames with foreign src addr
- * using 4-addr WDS frames */
- use_wds = WDS_COMPLIANT_FRAME;
- }
- }
-
- /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload
- * ==>
- * Prism2 TX frame with 802.11 header:
- * txdesc (address order depending on used mode; includes dst_addr and
- * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel;
- * proto[2], payload {, possible addr4[6]} */
-
- ethertype = (skb->data[12] << 8) | skb->data[13];
-
- memset(&hdr, 0, sizeof(hdr));
-
- /* Length of data after IEEE 802.11 header */
- encaps_data = NULL;
- encaps_len = 0;
- skip_header_bytes = ETH_HLEN;
- if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
- encaps_data = bridge_tunnel_header;
- encaps_len = sizeof(bridge_tunnel_header);
- skip_header_bytes -= 2;
- } else if (ethertype >= 0x600) {
- encaps_data = rfc1042_header;
- encaps_len = sizeof(rfc1042_header);
- skip_header_bytes -= 2;
- }
-
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
- hdr_len = IEEE80211_DATA_HDR3_LEN;
-
- if (use_wds != WDS_NO) {
- /* Note! Prism2 station firmware has problems with sending real
- * 802.11 frames with four addresses; until these problems can
- * be fixed or worked around, 4-addr frames needed for WDS are
- * using incompatible format: FromDS flag is not set and the
- * fourth address is added after the frame payload; it is
- * assumed, that the receiving station knows how to handle this
- * frame format */
-
- if (use_wds == WDS_COMPLIANT_FRAME) {
- fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS;
- /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA,
- * Addr4 = SA */
- skb_copy_from_linear_data_offset(skb, ETH_ALEN,
- &hdr.addr4, ETH_ALEN);
- hdr_len += ETH_ALEN;
- } else {
- /* bogus 4-addr format to workaround Prism2 station
- * f/w bug */
- fc |= IEEE80211_FCTL_TODS;
- /* From DS: Addr1 = DA (used as RA),
- * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA),
- */
-
- /* SA from skb->data + ETH_ALEN will be added after
- * frame payload; use hdr.addr4 as a temporary buffer
- */
- skb_copy_from_linear_data_offset(skb, ETH_ALEN,
- &hdr.addr4, ETH_ALEN);
- need_tailroom += ETH_ALEN;
- }
-
- /* send broadcast and multicast frames to broadcast RA, if
- * configured; otherwise, use unicast RA of the WDS link */
- if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) &&
- is_multicast_ether_addr(skb->data))
- eth_broadcast_addr(hdr.addr1);
- else if (iface->type == HOSTAP_INTERFACE_WDS)
- memcpy(&hdr.addr1, iface->u.wds.remote_addr,
- ETH_ALEN);
- else
- memcpy(&hdr.addr1, local->bssid, ETH_ALEN);
- memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
- skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
- } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) {
- fc |= IEEE80211_FCTL_FROMDS;
- /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */
- skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
- memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3,
- ETH_ALEN);
- } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) {
- fc |= IEEE80211_FCTL_TODS;
- /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
- memcpy(&hdr.addr1, to_assoc_ap ?
- local->assoc_ap_addr : local->bssid, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
- ETH_ALEN);
- skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN);
- } else if (local->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
- skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2,
- ETH_ALEN);
- memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
- }
-
- hdr.frame_control = cpu_to_le16(fc);
-
- skb_pull(skb, skip_header_bytes);
- need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
- if (skb_tailroom(skb) < need_tailroom) {
- skb = skb_unshare(skb, GFP_ATOMIC);
- if (skb == NULL) {
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- if (pskb_expand_head(skb, need_headroom, need_tailroom,
- GFP_ATOMIC)) {
- kfree_skb(skb);
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- } else if (skb_headroom(skb) < need_headroom) {
- struct sk_buff *tmp = skb;
- skb = skb_realloc_headroom(skb, need_headroom);
- kfree_skb(tmp);
- if (skb == NULL) {
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- } else {
- skb = skb_unshare(skb, GFP_ATOMIC);
- if (skb == NULL) {
- iface->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- }
-
- if (encaps_data)
- memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
- memcpy(skb_push(skb, hdr_len), &hdr, hdr_len);
- if (use_wds == WDS_OWN_FRAME) {
- skb_put_data(skb, &hdr.addr4, ETH_ALEN);
- }
-
- iface->stats.tx_packets++;
- iface->stats.tx_bytes += skb->len;
-
- skb_reset_mac_header(skb);
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- if (use_wds)
- meta->flags |= HOSTAP_TX_FLAGS_WDS;
- meta->ethertype = ethertype;
- meta->iface = iface;
-
- /* Send IEEE 802.11 encapsulated frame using the master radio device */
- skb->dev = local->dev;
- dev_queue_xmit(skb);
- return NETDEV_TX_OK;
-}
-
-
-/* hard_start_xmit function for hostapd wlan#ap interfaces */
-netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hostap_skb_tx_data *meta;
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (skb->len < 10) {
- printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb "
- "(len=%d)\n", dev->name, skb->len);
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- iface->stats.tx_packets++;
- iface->stats.tx_bytes += skb->len;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- meta->iface = iface;
-
- if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- if (ieee80211_is_data(hdr->frame_control) &&
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) {
- u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
- sizeof(rfc1042_header)];
- meta->ethertype = (pos[0] << 8) | pos[1];
- }
- }
-
- /* Send IEEE 802.11 encapsulated frame using the master radio device */
- skb->dev = local->dev;
- dev_queue_xmit(skb);
- return NETDEV_TX_OK;
-}
-
-
-/* Called only from software IRQ */
-static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
- int prefix_len, postfix_len, hdr_len, res;
-
- iface = netdev_priv(skb->dev);
- local = iface->local;
-
- if (skb->len < IEEE80211_DATA_HDR3_LEN) {
- kfree_skb(skb);
- return NULL;
- }
-
- if (local->tkip_countermeasures &&
- strcmp(crypt->ops->name, "TKIP") == 0) {
- hdr = (struct ieee80211_hdr *) skb->data;
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
- "TX packet to %pM\n",
- local->dev->name, hdr->addr1);
- }
- kfree_skb(skb);
- return NULL;
- }
-
- skb = skb_unshare(skb, GFP_ATOMIC);
- if (skb == NULL)
- return NULL;
-
- prefix_len = crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_msdu_prefix_len;
- postfix_len = crypt->ops->extra_mpdu_postfix_len +
- crypt->ops->extra_msdu_postfix_len;
- if ((skb_headroom(skb) < prefix_len ||
- skb_tailroom(skb) < postfix_len) &&
- pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) {
- kfree_skb(skb);
- return NULL;
- }
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdr_len = hostap_80211_get_hdrlen(hdr->frame_control);
-
- /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
- * call both MSDU and MPDU encryption functions from here. */
- atomic_inc(&crypt->refcnt);
- res = 0;
- if (crypt->ops->encrypt_msdu)
- res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv);
- if (res == 0 && crypt->ops->encrypt_mpdu)
- res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- kfree_skb(skb);
- return NULL;
- }
-
- return skb;
-}
-
-
-/* hard_start_xmit function for master radio interface wifi#.
- * AP processing (TX rate control, power save buffering, etc.).
- * Use hardware TX function to send the frame. */
-netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- netdev_tx_t ret = NETDEV_TX_BUSY;
- u16 fc;
- struct hostap_tx_data tx;
- ap_tx_ret tx_ret;
- struct hostap_skb_tx_data *meta;
- int no_encrypt = 0;
- struct ieee80211_hdr *hdr;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- tx.skb = skb;
- tx.sta_ptr = NULL;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
- printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
- "expected 0x%08x)\n",
- dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC);
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- goto fail;
- }
-
- if (local->host_encrypt) {
- /* Set crypt to default algorithm and key; will be replaced in
- * AP code if STA has own alg/key */
- tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx];
- tx.host_encrypt = 1;
- } else {
- tx.crypt = NULL;
- tx.host_encrypt = 0;
- }
-
- if (skb->len < 24) {
- printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb "
- "(len=%d)\n", dev->name, skb->len);
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- goto fail;
- }
-
- /* FIX (?):
- * Wi-Fi 802.11b test plan suggests that AP should ignore power save
- * bit in authentication and (re)association frames and assume tha
- * STA remains awake for the response. */
- tx_ret = hostap_handle_sta_tx(local, &tx);
- skb = tx.skb;
- meta = (struct hostap_skb_tx_data *) skb->cb;
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- switch (tx_ret) {
- case AP_TX_CONTINUE:
- break;
- case AP_TX_CONTINUE_NOT_AUTHORIZED:
- if (local->ieee_802_1x &&
- ieee80211_is_data(hdr->frame_control) &&
- meta->ethertype != ETH_P_PAE &&
- !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
- printk(KERN_DEBUG "%s: dropped frame to unauthorized "
- "port (IEEE 802.1X): ethertype=0x%04x\n",
- dev->name, meta->ethertype);
- hostap_dump_tx_80211(dev->name, skb);
-
- ret = NETDEV_TX_OK; /* drop packet */
- iface->stats.tx_dropped++;
- goto fail;
- }
- break;
- case AP_TX_DROP:
- ret = NETDEV_TX_OK; /* drop packet */
- iface->stats.tx_dropped++;
- goto fail;
- case AP_TX_RETRY:
- goto fail;
- case AP_TX_BUFFERED:
- /* do not free skb here, it will be freed when the
- * buffered frame is sent/timed out */
- ret = NETDEV_TX_OK;
- goto tx_exit;
- }
-
- /* Request TX callback if protocol version is 2 in 802.11 header;
- * this version 2 is a special case used between hostapd and kernel
- * driver */
- if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) &&
- local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) {
- meta->tx_cb_idx = local->ap->tx_callback_idx;
-
- /* remove special version from the frame header */
- fc &= ~IEEE80211_FCTL_VERS;
- hdr->frame_control = cpu_to_le16(fc);
- }
-
- if (!ieee80211_is_data(hdr->frame_control)) {
- no_encrypt = 1;
- tx.crypt = NULL;
- }
-
- if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt &&
- !(fc & IEEE80211_FCTL_PROTECTED)) {
- no_encrypt = 1;
- PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing "
- "unencrypted EAPOL frame\n", dev->name);
- tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */
- }
-
- if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu))
- tx.crypt = NULL;
- else if ((tx.crypt ||
- local->crypt_info.crypt[local->crypt_info.tx_keyidx]) &&
- !no_encrypt) {
- /* Add ISWEP flag both for firmware and host based encryption
- */
- fc |= IEEE80211_FCTL_PROTECTED;
- hdr->frame_control = cpu_to_le16(fc);
- } else if (local->drop_unencrypted &&
- ieee80211_is_data(hdr->frame_control) &&
- meta->ethertype != ETH_P_PAE) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: dropped unencrypted TX data "
- "frame (drop_unencrypted=1)\n", dev->name);
- }
- iface->stats.tx_dropped++;
- ret = NETDEV_TX_OK;
- goto fail;
- }
-
- if (tx.crypt) {
- skb = hostap_tx_encrypt(skb, tx.crypt);
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: TX - encryption failed\n",
- dev->name);
- ret = NETDEV_TX_OK;
- goto fail;
- }
- meta = (struct hostap_skb_tx_data *) skb->cb;
- if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) {
- printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, "
- "expected 0x%08x) after hostap_tx_encrypt\n",
- dev->name, meta->magic,
- HOSTAP_SKB_TX_DATA_MAGIC);
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- goto fail;
- }
- }
-
- if (local->func->tx == NULL || local->func->tx(skb, dev)) {
- ret = NETDEV_TX_OK;
- iface->stats.tx_dropped++;
- } else {
- ret = NETDEV_TX_OK;
- iface->stats.tx_packets++;
- iface->stats.tx_bytes += skb->len;
- }
-
- fail:
- if (ret == NETDEV_TX_OK && skb)
- dev_kfree_skb(skb);
- tx_exit:
- if (tx.sta_ptr)
- hostap_handle_sta_release(tx.sta_ptr);
- return ret;
-}
-
-
-EXPORT_SYMBOL(hostap_master_start_xmit);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.c b/drivers/net/wireless/intersil/hostap/hostap_ap.c
deleted file mode 100644
index 9b546a71e7a2e..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_ap.c
+++ /dev/null
@@ -1,3277 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Intersil Prism2 driver with Host AP (software access point) support
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <[email protected]>
- * Copyright (c) 2002-2005, Jouni Malinen <[email protected]>
- *
- * This file is to be included into hostap.c when S/W AP functionality is
- * compiled.
- *
- * AP: FIX:
- * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from
- * unauthenticated STA, send deauth. frame (8802.11: 5.5)
- * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received
- * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5)
- * - if unicast Class 3 received from unauthenticated STA, send deauth. frame
- * (8802.11: 5.5)
- */
-
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/if_arp.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/moduleparam.h>
-#include <linux/etherdevice.h>
-
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL,
- DEF_INTS };
-module_param_array(other_ap_policy, int, NULL, 0444);
-MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)");
-
-static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC,
- DEF_INTS };
-module_param_array(ap_max_inactivity, int, NULL, 0444);
-MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station "
- "inactivity");
-
-static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS };
-module_param_array(ap_bridge_packets, int, NULL, 0444);
-MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between "
- "stations");
-
-static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS };
-module_param_array(autom_ap_wds, int, NULL, 0444);
-MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs "
- "automatically");
-
-
-static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta);
-static void hostap_event_expired_sta(struct net_device *dev,
- struct sta_info *sta);
-static void handle_add_proc_queue(struct work_struct *work);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-static void handle_wds_oper_queue(struct work_struct *work);
-static void prism2_send_mgmt(struct net_device *dev,
- u16 type_subtype, char *body,
- int body_len, u8 *addr, u16 tx_cb_idx);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS)
-static int ap_debug_proc_show(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
-
- seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast);
- seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast);
- seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ);
- seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets);
- seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack);
- seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds);
- seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs);
- seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc);
- return 0;
-}
-#endif
-
-static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta)
-{
- sta->hnext = ap->sta_hash[STA_HASH(sta->addr)];
- ap->sta_hash[STA_HASH(sta->addr)] = sta;
-}
-
-static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
-{
- struct sta_info *s;
-
- s = ap->sta_hash[STA_HASH(sta->addr)];
- if (s == NULL) return;
- if (ether_addr_equal(s->addr, sta->addr)) {
- ap->sta_hash[STA_HASH(sta->addr)] = s->hnext;
- return;
- }
-
- while (s->hnext != NULL && !ether_addr_equal(s->hnext->addr, sta->addr))
- s = s->hnext;
- if (s->hnext != NULL)
- s->hnext = s->hnext->hnext;
- else
- printk("AP: could not remove STA %pM from hash table\n",
- sta->addr);
-}
-
-static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
-{
- if (sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
-
- if (ap->proc != NULL) {
- char name[20];
- sprintf(name, "%pM", sta->addr);
- remove_proc_entry(name, ap->proc);
- }
-
- if (sta->crypt) {
- sta->crypt->ops->deinit(sta->crypt->priv);
- kfree(sta->crypt);
- sta->crypt = NULL;
- }
-
- skb_queue_purge(&sta->tx_buf);
-
- ap->num_sta--;
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (sta->aid > 0)
- ap->sta_aid[sta->aid - 1] = NULL;
-
- if (!sta->ap)
- kfree(sta->u.sta.challenge);
- timer_shutdown_sync(&sta->timer);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- kfree(sta);
-}
-
-
-static void hostap_set_tim(local_info_t *local, int aid, int set)
-{
- if (local->func->set_tim)
- local->func->set_tim(local->dev, aid, set);
-}
-
-
-static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta)
-{
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL);
-}
-
-
-static void hostap_event_expired_sta(struct net_device *dev,
- struct sta_info *sta)
-{
- union iwreq_data wrqu;
- memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static void ap_handle_timer(struct timer_list *t)
-{
- struct sta_info *sta = from_timer(sta, t, timer);
- local_info_t *local;
- struct ap_data *ap;
- unsigned long next_time = 0;
- int was_assoc;
-
- if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
- PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
- return;
- }
-
- local = sta->local;
- ap = local->ap;
- was_assoc = sta->flags & WLAN_STA_ASSOC;
-
- if (atomic_read(&sta->users) != 0)
- next_time = jiffies + HZ;
- else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH))
- next_time = jiffies + ap->max_inactivity;
-
- if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) {
- /* station activity detected; reset timeout state */
- sta->timeout_next = STA_NULLFUNC;
- next_time = sta->last_rx + ap->max_inactivity;
- } else if (sta->timeout_next == STA_DISASSOC &&
- !(sta->flags & WLAN_STA_PENDING_POLL)) {
- /* STA ACKed data nullfunc frame poll */
- sta->timeout_next = STA_NULLFUNC;
- next_time = jiffies + ap->max_inactivity;
- }
-
- if (next_time) {
- sta->timer.expires = next_time;
- add_timer(&sta->timer);
- return;
- }
-
- if (sta->ap)
- sta->timeout_next = STA_DEAUTH;
-
- if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) {
- spin_lock(&ap->sta_table_lock);
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- spin_unlock(&ap->sta_table_lock);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- } else if (sta->timeout_next == STA_DISASSOC)
- sta->flags &= ~WLAN_STA_ASSOC;
-
- if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(local->dev, sta);
-
- if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 &&
- !skb_queue_empty(&sta->tx_buf)) {
- hostap_set_tim(local, sta->aid, 0);
- sta->flags &= ~WLAN_STA_TIM;
- }
-
- if (sta->ap) {
- if (ap->autom_ap_wds) {
- PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
- "connection to AP %pM\n",
- local->dev->name, sta->addr);
- hostap_wds_link_oper(local, sta->addr, WDS_DEL);
- }
- } else if (sta->timeout_next == STA_NULLFUNC) {
- /* send data frame to poll STA and check whether this frame
- * is ACKed */
- /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but
- * it is apparently not retried so TX Exc events are not
- * received for it */
- sta->flags |= WLAN_STA_PENDING_POLL;
- prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA |
- IEEE80211_STYPE_DATA, NULL, 0,
- sta->addr, ap->tx_callback_poll);
- } else {
- int deauth = sta->timeout_next == STA_DEAUTH;
- __le16 resp;
- PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM"
- "(last=%lu, jiffies=%lu)\n",
- local->dev->name,
- deauth ? "deauthentication" : "disassociation",
- sta->addr, sta->last_rx, jiffies);
-
- resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
- prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT |
- (deauth ? IEEE80211_STYPE_DEAUTH :
- IEEE80211_STYPE_DISASSOC),
- (char *) &resp, 2, sta->addr, 0);
- }
-
- if (sta->timeout_next == STA_DEAUTH) {
- if (sta->flags & WLAN_STA_PERM) {
- PDEBUG(DEBUG_AP, "%s: STA %pM"
- " would have been removed, "
- "but it has 'perm' flag\n",
- local->dev->name, sta->addr);
- } else
- ap_free_sta(ap, sta);
- return;
- }
-
- if (sta->timeout_next == STA_NULLFUNC) {
- sta->timeout_next = STA_DISASSOC;
- sta->timer.expires = jiffies + AP_DISASSOC_DELAY;
- } else {
- sta->timeout_next = STA_DEAUTH;
- sta->timer.expires = jiffies + AP_DEAUTH_DELAY;
- }
-
- add_timer(&sta->timer);
-}
-
-
-void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
- int resend)
-{
- u8 addr[ETH_ALEN];
- __le16 resp;
- int i;
-
- PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name);
- eth_broadcast_addr(addr);
-
- resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
-
- /* deauth message sent; try to resend it few times; the message is
- * broadcast, so it may be delayed until next DTIM; there is not much
- * else we can do at this point since the driver is going to be shut
- * down */
- for (i = 0; i < 5; i++) {
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
- IEEE80211_STYPE_DEAUTH,
- (char *) &resp, 2, addr, 0);
-
- if (!resend || ap->num_sta <= 0)
- return;
-
- mdelay(50);
- }
-}
-
-
-static int ap_control_proc_show(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- char *policy_txt;
- struct mac_entry *entry;
-
- if (v == SEQ_START_TOKEN) {
- switch (ap->mac_restrictions.policy) {
- case MAC_POLICY_OPEN:
- policy_txt = "open";
- break;
- case MAC_POLICY_ALLOW:
- policy_txt = "allow";
- break;
- case MAC_POLICY_DENY:
- policy_txt = "deny";
- break;
- default:
- policy_txt = "unknown";
- break;
- }
- seq_printf(m, "MAC policy: %s\n", policy_txt);
- seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries);
- seq_puts(m, "MAC list:\n");
- return 0;
- }
-
- entry = v;
- seq_printf(m, "%pM\n", entry->addr);
- return 0;
-}
-
-static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_lock_bh(&ap->mac_restrictions.lock);
- return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos);
-}
-
-static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos);
-}
-
-static void ap_control_proc_stop(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_unlock_bh(&ap->mac_restrictions.lock);
-}
-
-static const struct seq_operations ap_control_proc_seqops = {
- .start = ap_control_proc_start,
- .next = ap_control_proc_next,
- .stop = ap_control_proc_stop,
- .show = ap_control_proc_show,
-};
-
-int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
-{
- struct mac_entry *entry;
-
- entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL);
- if (entry == NULL)
- return -ENOMEM;
-
- memcpy(entry->addr, mac, ETH_ALEN);
-
- spin_lock_bh(&mac_restrictions->lock);
- list_add_tail(&entry->list, &mac_restrictions->mac_list);
- mac_restrictions->entries++;
- spin_unlock_bh(&mac_restrictions->lock);
-
- return 0;
-}
-
-
-int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac)
-{
- struct list_head *ptr;
- struct mac_entry *entry;
-
- spin_lock_bh(&mac_restrictions->lock);
- for (ptr = mac_restrictions->mac_list.next;
- ptr != &mac_restrictions->mac_list; ptr = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, list);
-
- if (ether_addr_equal(entry->addr, mac)) {
- list_del(ptr);
- kfree(entry);
- mac_restrictions->entries--;
- spin_unlock_bh(&mac_restrictions->lock);
- return 0;
- }
- }
- spin_unlock_bh(&mac_restrictions->lock);
- return -1;
-}
-
-
-static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions,
- u8 *mac)
-{
- struct mac_entry *entry;
- int found = 0;
-
- if (mac_restrictions->policy == MAC_POLICY_OPEN)
- return 0;
-
- spin_lock_bh(&mac_restrictions->lock);
- list_for_each_entry(entry, &mac_restrictions->mac_list, list) {
- if (ether_addr_equal(entry->addr, mac)) {
- found = 1;
- break;
- }
- }
- spin_unlock_bh(&mac_restrictions->lock);
-
- if (mac_restrictions->policy == MAC_POLICY_ALLOW)
- return !found;
- else
- return found;
-}
-
-
-void ap_control_flush_macs(struct mac_restrictions *mac_restrictions)
-{
- struct list_head *ptr, *n;
- struct mac_entry *entry;
-
- if (mac_restrictions->entries == 0)
- return;
-
- spin_lock_bh(&mac_restrictions->lock);
- for (ptr = mac_restrictions->mac_list.next, n = ptr->next;
- ptr != &mac_restrictions->mac_list;
- ptr = n, n = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, list);
- list_del(ptr);
- kfree(entry);
- }
- mac_restrictions->entries = 0;
- spin_unlock_bh(&mac_restrictions->lock);
-}
-
-
-int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac)
-{
- struct sta_info *sta;
- __le16 resp;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, mac);
- if (sta) {
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -EINVAL;
-
- resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH,
- (char *) &resp, 2, sta->addr, 0);
-
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(dev, sta);
-
- ap_free_sta(ap, sta);
-
- return 0;
-}
-
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-void ap_control_kickall(struct ap_data *ap)
-{
- struct list_head *ptr, *n;
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list;
- ptr = n, n = ptr->next) {
- sta = list_entry(ptr, struct sta_info, list);
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
- ap_free_sta(ap, sta);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static int prism2_ap_proc_show(struct seq_file *m, void *v)
-{
- struct sta_info *sta = v;
- int i;
-
- if (v == SEQ_START_TOKEN) {
- seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n");
- return 0;
- }
-
- if (!sta->ap)
- return 0;
-
- seq_printf(m, "%pM %d %d %d %d '",
- sta->addr,
- sta->u.ap.channel, sta->last_rx_signal,
- sta->last_rx_silence, sta->last_rx_rate);
-
- for (i = 0; i < sta->u.ap.ssid_len; i++) {
- if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127)
- seq_putc(m, sta->u.ap.ssid[i]);
- else
- seq_printf(m, "<%02x>", sta->u.ap.ssid[i]);
- }
-
- seq_putc(m, '\'');
- if (sta->capability & WLAN_CAPABILITY_ESS)
- seq_puts(m, " [ESS]");
- if (sta->capability & WLAN_CAPABILITY_IBSS)
- seq_puts(m, " [IBSS]");
- if (sta->capability & WLAN_CAPABILITY_PRIVACY)
- seq_puts(m, " [WEP]");
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_lock_bh(&ap->sta_table_lock);
- return seq_list_start_head(&ap->sta_list, *_pos);
-}
-
-static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- return seq_list_next(v, &ap->sta_list, _pos);
-}
-
-static void prism2_ap_proc_stop(struct seq_file *m, void *v)
-{
- struct ap_data *ap = pde_data(file_inode(m->file));
- spin_unlock_bh(&ap->sta_table_lock);
-}
-
-static const struct seq_operations prism2_ap_proc_seqops = {
- .start = prism2_ap_proc_start,
- .next = prism2_ap_proc_next,
- .stop = prism2_ap_proc_stop,
- .show = prism2_ap_proc_show,
-};
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver)
-{
- if (!ap)
- return;
-
- if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) {
- PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - "
- "firmware upgrade recommended\n");
- ap->nullfunc_ack = 1;
- } else
- ap->nullfunc_ack = 0;
-
- if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) {
- printk(KERN_WARNING "%s: Warning: secondary station firmware "
- "version 1.4.2 does not seem to work in Host AP mode\n",
- ap->local->dev->name);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct ieee80211_hdr *hdr;
-
- if (!ap->local->hostapd || !ap->local->apdev) {
- dev_kfree_skb(skb);
- return;
- }
-
- /* Pass the TX callback frame to the hostapd; use 802.11 header version
- * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */
-
- hdr = (struct ieee80211_hdr *) skb->data;
- hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS);
- hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0));
-
- skb->dev = ap->local->apdev;
- skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control));
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_802_2);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-/* Called only as a tasklet (software IRQ) */
-static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct net_device *dev = ap->local->dev;
- struct ieee80211_hdr *hdr;
- u16 auth_alg, auth_transaction, status;
- __le16 *pos;
- struct sta_info *sta = NULL;
- char *txt = NULL;
-
- if (ap->local->hostapd) {
- dev_kfree_skb(skb);
- return;
- }
-
- hdr = (struct ieee80211_hdr *) skb->data;
- if (!ieee80211_is_auth(hdr->frame_control) ||
- skb->len < IEEE80211_MGMT_HDR_LEN + 6) {
- printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid "
- "frame\n", dev->name);
- dev_kfree_skb(skb);
- return;
- }
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- auth_alg = le16_to_cpu(*pos++);
- auth_transaction = le16_to_cpu(*pos++);
- status = le16_to_cpu(*pos++);
-
- if (!ok) {
- txt = "frame was not ACKed";
- goto done;
- }
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr1);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&ap->sta_table_lock);
-
- if (!sta) {
- txt = "STA not found";
- goto done;
- }
-
- if (status == WLAN_STATUS_SUCCESS &&
- ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
- (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
- txt = "STA authenticated";
- sta->flags |= WLAN_STA_AUTH;
- sta->last_auth = jiffies;
- } else if (status != WLAN_STATUS_SUCCESS)
- txt = "authentication failed";
-
- done:
- if (sta)
- atomic_dec(&sta->users);
- if (txt) {
- PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d "
- "trans#=%d status=%d - %s\n",
- dev->name, hdr->addr1,
- auth_alg, auth_transaction, status, txt);
- }
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct net_device *dev = ap->local->dev;
- struct ieee80211_hdr *hdr;
- u16 status;
- __le16 *pos;
- struct sta_info *sta = NULL;
- char *txt = NULL;
-
- if (ap->local->hostapd) {
- dev_kfree_skb(skb);
- return;
- }
-
- hdr = (struct ieee80211_hdr *) skb->data;
- if ((!ieee80211_is_assoc_resp(hdr->frame_control) &&
- !ieee80211_is_reassoc_resp(hdr->frame_control)) ||
- skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
- printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid "
- "frame\n", dev->name);
- dev_kfree_skb(skb);
- return;
- }
-
- if (!ok) {
- txt = "frame was not ACKed";
- goto done;
- }
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr1);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&ap->sta_table_lock);
-
- if (!sta) {
- txt = "STA not found";
- goto done;
- }
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- pos++;
- status = le16_to_cpu(*pos++);
- if (status == WLAN_STATUS_SUCCESS) {
- if (!(sta->flags & WLAN_STA_ASSOC))
- hostap_event_new_sta(dev, sta);
- txt = "STA associated";
- sta->flags |= WLAN_STA_ASSOC;
- sta->last_assoc = jiffies;
- } else
- txt = "association failed";
-
- done:
- if (sta)
- atomic_dec(&sta->users);
- if (txt) {
- PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n",
- dev->name, hdr->addr1, txt);
- }
- dev_kfree_skb(skb);
-}
-
-/* Called only as a tasklet (software IRQ); TX callback for poll frames used
- * in verifying whether the STA is still present. */
-static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
-{
- struct ap_data *ap = data;
- struct ieee80211_hdr *hdr;
- struct sta_info *sta;
-
- if (skb->len < 24)
- goto fail;
- hdr = (struct ieee80211_hdr *) skb->data;
- if (ok) {
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr1);
- if (sta)
- sta->flags &= ~WLAN_STA_PENDING_POLL;
- spin_unlock(&ap->sta_table_lock);
- } else {
- PDEBUG(DEBUG_AP,
- "%s: STA %pM did not ACK activity poll frame\n",
- ap->local->dev->name, hdr->addr1);
- }
-
- fail:
- dev_kfree_skb(skb);
-}
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-void hostap_init_data(local_info_t *local)
-{
- struct ap_data *ap = local->ap;
-
- if (ap == NULL) {
- printk(KERN_WARNING "hostap_init_data: ap == NULL\n");
- return;
- }
- memset(ap, 0, sizeof(struct ap_data));
- ap->local = local;
-
- ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx);
- ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx);
- ap->max_inactivity =
- GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ;
- ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx);
-
- spin_lock_init(&ap->sta_table_lock);
- INIT_LIST_HEAD(&ap->sta_list);
-
- /* Initialize task queue structure for AP management */
- INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue);
-
- ap->tx_callback_idx =
- hostap_tx_callback_register(local, hostap_ap_tx_cb, ap);
- if (ap->tx_callback_idx == 0)
- printk(KERN_WARNING "%s: failed to register TX callback for "
- "AP\n", local->dev->name);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue);
-
- ap->tx_callback_auth =
- hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap);
- ap->tx_callback_assoc =
- hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap);
- ap->tx_callback_poll =
- hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap);
- if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 ||
- ap->tx_callback_poll == 0)
- printk(KERN_WARNING "%s: failed to register TX callback for "
- "AP\n", local->dev->name);
-
- spin_lock_init(&ap->mac_restrictions.lock);
- INIT_LIST_HEAD(&ap->mac_restrictions.mac_list);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- ap->initialized = 1;
-}
-
-
-void hostap_init_ap_proc(local_info_t *local)
-{
- struct ap_data *ap = local->ap;
-
- ap->proc = local->proc;
- if (ap->proc == NULL)
- return;
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- proc_create_single_data("ap_debug", 0, ap->proc, ap_debug_proc_show, ap);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- proc_create_seq_data("ap_control", 0, ap->proc, &ap_control_proc_seqops,
- ap);
- proc_create_seq_data("ap", 0, ap->proc, &prism2_ap_proc_seqops, ap);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-}
-
-
-void hostap_free_data(struct ap_data *ap)
-{
- struct sta_info *n, *sta;
-
- if (ap == NULL || !ap->initialized) {
- printk(KERN_DEBUG "hostap_free_data: ap has not yet been "
- "initialized - skip resource freeing\n");
- return;
- }
-
- flush_work(&ap->add_sta_proc_queue);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- flush_work(&ap->wds_oper_queue);
- if (ap->crypt)
- ap->crypt->deinit(ap->crypt_priv);
- ap->crypt = ap->crypt_priv = NULL;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- list_for_each_entry_safe(sta, n, &ap->sta_list, list) {
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
- ap_free_sta(ap, sta);
- }
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- if (ap->proc != NULL) {
- remove_proc_entry("ap_debug", ap->proc);
- }
-#endif /* PRISM2_NO_PROCFS_DEBUG */
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (ap->proc != NULL) {
- remove_proc_entry("ap", ap->proc);
- remove_proc_entry("ap_control", ap->proc);
- }
- ap_control_flush_macs(&ap->mac_restrictions);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- ap->initialized = 0;
-}
-
-
-/* caller should have mutex for AP STA list handling */
-static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta)
-{
- struct sta_info *s;
-
- s = ap->sta_hash[STA_HASH(sta)];
- while (s != NULL && !ether_addr_equal(s->addr, sta))
- s = s->hnext;
- return s;
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-/* Called from timer handler and from scheduled AP queue handlers */
-static void prism2_send_mgmt(struct net_device *dev,
- u16 type_subtype, char *body,
- int body_len, u8 *addr, u16 tx_cb_idx)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
- u16 fc;
- struct sk_buff *skb;
- struct hostap_skb_tx_data *meta;
- int hdrlen;
-
- iface = netdev_priv(dev);
- local = iface->local;
- dev = local->dev; /* always use master radio device */
- iface = netdev_priv(dev);
-
- if (!(dev->flags & IFF_UP)) {
- PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - "
- "cannot send frame\n", dev->name);
- return;
- }
-
- skb = dev_alloc_skb(sizeof(*hdr) + body_len);
- if (skb == NULL) {
- PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate "
- "skb\n", dev->name);
- return;
- }
-
- fc = type_subtype;
- hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype));
- hdr = skb_put_zero(skb, hdrlen);
- if (body)
- skb_put_data(skb, body, body_len);
-
- /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11
- * tx_control instead of using local->tx_control */
-
-
- memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */
- if (ieee80211_is_data(hdr->frame_control)) {
- fc |= IEEE80211_FCTL_FROMDS;
- memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */
- memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */
- } else if (ieee80211_is_ctl(hdr->frame_control)) {
- /* control:ACK does not have addr2 or addr3 */
- eth_zero_addr(hdr->addr2);
- eth_zero_addr(hdr->addr3);
- } else {
- memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */
- memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */
- }
-
- hdr->frame_control = cpu_to_le16(fc);
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- meta->iface = iface;
- meta->tx_cb_idx = tx_cb_idx;
-
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb_reset_network_header(skb);
- dev_queue_xmit(skb);
-}
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-#ifdef CONFIG_PROC_FS
-static int prism2_sta_proc_show(struct seq_file *m, void *v)
-{
- struct sta_info *sta = m->private;
- int i;
-
- /* FIX: possible race condition.. the STA data could have just expired,
- * but proc entry was still here so that the read could have started;
- * some locking should be done here.. */
-
- seq_printf(m,
- "%s=%pM\nusers=%d\naid=%d\n"
- "flags=0x%04x%s%s%s%s%s%s%s\n"
- "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
- sta->ap ? "AP" : "STA",
- sta->addr, atomic_read(&sta->users), sta->aid,
- sta->flags,
- sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
- sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
- sta->flags & WLAN_STA_PS ? " PS" : "",
- sta->flags & WLAN_STA_TIM ? " TIM" : "",
- sta->flags & WLAN_STA_PERM ? " PERM" : "",
- sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "",
- sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "",
- sta->capability, sta->listen_interval);
- /* supported_rates: 500 kbit/s units with msb ignored */
- for (i = 0; i < sizeof(sta->supported_rates); i++)
- if (sta->supported_rates[i] != 0)
- seq_printf(m, "%d%sMbps ",
- (sta->supported_rates[i] & 0x7f) / 2,
- sta->supported_rates[i] & 1 ? ".5" : "");
- seq_printf(m,
- "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n"
- "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n"
- "tx_packets=%lu\n"
- "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n"
- "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n"
- "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n"
- "tx[11M]=%d\n"
- "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n",
- jiffies, sta->last_auth, sta->last_assoc, sta->last_rx,
- sta->last_tx,
- sta->rx_packets, sta->tx_packets, sta->rx_bytes,
- sta->tx_bytes, skb_queue_len(&sta->tx_buf),
- sta->last_rx_silence,
- sta->last_rx_signal, sta->last_rx_rate / 10,
- sta->last_rx_rate % 10 ? ".5" : "",
- sta->tx_rate, sta->tx_count[0], sta->tx_count[1],
- sta->tx_count[2], sta->tx_count[3], sta->rx_count[0],
- sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]);
- if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats)
- sta->crypt->ops->print_stats(m, sta->crypt->priv);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (sta->ap) {
- if (sta->u.ap.channel >= 0)
- seq_printf(m, "channel=%d\n", sta->u.ap.channel);
- seq_puts(m, "ssid=");
- for (i = 0; i < sta->u.ap.ssid_len; i++) {
- if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127)
- seq_putc(m, sta->u.ap.ssid[i]);
- else
- seq_printf(m, "<%02x>", sta->u.ap.ssid[i]);
- }
- seq_putc(m, '\n');
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- return 0;
-}
-#endif
-
-static void handle_add_proc_queue(struct work_struct *work)
-{
- struct ap_data *ap = container_of(work, struct ap_data,
- add_sta_proc_queue);
- struct sta_info *sta;
- char name[20];
- struct add_sta_proc_data *entry, *prev;
-
- entry = ap->add_sta_proc_entries;
- ap->add_sta_proc_entries = NULL;
-
- while (entry) {
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, entry->addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (sta) {
- sprintf(name, "%pM", sta->addr);
- sta->proc = proc_create_single_data(
- name, 0, ap->proc,
- prism2_sta_proc_show, sta);
-
- atomic_dec(&sta->users);
- }
-
- prev = entry;
- entry = entry->next;
- kfree(prev);
- }
-}
-
-
-static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr)
-{
- struct sta_info *sta;
-
- sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC);
- if (sta == NULL) {
- PDEBUG(DEBUG_AP, "AP: kmalloc failed\n");
- return NULL;
- }
-
- /* initialize STA info data */
- sta->local = ap->local;
- skb_queue_head_init(&sta->tx_buf);
- memcpy(sta->addr, addr, ETH_ALEN);
-
- atomic_inc(&sta->users);
- spin_lock_bh(&ap->sta_table_lock);
- list_add(&sta->list, &ap->sta_list);
- ap->num_sta++;
- ap_sta_hash_add(ap, sta);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (ap->proc) {
- struct add_sta_proc_data *entry;
- /* schedule a non-interrupt context process to add a procfs
- * entry for the STA since procfs code use GFP_KERNEL */
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry) {
- memcpy(entry->addr, sta->addr, ETH_ALEN);
- entry->next = ap->add_sta_proc_entries;
- ap->add_sta_proc_entries = entry;
- schedule_work(&ap->add_sta_proc_queue);
- } else
- printk(KERN_DEBUG "Failed to add STA proc data\n");
- }
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- timer_setup(&sta->timer, ap_handle_timer, 0);
- sta->timer.expires = jiffies + ap->max_inactivity;
- if (!ap->local->hostapd)
- add_timer(&sta->timer);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- return sta;
-}
-
-
-static int ap_tx_rate_ok(int rateidx, struct sta_info *sta,
- local_info_t *local)
-{
- if (rateidx > sta->tx_max_rate ||
- !(sta->tx_supp_rates & (1 << rateidx)))
- return 0;
-
- if (local->tx_rate_control != 0 &&
- !(local->tx_rate_control & (1 << rateidx)))
- return 0;
-
- return 1;
-}
-
-
-static void prism2_check_tx_rates(struct sta_info *sta)
-{
- int i;
-
- sta->tx_supp_rates = 0;
- for (i = 0; i < sizeof(sta->supported_rates); i++) {
- if ((sta->supported_rates[i] & 0x7f) == 2)
- sta->tx_supp_rates |= WLAN_RATE_1M;
- if ((sta->supported_rates[i] & 0x7f) == 4)
- sta->tx_supp_rates |= WLAN_RATE_2M;
- if ((sta->supported_rates[i] & 0x7f) == 11)
- sta->tx_supp_rates |= WLAN_RATE_5M5;
- if ((sta->supported_rates[i] & 0x7f) == 22)
- sta->tx_supp_rates |= WLAN_RATE_11M;
- }
- sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0;
- if (sta->tx_supp_rates & WLAN_RATE_1M) {
- sta->tx_max_rate = 0;
- if (ap_tx_rate_ok(0, sta, sta->local)) {
- sta->tx_rate = 10;
- sta->tx_rate_idx = 0;
- }
- }
- if (sta->tx_supp_rates & WLAN_RATE_2M) {
- sta->tx_max_rate = 1;
- if (ap_tx_rate_ok(1, sta, sta->local)) {
- sta->tx_rate = 20;
- sta->tx_rate_idx = 1;
- }
- }
- if (sta->tx_supp_rates & WLAN_RATE_5M5) {
- sta->tx_max_rate = 2;
- if (ap_tx_rate_ok(2, sta, sta->local)) {
- sta->tx_rate = 55;
- sta->tx_rate_idx = 2;
- }
- }
- if (sta->tx_supp_rates & WLAN_RATE_11M) {
- sta->tx_max_rate = 3;
- if (ap_tx_rate_ok(3, sta, sta->local)) {
- sta->tx_rate = 110;
- sta->tx_rate_idx = 3;
- }
- }
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static void ap_crypt_init(struct ap_data *ap)
-{
- ap->crypt = lib80211_get_crypto_ops("WEP");
-
- if (ap->crypt) {
- if (ap->crypt->init) {
- ap->crypt_priv = ap->crypt->init(0);
- if (ap->crypt_priv == NULL)
- ap->crypt = NULL;
- else {
- u8 key[WEP_KEY_LEN];
- get_random_bytes(key, WEP_KEY_LEN);
- ap->crypt->set_key(key, WEP_KEY_LEN, NULL,
- ap->crypt_priv);
- }
- }
- }
-
- if (ap->crypt == NULL) {
- printk(KERN_WARNING "AP could not initialize WEP: load module "
- "lib80211_crypt_wep.ko\n");
- }
-}
-
-
-/* Generate challenge data for shared key authentication. IEEE 802.11 specifies
- * that WEP algorithm is used for generating challenge. This should be unique,
- * but otherwise there is not really need for randomness etc. Initialize WEP
- * with pseudo random key and then use increasing IV to get unique challenge
- * streams.
- *
- * Called only as a scheduled task for pending AP frames.
- */
-static char * ap_auth_make_challenge(struct ap_data *ap)
-{
- char *tmpbuf;
- struct sk_buff *skb;
-
- if (ap->crypt == NULL) {
- ap_crypt_init(ap);
- if (ap->crypt == NULL)
- return NULL;
- }
-
- tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC);
- if (tmpbuf == NULL) {
- PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n");
- return NULL;
- }
-
- skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN +
- ap->crypt->extra_mpdu_prefix_len +
- ap->crypt->extra_mpdu_postfix_len);
- if (skb == NULL) {
- kfree(tmpbuf);
- return NULL;
- }
-
- skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len);
- skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN);
- if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) {
- dev_kfree_skb(skb);
- kfree(tmpbuf);
- return NULL;
- }
-
- skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len,
- tmpbuf, WLAN_AUTH_CHALLENGE_LEN);
- dev_kfree_skb(skb);
-
- return tmpbuf;
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_authen(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- size_t hdrlen;
- struct ap_data *ap = local->ap;
- char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
- int len, olen;
- u16 auth_alg, auth_transaction, status_code;
- __le16 *pos;
- u16 resp = WLAN_STATUS_SUCCESS;
- struct sta_info *sta = NULL;
- struct lib80211_crypt_data *crypt;
- char *txt = "";
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
-
- if (len < 6) {
- PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
- "(len=%d) from %pM\n", dev->name, len, hdr->addr2);
- return;
- }
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta && sta->crypt)
- crypt = sta->crypt;
- else {
- int idx = 0;
- if (skb->len >= hdrlen + 3)
- idx = skb->data[hdrlen + 3] >> 6;
- crypt = local->crypt_info.crypt[idx];
- }
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- auth_alg = __le16_to_cpu(*pos);
- pos++;
- auth_transaction = __le16_to_cpu(*pos);
- pos++;
- status_code = __le16_to_cpu(*pos);
- pos++;
-
- if (ether_addr_equal(dev->dev_addr, hdr->addr2) ||
- ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) {
- txt = "authentication denied";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- if (((local->auth_algs & PRISM2_AUTH_OPEN) &&
- auth_alg == WLAN_AUTH_OPEN) ||
- ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) &&
- crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) {
- } else {
- txt = "unsupported algorithm";
- resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
- goto fail;
- }
-
- if (len >= 8) {
- u8 *u = (u8 *) pos;
- if (*u == WLAN_EID_CHALLENGE) {
- if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) {
- txt = "invalid challenge len";
- resp = WLAN_STATUS_CHALLENGE_FAIL;
- goto fail;
- }
- if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) {
- txt = "challenge underflow";
- resp = WLAN_STATUS_CHALLENGE_FAIL;
- goto fail;
- }
- challenge = (char *) (u + 2);
- }
- }
-
- if (sta && sta->ap) {
- if (time_after(jiffies, sta->u.ap.last_beacon +
- (10 * sta->listen_interval * HZ) / 1024)) {
- PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
- " assuming AP %pM is now STA\n",
- dev->name, sta->addr);
- sta->ap = 0;
- sta->flags = 0;
- sta->u.sta.challenge = NULL;
- } else {
- txt = "AP trying to authenticate?";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- }
-
- if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) ||
- (auth_alg == WLAN_AUTH_SHARED_KEY &&
- (auth_transaction == 1 ||
- (auth_transaction == 3 && sta != NULL &&
- sta->u.sta.challenge != NULL)))) {
- } else {
- txt = "unknown authentication transaction number";
- resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
- goto fail;
- }
-
- if (sta == NULL) {
- txt = "new STA";
-
- if (local->ap->num_sta >= MAX_STA_COUNT) {
- /* FIX: might try to remove some old STAs first? */
- txt = "no more room for new STAs";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- sta = ap_add_sta(local->ap, hdr->addr2);
- if (sta == NULL) {
- txt = "ap_add_sta failed";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- }
-
- switch (auth_alg) {
- case WLAN_AUTH_OPEN:
- txt = "authOK";
- /* IEEE 802.11 standard is not completely clear about
- * whether STA is considered authenticated after
- * authentication OK frame has been send or after it
- * has been ACKed. In order to reduce interoperability
- * issues, mark the STA authenticated before ACK. */
- sta->flags |= WLAN_STA_AUTH;
- break;
-
- case WLAN_AUTH_SHARED_KEY:
- if (auth_transaction == 1) {
- if (sta->u.sta.challenge == NULL) {
- sta->u.sta.challenge =
- ap_auth_make_challenge(local->ap);
- if (sta->u.sta.challenge == NULL) {
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- }
- } else {
- if (sta->u.sta.challenge == NULL ||
- challenge == NULL ||
- memcmp(sta->u.sta.challenge, challenge,
- WLAN_AUTH_CHALLENGE_LEN) != 0 ||
- !ieee80211_has_protected(hdr->frame_control)) {
- txt = "challenge response incorrect";
- resp = WLAN_STATUS_CHALLENGE_FAIL;
- goto fail;
- }
-
- txt = "challenge OK - authOK";
- /* IEEE 802.11 standard is not completely clear about
- * whether STA is considered authenticated after
- * authentication OK frame has been send or after it
- * has been ACKed. In order to reduce interoperability
- * issues, mark the STA authenticated before ACK. */
- sta->flags |= WLAN_STA_AUTH;
- kfree(sta->u.sta.challenge);
- sta->u.sta.challenge = NULL;
- }
- break;
- }
-
- fail:
- pos = (__le16 *) body;
- *pos = cpu_to_le16(auth_alg);
- pos++;
- *pos = cpu_to_le16(auth_transaction + 1);
- pos++;
- *pos = cpu_to_le16(resp); /* status_code */
- pos++;
- olen = 6;
-
- if (resp == WLAN_STATUS_SUCCESS && sta != NULL &&
- sta->u.sta.challenge != NULL &&
- auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) {
- u8 *tmp = (u8 *) pos;
- *tmp++ = WLAN_EID_CHALLENGE;
- *tmp++ = WLAN_AUTH_CHALLENGE_LEN;
- pos++;
- memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN);
- olen += 2 + WLAN_AUTH_CHALLENGE_LEN;
- }
-
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH,
- body, olen, hdr->addr2, ap->tx_callback_auth);
-
- if (sta) {
- sta->last_rx = jiffies;
- atomic_dec(&sta->users);
- }
-
- if (resp) {
- PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d "
- "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
- dev->name, hdr->addr2,
- auth_alg, auth_transaction, status_code, len,
- le16_to_cpu(hdr->frame_control), resp, txt);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_assoc(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats, int reassoc)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char body[12], *p, *lpos;
- int len, left;
- __le16 *pos;
- u16 resp = WLAN_STATUS_SUCCESS;
- struct sta_info *sta = NULL;
- int send_deauth = 0;
- char __always_unused *txt = "";
- u8 prev_ap[ETH_ALEN];
-
- left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < (reassoc ? 10 : 4)) {
- PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
- "(len=%d, reassoc=%d) from %pM\n",
- dev->name, len, reassoc, hdr->addr2);
- return;
- }
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
- spin_unlock_bh(&local->ap->sta_table_lock);
- txt = "trying to associate before authentication";
- send_deauth = 1;
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- sta = NULL; /* do not decrement sta->users */
- goto fail;
- }
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- sta->capability = __le16_to_cpu(*pos);
- pos++; left -= 2;
- sta->listen_interval = __le16_to_cpu(*pos);
- pos++; left -= 2;
-
- if (reassoc) {
- memcpy(prev_ap, pos, ETH_ALEN);
- pos++; pos++; pos++; left -= 6;
- } else
- eth_zero_addr(prev_ap);
-
- if (left >= 2) {
- unsigned int ileft;
- unsigned char *u = (unsigned char *) pos;
-
- if (*u == WLAN_EID_SSID) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft > MAX_SSID_LEN) {
- txt = "SSID overflow";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- if (ileft != strlen(local->essid) ||
- memcmp(local->essid, u, ileft) != 0) {
- txt = "not our SSID";
- resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC;
- goto fail;
- }
-
- u += ileft;
- left -= ileft;
- }
-
- if (left >= 2 && *u == WLAN_EID_SUPP_RATES) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft == 0 ||
- ileft > WLAN_SUPP_RATES_MAX) {
- txt = "SUPP_RATES len error";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- memset(sta->supported_rates, 0,
- sizeof(sta->supported_rates));
- memcpy(sta->supported_rates, u, ileft);
- prism2_check_tx_rates(sta);
-
- u += ileft;
- left -= ileft;
- }
-
- if (left > 0) {
- PDEBUG(DEBUG_AP, "%s: assoc from %pM"
- " with extra data (%d bytes) [",
- dev->name, hdr->addr2, left);
- while (left > 0) {
- PDEBUG2(DEBUG_AP, "<%02x>", *u);
- u++; left--;
- }
- PDEBUG2(DEBUG_AP, "]\n");
- }
- } else {
- txt = "frame underflow";
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
-
- /* get a unique AID */
- if (sta->aid > 0)
- txt = "OK, old AID";
- else {
- spin_lock_bh(&local->ap->sta_table_lock);
- for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
- if (local->ap->sta_aid[sta->aid - 1] == NULL)
- break;
- if (sta->aid > MAX_AID_TABLE_SIZE) {
- sta->aid = 0;
- spin_unlock_bh(&local->ap->sta_table_lock);
- resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
- txt = "no room for more AIDs";
- } else {
- local->ap->sta_aid[sta->aid - 1] = sta;
- spin_unlock_bh(&local->ap->sta_table_lock);
- txt = "OK, new AID";
- }
- }
-
- fail:
- pos = (__le16 *) body;
-
- if (send_deauth) {
- *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH);
- pos++;
- } else {
- /* FIX: CF-Pollable and CF-PollReq should be set to match the
- * values in beacons/probe responses */
- /* FIX: how about privacy and WEP? */
- /* capability */
- *pos = cpu_to_le16(WLAN_CAPABILITY_ESS);
- pos++;
-
- /* status_code */
- *pos = cpu_to_le16(resp);
- pos++;
-
- *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) |
- BIT(14) | BIT(15)); /* AID */
- pos++;
-
- /* Supported rates (Information element) */
- p = (char *) pos;
- *p++ = WLAN_EID_SUPP_RATES;
- lpos = p;
- *p++ = 0; /* len */
- if (local->tx_rate_control & WLAN_RATE_1M) {
- *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02;
- (*lpos)++;
- }
- if (local->tx_rate_control & WLAN_RATE_2M) {
- *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04;
- (*lpos)++;
- }
- if (local->tx_rate_control & WLAN_RATE_5M5) {
- *p++ = local->basic_rates & WLAN_RATE_5M5 ?
- 0x8b : 0x0b;
- (*lpos)++;
- }
- if (local->tx_rate_control & WLAN_RATE_11M) {
- *p++ = local->basic_rates & WLAN_RATE_11M ?
- 0x96 : 0x16;
- (*lpos)++;
- }
- pos = (__le16 *) p;
- }
-
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
- (send_deauth ? IEEE80211_STYPE_DEAUTH :
- (reassoc ? IEEE80211_STYPE_REASSOC_RESP :
- IEEE80211_STYPE_ASSOC_RESP)),
- body, (u8 *) pos - (u8 *) body,
- hdr->addr2,
- send_deauth ? 0 : local->ap->tx_callback_assoc);
-
- if (sta) {
- if (resp == WLAN_STATUS_SUCCESS) {
- sta->last_rx = jiffies;
- /* STA will be marked associated from TX callback, if
- * AssocResp is ACKed */
- }
- atomic_dec(&sta->users);
- }
-
-#if 0
- PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d "
- "prev_ap=%pM) => %d(%d) (%s)\n",
- dev->name,
- hdr->addr2,
- reassoc ? "re" : "", len,
- prev_ap,
- resp, send_deauth, txt);
-#endif
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_deauth(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
- int len;
- u16 reason_code;
- __le16 *pos;
- struct sta_info *sta = NULL;
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < 2) {
- printk("handle_deauth - too short payload (len=%d)\n", len);
- return;
- }
-
- pos = (__le16 *) body;
- reason_code = le16_to_cpu(*pos);
-
- PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, "
- "reason_code=%d\n", dev->name, hdr->addr2,
- len, reason_code);
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta != NULL) {
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(local->dev, sta);
- sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
- }
- spin_unlock_bh(&local->ap->sta_table_lock);
- if (sta == NULL) {
- printk("%s: deauthentication from %pM, "
- "reason_code=%d, but STA not authenticated\n", dev->name,
- hdr->addr2, reason_code);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
- int len;
- u16 reason_code;
- __le16 *pos;
- struct sta_info *sta = NULL;
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < 2) {
- printk("handle_disassoc - too short payload (len=%d)\n", len);
- return;
- }
-
- pos = (__le16 *) body;
- reason_code = le16_to_cpu(*pos);
-
- PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, "
- "reason_code=%d\n", dev->name, hdr->addr2,
- len, reason_code);
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta != NULL) {
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- hostap_event_expired_sta(local->dev, sta);
- sta->flags &= ~WLAN_STA_ASSOC;
- }
- spin_unlock_bh(&local->ap->sta_table_lock);
- if (sta == NULL) {
- printk("%s: disassociation from %pM, "
- "reason_code=%d, but STA not authenticated\n",
- dev->name, hdr->addr2, reason_code);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void ap_handle_data_nullfunc(local_info_t *local,
- struct ieee80211_hdr *hdr)
-{
- struct net_device *dev = local->dev;
-
- /* some STA f/w's seem to require control::ACK frame for
- * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does
- * not send this..
- * send control::ACK for the data::nullfunc */
-
- printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n");
- prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK,
- NULL, 0, hdr->addr2, 0);
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void ap_handle_dropped_data(local_info_t *local,
- struct ieee80211_hdr *hdr)
-{
- struct net_device *dev = local->dev;
- struct sta_info *sta;
- __le16 reason;
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) {
- PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n");
- atomic_dec(&sta->users);
- return;
- }
-
- reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
- prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT |
- ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ?
- IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC),
- (char *) &reason, sizeof(reason), hdr->addr2, 0);
-
- if (sta)
- atomic_dec(&sta->users);
-}
-
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta,
- struct sk_buff *skb)
-{
- struct hostap_skb_tx_data *meta;
-
- if (!(sta->flags & WLAN_STA_PS)) {
- /* Station has moved to non-PS mode, so send all buffered
- * frames using normal device queue. */
- dev_queue_xmit(skb);
- return;
- }
-
- /* add a flag for hostap_handle_sta_tx() to know that this skb should
- * be passed through even though STA is using PS */
- meta = (struct hostap_skb_tx_data *) skb->cb;
- meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME;
- if (!skb_queue_empty(&sta->tx_buf)) {
- /* indicate to STA that more frames follow */
- meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA;
- }
- dev_queue_xmit(skb);
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_pspoll(local_info_t *local,
- struct ieee80211_hdr *hdr,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct net_device *dev = local->dev;
- struct sta_info *sta;
- u16 aid;
- struct sk_buff *skb;
-
- PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n",
- hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control));
-
- if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- PDEBUG(DEBUG_AP,
- "handle_pspoll - addr1(BSSID)=%pM not own MAC\n",
- hdr->addr1);
- return;
- }
-
- aid = le16_to_cpu(hdr->duration_id);
- if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) {
- PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n");
- return;
- }
- aid &= ~(BIT(15) | BIT(14));
- if (aid == 0 || aid > MAX_AID_TABLE_SIZE) {
- PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid);
- return;
- }
- PDEBUG(DEBUG_PS2, " aid=%d\n", aid);
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta == NULL) {
- PDEBUG(DEBUG_PS, " STA not found\n");
- return;
- }
- if (sta->aid != aid) {
- PDEBUG(DEBUG_PS, " received aid=%i does not match with "
- "assoc.aid=%d\n", aid, sta->aid);
- return;
- }
-
- /* FIX: todo:
- * - add timeout for buffering (clear aid in TIM vector if buffer timed
- * out (expiry time must be longer than ListenInterval for
- * the corresponding STA; "8802-11: 11.2.1.9 AP aging function"
- * - what to do, if buffered, pspolled, and sent frame is not ACKed by
- * sta; store buffer for later use and leave TIM aid bit set? use
- * TX event to check whether frame was ACKed?
- */
-
- while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) {
- /* send buffered frame .. */
- PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL"
- " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf));
-
- pspoll_send_buffered(local, sta, skb);
-
- if (sta->flags & WLAN_STA_PS) {
- /* send only one buffered packet per PS Poll */
- /* FIX: should ignore further PS Polls until the
- * buffered packet that was just sent is acknowledged
- * (Tx or TxExc event) */
- break;
- }
- }
-
- if (skb_queue_empty(&sta->tx_buf)) {
- /* try to clear aid from TIM */
- if (!(sta->flags & WLAN_STA_TIM))
- PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n",
- aid);
- hostap_set_tim(local, aid, 0);
- sta->flags &= ~WLAN_STA_TIM;
- }
-
- atomic_dec(&sta->users);
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-
-static void handle_wds_oper_queue(struct work_struct *work)
-{
- struct ap_data *ap = container_of(work, struct ap_data,
- wds_oper_queue);
- local_info_t *local = ap->local;
- struct wds_oper_data *entry, *prev;
-
- spin_lock_bh(&local->lock);
- entry = local->ap->wds_oper_entries;
- local->ap->wds_oper_entries = NULL;
- spin_unlock_bh(&local->lock);
-
- while (entry) {
- PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
- "to AP %pM\n",
- local->dev->name,
- entry->type == WDS_ADD ? "adding" : "removing",
- entry->addr);
- if (entry->type == WDS_ADD)
- prism2_wds_add(local, entry->addr, 0);
- else if (entry->type == WDS_DEL)
- prism2_wds_del(local, entry->addr, 0, 1);
-
- prev = entry;
- entry = entry->next;
- kfree(prev);
- }
-}
-
-
-/* Called only as a scheduled task for pending AP frames. */
-static void handle_beacon(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
- int len, left;
- u16 beacon_int, capability;
- __le16 *pos;
- char *ssid = NULL;
- unsigned char *supp_rates = NULL;
- int ssid_len = 0, supp_rates_len = 0;
- struct sta_info *sta = NULL;
- int new_sta = 0, channel = -1;
-
- len = skb->len - IEEE80211_MGMT_HDR_LEN;
-
- if (len < 8 + 2 + 2) {
- printk(KERN_DEBUG "handle_beacon - too short payload "
- "(len=%d)\n", len);
- return;
- }
-
- pos = (__le16 *) body;
- left = len;
-
- /* Timestamp (8 octets) */
- pos += 4; left -= 8;
- /* Beacon interval (2 octets) */
- beacon_int = le16_to_cpu(*pos);
- pos++; left -= 2;
- /* Capability information (2 octets) */
- capability = le16_to_cpu(*pos);
- pos++; left -= 2;
-
- if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS &&
- capability & WLAN_CAPABILITY_IBSS)
- return;
-
- if (left >= 2) {
- unsigned int ileft;
- unsigned char *u = (unsigned char *) pos;
-
- if (*u == WLAN_EID_SSID) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft > MAX_SSID_LEN) {
- PDEBUG(DEBUG_AP, "SSID: overflow\n");
- return;
- }
-
- if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID &&
- (ileft != strlen(local->essid) ||
- memcmp(local->essid, u, ileft) != 0)) {
- /* not our SSID */
- return;
- }
-
- ssid = u;
- ssid_len = ileft;
-
- u += ileft;
- left -= ileft;
- }
-
- if (*u == WLAN_EID_SUPP_RATES) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft == 0 || ileft > 8) {
- PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n");
- return;
- }
-
- supp_rates = u;
- supp_rates_len = ileft;
-
- u += ileft;
- left -= ileft;
- }
-
- if (*u == WLAN_EID_DS_PARAMS) {
- u++; left--;
- ileft = *u;
- u++; left--;
-
- if (ileft > left || ileft != 1) {
- PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n");
- return;
- }
-
- channel = *u;
-
- u += ileft;
- left -= ileft;
- }
- }
-
- spin_lock_bh(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta != NULL)
- atomic_inc(&sta->users);
- spin_unlock_bh(&local->ap->sta_table_lock);
-
- if (sta == NULL) {
- /* add new AP */
- new_sta = 1;
- sta = ap_add_sta(local->ap, hdr->addr2);
- if (sta == NULL) {
- printk(KERN_INFO "prism2: kmalloc failed for AP "
- "data structure\n");
- return;
- }
- hostap_event_new_sta(local->dev, sta);
-
- /* mark APs authentication and associated for pseudo ad-hoc
- * style communication */
- sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
-
- if (local->ap->autom_ap_wds) {
- hostap_wds_link_oper(local, sta->addr, WDS_ADD);
- }
- }
-
- sta->ap = 1;
- if (ssid) {
- sta->u.ap.ssid_len = ssid_len;
- memcpy(sta->u.ap.ssid, ssid, ssid_len);
- sta->u.ap.ssid[ssid_len] = '\0';
- } else {
- sta->u.ap.ssid_len = 0;
- sta->u.ap.ssid[0] = '\0';
- }
- sta->u.ap.channel = channel;
- sta->rx_packets++;
- sta->rx_bytes += len;
- sta->u.ap.last_beacon = sta->last_rx = jiffies;
- sta->capability = capability;
- sta->listen_interval = beacon_int;
-
- atomic_dec(&sta->users);
-
- if (new_sta) {
- memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
- memcpy(sta->supported_rates, supp_rates, supp_rates_len);
- prism2_check_tx_rates(sta);
- }
-}
-
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-/* Called only as a tasklet. */
-static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- struct net_device *dev = local->dev;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- u16 fc, type, stype;
- struct ieee80211_hdr *hdr;
-
- /* FIX: should give skb->len to handler functions and check that the
- * buffer is long enough */
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- type = fc & IEEE80211_FCTL_FTYPE;
- stype = fc & IEEE80211_FCTL_STYPE;
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (!local->hostapd && type == IEEE80211_FTYPE_DATA) {
- PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n");
-
- if (!(fc & IEEE80211_FCTL_TODS) ||
- (fc & IEEE80211_FCTL_FROMDS)) {
- if (stype == IEEE80211_STYPE_NULLFUNC) {
- /* no ToDS nullfunc seems to be used to check
- * AP association; so send reject message to
- * speed up re-association */
- ap_handle_dropped_data(local, hdr);
- goto done;
- }
- PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n",
- fc);
- goto done;
- }
-
- if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM"
- " not own MAC\n", hdr->addr1);
- goto done;
- }
-
- if (local->ap->nullfunc_ack &&
- stype == IEEE80211_STYPE_NULLFUNC)
- ap_handle_data_nullfunc(local, hdr);
- else
- ap_handle_dropped_data(local, hdr);
- goto done;
- }
-
- if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) {
- handle_beacon(local, skb, rx_stats);
- goto done;
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) {
- handle_pspoll(local, hdr, rx_stats);
- goto done;
- }
-
- if (local->hostapd) {
- PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x "
- "subtype=0x%02x\n", type, stype);
- goto done;
- }
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (type != IEEE80211_FTYPE_MGMT) {
- PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n");
- goto done;
- }
-
- if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM"
- " not own MAC\n", hdr->addr1);
- goto done;
- }
-
- if (!ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM"
- " not own MAC\n", hdr->addr3);
- goto done;
- }
-
- switch (stype) {
- case IEEE80211_STYPE_ASSOC_REQ:
- handle_assoc(local, skb, rx_stats, 0);
- break;
- case IEEE80211_STYPE_ASSOC_RESP:
- PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n");
- break;
- case IEEE80211_STYPE_REASSOC_REQ:
- handle_assoc(local, skb, rx_stats, 1);
- break;
- case IEEE80211_STYPE_REASSOC_RESP:
- PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n");
- break;
- case IEEE80211_STYPE_ATIM:
- PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n");
- break;
- case IEEE80211_STYPE_DISASSOC:
- handle_disassoc(local, skb, rx_stats);
- break;
- case IEEE80211_STYPE_AUTH:
- handle_authen(local, skb, rx_stats);
- break;
- case IEEE80211_STYPE_DEAUTH:
- handle_deauth(local, skb, rx_stats);
- break;
- default:
- PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n",
- stype >> 4);
- break;
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- done:
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-void hostap_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ieee80211_hdr *hdr;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (skb->len < 16)
- goto drop;
-
- dev->stats.rx_packets++;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL &&
- ieee80211_is_beacon(hdr->frame_control))
- goto drop;
-
- skb->protocol = cpu_to_be16(ETH_P_HOSTAP);
- handle_ap_item(local, skb, rx_stats);
- return;
-
- drop:
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
-{
- struct sk_buff *skb;
- struct ieee80211_hdr *hdr;
- struct hostap_80211_rx_status rx_stats;
-
- if (skb_queue_empty(&sta->tx_buf))
- return;
-
- skb = dev_alloc_skb(16);
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc "
- "failed\n", local->dev->name);
- return;
- }
-
- hdr = skb_put(skb, 16);
-
- /* Generate a fake pspoll frame to start packet delivery */
- hdr->frame_control = cpu_to_le16(
- IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
- memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN);
- memcpy(hdr->addr2, sta->addr, ETH_ALEN);
- hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
-
- PDEBUG(DEBUG_PS2,
- "%s: Scheduling buffered packet delivery for STA %pM\n",
- local->dev->name, sta->addr);
-
- skb->dev = local->dev;
-
- memset(&rx_stats, 0, sizeof(rx_stats));
- hostap_rx(local->dev, skb, &rx_stats);
-}
-
-
-int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[],
- struct iw_quality qual[], int buf_size,
- int aplist)
-{
- struct ap_data *ap = local->ap;
- struct list_head *ptr;
- int count = 0;
-
- spin_lock_bh(&ap->sta_table_lock);
-
- for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
- ptr = ptr->next) {
- struct sta_info *sta = (struct sta_info *) ptr;
-
- if (aplist && !sta->ap)
- continue;
- addr[count].sa_family = ARPHRD_ETHER;
- memcpy(addr[count].sa_data, sta->addr, ETH_ALEN);
- if (sta->last_rx_silence == 0)
- qual[count].qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
- else
- qual[count].qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
- qual[count].updated = sta->last_rx_updated;
-
- sta->last_rx_updated = IW_QUAL_DBM;
-
- count++;
- if (count >= buf_size)
- break;
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- return count;
-}
-
-
-/* Translate our list of Access Points & Stations to a card independent
- * format that the Wireless Tools will understand - Jean II */
-int prism2_ap_translate_scan(struct net_device *dev,
- struct iw_request_info *info, char *buffer)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct ap_data *ap;
- struct list_head *ptr;
- struct iw_event iwe;
- char *current_ev = buffer;
- char *end_buf = buffer + IW_SCAN_MAX_DATA;
-#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT)
- char buf[64];
-#endif
-
- iface = netdev_priv(dev);
- local = iface->local;
- ap = local->ap;
-
- spin_lock_bh(&ap->sta_table_lock);
-
- for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list;
- ptr = ptr->next) {
- struct sta_info *sta = (struct sta_info *) ptr;
-
- /* First entry *MUST* be the AP MAC address */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN);
- iwe.len = IW_EV_ADDR_LEN;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Use the mode to indicate if it's a station or
- * an Access Point */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWMODE;
- if (sta->ap)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_INFRA;
- iwe.len = IW_EV_UINT_LEN;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
-
- /* Some quality */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVQUAL;
- if (sta->last_rx_silence == 0)
- iwe.u.qual.qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
- else
- iwe.u.qual.qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
- iwe.u.qual.updated = sta->last_rx_updated;
- iwe.len = IW_EV_QUAL_LEN;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (sta->ap) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = sta->u.ap.ssid_len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe,
- sta->u.ap.ssid);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWENCODE;
- if (sta->capability & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags =
- IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe,
- sta->u.ap.ssid);
-
- if (sta->u.ap.channel > 0 &&
- sta->u.ap.channel <= FREQ_COUNT) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = freq_list[sta->u.ap.channel - 1]
- * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(
- info, current_ev, end_buf, &iwe,
- IW_EV_FREQ_LEN);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "beacon_interval=%d",
- sta->listen_interval);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe, buf);
- }
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- sta->last_rx_updated = IW_QUAL_DBM;
-
- /* To be continued, we should make good use of IWEVCUSTOM */
- }
-
- spin_unlock_bh(&ap->sta_table_lock);
-
- return current_ev - buffer;
-}
-
-
-static int prism2_hostapd_add_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (sta == NULL) {
- sta = ap_add_sta(ap, param->sta_addr);
- if (sta == NULL)
- return -1;
- }
-
- if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_new_sta(sta->local->dev, sta);
-
- sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
- sta->last_rx = jiffies;
- sta->aid = param->u.add_sta.aid;
- sta->capability = param->u.add_sta.capability;
- sta->tx_supp_rates = param->u.add_sta.tx_supp_rates;
- if (sta->tx_supp_rates & WLAN_RATE_1M)
- sta->supported_rates[0] = 2;
- if (sta->tx_supp_rates & WLAN_RATE_2M)
- sta->supported_rates[1] = 4;
- if (sta->tx_supp_rates & WLAN_RATE_5M5)
- sta->supported_rates[2] = 11;
- if (sta->tx_supp_rates & WLAN_RATE_11M)
- sta->supported_rates[3] = 22;
- prism2_check_tx_rates(sta);
- atomic_dec(&sta->users);
- return 0;
-}
-
-
-static int prism2_hostapd_remove_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta) {
- ap_sta_hash_del(ap, sta);
- list_del(&sta->list);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local)
- hostap_event_expired_sta(sta->local->dev, sta);
- ap_free_sta(ap, sta);
-
- return 0;
-}
-
-
-static int prism2_hostapd_get_info_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ;
-
- atomic_dec(&sta->users);
-
- return 1;
-}
-
-
-static int prism2_hostapd_set_flags_sta(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta) {
- sta->flags |= param->u.set_flags_sta.flags_or;
- sta->flags &= param->u.set_flags_sta.flags_and;
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- return 0;
-}
-
-
-static int prism2_hostapd_sta_clear_stats(struct ap_data *ap,
- struct prism2_hostapd_param *param)
-{
- struct sta_info *sta;
- int rate;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, param->sta_addr);
- if (sta) {
- sta->rx_packets = sta->tx_packets = 0;
- sta->rx_bytes = sta->tx_bytes = 0;
- for (rate = 0; rate < WLAN_RATE_COUNT; rate++) {
- sta->tx_count[rate] = 0;
- sta->rx_count[rate] = 0;
- }
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta)
- return -ENOENT;
-
- return 0;
-}
-
-
-int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param)
-{
- switch (param->cmd) {
- case PRISM2_HOSTAPD_FLUSH:
- ap_control_kickall(ap);
- return 0;
- case PRISM2_HOSTAPD_ADD_STA:
- return prism2_hostapd_add_sta(ap, param);
- case PRISM2_HOSTAPD_REMOVE_STA:
- return prism2_hostapd_remove_sta(ap, param);
- case PRISM2_HOSTAPD_GET_INFO_STA:
- return prism2_hostapd_get_info_sta(ap, param);
- case PRISM2_HOSTAPD_SET_FLAGS_STA:
- return prism2_hostapd_set_flags_sta(ap, param);
- case PRISM2_HOSTAPD_STA_CLEAR_STATS:
- return prism2_hostapd_sta_clear_stats(ap, param);
- default:
- printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n",
- param->cmd);
- return -EOPNOTSUPP;
- }
-}
-
-
-/* Update station info for host-based TX rate control and return current
- * TX rate */
-static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev)
-{
- int ret = sta->tx_rate;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- sta->tx_count[sta->tx_rate_idx]++;
- sta->tx_since_last_failure++;
- sta->tx_consecutive_exc = 0;
- if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT &&
- sta->tx_rate_idx < sta->tx_max_rate) {
- /* use next higher rate */
- int old_rate, new_rate;
- old_rate = new_rate = sta->tx_rate_idx;
- while (new_rate < sta->tx_max_rate) {
- new_rate++;
- if (ap_tx_rate_ok(new_rate, sta, local)) {
- sta->tx_rate_idx = new_rate;
- break;
- }
- }
- if (old_rate != sta->tx_rate_idx) {
- switch (sta->tx_rate_idx) {
- case 0: sta->tx_rate = 10; break;
- case 1: sta->tx_rate = 20; break;
- case 2: sta->tx_rate = 55; break;
- case 3: sta->tx_rate = 110; break;
- default: sta->tx_rate = 0; break;
- }
- PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n",
- dev->name, sta->addr, sta->tx_rate);
- }
- sta->tx_since_last_failure = 0;
- }
-
- return ret;
-}
-
-
-/* Called only from software IRQ. Called for each TX frame prior possible
- * encryption and transmit. */
-ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
-{
- struct sta_info *sta = NULL;
- struct sk_buff *skb = tx->skb;
- int set_tim, ret;
- struct ieee80211_hdr *hdr;
- struct hostap_skb_tx_data *meta;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- ret = AP_TX_CONTINUE;
- if (local->ap == NULL || skb->len < 10 ||
- meta->iface->type == HOSTAP_INTERFACE_STA)
- goto out;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- if (hdr->addr1[0] & 0x01) {
- /* broadcast/multicast frame - no AP related processing */
- if (local->ap->num_sta <= 0)
- ret = AP_TX_DROP;
- goto out;
- }
-
- /* unicast packet - check whether destination STA is associated */
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr1);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (local->iw_mode == IW_MODE_MASTER && sta == NULL &&
- !(meta->flags & HOSTAP_TX_FLAGS_WDS) &&
- meta->iface->type != HOSTAP_INTERFACE_MASTER &&
- meta->iface->type != HOSTAP_INTERFACE_AP) {
-#if 0
- /* This can happen, e.g., when wlan0 is added to a bridge and
- * bridging code does not know which port is the correct target
- * for a unicast frame. In this case, the packet is send to all
- * ports of the bridge. Since this is a valid scenario, do not
- * print out any errors here. */
- if (net_ratelimit()) {
- printk(KERN_DEBUG "AP: drop packet to non-associated "
- "STA %pM\n", hdr->addr1);
- }
-#endif
- local->ap->tx_drop_nonassoc++;
- ret = AP_TX_DROP;
- goto out;
- }
-
- if (sta == NULL)
- goto out;
-
- if (!(sta->flags & WLAN_STA_AUTHORIZED))
- ret = AP_TX_CONTINUE_NOT_AUTHORIZED;
-
- /* Set tx_rate if using host-based TX rate control */
- if (!local->fw_tx_rate_control)
- local->ap->last_tx_rate = meta->rate =
- ap_update_sta_tx_rate(sta, local->dev);
-
- if (local->iw_mode != IW_MODE_MASTER)
- goto out;
-
- if (!(sta->flags & WLAN_STA_PS))
- goto out;
-
- if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) {
- /* indicate to STA that more frames follow */
- hdr->frame_control |=
- cpu_to_le16(IEEE80211_FCTL_MOREDATA);
- }
-
- if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) {
- /* packet was already buffered and now send due to
- * PS poll, so do not rebuffer it */
- goto out;
- }
-
- if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
- PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s"
- "PS mode buffer\n",
- local->dev->name, sta->addr);
- /* Make sure that TIM is set for the station (it might not be
- * after AP wlan hw reset). */
- /* FIX: should fix hw reset to restore bits based on STA
- * buffer state.. */
- hostap_set_tim(local, sta->aid, 1);
- sta->flags |= WLAN_STA_TIM;
- ret = AP_TX_DROP;
- goto out;
- }
-
- /* STA in PS mode, buffer frame for later delivery */
- set_tim = skb_queue_empty(&sta->tx_buf);
- skb_queue_tail(&sta->tx_buf, skb);
- /* FIX: could save RX time to skb and expire buffered frames after
- * some time if STA does not poll for them */
-
- if (set_tim) {
- if (sta->flags & WLAN_STA_TIM)
- PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n",
- sta->aid);
- hostap_set_tim(local, sta->aid, 1);
- sta->flags |= WLAN_STA_TIM;
- }
-
- ret = AP_TX_BUFFERED;
-
- out:
- if (sta != NULL) {
- if (ret == AP_TX_CONTINUE ||
- ret == AP_TX_CONTINUE_NOT_AUTHORIZED) {
- sta->tx_packets++;
- sta->tx_bytes += skb->len;
- sta->last_tx = jiffies;
- }
-
- if ((ret == AP_TX_CONTINUE ||
- ret == AP_TX_CONTINUE_NOT_AUTHORIZED) &&
- sta->crypt && tx->host_encrypt) {
- tx->crypt = sta->crypt;
- tx->sta_ptr = sta; /* hostap_handle_sta_release() will
- * be called to release sta info
- * later */
- } else
- atomic_dec(&sta->users);
- }
-
- return ret;
-}
-
-
-void hostap_handle_sta_release(void *ptr)
-{
- struct sta_info *sta = ptr;
- atomic_dec(&sta->users);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
-{
- struct sta_info *sta;
- struct ieee80211_hdr *hdr;
- struct hostap_skb_tx_data *meta;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- meta = (struct hostap_skb_tx_data *) skb->cb;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr1);
- if (!sta) {
- spin_unlock(&local->ap->sta_table_lock);
- PDEBUG(DEBUG_AP, "%s: Could not find STA %pM"
- " for this TX error (@%lu)\n",
- local->dev->name, hdr->addr1, jiffies);
- return;
- }
-
- sta->tx_since_last_failure = 0;
- sta->tx_consecutive_exc++;
-
- if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD &&
- sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) {
- /* use next lower rate */
- int old, rate;
- old = rate = sta->tx_rate_idx;
- while (rate > 0) {
- rate--;
- if (ap_tx_rate_ok(rate, sta, local)) {
- sta->tx_rate_idx = rate;
- break;
- }
- }
- if (old != sta->tx_rate_idx) {
- switch (sta->tx_rate_idx) {
- case 0: sta->tx_rate = 10; break;
- case 1: sta->tx_rate = 20; break;
- case 2: sta->tx_rate = 55; break;
- case 3: sta->tx_rate = 110; break;
- default: sta->tx_rate = 0; break;
- }
- PDEBUG(DEBUG_AP,
- "%s: STA %pM TX rate lowered to %d\n",
- local->dev->name, sta->addr, sta->tx_rate);
- }
- sta->tx_consecutive_exc = 0;
- }
- spin_unlock(&local->ap->sta_table_lock);
-}
-
-
-static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
- int pwrmgt, int type, int stype)
-{
- if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
- sta->flags |= WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA %pM changed to use PS "
- "mode (type=0x%02X, stype=0x%02X)\n",
- sta->addr, type >> 2, stype >> 4);
- } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
- sta->flags &= ~WLAN_STA_PS;
- PDEBUG(DEBUG_PS2, "STA %pM changed to not use "
- "PS mode (type=0x%02X, stype=0x%02X)\n",
- sta->addr, type >> 2, stype >> 4);
- if (type != IEEE80211_FTYPE_CTL ||
- stype != IEEE80211_STYPE_PSPOLL)
- schedule_packet_send(local, sta);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ). Called for each RX frame to update
- * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr)
-{
- struct sta_info *sta;
- u16 fc;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (!sta)
- return -1;
-
- fc = le16_to_cpu(hdr->frame_control);
- hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
- fc & IEEE80211_FCTL_FTYPE,
- fc & IEEE80211_FCTL_STYPE);
-
- atomic_dec(&sta->users);
- return 0;
-}
-
-
-/* Called only as a tasklet (software IRQ). Called for each RX frame after
- * getting RX header and payload from hardware. */
-ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
- struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats,
- int wds)
-{
- int ret;
- struct sta_info *sta;
- u16 fc, type, stype;
- struct ieee80211_hdr *hdr;
-
- if (local->ap == NULL)
- return AP_RX_CONTINUE;
-
- hdr = (struct ieee80211_hdr *) skb->data;
-
- fc = le16_to_cpu(hdr->frame_control);
- type = fc & IEEE80211_FCTL_FTYPE;
- stype = fc & IEEE80211_FCTL_STYPE;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (sta && !(sta->flags & WLAN_STA_AUTHORIZED))
- ret = AP_RX_CONTINUE_NOT_AUTHORIZED;
- else
- ret = AP_RX_CONTINUE;
-
-
- if (fc & IEEE80211_FCTL_TODS) {
- if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
- if (local->hostapd) {
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_NON_ASSOC);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- } else {
- printk(KERN_DEBUG "%s: dropped received packet"
- " from non-associated STA %pM"
- " (type=0x%02x, subtype=0x%02x)\n",
- dev->name, hdr->addr2,
- type >> 2, stype >> 4);
- hostap_rx(dev, skb, rx_stats);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- }
- ret = AP_RX_EXIT;
- goto out;
- }
- } else if (fc & IEEE80211_FCTL_FROMDS) {
- if (!wds) {
- /* FromDS frame - not for us; probably
- * broadcast/multicast in another BSS - drop */
- if (ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- printk(KERN_DEBUG "Odd.. FromDS packet "
- "received with own BSSID\n");
- hostap_dump_rx_80211(dev->name, skb, rx_stats);
- }
- ret = AP_RX_DROP;
- goto out;
- }
- } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL &&
- ether_addr_equal(hdr->addr1, dev->dev_addr)) {
-
- if (local->hostapd) {
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_NON_ASSOC);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- } else {
- /* At least Lucent f/w seems to send data::nullfunc
- * frames with no ToDS flag when the current AP returns
- * after being unavailable for some time. Speed up
- * re-association by informing the station about it not
- * being associated. */
- printk(KERN_DEBUG "%s: rejected received nullfunc frame"
- " without ToDS from not associated STA %pM\n",
- dev->name, hdr->addr2);
- hostap_rx(dev, skb, rx_stats);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- }
- ret = AP_RX_EXIT;
- goto out;
- } else if (stype == IEEE80211_STYPE_NULLFUNC) {
- /* At least Lucent cards seem to send periodic nullfunc
- * frames with ToDS. Let these through to update SQ
- * stats and PS state. Nullfunc frames do not contain
- * any data and they will be dropped below. */
- } else {
- /* If BSSID (Addr3) is foreign, this frame is a normal
- * broadcast frame from an IBSS network. Drop it silently.
- * If BSSID is own, report the dropping of this frame. */
- if (ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- printk(KERN_DEBUG "%s: dropped received packet from %pM"
- " with no ToDS flag "
- "(type=0x%02x, subtype=0x%02x)\n", dev->name,
- hdr->addr2, type >> 2, stype >> 4);
- hostap_dump_rx_80211(dev->name, skb, rx_stats);
- }
- ret = AP_RX_DROP;
- goto out;
- }
-
- if (sta) {
- hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
- type, stype);
-
- sta->rx_packets++;
- sta->rx_bytes += skb->len;
- sta->last_rx = jiffies;
- }
-
- if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC &&
- fc & IEEE80211_FCTL_TODS) {
- if (local->hostapd) {
- prism2_rx_80211(local->apdev, skb, rx_stats,
- PRISM2_RX_NULLFUNC_ACK);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- } else {
- /* some STA f/w's seem to require control::ACK frame
- * for data::nullfunc, but Prism2 f/w 0.8.0 (at least
- * from Compaq) does not send this.. Try to generate
- * ACK for these frames from the host driver to make
- * power saving work with, e.g., Lucent WaveLAN f/w */
- hostap_rx(dev, skb, rx_stats);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- }
- ret = AP_RX_EXIT;
- goto out;
- }
-
- out:
- if (sta)
- atomic_dec(&sta->users);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_handle_sta_crypto(local_info_t *local,
- struct ieee80211_hdr *hdr,
- struct lib80211_crypt_data **crypt,
- void **sta_ptr)
-{
- struct sta_info *sta;
-
- spin_lock(&local->ap->sta_table_lock);
- sta = ap_get_sta(local->ap, hdr->addr2);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock(&local->ap->sta_table_lock);
-
- if (!sta)
- return -1;
-
- if (sta->crypt) {
- *crypt = sta->crypt;
- *sta_ptr = sta;
- /* hostap_handle_sta_release() will be called to release STA
- * info */
- } else
- atomic_dec(&sta->users);
-
- return 0;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr)
-{
- struct sta_info *sta;
- int ret = 0;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, sta_addr);
- if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap)
- ret = 1;
- spin_unlock(&ap->sta_table_lock);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr)
-{
- struct sta_info *sta;
- int ret = 0;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, sta_addr);
- if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap &&
- ((sta->flags & WLAN_STA_AUTHORIZED) ||
- ap->local->ieee_802_1x == 0))
- ret = 1;
- spin_unlock(&ap->sta_table_lock);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
-{
- struct sta_info *sta;
- int ret = 1;
-
- if (!ap)
- return -1;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, sta_addr);
- if (sta)
- ret = 0;
- spin_unlock(&ap->sta_table_lock);
-
- if (ret == 1) {
- sta = ap_add_sta(ap, sta_addr);
- if (!sta)
- return -1;
- sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC;
- sta->ap = 1;
- memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
- /* No way of knowing which rates are supported since we did not
- * get supported rates element from beacon/assoc req. Assume
- * that remote end supports all 802.11b rates. */
- sta->supported_rates[0] = 0x82;
- sta->supported_rates[1] = 0x84;
- sta->supported_rates[2] = 0x0b;
- sta->supported_rates[3] = 0x16;
- sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M |
- WLAN_RATE_5M5 | WLAN_RATE_11M;
- sta->tx_rate = 110;
- sta->tx_max_rate = sta->tx_rate_idx = 3;
- }
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-int hostap_update_rx_stats(struct ap_data *ap,
- struct ieee80211_hdr *hdr,
- struct hostap_80211_rx_status *rx_stats)
-{
- struct sta_info *sta;
-
- if (!ap)
- return -1;
-
- spin_lock(&ap->sta_table_lock);
- sta = ap_get_sta(ap, hdr->addr2);
- if (sta) {
- sta->last_rx_silence = rx_stats->noise;
- sta->last_rx_signal = rx_stats->signal;
- sta->last_rx_rate = rx_stats->rate;
- sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- if (rx_stats->rate == 10)
- sta->rx_count[0]++;
- else if (rx_stats->rate == 20)
- sta->rx_count[1]++;
- else if (rx_stats->rate == 55)
- sta->rx_count[2]++;
- else if (rx_stats->rate == 110)
- sta->rx_count[3]++;
- }
- spin_unlock(&ap->sta_table_lock);
-
- return sta ? 0 : -1;
-}
-
-
-void hostap_update_rates(local_info_t *local)
-{
- struct sta_info *sta;
- struct ap_data *ap = local->ap;
-
- if (!ap)
- return;
-
- spin_lock_bh(&ap->sta_table_lock);
- list_for_each_entry(sta, &ap->sta_list, list) {
- prism2_check_tx_rates(sta);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-}
-
-
-void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent,
- struct lib80211_crypt_data ***crypt)
-{
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- sta = ap_get_sta(ap, addr);
- if (sta)
- atomic_inc(&sta->users);
- spin_unlock_bh(&ap->sta_table_lock);
-
- if (!sta && permanent)
- sta = ap_add_sta(ap, addr);
-
- if (!sta)
- return NULL;
-
- if (permanent)
- sta->flags |= WLAN_STA_PERM;
-
- *crypt = &sta->crypt;
-
- return sta;
-}
-
-
-void hostap_add_wds_links(local_info_t *local)
-{
- struct ap_data *ap = local->ap;
- struct sta_info *sta;
-
- spin_lock_bh(&ap->sta_table_lock);
- list_for_each_entry(sta, &ap->sta_list, list) {
- if (sta->ap)
- hostap_wds_link_oper(local, sta->addr, WDS_ADD);
- }
- spin_unlock_bh(&ap->sta_table_lock);
-
- schedule_work(&local->ap->wds_oper_queue);
-}
-
-
-void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type)
-{
- struct wds_oper_data *entry;
-
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry)
- return;
- memcpy(entry->addr, addr, ETH_ALEN);
- entry->type = type;
- spin_lock_bh(&local->lock);
- entry->next = local->ap->wds_oper_entries;
- local->ap->wds_oper_entries = entry;
- spin_unlock_bh(&local->lock);
-
- schedule_work(&local->ap->wds_oper_queue);
-}
-
-
-EXPORT_SYMBOL(hostap_init_data);
-EXPORT_SYMBOL(hostap_init_ap_proc);
-EXPORT_SYMBOL(hostap_free_data);
-EXPORT_SYMBOL(hostap_check_sta_fw_version);
-EXPORT_SYMBOL(hostap_handle_sta_tx_exc);
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_ap.h b/drivers/net/wireless/intersil/hostap/hostap_ap.h
deleted file mode 100644
index b7ac9e2f1a394..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_ap.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_AP_H
-#define HOSTAP_AP_H
-
-#include "hostap_80211.h"
-
-/* AP data structures for STAs */
-
-/* maximum number of frames to buffer per STA */
-#define STA_MAX_TX_BUFFER 32
-
-/* STA flags */
-#define WLAN_STA_AUTH BIT(0)
-#define WLAN_STA_ASSOC BIT(1)
-#define WLAN_STA_PS BIT(2)
-#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */
-#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */
-#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is
- * controlling whether STA is authorized to
- * send and receive non-IEEE 802.1X frames
- */
-#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
-
-#define WLAN_RATE_1M BIT(0)
-#define WLAN_RATE_2M BIT(1)
-#define WLAN_RATE_5M5 BIT(2)
-#define WLAN_RATE_11M BIT(3)
-#define WLAN_RATE_COUNT 4
-
-/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
- * but some pre-standard IEEE 802.11g products use longer elements. */
-#define WLAN_SUPP_RATES_MAX 32
-
-/* Try to increase TX rate after # successfully sent consecutive packets */
-#define WLAN_RATE_UPDATE_COUNT 50
-
-/* Decrease TX rate after # consecutive dropped packets */
-#define WLAN_RATE_DECREASE_THRESHOLD 2
-
-struct sta_info {
- struct list_head list;
- struct sta_info *hnext; /* next entry in hash table list */
- atomic_t users; /* number of users (do not remove if > 0) */
- struct proc_dir_entry *proc;
-
- u8 addr[6];
- u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
- u32 flags;
- u16 capability;
- u16 listen_interval; /* or beacon_int for APs */
- u8 supported_rates[WLAN_SUPP_RATES_MAX];
-
- unsigned long last_auth;
- unsigned long last_assoc;
- unsigned long last_rx;
- unsigned long last_tx;
- unsigned long rx_packets, tx_packets;
- unsigned long rx_bytes, tx_bytes;
- struct sk_buff_head tx_buf;
- /* FIX: timeout buffers with an expiry time somehow derived from
- * listen_interval */
-
- s8 last_rx_silence; /* Noise in dBm */
- s8 last_rx_signal; /* Signal strength in dBm */
- u8 last_rx_rate; /* TX rate in 0.1 Mbps */
- u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */
-
- u8 tx_supp_rates; /* bit field of supported TX rates */
- u8 tx_rate; /* current TX rate (in 0.1 Mbps) */
- u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */
- u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */
- u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */
- u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate)
- */
- u32 tx_since_last_failure;
- u32 tx_consecutive_exc;
-
- struct lib80211_crypt_data *crypt;
-
- int ap; /* whether this station is an AP */
-
- local_info_t *local;
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- union {
- struct {
- char *challenge; /* shared key authentication
- * challenge */
- } sta;
- struct {
- int ssid_len;
- unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */
- int channel;
- unsigned long last_beacon; /* last RX beacon time */
- } ap;
- } u;
-
- struct timer_list timer;
- enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-};
-
-
-#define MAX_STA_COUNT 1024
-
-/* Maximum number of AIDs to use for STAs; must be 2007 or lower
- * (8802.11 limitation) */
-#define MAX_AID_TABLE_SIZE 128
-
-#define STA_HASH_SIZE 256
-#define STA_HASH(sta) (sta[5])
-
-
-/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC
- * has passed since last received frame from the station, a nullfunc data
- * frame is sent to the station. If this frame is not acknowledged and no other
- * frames have been received, the station will be disassociated after
- * AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after
- * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with
- * max inactivity timer. */
-#define AP_MAX_INACTIVITY_SEC (5 * 60)
-#define AP_DISASSOC_DELAY (HZ)
-#define AP_DEAUTH_DELAY (HZ)
-
-/* ap_policy: whether to accept frames to/from other APs/IBSS */
-typedef enum {
- AP_OTHER_AP_SKIP_ALL = 0,
- AP_OTHER_AP_SAME_SSID = 1,
- AP_OTHER_AP_ALL = 2,
- AP_OTHER_AP_EVEN_IBSS = 3
-} ap_policy_enum;
-
-#define PRISM2_AUTH_OPEN BIT(0)
-#define PRISM2_AUTH_SHARED_KEY BIT(1)
-
-
-/* MAC address-based restrictions */
-struct mac_entry {
- struct list_head list;
- u8 addr[6];
-};
-
-struct mac_restrictions {
- enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy;
- unsigned int entries;
- struct list_head mac_list;
- spinlock_t lock;
-};
-
-
-struct add_sta_proc_data {
- u8 addr[ETH_ALEN];
- struct add_sta_proc_data *next;
-};
-
-
-typedef enum { WDS_ADD, WDS_DEL } wds_oper_type;
-struct wds_oper_data {
- wds_oper_type type;
- u8 addr[ETH_ALEN];
- struct wds_oper_data *next;
-};
-
-
-struct ap_data {
- int initialized; /* whether ap_data has been initialized */
- local_info_t *local;
- int bridge_packets; /* send packet to associated STAs directly to the
- * wireless media instead of higher layers in the
- * kernel */
- unsigned int bridged_unicast; /* number of unicast frames bridged on
- * wireless media */
- unsigned int bridged_multicast; /* number of non-unicast frames
- * bridged on wireless media */
- unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped
- * because they were to an address that
- * was not associated */
- int nullfunc_ack; /* use workaround for nullfunc frame ACKs */
-
- spinlock_t sta_table_lock;
- int num_sta; /* number of entries in sta_list */
- struct list_head sta_list; /* STA info list head */
- struct sta_info *sta_hash[STA_HASH_SIZE];
-
- struct proc_dir_entry *proc;
-
- ap_policy_enum ap_policy;
- unsigned int max_inactivity;
- int autom_ap_wds;
-
- struct mac_restrictions mac_restrictions; /* MAC-based auth */
- int last_tx_rate;
-
- struct work_struct add_sta_proc_queue;
- struct add_sta_proc_data *add_sta_proc_entries;
-
- struct work_struct wds_oper_queue;
- struct wds_oper_data *wds_oper_entries;
-
- u16 tx_callback_idx;
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- /* pointers to STA info; based on allocated AID or NULL if AID free
- * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
- * and so on
- */
- struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
-
- u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll;
-
- /* WEP operations for generating challenges to be used with shared key
- * authentication */
- struct lib80211_crypto_ops *crypt;
- void *crypt_priv;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-};
-
-
-void hostap_rx(struct net_device *dev, struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats);
-void hostap_init_data(local_info_t *local);
-void hostap_init_ap_proc(local_info_t *local);
-void hostap_free_data(struct ap_data *ap);
-void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver);
-
-typedef enum {
- AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED,
- AP_TX_CONTINUE_NOT_AUTHORIZED
-} ap_tx_ret;
-struct hostap_tx_data {
- struct sk_buff *skb;
- int host_encrypt;
- struct lib80211_crypt_data *crypt;
- void *sta_ptr;
-};
-ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
-void hostap_handle_sta_release(void *ptr);
-void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr);
-typedef enum {
- AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
-} ap_rx_ret;
-ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
- struct sk_buff *skb,
- struct hostap_80211_rx_status *rx_stats,
- int wds);
-int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr,
- struct lib80211_crypt_data **crypt,
- void **sta_ptr);
-int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
-int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
-int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
-int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr,
- struct hostap_80211_rx_status *rx_stats);
-void hostap_update_rates(local_info_t *local);
-void hostap_add_wds_links(local_info_t *local);
-void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type);
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap,
- int resend);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-#endif /* HOSTAP_AP_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_common.h b/drivers/net/wireless/intersil/hostap/hostap_common.h
deleted file mode 100644
index dd29a8e8d3496..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_common.h
+++ /dev/null
@@ -1,420 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_COMMON_H
-#define HOSTAP_COMMON_H
-
-#include <linux/types.h>
-#include <linux/if_ether.h>
-
-/* IEEE 802.11 defines */
-
-/* HFA384X Configuration RIDs */
-#define HFA384X_RID_CNFPORTTYPE 0xFC00
-#define HFA384X_RID_CNFOWNMACADDR 0xFC01
-#define HFA384X_RID_CNFDESIREDSSID 0xFC02
-#define HFA384X_RID_CNFOWNCHANNEL 0xFC03
-#define HFA384X_RID_CNFOWNSSID 0xFC04
-#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05
-#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06
-#define HFA384X_RID_CNFMAXDATALEN 0xFC07
-#define HFA384X_RID_CNFWDSADDRESS 0xFC08
-#define HFA384X_RID_CNFPMENABLED 0xFC09
-#define HFA384X_RID_CNFPMEPS 0xFC0A
-#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B
-#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C
-#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D
-#define HFA384X_RID_CNFOWNNAME 0xFC0E
-#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10
-#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */
-#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */
-#define HFA384X_RID_UNKNOWN1 0xFC20
-#define HFA384X_RID_UNKNOWN2 0xFC21
-#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23
-#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24
-#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25
-#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26
-#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27
-#define HFA384X_RID_CNFWEPFLAGS 0xFC28
-#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
-#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A
-#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */
-#define HFA384X_RID_CNFTXCONTROL 0xFC2C
-#define HFA384X_RID_CNFROAMINGMODE 0xFC2D
-#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */
-#define HFA384X_RID_CNFRCVCRCERROR 0xFC30
-#define HFA384X_RID_CNFMMLIFE 0xFC31
-#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32
-#define HFA384X_RID_CNFBEACONINT 0xFC33
-#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */
-#define HFA384X_RID_CNFSTAPCFINFO 0xFC35
-#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37
-#define HFA384X_RID_CNFTIMCTRL 0xFC40
-#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */
-#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */
-#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */
-#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0;
- * write only */
-#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_GROUPADDRESSES 0xFC80
-#define HFA384X_RID_CREATEIBSS 0xFC81
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82
-#define HFA384X_RID_RTSTHRESHOLD 0xFC83
-#define HFA384X_RID_TXRATECONTROL 0xFC84
-#define HFA384X_RID_PROMISCUOUSMODE 0xFC85
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */
-#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0
-#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
-#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
-#define HFA384X_RID_CNFBASICRATES 0xFCB3
-#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4
-#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */
-#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */
-#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */
-#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */
-#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */
-#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */
-#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */
-#define HFA384X_RID_TICKTIME 0xFCE0
-#define HFA384X_RID_SCANREQUEST 0xFCE1
-#define HFA384X_RID_JOINREQUEST 0xFCE2
-#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */
-#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */
-#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */
-
-/* HFA384X Information RIDs */
-#define HFA384X_RID_MAXLOADTIME 0xFD00
-#define HFA384X_RID_DOWNLOADBUFFER 0xFD01
-#define HFA384X_RID_PRIID 0xFD02
-#define HFA384X_RID_PRISUPRANGE 0xFD03
-#define HFA384X_RID_CFIACTRANGES 0xFD04
-#define HFA384X_RID_NICSERNUM 0xFD0A
-#define HFA384X_RID_NICID 0xFD0B
-#define HFA384X_RID_MFISUPRANGE 0xFD0C
-#define HFA384X_RID_CFISUPRANGE 0xFD0D
-#define HFA384X_RID_CHANNELLIST 0xFD10
-#define HFA384X_RID_REGULATORYDOMAINS 0xFD11
-#define HFA384X_RID_TEMPTYPE 0xFD12
-#define HFA384X_RID_CIS 0xFD13
-#define HFA384X_RID_STAID 0xFD20
-#define HFA384X_RID_STASUPRANGE 0xFD21
-#define HFA384X_RID_MFIACTRANGES 0xFD22
-#define HFA384X_RID_CFIACTRANGES2 0xFD23
-#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1;
- * only Prism2.5(?) */
-#define HFA384X_RID_PORTSTATUS 0xFD40
-#define HFA384X_RID_CURRENTSSID 0xFD41
-#define HFA384X_RID_CURRENTBSSID 0xFD42
-#define HFA384X_RID_COMMSQUALITY 0xFD43
-#define HFA384X_RID_CURRENTTXRATE 0xFD44
-#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45
-#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46
-#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47
-#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48
-#define HFA384X_RID_LONGRETRYLIMIT 0xFD49
-#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A
-#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B
-#define HFA384X_RID_CFPOLLABLE 0xFD4C
-#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D
-#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
-#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */
-#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */
-#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */
-#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */
-#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */
-#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */
-#define HFA384X_RID_PHYTYPE 0xFDC0
-#define HFA384X_RID_CURRENTCHANNEL 0xFDC1
-#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2
-#define HFA384X_RID_CCAMODE 0xFDC3
-#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6
-#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */
-#define HFA384X_RID_BUILDSEQ 0xFFFE
-#define HFA384X_RID_FWID 0xFFFF
-
-
-struct hfa384x_comp_ident
-{
- __le16 id;
- __le16 variant;
- __le16 major;
- __le16 minor;
-} __packed;
-
-#define HFA384X_COMP_ID_PRI 0x15
-#define HFA384X_COMP_ID_STA 0x1f
-#define HFA384X_COMP_ID_FW_AP 0x14b
-
-struct hfa384x_sup_range
-{
- __le16 role;
- __le16 id;
- __le16 variant;
- __le16 bottom;
- __le16 top;
-} __packed;
-
-
-struct hfa384x_build_id
-{
- __le16 pri_seq;
- __le16 sec_seq;
-} __packed;
-
-/* FD01 - Download Buffer */
-struct hfa384x_rid_download_buffer
-{
- __le16 page;
- __le16 offset;
- __le16 length;
-} __packed;
-
-/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
-struct hfa384x_comms_quality {
- __le16 comm_qual; /* 0 .. 92 */
- __le16 signal_level; /* 27 .. 154 */
- __le16 noise_level; /* 27 .. 154 */
-} __packed;
-
-
-/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
-
-/* New wireless extensions API - SET/GET convention (even ioctl numbers are
- * root only)
- */
-#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
-#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1)
-#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2)
-#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3)
-#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4)
-#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
-#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8)
-#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10)
-#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12)
-#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14)
-#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16)
-#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18)
-#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20)
-#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22)
-
-/* following are not in SIOCGIWPRIV list; check permission in the driver code
- */
-#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13)
-#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
-
-
-/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
-enum {
- /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
- PRISM2_PARAM_TXRATECTRL = 2,
- PRISM2_PARAM_BEACON_INT = 3,
- PRISM2_PARAM_PSEUDO_IBSS = 4,
- PRISM2_PARAM_ALC = 5,
- /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
- PRISM2_PARAM_DUMP = 7,
- PRISM2_PARAM_OTHER_AP_POLICY = 8,
- PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
- PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
- PRISM2_PARAM_DTIM_PERIOD = 11,
- PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
- PRISM2_PARAM_MAX_WDS = 13,
- PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
- PRISM2_PARAM_AP_AUTH_ALGS = 15,
- PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
- PRISM2_PARAM_HOST_ENCRYPT = 17,
- PRISM2_PARAM_HOST_DECRYPT = 18,
- /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */
- /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */
- PRISM2_PARAM_HOST_ROAMING = 21,
- PRISM2_PARAM_BCRX_STA_KEY = 22,
- PRISM2_PARAM_IEEE_802_1X = 23,
- PRISM2_PARAM_ANTSEL_TX = 24,
- PRISM2_PARAM_ANTSEL_RX = 25,
- PRISM2_PARAM_MONITOR_TYPE = 26,
- PRISM2_PARAM_WDS_TYPE = 27,
- PRISM2_PARAM_HOSTSCAN = 28,
- PRISM2_PARAM_AP_SCAN = 29,
- PRISM2_PARAM_ENH_SEC = 30,
- PRISM2_PARAM_IO_DEBUG = 31,
- PRISM2_PARAM_BASIC_RATES = 32,
- PRISM2_PARAM_OPER_RATES = 33,
- PRISM2_PARAM_HOSTAPD = 34,
- PRISM2_PARAM_HOSTAPD_STA = 35,
- PRISM2_PARAM_WPA = 36,
- PRISM2_PARAM_PRIVACY_INVOKED = 37,
- PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
- PRISM2_PARAM_DROP_UNENCRYPTED = 39,
- PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
-};
-
-enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1,
- HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 };
-
-
-/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */
-enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1,
- AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3,
- AP_MAC_CMD_KICKALL = 4 };
-
-
-/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */
-enum {
- PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */,
- /* Note! Old versions of prism2_srec have a fatal error in CRC-16
- * calculation, which will corrupt all non-volatile downloads.
- * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to
- * prevent use of old versions of prism2_srec for non-volatile
- * download. */
- PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */,
- PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */,
- /* Persistent versions of volatile download commands (keep firmware
- * data in memory and automatically re-download after hw_reset */
- PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5,
- PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6,
-};
-
-struct prism2_download_param {
- u32 dl_cmd;
- u32 start_addr;
- u32 num_areas;
- struct prism2_download_area {
- u32 addr; /* wlan card address */
- u32 len;
- void __user *ptr; /* pointer to data in user space */
- } data[];
-};
-
-#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072
-#define PRISM2_MAX_DOWNLOAD_LEN 262144
-
-
-/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
-enum {
- PRISM2_HOSTAPD_FLUSH = 1,
- PRISM2_HOSTAPD_ADD_STA = 2,
- PRISM2_HOSTAPD_REMOVE_STA = 3,
- PRISM2_HOSTAPD_GET_INFO_STA = 4,
- /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
- PRISM2_SET_ENCRYPTION = 6,
- PRISM2_GET_ENCRYPTION = 7,
- PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
- PRISM2_HOSTAPD_GET_RID = 9,
- PRISM2_HOSTAPD_SET_RID = 10,
- PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
- PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
- PRISM2_HOSTAPD_MLME = 13,
- PRISM2_HOSTAPD_SCAN_REQ = 14,
- PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
-};
-
-#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
-#define PRISM2_HOSTAPD_RID_HDR_LEN \
-offsetof(struct prism2_hostapd_param, u.rid.data)
-#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-offsetof(struct prism2_hostapd_param, u.generic_elem.data)
-
-/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
- */
-#define HOSTAP_CRYPT_ALG_NAME_LEN 16
-
-
-struct prism2_hostapd_param {
- u32 cmd;
- u8 sta_addr[ETH_ALEN];
- union {
- struct {
- u16 aid;
- u16 capability;
- u8 tx_supp_rates;
- } add_sta;
- struct {
- u32 inactive_sec;
- } get_info_sta;
- struct {
- u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
- u32 flags;
- u32 err;
- u8 idx;
- u8 seq[8]; /* sequence counter (set: RX, get: TX) */
- u16 key_len;
- u8 key[0];
- } crypt;
- struct {
- u32 flags_and;
- u32 flags_or;
- } set_flags_sta;
- struct {
- u16 rid;
- u16 len;
- u8 data[0];
- } rid;
- struct {
- u8 len;
- u8 data[0];
- } generic_elem;
- struct {
-#define MLME_STA_DEAUTH 0
-#define MLME_STA_DISASSOC 1
- u16 cmd;
- u16 reason_code;
- } mlme;
- struct {
- u8 ssid_len;
- u8 ssid[32];
- } scan_req;
- } u;
-};
-
-#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0)
-#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1)
-
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
-#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
-#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
-#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
-#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
-#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
-
-
-#endif /* HOSTAP_COMMON_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_config.h b/drivers/net/wireless/intersil/hostap/hostap_config.h
deleted file mode 100644
index 3ebd55847fad3..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_config.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_CONFIG_H
-#define HOSTAP_CONFIG_H
-
-/* In the previous versions of Host AP driver, support for user space version
- * of IEEE 802.11 management (hostapd) used to be disabled in the default
- * configuration. From now on, support for hostapd is always included and it is
- * possible to disable kernel driver version of IEEE 802.11 management with a
- * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */
-/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-/* Maximum number of events handler per one interrupt */
-#define PRISM2_MAX_INTERRUPT_EVENTS 20
-
-/* Include code for downloading firmware images into volatile RAM. */
-#define PRISM2_DOWNLOAD_SUPPORT
-
-/* Allow kernel configuration to enable download support. */
-#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE)
-#define PRISM2_DOWNLOAD_SUPPORT
-#endif
-
-/* Allow kernel configuration to enable non-volatile download support. */
-#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM
-#define PRISM2_NON_VOLATILE_DOWNLOAD
-#endif
-
-/* Save low-level I/O for debugging. This should not be enabled in normal use.
- */
-/* #define PRISM2_IO_DEBUG */
-
-/* Following defines can be used to remove unneeded parts of the driver, e.g.,
- * to limit the size of the kernel module. Definitions can be added here in
- * hostap_config.h or they can be added to make command with ccflags-y,
- * e.g.,
- * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"'
- */
-
-/* Do not include debug messages into the driver */
-/* #define PRISM2_NO_DEBUG */
-
-/* Do not include /proc/net/prism2/wlan#/{registers,debug} */
-/* #define PRISM2_NO_PROCFS_DEBUG */
-
-/* Do not include station functionality (i.e., allow only Master (Host AP) mode
- */
-/* #define PRISM2_NO_STATION_MODES */
-
-#endif /* HOSTAP_CONFIG_H */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_cs.c b/drivers/net/wireless/intersil/hostap/hostap_cs.c
deleted file mode 100644
index ec7db2badc40e..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_cs.c
+++ /dev/null
@@ -1,710 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define PRISM2_PCCARD
-
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/timer.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/workqueue.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <asm/io.h>
-
-#include "hostap_wlan.h"
-
-
-static char *dev_info = "hostap_cs";
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
- "cards (PC Card).");
-MODULE_LICENSE("GPL");
-
-
-static int ignore_cis_vcc;
-module_param(ignore_cis_vcc, int, 0444);
-MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
-
-
-/* struct local_info::hw_priv */
-struct hostap_cs_priv {
- struct pcmcia_device *link;
- int sandisk_connectplus;
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-
-static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
- outb(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u8 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- v = inb(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
- outw(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u16 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- v = inw(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
- outsw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline void hfa384x_insw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
- insw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
-#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
-#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
-
-#else /* PRISM2_IO_DEBUG */
-
-#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
-#define HFA384X_INB(a) inb(dev->base_addr + (a))
-#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
-#define HFA384X_INW(a) inw(dev->base_addr + (a))
-#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
-#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
- int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_INSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- *((char *) pos) = HFA384X_INB(d_off);
-
- return 0;
-}
-
-
-static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_OUTSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- HFA384X_OUTB(*((char *) pos), d_off);
-
- return 0;
-}
-
-
-/* FIX: This might change at some point.. */
-#include "hostap_hw.c"
-
-
-
-static void prism2_detach(struct pcmcia_device *p_dev);
-static void prism2_release(u_long arg);
-static int prism2_config(struct pcmcia_device *link);
-
-
-static int prism2_pccard_card_present(local_info_t *local)
-{
- struct hostap_cs_priv *hw_priv = local->hw_priv;
- if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link))
- return 1;
- return 0;
-}
-
-
-/*
- * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0
- * Document No. 20-10-00058, January 2004
- * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf
- */
-#define SANDISK_WLAN_ACTIVATION_OFF 0x40
-#define SANDISK_HCR_OFF 0x42
-
-
-static void sandisk_set_iobase(local_info_t *local)
-{
- int res;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- res = pcmcia_write_config_byte(hw_priv->link, 0x10,
- hw_priv->link->resource[0]->start & 0x00ff);
- if (res != 0) {
- printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -"
- " res=%d\n", res);
- }
- udelay(10);
-
- res = pcmcia_write_config_byte(hw_priv->link, 0x12,
- (hw_priv->link->resource[0]->start >> 8) & 0x00ff);
- if (res != 0) {
- printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -"
- " res=%d\n", res);
- }
-}
-
-
-static void sandisk_write_hcr(local_info_t *local, int hcr)
-{
- struct net_device *dev = local->dev;
- int i;
-
- HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF);
- udelay(50);
- for (i = 0; i < 10; i++) {
- HFA384X_OUTB(hcr, SANDISK_HCR_OFF);
- }
- udelay(55);
- HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF);
-}
-
-
-static int sandisk_enable_wireless(struct net_device *dev)
-{
- int res, ret = 0;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- if (resource_size(hw_priv->link->resource[0]) < 0x42) {
- /* Not enough ports to be SanDisk multi-function card */
- ret = -ENODEV;
- goto done;
- }
-
- if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) {
- /* No SanDisk manfid found */
- ret = -ENODEV;
- goto done;
- }
-
- if (hw_priv->link->socket->functions < 2) {
- /* No multi-function links found */
- ret = -ENODEV;
- goto done;
- }
-
- printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected"
- " - using vendor-specific initialization\n", dev->name);
- hw_priv->sandisk_connectplus = 1;
-
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- COR_SOFT_RESET);
- if (res != 0) {
- printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
- dev->name, res);
- goto done;
- }
- mdelay(5);
-
- /*
- * Do not enable interrupts here to avoid some bogus events. Interrupts
- * will be enabled during the first cor_sreset call.
- */
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- (COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE |
- COR_FUNC_ENA));
- if (res != 0) {
- printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n",
- dev->name, res);
- goto done;
- }
- mdelay(5);
-
- sandisk_set_iobase(local);
-
- HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF);
- udelay(10);
- HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF);
- udelay(10);
-
-done:
- return ret;
-}
-
-
-static void prism2_pccard_cor_sreset(local_info_t *local)
-{
- int res;
- u8 val;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- if (!prism2_pccard_card_present(local))
- return;
-
- res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val);
- if (res != 0) {
- printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n",
- res);
- return;
- }
- printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n",
- val);
-
- val |= COR_SOFT_RESET;
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
- if (res != 0) {
- printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n",
- res);
- return;
- }
-
- mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
-
- val &= ~COR_SOFT_RESET;
- if (hw_priv->sandisk_connectplus)
- val |= COR_IREQ_ENA;
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val);
- if (res != 0) {
- printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n",
- res);
- return;
- }
-
- mdelay(hw_priv->sandisk_connectplus ? 5 : 2);
-
- if (hw_priv->sandisk_connectplus)
- sandisk_set_iobase(local);
-}
-
-
-static void prism2_pccard_genesis_reset(local_info_t *local, int hcr)
-{
- int res;
- u8 old_cor;
- struct hostap_cs_priv *hw_priv = local->hw_priv;
-
- if (!prism2_pccard_card_present(local))
- return;
-
- if (hw_priv->sandisk_connectplus) {
- sandisk_write_hcr(local, hcr);
- return;
- }
-
- res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res);
- return;
- }
- printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor);
-
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- old_cor | COR_SOFT_RESET);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res);
- return;
- }
-
- mdelay(10);
-
- /* Setup Genesis mode */
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res);
- return;
- }
- mdelay(10);
-
- res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR,
- old_cor & ~COR_SOFT_RESET);
- if (res != 0) {
- printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res);
- return;
- }
-
- mdelay(10);
-}
-
-
-static struct prism2_helper_functions prism2_pccard_funcs =
-{
- .card_present = prism2_pccard_card_present,
- .cor_sreset = prism2_pccard_cor_sreset,
- .genesis_reset = prism2_pccard_genesis_reset,
- .hw_type = HOSTAP_HW_PCCARD,
-};
-
-
-/* allocate local data and register with CardServices
- * initialize dev_link structure, but do not configure the card yet */
-static int hostap_cs_probe(struct pcmcia_device *p_dev)
-{
- int ret;
-
- PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
-
- ret = prism2_config(p_dev);
- if (ret) {
- PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
- }
-
- return ret;
-}
-
-
-static void prism2_detach(struct pcmcia_device *link)
-{
- PDEBUG(DEBUG_FLOW, "prism2_detach\n");
-
- prism2_release((u_long)link);
-
- /* release net devices */
- if (link->priv) {
- struct hostap_cs_priv *hw_priv;
- struct net_device *dev;
- struct hostap_interface *iface;
- dev = link->priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- prism2_free_local_data(dev);
- kfree(hw_priv);
- }
-}
-
-
-static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-}
-
-static int prism2_config(struct pcmcia_device *link)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret;
- struct hostap_cs_priv *hw_priv;
- unsigned long flags;
-
- PDEBUG(DEBUG_FLOW, "prism2_config()\n");
-
- hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
- if (hw_priv == NULL) {
- ret = -ENOMEM;
- goto failed;
- }
-
- /* Look for an appropriate configuration table entry in the CIS */
- link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO |
- CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
- if (ignore_cis_vcc)
- link->config_flags &= ~CONF_AUTO_CHECK_VCC;
- ret = pcmcia_loop_config(link, prism2_config_check, NULL);
- if (ret) {
- if (!ignore_cis_vcc)
- printk(KERN_ERR "GetNextTuple(): No matching "
- "CIS configuration. Maybe you need the "
- "ignore_cis_vcc=1 parameter.\n");
- goto failed;
- }
-
- /* Need to allocate net_device before requesting IRQ handler */
- dev = prism2_init_local_data(&prism2_pccard_funcs, 0,
- &link->dev);
- if (!dev) {
- ret = -ENOMEM;
- goto failed;
- }
- link->priv = dev;
-
- iface = netdev_priv(dev);
- local = iface->local;
- local->hw_priv = hw_priv;
- hw_priv->link = link;
-
- /*
- * We enable IRQ here, but IRQ handler will not proceed
- * until dev->base_addr is set below. This protect us from
- * receive interrupts when driver is not initialized.
- */
- ret = pcmcia_request_irq(link, prism2_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- spin_lock_irqsave(&local->irq_init_lock, flags);
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
- spin_unlock_irqrestore(&local->irq_init_lock, flags);
-
- local->shutdown = 0;
-
- sandisk_enable_wireless(dev);
-
- ret = prism2_hw_config(dev, 1);
- if (!ret)
- ret = hostap_hw_ready(dev);
-
- return ret;
-
- failed:
- kfree(hw_priv);
- prism2_release((u_long)link);
- return ret;
-}
-
-
-static void prism2_release(u_long arg)
-{
- struct pcmcia_device *link = (struct pcmcia_device *)arg;
-
- PDEBUG(DEBUG_FLOW, "prism2_release\n");
-
- if (link->priv) {
- struct net_device *dev = link->priv;
- struct hostap_interface *iface;
-
- iface = netdev_priv(dev);
- prism2_hw_shutdown(dev, 0);
- iface->local->shutdown = 1;
- }
-
- pcmcia_disable_device(link);
- PDEBUG(DEBUG_FLOW, "release - done\n");
-}
-
-static int hostap_cs_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = (struct net_device *) link->priv;
- int dev_open = 0;
- struct hostap_interface *iface = NULL;
-
- if (!dev)
- return -ENODEV;
-
- iface = netdev_priv(dev);
-
- PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info);
- if (iface && iface->local)
- dev_open = iface->local->num_dev_open > 0;
- if (dev_open) {
- netif_stop_queue(dev);
- netif_device_detach(dev);
- }
- prism2_suspend(dev);
-
- return 0;
-}
-
-static int hostap_cs_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = (struct net_device *) link->priv;
- int dev_open = 0;
- struct hostap_interface *iface = NULL;
-
- if (!dev)
- return -ENODEV;
-
- iface = netdev_priv(dev);
-
- PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info);
-
- if (iface && iface->local)
- dev_open = iface->local->num_dev_open > 0;
-
- prism2_hw_shutdown(dev, 1);
- prism2_hw_config(dev, dev_open ? 0 : 1);
- if (dev_open) {
- netif_device_attach(dev);
- netif_start_queue(dev);
- }
-
- return 0;
-}
-
-static const struct pcmcia_device_id hostap_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
- PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
- PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
- PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
- PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
- PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
-/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */
- PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
- PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF",
- 0x2d858104),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
- 0x74c5e40d),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
- 0x4b801a17),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02",
- 0x4b74baa0),
- PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus",
- 0x7a954bd9, 0x74be00c6),
- PCMCIA_DEVICE_PROD_ID123(
- "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02",
- 0xe6ec52ce, 0x08649af2, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "Canon", "Wireless LAN CF Card K30225", "Version 01.00",
- 0x96ef6fe2, 0x263fcbab, 0xa57adb8c),
- PCMCIA_DEVICE_PROD_ID123(
- "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02",
- 0x71b18589, 0xb6f1b0ab, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "Instant Wireless ", " Network PC CARD", "Version 01.02",
- 0x11d901af, 0x6e9bd926, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "SMC", "SMC2632W", "Version 01.02",
- 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G",
- 0x2decece3, 0x82067c18),
- PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card",
- 0x54f7c49c, 0x15a75e5b),
- PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE",
- 0x74c5e40d, 0xdb472a18),
- PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card",
- 0x0733cc81, 0x0c52f395),
- PCMCIA_DEVICE_PROD_ID12(
- "ZoomAir 11Mbps High", "Rate wireless Networking",
- 0x273fe3db, 0x32a1eaee),
- PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card",
- 0xa37434e9, 0x9762e8f1),
- PCMCIA_DEVICE_PROD_ID123(
- "Pretec", "CompactWLAN Card 802.11b", "2.5",
- 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1),
- PCMCIA_DEVICE_PROD_ID123(
- "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02",
- 0xc7b8df9d, 0x1700d087, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID123(
- "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
- "Ver. 1.00",
- 0x5cd01705, 0x4271660f, 0x9d08ee12),
- PCMCIA_DEVICE_PROD_ID123(
- "Wireless LAN" , "11Mbps PC Card", "Version 01.02",
- 0x4b8870ff, 0x70e946d1, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
- PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
- PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
- PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
-
-
-static struct pcmcia_driver hostap_driver = {
- .name = "hostap_cs",
- .probe = hostap_cs_probe,
- .remove = prism2_detach,
- .owner = THIS_MODULE,
- .id_table = hostap_cs_ids,
- .suspend = hostap_cs_suspend,
- .resume = hostap_cs_resume,
-};
-module_pcmcia_driver(hostap_driver);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_download.c b/drivers/net/wireless/intersil/hostap/hostap_download.c
deleted file mode 100644
index 3672291ced5c8..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_download.c
+++ /dev/null
@@ -1,811 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-static int prism2_enable_aux_port(struct net_device *dev, int enable)
-{
- u16 val, reg;
- int i, tries;
- unsigned long flags;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- if (enable) {
- PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
- "port is already enabled\n", dev->name);
- }
- return 0;
- }
-
- spin_lock_irqsave(&local->cmdlock, flags);
-
- /* wait until busy bit is clear */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- spin_unlock_irqrestore(&local->cmdlock, flags);
- printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
- dev->name, reg);
- return -ETIMEDOUT;
- }
-
- val = HFA384X_INW(HFA384X_CONTROL_OFF);
-
- if (enable) {
- HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
-
- if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
- printk("prism2_enable_aux_port: was not disabled!?\n");
- val &= ~HFA384X_AUX_PORT_MASK;
- val |= HFA384X_AUX_PORT_ENABLE;
- } else {
- HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
-
- if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
- printk("prism2_enable_aux_port: was not enabled!?\n");
- val &= ~HFA384X_AUX_PORT_MASK;
- val |= HFA384X_AUX_PORT_DISABLE;
- }
- HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
-
- udelay(5);
-
- i = 10000;
- while (i > 0) {
- val = HFA384X_INW(HFA384X_CONTROL_OFF);
- val &= HFA384X_AUX_PORT_MASK;
-
- if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
- (!enable && val == HFA384X_AUX_PORT_DISABLED))
- break;
-
- udelay(10);
- i--;
- }
-
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- if (i == 0) {
- printk("prism2_enable_aux_port(%d) timed out\n",
- enable);
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-
-static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
- void *buf)
-{
- u16 page, offset;
- if (addr & 1 || len & 1)
- return -1;
-
- page = addr >> 7;
- offset = addr & 0x7f;
-
- HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
- HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
-
- udelay(5);
-
-#ifdef PRISM2_PCI
- {
- __le16 *pos = (__le16 *) buf;
- while (len > 0) {
- *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
- len -= 2;
- }
- }
-#else /* PRISM2_PCI */
- HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
-#endif /* PRISM2_PCI */
-
- return 0;
-}
-
-
-static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
- void *buf)
-{
- u16 page, offset;
- if (addr & 1 || len & 1)
- return -1;
-
- page = addr >> 7;
- offset = addr & 0x7f;
-
- HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
- HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
-
- udelay(5);
-
-#ifdef PRISM2_PCI
- {
- __le16 *pos = (__le16 *) buf;
- while (len > 0) {
- HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
- len -= 2;
- }
- }
-#else /* PRISM2_PCI */
- HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
-#endif /* PRISM2_PCI */
-
- return 0;
-}
-
-
-static int prism2_pda_ok(u8 *buf)
-{
- __le16 *pda = (__le16 *) buf;
- int pos;
- u16 len, pdr;
-
- if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
- buf[3] == 0x00)
- return 0;
-
- pos = 0;
- while (pos + 1 < PRISM2_PDA_SIZE / 2) {
- len = le16_to_cpu(pda[pos]);
- pdr = le16_to_cpu(pda[pos + 1]);
- if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
- return 0;
-
- if (pdr == 0x0000 && len == 2) {
- /* PDA end found */
- return 1;
- }
-
- pos += len + 1;
- }
-
- return 0;
-}
-
-
-#define prism2_download_aux_dump_npages 65536
-
-struct prism2_download_aux_dump {
- local_info_t *local;
- u16 page[0x80];
-};
-
-static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v)
-{
- struct prism2_download_aux_dump *ctx = m->private;
-
- hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page);
- seq_write(m, ctx->page, 0x80);
- return 0;
-}
-
-static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos)
-{
- struct prism2_download_aux_dump *ctx = m->private;
- prism2_enable_aux_port(ctx->local->dev, 1);
- if (*_pos >= prism2_download_aux_dump_npages)
- return NULL;
- return (void *)((unsigned long)*_pos + 1);
-}
-
-static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- ++*_pos;
- if (*_pos >= prism2_download_aux_dump_npages)
- return NULL;
- return (void *)((unsigned long)*_pos + 1);
-}
-
-static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v)
-{
- struct prism2_download_aux_dump *ctx = m->private;
- prism2_enable_aux_port(ctx->local->dev, 0);
-}
-
-static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
- .start = prism2_download_aux_dump_proc_start,
- .next = prism2_download_aux_dump_proc_next,
- .stop = prism2_download_aux_dump_proc_stop,
- .show = prism2_download_aux_dump_proc_show,
-};
-
-static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file)
-{
- int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops,
- sizeof(struct prism2_download_aux_dump));
- if (ret == 0) {
- struct seq_file *m = file->private_data;
- m->private = pde_data(inode);
- }
- return ret;
-}
-
-static const struct proc_ops prism2_download_aux_dump_proc_ops = {
- .proc_open = prism2_download_aux_dump_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = seq_release_private,
-};
-
-
-static u8 * prism2_read_pda(struct net_device *dev)
-{
- u8 *buf;
- int res, i, found = 0;
-#define NUM_PDA_ADDRS 4
- unsigned int pda_addr[NUM_PDA_ADDRS] = {
- 0x7f0000 /* others than HFA3841 */,
- 0x3f0000 /* HFA3841 */,
- 0x390000 /* apparently used in older cards */,
- 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
- };
-
- buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
- if (buf == NULL)
- return NULL;
-
- /* Note: wlan card should be in initial state (just after init cmd)
- * and no other operations should be performed concurrently. */
-
- prism2_enable_aux_port(dev, 1);
-
- for (i = 0; i < NUM_PDA_ADDRS; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
- dev->name, pda_addr[i]);
- res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
- if (res)
- continue;
- if (res == 0 && prism2_pda_ok(buf)) {
- PDEBUG2(DEBUG_EXTRA2, ": OK\n");
- found = 1;
- break;
- } else {
- PDEBUG2(DEBUG_EXTRA2, ": failed\n");
- }
- }
-
- prism2_enable_aux_port(dev, 0);
-
- if (!found) {
- printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
- kfree(buf);
- buf = NULL;
- }
-
- return buf;
-}
-
-
-static int prism2_download_volatile(local_info_t *local,
- struct prism2_download_data *param)
-{
- struct net_device *dev = local->dev;
- int ret = 0, i;
- u16 param0, param1;
-
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -1;
- }
-
- local->hw_downloading = 1;
- if (local->pri_only) {
- hfa384x_disable_interrupts(dev);
- } else {
- prism2_hw_shutdown(dev, 0);
-
- if (prism2_hw_init(dev, 0)) {
- printk(KERN_WARNING "%s: Could not initialize card for"
- " download\n", dev->name);
- ret = -1;
- goto out;
- }
- }
-
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_WARNING "%s: Could not enable AUX port\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- param0 = param->start_addr & 0xffff;
- param1 = param->start_addr >> 16;
-
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
- param0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
- dev->name, param->data[i].len, param->data[i].addr);
- if (hfa384x_to_aux(dev, param->data[i].addr,
- param->data[i].len, param->data[i].data)) {
- printk(KERN_WARNING "%s: RAM download at 0x%08x "
- "(len=%d) failed\n", dev->name,
- param->data[i].addr, param->data[i].len);
- ret = -1;
- goto out;
- }
- }
-
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_DISABLE << 8), param0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
- /* ProgMode disable causes the hardware to restart itself from the
- * given starting address. Give hw some time and ACK command just in
- * case restart did not happen. */
- mdelay(5);
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
-
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
- dev->name);
- /* continue anyway.. restart should have taken care of this */
- }
-
- mdelay(5);
- local->hw_downloading = 0;
- if (prism2_hw_config(dev, 2)) {
- printk(KERN_WARNING "%s: Card configuration after RAM "
- "download failed\n", dev->name);
- ret = -1;
- goto out;
- }
-
- out:
- local->hw_downloading = 0;
- return ret;
-}
-
-
-static int prism2_enable_genesis(local_info_t *local, int hcr)
-{
- struct net_device *dev = local->dev;
- u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
- u8 readbuf[4];
-
- printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
- dev->name, hcr);
- local->func->cor_sreset(local);
- hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
- local->func->genesis_reset(local, hcr);
-
- /* Readback test */
- hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
- hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
- hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
-
- if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
- printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
- hcr);
- return 0;
- } else {
- printk(KERN_DEBUG "Readback test failed, HCR 0x%02x write %4ph read %4ph\n",
- hcr, initseq, readbuf);
- return 1;
- }
-}
-
-
-static int prism2_get_ram_size(local_info_t *local)
-{
- int ret;
-
- /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
- if (prism2_enable_genesis(local, 0x1f) == 0)
- ret = 8;
- else if (prism2_enable_genesis(local, 0x0f) == 0)
- ret = 16;
- else
- ret = -1;
-
- /* Disable genesis mode */
- local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
-
- return ret;
-}
-
-
-static int prism2_download_genesis(local_info_t *local,
- struct prism2_download_data *param)
-{
- struct net_device *dev = local->dev;
- int ram16 = 0, i;
- int ret = 0;
-
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -EBUSY;
- }
-
- if (!local->func->genesis_reset || !local->func->cor_sreset) {
- printk(KERN_INFO "%s: Genesis mode downloading not supported "
- "with this hwmodel\n", dev->name);
- return -EOPNOTSUPP;
- }
-
- local->hw_downloading = 1;
-
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_DEBUG "%s: failed to enable AUX port\n",
- dev->name);
- ret = -EIO;
- goto out;
- }
-
- if (local->sram_type == -1) {
- /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
- if (prism2_enable_genesis(local, 0x1f) == 0) {
- ram16 = 0;
- PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
- "SRAM\n", dev->name);
- } else if (prism2_enable_genesis(local, 0x0f) == 0) {
- ram16 = 1;
- PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
- "SRAM\n", dev->name);
- } else {
- printk(KERN_DEBUG "%s: Could not initiate genesis "
- "mode\n", dev->name);
- ret = -EIO;
- goto out;
- }
- } else {
- if (prism2_enable_genesis(local, local->sram_type == 8 ?
- 0x1f : 0x0f)) {
- printk(KERN_DEBUG "%s: Failed to set Genesis "
- "mode (sram_type=%d)\n", dev->name,
- local->sram_type);
- ret = -EIO;
- goto out;
- }
- ram16 = local->sram_type != 8;
- }
-
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
- dev->name, param->data[i].len, param->data[i].addr);
- if (hfa384x_to_aux(dev, param->data[i].addr,
- param->data[i].len, param->data[i].data)) {
- printk(KERN_WARNING "%s: RAM download at 0x%08x "
- "(len=%d) failed\n", dev->name,
- param->data[i].addr, param->data[i].len);
- ret = -EIO;
- goto out;
- }
- }
-
- PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
- local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
- dev->name);
- }
-
- mdelay(5);
- local->hw_downloading = 0;
-
- PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
- /*
- * Make sure the INIT command does not generate a command completion
- * event by disabling interrupts.
- */
- hfa384x_disable_interrupts(dev);
- if (prism2_hw_init(dev, 1)) {
- printk(KERN_DEBUG "%s: Initialization after genesis mode "
- "download failed\n", dev->name);
- ret = -EIO;
- goto out;
- }
-
- PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
- if (prism2_hw_init2(dev, 1)) {
- printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
- "download failed\n", dev->name);
- ret = -EIO;
- goto out;
- }
-
- out:
- local->hw_downloading = 0;
- return ret;
-}
-
-
-#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
-/* Note! Non-volatile downloading functionality has not yet been tested
- * thoroughly and it may corrupt flash image and effectively kill the card that
- * is being updated. You have been warned. */
-
-static inline int prism2_download_block(struct net_device *dev,
- u32 addr, u8 *data,
- u32 bufaddr, int rest_len)
-{
- u16 param0, param1;
- int block_len;
-
- block_len = rest_len < 4096 ? rest_len : 4096;
-
- param0 = addr & 0xffff;
- param1 = addr >> 16;
-
- HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
-
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
- param0)) {
- printk(KERN_WARNING "%s: Flash download command execution "
- "failed\n", dev->name);
- return -1;
- }
-
- if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
- printk(KERN_WARNING "%s: flash download at 0x%08x "
- "(len=%d) failed\n", dev->name, addr, block_len);
- return -1;
- }
-
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
- 0)) {
- printk(KERN_WARNING "%s: Flash write command execution "
- "failed\n", dev->name);
- return -1;
- }
-
- return block_len;
-}
-
-
-static int prism2_download_nonvolatile(local_info_t *local,
- struct prism2_download_data *dl)
-{
- struct net_device *dev = local->dev;
- int ret = 0, i;
- struct {
- __le16 page;
- __le16 offset;
- __le16 len;
- } dlbuffer;
- u32 bufaddr;
-
- if (local->hw_downloading) {
- printk(KERN_WARNING "%s: Already downloading - aborting new "
- "request\n", dev->name);
- return -1;
- }
-
- ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
- &dlbuffer, 6, 0);
-
- if (ret < 0) {
- printk(KERN_WARNING "%s: Could not read download buffer "
- "parameters\n", dev->name);
- goto out;
- }
-
- printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
- le16_to_cpu(dlbuffer.len),
- le16_to_cpu(dlbuffer.page),
- le16_to_cpu(dlbuffer.offset));
-
- bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
-
- local->hw_downloading = 1;
-
- if (!local->pri_only) {
- prism2_hw_shutdown(dev, 0);
-
- if (prism2_hw_init(dev, 0)) {
- printk(KERN_WARNING "%s: Could not initialize card for"
- " download\n", dev->name);
- ret = -1;
- goto out;
- }
- }
-
- hfa384x_disable_interrupts(dev);
-
- if (prism2_enable_aux_port(dev, 1)) {
- printk(KERN_WARNING "%s: Could not enable AUX port\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
- for (i = 0; i < dl->num_areas; i++) {
- int rest_len = dl->data[i].len;
- int data_off = 0;
-
- while (rest_len > 0) {
- int block_len;
-
- block_len = prism2_download_block(
- dev, dl->data[i].addr + data_off,
- dl->data[i].data + data_off, bufaddr,
- rest_len);
-
- if (block_len < 0) {
- ret = -1;
- goto out;
- }
-
- rest_len -= block_len;
- data_off += block_len;
- }
- }
-
- HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
- (HFA384X_PROGMODE_DISABLE << 8), 0)) {
- printk(KERN_WARNING "%s: Download command execution failed\n",
- dev->name);
- ret = -1;
- goto out;
- }
-
- if (prism2_enable_aux_port(dev, 0)) {
- printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
- dev->name);
- /* continue anyway.. restart should have taken care of this */
- }
-
- mdelay(5);
-
- local->func->hw_reset(dev);
- local->hw_downloading = 0;
- if (prism2_hw_config(dev, 2)) {
- printk(KERN_WARNING "%s: Card configuration after flash "
- "download failed\n", dev->name);
- ret = -1;
- } else {
- printk(KERN_INFO "%s: Card initialized successfully after "
- "flash download\n", dev->name);
- }
-
- out:
- local->hw_downloading = 0;
- return ret;
-}
-#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
-
-
-static void prism2_download_free_data(struct prism2_download_data *dl)
-{
- int i;
-
- if (dl == NULL)
- return;
-
- for (i = 0; i < dl->num_areas; i++)
- kfree(dl->data[i].data);
- kfree(dl);
-}
-
-
-static int prism2_download(local_info_t *local,
- struct prism2_download_param *param)
-{
- int ret = 0;
- int i;
- u32 total_len = 0;
- struct prism2_download_data *dl = NULL;
-
- printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
- "num_areas=%d\n",
- param->dl_cmd, param->start_addr, param->num_areas);
-
- if (param->num_areas > 100) {
- ret = -EINVAL;
- goto out;
- }
-
- dl = kzalloc(sizeof(*dl) + param->num_areas *
- sizeof(struct prism2_download_data_area), GFP_KERNEL);
- if (dl == NULL) {
- ret = -ENOMEM;
- goto out;
- }
- dl->dl_cmd = param->dl_cmd;
- dl->start_addr = param->start_addr;
- dl->num_areas = param->num_areas;
- for (i = 0; i < param->num_areas; i++) {
- PDEBUG(DEBUG_EXTRA2,
- " area %d: addr=0x%08x len=%d ptr=0x%p\n",
- i, param->data[i].addr, param->data[i].len,
- param->data[i].ptr);
-
- dl->data[i].addr = param->data[i].addr;
- dl->data[i].len = param->data[i].len;
-
- total_len += param->data[i].len;
- if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
- total_len > PRISM2_MAX_DOWNLOAD_LEN) {
- ret = -E2BIG;
- goto out;
- }
-
- dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
- if (dl->data[i].data == NULL) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (copy_from_user(dl->data[i].data, param->data[i].ptr,
- param->data[i].len)) {
- ret = -EFAULT;
- goto out;
- }
- }
-
- switch (param->dl_cmd) {
- case PRISM2_DOWNLOAD_VOLATILE:
- case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
- ret = prism2_download_volatile(local, dl);
- break;
- case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
- case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
- ret = prism2_download_genesis(local, dl);
- break;
- case PRISM2_DOWNLOAD_NON_VOLATILE:
-#ifdef PRISM2_NON_VOLATILE_DOWNLOAD
- ret = prism2_download_nonvolatile(local, dl);
-#else /* PRISM2_NON_VOLATILE_DOWNLOAD */
- printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
- local->dev->name);
- ret = -EOPNOTSUPP;
-#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
- break;
- default:
- printk(KERN_DEBUG "%s: unsupported download command %d\n",
- local->dev->name, param->dl_cmd);
- ret = -EINVAL;
- break;
- }
-
- out:
- if (ret == 0 && dl &&
- param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
- prism2_download_free_data(local->dl_pri);
- local->dl_pri = dl;
- } else if (ret == 0 && dl &&
- param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
- prism2_download_free_data(local->dl_sec);
- local->dl_sec = dl;
- } else
- prism2_download_free_data(dl);
-
- return ret;
-}
diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c
deleted file mode 100644
index b74f4cb5d6d39..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_hw.c
+++ /dev/null
@@ -1,3387 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Host AP (software wireless LAN access point) driver for
- * Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <[email protected]>
- * Copyright (c) 2002-2005, Jouni Malinen <[email protected]>
- *
- * FIX:
- * - there is currently no way of associating TX packets to correct wds device
- * when TX Exc/OK event occurs, so all tx_packets and some
- * tx_errors/tx_dropped are added to the main netdevice; using sw_support
- * field in txdesc might be used to fix this (using Alloc event to increment
- * tx_packets would need some further info in txfid table)
- *
- * Buffer Access Path (BAP) usage:
- * Prism2 cards have two separate BAPs for accessing the card memory. These
- * should allow concurrent access to two different frames and the driver
- * previously used BAP0 for sending data and BAP1 for receiving data.
- * However, there seems to be number of issues with concurrent access and at
- * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI
- * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between
- * host and card memories. BAP0 accesses are protected with local->baplock
- * (spin_lock_bh) to prevent concurrent use.
- */
-
-
-
-#include <asm/delay.h>
-#include <linux/uaccess.h>
-
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/wait.h>
-#include <linux/sched/signal.h>
-#include <linux/rtnetlink.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
-#include <asm/irq.h>
-
-#include "hostap_80211.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-
-/* #define final_version */
-
-static int mtu = 1500;
-module_param(mtu, int, 0444);
-MODULE_PARM_DESC(mtu, "Maximum transfer unit");
-
-static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS };
-module_param_array(channel, int, NULL, 0444);
-MODULE_PARM_DESC(channel, "Initial channel");
-
-static char essid[33] = "test";
-module_param_string(essid, essid, sizeof(essid), 0444);
-MODULE_PARM_DESC(essid, "Host AP's ESSID");
-
-static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS };
-module_param_array(iw_mode, int, NULL, 0444);
-MODULE_PARM_DESC(iw_mode, "Initial operation mode");
-
-static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS };
-module_param_array(beacon_int, int, NULL, 0444);
-MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)");
-
-static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS };
-module_param_array(dtim_period, int, NULL, 0444);
-MODULE_PARM_DESC(dtim_period, "DTIM period");
-
-static char dev_template[16] = "wlan%d";
-module_param_string(dev_template, dev_template, sizeof(dev_template), 0444);
-MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: "
- "wlan%d)");
-
-#ifdef final_version
-#define EXTRA_EVENTS_WTERR 0
-#else
-/* check WTERR events (Wait Time-out) in development versions */
-#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR
-#endif
-
-/* Events that will be using BAP0 */
-#define HFA384X_BAP0_EVENTS \
- (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX)
-
-/* event mask, i.e., events that will result in an interrupt */
-#define HFA384X_EVENT_MASK \
- (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \
- HFA384X_EV_CMD | HFA384X_EV_TICK | \
- EXTRA_EVENTS_WTERR)
-
-/* Default TX control flags: use 802.11 headers and request interrupt for
- * failed transmits. Frames that request ACK callback, will add
- * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy.
- */
-#define HFA384X_TX_CTRL_FLAGS \
- (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX)
-
-
-/* ca. 1 usec */
-#define HFA384X_CMD_BUSY_TIMEOUT 5000
-#define HFA384X_BAP_BUSY_TIMEOUT 50000
-
-/* ca. 10 usec */
-#define HFA384X_CMD_COMPL_TIMEOUT 20000
-#define HFA384X_DL_COMPL_TIMEOUT 1000000
-
-/* Wait times for initialization; yield to other processes to avoid busy
- * waiting for long time. */
-#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */
-#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */
-
-
-static void prism2_hw_reset(struct net_device *dev);
-static void prism2_check_sta_fw_version(local_info_t *local);
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
-/* hostap_download.c */
-static const struct proc_ops prism2_download_aux_dump_proc_ops;
-static u8 * prism2_read_pda(struct net_device *dev);
-static int prism2_download(local_info_t *local,
- struct prism2_download_param *param);
-static void prism2_download_free_data(struct prism2_download_data *dl);
-static int prism2_download_volatile(local_info_t *local,
- struct prism2_download_data *param);
-static int prism2_download_genesis(local_info_t *local,
- struct prism2_download_data *param);
-static int prism2_get_ram_size(local_info_t *local);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-
-
-
-#ifndef final_version
-/* magic value written to SWSUPPORT0 reg. for detecting whether card is still
- * present */
-#define HFA384X_MAGIC 0x8A32
-#endif
-
-static void hfa384x_read_regs(struct net_device *dev,
- struct hfa384x_regs *regs)
-{
- regs->cmd = HFA384X_INW(HFA384X_CMD_OFF);
- regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
- regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF);
- regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF);
- regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF);
-}
-
-
-/**
- * __hostap_cmd_queue_free - Free Prism2 command queue entry (private)
- * @local: pointer to private Host AP driver data
- * @entry: Prism2 command queue entry to be freed
- * @del_req: request the entry to be removed
- *
- * Internal helper function for freeing Prism2 command queue entries.
- * Caller must have acquired local->cmdlock before calling this function.
- */
-static inline void __hostap_cmd_queue_free(local_info_t *local,
- struct hostap_cmd_queue *entry,
- int del_req)
-{
- if (del_req) {
- entry->del_req = 1;
- if (!list_empty(&entry->list)) {
- list_del_init(&entry->list);
- local->cmd_queue_len--;
- }
- }
-
- if (refcount_dec_and_test(&entry->usecnt) && entry->del_req)
- kfree(entry);
-}
-
-
-/**
- * hostap_cmd_queue_free - Free Prism2 command queue entry
- * @local: pointer to private Host AP driver data
- * @entry: Prism2 command queue entry to be freed
- * @del_req: request the entry to be removed
- *
- * Free a Prism2 command queue entry.
- */
-static inline void hostap_cmd_queue_free(local_info_t *local,
- struct hostap_cmd_queue *entry,
- int del_req)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&local->cmdlock, flags);
- __hostap_cmd_queue_free(local, entry, del_req);
- spin_unlock_irqrestore(&local->cmdlock, flags);
-}
-
-
-/**
- * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries
- * @local: pointer to private Host AP driver data
- */
-static void prism2_clear_cmd_queue(local_info_t *local)
-{
- struct list_head *ptr, *n;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
-
- spin_lock_irqsave(&local->cmdlock, flags);
- list_for_each_safe(ptr, n, &local->cmd_queue) {
- entry = list_entry(ptr, struct hostap_cmd_queue, list);
- refcount_inc(&entry->usecnt);
- printk(KERN_DEBUG "%s: removed pending cmd_queue entry "
- "(type=%d, cmd=0x%04x, param0=0x%04x)\n",
- local->dev->name, entry->type, entry->cmd,
- entry->param0);
- __hostap_cmd_queue_free(local, entry, 1);
- }
- if (local->cmd_queue_len) {
- /* This should not happen; print debug message and clear
- * queue length. */
- printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after "
- "flush\n", local->dev->name, local->cmd_queue_len);
- local->cmd_queue_len = 0;
- }
- spin_unlock_irqrestore(&local->cmdlock, flags);
-}
-
-
-/**
- * hfa384x_cmd_issue - Issue a Prism2 command to the hardware
- * @dev: pointer to net_device
- * @entry: Prism2 command queue entry to be issued
- */
-static int hfa384x_cmd_issue(struct net_device *dev,
- struct hostap_cmd_queue *entry)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int tries;
- u16 reg;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->card_present && !local->func->card_present(local))
- return -ENODEV;
-
- if (entry->issued) {
- printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n",
- dev->name, entry);
- }
-
- /* wait until busy bit is clear; this should always be clear since the
- * commands are serialized */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
-#ifndef final_version
- if (tries != HFA384X_CMD_BUSY_TIMEOUT) {
- prism2_io_debug_error(dev, 1);
- printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy "
- "for %d usec\n", dev->name,
- HFA384X_CMD_BUSY_TIMEOUT - tries);
- }
-#endif
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- prism2_io_debug_error(dev, 2);
- printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - "
- "reg=0x%04x\n", dev->name, reg);
- return -ETIMEDOUT;
- }
-
- /* write command */
- spin_lock_irqsave(&local->cmdlock, flags);
- HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF);
- HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF);
- entry->issued = 1;
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- return 0;
-}
-
-
-/**
- * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @param1: value for Param1 register (pointer; %NULL if not used)
- * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed
- *
- * Issue given command (possibly after waiting in command queue) and sleep
- * until the command is completed (or timed out or interrupted). This can be
- * called only from user process context.
- */
-static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0,
- u16 *param1, u16 *resp0)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int err, res, issue, issued = 0;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
- DECLARE_WAITQUEUE(wait, current);
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
- dev->name);
- return -1;
- }
-
- if (signal_pending(current))
- return -EINTR;
-
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry == NULL)
- return -ENOMEM;
-
- refcount_set(&entry->usecnt, 1);
- entry->type = CMD_SLEEP;
- entry->cmd = cmd;
- entry->param0 = param0;
- if (param1)
- entry->param1 = *param1;
- init_waitqueue_head(&entry->compl);
-
- /* prepare to wait for command completion event, but do not sleep yet
- */
- add_wait_queue(&entry->compl, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- spin_lock_irqsave(&local->cmdlock, flags);
- issue = list_empty(&local->cmd_queue);
- if (issue)
- entry->issuing = 1;
- list_add_tail(&entry->list, &local->cmd_queue);
- local->cmd_queue_len++;
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- err = 0;
- if (!issue)
- goto wait_completion;
-
- if (signal_pending(current))
- err = -EINTR;
-
- if (!err) {
- if (hfa384x_cmd_issue(dev, entry))
- err = -ETIMEDOUT;
- else
- issued = 1;
- }
-
- wait_completion:
- if (!err && entry->type != CMD_COMPLETED) {
- /* sleep until command is completed or timed out */
- res = schedule_timeout(2 * HZ);
- } else
- res = -1;
-
- if (!err && signal_pending(current))
- err = -EINTR;
-
- if (err && issued) {
- /* the command was issued, so a CmdCompl event should occur
- * soon; however, there's a pending signal and
- * schedule_timeout() would be interrupted; wait a short period
- * of time to avoid removing entry from the list before
- * CmdCompl event */
- udelay(300);
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&entry->compl, &wait);
-
- /* If entry->list is still in the list, it must be removed
- * first and in this case prism2_cmd_ev() does not yet have
- * local reference to it, and the data can be kfree()'d
- * here. If the command completion event is still generated,
- * it will be assigned to next (possibly) pending command, but
- * the driver will reset the card anyway due to timeout
- *
- * If the entry is not in the list prism2_cmd_ev() has a local
- * reference to it, but keeps cmdlock as long as the data is
- * needed, so the data can be kfree()'d here. */
-
- /* FIX: if the entry->list is in the list, it has not been completed
- * yet, so removing it here is somewhat wrong.. this could cause
- * references to freed memory and next list_del() causing NULL pointer
- * dereference.. it would probably be better to leave the entry in the
- * list and the list should be emptied during hw reset */
-
- spin_lock_irqsave(&local->cmdlock, flags);
- if (!list_empty(&entry->list)) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? "
- "(entry=%p, type=%d, res=%d)\n", dev->name, entry,
- entry->type, res);
- list_del_init(&entry->list);
- local->cmd_queue_len--;
- }
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- if (err) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n",
- dev->name, err);
- res = err;
- goto done;
- }
-
- if (entry->type != CMD_COMPLETED) {
- u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
- printk(KERN_DEBUG "%s: hfa384x_cmd: command was not "
- "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, "
- "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name,
- res, entry, entry->type, entry->cmd, entry->param0, reg,
- HFA384X_INW(HFA384X_INTEN_OFF));
- if (reg & HFA384X_EV_CMD) {
- /* Command completion event is pending, but the
- * interrupt was not delivered - probably an issue
- * with pcmcia-cs configuration. */
- printk(KERN_WARNING "%s: interrupt delivery does not "
- "seem to work\n", dev->name);
- }
- prism2_io_debug_error(dev, 3);
- res = -ETIMEDOUT;
- goto done;
- }
-
- if (resp0 != NULL)
- *resp0 = entry->resp0;
-#ifndef final_version
- if (entry->res) {
- printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, "
- "resp0=0x%04x\n",
- dev->name, cmd, entry->res, entry->resp0);
- }
-#endif /* final_version */
-
- res = entry->res;
- done:
- hostap_cmd_queue_free(local, entry, 1);
- return res;
-}
-
-
-/**
- * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @callback: command completion callback function (%NULL = no callback)
- * @context: context data to be given to the callback function
- *
- * Issue given command (possibly after waiting in command queue) and use
- * callback function to indicate command completion. This can be called both
- * from user and interrupt context. The callback function will be called in
- * hardware IRQ context. It can be %NULL, when no function is called when
- * command is completed.
- */
-static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0,
- void (*callback)(struct net_device *dev,
- long context, u16 resp0,
- u16 status),
- long context)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int issue, ret;
- unsigned long flags;
- struct hostap_cmd_queue *entry;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) {
- printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n",
- dev->name);
- return -1;
- }
-
- entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
- if (entry == NULL)
- return -ENOMEM;
-
- refcount_set(&entry->usecnt, 1);
- entry->type = CMD_CALLBACK;
- entry->cmd = cmd;
- entry->param0 = param0;
- entry->callback = callback;
- entry->context = context;
-
- spin_lock_irqsave(&local->cmdlock, flags);
- issue = list_empty(&local->cmd_queue);
- if (issue)
- entry->issuing = 1;
- list_add_tail(&entry->list, &local->cmd_queue);
- local->cmd_queue_len++;
- spin_unlock_irqrestore(&local->cmdlock, flags);
-
- if (issue && hfa384x_cmd_issue(dev, entry))
- ret = -ETIMEDOUT;
- else
- ret = 0;
-
- hostap_cmd_queue_free(local, entry, ret);
-
- return ret;
-}
-
-
-/**
- * __hfa384x_cmd_no_wait - Issue a Prism2 command (private)
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- * @io_debug_num: I/O debug error number
- *
- * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait().
- */
-static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0,
- int io_debug_num)
-{
- int tries;
- u16 reg;
-
- /* wait until busy bit is clear; this should always be clear since the
- * commands are serialized */
- tries = HFA384X_CMD_BUSY_TIMEOUT;
- while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
- tries--;
- udelay(1);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_CMD_OFF);
- prism2_io_debug_error(dev, io_debug_num);
- printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - "
- "reg=0x%04x\n", dev->name, io_debug_num, reg);
- return -ETIMEDOUT;
- }
-
- /* write command */
- HFA384X_OUTW(param0, HFA384X_PARAM0_OFF);
- HFA384X_OUTW(cmd, HFA384X_CMD_OFF);
-
- return 0;
-}
-
-
-/**
- * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- */
-static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0)
-{
- int res, tries;
- u16 reg;
-
- res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4);
- if (res)
- return res;
-
- /* wait for command completion */
- if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD)
- tries = HFA384X_DL_COMPL_TIMEOUT;
- else
- tries = HFA384X_CMD_COMPL_TIMEOUT;
-
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
- tries > 0) {
- tries--;
- udelay(10);
- }
- if (tries == 0) {
- reg = HFA384X_INW(HFA384X_EVSTAT_OFF);
- prism2_io_debug_error(dev, 5);
- printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - "
- "reg=0x%04x\n", dev->name, reg);
- return -ETIMEDOUT;
- }
-
- res = (HFA384X_INW(HFA384X_STATUS_OFF) &
- (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) |
- BIT(8))) >> 8;
-#ifndef final_version
- if (res) {
- printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n",
- dev->name, cmd, res);
- }
-#endif
-
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
-
- return res;
-}
-
-
-/**
- * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion
- * @dev: pointer to net_device
- * @cmd: Prism2 command code (HFA384X_CMD_CODE_*)
- * @param0: value for Param0 register
- */
-static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd,
- u16 param0)
-{
- return __hfa384x_cmd_no_wait(dev, cmd, param0, 6);
-}
-
-
-/**
- * prism2_cmd_ev - Prism2 command completion event handler
- * @dev: pointer to net_device
- *
- * Interrupt handler for command completion events. Called by the main
- * interrupt handler in hardware IRQ context. Read Resp0 and status registers
- * from the hardware and ACK the event. Depending on the issued command type
- * either wake up the sleeping process that is waiting for command completion
- * or call the callback function. Issue the next command, if one is pending.
- */
-static void prism2_cmd_ev(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hostap_cmd_queue *entry = NULL;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock(&local->cmdlock);
- if (!list_empty(&local->cmd_queue)) {
- entry = list_entry(local->cmd_queue.next,
- struct hostap_cmd_queue, list);
- refcount_inc(&entry->usecnt);
- list_del_init(&entry->list);
- local->cmd_queue_len--;
-
- if (!entry->issued) {
- printk(KERN_DEBUG "%s: Command completion event, but "
- "cmd not issued\n", dev->name);
- __hostap_cmd_queue_free(local, entry, 1);
- entry = NULL;
- }
- }
- spin_unlock(&local->cmdlock);
-
- if (!entry) {
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: Command completion event, but no "
- "pending commands\n", dev->name);
- return;
- }
-
- entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF);
- entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) &
- (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) |
- BIT(9) | BIT(8))) >> 8;
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
-
- /* TODO: rest of the CmdEv handling could be moved to tasklet */
- if (entry->type == CMD_SLEEP) {
- entry->type = CMD_COMPLETED;
- wake_up_interruptible(&entry->compl);
- } else if (entry->type == CMD_CALLBACK) {
- if (entry->callback)
- entry->callback(dev, entry->context, entry->resp0,
- entry->res);
- } else {
- printk(KERN_DEBUG "%s: Invalid command completion type %d\n",
- dev->name, entry->type);
- }
- hostap_cmd_queue_free(local, entry, 1);
-
- /* issue next command, if pending */
- entry = NULL;
- spin_lock(&local->cmdlock);
- if (!list_empty(&local->cmd_queue)) {
- entry = list_entry(local->cmd_queue.next,
- struct hostap_cmd_queue, list);
- if (entry->issuing) {
- /* hfa384x_cmd() has already started issuing this
- * command, so do not start here */
- entry = NULL;
- }
- if (entry)
- refcount_inc(&entry->usecnt);
- }
- spin_unlock(&local->cmdlock);
-
- if (entry) {
- /* issue next command; if command issuing fails, remove the
- * entry from cmd_queue */
- int res = hfa384x_cmd_issue(dev, entry);
- spin_lock(&local->cmdlock);
- __hostap_cmd_queue_free(local, entry, res);
- spin_unlock(&local->cmdlock);
- }
-}
-
-
-static int hfa384x_wait_offset(struct net_device *dev, u16 o_off)
-{
- int tries = HFA384X_BAP_BUSY_TIMEOUT;
- int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
-
- while (res && tries > 0) {
- tries--;
- udelay(1);
- res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY;
- }
- return res;
-}
-
-
-/* Offset must be even */
-static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id,
- int offset)
-{
- u16 o_off, s_off;
- int ret = 0;
-
- if (offset % 2 || bap > 1)
- return -EINVAL;
-
- if (bap == BAP1) {
- o_off = HFA384X_OFFSET1_OFF;
- s_off = HFA384X_SELECT1_OFF;
- } else {
- o_off = HFA384X_OFFSET0_OFF;
- s_off = HFA384X_SELECT0_OFF;
- }
-
- if (hfa384x_wait_offset(dev, o_off)) {
- prism2_io_debug_error(dev, 7);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n",
- dev->name);
- ret = -ETIMEDOUT;
- goto out;
- }
-
- HFA384X_OUTW(id, s_off);
- HFA384X_OUTW(offset, o_off);
-
- if (hfa384x_wait_offset(dev, o_off)) {
- prism2_io_debug_error(dev, 8);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n",
- dev->name);
- ret = -ETIMEDOUT;
- goto out;
- }
-#ifndef final_version
- if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) {
- prism2_io_debug_error(dev, 9);
- printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error "
- "(%d,0x04%x,%d); reg=0x%04x\n",
- dev->name, bap, id, offset, HFA384X_INW(o_off));
- ret = -EINVAL;
- }
-#endif
-
- out:
- return ret;
-}
-
-
-static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
- int exact_len)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int res, rlen = 0;
- struct hfa384x_rid_hdr rec;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI "
- "f/w\n", dev->name, rid, len);
- return -ENOTTY; /* Well.. not really correct, but return
- * something unique enough.. */
- }
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
-
- res = mutex_lock_interruptible(&local->rid_bap_mtx);
- if (res)
- return res;
-
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL);
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
- "(res=%d, rid=%04x, len=%d)\n",
- dev->name, res, rid, len);
- mutex_unlock(&local->rid_bap_mtx);
- return res;
- }
-
- spin_lock_bh(&local->baplock);
-
- res = hfa384x_setup_bap(dev, BAP0, rid, 0);
- if (res)
- goto unlock;
-
- res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
- if (res)
- goto unlock;
-
- if (le16_to_cpu(rec.len) == 0) {
- /* RID not available */
- res = -ENODATA;
- goto unlock;
- }
-
- rlen = (le16_to_cpu(rec.len) - 1) * 2;
- if (exact_len && rlen != len) {
- printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
- "rid=0x%04x, len=%d (expected %d)\n",
- dev->name, rid, rlen, len);
- res = -ENODATA;
- }
-
- res = hfa384x_from_bap(dev, BAP0, buf, len);
-
-unlock:
- spin_unlock_bh(&local->baplock);
- mutex_unlock(&local->rid_bap_mtx);
-
- if (res) {
- if (res != -ENODATA)
- printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, "
- "len=%d) - failed - res=%d\n", dev->name, rid,
- len, res);
- if (res == -ETIMEDOUT)
- prism2_hw_reset(dev);
- return res;
- }
-
- return rlen;
-}
-
-
-static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_rid_hdr rec;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI "
- "f/w\n", dev->name, rid, len);
- return -ENOTTY; /* Well.. not really correct, but return
- * something unique enough.. */
- }
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
-
- rec.rid = cpu_to_le16(rid);
- /* RID len in words and +1 for rec.rid */
- rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
-
- res = mutex_lock_interruptible(&local->rid_bap_mtx);
- if (res)
- return res;
-
- spin_lock_bh(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, rid, 0);
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec));
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, buf, len);
- spin_unlock_bh(&local->baplock);
-
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
- "failed - res=%d\n", dev->name, rid, len, res);
- mutex_unlock(&local->rid_bap_mtx);
- return res;
- }
-
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
- mutex_unlock(&local->rid_bap_mtx);
-
- if (res) {
- printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
- "failed (res=%d, rid=%04x, len=%d)\n",
- dev->name, res, rid, len);
-
- if (res == -ETIMEDOUT)
- prism2_hw_reset(dev);
- }
-
- return res;
-}
-
-
-static void hfa384x_disable_interrupts(struct net_device *dev)
-{
- /* disable interrupts and clear event status */
- HFA384X_OUTW(0, HFA384X_INTEN_OFF);
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
-}
-
-
-static void hfa384x_enable_interrupts(struct net_device *dev)
-{
- /* ack pending events and enable interrupts from selected events */
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
-}
-
-
-static void hfa384x_events_no_bap0(struct net_device *dev)
-{
- HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS,
- HFA384X_INTEN_OFF);
-}
-
-
-static void hfa384x_events_all(struct net_device *dev)
-{
- HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF);
-}
-
-
-static void hfa384x_events_only_cmd(struct net_device *dev)
-{
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF);
-}
-
-
-static u16 hfa384x_allocate_fid(struct net_device *dev, int len)
-{
- u16 fid;
- unsigned long delay;
-
- /* FIX: this could be replace with hfa384x_cmd() if the Alloc event
- * below would be handled like CmdCompl event (sleep here, wake up from
- * interrupt handler */
- if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) {
- printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n",
- dev->name, len);
- return 0xffff;
- }
-
- delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT;
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) &&
- time_before(jiffies, delay))
- yield();
- if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) {
- printk("%s: fid allocate, len=%d - timeout\n", dev->name, len);
- return 0xffff;
- }
-
- fid = HFA384X_INW(HFA384X_ALLOCFID_OFF);
- HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
-
- return fid;
-}
-
-
-static int prism2_reset_port(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (!local->dev_enabled)
- return 0;
-
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0,
- NULL, NULL);
- if (res)
- printk(KERN_DEBUG "%s: reset port failed to disable port\n",
- dev->name);
- else {
- res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0,
- NULL, NULL);
- if (res)
- printk(KERN_DEBUG "%s: reset port failed to enable "
- "port\n", dev->name);
- }
-
- /* It looks like at least some STA firmware versions reset
- * fragmentation threshold back to 2346 after enable command. Restore
- * the configured value, if it differs from this default. */
- if (local->fragm_threshold != 2346 &&
- hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- local->fragm_threshold)) {
- printk(KERN_DEBUG "%s: failed to restore fragmentation "
- "threshold (%d) after Port0 enable\n",
- dev->name, local->fragm_threshold);
- }
-
- /* Some firmwares lose antenna selection settings on reset */
- (void) hostap_set_antsel(local);
-
- return res;
-}
-
-
-static int prism2_get_version_info(struct net_device *dev, u16 rid,
- const char *txt)
-{
- struct hfa384x_comp_ident comp;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- /* PRI f/w not yet available - cannot read RIDs */
- return -1;
- }
- if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) {
- printk(KERN_DEBUG "Could not get RID for component %s\n", txt);
- return -1;
- }
-
- printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt,
- __le16_to_cpu(comp.id), __le16_to_cpu(comp.major),
- __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant));
- return 0;
-}
-
-
-static int prism2_setup_rids(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 tmp;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000);
-
- if (!local->fw_ap) {
- u16 tmp1 = hostap_get_porttype(local);
- ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1);
- if (ret) {
- printk("%s: Port type setting to %d failed\n",
- dev->name, tmp1);
- goto fail;
- }
- }
-
- /* Setting SSID to empty string seems to kill the card in Host AP mode
- */
- if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') {
- ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID,
- local->essid);
- if (ret) {
- printk("%s: AP own SSID setting failed\n", dev->name);
- goto fail;
- }
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN,
- PRISM2_DATA_MAXLEN);
- if (ret) {
- printk("%s: MAC data length setting to %d failed\n",
- dev->name, PRISM2_DATA_MAXLEN);
- goto fail;
- }
-
- if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) {
- printk("%s: Channel list read failed\n", dev->name);
- ret = -EINVAL;
- goto fail;
- }
- local->channel_mask = le16_to_cpu(tmp);
-
- if (local->channel < 1 || local->channel > 14 ||
- !(local->channel_mask & (1 << (local->channel - 1)))) {
- printk(KERN_WARNING "%s: Channel setting out of range "
- "(%d)!\n", dev->name, local->channel);
- ret = -EBUSY;
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel);
- if (ret) {
- printk("%s: Channel setting to %d failed\n",
- dev->name, local->channel);
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT,
- local->beacon_int);
- if (ret) {
- printk("%s: Beacon interval setting to %d failed\n",
- dev->name, local->beacon_int);
- /* this may fail with Symbol/Lucent firmware */
- if (ret == -ETIMEDOUT)
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD,
- local->dtim_period);
- if (ret) {
- printk("%s: DTIM period setting to %d failed\n",
- dev->name, local->dtim_period);
- /* this may fail with Symbol/Lucent firmware */
- if (ret == -ETIMEDOUT)
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
- local->is_promisc);
- if (ret)
- printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n",
- dev->name, local->is_promisc);
-
- if (!local->fw_ap) {
- ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID,
- local->essid);
- if (ret) {
- printk("%s: Desired SSID setting failed\n", dev->name);
- goto fail;
- }
- }
-
- /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and
- * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic
- * rates */
- if (local->tx_rate_control == 0) {
- local->tx_rate_control =
- HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS |
- HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- }
- if (local->basic_rates == 0)
- local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS;
-
- if (!local->fw_ap) {
- ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
- local->tx_rate_control);
- if (ret) {
- printk("%s: TXRateControl setting to %d failed\n",
- dev->name, local->tx_rate_control);
- goto fail;
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
- local->tx_rate_control);
- if (ret) {
- printk("%s: cnfSupportedRates setting to %d failed\n",
- dev->name, local->tx_rate_control);
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
- local->basic_rates);
- if (ret) {
- printk("%s: cnfBasicRates setting to %d failed\n",
- dev->name, local->basic_rates);
- }
-
- ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1);
- if (ret) {
- printk("%s: Create IBSS setting to 1 failed\n",
- dev->name);
- }
- }
-
- if (local->name_set)
- (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME,
- local->name);
-
- if (hostap_set_encryption(local)) {
- printk(KERN_INFO "%s: could not configure encryption\n",
- dev->name);
- }
-
- (void) hostap_set_antsel(local);
-
- if (hostap_set_roaming(local)) {
- printk(KERN_INFO "%s: could not set host roaming\n",
- dev->name);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) &&
- hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec))
- printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n",
- dev->name, local->enh_sec);
-
- /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently
- * not working correctly (last seven counters report bogus values).
- * This has been fixed in 0.8.2, so enable 32-bit tallies only
- * beginning with that firmware version. Another bug fix for 32-bit
- * tallies in 1.4.0; should 16-bit tallies be used for some other
- * versions, too? */
- if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) {
- if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) {
- printk(KERN_INFO "%s: cnfThirty2Tally setting "
- "failed\n", dev->name);
- local->tallies32 = 0;
- } else
- local->tallies32 = 1;
- } else
- local->tallies32 = 0;
-
- hostap_set_auth_algs(local);
-
- if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- local->fragm_threshold)) {
- printk(KERN_INFO "%s: setting FragmentationThreshold to %d "
- "failed\n", dev->name, local->fragm_threshold);
- }
-
- if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD,
- local->rts_threshold)) {
- printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n",
- dev->name, local->rts_threshold);
- }
-
- if (local->manual_retry_count >= 0 &&
- hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
- local->manual_retry_count)) {
- printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n",
- dev->name, local->manual_retry_count);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) &&
- hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) {
- local->rssi_to_dBm = le16_to_cpu(tmp);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa &&
- hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) {
- printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n",
- dev->name);
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem &&
- hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT,
- local->generic_elem, local->generic_elem_len)) {
- printk(KERN_INFO "%s: setting genericElement failed\n",
- dev->name);
- }
-
- fail:
- return ret;
-}
-
-
-static int prism2_hw_init(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int ret, first = 1;
- unsigned long start, delay;
-
- PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n");
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits);
-
- init:
- /* initialize HFA 384x */
- ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0);
- if (ret) {
- printk(KERN_INFO "%s: first command failed - assuming card "
- "does not have primary firmware\n", dev_info);
- }
-
- if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
- /* EvStat has Cmd bit set in some cases, so retry once if no
- * wait was needed */
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: init command completed too quickly - "
- "retrying\n", dev->name);
- first = 0;
- goto init;
- }
-
- start = jiffies;
- delay = jiffies + HFA384X_INIT_TIMEOUT;
- while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) &&
- time_before(jiffies, delay))
- yield();
- if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) {
- printk(KERN_DEBUG "%s: assuming no Primary image in "
- "flash - card initialization not completed\n",
- dev_info);
- local->no_pri = 1;
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- if (local->sram_type == -1)
- local->sram_type = prism2_get_ram_size(local);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
- return 1;
- }
- local->no_pri = 0;
- printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n",
- (jiffies - start) * 1000 / HZ);
- HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
- return 0;
-}
-
-
-static int prism2_hw_init2(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int i;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- kfree(local->pda);
- if (local->no_pri)
- local->pda = NULL;
- else
- local->pda = prism2_read_pda(dev);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- hfa384x_disable_interrupts(dev);
-
-#ifndef final_version
- HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF);
- if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
- printk("SWSUPPORT0 write/read failed: %04X != %04X\n",
- HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC);
- goto failed;
- }
-#endif
-
- if (initial || local->pri_only) {
- hfa384x_events_only_cmd(dev);
- /* get card version information */
- if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") ||
- prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) {
- hfa384x_disable_interrupts(dev);
- goto failed;
- }
-
- if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) {
- printk(KERN_DEBUG "%s: Failed to read STA f/w version "
- "- only Primary f/w present\n", dev->name);
- local->pri_only = 1;
- return 0;
- }
- local->pri_only = 0;
- hfa384x_disable_interrupts(dev);
- }
-
- /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and
- * enable interrupts before this. This would also require some sort of
- * sleeping AllocEv waiting */
-
- /* allocate TX FIDs */
- local->txfid_len = PRISM2_TXFID_LEN;
- for (i = 0; i < PRISM2_TXFID_COUNT; i++) {
- local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len);
- if (local->txfid[i] == 0xffff && local->txfid_len > 1600) {
- local->txfid[i] = hfa384x_allocate_fid(dev, 1600);
- if (local->txfid[i] != 0xffff) {
- printk(KERN_DEBUG "%s: Using shorter TX FID "
- "(1600 bytes)\n", dev->name);
- local->txfid_len = 1600;
- }
- }
- if (local->txfid[i] == 0xffff)
- goto failed;
- local->intransmitfid[i] = PRISM2_TXFID_EMPTY;
- }
-
- hfa384x_events_only_cmd(dev);
-
- if (initial) {
- u8 addr[ETH_ALEN] = {};
- struct list_head *ptr;
-
- prism2_check_sta_fw_version(local);
-
- if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR,
- addr, ETH_ALEN, 1) < 0) {
- printk("%s: could not get own MAC address\n",
- dev->name);
- }
- eth_hw_addr_set(dev, addr);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- eth_hw_addr_inherit(iface->dev, dev);
- }
- } else if (local->fw_ap)
- prism2_check_sta_fw_version(local);
-
- prism2_setup_rids(dev);
-
- /* MAC is now configured, but port 0 is not yet enabled */
- return 0;
-
- failed:
- if (!local->no_pri)
- printk(KERN_WARNING "%s: Initialization failed\n", dev_info);
- return 1;
-}
-
-
-static int prism2_hw_enable(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int was_resetting;
-
- iface = netdev_priv(dev);
- local = iface->local;
- was_resetting = local->hw_resetting;
-
- if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) {
- printk("%s: MAC port 0 enabling failed\n", dev->name);
- return 1;
- }
-
- local->hw_ready = 1;
- local->hw_reset_tries = 0;
- local->hw_resetting = 0;
- hfa384x_enable_interrupts(dev);
-
- /* at least D-Link DWL-650 seems to require additional port reset
- * before it starts acting as an AP, so reset port automatically
- * here just in case */
- if (initial && prism2_reset_port(dev)) {
- printk("%s: MAC port 0 resetting failed\n", dev->name);
- return 1;
- }
-
- if (was_resetting && netif_queue_stopped(dev)) {
- /* If hw_reset() was called during pending transmit, netif
- * queue was stopped. Wake it up now since the wlan card has
- * been resetted. */
- netif_wake_queue(dev);
- }
-
- return 0;
-}
-
-
-static int prism2_hw_config(struct net_device *dev, int initial)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->hw_downloading)
- return 1;
-
- if (prism2_hw_init(dev, initial)) {
- return local->no_pri ? 0 : 1;
- }
-
- if (prism2_hw_init2(dev, initial))
- return 1;
-
- /* Enable firmware if secondary image is loaded and at least one of the
- * netdevices is up. */
- if (!local->pri_only &&
- (initial == 0 || (initial == 2 && local->num_dev_open > 0))) {
- if (!local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_ENABLE);
- local->dev_enabled = 1;
- return prism2_hw_enable(dev, initial);
- }
-
- return 0;
-}
-
-
-static void prism2_hw_shutdown(struct net_device *dev, int no_disable)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Allow only command completion events during disable */
- hfa384x_events_only_cmd(dev);
-
- local->hw_ready = 0;
- if (local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_DISABLE);
- local->dev_enabled = 0;
-
- if (local->func->card_present && !local->func->card_present(local)) {
- printk(KERN_DEBUG "%s: card already removed or not configured "
- "during shutdown\n", dev->name);
- return;
- }
-
- if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 &&
- hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL))
- printk(KERN_WARNING "%s: Shutdown failed\n", dev_info);
-
- hfa384x_disable_interrupts(dev);
-
- if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL)
- hfa384x_events_only_cmd(dev);
- else
- prism2_clear_cmd_queue(local);
-}
-
-
-static void prism2_hw_reset(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
-#if 0
- static long last_reset = 0;
-
- /* do not reset card more than once per second to avoid ending up in a
- * busy loop resetting the card */
- if (time_before_eq(jiffies, last_reset + HZ))
- return;
- last_reset = jiffies;
-#endif
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->hw_downloading)
- return;
-
- if (local->hw_resetting) {
- printk(KERN_WARNING "%s: %s: already resetting card - "
- "ignoring reset request\n", dev_info, dev->name);
- return;
- }
-
- local->hw_reset_tries++;
- if (local->hw_reset_tries > 10) {
- printk(KERN_WARNING "%s: too many reset tries, skipping\n",
- dev->name);
- return;
- }
-
- printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name);
- hfa384x_disable_interrupts(dev);
- local->hw_resetting = 1;
- if (local->func->cor_sreset) {
- /* Host system seems to hang in some cases with high traffic
- * load or shared interrupts during COR sreset. Disable shared
- * interrupts during reset to avoid these crashes. COS sreset
- * takes quite a long time, so it is unfortunate that this
- * seems to be needed. Anyway, I do not know of any better way
- * of avoiding the crash. */
- disable_irq(dev->irq);
- local->func->cor_sreset(local);
- enable_irq(dev->irq);
- }
- prism2_hw_shutdown(dev, 1);
- prism2_hw_config(dev, 0);
- local->hw_resetting = 0;
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- if (local->dl_pri) {
- printk(KERN_DEBUG "%s: persistent download of primary "
- "firmware\n", dev->name);
- if (prism2_download_genesis(local, local->dl_pri) < 0)
- printk(KERN_WARNING "%s: download (PRI) failed\n",
- dev->name);
- }
-
- if (local->dl_sec) {
- printk(KERN_DEBUG "%s: persistent download of secondary "
- "firmware\n", dev->name);
- if (prism2_download_volatile(local, local->dl_sec) < 0)
- printk(KERN_WARNING "%s: download (SEC) failed\n",
- dev->name);
- }
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- /* TODO: restore beacon TIM bits for STAs that have buffered frames */
-}
-
-
-static void prism2_schedule_reset(local_info_t *local)
-{
- schedule_work(&local->reset_queue);
-}
-
-
-/* Called only as scheduled task after noticing card timeout in interrupt
- * context */
-static void handle_reset_queue(struct work_struct *work)
-{
- local_info_t *local = container_of(work, local_info_t, reset_queue);
-
- printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name);
- prism2_hw_reset(local->dev);
-
- if (netif_queue_stopped(local->dev)) {
- int i;
-
- for (i = 0; i < PRISM2_TXFID_COUNT; i++)
- if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) {
- PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: "
- "wake up queue\n");
- netif_wake_queue(local->dev);
- break;
- }
- }
-}
-
-
-static int prism2_get_txfid_idx(local_info_t *local)
-{
- int idx, end;
- unsigned long flags;
-
- spin_lock_irqsave(&local->txfidlock, flags);
- end = idx = local->next_txfid;
- do {
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
- local->intransmitfid[idx] = PRISM2_TXFID_RESERVED;
- spin_unlock_irqrestore(&local->txfidlock, flags);
- return idx;
- }
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != end);
- spin_unlock_irqrestore(&local->txfidlock, flags);
-
- PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: "
- "packet dropped\n");
- local->dev->stats.tx_dropped++;
-
- return -1;
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_transmit_cb(struct net_device *dev, long context,
- u16 resp0, u16 res)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int idx = (int) context;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (res) {
- printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n",
- dev->name, res);
- return;
- }
-
- if (idx < 0 || idx >= PRISM2_TXFID_COUNT) {
- printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid "
- "idx=%d\n", dev->name, idx);
- return;
- }
-
- if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called "
- "with no pending transmit\n", dev->name);
- }
-
- if (netif_queue_stopped(dev)) {
- /* ready for next TX, so wake up queue that was stopped in
- * prism2_transmit() */
- netif_wake_queue(dev);
- }
-
- spin_lock(&local->txfidlock);
-
- /* With reclaim, Resp0 contains new txfid for transmit; the old txfid
- * will be automatically allocated for the next TX frame */
- local->intransmitfid[idx] = resp0;
-
- PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, "
- "resp0=0x%04x, transmit_txfid=0x%04x\n",
- dev->name, idx, local->txfid[idx],
- resp0, local->intransmitfid[local->next_txfid]);
-
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- local->next_txfid = idx;
-
- /* check if all TX buffers are occupied */
- do {
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) {
- spin_unlock(&local->txfidlock);
- return;
- }
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != local->next_txfid);
- spin_unlock(&local->txfidlock);
-
- /* no empty TX buffers, stop queue */
- netif_stop_queue(dev);
-}
-
-
-/* Called only from software IRQ if PCI bus master is not used (with bus master
- * this can be called both from software and hardware IRQ) */
-static int prism2_transmit(struct net_device *dev, int idx)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* The driver tries to stop netif queue so that there would not be
- * more than one attempt to transmit frames going on; check that this
- * is really the case */
-
- if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called "
- "when previous TX was pending\n", dev->name);
- return -1;
- }
-
- /* stop the queue for the time that transmit is pending */
- netif_stop_queue(dev);
-
- /* transmit packet */
- res = hfa384x_cmd_callback(
- dev,
- HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM,
- local->txfid[idx],
- prism2_transmit_cb, (long) idx);
-
- if (res) {
- printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT "
- "failed (res=%d)\n", dev->name, res);
- dev->stats.tx_dropped++;
- netif_wake_queue(dev);
- return -1;
- }
- netif_trans_update(dev);
-
- /* Since we did not wait for command completion, the card continues
- * to process on the background and we will finish handling when
- * command completion event is handled (prism2_cmd_ev() function) */
-
- return 0;
-}
-
-
-/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and
- * send the payload with this descriptor) */
-/* Called only from software IRQ */
-static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_tx_frame txdesc;
- struct hostap_skb_tx_data *meta;
- int hdr_len, data_len, idx, res, ret = -1;
- u16 tx_control;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
-
- prism2_callback(local, PRISM2_CALLBACK_TX_START);
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- !local->hw_ready || local->hw_downloading || local->pri_only) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -"
- " skipping\n", dev->name);
- }
- goto fail;
- }
-
- memset(&txdesc, 0, sizeof(txdesc));
-
- /* skb->data starts with txdesc->frame_control */
- hdr_len = sizeof(txdesc.header);
- BUILD_BUG_ON(hdr_len != 24);
- skb_copy_from_linear_data(skb, &txdesc.header, hdr_len);
- if (ieee80211_is_data(txdesc.frame_control) &&
- ieee80211_has_a4(txdesc.frame_control) &&
- skb->len >= 30) {
- /* Addr4 */
- skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4,
- ETH_ALEN);
- hdr_len += ETH_ALEN;
- }
-
- tx_control = local->tx_control;
- if (meta->tx_cb_idx) {
- tx_control |= HFA384X_TX_CTRL_TX_OK;
- txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx);
- }
- txdesc.tx_control = cpu_to_le16(tx_control);
- txdesc.tx_rate = meta->rate;
-
- data_len = skb->len - hdr_len;
- txdesc.data_len = cpu_to_le16(data_len);
- txdesc.len = cpu_to_be16(data_len);
-
- idx = prism2_get_txfid_idx(local);
- if (idx < 0)
- goto fail;
-
- if (local->frame_dump & PRISM2_DUMP_TX_HDR)
- hostap_dump_tx_header(dev->name, &txdesc);
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0);
-
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc));
- if (!res)
- res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len,
- skb->len - hdr_len);
- spin_unlock(&local->baplock);
-
- if (!res)
- res = prism2_transmit(dev, idx);
- if (res) {
- printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n",
- dev->name);
- local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
- schedule_work(&local->reset_queue);
- goto fail;
- }
-
- ret = 0;
-
-fail:
- prism2_callback(local, PRISM2_CALLBACK_TX_END);
- return ret;
-}
-
-
-/* Some SMP systems have reported number of odd errors with hostap_pci. fid
- * register has changed values between consecutive reads for an unknown reason.
- * This should really not happen, so more debugging is needed. This test
- * version is a bit slower, but it will detect most of such register changes
- * and will try to get the correct fid eventually. */
-#define EXTRA_FID_READ_TESTS
-
-static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg)
-{
-#ifdef EXTRA_FID_READ_TESTS
- u16 val, val2, val3;
- int i;
-
- for (i = 0; i < 10; i++) {
- val = HFA384X_INW(reg);
- val2 = HFA384X_INW(reg);
- val3 = HFA384X_INW(reg);
-
- if (val == val2 && val == val3)
- return val;
-
- printk(KERN_DEBUG "%s: detected fid change (try=%d, reg=%04x):"
- " %04x %04x %04x\n",
- dev->name, i, reg, val, val2, val3);
- if ((val == val2 || val == val3) && val != 0)
- return val;
- if (val2 == val3 && val2 != 0)
- return val2;
- }
- printk(KERN_WARNING "%s: Uhhuh.. could not read good fid from reg "
- "%04x (%04x %04x %04x)\n", dev->name, reg, val, val2, val3);
- return val;
-#else /* EXTRA_FID_READ_TESTS */
- return HFA384X_INW(reg);
-#endif /* EXTRA_FID_READ_TESTS */
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_rx(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- int res, rx_pending = 0;
- u16 len, hdr_len, rxfid, status, macport;
- struct hfa384x_rx_frame rxdesc;
- struct sk_buff *skb = NULL;
-
- prism2_callback(local, PRISM2_CALLBACK_RX_START);
-
- rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF);
-#ifndef final_version
- if (rxfid == 0) {
- rxfid = HFA384X_INW(HFA384X_RXFID_OFF);
- printk(KERN_DEBUG "prism2_rx: rxfid=0 (next 0x%04x)\n",
- rxfid);
- if (rxfid == 0) {
- schedule_work(&local->reset_queue);
- goto rx_dropped;
- }
- /* try to continue with the new rxfid value */
- }
-#endif
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, rxfid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, &rxdesc, sizeof(rxdesc));
-
- if (res) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: copy from BAP0 failed %d\n", dev->name,
- res);
- if (res == -ETIMEDOUT) {
- schedule_work(&local->reset_queue);
- }
- goto rx_dropped;
- }
-
- len = le16_to_cpu(rxdesc.data_len);
- hdr_len = sizeof(rxdesc);
- status = le16_to_cpu(rxdesc.status);
- macport = (status >> 8) & 0x07;
-
- /* Drop frames with too large reported payload length. Monitor mode
- * seems to sometimes pass frames (e.g., ctrl::ack) with signed and
- * negative value, so allow also values 65522 .. 65534 (-14 .. -2) for
- * macport 7 */
- if (len > PRISM2_DATA_MAXLEN + 8 /* WEP */) {
- if (macport == 7 && local->iw_mode == IW_MODE_MONITOR) {
- if (len >= (u16) -14) {
- hdr_len -= 65535 - len;
- hdr_len--;
- }
- len = 0;
- } else {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: Received frame with invalid "
- "length 0x%04x\n", dev->name, len);
- hostap_dump_rx_header(dev->name, &rxdesc);
- goto rx_dropped;
- }
- }
-
- skb = dev_alloc_skb(len + hdr_len);
- if (!skb) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: RX failed to allocate skb\n",
- dev->name);
- goto rx_dropped;
- }
- skb->dev = dev;
- skb_put_data(skb, &rxdesc, hdr_len);
-
- if (len > 0)
- res = hfa384x_from_bap(dev, BAP0, skb_put(skb, len), len);
- spin_unlock(&local->baplock);
- if (res) {
- printk(KERN_DEBUG "%s: RX failed to read "
- "frame data\n", dev->name);
- goto rx_dropped;
- }
-
- skb_queue_tail(&local->rx_list, skb);
- tasklet_schedule(&local->rx_tasklet);
-
- rx_exit:
- prism2_callback(local, PRISM2_CALLBACK_RX_END);
- if (!rx_pending) {
- HFA384X_OUTW(HFA384X_EV_RX, HFA384X_EVACK_OFF);
- }
-
- return;
-
- rx_dropped:
- dev->stats.rx_dropped++;
- if (skb)
- dev_kfree_skb(skb);
- goto rx_exit;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb)
-{
- struct hfa384x_rx_frame *rxdesc;
- struct net_device *dev = skb->dev;
- struct hostap_80211_rx_status stats;
- int hdrlen, rx_hdrlen;
-
- rx_hdrlen = sizeof(*rxdesc);
- if (skb->len < sizeof(*rxdesc)) {
- /* Allow monitor mode to receive shorter frames */
- if (local->iw_mode == IW_MODE_MONITOR &&
- skb->len >= sizeof(*rxdesc) - 30) {
- rx_hdrlen = skb->len;
- } else {
- dev_kfree_skb(skb);
- return;
- }
- }
-
- rxdesc = (struct hfa384x_rx_frame *) skb->data;
-
- if (local->frame_dump & PRISM2_DUMP_RX_HDR &&
- skb->len >= sizeof(*rxdesc))
- hostap_dump_rx_header(dev->name, rxdesc);
-
- if (le16_to_cpu(rxdesc->status) & HFA384X_RX_STATUS_FCSERR &&
- (!local->monitor_allow_fcserr ||
- local->iw_mode != IW_MODE_MONITOR))
- goto drop;
-
- if (skb->len > PRISM2_DATA_MAXLEN) {
- printk(KERN_DEBUG "%s: RX: len(%d) > MAX(%d)\n",
- dev->name, skb->len, PRISM2_DATA_MAXLEN);
- goto drop;
- }
-
- stats.mac_time = le32_to_cpu(rxdesc->time);
- stats.signal = rxdesc->signal - local->rssi_to_dBm;
- stats.noise = rxdesc->silence - local->rssi_to_dBm;
- stats.rate = rxdesc->rate;
-
- /* Convert Prism2 RX structure into IEEE 802.11 header */
- hdrlen = hostap_80211_get_hdrlen(rxdesc->frame_control);
- if (hdrlen > rx_hdrlen)
- hdrlen = rx_hdrlen;
-
- memmove(skb_pull(skb, rx_hdrlen - hdrlen),
- &rxdesc->frame_control, hdrlen);
-
- hostap_80211_rx(dev, skb, &stats);
- return;
-
- drop:
- dev_kfree_skb(skb);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_rx_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, rx_tasklet);
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&local->rx_list)) != NULL)
- hostap_rx_skb(local, skb);
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_alloc_ev(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int idx;
- u16 fid;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- fid = prism2_read_fid_reg(dev, HFA384X_ALLOCFID_OFF);
-
- PDEBUG(DEBUG_FID, "FID: interrupt: ALLOC - fid=0x%04x\n", fid);
-
- spin_lock(&local->txfidlock);
- idx = local->next_alloc;
-
- do {
- if (local->txfid[idx] == fid) {
- PDEBUG(DEBUG_FID, "FID: found matching txfid[%d]\n",
- idx);
-
-#ifndef final_version
- if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY)
- printk("Already released txfid found at idx "
- "%d\n", idx);
- if (local->intransmitfid[idx] == PRISM2_TXFID_RESERVED)
- printk("Already reserved txfid found at idx "
- "%d\n", idx);
-#endif
- local->intransmitfid[idx] = PRISM2_TXFID_EMPTY;
- idx++;
- local->next_alloc = idx >= PRISM2_TXFID_COUNT ? 0 :
- idx;
-
- if (!test_bit(HOSTAP_BITS_TRANSMIT, &local->bits) &&
- netif_queue_stopped(dev))
- netif_wake_queue(dev);
-
- spin_unlock(&local->txfidlock);
- return;
- }
-
- idx++;
- if (idx >= PRISM2_TXFID_COUNT)
- idx = 0;
- } while (idx != local->next_alloc);
-
- printk(KERN_WARNING "%s: could not find matching txfid (0x%04x, new "
- "read 0x%04x) for alloc event\n", dev->name, fid,
- HFA384X_INW(HFA384X_ALLOCFID_OFF));
- printk(KERN_DEBUG "TXFIDs:");
- for (idx = 0; idx < PRISM2_TXFID_COUNT; idx++)
- printk(" %04x[%04x]", local->txfid[idx],
- local->intransmitfid[idx]);
- printk("\n");
- spin_unlock(&local->txfidlock);
-
- /* FIX: should probably schedule reset; reference to one txfid was lost
- * completely.. Bad things will happen if we run out of txfids
- * Actually, this will cause netdev watchdog to notice TX timeout and
- * then card reset after all txfids have been leaked. */
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_tx_callback(local_info_t *local,
- struct hfa384x_tx_frame *txdesc, int ok,
- char *payload)
-{
- u16 sw_support, hdrlen, len;
- struct sk_buff *skb;
- struct hostap_tx_callback_info *cb;
-
- /* Make sure that frame was from us. */
- if (!ether_addr_equal(txdesc->addr2, local->dev->dev_addr)) {
- printk(KERN_DEBUG "%s: TX callback - foreign frame\n",
- local->dev->name);
- return;
- }
-
- sw_support = le32_to_cpu(txdesc->sw_support);
-
- spin_lock(&local->lock);
- cb = local->tx_callback;
- while (cb != NULL && cb->idx != sw_support)
- cb = cb->next;
- spin_unlock(&local->lock);
-
- if (cb == NULL) {
- printk(KERN_DEBUG "%s: could not find TX callback (idx %d)\n",
- local->dev->name, sw_support);
- return;
- }
-
- hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control);
- len = le16_to_cpu(txdesc->data_len);
- skb = dev_alloc_skb(hdrlen + len);
- if (skb == NULL) {
- printk(KERN_DEBUG "%s: hostap_tx_callback failed to allocate "
- "skb\n", local->dev->name);
- return;
- }
-
- skb_put_data(skb, (void *)&txdesc->frame_control, hdrlen);
- if (payload)
- skb_put_data(skb, payload, len);
-
- skb->dev = local->dev;
- skb_reset_mac_header(skb);
-
- cb->func(skb, ok, cb->data);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static int hostap_tx_compl_read(local_info_t *local, int error,
- struct hfa384x_tx_frame *txdesc,
- char **payload)
-{
- u16 fid, len;
- int res, ret = 0;
- struct net_device *dev = local->dev;
-
- fid = prism2_read_fid_reg(dev, HFA384X_TXCOMPLFID_OFF);
-
- PDEBUG(DEBUG_FID, "interrupt: TX (err=%d) - fid=0x%04x\n", fid, error);
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, fid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, txdesc, sizeof(*txdesc));
- if (res) {
- PDEBUG(DEBUG_EXTRA, "%s: TX (err=%d) - fid=0x%04x - could not "
- "read txdesc\n", dev->name, error, fid);
- if (res == -ETIMEDOUT) {
- schedule_work(&local->reset_queue);
- }
- ret = -1;
- goto fail;
- }
- if (txdesc->sw_support) {
- len = le16_to_cpu(txdesc->data_len);
- if (len < PRISM2_DATA_MAXLEN) {
- *payload = kmalloc(len, GFP_ATOMIC);
- if (*payload == NULL ||
- hfa384x_from_bap(dev, BAP0, *payload, len)) {
- PDEBUG(DEBUG_EXTRA, "%s: could not read TX "
- "frame payload\n", dev->name);
- kfree(*payload);
- *payload = NULL;
- ret = -1;
- goto fail;
- }
- }
- }
-
- fail:
- spin_unlock(&local->baplock);
-
- return ret;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_tx_ev(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- char *payload = NULL;
- struct hfa384x_tx_frame txdesc;
-
- if (hostap_tx_compl_read(local, 0, &txdesc, &payload))
- goto fail;
-
- if (local->frame_dump & PRISM2_DUMP_TX_HDR) {
- PDEBUG(DEBUG_EXTRA, "%s: TX - status=0x%04x "
- "retry_count=%d tx_rate=%d seq_ctrl=%d "
- "duration_id=%d\n",
- dev->name, le16_to_cpu(txdesc.status),
- txdesc.retry_count, txdesc.tx_rate,
- le16_to_cpu(txdesc.seq_ctrl),
- le16_to_cpu(txdesc.duration_id));
- }
-
- if (txdesc.sw_support)
- hostap_tx_callback(local, &txdesc, 1, payload);
- kfree(payload);
-
- fail:
- HFA384X_OUTW(HFA384X_EV_TX, HFA384X_EVACK_OFF);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_sta_tx_exc_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, sta_tx_exc_tasklet);
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&local->sta_tx_exc_list)) != NULL) {
- struct hfa384x_tx_frame *txdesc =
- (struct hfa384x_tx_frame *) skb->data;
-
- if (skb->len >= sizeof(*txdesc)) {
- /* Convert Prism2 RX structure into IEEE 802.11 header
- */
- int hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control);
- memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen),
- &txdesc->frame_control, hdrlen);
-
- hostap_handle_sta_tx_exc(local, skb);
- }
- dev_kfree_skb(skb);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_txexc(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- u16 status, fc;
- int show_dump, res;
- char *payload = NULL;
- struct hfa384x_tx_frame txdesc;
-
- show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
- dev->stats.tx_errors++;
-
- res = hostap_tx_compl_read(local, 1, &txdesc, &payload);
- HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF);
- if (res)
- return;
-
- status = le16_to_cpu(txdesc.status);
-
- /* We produce a TXDROP event only for retry or lifetime
- * exceeded, because that's the only status that really mean
- * that this particular node went away.
- * Other errors means that *we* screwed up. - Jean II */
- if (status & (HFA384X_TX_STATUS_RETRYERR | HFA384X_TX_STATUS_AGEDERR))
- {
- union iwreq_data wrqu;
-
- /* Copy 802.11 dest address. */
- memcpy(wrqu.addr.sa_data, txdesc.addr1, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
- } else
- show_dump = 1;
-
- if (local->iw_mode == IW_MODE_MASTER ||
- local->iw_mode == IW_MODE_REPEAT ||
- local->wds_type & HOSTAP_WDS_AP_CLIENT) {
- struct sk_buff *skb;
- skb = dev_alloc_skb(sizeof(txdesc));
- if (skb) {
- skb_put_data(skb, &txdesc, sizeof(txdesc));
- skb_queue_tail(&local->sta_tx_exc_list, skb);
- tasklet_schedule(&local->sta_tx_exc_tasklet);
- }
- }
-
- if (txdesc.sw_support)
- hostap_tx_callback(local, &txdesc, 0, payload);
- kfree(payload);
-
- if (!show_dump)
- return;
-
- PDEBUG(DEBUG_EXTRA, "%s: TXEXC - status=0x%04x (%s%s%s%s)"
- " tx_control=%04x\n",
- dev->name, status,
- status & HFA384X_TX_STATUS_RETRYERR ? "[RetryErr]" : "",
- status & HFA384X_TX_STATUS_AGEDERR ? "[AgedErr]" : "",
- status & HFA384X_TX_STATUS_DISCON ? "[Discon]" : "",
- status & HFA384X_TX_STATUS_FORMERR ? "[FormErr]" : "",
- le16_to_cpu(txdesc.tx_control));
-
- fc = le16_to_cpu(txdesc.frame_control);
- PDEBUG(DEBUG_EXTRA, " retry_count=%d tx_rate=%d fc=0x%04x "
- "(%s%s%s::%d%s%s)\n",
- txdesc.retry_count, txdesc.tx_rate, fc,
- ieee80211_is_mgmt(txdesc.frame_control) ? "Mgmt" : "",
- ieee80211_is_ctl(txdesc.frame_control) ? "Ctrl" : "",
- ieee80211_is_data(txdesc.frame_control) ? "Data" : "",
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- ieee80211_has_tods(txdesc.frame_control) ? " ToDS" : "",
- ieee80211_has_fromds(txdesc.frame_control) ? " FromDS" : "");
- PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n",
- txdesc.addr1, txdesc.addr2,
- txdesc.addr3, txdesc.addr4);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_info_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, info_tasklet);
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&local->info_list)) != NULL) {
- hostap_info_process(local, skb);
- dev_kfree_skb(skb);
- }
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- u16 fid;
- int res, left;
- struct hfa384x_info_frame info;
- struct sk_buff *skb;
-
- fid = HFA384X_INW(HFA384X_INFOFID_OFF);
-
- spin_lock(&local->baplock);
- res = hfa384x_setup_bap(dev, BAP0, fid, 0);
- if (!res)
- res = hfa384x_from_bap(dev, BAP0, &info, sizeof(info));
- if (res) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "Could not get info frame (fid=0x%04x)\n",
- fid);
- if (res == -ETIMEDOUT) {
- schedule_work(&local->reset_queue);
- }
- goto out;
- }
-
- left = (le16_to_cpu(info.len) - 1) * 2;
-
- if (info.len & cpu_to_le16(0x8000) || info.len == 0 || left > 2060) {
- /* data register seems to give 0x8000 in some error cases even
- * though busy bit is not set in offset register;
- * in addition, length must be at least 1 due to type field */
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: Received info frame with invalid "
- "length 0x%04x (type 0x%04x)\n", dev->name,
- le16_to_cpu(info.len), le16_to_cpu(info.type));
- goto out;
- }
-
- skb = dev_alloc_skb(sizeof(info) + left);
- if (skb == NULL) {
- spin_unlock(&local->baplock);
- printk(KERN_DEBUG "%s: Could not allocate skb for info "
- "frame\n", dev->name);
- goto out;
- }
-
- skb_put_data(skb, &info, sizeof(info));
- if (left > 0 && hfa384x_from_bap(dev, BAP0, skb_put(skb, left), left))
- {
- spin_unlock(&local->baplock);
- printk(KERN_WARNING "%s: Info frame read failed (fid=0x%04x, "
- "len=0x%04x, type=0x%04x\n", dev->name, fid,
- le16_to_cpu(info.len), le16_to_cpu(info.type));
- dev_kfree_skb(skb);
- goto out;
- }
- spin_unlock(&local->baplock);
-
- skb_queue_tail(&local->info_list, skb);
- tasklet_schedule(&local->info_tasklet);
-
- out:
- HFA384X_OUTW(HFA384X_EV_INFO, HFA384X_EVACK_OFF);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void hostap_bap_tasklet(struct tasklet_struct *t)
-{
- local_info_t *local = from_tasklet(local, t, bap_tasklet);
- struct net_device *dev = local->dev;
- u16 ev;
- int frames = 30;
-
- if (local->func->card_present && !local->func->card_present(local))
- return;
-
- set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
-
- /* Process all pending BAP events without generating new interrupts
- * for them */
- while (frames-- > 0) {
- ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
- if (ev == 0xffff || !(ev & HFA384X_BAP0_EVENTS))
- break;
- if (ev & HFA384X_EV_RX)
- prism2_rx(local);
- if (ev & HFA384X_EV_INFO)
- prism2_info(local);
- if (ev & HFA384X_EV_TX)
- prism2_tx_ev(local);
- if (ev & HFA384X_EV_TXEXC)
- prism2_txexc(local);
- }
-
- set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
- clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits);
-
- /* Enable interrupts for new BAP events */
- hfa384x_events_all(dev);
- clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits);
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_infdrop(struct net_device *dev)
-{
- static unsigned long last_inquire = 0;
-
- PDEBUG(DEBUG_EXTRA, "%s: INFDROP event\n", dev->name);
-
- /* some firmware versions seem to get stuck with
- * full CommTallies in high traffic load cases; every
- * packet will then cause INFDROP event and CommTallies
- * info frame will not be sent automatically. Try to
- * get out of this state by inquiring CommTallies. */
- if (!last_inquire || time_after(jiffies, last_inquire + HZ)) {
- hfa384x_cmd_callback(dev, HFA384X_CMDCODE_INQUIRE,
- HFA384X_INFO_COMMTALLIES, NULL, 0);
- last_inquire = jiffies;
- }
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_ev_tick(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u16 evstat, inten;
- static int prev_stuck = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (time_after(jiffies, local->last_tick_timer + 5 * HZ) &&
- local->last_tick_timer) {
- evstat = HFA384X_INW(HFA384X_EVSTAT_OFF);
- inten = HFA384X_INW(HFA384X_INTEN_OFF);
- if (!prev_stuck) {
- printk(KERN_INFO "%s: SW TICK stuck? "
- "bits=0x%lx EvStat=%04x IntEn=%04x\n",
- dev->name, local->bits, evstat, inten);
- }
- local->sw_tick_stuck++;
- if ((evstat & HFA384X_BAP0_EVENTS) &&
- (inten & HFA384X_BAP0_EVENTS)) {
- printk(KERN_INFO "%s: trying to recover from IRQ "
- "hang\n", dev->name);
- hfa384x_events_no_bap0(dev);
- }
- prev_stuck = 1;
- } else
- prev_stuck = 0;
-}
-
-
-/* Called only from hardware IRQ */
-static void prism2_check_magic(local_info_t *local)
-{
- /* at least PCI Prism2.5 with bus mastering seems to sometimes
- * return 0x0000 in SWSUPPORT0 for unknown reason, but re-reading the
- * register once or twice seems to get the correct value.. PCI cards
- * cannot anyway be removed during normal operation, so there is not
- * really any need for this verification with them. */
-
-#ifndef PRISM2_PCI
-#ifndef final_version
- static unsigned long last_magic_err = 0;
- struct net_device *dev = local->dev;
-
- if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) {
- if (!local->hw_ready)
- return;
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- if (time_after(jiffies, last_magic_err + 10 * HZ)) {
- printk("%s: Interrupt, but SWSUPPORT0 does not match: "
- "%04X != %04X - card removed?\n", dev->name,
- HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
- HFA384X_MAGIC);
- last_magic_err = jiffies;
- } else if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x "
- "MAGIC=%04x\n", dev->name,
- HFA384X_INW(HFA384X_SWSUPPORT0_OFF),
- HFA384X_MAGIC);
- }
- if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != 0xffff)
- schedule_work(&local->reset_queue);
- return;
- }
-#endif /* final_version */
-#endif /* !PRISM2_PCI */
-}
-
-
-/* Called only from hardware IRQ */
-static irqreturn_t prism2_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct hostap_interface *iface;
- local_info_t *local;
- int events = 0;
- u16 ev;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Detect early interrupt before driver is fully configured */
- spin_lock(&local->irq_init_lock);
- if (!dev->base_addr) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
- dev->name);
- }
- spin_unlock(&local->irq_init_lock);
- return IRQ_HANDLED;
- }
- spin_unlock(&local->irq_init_lock);
-
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
-
- if (local->func->card_present && !local->func->card_present(local)) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: Interrupt, but dev not OK\n",
- dev->name);
- }
- return IRQ_HANDLED;
- }
-
- prism2_check_magic(local);
-
- for (;;) {
- ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
- if (ev == 0xffff) {
- if (local->shutdown)
- return IRQ_HANDLED;
- HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF);
- printk(KERN_DEBUG "%s: prism2_interrupt: ev=0xffff\n",
- dev->name);
- return IRQ_HANDLED;
- }
-
- ev &= HFA384X_INW(HFA384X_INTEN_OFF);
- if (ev == 0)
- break;
-
- if (ev & HFA384X_EV_CMD) {
- prism2_cmd_ev(dev);
- }
-
- /* Above events are needed even before hw is ready, but other
- * events should be skipped during initialization. This may
- * change for AllocEv if allocate_fid is implemented without
- * busy waiting. */
- if (!local->hw_ready || local->hw_resetting ||
- !local->dev_enabled) {
- ev = HFA384X_INW(HFA384X_EVSTAT_OFF);
- if (ev & HFA384X_EV_CMD)
- goto next_event;
- if ((ev & HFA384X_EVENT_MASK) == 0)
- return IRQ_HANDLED;
- if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) &&
- net_ratelimit()) {
- printk(KERN_DEBUG "%s: prism2_interrupt: hw "
- "not ready; skipping events 0x%04x "
- "(IntEn=0x%04x)%s%s%s\n",
- dev->name, ev,
- HFA384X_INW(HFA384X_INTEN_OFF),
- !local->hw_ready ? " (!hw_ready)" : "",
- local->hw_resetting ?
- " (hw_resetting)" : "",
- !local->dev_enabled ?
- " (!dev_enabled)" : "");
- }
- HFA384X_OUTW(ev, HFA384X_EVACK_OFF);
- return IRQ_HANDLED;
- }
-
- if (ev & HFA384X_EV_TICK) {
- prism2_ev_tick(dev);
- HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF);
- }
-
- if (ev & HFA384X_EV_ALLOC) {
- prism2_alloc_ev(dev);
- HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF);
- }
-
- /* Reading data from the card is quite time consuming, so do it
- * in tasklets. TX, TXEXC, RX, and INFO events will be ACKed
- * and unmasked after needed data has been read completely. */
- if (ev & HFA384X_BAP0_EVENTS) {
- hfa384x_events_no_bap0(dev);
- tasklet_schedule(&local->bap_tasklet);
- }
-
-#ifndef final_version
- if (ev & HFA384X_EV_WTERR) {
- PDEBUG(DEBUG_EXTRA, "%s: WTERR event\n", dev->name);
- HFA384X_OUTW(HFA384X_EV_WTERR, HFA384X_EVACK_OFF);
- }
-#endif /* final_version */
-
- if (ev & HFA384X_EV_INFDROP) {
- prism2_infdrop(dev);
- HFA384X_OUTW(HFA384X_EV_INFDROP, HFA384X_EVACK_OFF);
- }
-
- next_event:
- events++;
- if (events >= PRISM2_MAX_INTERRUPT_EVENTS) {
- PDEBUG(DEBUG_EXTRA, "prism2_interrupt: >%d events "
- "(EvStat=0x%04x)\n",
- PRISM2_MAX_INTERRUPT_EVENTS,
- HFA384X_INW(HFA384X_EVSTAT_OFF));
- break;
- }
- }
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 1);
- return IRQ_RETVAL(events);
-}
-
-
-static void prism2_check_sta_fw_version(local_info_t *local)
-{
- struct hfa384x_comp_ident comp;
- int id, variant, major, minor;
-
- if (hfa384x_get_rid(local->dev, HFA384X_RID_STAID,
- &comp, sizeof(comp), 1) < 0)
- return;
-
- local->fw_ap = 0;
- id = le16_to_cpu(comp.id);
- if (id != HFA384X_COMP_ID_STA) {
- if (id == HFA384X_COMP_ID_FW_AP)
- local->fw_ap = 1;
- return;
- }
-
- major = __le16_to_cpu(comp.major);
- minor = __le16_to_cpu(comp.minor);
- variant = __le16_to_cpu(comp.variant);
- local->sta_fw_ver = PRISM2_FW_VER(major, minor, variant);
-
- /* Station firmware versions before 1.4.x seem to have a bug in
- * firmware-based WEP encryption when using Host AP mode, so use
- * host_encrypt as a default for them. Firmware version 1.4.9 is the
- * first one that has been seen to produce correct encryption, but the
- * bug might be fixed before that (although, at least 1.4.2 is broken).
- */
- local->fw_encrypt_ok = local->sta_fw_ver >= PRISM2_FW_VER(1,4,9);
-
- if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
- !local->fw_encrypt_ok) {
- printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
- "a workaround for firmware bug in Host AP mode WEP\n",
- local->dev->name);
- local->host_encrypt = 1;
- }
-
- /* IEEE 802.11 standard compliant WDS frames (4 addresses) were broken
- * in station firmware versions before 1.5.x. With these versions, the
- * driver uses a workaround with bogus frame format (4th address after
- * the payload). This is not compatible with other AP devices. Since
- * the firmware bug is fixed in the latest station firmware versions,
- * automatically enable standard compliant mode for cards using station
- * firmware version 1.5.0 or newer. */
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,5,0))
- local->wds_type |= HOSTAP_WDS_STANDARD_FRAME;
- else {
- printk(KERN_DEBUG "%s: defaulting to bogus WDS frame as a "
- "workaround for firmware bug in Host AP mode WDS\n",
- local->dev->name);
- }
-
- hostap_check_sta_fw_version(local->ap, local->sta_fw_ver);
-}
-
-
-static void hostap_passive_scan(struct timer_list *t)
-{
- local_info_t *local = from_timer(local, t, passive_scan_timer);
- struct net_device *dev = local->dev;
- u16 chan;
-
- if (local->passive_scan_interval <= 0)
- return;
-
- if (local->passive_scan_state == PASSIVE_SCAN_LISTEN) {
- int max_tries = 16;
-
- /* Even though host system does not really know when the WLAN
- * MAC is sending frames, try to avoid changing channels for
- * passive scanning when a host-generated frame is being
- * transmitted */
- if (test_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) {
- printk(KERN_DEBUG "%s: passive scan detected pending "
- "TX - delaying\n", dev->name);
- local->passive_scan_timer.expires = jiffies + HZ / 10;
- add_timer(&local->passive_scan_timer);
- return;
- }
-
- do {
- local->passive_scan_channel++;
- if (local->passive_scan_channel > 14)
- local->passive_scan_channel = 1;
- max_tries--;
- } while (!(local->channel_mask &
- (1 << (local->passive_scan_channel - 1))) &&
- max_tries > 0);
-
- if (max_tries == 0) {
- printk(KERN_INFO "%s: no allowed passive scan channels"
- " found\n", dev->name);
- return;
- }
-
- printk(KERN_DEBUG "%s: passive scan channel %d\n",
- dev->name, local->passive_scan_channel);
- chan = local->passive_scan_channel;
- local->passive_scan_state = PASSIVE_SCAN_WAIT;
- local->passive_scan_timer.expires = jiffies + HZ / 10;
- } else {
- chan = local->channel;
- local->passive_scan_state = PASSIVE_SCAN_LISTEN;
- local->passive_scan_timer.expires = jiffies +
- local->passive_scan_interval * HZ;
- }
-
- if (hfa384x_cmd_callback(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CHANGE_CHANNEL << 8),
- chan, NULL, 0))
- printk(KERN_ERR "%s: passive scan channel set %d "
- "failed\n", dev->name, chan);
-
- add_timer(&local->passive_scan_timer);
-}
-
-
-/* Called only as a scheduled task when communications quality values should
- * be updated. */
-static void handle_comms_qual_update(struct work_struct *work)
-{
- local_info_t *local =
- container_of(work, local_info_t, comms_qual_update);
- prism2_update_comms_qual(local->dev);
-}
-
-
-/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is
- * used to monitor that local->last_tick_timer is being updated. If not,
- * interrupt busy-loop is assumed and driver tries to recover by masking out
- * some events. */
-static void hostap_tick_timer(struct timer_list *t)
-{
- static unsigned long last_inquire = 0;
- local_info_t *local = from_timer(local, t, tick_timer);
- local->last_tick_timer = jiffies;
-
- /* Inquire CommTallies every 10 seconds to keep the statistics updated
- * more often during low load and when using 32-bit tallies. */
- if ((!last_inquire || time_after(jiffies, last_inquire + 10 * HZ)) &&
- !local->hw_downloading && local->hw_ready &&
- !local->hw_resetting && local->dev_enabled) {
- hfa384x_cmd_callback(local->dev, HFA384X_CMDCODE_INQUIRE,
- HFA384X_INFO_COMMTALLIES, NULL, 0);
- last_inquire = jiffies;
- }
-
- if ((local->last_comms_qual_update == 0 ||
- time_after(jiffies, local->last_comms_qual_update + 10 * HZ)) &&
- (local->iw_mode == IW_MODE_INFRA ||
- local->iw_mode == IW_MODE_ADHOC)) {
- schedule_work(&local->comms_qual_update);
- }
-
- local->tick_timer.expires = jiffies + 2 * HZ;
- add_timer(&local->tick_timer);
-}
-
-
-#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS)
-static u16 hfa384x_read_reg(struct net_device *dev, u16 reg)
-{
- return HFA384X_INW(reg);
-}
-
-static int prism2_registers_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
-
-#define SHOW_REG(n) \
- seq_printf(m, #n "=%04x\n", hfa384x_read_reg(local->dev, HFA384X_##n##_OFF))
-
- SHOW_REG(CMD);
- SHOW_REG(PARAM0);
- SHOW_REG(PARAM1);
- SHOW_REG(PARAM2);
- SHOW_REG(STATUS);
- SHOW_REG(RESP0);
- SHOW_REG(RESP1);
- SHOW_REG(RESP2);
- SHOW_REG(INFOFID);
- SHOW_REG(CONTROL);
- SHOW_REG(SELECT0);
- SHOW_REG(SELECT1);
- SHOW_REG(OFFSET0);
- SHOW_REG(OFFSET1);
- SHOW_REG(RXFID);
- SHOW_REG(ALLOCFID);
- SHOW_REG(TXCOMPLFID);
- SHOW_REG(SWSUPPORT0);
- SHOW_REG(SWSUPPORT1);
- SHOW_REG(SWSUPPORT2);
- SHOW_REG(EVSTAT);
- SHOW_REG(INTEN);
- SHOW_REG(EVACK);
- /* Do not read data registers, because they change the state of the
- * MAC (offset += 2) */
- /* SHOW_REG(DATA0); */
- /* SHOW_REG(DATA1); */
- SHOW_REG(AUXPAGE);
- SHOW_REG(AUXOFFSET);
- /* SHOW_REG(AUXDATA); */
-#ifdef PRISM2_PCI
- SHOW_REG(PCICOR);
- SHOW_REG(PCIHCR);
- SHOW_REG(PCI_M0_ADDRH);
- SHOW_REG(PCI_M0_ADDRL);
- SHOW_REG(PCI_M0_LEN);
- SHOW_REG(PCI_M0_CTL);
- SHOW_REG(PCI_STATUS);
- SHOW_REG(PCI_M1_ADDRH);
- SHOW_REG(PCI_M1_ADDRL);
- SHOW_REG(PCI_M1_LEN);
- SHOW_REG(PCI_M1_CTL);
-#endif /* PRISM2_PCI */
-
- return 0;
-}
-#endif
-
-struct set_tim_data {
- struct list_head list;
- int aid;
- int set;
-};
-
-static int prism2_set_tim(struct net_device *dev, int aid, int set)
-{
- struct list_head *ptr;
- struct set_tim_data *new_entry;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- new_entry = kzalloc(sizeof(*new_entry), GFP_ATOMIC);
- if (new_entry == NULL)
- return -ENOMEM;
-
- new_entry->aid = aid;
- new_entry->set = set;
-
- spin_lock_bh(&local->set_tim_lock);
- list_for_each(ptr, &local->set_tim_list) {
- struct set_tim_data *entry =
- list_entry(ptr, struct set_tim_data, list);
- if (entry->aid == aid) {
- PDEBUG(DEBUG_PS2, "%s: prism2_set_tim: aid=%d "
- "set=%d ==> %d\n",
- local->dev->name, aid, entry->set, set);
- entry->set = set;
- kfree(new_entry);
- new_entry = NULL;
- break;
- }
- }
- if (new_entry)
- list_add_tail(&new_entry->list, &local->set_tim_list);
- spin_unlock_bh(&local->set_tim_lock);
-
- schedule_work(&local->set_tim_queue);
-
- return 0;
-}
-
-
-static void handle_set_tim_queue(struct work_struct *work)
-{
- local_info_t *local = container_of(work, local_info_t, set_tim_queue);
- struct set_tim_data *entry;
- u16 val;
-
- for (;;) {
- entry = NULL;
- spin_lock_bh(&local->set_tim_lock);
- if (!list_empty(&local->set_tim_list)) {
- entry = list_entry(local->set_tim_list.next,
- struct set_tim_data, list);
- list_del(&entry->list);
- }
- spin_unlock_bh(&local->set_tim_lock);
- if (!entry)
- break;
-
- PDEBUG(DEBUG_PS2, "%s: handle_set_tim_queue: aid=%d set=%d\n",
- local->dev->name, entry->aid, entry->set);
-
- val = entry->aid;
- if (entry->set)
- val |= 0x8000;
- if (hostap_set_word(local->dev, HFA384X_RID_CNFTIMCTRL, val)) {
- printk(KERN_DEBUG "%s: set_tim failed (aid=%d "
- "set=%d)\n",
- local->dev->name, entry->aid, entry->set);
- }
-
- kfree(entry);
- }
-}
-
-
-static void prism2_clear_set_tim_queue(local_info_t *local)
-{
- struct list_head *ptr, *n;
-
- list_for_each_safe(ptr, n, &local->set_tim_list) {
- struct set_tim_data *entry;
- entry = list_entry(ptr, struct set_tim_data, list);
- list_del(&entry->list);
- kfree(entry);
- }
-}
-
-
-/*
- * HostAP uses two layers of net devices, where the inner
- * layer gets called all the time from the outer layer.
- * This is a natural nesting, which needs a split lock type.
- */
-static struct lock_class_key hostap_netdev_xmit_lock_key;
-static struct lock_class_key hostap_netdev_addr_lock_key;
-
-static void prism2_set_lockdep_class_one(struct net_device *dev,
- struct netdev_queue *txq,
- void *_unused)
-{
- lockdep_set_class(&txq->_xmit_lock,
- &hostap_netdev_xmit_lock_key);
-}
-
-static void prism2_set_lockdep_class(struct net_device *dev)
-{
- lockdep_set_class(&dev->addr_list_lock,
- &hostap_netdev_addr_lock_key);
- netdev_for_each_tx_queue(dev, prism2_set_lockdep_class_one, NULL);
-}
-
-static struct net_device *
-prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
- struct device *sdev)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- struct local_info *local;
- int len, i, ret;
-
- if (funcs == NULL)
- return NULL;
-
- len = strlen(dev_template);
- if (len >= IFNAMSIZ || strstr(dev_template, "%d") == NULL) {
- printk(KERN_WARNING "hostap: Invalid dev_template='%s'\n",
- dev_template);
- return NULL;
- }
-
- len = sizeof(struct hostap_interface) +
- 3 + sizeof(struct local_info) +
- 3 + sizeof(struct ap_data);
-
- dev = alloc_etherdev(len);
- if (dev == NULL)
- return NULL;
-
- iface = netdev_priv(dev);
- local = (struct local_info *) ((((long) (iface + 1)) + 3) & ~3);
- local->ap = (struct ap_data *) ((((long) (local + 1)) + 3) & ~3);
- local->dev = iface->dev = dev;
- iface->local = local;
- iface->type = HOSTAP_INTERFACE_MASTER;
- INIT_LIST_HEAD(&local->hostap_interfaces);
-
- local->hw_module = THIS_MODULE;
-
-#ifdef PRISM2_IO_DEBUG
- local->io_debug_enabled = 1;
-#endif /* PRISM2_IO_DEBUG */
-
- local->func = funcs;
- local->func->cmd = hfa384x_cmd;
- local->func->read_regs = hfa384x_read_regs;
- local->func->get_rid = hfa384x_get_rid;
- local->func->set_rid = hfa384x_set_rid;
- local->func->hw_enable = prism2_hw_enable;
- local->func->hw_config = prism2_hw_config;
- local->func->hw_reset = prism2_hw_reset;
- local->func->hw_shutdown = prism2_hw_shutdown;
- local->func->reset_port = prism2_reset_port;
- local->func->schedule_reset = prism2_schedule_reset;
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- local->func->read_aux_proc_ops = &prism2_download_aux_dump_proc_ops;
- local->func->download = prism2_download;
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
- local->func->tx = prism2_tx_80211;
- local->func->set_tim = prism2_set_tim;
- local->func->need_tx_headroom = 0; /* no need to add txdesc in
- * skb->data (FIX: maybe for DMA bus
- * mastering? */
-
- local->mtu = mtu;
-
- rwlock_init(&local->iface_lock);
- spin_lock_init(&local->txfidlock);
- spin_lock_init(&local->cmdlock);
- spin_lock_init(&local->baplock);
- spin_lock_init(&local->lock);
- spin_lock_init(&local->irq_init_lock);
- mutex_init(&local->rid_bap_mtx);
-
- if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
- card_idx = 0;
- local->card_idx = card_idx;
-
- len = strlen(essid);
- memcpy(local->essid, essid,
- len > MAX_SSID_LEN ? MAX_SSID_LEN : len);
- local->essid[MAX_SSID_LEN] = '\0';
- i = GET_INT_PARM(iw_mode, card_idx);
- if ((i >= IW_MODE_ADHOC && i <= IW_MODE_REPEAT) ||
- i == IW_MODE_MONITOR) {
- local->iw_mode = i;
- } else {
- printk(KERN_WARNING "prism2: Unknown iw_mode %d; using "
- "IW_MODE_MASTER\n", i);
- local->iw_mode = IW_MODE_MASTER;
- }
- local->channel = GET_INT_PARM(channel, card_idx);
- local->beacon_int = GET_INT_PARM(beacon_int, card_idx);
- local->dtim_period = GET_INT_PARM(dtim_period, card_idx);
- local->wds_max_connections = 16;
- local->tx_control = HFA384X_TX_CTRL_FLAGS;
- local->manual_retry_count = -1;
- local->rts_threshold = 2347;
- local->fragm_threshold = 2346;
- local->rssi_to_dBm = 100; /* default; to be overriden by
- * cnfDbmAdjust, if available */
- local->auth_algs = PRISM2_AUTH_OPEN | PRISM2_AUTH_SHARED_KEY;
- local->sram_type = -1;
- local->scan_channel_mask = 0xffff;
- local->monitor_type = PRISM2_MONITOR_RADIOTAP;
-
- /* Initialize task queue structures */
- INIT_WORK(&local->reset_queue, handle_reset_queue);
- INIT_WORK(&local->set_multicast_list_queue,
- hostap_set_multicast_list_queue);
-
- INIT_WORK(&local->set_tim_queue, handle_set_tim_queue);
- INIT_LIST_HEAD(&local->set_tim_list);
- spin_lock_init(&local->set_tim_lock);
-
- INIT_WORK(&local->comms_qual_update, handle_comms_qual_update);
-
- /* Initialize tasklets for handling hardware IRQ related operations
- * outside hw IRQ handler */
- tasklet_setup(&local->bap_tasklet, hostap_bap_tasklet);
- tasklet_setup(&local->info_tasklet, hostap_info_tasklet);
- hostap_info_init(local);
-
- tasklet_setup(&local->rx_tasklet, hostap_rx_tasklet);
- skb_queue_head_init(&local->rx_list);
-
- tasklet_setup(&local->sta_tx_exc_tasklet,
- hostap_sta_tx_exc_tasklet);
- skb_queue_head_init(&local->sta_tx_exc_list);
-
- INIT_LIST_HEAD(&local->cmd_queue);
- init_waitqueue_head(&local->hostscan_wq);
-
- lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock);
-
- timer_setup(&local->passive_scan_timer, hostap_passive_scan, 0);
- timer_setup(&local->tick_timer, hostap_tick_timer, 0);
- local->tick_timer.expires = jiffies + 2 * HZ;
- add_timer(&local->tick_timer);
-
- INIT_LIST_HEAD(&local->bss_list);
-
- hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER);
-
- dev->type = ARPHRD_IEEE80211;
- dev->header_ops = &hostap_80211_ops;
-
- rtnl_lock();
- ret = dev_alloc_name(dev, "wifi%d");
- SET_NETDEV_DEV(dev, sdev);
- if (ret >= 0)
- ret = register_netdevice(dev);
-
- prism2_set_lockdep_class(dev);
- rtnl_unlock();
- if (ret < 0) {
- printk(KERN_WARNING "%s: register netdevice failed!\n",
- dev_info);
- goto fail;
- }
- printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name);
-
- hostap_init_data(local);
- return dev;
-
- fail:
- free_netdev(dev);
- return NULL;
-}
-
-
-static int hostap_hw_ready(struct net_device *dev)
-{
- struct hostap_interface *iface;
- struct local_info *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
- local->ddev = hostap_add_interface(local, HOSTAP_INTERFACE_MAIN, 0,
- "", dev_template);
-
- if (local->ddev) {
- if (local->iw_mode == IW_MODE_INFRA ||
- local->iw_mode == IW_MODE_ADHOC) {
- netif_carrier_off(local->dev);
- netif_carrier_off(local->ddev);
- }
- hostap_init_proc(local);
-#ifndef PRISM2_NO_PROCFS_DEBUG
- proc_create_single_data("registers", 0, local->proc,
- prism2_registers_proc_show, local);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
- hostap_init_ap_proc(local);
- return 0;
- }
-
- return -1;
-}
-
-
-static void prism2_free_local_data(struct net_device *dev)
-{
- struct hostap_tx_callback_info *tx_cb, *tx_cb_prev;
- int i;
- struct hostap_interface *iface;
- struct local_info *local;
- struct list_head *ptr, *n;
-
- if (dev == NULL)
- return;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Unregister all netdevs before freeing local data. */
- list_for_each_safe(ptr, n, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type == HOSTAP_INTERFACE_MASTER) {
- /* special handling for this interface below */
- continue;
- }
- hostap_remove_interface(iface->dev, 0, 1);
- }
-
- unregister_netdev(local->dev);
-
- flush_work(&local->reset_queue);
- flush_work(&local->set_multicast_list_queue);
- flush_work(&local->set_tim_queue);
-#ifndef PRISM2_NO_STATION_MODES
- flush_work(&local->info_queue);
-#endif
- flush_work(&local->comms_qual_update);
-
- lib80211_crypt_info_free(&local->crypt_info);
-
- if (timer_pending(&local->passive_scan_timer))
- del_timer(&local->passive_scan_timer);
-
- if (timer_pending(&local->tick_timer))
- del_timer(&local->tick_timer);
-
- prism2_clear_cmd_queue(local);
-
- skb_queue_purge(&local->info_list);
- skb_queue_purge(&local->rx_list);
- skb_queue_purge(&local->sta_tx_exc_list);
-
- if (local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_DISABLE);
-
- if (local->ap != NULL)
- hostap_free_data(local->ap);
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- if (local->proc != NULL)
- remove_proc_entry("registers", local->proc);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
- hostap_remove_proc(local);
-
- tx_cb = local->tx_callback;
- while (tx_cb != NULL) {
- tx_cb_prev = tx_cb;
- tx_cb = tx_cb->next;
- kfree(tx_cb_prev);
- }
-
- hostap_set_hostapd(local, 0, 0);
- hostap_set_hostapd_sta(local, 0, 0);
-
- for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) {
- if (local->frag_cache[i].skb != NULL)
- dev_kfree_skb(local->frag_cache[i].skb);
- }
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- prism2_download_free_data(local->dl_pri);
- prism2_download_free_data(local->dl_sec);
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- prism2_clear_set_tim_queue(local);
-
- list_for_each_safe(ptr, n, &local->bss_list) {
- struct hostap_bss_info *bss =
- list_entry(ptr, struct hostap_bss_info, list);
- kfree(bss);
- }
-
- kfree(local->pda);
- kfree(local->last_scan_results);
- kfree(local->generic_elem);
-
- free_netdev(local->dev);
-}
-
-
-#if defined(PRISM2_PCI) || defined(PRISM2_PCCARD)
-static void __maybe_unused prism2_suspend(struct net_device *dev)
-{
- struct hostap_interface *iface;
- struct local_info *local;
- union iwreq_data wrqu;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Send disconnect event, e.g., to trigger reassociation after resume
- * if wpa_supplicant is used. */
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
-
- /* Disable hardware and firmware */
- prism2_hw_shutdown(dev, 0);
-}
-#endif /* PRISM2_PCI || PRISM2_PCCARD */
-
-
-/* These might at some point be compiled separately and used as separate
- * kernel modules or linked into one */
-#ifdef PRISM2_DOWNLOAD_SUPPORT
-#include "hostap_download.c"
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-#ifdef PRISM2_CALLBACK
-/* External hostap_callback.c file can be used to, e.g., blink activity led.
- * This can use platform specific code and must define prism2_callback()
- * function (if PRISM2_CALLBACK is not defined, these function calls are not
- * used. */
-#include "hostap_callback.c"
-#endif /* PRISM2_CALLBACK */
diff --git a/drivers/net/wireless/intersil/hostap/hostap_info.c b/drivers/net/wireless/intersil/hostap/hostap_info.c
deleted file mode 100644
index da8c30f10d923..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_info.c
+++ /dev/null
@@ -1,509 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Host AP driver Info Frame processing (part of hostap.o module) */
-
-#include <linux/if_arp.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/etherdevice.h>
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_commtallies16(local_info_t *local, unsigned char *buf,
- int left)
-{
- struct hfa384x_comm_tallies *tallies;
-
- if (left < sizeof(struct hfa384x_comm_tallies)) {
- printk(KERN_DEBUG "%s: too short (len=%d) commtallies "
- "info frame\n", local->dev->name, left);
- return;
- }
-
- tallies = (struct hfa384x_comm_tallies *) buf;
-#define ADD_COMM_TALLIES(name) \
-local->comm_tallies.name += le16_to_cpu(tallies->name)
- ADD_COMM_TALLIES(tx_unicast_frames);
- ADD_COMM_TALLIES(tx_multicast_frames);
- ADD_COMM_TALLIES(tx_fragments);
- ADD_COMM_TALLIES(tx_unicast_octets);
- ADD_COMM_TALLIES(tx_multicast_octets);
- ADD_COMM_TALLIES(tx_deferred_transmissions);
- ADD_COMM_TALLIES(tx_single_retry_frames);
- ADD_COMM_TALLIES(tx_multiple_retry_frames);
- ADD_COMM_TALLIES(tx_retry_limit_exceeded);
- ADD_COMM_TALLIES(tx_discards);
- ADD_COMM_TALLIES(rx_unicast_frames);
- ADD_COMM_TALLIES(rx_multicast_frames);
- ADD_COMM_TALLIES(rx_fragments);
- ADD_COMM_TALLIES(rx_unicast_octets);
- ADD_COMM_TALLIES(rx_multicast_octets);
- ADD_COMM_TALLIES(rx_fcs_errors);
- ADD_COMM_TALLIES(rx_discards_no_buffer);
- ADD_COMM_TALLIES(tx_discards_wrong_sa);
- ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
- ADD_COMM_TALLIES(rx_message_in_msg_fragments);
- ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
-#undef ADD_COMM_TALLIES
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_commtallies32(local_info_t *local, unsigned char *buf,
- int left)
-{
- struct hfa384x_comm_tallies32 *tallies;
-
- if (left < sizeof(struct hfa384x_comm_tallies32)) {
- printk(KERN_DEBUG "%s: too short (len=%d) commtallies32 "
- "info frame\n", local->dev->name, left);
- return;
- }
-
- tallies = (struct hfa384x_comm_tallies32 *) buf;
-#define ADD_COMM_TALLIES(name) \
-local->comm_tallies.name += le32_to_cpu(tallies->name)
- ADD_COMM_TALLIES(tx_unicast_frames);
- ADD_COMM_TALLIES(tx_multicast_frames);
- ADD_COMM_TALLIES(tx_fragments);
- ADD_COMM_TALLIES(tx_unicast_octets);
- ADD_COMM_TALLIES(tx_multicast_octets);
- ADD_COMM_TALLIES(tx_deferred_transmissions);
- ADD_COMM_TALLIES(tx_single_retry_frames);
- ADD_COMM_TALLIES(tx_multiple_retry_frames);
- ADD_COMM_TALLIES(tx_retry_limit_exceeded);
- ADD_COMM_TALLIES(tx_discards);
- ADD_COMM_TALLIES(rx_unicast_frames);
- ADD_COMM_TALLIES(rx_multicast_frames);
- ADD_COMM_TALLIES(rx_fragments);
- ADD_COMM_TALLIES(rx_unicast_octets);
- ADD_COMM_TALLIES(rx_multicast_octets);
- ADD_COMM_TALLIES(rx_fcs_errors);
- ADD_COMM_TALLIES(rx_discards_no_buffer);
- ADD_COMM_TALLIES(tx_discards_wrong_sa);
- ADD_COMM_TALLIES(rx_discards_wep_undecryptable);
- ADD_COMM_TALLIES(rx_message_in_msg_fragments);
- ADD_COMM_TALLIES(rx_message_in_bad_msg_fragments);
-#undef ADD_COMM_TALLIES
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_commtallies(local_info_t *local, unsigned char *buf,
- int left)
-{
- if (local->tallies32)
- prism2_info_commtallies32(local, buf, left);
- else
- prism2_info_commtallies16(local, buf, left);
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-#ifndef PRISM2_NO_DEBUG
-static const char* hfa384x_linkstatus_str(u16 linkstatus)
-{
- switch (linkstatus) {
- case HFA384X_LINKSTATUS_CONNECTED:
- return "Connected";
- case HFA384X_LINKSTATUS_DISCONNECTED:
- return "Disconnected";
- case HFA384X_LINKSTATUS_AP_CHANGE:
- return "Access point change";
- case HFA384X_LINKSTATUS_AP_OUT_OF_RANGE:
- return "Access point out of range";
- case HFA384X_LINKSTATUS_AP_IN_RANGE:
- return "Access point in range";
- case HFA384X_LINKSTATUS_ASSOC_FAILED:
- return "Association failed";
- default:
- return "Unknown";
- }
-}
-#endif /* PRISM2_NO_DEBUG */
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_linkstatus(local_info_t *local, unsigned char *buf,
- int left)
-{
- u16 val;
- int non_sta_mode;
-
- /* Alloc new JoinRequests to occur since LinkStatus for the previous
- * has been received */
- local->last_join_time = 0;
-
- if (left != 2) {
- printk(KERN_DEBUG "%s: invalid linkstatus info frame "
- "length %d\n", local->dev->name, left);
- return;
- }
-
- non_sta_mode = local->iw_mode == IW_MODE_MASTER ||
- local->iw_mode == IW_MODE_REPEAT ||
- local->iw_mode == IW_MODE_MONITOR;
-
- val = buf[0] | (buf[1] << 8);
- if (!non_sta_mode || val != HFA384X_LINKSTATUS_DISCONNECTED) {
- PDEBUG(DEBUG_EXTRA, "%s: LinkStatus=%d (%s)\n",
- local->dev->name, val, hfa384x_linkstatus_str(val));
- }
-
- if (non_sta_mode) {
- netif_carrier_on(local->dev);
- netif_carrier_on(local->ddev);
- return;
- }
-
- /* Get current BSSID later in scheduled task */
- set_bit(PRISM2_INFO_PENDING_LINKSTATUS, &local->pending_info);
- local->prev_link_status = val;
- schedule_work(&local->info_queue);
-}
-
-
-static void prism2_host_roaming(local_info_t *local)
-{
- struct hfa384x_join_request req;
- struct net_device *dev = local->dev;
- struct hfa384x_hostscan_result *selected, *entry;
- int i;
- unsigned long flags;
-
- if (local->last_join_time &&
- time_before(jiffies, local->last_join_time + 10 * HZ)) {
- PDEBUG(DEBUG_EXTRA, "%s: last join request has not yet been "
- "completed - waiting for it before issuing new one\n",
- dev->name);
- return;
- }
-
- /* ScanResults are sorted: first ESS results in decreasing signal
- * quality then IBSS results in similar order.
- * Trivial roaming policy: just select the first entry.
- * This could probably be improved by adding hysteresis to limit
- * number of handoffs, etc.
- *
- * Could do periodic RID_SCANREQUEST or Inquire F101 to get new
- * ScanResults */
- spin_lock_irqsave(&local->lock, flags);
- if (local->last_scan_results == NULL ||
- local->last_scan_results_count == 0) {
- spin_unlock_irqrestore(&local->lock, flags);
- PDEBUG(DEBUG_EXTRA, "%s: no scan results for host roaming\n",
- dev->name);
- return;
- }
-
- selected = &local->last_scan_results[0];
-
- if (local->preferred_ap[0] || local->preferred_ap[1] ||
- local->preferred_ap[2] || local->preferred_ap[3] ||
- local->preferred_ap[4] || local->preferred_ap[5]) {
- /* Try to find preferred AP */
- PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n",
- dev->name, local->preferred_ap);
- for (i = 0; i < local->last_scan_results_count; i++) {
- entry = &local->last_scan_results[i];
- if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
- {
- PDEBUG(DEBUG_EXTRA, "%s: using preferred AP "
- "selection\n", dev->name);
- selected = entry;
- break;
- }
- }
- }
-
- memcpy(req.bssid, selected->bssid, ETH_ALEN);
- req.channel = selected->chid;
- spin_unlock_irqrestore(&local->lock, flags);
-
- PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM"
- " channel=%d\n",
- dev->name, req.bssid, le16_to_cpu(req.channel));
- if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
- sizeof(req))) {
- printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
- }
- local->last_join_time = jiffies;
-}
-
-
-static void hostap_report_scan_complete(local_info_t *local)
-{
- union iwreq_data wrqu;
-
- /* Inform user space about new scan results (just empty event,
- * SIOCGIWSCAN can be used to fetch data */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(local->dev, SIOCGIWSCAN, &wrqu, NULL);
-
- /* Allow SIOCGIWSCAN handling to occur since we have received
- * scanning result */
- local->scan_timestamp = 0;
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_scanresults(local_info_t *local, unsigned char *buf,
- int left)
-{
- u16 *pos;
- int new_count, i;
- unsigned long flags;
- struct hfa384x_scan_result *res;
- struct hfa384x_hostscan_result *results, *prev;
-
- if (left < 4) {
- printk(KERN_DEBUG "%s: invalid scanresult info frame "
- "length %d\n", local->dev->name, left);
- return;
- }
-
- pos = (u16 *) buf;
- pos++;
- pos++;
- left -= 4;
-
- new_count = left / sizeof(struct hfa384x_scan_result);
- results = kmalloc_array(new_count,
- sizeof(struct hfa384x_hostscan_result),
- GFP_ATOMIC);
- if (results == NULL)
- return;
-
- /* Convert to hostscan result format. */
- res = (struct hfa384x_scan_result *) pos;
- for (i = 0; i < new_count; i++) {
- memcpy(&results[i], &res[i],
- sizeof(struct hfa384x_scan_result));
- results[i].atim = 0;
- }
-
- spin_lock_irqsave(&local->lock, flags);
- local->last_scan_type = PRISM2_SCAN;
- prev = local->last_scan_results;
- local->last_scan_results = results;
- local->last_scan_results_count = new_count;
- spin_unlock_irqrestore(&local->lock, flags);
- kfree(prev);
-
- hostap_report_scan_complete(local);
-
- /* Perform rest of ScanResults handling later in scheduled task */
- set_bit(PRISM2_INFO_PENDING_SCANRESULTS, &local->pending_info);
- schedule_work(&local->info_queue);
-}
-
-
-/* Called only as a tasklet (software IRQ) */
-static void prism2_info_hostscanresults(local_info_t *local,
- unsigned char *buf, int left)
-{
- int i, result_size, copy_len, new_count;
- struct hfa384x_hostscan_result *results, *prev;
- unsigned long flags;
- __le16 *pos;
- u8 *ptr;
-
- wake_up_interruptible(&local->hostscan_wq);
-
- if (left < 4) {
- printk(KERN_DEBUG "%s: invalid hostscanresult info frame "
- "length %d\n", local->dev->name, left);
- return;
- }
-
- pos = (__le16 *) buf;
- copy_len = result_size = le16_to_cpu(*pos);
- if (result_size == 0) {
- printk(KERN_DEBUG "%s: invalid result_size (0) in "
- "hostscanresults\n", local->dev->name);
- return;
- }
- if (copy_len > sizeof(struct hfa384x_hostscan_result))
- copy_len = sizeof(struct hfa384x_hostscan_result);
-
- pos++;
- pos++;
- left -= 4;
- ptr = (u8 *) pos;
-
- new_count = left / result_size;
- results = kcalloc(new_count, sizeof(struct hfa384x_hostscan_result),
- GFP_ATOMIC);
- if (results == NULL)
- return;
-
- for (i = 0; i < new_count; i++) {
- memcpy(&results[i], ptr, copy_len);
- ptr += result_size;
- left -= result_size;
- }
-
- if (left) {
- printk(KERN_DEBUG "%s: short HostScan result entry (%d/%d)\n",
- local->dev->name, left, result_size);
- }
-
- spin_lock_irqsave(&local->lock, flags);
- local->last_scan_type = PRISM2_HOSTSCAN;
- prev = local->last_scan_results;
- local->last_scan_results = results;
- local->last_scan_results_count = new_count;
- spin_unlock_irqrestore(&local->lock, flags);
- kfree(prev);
-
- hostap_report_scan_complete(local);
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-/* Called only as a tasklet (software IRQ) */
-void hostap_info_process(local_info_t *local, struct sk_buff *skb)
-{
- struct hfa384x_info_frame *info;
- unsigned char *buf;
- int left;
-#ifndef PRISM2_NO_DEBUG
- int i;
-#endif /* PRISM2_NO_DEBUG */
-
- info = (struct hfa384x_info_frame *) skb->data;
- buf = skb->data + sizeof(*info);
- left = skb->len - sizeof(*info);
-
- switch (le16_to_cpu(info->type)) {
- case HFA384X_INFO_COMMTALLIES:
- prism2_info_commtallies(local, buf, left);
- break;
-
-#ifndef PRISM2_NO_STATION_MODES
- case HFA384X_INFO_LINKSTATUS:
- prism2_info_linkstatus(local, buf, left);
- break;
-
- case HFA384X_INFO_SCANRESULTS:
- prism2_info_scanresults(local, buf, left);
- break;
-
- case HFA384X_INFO_HOSTSCANRESULTS:
- prism2_info_hostscanresults(local, buf, left);
- break;
-#endif /* PRISM2_NO_STATION_MODES */
-
-#ifndef PRISM2_NO_DEBUG
- default:
- PDEBUG(DEBUG_EXTRA, "%s: INFO - len=%d type=0x%04x\n",
- local->dev->name, le16_to_cpu(info->len),
- le16_to_cpu(info->type));
- PDEBUG(DEBUG_EXTRA, "Unknown info frame:");
- for (i = 0; i < (left < 100 ? left : 100); i++)
- PDEBUG2(DEBUG_EXTRA, " %02x", buf[i]);
- PDEBUG2(DEBUG_EXTRA, "\n");
- break;
-#endif /* PRISM2_NO_DEBUG */
- }
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static void handle_info_queue_linkstatus(local_info_t *local)
-{
- int val = local->prev_link_status;
- int connected;
- union iwreq_data wrqu;
-
- connected =
- val == HFA384X_LINKSTATUS_CONNECTED ||
- val == HFA384X_LINKSTATUS_AP_CHANGE ||
- val == HFA384X_LINKSTATUS_AP_IN_RANGE;
-
- if (local->func->get_rid(local->dev, HFA384X_RID_CURRENTBSSID,
- local->bssid, ETH_ALEN, 1) < 0) {
- printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
- "LinkStatus event\n", local->dev->name);
- } else {
- PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n",
- local->dev->name,
- (unsigned char *) local->bssid);
- if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
- hostap_add_sta(local->ap, local->bssid);
- }
-
- /* Get BSSID if we have a valid AP address */
- if (connected) {
- netif_carrier_on(local->dev);
- netif_carrier_on(local->ddev);
- memcpy(wrqu.ap_addr.sa_data, local->bssid, ETH_ALEN);
- } else {
- netif_carrier_off(local->dev);
- netif_carrier_off(local->ddev);
- eth_zero_addr(wrqu.ap_addr.sa_data);
- }
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /*
- * Filter out sequential disconnect events in order not to cause a
- * flood of SIOCGIWAP events that have a race condition with EAPOL
- * frames and can confuse wpa_supplicant about the current association
- * status.
- */
- if (connected || local->prev_linkstatus_connected)
- wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
- local->prev_linkstatus_connected = connected;
-}
-
-
-static void handle_info_queue_scanresults(local_info_t *local)
-{
- if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA)
- prism2_host_roaming(local);
-
- if (local->host_roaming == 2 && local->iw_mode == IW_MODE_INFRA &&
- !is_zero_ether_addr(local->preferred_ap)) {
- /*
- * Firmware seems to be getting into odd state in host_roaming
- * mode 2 when hostscan is used without join command, so try
- * to fix this by re-joining the current AP. This does not
- * actually trigger a new association if the current AP is
- * still in the scan results.
- */
- prism2_host_roaming(local);
- }
-}
-
-
-/* Called only as scheduled task after receiving info frames (used to avoid
- * pending too much time in HW IRQ handler). */
-static void handle_info_queue(struct work_struct *work)
-{
- local_info_t *local = container_of(work, local_info_t, info_queue);
-
- if (test_and_clear_bit(PRISM2_INFO_PENDING_LINKSTATUS,
- &local->pending_info))
- handle_info_queue_linkstatus(local);
-
- if (test_and_clear_bit(PRISM2_INFO_PENDING_SCANRESULTS,
- &local->pending_info))
- handle_info_queue_scanresults(local);
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-void hostap_info_init(local_info_t *local)
-{
- skb_queue_head_init(&local->info_list);
-#ifndef PRISM2_NO_STATION_MODES
- INIT_WORK(&local->info_queue, handle_info_queue);
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-EXPORT_SYMBOL(hostap_info_init);
-EXPORT_SYMBOL(hostap_info_process);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c b/drivers/net/wireless/intersil/hostap/hostap_ioctl.c
deleted file mode 100644
index b4adfc190ae87..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_ioctl.c
+++ /dev/null
@@ -1,4075 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/sched/signal.h>
-#include <linux/ethtool.h>
-#include <linux/if_arp.h>
-#include <linux/module.h>
-#include <linux/etherdevice.h>
-#include <net/lib80211.h>
-
-#include "hostap_wlan.h"
-#include "hostap.h"
-#include "hostap_ap.h"
-
-static struct iw_statistics *hostap_get_wireless_stats(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct iw_statistics *wstats;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Why are we doing that ? Jean II */
- if (iface->type != HOSTAP_INTERFACE_MAIN)
- return NULL;
-
- wstats = &local->wstats;
-
- wstats->status = 0;
- wstats->discard.code =
- local->comm_tallies.rx_discards_wep_undecryptable;
- wstats->discard.misc =
- local->comm_tallies.rx_fcs_errors +
- local->comm_tallies.rx_discards_no_buffer +
- local->comm_tallies.tx_discards_wrong_sa;
-
- wstats->discard.retries =
- local->comm_tallies.tx_retry_limit_exceeded;
- wstats->discard.fragment =
- local->comm_tallies.rx_message_in_bad_msg_fragments;
-
- if (local->iw_mode != IW_MODE_MASTER &&
- local->iw_mode != IW_MODE_REPEAT) {
-
- if (prism2_update_comms_qual(dev) == 0)
- wstats->qual.updated = IW_QUAL_ALL_UPDATED |
- IW_QUAL_DBM;
-
- wstats->qual.qual = local->comms_qual;
- wstats->qual.level = local->avg_signal;
- wstats->qual.noise = local->avg_noise;
- } else {
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = IW_QUAL_ALL_INVALID;
- }
-
- return wstats;
-}
-
-
-static int prism2_get_datarates(struct net_device *dev, u8 *rates)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u8 buf[12];
- int len;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- len = local->func->get_rid(dev, HFA384X_RID_SUPPORTEDDATARATES, buf,
- sizeof(buf), 0);
- if (len < 2)
- return 0;
-
- val = le16_to_cpu(*(__le16 *) buf); /* string length */
-
- if (len - 2 < val || val > 10)
- return 0;
-
- memcpy(rates, buf + 2, val);
- return val;
-}
-
-
-static int prism2_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 rates[10];
- int len, i, over2 = 0;
-
- len = prism2_get_datarates(dev, rates);
-
- for (i = 0; i < len; i++) {
- if (rates[i] == 0x0b || rates[i] == 0x16) {
- over2 = 1;
- break;
- }
- }
-
- strcpy(wrqu->name, over2 ? "IEEE 802.11b" : "IEEE 802.11-DS");
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface;
- local_info_t *local;
- int i;
- struct lib80211_crypt_data **crypt;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i < 1 || i > 4)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
- if (i < 0 || i >= WEP_KEYS)
- return -EINVAL;
-
- crypt = &local->crypt_info.crypt[i];
-
- if (erq->flags & IW_ENCODE_DISABLED) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- goto done;
- }
-
- if (*crypt != NULL && (*crypt)->ops != NULL &&
- strcmp((*crypt)->ops->name, "WEP") != 0) {
- /* changing to use WEP; deinit previously used algorithm */
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- }
-
- if (*crypt == NULL) {
- struct lib80211_crypt_data *new_crypt;
-
- /* take WEP into use */
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL)
- return -ENOMEM;
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- if (!new_crypt->ops) {
- request_module("lib80211_crypt_wep");
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- }
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(i);
- if (!new_crypt->ops || !new_crypt->priv) {
- kfree(new_crypt);
- new_crypt = NULL;
-
- printk(KERN_WARNING "%s: could not initialize WEP: "
- "load module hostap_crypt_wep.o\n",
- dev->name);
- return -EOPNOTSUPP;
- }
- *crypt = new_crypt;
- }
-
- if (erq->length > 0) {
- int len = erq->length <= 5 ? 5 : 13;
- int first = 1, j;
- if (len > erq->length)
- memset(keybuf + erq->length, 0, len - erq->length);
- (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv);
- for (j = 0; j < WEP_KEYS; j++) {
- if (j != i && local->crypt_info.crypt[j]) {
- first = 0;
- break;
- }
- }
- if (first)
- local->crypt_info.tx_keyidx = i;
- } else {
- /* No key data - just set the default TX key index */
- local->crypt_info.tx_keyidx = i;
- }
-
- done:
- local->open_wep = erq->flags & IW_ENCODE_OPEN;
-
- if (hostap_set_encryption(local)) {
- printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name);
- return -EINVAL;
- }
-
- /* Do not reset port0 if card is in Managed mode since resetting will
- * generate new IEEE 802.11 authentication which may end up in looping
- * with IEEE 802.1X. Prism2 documentation seem to require port reset
- * after WEP configuration. However, keys are apparently changed at
- * least in Managed mode. */
- if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) {
- printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-static int prism2_ioctl_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface;
- local_info_t *local;
- int i, len;
- u16 val;
- struct lib80211_crypt_data *crypt;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i < 1 || i > 4)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
- if (i < 0 || i >= WEP_KEYS)
- return -EINVAL;
-
- crypt = local->crypt_info.crypt[i];
- erq->flags = i + 1;
-
- if (crypt == NULL || crypt->ops == NULL) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- if (strcmp(crypt->ops->name, "WEP") != 0) {
- /* only WEP is supported with wireless extensions, so just
- * report that encryption is used */
- erq->length = 0;
- erq->flags |= IW_ENCODE_ENABLED;
- return 0;
- }
-
- /* Reads from HFA384X_RID_CNFDEFAULTKEY* return bogus values, so show
- * the keys from driver buffer */
- len = crypt->ops->get_key(key, WEP_KEY_LEN, NULL, crypt->priv);
- erq->length = (len >= 0 ? len : 0);
-
- if (local->func->get_rid(dev, HFA384X_RID_CNFWEPFLAGS, &val, 2, 1) < 0)
- {
- printk("CNFWEPFLAGS reading failed\n");
- return -EOPNOTSUPP;
- }
- le16_to_cpus(&val);
- if (val & HFA384X_WEPFLAGS_PRIVACYINVOKED)
- erq->flags |= IW_ENCODE_ENABLED;
- else
- erq->flags |= IW_ENCODE_DISABLED;
- if (val & HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- return 0;
-}
-
-
-static int hostap_set_rate(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int ret, basic_rates;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- basic_rates = local->basic_rates & local->tx_rate_control;
- if (!basic_rates || basic_rates != local->basic_rates) {
- printk(KERN_INFO "%s: updating basic rate set automatically "
- "to match with the new supported rate set\n",
- dev->name);
- if (!basic_rates)
- basic_rates = local->tx_rate_control;
-
- local->basic_rates = basic_rates;
- if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
- basic_rates))
- printk(KERN_WARNING "%s: failed to set "
- "cnfBasicRates\n", dev->name);
- }
-
- ret = (hostap_set_word(dev, HFA384X_RID_TXRATECONTROL,
- local->tx_rate_control) ||
- hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES,
- local->tx_rate_control) ||
- local->func->reset_port(dev));
-
- if (ret) {
- printk(KERN_WARNING "%s: TXRateControl/cnfSupportedRates "
- "setting to 0x%x failed\n",
- dev->name, local->tx_rate_control);
- }
-
- /* Update TX rate configuration for all STAs based on new operational
- * rate set. */
- hostap_update_rates(local);
-
- return ret;
-}
-
-
-static int prism2_ioctl_siwrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rrq->fixed) {
- switch (rrq->value) {
- case 11000000:
- local->tx_rate_control = HFA384X_RATES_11MBPS;
- break;
- case 5500000:
- local->tx_rate_control = HFA384X_RATES_5MBPS;
- break;
- case 2000000:
- local->tx_rate_control = HFA384X_RATES_2MBPS;
- break;
- case 1000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS;
- break;
- default:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- break;
- }
- } else {
- switch (rrq->value) {
- case 11000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- break;
- case 5500000:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS;
- break;
- case 2000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS;
- break;
- case 1000000:
- local->tx_rate_control = HFA384X_RATES_1MBPS;
- break;
- default:
- local->tx_rate_control = HFA384X_RATES_1MBPS |
- HFA384X_RATES_2MBPS | HFA384X_RATES_5MBPS |
- HFA384X_RATES_11MBPS;
- break;
- }
- }
-
- return hostap_set_rate(dev);
-}
-
-
-static int prism2_ioctl_giwrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- u16 val;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_TXRATECONTROL, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- if ((val & 0x1) && (val > 1))
- rrq->fixed = 0;
- else
- rrq->fixed = 1;
-
- if (local->iw_mode == IW_MODE_MASTER && local->ap != NULL &&
- !local->fw_tx_rate_control) {
- /* HFA384X_RID_CURRENTTXRATE seems to always be 2 Mbps in
- * Host AP mode, so use the recorded TX rate of the last sent
- * frame */
- rrq->value = local->ap->last_tx_rate > 0 ?
- local->ap->last_tx_rate * 100000 : 11000000;
- return 0;
- }
-
- if (local->func->get_rid(dev, HFA384X_RID_CURRENTTXRATE, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- switch (val) {
- case HFA384X_RATES_1MBPS:
- rrq->value = 1000000;
- break;
- case HFA384X_RATES_2MBPS:
- rrq->value = 2000000;
- break;
- case HFA384X_RATES_5MBPS:
- rrq->value = 5500000;
- break;
- case HFA384X_RATES_11MBPS:
- rrq->value = 11000000;
- break;
- default:
- /* should not happen */
- rrq->value = 11000000;
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_siwsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *sens = &wrqu->sens;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Set the desired AP density */
- if (sens->value < 1 || sens->value > 3)
- return -EINVAL;
-
- if (hostap_set_word(dev, HFA384X_RID_CNFSYSTEMSCALE, sens->value) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *sens = &wrqu->sens;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Get the current AP density */
- if (local->func->get_rid(dev, HFA384X_RID_CNFSYSTEMSCALE, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- sens->value = le16_to_cpu(val);
- sens->fixed = 1;
-
- return 0;
-}
-
-
-/* Deprecated in new wireless extension API */
-static int prism2_ioctl_giwaplist(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- struct sockaddr *addr;
- struct iw_quality *qual;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->iw_mode != IW_MODE_MASTER) {
- printk(KERN_DEBUG "SIOCGIWAPLIST is currently only supported "
- "in Host AP mode\n");
- data->length = 0;
- return -EOPNOTSUPP;
- }
-
- addr = kmalloc_array(IW_MAX_AP, sizeof(struct sockaddr), GFP_KERNEL);
- qual = kmalloc_array(IW_MAX_AP, sizeof(struct iw_quality), GFP_KERNEL);
- if (addr == NULL || qual == NULL) {
- kfree(addr);
- kfree(qual);
- data->length = 0;
- return -ENOMEM;
- }
-
- data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1);
-
- memcpy(extra, addr, sizeof(struct sockaddr) * data->length);
- data->flags = 1; /* has quality information */
- memcpy(extra + sizeof(struct sockaddr) * data->length, qual,
- sizeof(struct iw_quality) * data->length);
-
- kfree(addr);
- kfree(qual);
- return 0;
-}
-
-
-static int prism2_ioctl_siwrts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rts->disabled)
- val = cpu_to_le16(2347);
- else if (rts->value < 0 || rts->value > 2347)
- return -EINVAL;
- else
- val = cpu_to_le16(rts->value);
-
- if (local->func->set_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- local->rts_threshold = rts->value;
-
- return 0;
-}
-
-static int prism2_ioctl_giwrts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_RTSTHRESHOLD, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- rts->value = le16_to_cpu(val);
- rts->disabled = (rts->value == 2347);
- rts->fixed = 1;
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwfrag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rts->disabled)
- val = cpu_to_le16(2346);
- else if (rts->value < 256 || rts->value > 2346)
- return -EINVAL;
- else
- val = cpu_to_le16(rts->value & ~0x1); /* even numbers only */
-
- local->fragm_threshold = rts->value & ~0x1;
- if (local->func->set_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, &val,
- 2)
- || local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwfrag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD,
- &val, 2, 1) < 0)
- return -EINVAL;
-
- rts->value = le16_to_cpu(val);
- rts->disabled = (rts->value == 2346);
- rts->fixed = 1;
-
- return 0;
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static int hostap_join_ap(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_join_request req;
- unsigned long flags;
- int i;
- struct hfa384x_hostscan_result *entry;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memcpy(req.bssid, local->preferred_ap, ETH_ALEN);
- req.channel = 0;
-
- spin_lock_irqsave(&local->lock, flags);
- for (i = 0; i < local->last_scan_results_count; i++) {
- if (!local->last_scan_results)
- break;
- entry = &local->last_scan_results[i];
- if (ether_addr_equal(local->preferred_ap, entry->bssid)) {
- req.channel = entry->chid;
- break;
- }
- }
- spin_unlock_irqrestore(&local->lock, flags);
-
- if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
- sizeof(req))) {
- printk(KERN_DEBUG "%s: JoinRequest %pM failed\n",
- dev->name, local->preferred_ap);
- return -1;
- }
-
- printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n",
- dev->name, local->preferred_ap);
-
- return 0;
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-static int prism2_ioctl_siwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memcpy(local->preferred_ap, &ap_addr->sa_data, ETH_ALEN);
-
- if (local->host_roaming == 1 && local->iw_mode == IW_MODE_INFRA) {
- struct hfa384x_scan_request scan_req;
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(0x3fff);
- scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS);
- if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST,
- &scan_req, sizeof(scan_req))) {
- printk(KERN_DEBUG "%s: ScanResults request failed - "
- "preferred AP delayed to next unsolicited "
- "scan\n", dev->name);
- }
- } else if (local->host_roaming == 2 &&
- local->iw_mode == IW_MODE_INFRA) {
- if (hostap_join_ap(dev))
- return -EINVAL;
- } else {
- printk(KERN_DEBUG "%s: Preferred AP (SIOCSIWAP) is used only "
- "in Managed mode when host_roaming is enabled\n",
- dev->name);
- }
-
- return 0;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-static int prism2_ioctl_giwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- ap_addr->sa_family = ARPHRD_ETHER;
- switch (iface->type) {
- case HOSTAP_INTERFACE_AP:
- memcpy(&ap_addr->sa_data, dev->dev_addr, ETH_ALEN);
- break;
- case HOSTAP_INTERFACE_STA:
- memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN);
- break;
- case HOSTAP_INTERFACE_WDS:
- memcpy(&ap_addr->sa_data, iface->u.wds.remote_addr, ETH_ALEN);
- break;
- default:
- if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID,
- &ap_addr->sa_data, ETH_ALEN, 1) < 0)
- return -EOPNOTSUPP;
-
- /* local->bssid is also updated in LinkStatus handler when in
- * station mode */
- memcpy(local->bssid, &ap_addr->sa_data, ETH_ALEN);
- break;
- }
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwnickn(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *nickname)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memset(local->name, 0, sizeof(local->name));
- memcpy(local->name, nickname, data->length);
- local->name_set = 1;
-
- if (hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, local->name) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwnickn(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *nickname)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- int len;
- char name[MAX_NAME_LEN + 3];
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- len = local->func->get_rid(dev, HFA384X_RID_CNFOWNNAME,
- &name, MAX_NAME_LEN + 2, 0);
- val = le16_to_cpu(*(__le16 *) name);
- if (len > MAX_NAME_LEN + 2 || len < 0 || val > MAX_NAME_LEN)
- return -EOPNOTSUPP;
-
- name[val + 2] = '\0';
- data->length = val + 1;
- memcpy(nickname, name + 2, val + 1);
-
- return 0;
-}
-
-
-static int prism2_ioctl_siwfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* freq => chan. */
- if (freq->e == 1 &&
- freq->m / 100000 >= freq_list[0] &&
- freq->m / 100000 <= freq_list[FREQ_COUNT - 1]) {
- int ch;
- int fr = freq->m / 100000;
- for (ch = 0; ch < FREQ_COUNT; ch++) {
- if (fr == freq_list[ch]) {
- freq->e = 0;
- freq->m = ch + 1;
- break;
- }
- }
- }
-
- if (freq->e != 0 || freq->m < 1 || freq->m > FREQ_COUNT ||
- !(local->channel_mask & (1 << (freq->m - 1))))
- return -EINVAL;
-
- local->channel = freq->m; /* channel is used in prism2_setup_rids() */
- if (hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct hostap_interface *iface;
- local_info_t *local;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_CURRENTCHANNEL, &val, 2, 1) <
- 0)
- return -EINVAL;
-
- le16_to_cpus(&val);
- if (val < 1 || val > FREQ_COUNT)
- return -EINVAL;
-
- freq->m = freq_list[val - 1] * 100000;
- freq->e = 1;
-
- return 0;
-}
-
-
-static void hostap_monitor_set_type(local_info_t *local)
-{
- struct net_device *dev = local->ddev;
-
- if (dev == NULL)
- return;
-
- if (local->monitor_type == PRISM2_MONITOR_PRISM ||
- local->monitor_type == PRISM2_MONITOR_CAPHDR) {
- dev->type = ARPHRD_IEEE80211_PRISM;
- } else if (local->monitor_type == PRISM2_MONITOR_RADIOTAP) {
- dev->type = ARPHRD_IEEE80211_RADIOTAP;
- } else {
- dev->type = ARPHRD_IEEE80211;
- }
-}
-
-
-static int prism2_ioctl_siwessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *ssid)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (iface->type == HOSTAP_INTERFACE_WDS)
- return -EOPNOTSUPP;
-
- if (data->flags == 0)
- ssid[0] = '\0'; /* ANY */
-
- if (local->iw_mode == IW_MODE_MASTER && ssid[0] == '\0') {
- /* Setting SSID to empty string seems to kill the card in
- * Host AP mode */
- printk(KERN_DEBUG "%s: Host AP mode does not support "
- "'Any' essid\n", dev->name);
- return -EINVAL;
- }
-
- memcpy(local->essid, ssid, data->length);
- local->essid[data->length] = '\0';
-
- if ((!local->fw_ap &&
- hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, local->essid))
- || hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, local->essid) ||
- local->func->reset_port(dev))
- return -EINVAL;
-
- return 0;
-}
-
-static int prism2_ioctl_giwessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *essid)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (iface->type == HOSTAP_INTERFACE_WDS)
- return -EOPNOTSUPP;
-
- data->flags = 1; /* active */
- if (local->iw_mode == IW_MODE_MASTER) {
- data->length = strlen(local->essid);
- memcpy(essid, local->essid, IW_ESSID_MAX_SIZE);
- } else {
- int len;
- char ssid[MAX_SSID_LEN + 2];
- memset(ssid, 0, sizeof(ssid));
- len = local->func->get_rid(dev, HFA384X_RID_CURRENTSSID,
- &ssid, MAX_SSID_LEN + 2, 0);
- val = le16_to_cpu(*(__le16 *) ssid);
- if (len > MAX_SSID_LEN + 2 || len < 0 || val > MAX_SSID_LEN) {
- return -EOPNOTSUPP;
- }
- data->length = val;
- memcpy(essid, ssid + 2, IW_ESSID_MAX_SIZE);
- }
-
- return 0;
-}
-
-
-static int prism2_ioctl_giwrange(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- struct iw_range *range = (struct iw_range *) extra;
- u8 rates[10];
- u16 val;
- int i, len, over2;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- data->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
-
- /* TODO: could fill num_txpower and txpower array with
- * something; however, there are 128 different values.. */
-
- range->txpower_capa = IW_TXPOW_DBM;
-
- if (local->iw_mode == IW_MODE_INFRA || local->iw_mode == IW_MODE_ADHOC)
- {
- range->min_pmp = 1 * 1024;
- range->max_pmp = 65535 * 1024;
- range->min_pmt = 1 * 1024;
- range->max_pmt = 1000 * 1024;
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT |
- IW_POWER_UNICAST_R | IW_POWER_ALL_R;
- }
-
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
- range->retry_capa = IW_RETRY_LIMIT;
- range->retry_flags = IW_RETRY_LIMIT;
- range->min_retry = 0;
- range->max_retry = 255;
-
- range->num_channels = FREQ_COUNT;
-
- val = 0;
- for (i = 0; i < FREQ_COUNT; i++) {
- if (local->channel_mask & (1 << i)) {
- range->freq[val].i = i + 1;
- range->freq[val].m = freq_list[i] * 100000;
- range->freq[val].e = 1;
- val++;
- }
- if (val == IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = val;
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
- range->max_qual.qual = 70; /* what is correct max? This was not
- * documented exactly. At least
- * 69 has been observed. */
- range->max_qual.level = 0; /* dB */
- range->max_qual.noise = 0; /* dB */
-
- /* What would be suitable values for "average/typical" qual? */
- range->avg_qual.qual = 20;
- range->avg_qual.level = -60;
- range->avg_qual.noise = -95;
- } else {
- range->max_qual.qual = 92; /* 0 .. 92 */
- range->max_qual.level = 154; /* 27 .. 154 */
- range->max_qual.noise = 154; /* 27 .. 154 */
- }
- range->sensitivity = 3;
-
- range->max_encoding_tokens = WEP_KEYS;
- range->num_encoding_sizes = 2;
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
-
- over2 = 0;
- len = prism2_get_datarates(dev, rates);
- range->num_bitrates = 0;
- for (i = 0; i < len; i++) {
- if (range->num_bitrates < IW_MAX_BITRATES) {
- range->bitrate[range->num_bitrates] =
- rates[i] * 500000;
- range->num_bitrates++;
- }
- if (rates[i] == 0x0b || rates[i] == 0x16)
- over2 = 1;
- }
- /* estimated maximum TCP throughput values (bps) */
- range->throughput = over2 ? 5500000 : 1500000;
-
- range->min_rts = 0;
- range->max_rts = 2347;
- range->min_frag = 256;
- range->max_frag = 2346;
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
- range->event_capa[4] = (IW_EVENT_CAPA_MASK(IWEVTXDROP) |
- IW_EVENT_CAPA_MASK(IWEVCUSTOM) |
- IW_EVENT_CAPA_MASK(IWEVREGISTERED) |
- IW_EVENT_CAPA_MASK(IWEVEXPIRED));
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
- range->scan_capa = IW_SCAN_CAPA_ESSID;
-
- return 0;
-}
-
-
-static int hostap_monitor_mode_enable(local_info_t *local)
-{
- struct net_device *dev = local->dev;
-
- printk(KERN_DEBUG "Enabling monitor mode\n");
- hostap_monitor_set_type(local);
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- HFA384X_PORTTYPE_PSEUDO_IBSS)) {
- printk(KERN_DEBUG "Port type setting for monitor mode "
- "failed\n");
- return -EOPNOTSUPP;
- }
-
- /* Host decrypt is needed to get the IV and ICV fields;
- * however, monitor mode seems to remove WEP flag from frame
- * control field */
- if (hostap_set_word(dev, HFA384X_RID_CNFWEPFLAGS,
- HFA384X_WEPFLAGS_HOSTENCRYPT |
- HFA384X_WEPFLAGS_HOSTDECRYPT)) {
- printk(KERN_DEBUG "WEP flags setting failed\n");
- return -EOPNOTSUPP;
- }
-
- if (local->func->reset_port(dev) ||
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_MONITOR << 8),
- 0, NULL, NULL)) {
- printk(KERN_DEBUG "Setting monitor mode failed\n");
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-
-static int hostap_monitor_mode_disable(local_info_t *local)
-{
- struct net_device *dev = local->ddev;
-
- if (dev == NULL)
- return -1;
-
- printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
- dev->type = ARPHRD_ETHER;
-
- if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_STOP << 8),
- 0, NULL, NULL))
- return -1;
- return hostap_set_encryption(local);
-}
-
-
-static int prism2_ioctl_siwmode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct hostap_interface *iface;
- local_info_t *local;
- int double_reset = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (*mode != IW_MODE_ADHOC && *mode != IW_MODE_INFRA &&
- *mode != IW_MODE_MASTER && *mode != IW_MODE_REPEAT &&
- *mode != IW_MODE_MONITOR)
- return -EOPNOTSUPP;
-
-#ifdef PRISM2_NO_STATION_MODES
- if (*mode == IW_MODE_ADHOC || *mode == IW_MODE_INFRA)
- return -EOPNOTSUPP;
-#endif /* PRISM2_NO_STATION_MODES */
-
- if (*mode == local->iw_mode)
- return 0;
-
- if (*mode == IW_MODE_MASTER && local->essid[0] == '\0') {
- printk(KERN_WARNING "%s: empty SSID not allowed in Master "
- "mode\n", dev->name);
- return -EINVAL;
- }
-
- if (local->iw_mode == IW_MODE_MONITOR)
- hostap_monitor_mode_disable(local);
-
- if ((local->iw_mode == IW_MODE_ADHOC ||
- local->iw_mode == IW_MODE_MONITOR) && *mode == IW_MODE_MASTER) {
- /* There seems to be a firmware bug in at least STA f/w v1.5.6
- * that leaves beacon frames to use IBSS type when moving from
- * IBSS to Host AP mode. Doing double Port0 reset seems to be
- * enough to workaround this. */
- double_reset = 1;
- }
-
- printk(KERN_DEBUG "prism2: %s: operating mode changed "
- "%d -> %d\n", dev->name, local->iw_mode, *mode);
- local->iw_mode = *mode;
-
- if (local->iw_mode == IW_MODE_MONITOR)
- hostap_monitor_mode_enable(local);
- else if (local->iw_mode == IW_MODE_MASTER && !local->host_encrypt &&
- !local->fw_encrypt_ok) {
- printk(KERN_DEBUG "%s: defaulting to host-based encryption as "
- "a workaround for firmware bug in Host AP mode WEP\n",
- dev->name);
- local->host_encrypt = 1;
- }
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- hostap_get_porttype(local)))
- return -EOPNOTSUPP;
-
- if (local->func->reset_port(dev))
- return -EINVAL;
- if (double_reset && local->func->reset_port(dev))
- return -EINVAL;
-
- if (local->iw_mode != IW_MODE_INFRA && local->iw_mode != IW_MODE_ADHOC)
- {
- /* netif_carrier is used only in client modes for now, so make
- * sure carrier is on when moving to non-client modes. */
- netif_carrier_on(local->dev);
- netif_carrier_on(local->ddev);
- }
- return 0;
-}
-
-
-static int prism2_ioctl_giwmode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- switch (iface->type) {
- case HOSTAP_INTERFACE_STA:
- *mode = IW_MODE_INFRA;
- break;
- case HOSTAP_INTERFACE_WDS:
- *mode = IW_MODE_REPEAT;
- break;
- default:
- *mode = local->iw_mode;
- break;
- }
- return 0;
-}
-
-
-static int prism2_ioctl_siwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *wrq = &wrqu->power;
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- int ret = 0;
-
- if (wrq->disabled)
- return hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 0);
-
- switch (wrq->flags & IW_POWER_MODE) {
- case IW_POWER_UNICAST_R:
- ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 0);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- break;
- case IW_POWER_ALL_R:
- ret = hostap_set_word(dev, HFA384X_RID_CNFMULTICASTRECEIVE, 1);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- break;
- case IW_POWER_ON:
- break;
- default:
- return -EINVAL;
- }
-
- if (wrq->flags & IW_POWER_TIMEOUT) {
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMHOLDOVERDURATION,
- wrq->value / 1024);
- if (ret)
- return ret;
- }
- if (wrq->flags & IW_POWER_PERIOD) {
- ret = hostap_set_word(dev, HFA384X_RID_CNFPMENABLED, 1);
- if (ret)
- return ret;
- ret = hostap_set_word(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
- wrq->value / 1024);
- if (ret)
- return ret;
- }
-
- return ret;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_giwpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->power;
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 enable, mcast;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_CNFPMENABLED, &enable, 2, 1)
- < 0)
- return -EINVAL;
-
- if (!le16_to_cpu(enable)) {
- rrq->disabled = 1;
- return 0;
- }
-
- rrq->disabled = 0;
-
- if ((rrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- __le16 timeout;
- if (local->func->get_rid(dev,
- HFA384X_RID_CNFPMHOLDOVERDURATION,
- &timeout, 2, 1) < 0)
- return -EINVAL;
-
- rrq->flags = IW_POWER_TIMEOUT;
- rrq->value = le16_to_cpu(timeout) * 1024;
- } else {
- __le16 period;
- if (local->func->get_rid(dev, HFA384X_RID_CNFMAXSLEEPDURATION,
- &period, 2, 1) < 0)
- return -EINVAL;
-
- rrq->flags = IW_POWER_PERIOD;
- rrq->value = le16_to_cpu(period) * 1024;
- }
-
- if (local->func->get_rid(dev, HFA384X_RID_CNFMULTICASTRECEIVE, &mcast,
- 2, 1) < 0)
- return -EINVAL;
-
- if (le16_to_cpu(mcast))
- rrq->flags |= IW_POWER_ALL_R;
- else
- rrq->flags |= IW_POWER_UNICAST_R;
-
- return 0;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_siwretry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->retry;
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rrq->disabled)
- return -EINVAL;
-
- /* setting retry limits is not supported with the current station
- * firmware code; simulate this with alternative retry count for now */
- if (rrq->flags == IW_RETRY_LIMIT) {
- if (rrq->value < 0) {
- /* disable manual retry count setting and use firmware
- * defaults */
- local->manual_retry_count = -1;
- local->tx_control &= ~HFA384X_TX_CTRL_ALT_RTRY;
- } else {
- if (hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT,
- rrq->value)) {
- printk(KERN_DEBUG "%s: Alternate retry count "
- "setting to %d failed\n",
- dev->name, rrq->value);
- return -EOPNOTSUPP;
- }
-
- local->manual_retry_count = rrq->value;
- local->tx_control |= HFA384X_TX_CTRL_ALT_RTRY;
- }
- return 0;
- }
-
- return -EOPNOTSUPP;
-
-#if 0
- /* what could be done, if firmware would support this.. */
-
- if (rrq->flags & IW_RETRY_LIMIT) {
- if (rrq->flags & IW_RETRY_LONG)
- HFA384X_RID_LONGRETRYLIMIT = rrq->value;
- else if (rrq->flags & IW_RETRY_SHORT)
- HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
- else {
- HFA384X_RID_LONGRETRYLIMIT = rrq->value;
- HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
- }
-
- }
-
- if (rrq->flags & IW_RETRY_LIFETIME) {
- HFA384X_RID_MAXTRANSMITLIFETIME = rrq->value / 1024;
- }
-
- return 0;
-#endif /* 0 */
-}
-
-static int prism2_ioctl_giwretry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->retry;
- struct hostap_interface *iface;
- local_info_t *local;
- __le16 shortretry, longretry, lifetime, altretry;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->get_rid(dev, HFA384X_RID_SHORTRETRYLIMIT, &shortretry,
- 2, 1) < 0 ||
- local->func->get_rid(dev, HFA384X_RID_LONGRETRYLIMIT, &longretry,
- 2, 1) < 0 ||
- local->func->get_rid(dev, HFA384X_RID_MAXTRANSMITLIFETIME,
- &lifetime, 2, 1) < 0)
- return -EINVAL;
-
- rrq->disabled = 0;
-
- if ((rrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- rrq->flags = IW_RETRY_LIFETIME;
- rrq->value = le16_to_cpu(lifetime) * 1024;
- } else {
- if (local->manual_retry_count >= 0) {
- rrq->flags = IW_RETRY_LIMIT;
- if (local->func->get_rid(dev,
- HFA384X_RID_CNFALTRETRYCOUNT,
- &altretry, 2, 1) >= 0)
- rrq->value = le16_to_cpu(altretry);
- else
- rrq->value = local->manual_retry_count;
- } else if ((rrq->flags & IW_RETRY_LONG)) {
- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- rrq->value = le16_to_cpu(longretry);
- } else {
- rrq->flags = IW_RETRY_LIMIT;
- rrq->value = le16_to_cpu(shortretry);
- if (shortretry != longretry)
- rrq->flags |= IW_RETRY_SHORT;
- }
- }
- return 0;
-}
-
-
-/* Note! This TX power controlling is experimental and should not be used in
- * production use. It just sets raw power register and does not use any kind of
- * feedback information from the measured TX power (CR58). This is now
- * commented out to make sure that it is not used by accident. TX power
- * configuration will be enabled again after proper algorithm using feedback
- * has been implemented. */
-
-#ifdef RAW_TXPOWER_SETTING
-/* Map HFA386x's CR31 to and from dBm with some sort of ad hoc mapping..
- * This version assumes following mapping:
- * CR31 is 7-bit value with -64 to +63 range.
- * -64 is mapped into +20dBm and +63 into -43dBm.
- * This is certainly not an exact mapping for every card, but at least
- * increasing dBm value should correspond to increasing TX power.
- */
-
-static int prism2_txpower_hfa386x_to_dBm(u16 val)
-{
- signed char tmp;
-
- if (val > 255)
- val = 255;
-
- tmp = val;
- tmp >>= 2;
-
- return -12 - tmp;
-}
-
-static u16 prism2_txpower_dBm_to_hfa386x(int val)
-{
- signed char tmp;
-
- if (val > 20)
- return 128;
- else if (val < -43)
- return 127;
-
- tmp = val;
- tmp = -12 - tmp;
- tmp <<= 2;
-
- return (unsigned char) tmp;
-}
-#endif /* RAW_TXPOWER_SETTING */
-
-
-static int prism2_ioctl_siwtxpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->txpower;
- struct hostap_interface *iface;
- local_info_t *local;
-#ifdef RAW_TXPOWER_SETTING
- char *tmp;
-#endif
- u16 val;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (rrq->disabled) {
- if (local->txpower_type != PRISM2_TXPOWER_OFF) {
- val = 0xff; /* use all standby and sleep modes */
- ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_A_D_TEST_MODES2,
- &val, NULL);
- printk(KERN_DEBUG "%s: Turning radio off: %s\n",
- dev->name, ret ? "failed" : "OK");
- local->txpower_type = PRISM2_TXPOWER_OFF;
- }
- return (ret ? -EOPNOTSUPP : 0);
- }
-
- if (local->txpower_type == PRISM2_TXPOWER_OFF) {
- val = 0; /* disable all standby and sleep modes */
- ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_A_D_TEST_MODES2, &val, NULL);
- printk(KERN_DEBUG "%s: Turning radio on: %s\n",
- dev->name, ret ? "failed" : "OK");
- local->txpower_type = PRISM2_TXPOWER_UNKNOWN;
- }
-
-#ifdef RAW_TXPOWER_SETTING
- if (!rrq->fixed && local->txpower_type != PRISM2_TXPOWER_AUTO) {
- printk(KERN_DEBUG "Setting ALC on\n");
- val = HFA384X_TEST_CFG_BIT_ALC;
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CFG_BITS << 8), 1, &val, NULL);
- local->txpower_type = PRISM2_TXPOWER_AUTO;
- return 0;
- }
-
- if (local->txpower_type != PRISM2_TXPOWER_FIXED) {
- printk(KERN_DEBUG "Setting ALC off\n");
- val = HFA384X_TEST_CFG_BIT_ALC;
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL);
- local->txpower_type = PRISM2_TXPOWER_FIXED;
- }
-
- if (rrq->flags == IW_TXPOW_DBM)
- tmp = "dBm";
- else if (rrq->flags == IW_TXPOW_MWATT)
- tmp = "mW";
- else
- tmp = "UNKNOWN";
- printk(KERN_DEBUG "Setting TX power to %d %s\n", rrq->value, tmp);
-
- if (rrq->flags != IW_TXPOW_DBM) {
- printk("SIOCSIWTXPOW with mW is not supported; use dBm\n");
- return -EOPNOTSUPP;
- }
-
- local->txpower = rrq->value;
- val = prism2_txpower_dBm_to_hfa386x(local->txpower);
- if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_MANUAL_TX_POWER, &val, NULL))
- ret = -EOPNOTSUPP;
-#else /* RAW_TXPOWER_SETTING */
- if (rrq->fixed)
- ret = -EOPNOTSUPP;
-#endif /* RAW_TXPOWER_SETTING */
-
- return ret;
-}
-
-static int prism2_ioctl_giwtxpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
-#ifdef RAW_TXPOWER_SETTING
- struct iw_param *rrq = &wrqu->txpower;
- struct hostap_interface *iface;
- local_info_t *local;
- u16 resp0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- rrq->flags = IW_TXPOW_DBM;
- rrq->disabled = 0;
- rrq->fixed = 0;
-
- if (local->txpower_type == PRISM2_TXPOWER_AUTO) {
- if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF,
- HFA386X_CR_MANUAL_TX_POWER,
- NULL, &resp0) == 0) {
- rrq->value = prism2_txpower_hfa386x_to_dBm(resp0);
- } else {
- /* Could not get real txpower; guess 15 dBm */
- rrq->value = 15;
- }
- } else if (local->txpower_type == PRISM2_TXPOWER_OFF) {
- rrq->value = 0;
- rrq->disabled = 1;
- } else if (local->txpower_type == PRISM2_TXPOWER_FIXED) {
- rrq->value = local->txpower;
- rrq->fixed = 1;
- } else {
- printk("SIOCGIWTXPOW - unknown txpower_type=%d\n",
- local->txpower_type);
- }
- return 0;
-#else /* RAW_TXPOWER_SETTING */
- return -EOPNOTSUPP;
-#endif /* RAW_TXPOWER_SETTING */
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-
-/* HostScan request works with and without host_roaming mode. In addition, it
- * does not break current association. However, it requires newer station
- * firmware version (>= 1.3.1) than scan request. */
-static int prism2_request_hostscan(struct net_device *dev,
- u8 *ssid, u8 ssid_len)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_hostscan_request scan_req;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(local->channel_mask &
- local->scan_channel_mask);
- scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS);
- if (ssid) {
- if (ssid_len > 32)
- return -EINVAL;
- scan_req.target_ssid_len = cpu_to_le16(ssid_len);
- memcpy(scan_req.target_ssid, ssid, ssid_len);
- }
-
- if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
- sizeof(scan_req))) {
- printk(KERN_DEBUG "%s: HOSTSCAN failed\n", dev->name);
- return -EINVAL;
- }
- return 0;
-}
-
-
-static int prism2_request_scan(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_scan_request scan_req;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(local->channel_mask &
- local->scan_channel_mask);
- scan_req.txrate = cpu_to_le16(HFA384X_RATES_1MBPS);
-
- /* FIX:
- * It seems to be enough to set roaming mode for a short moment to
- * host-based and then setup scanrequest data and return the mode to
- * firmware-based.
- *
- * Master mode would need to drop to Managed mode for a short while
- * to make scanning work.. Or sweep through the different channels and
- * use passive scan based on beacons. */
-
- if (!local->host_roaming)
- hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
- HFA384X_ROAMING_HOST);
-
- if (local->func->set_rid(dev, HFA384X_RID_SCANREQUEST, &scan_req,
- sizeof(scan_req))) {
- printk(KERN_DEBUG "SCANREQUEST failed\n");
- ret = -EINVAL;
- }
-
- if (!local->host_roaming)
- hostap_set_word(dev, HFA384X_RID_CNFROAMINGMODE,
- HFA384X_ROAMING_FIRMWARE);
-
- return ret;
-}
-
-#else /* !PRISM2_NO_STATION_MODES */
-
-static inline int prism2_request_hostscan(struct net_device *dev,
- u8 *ssid, u8 ssid_len)
-{
- return -EOPNOTSUPP;
-}
-
-
-static inline int prism2_request_scan(struct net_device *dev)
-{
- return -EOPNOTSUPP;
-}
-
-#endif /* !PRISM2_NO_STATION_MODES */
-
-
-static int prism2_ioctl_siwscan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret;
- u8 *ssid = NULL, ssid_len = 0;
- struct iw_scan_req *req = (struct iw_scan_req *) extra;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (data->length < sizeof(struct iw_scan_req))
- req = NULL;
-
- if (local->iw_mode == IW_MODE_MASTER) {
- /* In master mode, we just return the results of our local
- * tables, so we don't need to start anything...
- * Jean II */
- data->length = 0;
- return 0;
- }
-
- if (!local->dev_enabled)
- return -ENETDOWN;
-
- if (req && data->flags & IW_SCAN_THIS_ESSID) {
- ssid = req->essid;
- ssid_len = req->essid_len;
-
- if (ssid_len &&
- ((local->iw_mode != IW_MODE_INFRA &&
- local->iw_mode != IW_MODE_ADHOC) ||
- (local->sta_fw_ver < PRISM2_FW_VER(1,3,1))))
- return -EOPNOTSUPP;
- }
-
- if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1))
- ret = prism2_request_hostscan(dev, ssid, ssid_len);
- else
- ret = prism2_request_scan(dev);
-
- if (ret == 0)
- local->scan_timestamp = jiffies;
-
- /* Could inquire F101, F103 or wait for SIOCGIWSCAN and read RID */
-
- return ret;
-}
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static char * __prism2_translate_scan(local_info_t *local,
- struct iw_request_info *info,
- struct hfa384x_hostscan_result *scan,
- struct hostap_bss_info *bss,
- char *current_ev, char *end_buf)
-{
- int i, chan;
- struct iw_event iwe;
- char *current_val;
- u16 capabilities;
- u8 *pos;
- u8 *ssid, *bssid;
- size_t ssid_len;
- char *buf;
-
- if (bss) {
- ssid = bss->ssid;
- ssid_len = bss->ssid_len;
- bssid = bss->bssid;
- } else {
- ssid = scan->ssid;
- ssid_len = le16_to_cpu(scan->ssid_len);
- bssid = scan->bssid;
- }
- if (ssid_len > 32)
- ssid_len = 32;
-
- /* First entry *MUST* be the AP MAC address */
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
- IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = ssid_len;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, ssid);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWMODE;
- if (bss) {
- capabilities = bss->capab_info;
- } else {
- capabilities = le16_to_cpu(scan->capability);
- }
- if (capabilities & (WLAN_CAPABILITY_ESS |
- WLAN_CAPABILITY_IBSS)) {
- if (capabilities & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWFREQ;
- if (scan) {
- chan = le16_to_cpu(scan->chid);
- } else if (bss) {
- chan = bss->chan;
- } else {
- chan = 0;
- }
-
- if (chan > 0) {
- iwe.u.freq.m = freq_list[chan - 1] * 100000;
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
- }
-
- if (scan) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVQUAL;
- if (local->last_scan_type == PRISM2_HOSTSCAN) {
- iwe.u.qual.level = le16_to_cpu(scan->sl);
- iwe.u.qual.noise = le16_to_cpu(scan->anl);
- } else {
- iwe.u.qual.level =
- HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->sl));
- iwe.u.qual.noise =
- HFA384X_LEVEL_TO_dBm(le16_to_cpu(scan->anl));
- }
- iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_NOISE_UPDATED
- | IW_QUAL_QUAL_INVALID
- | IW_QUAL_DBM;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, "");
-
- /* TODO: add SuppRates into BSS table */
- if (scan) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = SIOCGIWRATE;
- current_val = current_ev + iwe_stream_lcp_len(info);
- pos = scan->sup_rates;
- for (i = 0; i < sizeof(scan->sup_rates); i++) {
- if (pos[i] == 0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((pos[i] & 0x7f) * 500000);
- current_val = iwe_stream_add_value(
- info, current_ev, current_val, end_buf, &iwe,
- IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
- }
-
- /* TODO: add BeaconInt,resp_rate,atim into BSS table */
- buf = kmalloc(MAX_WPA_IE_LEN * 2 + 30, GFP_ATOMIC);
- if (buf && scan) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "bcn_int=%d", le16_to_cpu(scan->beacon_interval));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
-
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "resp_rate=%d", le16_to_cpu(scan->rate));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
-
- if (local->last_scan_type == PRISM2_HOSTSCAN &&
- (capabilities & WLAN_CAPABILITY_IBSS)) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "atim=%d", le16_to_cpu(scan->atim));
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev,
- end_buf, &iwe, buf);
- }
- }
- kfree(buf);
-
- if (bss && bss->wpa_ie_len > 0 && bss->wpa_ie_len <= MAX_WPA_IE_LEN) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = bss->wpa_ie_len;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->wpa_ie);
- }
-
- if (bss && bss->rsn_ie_len > 0 && bss->rsn_ie_len <= MAX_WPA_IE_LEN) {
- memset(&iwe, 0, sizeof(iwe));
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = bss->rsn_ie_len;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->rsn_ie);
- }
-
- return current_ev;
-}
-
-
-/* Translate scan data returned from the card to a card independent
- * format that the Wireless Tools will understand - Jean II */
-static inline int prism2_translate_scan(local_info_t *local,
- struct iw_request_info *info,
- char *buffer, int buflen)
-{
- struct hfa384x_hostscan_result *scan;
- int entry;
- char *current_ev = buffer;
- char *end_buf = buffer + buflen;
- struct list_head *ptr;
-
- spin_lock_bh(&local->lock);
-
- list_for_each(ptr, &local->bss_list) {
- struct hostap_bss_info *bss;
- bss = list_entry(ptr, struct hostap_bss_info, list);
- bss->included = 0;
- }
-
- for (entry = 0; entry < local->last_scan_results_count; entry++) {
- int found = 0;
- scan = &local->last_scan_results[entry];
-
- /* Report every SSID if the AP is using multiple SSIDs. If no
- * BSS record is found (e.g., when WPA mode is disabled),
- * report the AP once. */
- list_for_each(ptr, &local->bss_list) {
- struct hostap_bss_info *bss;
- bss = list_entry(ptr, struct hostap_bss_info, list);
- if (ether_addr_equal(bss->bssid, scan->bssid)) {
- bss->included = 1;
- current_ev = __prism2_translate_scan(
- local, info, scan, bss, current_ev,
- end_buf);
- found++;
- }
- }
- if (!found) {
- current_ev = __prism2_translate_scan(
- local, info, scan, NULL, current_ev, end_buf);
- }
- /* Check if there is space for one more entry */
- if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a bigger buffer */
- spin_unlock_bh(&local->lock);
- return -E2BIG;
- }
- }
-
- /* Prism2 firmware has limits (32 at least in some versions) for number
- * of BSSes in scan results. Extend this limit by using local BSS list.
- */
- list_for_each(ptr, &local->bss_list) {
- struct hostap_bss_info *bss;
- bss = list_entry(ptr, struct hostap_bss_info, list);
- if (bss->included)
- continue;
- current_ev = __prism2_translate_scan(local, info, NULL, bss,
- current_ev, end_buf);
- /* Check if there is space for one more entry */
- if ((end_buf - current_ev) <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a bigger buffer */
- spin_unlock_bh(&local->lock);
- return -E2BIG;
- }
- }
-
- spin_unlock_bh(&local->lock);
-
- return current_ev - buffer;
-}
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-static inline int prism2_ioctl_giwscan_sta(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *data, char *extra)
-{
-#ifdef PRISM2_NO_STATION_MODES
- return -EOPNOTSUPP;
-#else /* PRISM2_NO_STATION_MODES */
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- /* Wait until the scan is finished. We can probably do better
- * than that - Jean II */
- if (local->scan_timestamp &&
- time_before(jiffies, local->scan_timestamp + 3 * HZ)) {
- /* Important note : we don't want to block the caller
- * until results are ready for various reasons.
- * First, managing wait queues is complex and racy
- * (there may be multiple simultaneous callers).
- * Second, we grab some rtnetlink lock before coming
- * here (in dev_ioctl()).
- * Third, the caller can wait on the Wireless Event
- * - Jean II */
- return -EAGAIN;
- }
- local->scan_timestamp = 0;
-
- res = prism2_translate_scan(local, info, extra, data->length);
-
- if (res >= 0) {
- data->length = res;
- return 0;
- } else {
- data->length = 0;
- return res;
- }
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_giwscan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface;
- local_info_t *local;
- int res;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->iw_mode == IW_MODE_MASTER) {
- /* In MASTER mode, it doesn't make sense to go around
- * scanning the frequencies and make the stations we serve
- * wait when what the user is really interested about is the
- * list of stations and access points we are talking to.
- * So, just extract results from our cache...
- * Jean II */
-
- /* Translate to WE format */
- res = prism2_ap_translate_scan(dev, info, extra);
- if (res >= 0) {
- printk(KERN_DEBUG "Scan result translation succeeded "
- "(length=%d)\n", res);
- data->length = res;
- return 0;
- } else {
- printk(KERN_DEBUG
- "Scan result translation failed (res=%d)\n",
- res);
- data->length = 0;
- return res;
- }
- } else {
- /* Station mode */
- return prism2_ioctl_giwscan_sta(dev, info, data, extra);
- }
-}
-
-
-static const struct iw_priv_args prism2_priv[] = {
- { PRISM2_IOCTL_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor" },
- { PRISM2_IOCTL_READMIF,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "readmif" },
- { PRISM2_IOCTL_WRITEMIF,
- IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 2, 0, "writemif" },
- { PRISM2_IOCTL_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "reset" },
- { PRISM2_IOCTL_INQUIRE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "inquire" },
- { PRISM2_IOCTL_SET_RID_WORD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "set_rid_word" },
- { PRISM2_IOCTL_MACCMD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "maccmd" },
- { PRISM2_IOCTL_WDS_ADD,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_add" },
- { PRISM2_IOCTL_WDS_DEL,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "wds_del" },
- { PRISM2_IOCTL_ADDMAC,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "addmac" },
- { PRISM2_IOCTL_DELMAC,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "delmac" },
- { PRISM2_IOCTL_KICKMAC,
- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac" },
- /* --- raw access to sub-ioctls --- */
- { PRISM2_IOCTL_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "prism2_param" },
- { PRISM2_IOCTL_GET_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprism2_param" },
- /* --- sub-ioctls handlers --- */
- { PRISM2_IOCTL_PRISM2_PARAM,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
- { PRISM2_IOCTL_GET_PRISM2_PARAM,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
- /* --- sub-ioctls definitions --- */
- { PRISM2_PARAM_TXRATECTRL,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "txratectrl" },
- { PRISM2_PARAM_TXRATECTRL,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettxratectrl" },
- { PRISM2_PARAM_BEACON_INT,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beacon_int" },
- { PRISM2_PARAM_BEACON_INT,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbeacon_int" },
-#ifndef PRISM2_NO_STATION_MODES
- { PRISM2_PARAM_PSEUDO_IBSS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "pseudo_ibss" },
- { PRISM2_PARAM_PSEUDO_IBSS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpseudo_ibss" },
-#endif /* PRISM2_NO_STATION_MODES */
- { PRISM2_PARAM_ALC,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "alc" },
- { PRISM2_PARAM_ALC,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getalc" },
- { PRISM2_PARAM_DUMP,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dump" },
- { PRISM2_PARAM_DUMP,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdump" },
- { PRISM2_PARAM_OTHER_AP_POLICY,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "other_ap_policy" },
- { PRISM2_PARAM_OTHER_AP_POLICY,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getother_ap_pol" },
- { PRISM2_PARAM_AP_MAX_INACTIVITY,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_inactivity" },
- { PRISM2_PARAM_AP_MAX_INACTIVITY,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_inactivi" },
- { PRISM2_PARAM_AP_BRIDGE_PACKETS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bridge_packets" },
- { PRISM2_PARAM_AP_BRIDGE_PACKETS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbridge_packe" },
- { PRISM2_PARAM_DTIM_PERIOD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dtim_period" },
- { PRISM2_PARAM_DTIM_PERIOD,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdtim_period" },
- { PRISM2_PARAM_AP_NULLFUNC_ACK,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "nullfunc_ack" },
- { PRISM2_PARAM_AP_NULLFUNC_ACK,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getnullfunc_ack" },
- { PRISM2_PARAM_MAX_WDS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "max_wds" },
- { PRISM2_PARAM_MAX_WDS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmax_wds" },
- { PRISM2_PARAM_AP_AUTOM_AP_WDS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "autom_ap_wds" },
- { PRISM2_PARAM_AP_AUTOM_AP_WDS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getautom_ap_wds" },
- { PRISM2_PARAM_AP_AUTH_ALGS,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_auth_algs" },
- { PRISM2_PARAM_AP_AUTH_ALGS,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_auth_algs" },
- { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "allow_fcserr" },
- { PRISM2_PARAM_MONITOR_ALLOW_FCSERR,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getallow_fcserr" },
- { PRISM2_PARAM_HOST_ENCRYPT,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_encrypt" },
- { PRISM2_PARAM_HOST_ENCRYPT,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_encrypt" },
- { PRISM2_PARAM_HOST_DECRYPT,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_decrypt" },
- { PRISM2_PARAM_HOST_DECRYPT,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_decrypt" },
-#ifndef PRISM2_NO_STATION_MODES
- { PRISM2_PARAM_HOST_ROAMING,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "host_roaming" },
- { PRISM2_PARAM_HOST_ROAMING,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethost_roaming" },
-#endif /* PRISM2_NO_STATION_MODES */
- { PRISM2_PARAM_BCRX_STA_KEY,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bcrx_sta_key" },
- { PRISM2_PARAM_BCRX_STA_KEY,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbcrx_sta_key" },
- { PRISM2_PARAM_IEEE_802_1X,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ieee_802_1x" },
- { PRISM2_PARAM_IEEE_802_1X,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getieee_802_1x" },
- { PRISM2_PARAM_ANTSEL_TX,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_tx" },
- { PRISM2_PARAM_ANTSEL_TX,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_tx" },
- { PRISM2_PARAM_ANTSEL_RX,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "antsel_rx" },
- { PRISM2_PARAM_ANTSEL_RX,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getantsel_rx" },
- { PRISM2_PARAM_MONITOR_TYPE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "monitor_type" },
- { PRISM2_PARAM_MONITOR_TYPE,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmonitor_type" },
- { PRISM2_PARAM_WDS_TYPE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wds_type" },
- { PRISM2_PARAM_WDS_TYPE,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwds_type" },
- { PRISM2_PARAM_HOSTSCAN,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostscan" },
- { PRISM2_PARAM_HOSTSCAN,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostscan" },
- { PRISM2_PARAM_AP_SCAN,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ap_scan" },
- { PRISM2_PARAM_AP_SCAN,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getap_scan" },
- { PRISM2_PARAM_ENH_SEC,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "enh_sec" },
- { PRISM2_PARAM_ENH_SEC,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getenh_sec" },
-#ifdef PRISM2_IO_DEBUG
- { PRISM2_PARAM_IO_DEBUG,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "io_debug" },
- { PRISM2_PARAM_IO_DEBUG,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getio_debug" },
-#endif /* PRISM2_IO_DEBUG */
- { PRISM2_PARAM_BASIC_RATES,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "basic_rates" },
- { PRISM2_PARAM_BASIC_RATES,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getbasic_rates" },
- { PRISM2_PARAM_OPER_RATES,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" },
- { PRISM2_PARAM_OPER_RATES,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" },
- { PRISM2_PARAM_HOSTAPD,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" },
- { PRISM2_PARAM_HOSTAPD,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" },
- { PRISM2_PARAM_HOSTAPD_STA,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd_sta" },
- { PRISM2_PARAM_HOSTAPD_STA,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd_sta" },
- { PRISM2_PARAM_WPA,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wpa" },
- { PRISM2_PARAM_WPA,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwpa" },
- { PRISM2_PARAM_PRIVACY_INVOKED,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "privacy_invoked" },
- { PRISM2_PARAM_PRIVACY_INVOKED,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getprivacy_invo" },
- { PRISM2_PARAM_TKIP_COUNTERMEASURES,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "tkip_countermea" },
- { PRISM2_PARAM_TKIP_COUNTERMEASURES,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gettkip_counter" },
- { PRISM2_PARAM_DROP_UNENCRYPTED,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "drop_unencrypte" },
- { PRISM2_PARAM_DROP_UNENCRYPTED,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdrop_unencry" },
- { PRISM2_PARAM_SCAN_CHANNEL_MASK,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "scan_channels" },
- { PRISM2_PARAM_SCAN_CHANNEL_MASK,
- 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getscan_channel" },
-};
-
-
-static int prism2_ioctl_priv_inquire(struct net_device *dev, int *i)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->cmd(dev, HFA384X_CMDCODE_INQUIRE, *i, NULL, NULL))
- return -EOPNOTSUPP;
-
- return 0;
-}
-
-
-static int prism2_ioctl_priv_prism2_param(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *uwrq, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int *i = (int *) extra;
- int param = *i;
- int value = *(i + 1);
- int ret = 0;
- u16 val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- switch (param) {
- case PRISM2_PARAM_TXRATECTRL:
- local->fw_tx_rate_control = value;
- break;
-
- case PRISM2_PARAM_BEACON_INT:
- if (hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, value) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- else
- local->beacon_int = value;
- break;
-
-#ifndef PRISM2_NO_STATION_MODES
- case PRISM2_PARAM_PSEUDO_IBSS:
- if (value == local->pseudo_adhoc)
- break;
-
- if (value != 0 && value != 1) {
- ret = -EINVAL;
- break;
- }
-
- printk(KERN_DEBUG "prism2: %s: pseudo IBSS change %d -> %d\n",
- dev->name, local->pseudo_adhoc, value);
- local->pseudo_adhoc = value;
- if (local->iw_mode != IW_MODE_ADHOC)
- break;
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- hostap_get_porttype(local))) {
- ret = -EOPNOTSUPP;
- break;
- }
-
- if (local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-#endif /* PRISM2_NO_STATION_MODES */
-
- case PRISM2_PARAM_ALC:
- printk(KERN_DEBUG "%s: %s ALC\n", dev->name,
- value == 0 ? "Disabling" : "Enabling");
- val = HFA384X_TEST_CFG_BIT_ALC;
- local->func->cmd(dev, HFA384X_CMDCODE_TEST |
- (HFA384X_TEST_CFG_BITS << 8),
- value == 0 ? 0 : 1, &val, NULL);
- break;
-
- case PRISM2_PARAM_DUMP:
- local->frame_dump = value;
- break;
-
- case PRISM2_PARAM_OTHER_AP_POLICY:
- if (value < 0 || value > 3) {
- ret = -EINVAL;
- break;
- }
- if (local->ap != NULL)
- local->ap->ap_policy = value;
- break;
-
- case PRISM2_PARAM_AP_MAX_INACTIVITY:
- if (value < 0 || value > 7 * 24 * 60 * 60) {
- ret = -EINVAL;
- break;
- }
- if (local->ap != NULL)
- local->ap->max_inactivity = value * HZ;
- break;
-
- case PRISM2_PARAM_AP_BRIDGE_PACKETS:
- if (local->ap != NULL)
- local->ap->bridge_packets = value;
- break;
-
- case PRISM2_PARAM_DTIM_PERIOD:
- if (value < 0 || value > 65535) {
- ret = -EINVAL;
- break;
- }
- if (hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, value)
- || local->func->reset_port(dev))
- ret = -EINVAL;
- else
- local->dtim_period = value;
- break;
-
- case PRISM2_PARAM_AP_NULLFUNC_ACK:
- if (local->ap != NULL)
- local->ap->nullfunc_ack = value;
- break;
-
- case PRISM2_PARAM_MAX_WDS:
- local->wds_max_connections = value;
- break;
-
- case PRISM2_PARAM_AP_AUTOM_AP_WDS:
- if (local->ap != NULL) {
- if (!local->ap->autom_ap_wds && value) {
- /* add WDS link to all APs in STA table */
- hostap_add_wds_links(local);
- }
- local->ap->autom_ap_wds = value;
- }
- break;
-
- case PRISM2_PARAM_AP_AUTH_ALGS:
- local->auth_algs = value;
- if (hostap_set_auth_algs(local))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
- local->monitor_allow_fcserr = value;
- break;
-
- case PRISM2_PARAM_HOST_ENCRYPT:
- local->host_encrypt = value;
- if (hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_HOST_DECRYPT:
- local->host_decrypt = value;
- if (hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
-#ifndef PRISM2_NO_STATION_MODES
- case PRISM2_PARAM_HOST_ROAMING:
- if (value < 0 || value > 2) {
- ret = -EINVAL;
- break;
- }
- local->host_roaming = value;
- if (hostap_set_roaming(local) || local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-#endif /* PRISM2_NO_STATION_MODES */
-
- case PRISM2_PARAM_BCRX_STA_KEY:
- local->bcrx_sta_key = value;
- break;
-
- case PRISM2_PARAM_IEEE_802_1X:
- local->ieee_802_1x = value;
- break;
-
- case PRISM2_PARAM_ANTSEL_TX:
- if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
- ret = -EINVAL;
- break;
- }
- local->antsel_tx = value;
- hostap_set_antsel(local);
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- if (value < 0 || value > HOSTAP_ANTSEL_HIGH) {
- ret = -EINVAL;
- break;
- }
- local->antsel_rx = value;
- hostap_set_antsel(local);
- break;
-
- case PRISM2_PARAM_MONITOR_TYPE:
- if (value != PRISM2_MONITOR_80211 &&
- value != PRISM2_MONITOR_CAPHDR &&
- value != PRISM2_MONITOR_PRISM &&
- value != PRISM2_MONITOR_RADIOTAP) {
- ret = -EINVAL;
- break;
- }
- local->monitor_type = value;
- if (local->iw_mode == IW_MODE_MONITOR)
- hostap_monitor_set_type(local);
- break;
-
- case PRISM2_PARAM_WDS_TYPE:
- local->wds_type = value;
- break;
-
- case PRISM2_PARAM_HOSTSCAN:
- {
- struct hfa384x_hostscan_request scan_req;
- u16 rate;
-
- memset(&scan_req, 0, sizeof(scan_req));
- scan_req.channel_list = cpu_to_le16(0x3fff);
- switch (value) {
- case 1: rate = HFA384X_RATES_1MBPS; break;
- case 2: rate = HFA384X_RATES_2MBPS; break;
- case 3: rate = HFA384X_RATES_5MBPS; break;
- case 4: rate = HFA384X_RATES_11MBPS; break;
- default: rate = HFA384X_RATES_1MBPS; break;
- }
- scan_req.txrate = cpu_to_le16(rate);
- /* leave SSID empty to accept all SSIDs */
-
- if (local->iw_mode == IW_MODE_MASTER) {
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- HFA384X_PORTTYPE_BSS) ||
- local->func->reset_port(dev))
- printk(KERN_DEBUG "Leaving Host AP mode "
- "for HostScan failed\n");
- }
-
- if (local->func->set_rid(dev, HFA384X_RID_HOSTSCAN, &scan_req,
- sizeof(scan_req))) {
- printk(KERN_DEBUG "HOSTSCAN failed\n");
- ret = -EINVAL;
- }
- if (local->iw_mode == IW_MODE_MASTER) {
- wait_queue_entry_t __wait;
- init_waitqueue_entry(&__wait, current);
- add_wait_queue(&local->hostscan_wq, &__wait);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- if (signal_pending(current))
- ret = -EINTR;
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&local->hostscan_wq, &__wait);
-
- if (hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE,
- HFA384X_PORTTYPE_HOSTAP) ||
- local->func->reset_port(dev))
- printk(KERN_DEBUG "Returning to Host AP mode "
- "after HostScan failed\n");
- }
- break;
- }
-
- case PRISM2_PARAM_AP_SCAN:
- local->passive_scan_interval = value;
- if (timer_pending(&local->passive_scan_timer))
- del_timer(&local->passive_scan_timer);
- if (value > 0 && value < INT_MAX / HZ) {
- local->passive_scan_timer.expires = jiffies +
- local->passive_scan_interval * HZ;
- add_timer(&local->passive_scan_timer);
- }
- break;
-
- case PRISM2_PARAM_ENH_SEC:
- if (value < 0 || value > 3) {
- ret = -EINVAL;
- break;
- }
- local->enh_sec = value;
- if (hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY,
- local->enh_sec) ||
- local->func->reset_port(dev)) {
- printk(KERN_INFO "%s: cnfEnhSecurity requires STA f/w "
- "1.6.3 or newer\n", dev->name);
- ret = -EOPNOTSUPP;
- }
- break;
-
-#ifdef PRISM2_IO_DEBUG
- case PRISM2_PARAM_IO_DEBUG:
- local->io_debug_enabled = value;
- break;
-#endif /* PRISM2_IO_DEBUG */
-
- case PRISM2_PARAM_BASIC_RATES:
- if ((value & local->tx_rate_control) != value || value == 0) {
- printk(KERN_INFO "%s: invalid basic rate set - basic "
- "rates must be in supported rate set\n",
- dev->name);
- ret = -EINVAL;
- break;
- }
- local->basic_rates = value;
- if (hostap_set_word(dev, HFA384X_RID_CNFBASICRATES,
- local->basic_rates) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_OPER_RATES:
- local->tx_rate_control = value;
- if (hostap_set_rate(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_HOSTAPD:
- ret = hostap_set_hostapd(local, value, 1);
- break;
-
- case PRISM2_PARAM_HOSTAPD_STA:
- ret = hostap_set_hostapd_sta(local, value, 1);
- break;
-
- case PRISM2_PARAM_WPA:
- local->wpa = value;
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- ret = -EOPNOTSUPP;
- else if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
- value ? 1 : 0))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_PRIVACY_INVOKED:
- local->privacy_invoked = value;
- if (hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_TKIP_COUNTERMEASURES:
- local->tkip_countermeasures = value;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- local->drop_unencrypted = value;
- break;
-
- case PRISM2_PARAM_SCAN_CHANNEL_MASK:
- local->scan_channel_mask = value;
- break;
-
- default:
- printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n",
- dev->name, param);
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_priv_get_prism2_param(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int *param = (int *) extra;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- switch (*param) {
- case PRISM2_PARAM_TXRATECTRL:
- *param = local->fw_tx_rate_control;
- break;
-
- case PRISM2_PARAM_BEACON_INT:
- *param = local->beacon_int;
- break;
-
- case PRISM2_PARAM_PSEUDO_IBSS:
- *param = local->pseudo_adhoc;
- break;
-
- case PRISM2_PARAM_ALC:
- ret = -EOPNOTSUPP; /* FIX */
- break;
-
- case PRISM2_PARAM_DUMP:
- *param = local->frame_dump;
- break;
-
- case PRISM2_PARAM_OTHER_AP_POLICY:
- if (local->ap != NULL)
- *param = local->ap->ap_policy;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_MAX_INACTIVITY:
- if (local->ap != NULL)
- *param = local->ap->max_inactivity / HZ;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_BRIDGE_PACKETS:
- if (local->ap != NULL)
- *param = local->ap->bridge_packets;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_DTIM_PERIOD:
- *param = local->dtim_period;
- break;
-
- case PRISM2_PARAM_AP_NULLFUNC_ACK:
- if (local->ap != NULL)
- *param = local->ap->nullfunc_ack;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_MAX_WDS:
- *param = local->wds_max_connections;
- break;
-
- case PRISM2_PARAM_AP_AUTOM_AP_WDS:
- if (local->ap != NULL)
- *param = local->ap->autom_ap_wds;
- else
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_AUTH_ALGS:
- *param = local->auth_algs;
- break;
-
- case PRISM2_PARAM_MONITOR_ALLOW_FCSERR:
- *param = local->monitor_allow_fcserr;
- break;
-
- case PRISM2_PARAM_HOST_ENCRYPT:
- *param = local->host_encrypt;
- break;
-
- case PRISM2_PARAM_HOST_DECRYPT:
- *param = local->host_decrypt;
- break;
-
- case PRISM2_PARAM_HOST_ROAMING:
- *param = local->host_roaming;
- break;
-
- case PRISM2_PARAM_BCRX_STA_KEY:
- *param = local->bcrx_sta_key;
- break;
-
- case PRISM2_PARAM_IEEE_802_1X:
- *param = local->ieee_802_1x;
- break;
-
- case PRISM2_PARAM_ANTSEL_TX:
- *param = local->antsel_tx;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- *param = local->antsel_rx;
- break;
-
- case PRISM2_PARAM_MONITOR_TYPE:
- *param = local->monitor_type;
- break;
-
- case PRISM2_PARAM_WDS_TYPE:
- *param = local->wds_type;
- break;
-
- case PRISM2_PARAM_HOSTSCAN:
- ret = -EOPNOTSUPP;
- break;
-
- case PRISM2_PARAM_AP_SCAN:
- *param = local->passive_scan_interval;
- break;
-
- case PRISM2_PARAM_ENH_SEC:
- *param = local->enh_sec;
- break;
-
-#ifdef PRISM2_IO_DEBUG
- case PRISM2_PARAM_IO_DEBUG:
- *param = local->io_debug_enabled;
- break;
-#endif /* PRISM2_IO_DEBUG */
-
- case PRISM2_PARAM_BASIC_RATES:
- *param = local->basic_rates;
- break;
-
- case PRISM2_PARAM_OPER_RATES:
- *param = local->tx_rate_control;
- break;
-
- case PRISM2_PARAM_HOSTAPD:
- *param = local->hostapd;
- break;
-
- case PRISM2_PARAM_HOSTAPD_STA:
- *param = local->hostapd_sta;
- break;
-
- case PRISM2_PARAM_WPA:
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- ret = -EOPNOTSUPP;
- *param = local->wpa;
- break;
-
- case PRISM2_PARAM_PRIVACY_INVOKED:
- *param = local->privacy_invoked;
- break;
-
- case PRISM2_PARAM_TKIP_COUNTERMEASURES:
- *param = local->tkip_countermeasures;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- *param = local->drop_unencrypted;
- break;
-
- case PRISM2_PARAM_SCAN_CHANNEL_MASK:
- *param = local->scan_channel_mask;
- break;
-
- default:
- printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n",
- dev->name, *param);
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_priv_readmif(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u16 resp0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->cmd(dev, HFA384X_CMDCODE_READMIF, *extra, NULL,
- &resp0))
- return -EOPNOTSUPP;
- else
- *extra = resp0;
-
- return 0;
-}
-
-
-static int prism2_ioctl_priv_writemif(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- u16 cr, val;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- cr = *extra;
- val = *(extra + 1);
- if (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF, cr, &val, NULL))
- return -EOPNOTSUPP;
-
- return 0;
-}
-
-
-static int prism2_ioctl_priv_monitor(struct net_device *dev, int *i)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
- union iwreq_data wrqu;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- printk(KERN_DEBUG "%s: process %d (%s) used deprecated iwpriv monitor "
- "- update software to use iwconfig mode monitor\n",
- dev->name, task_pid_nr(current), current->comm);
-
- /* Backward compatibility code - this can be removed at some point */
-
- if (*i == 0) {
- /* Disable monitor mode - old mode was not saved, so go to
- * Master mode */
- wrqu.mode = IW_MODE_MASTER;
- ret = prism2_ioctl_siwmode(dev, NULL, &wrqu, NULL);
- } else if (*i == 1) {
- /* netlink socket mode is not supported anymore since it did
- * not separate different devices from each other and was not
- * best method for delivering large amount of packets to
- * user space */
- ret = -EOPNOTSUPP;
- } else if (*i == 2 || *i == 3) {
- switch (*i) {
- case 2:
- local->monitor_type = PRISM2_MONITOR_80211;
- break;
- case 3:
- local->monitor_type = PRISM2_MONITOR_PRISM;
- break;
- }
- wrqu.mode = IW_MODE_MONITOR;
- ret = prism2_ioctl_siwmode(dev, NULL, &wrqu, NULL);
- hostap_monitor_mode_enable(local);
- } else
- ret = -EINVAL;
-
- return ret;
-}
-
-
-static int prism2_ioctl_priv_reset(struct net_device *dev, int *i)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- printk(KERN_DEBUG "%s: manual reset request(%d)\n", dev->name, *i);
- switch (*i) {
- case 0:
- /* Disable and enable card */
- local->func->hw_shutdown(dev, 1);
- local->func->hw_config(dev, 0);
- break;
-
- case 1:
- /* COR sreset */
- local->func->hw_reset(dev);
- break;
-
- case 2:
- /* Disable and enable port 0 */
- local->func->reset_port(dev);
- break;
-
- case 3:
- prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING);
- if (local->func->cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL,
- NULL))
- return -EINVAL;
- break;
-
- case 4:
- if (local->func->cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL,
- NULL))
- return -EINVAL;
- break;
-
- default:
- printk(KERN_DEBUG "Unknown reset request %d\n", *i);
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-
-static int prism2_ioctl_priv_set_rid_word(struct net_device *dev, int *i)
-{
- int rid = *i;
- int value = *(i + 1);
-
- printk(KERN_DEBUG "%s: Set RID[0x%X] = %d\n", dev->name, rid, value);
-
- if (hostap_set_word(dev, rid, value))
- return -EINVAL;
-
- return 0;
-}
-
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
-static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd)
-{
- int ret = 0;
-
- switch (*cmd) {
- case AP_MAC_CMD_POLICY_OPEN:
- local->ap->mac_restrictions.policy = MAC_POLICY_OPEN;
- break;
- case AP_MAC_CMD_POLICY_ALLOW:
- local->ap->mac_restrictions.policy = MAC_POLICY_ALLOW;
- break;
- case AP_MAC_CMD_POLICY_DENY:
- local->ap->mac_restrictions.policy = MAC_POLICY_DENY;
- break;
- case AP_MAC_CMD_FLUSH:
- ap_control_flush_macs(&local->ap->mac_restrictions);
- break;
- case AP_MAC_CMD_KICKALL:
- ap_control_kickall(local->ap);
- hostap_deauth_all_stas(local->dev, local->ap, 0);
- break;
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
-static int prism2_ioctl_priv_download(local_info_t *local, struct iw_point *p)
-{
- struct prism2_download_param *param;
- int ret = 0;
-
- if (p->length < sizeof(struct prism2_download_param) ||
- p->length > 1024 || !p->pointer)
- return -EINVAL;
-
- param = memdup_user(p->pointer, p->length);
- if (IS_ERR(param)) {
- return PTR_ERR(param);
- }
-
- if (p->length < sizeof(struct prism2_download_param) +
- param->num_areas * sizeof(struct prism2_download_area)) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = local->func->download(local, param);
-
- out:
- kfree(param);
- return ret;
-}
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-
-static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
- size_t len)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- u8 *buf;
-
- /*
- * Add 16-bit length in the beginning of the buffer because Prism2 RID
- * includes it.
- */
- buf = kmalloc(len + 2, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- *((__le16 *) buf) = cpu_to_le16(len);
- memcpy(buf + 2, elem, len);
-
- kfree(local->generic_elem);
- local->generic_elem = buf;
- local->generic_elem_len = len + 2;
-
- return local->func->set_rid(local->dev, HFA384X_RID_GENERICELEMENT,
- buf, len + 2);
-}
-
-
-static int prism2_ioctl_siwauth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *data = &wrqu->param;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * Host AP driver does not use these parameters and allows
- * wpa_supplicant to control them internally.
- */
- break;
- case IW_AUTH_TKIP_COUNTERMEASURES:
- local->tkip_countermeasures = data->value;
- break;
- case IW_AUTH_DROP_UNENCRYPTED:
- local->drop_unencrypted = data->value;
- break;
- case IW_AUTH_80211_AUTH_ALG:
- local->auth_algs = data->value;
- break;
- case IW_AUTH_WPA_ENABLED:
- if (data->value == 0) {
- local->wpa = 0;
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- break;
- prism2_set_genericelement(dev, "", 0);
- local->host_roaming = 0;
- local->privacy_invoked = 0;
- if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE,
- 0) ||
- hostap_set_roaming(local) ||
- hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- return -EINVAL;
- break;
- }
- if (local->sta_fw_ver < PRISM2_FW_VER(1,7,0))
- return -EOPNOTSUPP;
- local->host_roaming = 2;
- local->privacy_invoked = 1;
- local->wpa = 1;
- if (hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1) ||
- hostap_set_roaming(local) ||
- hostap_set_encryption(local) ||
- local->func->reset_port(dev))
- return -EINVAL;
- break;
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- local->ieee_802_1x = data->value;
- break;
- case IW_AUTH_PRIVACY_INVOKED:
- local->privacy_invoked = data->value;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-
-static int prism2_ioctl_giwauth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *data = &wrqu->param;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
-
- switch (data->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * Host AP driver does not use these parameters and allows
- * wpa_supplicant to control them internally.
- */
- return -EOPNOTSUPP;
- case IW_AUTH_TKIP_COUNTERMEASURES:
- data->value = local->tkip_countermeasures;
- break;
- case IW_AUTH_DROP_UNENCRYPTED:
- data->value = local->drop_unencrypted;
- break;
- case IW_AUTH_80211_AUTH_ALG:
- data->value = local->auth_algs;
- break;
- case IW_AUTH_WPA_ENABLED:
- data->value = local->wpa;
- break;
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- data->value = local->ieee_802_1x;
- break;
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-
-static int prism2_ioctl_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int i, ret = 0;
- struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
- u8 *addr;
- const char *alg, *module;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i > WEP_KEYS)
- return -EINVAL;
- if (i < 1 || i > WEP_KEYS)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
- if (i < 0 || i >= WEP_KEYS)
- return -EINVAL;
-
- addr = ext->addr.sa_data;
- if (is_broadcast_ether_addr(addr)) {
- sta_ptr = NULL;
- crypt = &local->crypt_info.crypt[i];
- } else {
- if (i != 0)
- return -EINVAL;
- sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
- if (sta_ptr == NULL) {
- if (local->iw_mode == IW_MODE_INFRA) {
- /*
- * TODO: add STA entry for the current AP so
- * that unicast key can be used. For now, this
- * is emulated by using default key idx 0.
- */
- i = 0;
- crypt = &local->crypt_info.crypt[i];
- } else
- return -EINVAL;
- }
- }
-
- if ((erq->flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- goto done;
- }
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_WEP:
- alg = "WEP";
- module = "lib80211_crypt_wep";
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = "TKIP";
- module = "lib80211_crypt_tkip";
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = "CCMP";
- module = "lib80211_crypt_ccmp";
- break;
- default:
- printk(KERN_DEBUG "%s: unsupported algorithm %d\n",
- local->dev->name, ext->alg);
- ret = -EOPNOTSUPP;
- goto done;
- }
-
- ops = lib80211_get_crypto_ops(alg);
- if (ops == NULL) {
- request_module(module);
- ops = lib80211_get_crypto_ops(alg);
- }
- if (ops == NULL) {
- printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
- local->dev->name, alg);
- ret = -EOPNOTSUPP;
- goto done;
- }
-
- if (sta_ptr || ext->alg != IW_ENCODE_ALG_WEP) {
- /*
- * Per station encryption and other than WEP algorithms
- * require host-based encryption, so force them on
- * automatically.
- */
- local->host_decrypt = local->host_encrypt = 1;
- }
-
- if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- new_crypt->ops = ops;
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(i);
- if (new_crypt->priv == NULL) {
- kfree(new_crypt);
- ret = -EINVAL;
- goto done;
- }
-
- *crypt = new_crypt;
- }
-
- /*
- * TODO: if ext_flags does not have IW_ENCODE_EXT_RX_SEQ_VALID, the
- * existing seq# should not be changed.
- * TODO: if ext_flags has IW_ENCODE_EXT_TX_SEQ_VALID, next TX seq#
- * should be changed to something else than zero.
- */
- if ((!(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) || ext->key_len > 0)
- && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
- (*crypt)->priv) < 0) {
- printk(KERN_DEBUG "%s: key setting failed\n",
- local->dev->name);
- ret = -EINVAL;
- goto done;
- }
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- if (!sta_ptr)
- local->crypt_info.tx_keyidx = i;
- }
-
-
- if (sta_ptr == NULL && ext->key_len > 0) {
- int first = 1, j;
- for (j = 0; j < WEP_KEYS; j++) {
- if (j != i && local->crypt_info.crypt[j]) {
- first = 0;
- break;
- }
- }
- if (first)
- local->crypt_info.tx_keyidx = i;
- }
-
- done:
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- local->open_wep = erq->flags & IW_ENCODE_OPEN;
-
- /*
- * Do not reset port0 if card is in Managed mode since resetting will
- * generate new IEEE 802.11 authentication which may end up in looping
- * with IEEE 802.1X. Prism2 documentation seem to require port reset
- * after WEP configuration. However, keys are apparently changed at
- * least in Managed mode.
- */
- if (ret == 0 &&
- (hostap_set_encryption(local) ||
- (local->iw_mode != IW_MODE_INFRA &&
- local->func->reset_port(local->dev))))
- ret = -EINVAL;
-
- return ret;
-}
-
-
-static int prism2_ioctl_giwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
- int max_key_len, i;
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- u8 *addr;
-
- max_key_len = erq->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- i = erq->flags & IW_ENCODE_INDEX;
- if (i < 1 || i > WEP_KEYS)
- i = local->crypt_info.tx_keyidx;
- else
- i--;
-
- addr = ext->addr.sa_data;
- if (is_broadcast_ether_addr(addr)) {
- sta_ptr = NULL;
- crypt = &local->crypt_info.crypt[i];
- } else {
- i = 0;
- sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt);
- if (sta_ptr == NULL)
- return -EINVAL;
- }
- erq->flags = i + 1;
- memset(ext, 0, sizeof(*ext));
-
- if (*crypt == NULL || (*crypt)->ops == NULL) {
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- } else {
- if (strcmp((*crypt)->ops->name, "WEP") == 0)
- ext->alg = IW_ENCODE_ALG_WEP;
- else if (strcmp((*crypt)->ops->name, "TKIP") == 0)
- ext->alg = IW_ENCODE_ALG_TKIP;
- else if (strcmp((*crypt)->ops->name, "CCMP") == 0)
- ext->alg = IW_ENCODE_ALG_CCMP;
- else
- return -EINVAL;
-
- if ((*crypt)->ops->get_key) {
- ext->key_len =
- (*crypt)->ops->get_key(ext->key,
- max_key_len,
- ext->tx_seq,
- (*crypt)->priv);
- if (ext->key_len &&
- (ext->alg == IW_ENCODE_ALG_TKIP ||
- ext->alg == IW_ENCODE_ALG_CCMP))
- ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
- }
- }
-
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- return 0;
-}
-
-
-static int prism2_ioctl_set_encryption(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int ret = 0;
- struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
-
- param->u.crypt.err = 0;
- param->u.crypt.alg[HOSTAP_CRYPT_ALG_NAME_LEN - 1] = '\0';
-
- if (param_len !=
- (int) ((char *) param->u.crypt.key - (char *) param) +
- param->u.crypt.key_len)
- return -EINVAL;
-
- if (is_broadcast_ether_addr(param->sta_addr)) {
- if (param->u.crypt.idx >= WEP_KEYS)
- return -EINVAL;
- sta_ptr = NULL;
- crypt = &local->crypt_info.crypt[param->u.crypt.idx];
- } else {
- if (param->u.crypt.idx)
- return -EINVAL;
- sta_ptr = ap_crypt_get_ptrs(
- local->ap, param->sta_addr,
- (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_PERMANENT),
- &crypt);
-
- if (sta_ptr == NULL) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
- return -EINVAL;
- }
- }
-
- if (strcmp(param->u.crypt.alg, "none") == 0) {
- if (crypt)
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
- goto done;
- }
-
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) {
- request_module("lib80211_crypt_wep");
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) {
- request_module("lib80211_crypt_tkip");
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) {
- request_module("lib80211_crypt_ccmp");
- ops = lib80211_get_crypto_ops(param->u.crypt.alg);
- }
- if (ops == NULL) {
- printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n",
- local->dev->name, param->u.crypt.alg);
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ALG;
- ret = -EINVAL;
- goto done;
- }
-
- /* station based encryption and other than WEP algorithms require
- * host-based encryption, so force them on automatically */
- local->host_decrypt = local->host_encrypt = 1;
-
- if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&local->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- new_crypt->ops = ops;
- new_crypt->priv = new_crypt->ops->init(param->u.crypt.idx);
- if (new_crypt->priv == NULL) {
- kfree(new_crypt);
- param->u.crypt.err =
- HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED;
- ret = -EINVAL;
- goto done;
- }
-
- *crypt = new_crypt;
- }
-
- if ((!(param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) ||
- param->u.crypt.key_len > 0) && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(param->u.crypt.key,
- param->u.crypt.key_len, param->u.crypt.seq,
- (*crypt)->priv) < 0) {
- printk(KERN_DEBUG "%s: key setting failed\n",
- local->dev->name);
- param->u.crypt.err = HOSTAP_CRYPT_ERR_KEY_SET_FAILED;
- ret = -EINVAL;
- goto done;
- }
-
- if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) {
- if (!sta_ptr)
- local->crypt_info.tx_keyidx = param->u.crypt.idx;
- else if (param->u.crypt.idx) {
- printk(KERN_DEBUG "%s: TX key idx setting failed\n",
- local->dev->name);
- param->u.crypt.err =
- HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED;
- ret = -EINVAL;
- goto done;
- }
- }
-
- done:
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- /* Do not reset port0 if card is in Managed mode since resetting will
- * generate new IEEE 802.11 authentication which may end up in looping
- * with IEEE 802.1X. Prism2 documentation seem to require port reset
- * after WEP configuration. However, keys are apparently changed at
- * least in Managed mode. */
- if (ret == 0 &&
- (hostap_set_encryption(local) ||
- (local->iw_mode != IW_MODE_INFRA &&
- local->func->reset_port(local->dev)))) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_CARD_CONF_FAILED;
- return -EINVAL;
- }
-
- return ret;
-}
-
-
-static int prism2_ioctl_get_encryption(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- struct lib80211_crypt_data **crypt;
- void *sta_ptr;
- int max_key_len;
-
- param->u.crypt.err = 0;
-
- max_key_len = param_len -
- (int) ((char *) param->u.crypt.key - (char *) param);
- if (max_key_len < 0)
- return -EINVAL;
-
- if (is_broadcast_ether_addr(param->sta_addr)) {
- sta_ptr = NULL;
- if (param->u.crypt.idx >= WEP_KEYS)
- param->u.crypt.idx = local->crypt_info.tx_keyidx;
- crypt = &local->crypt_info.crypt[param->u.crypt.idx];
- } else {
- param->u.crypt.idx = 0;
- sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0,
- &crypt);
-
- if (sta_ptr == NULL) {
- param->u.crypt.err = HOSTAP_CRYPT_ERR_UNKNOWN_ADDR;
- return -EINVAL;
- }
- }
-
- if (*crypt == NULL || (*crypt)->ops == NULL) {
- memcpy(param->u.crypt.alg, "none", 5);
- param->u.crypt.key_len = 0;
- param->u.crypt.idx = 0xff;
- } else {
- strscpy(param->u.crypt.alg, (*crypt)->ops->name,
- HOSTAP_CRYPT_ALG_NAME_LEN);
- param->u.crypt.key_len = 0;
-
- memset(param->u.crypt.seq, 0, 8);
- if ((*crypt)->ops->get_key) {
- param->u.crypt.key_len =
- (*crypt)->ops->get_key(param->u.crypt.key,
- max_key_len,
- param->u.crypt.seq,
- (*crypt)->priv);
- }
- }
-
- if (sta_ptr)
- hostap_handle_sta_release(sta_ptr);
-
- return 0;
-}
-
-
-static int prism2_ioctl_get_rid(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int max_len, res;
-
- max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
- if (max_len < 0)
- return -EINVAL;
-
- res = local->func->get_rid(local->dev, param->u.rid.rid,
- param->u.rid.data, param->u.rid.len, 0);
- if (res >= 0) {
- param->u.rid.len = res;
- return 0;
- }
-
- return res;
-}
-
-
-static int prism2_ioctl_set_rid(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int max_len;
-
- max_len = param_len - PRISM2_HOSTAPD_RID_HDR_LEN;
- if (max_len < 0 || max_len < param->u.rid.len)
- return -EINVAL;
-
- return local->func->set_rid(local->dev, param->u.rid.rid,
- param->u.rid.data, param->u.rid.len);
-}
-
-
-static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n",
- local->dev->name, param->sta_addr);
- memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
- return 0;
-}
-
-
-static int prism2_ioctl_siwgenie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- return prism2_set_genericelement(dev, extra, data->length);
-}
-
-
-static int prism2_ioctl_giwgenie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- int len = local->generic_elem_len - 2;
-
- if (len <= 0 || local->generic_elem == NULL) {
- data->length = 0;
- return 0;
- }
-
- if (data->length < len)
- return -E2BIG;
-
- data->length = len;
- memcpy(extra, local->generic_elem + 2, len);
-
- return 0;
-}
-
-
-static int prism2_ioctl_set_generic_element(local_info_t *local,
- struct prism2_hostapd_param *param,
- int param_len)
-{
- int max_len, len;
-
- len = param->u.generic_elem.len;
- max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
- if (max_len < 0 || max_len < len)
- return -EINVAL;
-
- return prism2_set_genericelement(local->dev,
- param->u.generic_elem.data, len);
-}
-
-
-static int prism2_ioctl_siwmlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- struct iw_mlme *mlme = (struct iw_mlme *) extra;
- __le16 reason;
-
- reason = cpu_to_le16(mlme->reason_code);
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
- IEEE80211_STYPE_DEAUTH,
- (u8 *) &reason, 2);
- case IW_MLME_DISASSOC:
- return prism2_sta_send_mgmt(local, mlme->addr.sa_data,
- IEEE80211_STYPE_DISASSOC,
- (u8 *) &reason, 2);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-
-static int prism2_ioctl_mlme(local_info_t *local,
- struct prism2_hostapd_param *param)
-{
- __le16 reason;
-
- reason = cpu_to_le16(param->u.mlme.reason_code);
- switch (param->u.mlme.cmd) {
- case MLME_STA_DEAUTH:
- return prism2_sta_send_mgmt(local, param->sta_addr,
- IEEE80211_STYPE_DEAUTH,
- (u8 *) &reason, 2);
- case MLME_STA_DISASSOC:
- return prism2_sta_send_mgmt(local, param->sta_addr,
- IEEE80211_STYPE_DISASSOC,
- (u8 *) &reason, 2);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-
-static int prism2_ioctl_scan_req(local_info_t *local,
- struct prism2_hostapd_param *param)
-{
-#ifndef PRISM2_NO_STATION_MODES
- if ((local->iw_mode != IW_MODE_INFRA &&
- local->iw_mode != IW_MODE_ADHOC) ||
- (local->sta_fw_ver < PRISM2_FW_VER(1,3,1)))
- return -EOPNOTSUPP;
-
- if (!local->dev_enabled)
- return -ENETDOWN;
-
- return prism2_request_hostscan(local->dev, param->u.scan_req.ssid,
- param->u.scan_req.ssid_len);
-#else /* PRISM2_NO_STATION_MODES */
- return -EOPNOTSUPP;
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p)
-{
- struct prism2_hostapd_param *param;
- int ret = 0;
- int ap_ioctl = 0;
-
- if (p->length < sizeof(struct prism2_hostapd_param) ||
- p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
- return -EINVAL;
-
- param = memdup_user(p->pointer, p->length);
- if (IS_ERR(param)) {
- return PTR_ERR(param);
- }
-
- switch (param->cmd) {
- case PRISM2_SET_ENCRYPTION:
- ret = prism2_ioctl_set_encryption(local, param, p->length);
- break;
- case PRISM2_GET_ENCRYPTION:
- ret = prism2_ioctl_get_encryption(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_GET_RID:
- ret = prism2_ioctl_get_rid(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_SET_RID:
- ret = prism2_ioctl_set_rid(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR:
- ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length);
- break;
- case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
- ret = prism2_ioctl_set_generic_element(local, param,
- p->length);
- break;
- case PRISM2_HOSTAPD_MLME:
- ret = prism2_ioctl_mlme(local, param);
- break;
- case PRISM2_HOSTAPD_SCAN_REQ:
- ret = prism2_ioctl_scan_req(local, param);
- break;
- default:
- ret = prism2_hostapd(local->ap, param);
- ap_ioctl = 1;
- break;
- }
-
- if (ret == 1 || !ap_ioctl) {
- if (copy_to_user(p->pointer, param, p->length)) {
- ret = -EFAULT;
- goto out;
- } else if (ap_ioctl)
- ret = 0;
- }
-
- out:
- kfree(param);
- return ret;
-}
-
-
-static void prism2_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- strscpy(info->driver, "hostap", sizeof(info->driver));
- snprintf(info->fw_version, sizeof(info->fw_version),
- "%d.%d.%d", (local->sta_fw_ver >> 16) & 0xff,
- (local->sta_fw_ver >> 8) & 0xff,
- local->sta_fw_ver & 0xff);
-}
-
-const struct ethtool_ops prism2_ethtool_ops = {
- .get_drvinfo = prism2_get_drvinfo
-};
-
-
-/* Structures to export the Wireless Handlers */
-
-static const iw_handler prism2_handler[] =
-{
- IW_HANDLER(SIOCGIWNAME, prism2_get_name),
- IW_HANDLER(SIOCSIWFREQ, prism2_ioctl_siwfreq),
- IW_HANDLER(SIOCGIWFREQ, prism2_ioctl_giwfreq),
- IW_HANDLER(SIOCSIWMODE, prism2_ioctl_siwmode),
- IW_HANDLER(SIOCGIWMODE, prism2_ioctl_giwmode),
- IW_HANDLER(SIOCSIWSENS, prism2_ioctl_siwsens),
- IW_HANDLER(SIOCGIWSENS, prism2_ioctl_giwsens),
- IW_HANDLER(SIOCGIWRANGE, prism2_ioctl_giwrange),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, prism2_ioctl_siwap),
- IW_HANDLER(SIOCGIWAP, prism2_ioctl_giwap),
- IW_HANDLER(SIOCSIWMLME, prism2_ioctl_siwmlme),
- IW_HANDLER(SIOCGIWAPLIST, prism2_ioctl_giwaplist),
- IW_HANDLER(SIOCSIWSCAN, prism2_ioctl_siwscan),
- IW_HANDLER(SIOCGIWSCAN, prism2_ioctl_giwscan),
- IW_HANDLER(SIOCSIWESSID, prism2_ioctl_siwessid),
- IW_HANDLER(SIOCGIWESSID, prism2_ioctl_giwessid),
- IW_HANDLER(SIOCSIWNICKN, prism2_ioctl_siwnickn),
- IW_HANDLER(SIOCGIWNICKN, prism2_ioctl_giwnickn),
- IW_HANDLER(SIOCSIWRATE, prism2_ioctl_siwrate),
- IW_HANDLER(SIOCGIWRATE, prism2_ioctl_giwrate),
- IW_HANDLER(SIOCSIWRTS, prism2_ioctl_siwrts),
- IW_HANDLER(SIOCGIWRTS, prism2_ioctl_giwrts),
- IW_HANDLER(SIOCSIWFRAG, prism2_ioctl_siwfrag),
- IW_HANDLER(SIOCGIWFRAG, prism2_ioctl_giwfrag),
- IW_HANDLER(SIOCSIWTXPOW, prism2_ioctl_siwtxpow),
- IW_HANDLER(SIOCGIWTXPOW, prism2_ioctl_giwtxpow),
- IW_HANDLER(SIOCSIWRETRY, prism2_ioctl_siwretry),
- IW_HANDLER(SIOCGIWRETRY, prism2_ioctl_giwretry),
- IW_HANDLER(SIOCSIWENCODE, prism2_ioctl_siwencode),
- IW_HANDLER(SIOCGIWENCODE, prism2_ioctl_giwencode),
- IW_HANDLER(SIOCSIWPOWER, prism2_ioctl_siwpower),
- IW_HANDLER(SIOCGIWPOWER, prism2_ioctl_giwpower),
- IW_HANDLER(SIOCSIWGENIE, prism2_ioctl_siwgenie),
- IW_HANDLER(SIOCGIWGENIE, prism2_ioctl_giwgenie),
- IW_HANDLER(SIOCSIWAUTH, prism2_ioctl_siwauth),
- IW_HANDLER(SIOCGIWAUTH, prism2_ioctl_giwauth),
- IW_HANDLER(SIOCSIWENCODEEXT, prism2_ioctl_siwencodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, prism2_ioctl_giwencodeext),
-};
-
-static const iw_handler prism2_private_handler[] =
-{ /* SIOCIWFIRSTPRIV + */
- prism2_ioctl_priv_prism2_param, /* 0 */
- prism2_ioctl_priv_get_prism2_param, /* 1 */
- prism2_ioctl_priv_writemif, /* 2 */
- prism2_ioctl_priv_readmif, /* 3 */
-};
-
-const struct iw_handler_def hostap_iw_handler_def =
-{
- .num_standard = ARRAY_SIZE(prism2_handler),
- .num_private = ARRAY_SIZE(prism2_private_handler),
- .num_private_args = ARRAY_SIZE(prism2_priv),
- .standard = prism2_handler,
- .private = prism2_private_handler,
- .private_args = (struct iw_priv_args *) prism2_priv,
- .get_wireless_stats = hostap_get_wireless_stats,
-};
-
-/* Private ioctls (iwpriv) that have not yet been converted
- * into new wireless extensions API */
-int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- struct iwreq *wrq = (struct iwreq *) ifr;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- switch (cmd) {
- case PRISM2_IOCTL_INQUIRE:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_inquire(dev, (int *) wrq->u.name);
- break;
-
- case PRISM2_IOCTL_MONITOR:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_monitor(dev, (int *) wrq->u.name);
- break;
-
- case PRISM2_IOCTL_RESET:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_reset(dev, (int *) wrq->u.name);
- break;
-
- case PRISM2_IOCTL_WDS_ADD:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_wds_add(local, wrq->u.ap_addr.sa_data, 1);
- break;
-
- case PRISM2_IOCTL_WDS_DEL:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_wds_del(local, wrq->u.ap_addr.sa_data, 1, 0);
- break;
-
- case PRISM2_IOCTL_SET_RID_WORD:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_set_rid_word(dev,
- (int *) wrq->u.name);
- break;
-
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- case PRISM2_IOCTL_MACCMD:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name);
- break;
-
- case PRISM2_IOCTL_ADDMAC:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = ap_control_add_mac(&local->ap->mac_restrictions,
- wrq->u.ap_addr.sa_data);
- break;
- case PRISM2_IOCTL_DELMAC:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = ap_control_del_mac(&local->ap->mac_restrictions,
- wrq->u.ap_addr.sa_data);
- break;
- case PRISM2_IOCTL_KICKMAC:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = ap_control_kick_mac(local->ap, local->dev,
- wrq->u.ap_addr.sa_data);
- break;
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
-
-/* Private ioctls that are not used with iwpriv;
- * in SIOCDEVPRIVATE range */
-int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
- void __user *data, int cmd)
-{
- struct iwreq *wrq = (struct iwreq *)ifr;
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (in_compat_syscall()) /* not implemented yet */
- return -EOPNOTSUPP;
-
- switch (cmd) {
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- case PRISM2_IOCTL_DOWNLOAD:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_download(local, &wrq->u.data);
- break;
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
- case PRISM2_IOCTL_HOSTAPD:
- if (!capable(CAP_NET_ADMIN)) ret = -EPERM;
- else ret = prism2_ioctl_priv_hostapd(local, &wrq->u.data);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- break;
- }
-
- return ret;
-}
diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c
deleted file mode 100644
index 787f685e70b49..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_main.c
+++ /dev/null
@@ -1,1126 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Host AP (software wireless LAN access point) driver for
- * Intersil Prism2/2.5/3 - hostap.o module, common routines
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <[email protected]>
- * Copyright (c) 2002-2005, Jouni Malinen <[email protected]>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/if_arp.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/workqueue.h>
-#include <linux/kmod.h>
-#include <linux/rtnetlink.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <net/net_namespace.h>
-#include <net/iw_handler.h>
-#include <net/lib80211.h>
-#include <linux/uaccess.h>
-
-#include "hostap_wlan.h"
-#include "hostap_80211.h"
-#include "hostap_ap.h"
-#include "hostap.h"
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Host AP common routines");
-MODULE_LICENSE("GPL");
-
-#define TX_TIMEOUT (2 * HZ)
-
-#define PRISM2_MAX_FRAME_SIZE 2304
-#define PRISM2_MIN_MTU 256
-/* FIX: */
-#define PRISM2_MAX_MTU (PRISM2_MAX_FRAME_SIZE - (6 /* LLC */ + 8 /* WEP */))
-
-
-struct net_device * hostap_add_interface(struct local_info *local,
- int type, int rtnl_locked,
- const char *prefix,
- const char *name)
-{
- struct net_device *dev, *mdev;
- struct hostap_interface *iface;
- int ret;
-
- dev = alloc_etherdev(sizeof(struct hostap_interface));
- if (dev == NULL)
- return NULL;
-
- iface = netdev_priv(dev);
- iface->dev = dev;
- iface->local = local;
- iface->type = type;
- list_add(&iface->list, &local->hostap_interfaces);
-
- mdev = local->dev;
- eth_hw_addr_inherit(dev, mdev);
- dev->base_addr = mdev->base_addr;
- dev->irq = mdev->irq;
- dev->mem_start = mdev->mem_start;
- dev->mem_end = mdev->mem_end;
-
- hostap_setup_dev(dev, local, type);
- dev->needs_free_netdev = true;
-
- sprintf(dev->name, "%s%s", prefix, name);
- if (!rtnl_locked)
- rtnl_lock();
-
- SET_NETDEV_DEV(dev, mdev->dev.parent);
- ret = register_netdevice(dev);
-
- if (!rtnl_locked)
- rtnl_unlock();
-
- if (ret < 0) {
- printk(KERN_WARNING "%s: failed to add new netdevice!\n",
- dev->name);
- free_netdev(dev);
- return NULL;
- }
-
- printk(KERN_DEBUG "%s: registered netdevice %s\n",
- mdev->name, dev->name);
-
- return dev;
-}
-
-
-void hostap_remove_interface(struct net_device *dev, int rtnl_locked,
- int remove_from_list)
-{
- struct hostap_interface *iface;
-
- if (!dev)
- return;
-
- iface = netdev_priv(dev);
-
- if (remove_from_list) {
- list_del(&iface->list);
- }
-
- if (dev == iface->local->ddev)
- iface->local->ddev = NULL;
- else if (dev == iface->local->apdev)
- iface->local->apdev = NULL;
- else if (dev == iface->local->stadev)
- iface->local->stadev = NULL;
-
- if (rtnl_locked)
- unregister_netdevice(dev);
- else
- unregister_netdev(dev);
-
- /* 'dev->needs_free_netdev = true' implies device data, including
- * private data, will be freed when the device is removed */
-}
-
-
-static inline int prism2_wds_special_addr(u8 *addr)
-{
- if (addr[0] || addr[1] || addr[2] || addr[3] || addr[4] || addr[5])
- return 0;
-
- return 1;
-}
-
-
-int prism2_wds_add(local_info_t *local, u8 *remote_addr,
- int rtnl_locked)
-{
- struct net_device *dev;
- struct list_head *ptr;
- struct hostap_interface *iface, *empty, *match;
-
- empty = match = NULL;
- read_lock_bh(&local->iface_lock);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type != HOSTAP_INTERFACE_WDS)
- continue;
-
- if (prism2_wds_special_addr(iface->u.wds.remote_addr))
- empty = iface;
- else if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) {
- match = iface;
- break;
- }
- }
- if (!match && empty && !prism2_wds_special_addr(remote_addr)) {
- /* take pre-allocated entry into use */
- memcpy(empty->u.wds.remote_addr, remote_addr, ETH_ALEN);
- read_unlock_bh(&local->iface_lock);
- printk(KERN_DEBUG "%s: using pre-allocated WDS netdevice %s\n",
- local->dev->name, empty->dev->name);
- return 0;
- }
- read_unlock_bh(&local->iface_lock);
-
- if (!prism2_wds_special_addr(remote_addr)) {
- if (match)
- return -EEXIST;
- hostap_add_sta(local->ap, remote_addr);
- }
-
- if (local->wds_connections >= local->wds_max_connections)
- return -ENOBUFS;
-
- /* verify that there is room for wds# postfix in the interface name */
- if (strlen(local->dev->name) >= IFNAMSIZ - 5) {
- printk(KERN_DEBUG "'%s' too long base device name\n",
- local->dev->name);
- return -EINVAL;
- }
-
- dev = hostap_add_interface(local, HOSTAP_INTERFACE_WDS, rtnl_locked,
- local->ddev->name, "wds%d");
- if (dev == NULL)
- return -ENOMEM;
-
- iface = netdev_priv(dev);
- memcpy(iface->u.wds.remote_addr, remote_addr, ETH_ALEN);
-
- local->wds_connections++;
-
- return 0;
-}
-
-
-int prism2_wds_del(local_info_t *local, u8 *remote_addr,
- int rtnl_locked, int do_not_remove)
-{
- unsigned long flags;
- struct list_head *ptr;
- struct hostap_interface *iface, *selected = NULL;
-
- write_lock_irqsave(&local->iface_lock, flags);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type != HOSTAP_INTERFACE_WDS)
- continue;
-
- if (ether_addr_equal(iface->u.wds.remote_addr, remote_addr)) {
- selected = iface;
- break;
- }
- }
- if (selected && !do_not_remove)
- list_del(&selected->list);
- write_unlock_irqrestore(&local->iface_lock, flags);
-
- if (selected) {
- if (do_not_remove)
- eth_zero_addr(selected->u.wds.remote_addr);
- else {
- hostap_remove_interface(selected->dev, rtnl_locked, 0);
- local->wds_connections--;
- }
- }
-
- return selected ? 0 : -ENODEV;
-}
-
-
-u16 hostap_tx_callback_register(local_info_t *local,
- void (*func)(struct sk_buff *, int ok, void *),
- void *data)
-{
- unsigned long flags;
- struct hostap_tx_callback_info *entry;
-
- entry = kmalloc(sizeof(*entry), GFP_KERNEL);
- if (entry == NULL)
- return 0;
-
- entry->func = func;
- entry->data = data;
-
- spin_lock_irqsave(&local->lock, flags);
- entry->idx = local->tx_callback ? local->tx_callback->idx + 1 : 1;
- entry->next = local->tx_callback;
- local->tx_callback = entry;
- spin_unlock_irqrestore(&local->lock, flags);
-
- return entry->idx;
-}
-
-
-int hostap_tx_callback_unregister(local_info_t *local, u16 idx)
-{
- unsigned long flags;
- struct hostap_tx_callback_info *cb, *prev = NULL;
-
- spin_lock_irqsave(&local->lock, flags);
- cb = local->tx_callback;
- while (cb != NULL && cb->idx != idx) {
- prev = cb;
- cb = cb->next;
- }
- if (cb) {
- if (prev == NULL)
- local->tx_callback = cb->next;
- else
- prev->next = cb->next;
- kfree(cb);
- }
- spin_unlock_irqrestore(&local->lock, flags);
-
- return cb ? 0 : -1;
-}
-
-
-/* val is in host byte order */
-int hostap_set_word(struct net_device *dev, int rid, u16 val)
-{
- struct hostap_interface *iface;
- __le16 tmp = cpu_to_le16(val);
- iface = netdev_priv(dev);
- return iface->local->func->set_rid(dev, rid, &tmp, 2);
-}
-
-
-int hostap_set_string(struct net_device *dev, int rid, const char *val)
-{
- struct hostap_interface *iface;
- char buf[MAX_SSID_LEN + 2];
- int len;
-
- iface = netdev_priv(dev);
- len = strlen(val);
- if (len > MAX_SSID_LEN)
- return -1;
- memset(buf, 0, sizeof(buf));
- buf[0] = len; /* little endian 16 bit word */
- memcpy(buf + 2, val, len);
-
- return iface->local->func->set_rid(dev, rid, &buf, MAX_SSID_LEN + 2);
-}
-
-
-u16 hostap_get_porttype(local_info_t *local)
-{
- if (local->iw_mode == IW_MODE_ADHOC && local->pseudo_adhoc)
- return HFA384X_PORTTYPE_PSEUDO_IBSS;
- if (local->iw_mode == IW_MODE_ADHOC)
- return HFA384X_PORTTYPE_IBSS;
- if (local->iw_mode == IW_MODE_INFRA)
- return HFA384X_PORTTYPE_BSS;
- if (local->iw_mode == IW_MODE_REPEAT)
- return HFA384X_PORTTYPE_WDS;
- if (local->iw_mode == IW_MODE_MONITOR)
- return HFA384X_PORTTYPE_PSEUDO_IBSS;
- return HFA384X_PORTTYPE_HOSTAP;
-}
-
-
-int hostap_set_encryption(local_info_t *local)
-{
- u16 val, old_val;
- int i, keylen, len, idx;
- char keybuf[WEP_KEY_LEN + 1];
- enum { NONE, WEP, OTHER } encrypt_type;
-
- idx = local->crypt_info.tx_keyidx;
- if (local->crypt_info.crypt[idx] == NULL ||
- local->crypt_info.crypt[idx]->ops == NULL)
- encrypt_type = NONE;
- else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0)
- encrypt_type = WEP;
- else
- encrypt_type = OTHER;
-
- if (local->func->get_rid(local->dev, HFA384X_RID_CNFWEPFLAGS, &val, 2,
- 1) < 0) {
- printk(KERN_DEBUG "Could not read current WEP flags.\n");
- goto fail;
- }
- le16_to_cpus(&val);
- old_val = val;
-
- if (encrypt_type != NONE || local->privacy_invoked)
- val |= HFA384X_WEPFLAGS_PRIVACYINVOKED;
- else
- val &= ~HFA384X_WEPFLAGS_PRIVACYINVOKED;
-
- if (local->open_wep || encrypt_type == NONE ||
- ((local->ieee_802_1x || local->wpa) && local->host_decrypt))
- val &= ~HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
- else
- val |= HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED;
-
- if ((encrypt_type != NONE || local->privacy_invoked) &&
- (encrypt_type == OTHER || local->host_encrypt))
- val |= HFA384X_WEPFLAGS_HOSTENCRYPT;
- else
- val &= ~HFA384X_WEPFLAGS_HOSTENCRYPT;
- if ((encrypt_type != NONE || local->privacy_invoked) &&
- (encrypt_type == OTHER || local->host_decrypt))
- val |= HFA384X_WEPFLAGS_HOSTDECRYPT;
- else
- val &= ~HFA384X_WEPFLAGS_HOSTDECRYPT;
-
- if (val != old_val &&
- hostap_set_word(local->dev, HFA384X_RID_CNFWEPFLAGS, val)) {
- printk(KERN_DEBUG "Could not write new WEP flags (0x%x)\n",
- val);
- goto fail;
- }
-
- if (encrypt_type != WEP)
- return 0;
-
- /* 104-bit support seems to require that all the keys are set to the
- * same keylen */
- keylen = 6; /* first 5 octets */
- len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL,
- local->crypt_info.crypt[idx]->priv);
- if (idx >= 0 && idx < WEP_KEYS && len > 5)
- keylen = WEP_KEY_LEN + 1; /* first 13 octets */
-
- for (i = 0; i < WEP_KEYS; i++) {
- memset(keybuf, 0, sizeof(keybuf));
- if (local->crypt_info.crypt[i]) {
- (void) local->crypt_info.crypt[i]->ops->get_key(
- keybuf, sizeof(keybuf),
- NULL, local->crypt_info.crypt[i]->priv);
- }
- if (local->func->set_rid(local->dev,
- HFA384X_RID_CNFDEFAULTKEY0 + i,
- keybuf, keylen)) {
- printk(KERN_DEBUG "Could not set key %d (len=%d)\n",
- i, keylen);
- goto fail;
- }
- }
- if (hostap_set_word(local->dev, HFA384X_RID_CNFWEPDEFAULTKEYID, idx)) {
- printk(KERN_DEBUG "Could not set default keyid %d\n", idx);
- goto fail;
- }
-
- return 0;
-
- fail:
- printk(KERN_DEBUG "%s: encryption setup failed\n", local->dev->name);
- return -1;
-}
-
-
-int hostap_set_antsel(local_info_t *local)
-{
- u16 val;
- int ret = 0;
-
- if (local->antsel_tx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
- local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
- HFA386X_CR_TX_CONFIGURE,
- NULL, &val) == 0) {
- val &= ~(BIT(2) | BIT(1));
- switch (local->antsel_tx) {
- case HOSTAP_ANTSEL_DIVERSITY:
- val |= BIT(1);
- break;
- case HOSTAP_ANTSEL_LOW:
- break;
- case HOSTAP_ANTSEL_HIGH:
- val |= BIT(2);
- break;
- }
-
- if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_TX_CONFIGURE, &val, NULL)) {
- printk(KERN_INFO "%s: setting TX AntSel failed\n",
- local->dev->name);
- ret = -1;
- }
- }
-
- if (local->antsel_rx != HOSTAP_ANTSEL_DO_NOT_TOUCH &&
- local->func->cmd(local->dev, HFA384X_CMDCODE_READMIF,
- HFA386X_CR_RX_CONFIGURE,
- NULL, &val) == 0) {
- val &= ~(BIT(1) | BIT(0));
- switch (local->antsel_rx) {
- case HOSTAP_ANTSEL_DIVERSITY:
- break;
- case HOSTAP_ANTSEL_LOW:
- val |= BIT(0);
- break;
- case HOSTAP_ANTSEL_HIGH:
- val |= BIT(0) | BIT(1);
- break;
- }
-
- if (local->func->cmd(local->dev, HFA384X_CMDCODE_WRITEMIF,
- HFA386X_CR_RX_CONFIGURE, &val, NULL)) {
- printk(KERN_INFO "%s: setting RX AntSel failed\n",
- local->dev->name);
- ret = -1;
- }
- }
-
- return ret;
-}
-
-
-int hostap_set_roaming(local_info_t *local)
-{
- u16 val;
-
- switch (local->host_roaming) {
- case 1:
- val = HFA384X_ROAMING_HOST;
- break;
- case 2:
- val = HFA384X_ROAMING_DISABLED;
- break;
- case 0:
- default:
- val = HFA384X_ROAMING_FIRMWARE;
- break;
- }
-
- return hostap_set_word(local->dev, HFA384X_RID_CNFROAMINGMODE, val);
-}
-
-
-int hostap_set_auth_algs(local_info_t *local)
-{
- int val = local->auth_algs;
- /* At least STA f/w v0.6.2 seems to have issues with cnfAuthentication
- * set to include both Open and Shared Key flags. It tries to use
- * Shared Key authentication in that case even if WEP keys are not
- * configured.. STA f/w v0.7.6 is able to handle such configuration,
- * but it is unknown when this was fixed between 0.6.2 .. 0.7.6. */
- if (local->sta_fw_ver < PRISM2_FW_VER(0,7,0) &&
- val != PRISM2_AUTH_OPEN && val != PRISM2_AUTH_SHARED_KEY)
- val = PRISM2_AUTH_OPEN;
-
- if (hostap_set_word(local->dev, HFA384X_RID_CNFAUTHENTICATION, val)) {
- printk(KERN_INFO "%s: cnfAuthentication setting to 0x%x "
- "failed\n", local->dev->name, local->auth_algs);
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
-{
- u16 status, fc;
-
- status = __le16_to_cpu(rx->status);
-
- printk(KERN_DEBUG "%s: RX status=0x%04x (port=%d, type=%d, "
- "fcserr=%d) silence=%d signal=%d rate=%d rxflow=%d; "
- "jiffies=%ld\n",
- name, status, (status >> 8) & 0x07, status >> 13, status & 1,
- rx->silence, rx->signal, rx->rate, rx->rxflow, jiffies);
-
- fc = __le16_to_cpu(rx->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
- "data_len=%d%s%s\n",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl),
- __le16_to_cpu(rx->data_len),
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n",
- rx->addr1, rx->addr2, rx->addr3, rx->addr4);
-
- printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n",
- rx->dst_addr, rx->src_addr,
- __be16_to_cpu(rx->len));
-}
-
-
-void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
-{
- u16 fc;
-
- printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
- "tx_control=0x%04x; jiffies=%ld\n",
- name, __le16_to_cpu(tx->status), tx->retry_count, tx->tx_rate,
- __le16_to_cpu(tx->tx_control), jiffies);
-
- fc = __le16_to_cpu(tx->frame_control);
- printk(KERN_DEBUG " FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
- "data_len=%d%s%s\n",
- fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
- (fc & IEEE80211_FCTL_STYPE) >> 4,
- __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl),
- __le16_to_cpu(tx->data_len),
- fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
- fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
-
- printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n",
- tx->addr1, tx->addr2, tx->addr3, tx->addr4);
-
- printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n",
- tx->dst_addr, tx->src_addr,
- __be16_to_cpu(tx->len));
-}
-
-
-static int hostap_80211_header_parse(const struct sk_buff *skb,
- unsigned char *haddr)
-{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
- return ETH_ALEN;
-}
-
-
-int hostap_80211_get_hdrlen(__le16 fc)
-{
- if (ieee80211_is_data(fc) && ieee80211_has_a4 (fc))
- return 30; /* Addr4 */
- else if (ieee80211_is_cts(fc) || ieee80211_is_ack(fc))
- return 10;
- else if (ieee80211_is_ctl(fc))
- return 16;
-
- return 24;
-}
-
-
-static int prism2_close(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name);
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (dev == local->ddev) {
- prism2_sta_deauth(local, WLAN_REASON_DEAUTH_LEAVING);
- }
-#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
- if (!local->hostapd && dev == local->dev &&
- (!local->func->card_present || local->func->card_present(local)) &&
- local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER)
- hostap_deauth_all_stas(dev, local->ap, 1);
-#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
-
- if (dev == local->dev) {
- local->func->hw_shutdown(dev, HOSTAP_HW_ENABLE_CMDCOMPL);
- }
-
- if (netif_running(dev)) {
- netif_stop_queue(dev);
- netif_device_detach(dev);
- }
-
- cancel_work_sync(&local->reset_queue);
- cancel_work_sync(&local->set_multicast_list_queue);
- cancel_work_sync(&local->set_tim_queue);
-#ifndef PRISM2_NO_STATION_MODES
- cancel_work_sync(&local->info_queue);
-#endif
- cancel_work_sync(&local->comms_qual_update);
-
- module_put(local->hw_module);
-
- local->num_dev_open--;
-
- if (dev != local->dev && local->dev->flags & IFF_UP &&
- local->master_dev_auto_open && local->num_dev_open == 1) {
- /* Close master radio interface automatically if it was also
- * opened automatically and we are now closing the last
- * remaining non-master device. */
- dev_close(local->dev);
- }
-
- return 0;
-}
-
-
-static int prism2_open(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
-
- PDEBUG(DEBUG_FLOW, "%s: prism2_open\n", dev->name);
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->no_pri) {
- printk(KERN_DEBUG "%s: could not set interface UP - no PRI "
- "f/w\n", dev->name);
- return -ENODEV;
- }
-
- if ((local->func->card_present && !local->func->card_present(local)) ||
- local->hw_downloading)
- return -ENODEV;
-
- if (!try_module_get(local->hw_module))
- return -ENODEV;
- local->num_dev_open++;
-
- if (!local->dev_enabled && local->func->hw_enable(dev, 1)) {
- printk(KERN_WARNING "%s: could not enable MAC port\n",
- dev->name);
- prism2_close(dev);
- return -ENODEV;
- }
- if (!local->dev_enabled)
- prism2_callback(local, PRISM2_CALLBACK_ENABLE);
- local->dev_enabled = 1;
-
- if (dev != local->dev && !(local->dev->flags & IFF_UP)) {
- /* Master radio interface is needed for all operation, so open
- * it automatically when any virtual net_device is opened. */
- local->master_dev_auto_open = 1;
- dev_open(local->dev, NULL);
- }
-
- netif_device_attach(dev);
- netif_start_queue(dev);
-
- return 0;
-}
-
-
-static int prism2_set_mac_address(struct net_device *dev, void *p)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct list_head *ptr;
- struct sockaddr *addr = p;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- if (local->func->set_rid(dev, HFA384X_RID_CNFOWNMACADDR, addr->sa_data,
- ETH_ALEN) < 0 || local->func->reset_port(dev))
- return -EINVAL;
-
- read_lock_bh(&local->iface_lock);
- list_for_each(ptr, &local->hostap_interfaces) {
- iface = list_entry(ptr, struct hostap_interface, list);
- eth_hw_addr_set(iface->dev, addr->sa_data);
- }
- eth_hw_addr_set(local->dev, addr->sa_data);
- read_unlock_bh(&local->iface_lock);
-
- return 0;
-}
-
-
-/* TODO: to be further implemented as soon as Prism2 fully supports
- * GroupAddresses and correct documentation is available */
-void hostap_set_multicast_list_queue(struct work_struct *work)
-{
- local_info_t *local =
- container_of(work, local_info_t, set_multicast_list_queue);
- struct net_device *dev = local->dev;
-
- if (hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE,
- local->is_promisc)) {
- printk(KERN_INFO "%s: %sabling promiscuous mode failed\n",
- dev->name, local->is_promisc ? "en" : "dis");
- }
-}
-
-
-static void hostap_set_multicast_list(struct net_device *dev)
-{
-#if 0
- /* FIX: promiscuous mode seems to be causing a lot of problems with
- * some station firmware versions (FCSErr frames, invalid MACPort, etc.
- * corrupted incoming frames). This code is now commented out while the
- * problems are investigated. */
- struct hostap_interface *iface;
- local_info_t *local;
-
- iface = netdev_priv(dev);
- local = iface->local;
- if ((dev->flags & IFF_ALLMULTI) || (dev->flags & IFF_PROMISC)) {
- local->is_promisc = 1;
- } else {
- local->is_promisc = 0;
- }
-
- schedule_work(&local->set_multicast_list_queue);
-#endif
-}
-
-
-static void prism2_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- struct hfa384x_regs regs;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- printk(KERN_WARNING "%s Tx timed out! Resetting card\n", dev->name);
- netif_stop_queue(local->dev);
-
- local->func->read_regs(dev, &regs);
- printk(KERN_DEBUG "%s: CMD=%04x EVSTAT=%04x "
- "OFFSET0=%04x OFFSET1=%04x SWSUPPORT0=%04x\n",
- dev->name, regs.cmd, regs.evstat, regs.offset0, regs.offset1,
- regs.swsupport0);
-
- local->func->schedule_reset(local);
-}
-
-const struct header_ops hostap_80211_ops = {
- .create = eth_header,
- .cache = eth_header_cache,
- .cache_update = eth_header_cache_update,
- .parse = hostap_80211_header_parse,
-};
-EXPORT_SYMBOL(hostap_80211_ops);
-
-
-static const struct net_device_ops hostap_netdev_ops = {
- .ndo_start_xmit = hostap_data_start_xmit,
-
- .ndo_open = prism2_open,
- .ndo_stop = prism2_close,
- .ndo_do_ioctl = hostap_ioctl,
- .ndo_siocdevprivate = hostap_siocdevprivate,
- .ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_rx_mode = hostap_set_multicast_list,
- .ndo_tx_timeout = prism2_tx_timeout,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static const struct net_device_ops hostap_mgmt_netdev_ops = {
- .ndo_start_xmit = hostap_mgmt_start_xmit,
-
- .ndo_open = prism2_open,
- .ndo_stop = prism2_close,
- .ndo_do_ioctl = hostap_ioctl,
- .ndo_siocdevprivate = hostap_siocdevprivate,
- .ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_rx_mode = hostap_set_multicast_list,
- .ndo_tx_timeout = prism2_tx_timeout,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static const struct net_device_ops hostap_master_ops = {
- .ndo_start_xmit = hostap_master_start_xmit,
-
- .ndo_open = prism2_open,
- .ndo_stop = prism2_close,
- .ndo_do_ioctl = hostap_ioctl,
- .ndo_siocdevprivate = hostap_siocdevprivate,
- .ndo_set_mac_address = prism2_set_mac_address,
- .ndo_set_rx_mode = hostap_set_multicast_list,
- .ndo_tx_timeout = prism2_tx_timeout,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-void hostap_setup_dev(struct net_device *dev, local_info_t *local,
- int type)
-{
- struct hostap_interface *iface;
-
- iface = netdev_priv(dev);
- ether_setup(dev);
- dev->min_mtu = PRISM2_MIN_MTU;
- dev->max_mtu = PRISM2_MAX_MTU;
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
-
- /* kernel callbacks */
- if (iface) {
- /* Currently, we point to the proper spy_data only on
- * the main_dev. This could be fixed. Jean II */
- iface->wireless_data.spy_data = &iface->spy_data;
- dev->wireless_data = &iface->wireless_data;
- }
- dev->wireless_handlers = &hostap_iw_handler_def;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- switch(type) {
- case HOSTAP_INTERFACE_AP:
- dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */
- dev->netdev_ops = &hostap_mgmt_netdev_ops;
- dev->type = ARPHRD_IEEE80211;
- dev->header_ops = &hostap_80211_ops;
- break;
- case HOSTAP_INTERFACE_MASTER:
- dev->netdev_ops = &hostap_master_ops;
- break;
- default:
- dev->priv_flags |= IFF_NO_QUEUE; /* use main radio device queue */
- dev->netdev_ops = &hostap_netdev_ops;
- }
-
- dev->mtu = local->mtu;
-
-
- dev->ethtool_ops = &prism2_ethtool_ops;
-
-}
-
-static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- if (local->apdev)
- return -EEXIST;
-
- printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name);
-
- local->apdev = hostap_add_interface(local, HOSTAP_INTERFACE_AP,
- rtnl_locked, local->ddev->name,
- "ap");
- if (local->apdev == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-
-static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
-
- hostap_remove_interface(local->apdev, rtnl_locked, 1);
- local->apdev = NULL;
-
- return 0;
-}
-
-
-static int hostap_enable_hostapd_sta(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- if (local->stadev)
- return -EEXIST;
-
- printk(KERN_DEBUG "%s: enabling hostapd STA mode\n", dev->name);
-
- local->stadev = hostap_add_interface(local, HOSTAP_INTERFACE_STA,
- rtnl_locked, local->ddev->name,
- "sta");
- if (local->stadev == NULL)
- return -ENOMEM;
-
- return 0;
-}
-
-
-static int hostap_disable_hostapd_sta(local_info_t *local, int rtnl_locked)
-{
- struct net_device *dev = local->dev;
-
- printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name);
-
- hostap_remove_interface(local->stadev, rtnl_locked, 1);
- local->stadev = NULL;
-
- return 0;
-}
-
-
-int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked)
-{
- int ret;
-
- if (val < 0 || val > 1)
- return -EINVAL;
-
- if (local->hostapd == val)
- return 0;
-
- if (val) {
- ret = hostap_enable_hostapd(local, rtnl_locked);
- if (ret == 0)
- local->hostapd = 1;
- } else {
- local->hostapd = 0;
- ret = hostap_disable_hostapd(local, rtnl_locked);
- if (ret != 0)
- local->hostapd = 1;
- }
-
- return ret;
-}
-
-
-int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked)
-{
- int ret;
-
- if (val < 0 || val > 1)
- return -EINVAL;
-
- if (local->hostapd_sta == val)
- return 0;
-
- if (val) {
- ret = hostap_enable_hostapd_sta(local, rtnl_locked);
- if (ret == 0)
- local->hostapd_sta = 1;
- } else {
- local->hostapd_sta = 0;
- ret = hostap_disable_hostapd_sta(local, rtnl_locked);
- if (ret != 0)
- local->hostapd_sta = 1;
- }
-
-
- return ret;
-}
-
-
-int prism2_update_comms_qual(struct net_device *dev)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- int ret = 0;
- struct hfa384x_comms_quality sq;
-
- iface = netdev_priv(dev);
- local = iface->local;
- if (!local->sta_fw_ver)
- ret = -1;
- else if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1)) {
- if (local->func->get_rid(local->dev,
- HFA384X_RID_DBMCOMMSQUALITY,
- &sq, sizeof(sq), 1) >= 0) {
- local->comms_qual = (s16) le16_to_cpu(sq.comm_qual);
- local->avg_signal = (s16) le16_to_cpu(sq.signal_level);
- local->avg_noise = (s16) le16_to_cpu(sq.noise_level);
- local->last_comms_qual_update = jiffies;
- } else
- ret = -1;
- } else {
- if (local->func->get_rid(local->dev, HFA384X_RID_COMMSQUALITY,
- &sq, sizeof(sq), 1) >= 0) {
- local->comms_qual = le16_to_cpu(sq.comm_qual);
- local->avg_signal = HFA384X_LEVEL_TO_dBm(
- le16_to_cpu(sq.signal_level));
- local->avg_noise = HFA384X_LEVEL_TO_dBm(
- le16_to_cpu(sq.noise_level));
- local->last_comms_qual_update = jiffies;
- } else
- ret = -1;
- }
-
- return ret;
-}
-
-
-int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype,
- u8 *body, size_t bodylen)
-{
- struct sk_buff *skb;
- struct hostap_ieee80211_mgmt *mgmt;
- struct hostap_skb_tx_data *meta;
- struct net_device *dev = local->dev;
-
- skb = dev_alloc_skb(IEEE80211_MGMT_HDR_LEN + bodylen);
- if (skb == NULL)
- return -ENOMEM;
-
- mgmt = skb_put_zero(skb, IEEE80211_MGMT_HDR_LEN);
- mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
- memcpy(mgmt->da, dst, ETH_ALEN);
- memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
- memcpy(mgmt->bssid, dst, ETH_ALEN);
- if (body)
- skb_put_data(skb, body, bodylen);
-
- meta = (struct hostap_skb_tx_data *) skb->cb;
- memset(meta, 0, sizeof(*meta));
- meta->magic = HOSTAP_SKB_TX_DATA_MAGIC;
- meta->iface = netdev_priv(dev);
-
- skb->dev = dev;
- skb_reset_mac_header(skb);
- skb_reset_network_header(skb);
- dev_queue_xmit(skb);
-
- return 0;
-}
-
-
-int prism2_sta_deauth(local_info_t *local, u16 reason)
-{
- union iwreq_data wrqu;
- int ret;
- __le16 val = cpu_to_le16(reason);
-
- if (local->iw_mode != IW_MODE_INFRA ||
- is_zero_ether_addr(local->bssid) ||
- ether_addr_equal(local->bssid, "\x44\x44\x44\x44\x44\x44"))
- return 0;
-
- ret = prism2_sta_send_mgmt(local, local->bssid, IEEE80211_STYPE_DEAUTH,
- (u8 *) &val, 2);
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wireless_send_event(local->dev, SIOCGIWAP, &wrqu, NULL);
- return ret;
-}
-
-
-struct proc_dir_entry *hostap_proc;
-
-static int __init hostap_init(void)
-{
- if (init_net.proc_net != NULL) {
- hostap_proc = proc_mkdir("hostap", init_net.proc_net);
- if (!hostap_proc)
- printk(KERN_WARNING "Failed to mkdir "
- "/proc/net/hostap\n");
- } else
- hostap_proc = NULL;
-
- return 0;
-}
-
-
-static void __exit hostap_exit(void)
-{
- if (hostap_proc != NULL) {
- hostap_proc = NULL;
- remove_proc_entry("hostap", init_net.proc_net);
- }
-}
-
-
-EXPORT_SYMBOL(hostap_set_word);
-EXPORT_SYMBOL(hostap_set_string);
-EXPORT_SYMBOL(hostap_get_porttype);
-EXPORT_SYMBOL(hostap_set_encryption);
-EXPORT_SYMBOL(hostap_set_antsel);
-EXPORT_SYMBOL(hostap_set_roaming);
-EXPORT_SYMBOL(hostap_set_auth_algs);
-EXPORT_SYMBOL(hostap_dump_rx_header);
-EXPORT_SYMBOL(hostap_dump_tx_header);
-EXPORT_SYMBOL(hostap_80211_get_hdrlen);
-EXPORT_SYMBOL(hostap_setup_dev);
-EXPORT_SYMBOL(hostap_set_multicast_list_queue);
-EXPORT_SYMBOL(hostap_set_hostapd);
-EXPORT_SYMBOL(hostap_set_hostapd_sta);
-EXPORT_SYMBOL(hostap_add_interface);
-EXPORT_SYMBOL(hostap_remove_interface);
-EXPORT_SYMBOL(prism2_update_comms_qual);
-
-module_init(hostap_init);
-module_exit(hostap_exit);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_pci.c b/drivers/net/wireless/intersil/hostap/hostap_pci.c
deleted file mode 100644
index 52d77506effd2..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_pci.c
+++ /dev/null
@@ -1,445 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define PRISM2_PCI
-
-/* Host AP driver's support for Intersil Prism2.5 PCI cards is based on
- * driver patches from Reyk Floeter <[email protected]> and
- * Andy Warner <[email protected]> */
-
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "hostap_wlan.h"
-
-
-static char *dev_info = "hostap_pci";
-
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Support for Intersil Prism2.5-based 802.11 wireless LAN "
- "PCI cards.");
-MODULE_LICENSE("GPL");
-
-
-/* struct local_info::hw_priv */
-struct hostap_pci_priv {
- void __iomem *mem_start;
-};
-
-
-/* FIX: do we need mb/wmb/rmb with memory operations? */
-
-
-static const struct pci_device_id prism2_pci_id_table[] = {
- /* Intersil Prism3 ISL3872 11Mb/s WLAN Controller */
- { 0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID },
- /* Intersil Prism2.5 ISL3874 11Mb/s WLAN Controller */
- { 0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID },
- /* Samsung MagicLAN SWL-2210P */
- { 0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID },
- { 0 }
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-
-static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
- writeb(v, hw_priv->mem_start + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
- u8 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- v = readb(hw_priv->mem_start + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
- writew(v, hw_priv->mem_start + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- local_info_t *local;
- unsigned long flags;
- u16 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
- hw_priv = local->hw_priv;
-
- spin_lock_irqsave(&local->lock, flags);
- v = readw(hw_priv->mem_start + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
-#define HFA384X_OUTW_DATA(v,a) hfa384x_outw_debug(dev, (a), le16_to_cpu((v)))
-#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw_debug(dev, (a)))
-
-#else /* PRISM2_IO_DEBUG */
-
-static inline void hfa384x_outb(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- writeb(v, hw_priv->mem_start + a);
-}
-
-static inline u8 hfa384x_inb(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- return readb(hw_priv->mem_start + a);
-}
-
-static inline void hfa384x_outw(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- writew(v, hw_priv->mem_start + a);
-}
-
-static inline u16 hfa384x_inw(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
- return readw(hw_priv->mem_start + a);
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw(dev, (a))
-#define HFA384X_OUTW_DATA(v,a) hfa384x_outw(dev, (a), le16_to_cpu((v)))
-#define HFA384X_INW_DATA(a) cpu_to_le16(hfa384x_inw(dev, (a)))
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
- int len)
-{
- u16 d_off;
- __le16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (__le16 *) buf;
-
- for ( ; len > 1; len -= 2)
- *pos++ = HFA384X_INW_DATA(d_off);
-
- if (len & 1)
- *((char *) pos) = HFA384X_INB(d_off);
-
- return 0;
-}
-
-
-static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
-{
- u16 d_off;
- __le16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (__le16 *) buf;
-
- for ( ; len > 1; len -= 2)
- HFA384X_OUTW_DATA(*pos++, d_off);
-
- if (len & 1)
- HFA384X_OUTB(*((char *) pos), d_off);
-
- return 0;
-}
-
-
-/* FIX: This might change at some point.. */
-#include "hostap_hw.c"
-
-static void prism2_pci_cor_sreset(local_info_t *local)
-{
- struct net_device *dev = local->dev;
- u16 reg;
-
- reg = HFA384X_INB(HFA384X_PCICOR_OFF);
- printk(KERN_DEBUG "%s: Original COR value: 0x%0x\n", dev->name, reg);
-
- /* linux-wlan-ng uses extremely long hold and settle times for
- * COR sreset. A comment in the driver code mentions that the long
- * delays appear to be necessary. However, at least IBM 22P6901 seems
- * to work fine with shorter delays.
- *
- * Longer delays can be configured by uncommenting following line: */
-/* #define PRISM2_PCI_USE_LONG_DELAYS */
-
-#ifdef PRISM2_PCI_USE_LONG_DELAYS
- int i;
-
- HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
- mdelay(250);
-
- HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
- mdelay(500);
-
- /* Wait for f/w to complete initialization (CMD:BUSY == 0) */
- i = 2000000 / 10;
- while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i)
- udelay(10);
-
-#else /* PRISM2_PCI_USE_LONG_DELAYS */
-
- HFA384X_OUTW(reg | 0x0080, HFA384X_PCICOR_OFF);
- mdelay(2);
- HFA384X_OUTW(reg & ~0x0080, HFA384X_PCICOR_OFF);
- mdelay(2);
-
-#endif /* PRISM2_PCI_USE_LONG_DELAYS */
-
- if (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) {
- printk(KERN_DEBUG "%s: COR sreset timeout\n", dev->name);
- }
-}
-
-
-static void prism2_pci_genesis_reset(local_info_t *local, int hcr)
-{
- struct net_device *dev = local->dev;
-
- HFA384X_OUTW(0x00C5, HFA384X_PCICOR_OFF);
- mdelay(10);
- HFA384X_OUTW(hcr, HFA384X_PCIHCR_OFF);
- mdelay(10);
- HFA384X_OUTW(0x0045, HFA384X_PCICOR_OFF);
- mdelay(10);
-}
-
-
-static struct prism2_helper_functions prism2_pci_funcs =
-{
- .card_present = NULL,
- .cor_sreset = prism2_pci_cor_sreset,
- .genesis_reset = prism2_pci_genesis_reset,
- .hw_type = HOSTAP_HW_PCI,
-};
-
-
-static int prism2_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- unsigned long phymem;
- void __iomem *mem = NULL;
- local_info_t *local = NULL;
- struct net_device *dev = NULL;
- static int cards_found /* = 0 */;
- int irq_registered = 0;
- struct hostap_interface *iface;
- struct hostap_pci_priv *hw_priv;
-
- hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
- if (hw_priv == NULL)
- return -ENOMEM;
-
- if (pci_enable_device(pdev))
- goto err_out_free;
-
- phymem = pci_resource_start(pdev, 0);
-
- if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "Prism2")) {
- printk(KERN_ERR "prism2: Cannot reserve PCI memory region\n");
- goto err_out_disable;
- }
-
- mem = pci_ioremap_bar(pdev, 0);
- if (mem == NULL) {
- printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ;
- goto fail;
- }
-
- dev = prism2_init_local_data(&prism2_pci_funcs, cards_found,
- &pdev->dev);
- if (dev == NULL)
- goto fail;
- iface = netdev_priv(dev);
- local = iface->local;
- local->hw_priv = hw_priv;
- cards_found++;
-
- dev->irq = pdev->irq;
- hw_priv->mem_start = mem;
- dev->base_addr = (unsigned long) mem;
-
- prism2_pci_cor_sreset(local);
-
- pci_set_drvdata(pdev, dev);
-
- if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
- dev)) {
- printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
- goto fail;
- } else
- irq_registered = 1;
-
- if (!local->pri_only && prism2_hw_config(dev, 1)) {
- printk(KERN_DEBUG "%s: hardware initialization failed\n",
- dev_info);
- goto fail;
- }
-
- printk(KERN_INFO "%s: Intersil Prism2.5 PCI: "
- "mem=0x%lx, irq=%d\n", dev->name, phymem, dev->irq);
-
- return hostap_hw_ready(dev);
-
- fail:
- if (irq_registered && dev)
- free_irq(dev->irq, dev);
-
- if (mem)
- iounmap(mem);
-
- release_mem_region(phymem, pci_resource_len(pdev, 0));
-
- err_out_disable:
- pci_disable_device(pdev);
- prism2_free_local_data(dev);
-
- err_out_free:
- kfree(hw_priv);
-
- return -ENODEV;
-}
-
-
-static void prism2_pci_remove(struct pci_dev *pdev)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- void __iomem *mem_start;
- struct hostap_pci_priv *hw_priv;
-
- dev = pci_get_drvdata(pdev);
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
-
- /* Reset the hardware, and ensure interrupts are disabled. */
- prism2_pci_cor_sreset(iface->local);
- hfa384x_disable_interrupts(dev);
-
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- mem_start = hw_priv->mem_start;
- prism2_free_local_data(dev);
- kfree(hw_priv);
-
- iounmap(mem_start);
-
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- pci_disable_device(pdev);
-}
-
-static int __maybe_unused prism2_pci_suspend(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
-
- if (netif_running(dev)) {
- netif_stop_queue(dev);
- netif_device_detach(dev);
- }
- prism2_suspend(dev);
-
- return 0;
-}
-
-static int __maybe_unused prism2_pci_resume(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
-
- prism2_hw_config(dev, 0);
- if (netif_running(dev)) {
- netif_device_attach(dev);
- netif_start_queue(dev);
- }
-
- return 0;
-}
-
-MODULE_DEVICE_TABLE(pci, prism2_pci_id_table);
-
-static SIMPLE_DEV_PM_OPS(prism2_pci_pm_ops,
- prism2_pci_suspend,
- prism2_pci_resume);
-
-static struct pci_driver prism2_pci_driver = {
- .name = "hostap_pci",
- .id_table = prism2_pci_id_table,
- .probe = prism2_pci_probe,
- .remove = prism2_pci_remove,
- .driver.pm = &prism2_pci_pm_ops,
-};
-
-module_pci_driver(prism2_pci_driver);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_plx.c b/drivers/net/wireless/intersil/hostap/hostap_plx.c
deleted file mode 100644
index 58247290fcbc4..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_plx.c
+++ /dev/null
@@ -1,617 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-#define PRISM2_PLX
-
-/* Host AP driver's support for PC Cards on PCI adapters using PLX9052 is
- * based on:
- * - Host AP driver patch from [email protected]
- * - linux-wlan-ng driver, Copyright (C) AbsoluteValue Systems, Inc.
- */
-
-
-#include <linux/module.h>
-#include <linux/if.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-#include "hostap_wlan.h"
-
-
-static char *dev_info = "hostap_plx";
-
-
-MODULE_AUTHOR("Jouni Malinen");
-MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN "
- "cards (PLX).");
-MODULE_LICENSE("GPL");
-
-
-static int ignore_cis;
-module_param(ignore_cis, int, 0444);
-MODULE_PARM_DESC(ignore_cis, "Do not verify manfid information in CIS");
-
-
-/* struct local_info::hw_priv */
-struct hostap_plx_priv {
- void __iomem *attr_mem;
- unsigned int cor_offset;
-};
-
-
-#define PLX_MIN_ATTR_LEN 512 /* at least 2 x 256 is needed for CIS */
-#define COR_SRESET 0x80
-#define COR_LEVLREQ 0x40
-#define COR_ENABLE_FUNC 0x01
-/* PCI Configuration Registers */
-#define PLX_PCIIPR 0x3d /* PCI Interrupt Pin */
-/* Local Configuration Registers */
-#define PLX_INTCSR 0x4c /* Interrupt Control/Status Register */
-#define PLX_INTCSR_PCI_INTEN BIT(6) /* PCI Interrupt Enable */
-#define PLX_CNTRL 0x50
-#define PLX_CNTRL_SERIAL_EEPROM_PRESENT BIT(28)
-
-
-#define PLXDEV(vendor,dev,str) { vendor, dev, PCI_ANY_ID, PCI_ANY_ID }
-
-static const struct pci_device_id prism2_plx_id_table[] = {
- PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
- PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
- PLXDEV(0x126c, 0x8030, "Nortel emobility"),
- PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
- PLXDEV(0x1385, 0x4100, "Netgear MA301"),
- PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
- PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
- PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
- PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
- PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
- PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
- PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
- PLXDEV(0x16ec, 0x3685, "US Robotics USR2415"),
- PLXDEV(0xec80, 0xec00, "Belkin F5D6000"),
- { 0 }
-};
-
-
-/* Array of known Prism2/2.5 PC Card manufactured ids. If your card's manfid
- * is not listed here, you will need to add it here to get the driver
- * initialized. */
-static struct prism2_plx_manfid {
- u16 manfid1, manfid2;
-} prism2_plx_known_manfids[] = {
- { 0x000b, 0x7110 } /* D-Link DWL-650 Rev. P1 */,
- { 0x000b, 0x7300 } /* Philips 802.11b WLAN PCMCIA */,
- { 0x0101, 0x0777 } /* 3Com AirConnect PCI 777A */,
- { 0x0126, 0x8000 } /* Proxim RangeLAN */,
- { 0x0138, 0x0002 } /* Compaq WL100 */,
- { 0x0156, 0x0002 } /* Intersil Prism II Ref. Design (and others) */,
- { 0x026f, 0x030b } /* Buffalo WLI-CF-S11G */,
- { 0x0274, 0x1612 } /* Linksys WPC11 Ver 2.5 */,
- { 0x0274, 0x1613 } /* Linksys WPC11 Ver 3 */,
- { 0x028a, 0x0002 } /* D-Link DRC-650 */,
- { 0x0250, 0x0002 } /* Samsung SWL2000-N */,
- { 0xc250, 0x0002 } /* EMTAC A2424i */,
- { 0xd601, 0x0002 } /* Z-Com XI300 */,
- { 0xd601, 0x0005 } /* Zcomax XI-325H 200mW */,
- { 0, 0}
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-
-static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v);
- outb(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u8 hfa384x_inb_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u8 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- v = inb(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v);
- outw(v, dev->base_addr + a);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline u16 hfa384x_inw_debug(struct net_device *dev, int a)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
- u16 v;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- v = inw(dev->base_addr + a);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v);
- spin_unlock_irqrestore(&local->lock, flags);
- return v;
-}
-
-static inline void hfa384x_outsw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc);
- outsw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-static inline void hfa384x_insw_debug(struct net_device *dev, int a,
- u8 *buf, int wc)
-{
- struct hostap_interface *iface;
- local_info_t *local;
- unsigned long flags;
-
- iface = netdev_priv(dev);
- local = iface->local;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc);
- insw(dev->base_addr + a, buf, wc);
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v))
-#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a))
-#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v))
-#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a))
-#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc))
-#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc))
-
-#else /* PRISM2_IO_DEBUG */
-
-#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a))
-#define HFA384X_INB(a) inb(dev->base_addr + (a))
-#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a))
-#define HFA384X_INW(a) inw(dev->base_addr + (a))
-#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc)
-#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc)
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf,
- int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_INSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- *((char *) pos) = HFA384X_INB(d_off);
-
- return 0;
-}
-
-
-static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len)
-{
- u16 d_off;
- u16 *pos;
-
- d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF;
- pos = (u16 *) buf;
-
- if (len / 2)
- HFA384X_OUTSW(d_off, buf, len / 2);
- pos += len / 2;
-
- if (len & 1)
- HFA384X_OUTB(*((char *) pos), d_off);
-
- return 0;
-}
-
-
-/* FIX: This might change at some point.. */
-#include "hostap_hw.c"
-
-
-static void prism2_plx_cor_sreset(local_info_t *local)
-{
- unsigned char corsave;
- struct hostap_plx_priv *hw_priv = local->hw_priv;
-
- printk(KERN_DEBUG "%s: Doing reset via direct COR access.\n",
- dev_info);
-
- /* Set sreset bit of COR and clear it after hold time */
-
- if (hw_priv->attr_mem == NULL) {
- /* TMD7160 - COR at card's first I/O addr */
- corsave = inb(hw_priv->cor_offset);
- outb(corsave | COR_SRESET, hw_priv->cor_offset);
- mdelay(2);
- outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
- mdelay(2);
- } else {
- /* PLX9052 */
- corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
- writeb(corsave | COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(2);
- writeb(corsave & ~COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(2);
- }
-}
-
-
-static void prism2_plx_genesis_reset(local_info_t *local, int hcr)
-{
- unsigned char corsave;
- struct hostap_plx_priv *hw_priv = local->hw_priv;
-
- if (hw_priv->attr_mem == NULL) {
- /* TMD7160 - COR at card's first I/O addr */
- corsave = inb(hw_priv->cor_offset);
- outb(corsave | COR_SRESET, hw_priv->cor_offset);
- mdelay(10);
- outb(hcr, hw_priv->cor_offset + 2);
- mdelay(10);
- outb(corsave & ~COR_SRESET, hw_priv->cor_offset);
- mdelay(10);
- } else {
- /* PLX9052 */
- corsave = readb(hw_priv->attr_mem + hw_priv->cor_offset);
- writeb(corsave | COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(10);
- writeb(hcr, hw_priv->attr_mem + hw_priv->cor_offset + 2);
- mdelay(10);
- writeb(corsave & ~COR_SRESET,
- hw_priv->attr_mem + hw_priv->cor_offset);
- mdelay(10);
- }
-}
-
-
-static struct prism2_helper_functions prism2_plx_funcs =
-{
- .card_present = NULL,
- .cor_sreset = prism2_plx_cor_sreset,
- .genesis_reset = prism2_plx_genesis_reset,
- .hw_type = HOSTAP_HW_PLX,
-};
-
-
-static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len,
- unsigned int *cor_offset,
- unsigned int *cor_index)
-{
-#define CISTPL_CONFIG 0x1A
-#define CISTPL_MANFID 0x20
-#define CISTPL_END 0xFF
-#define CIS_MAX_LEN 256
- u8 *cis;
- int i, pos;
- unsigned int rmsz, rasz, manfid1, manfid2;
- struct prism2_plx_manfid *manfid;
-
- cis = kmalloc(CIS_MAX_LEN, GFP_KERNEL);
- if (cis == NULL)
- return -ENOMEM;
-
- /* read CIS; it is in even offsets in the beginning of attr_mem */
- for (i = 0; i < CIS_MAX_LEN; i++)
- cis[i] = readb(attr_mem + 2 * i);
- printk(KERN_DEBUG "%s: CIS: %6ph ...\n", dev_info, cis);
-
- /* set reasonable defaults for Prism2 cards just in case CIS parsing
- * fails */
- *cor_offset = 0x3e0;
- *cor_index = 0x01;
- manfid1 = manfid2 = 0;
-
- pos = 0;
- while (pos < CIS_MAX_LEN - 1 && cis[pos] != CISTPL_END) {
- if (pos + 2 + cis[pos + 1] > CIS_MAX_LEN)
- goto cis_error;
-
- switch (cis[pos]) {
- case CISTPL_CONFIG:
- if (cis[pos + 1] < 2)
- goto cis_error;
- rmsz = (cis[pos + 2] & 0x3c) >> 2;
- rasz = cis[pos + 2] & 0x03;
- if (4 + rasz + rmsz > cis[pos + 1])
- goto cis_error;
- *cor_index = cis[pos + 3] & 0x3F;
- *cor_offset = 0;
- for (i = 0; i <= rasz; i++)
- *cor_offset += cis[pos + 4 + i] << (8 * i);
- printk(KERN_DEBUG "%s: cor_index=0x%x "
- "cor_offset=0x%x\n", dev_info,
- *cor_index, *cor_offset);
- if (*cor_offset > attr_len) {
- printk(KERN_ERR "%s: COR offset not within "
- "attr_mem\n", dev_info);
- kfree(cis);
- return -1;
- }
- break;
-
- case CISTPL_MANFID:
- if (cis[pos + 1] < 4)
- goto cis_error;
- manfid1 = cis[pos + 2] + (cis[pos + 3] << 8);
- manfid2 = cis[pos + 4] + (cis[pos + 5] << 8);
- printk(KERN_DEBUG "%s: manfid=0x%04x, 0x%04x\n",
- dev_info, manfid1, manfid2);
- break;
- }
-
- pos += cis[pos + 1] + 2;
- }
-
- if (pos >= CIS_MAX_LEN || cis[pos] != CISTPL_END)
- goto cis_error;
-
- for (manfid = prism2_plx_known_manfids; manfid->manfid1 != 0; manfid++)
- if (manfid1 == manfid->manfid1 && manfid2 == manfid->manfid2) {
- kfree(cis);
- return 0;
- }
-
- printk(KERN_INFO "%s: unknown manfid 0x%04x, 0x%04x - assuming this is"
- " not supported card\n", dev_info, manfid1, manfid2);
- goto fail;
-
- cis_error:
- printk(KERN_WARNING "%s: invalid CIS data\n", dev_info);
-
- fail:
- kfree(cis);
- if (ignore_cis) {
- printk(KERN_INFO "%s: ignore_cis parameter set - ignoring "
- "errors during CIS verification\n", dev_info);
- return 0;
- }
- return -1;
-}
-
-
-static int prism2_plx_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- unsigned int pccard_ioaddr, plx_ioaddr;
- unsigned long pccard_attr_mem;
- unsigned int pccard_attr_len;
- void __iomem *attr_mem = NULL;
- unsigned int cor_offset = 0, cor_index = 0;
- u32 reg;
- local_info_t *local = NULL;
- struct net_device *dev = NULL;
- struct hostap_interface *iface;
- static int cards_found /* = 0 */;
- int irq_registered = 0;
- int tmd7160;
- struct hostap_plx_priv *hw_priv;
-
- hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL);
- if (hw_priv == NULL)
- return -ENOMEM;
-
- if (pci_enable_device(pdev))
- goto err_out_free;
-
- /* National Datacomm NCP130 based on TMD7160, not PLX9052. */
- tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131);
-
- plx_ioaddr = pci_resource_start(pdev, 1);
- pccard_ioaddr = pci_resource_start(pdev, tmd7160 ? 2 : 3);
-
- if (tmd7160) {
- /* TMD7160 */
- attr_mem = NULL; /* no access to PC Card attribute memory */
-
- printk(KERN_INFO "TMD7160 PCI/PCMCIA adapter: io=0x%x, "
- "irq=%d, pccard_io=0x%x\n",
- plx_ioaddr, pdev->irq, pccard_ioaddr);
-
- cor_offset = plx_ioaddr;
- cor_index = 0x04;
-
- outb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, plx_ioaddr);
- mdelay(1);
- reg = inb(plx_ioaddr);
- if (reg != (cor_index | COR_LEVLREQ | COR_ENABLE_FUNC)) {
- printk(KERN_ERR "%s: Error setting COR (expected="
- "0x%02x, was=0x%02x)\n", dev_info,
- cor_index | COR_LEVLREQ | COR_ENABLE_FUNC, reg);
- goto fail;
- }
- } else {
- /* PLX9052 */
- pccard_attr_mem = pci_resource_start(pdev, 2);
- pccard_attr_len = pci_resource_len(pdev, 2);
- if (pccard_attr_len < PLX_MIN_ATTR_LEN)
- goto fail;
-
-
- attr_mem = ioremap(pccard_attr_mem, pccard_attr_len);
- if (attr_mem == NULL) {
- printk(KERN_ERR "%s: cannot remap attr_mem\n",
- dev_info);
- goto fail;
- }
-
- printk(KERN_INFO "PLX9052 PCI/PCMCIA adapter: "
- "mem=0x%lx, plx_io=0x%x, irq=%d, pccard_io=0x%x\n",
- pccard_attr_mem, plx_ioaddr, pdev->irq, pccard_ioaddr);
-
- if (prism2_plx_check_cis(attr_mem, pccard_attr_len,
- &cor_offset, &cor_index)) {
- printk(KERN_INFO "Unknown PC Card CIS - not a "
- "Prism2/2.5 card?\n");
- goto fail;
- }
-
- printk(KERN_DEBUG "Prism2/2.5 PC Card detected in PLX9052 "
- "adapter\n");
-
- /* Write COR to enable PC Card */
- writeb(cor_index | COR_LEVLREQ | COR_ENABLE_FUNC,
- attr_mem + cor_offset);
-
- /* Enable PCI interrupts if they are not already enabled */
- reg = inl(plx_ioaddr + PLX_INTCSR);
- printk(KERN_DEBUG "PLX_INTCSR=0x%x\n", reg);
- if (!(reg & PLX_INTCSR_PCI_INTEN)) {
- outl(reg | PLX_INTCSR_PCI_INTEN,
- plx_ioaddr + PLX_INTCSR);
- if (!(inl(plx_ioaddr + PLX_INTCSR) &
- PLX_INTCSR_PCI_INTEN)) {
- printk(KERN_WARNING "%s: Could not enable "
- "Local Interrupts\n", dev_info);
- goto fail;
- }
- }
-
- reg = inl(plx_ioaddr + PLX_CNTRL);
- printk(KERN_DEBUG "PLX_CNTRL=0x%x (Serial EEPROM "
- "present=%d)\n",
- reg, (reg & PLX_CNTRL_SERIAL_EEPROM_PRESENT) != 0);
- /* should set PLX_PCIIPR to 0x01 (INTA#) if Serial EEPROM is
- * not present; but are there really such cards in use(?) */
- }
-
- dev = prism2_init_local_data(&prism2_plx_funcs, cards_found,
- &pdev->dev);
- if (dev == NULL)
- goto fail;
- iface = netdev_priv(dev);
- local = iface->local;
- local->hw_priv = hw_priv;
- cards_found++;
-
- dev->irq = pdev->irq;
- dev->base_addr = pccard_ioaddr;
- hw_priv->attr_mem = attr_mem;
- hw_priv->cor_offset = cor_offset;
-
- pci_set_drvdata(pdev, dev);
-
- if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
- dev)) {
- printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
- goto fail;
- } else
- irq_registered = 1;
-
- if (prism2_hw_config(dev, 1)) {
- printk(KERN_DEBUG "%s: hardware initialization failed\n",
- dev_info);
- goto fail;
- }
-
- return hostap_hw_ready(dev);
-
- fail:
- if (irq_registered && dev)
- free_irq(dev->irq, dev);
-
- if (attr_mem)
- iounmap(attr_mem);
-
- pci_disable_device(pdev);
- prism2_free_local_data(dev);
-
- err_out_free:
- kfree(hw_priv);
-
- return -ENODEV;
-}
-
-
-static void prism2_plx_remove(struct pci_dev *pdev)
-{
- struct net_device *dev;
- struct hostap_interface *iface;
- struct hostap_plx_priv *hw_priv;
-
- dev = pci_get_drvdata(pdev);
- iface = netdev_priv(dev);
- hw_priv = iface->local->hw_priv;
-
- /* Reset the hardware, and ensure interrupts are disabled. */
- prism2_plx_cor_sreset(iface->local);
- hfa384x_disable_interrupts(dev);
-
- if (hw_priv->attr_mem)
- iounmap(hw_priv->attr_mem);
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- prism2_free_local_data(dev);
- kfree(hw_priv);
- pci_disable_device(pdev);
-}
-
-
-MODULE_DEVICE_TABLE(pci, prism2_plx_id_table);
-
-static struct pci_driver prism2_plx_driver = {
- .name = "hostap_plx",
- .id_table = prism2_plx_id_table,
- .probe = prism2_plx_probe,
- .remove = prism2_plx_remove,
-};
-
-module_pci_driver(prism2_plx_driver);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_proc.c b/drivers/net/wireless/intersil/hostap/hostap_proc.c
deleted file mode 100644
index 61f68786056f4..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_proc.c
+++ /dev/null
@@ -1,411 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* /proc routines for Host AP driver */
-
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/export.h>
-#include <net/lib80211.h>
-
-#include "hostap_wlan.h"
-#include "hostap.h"
-
-#define PROC_LIMIT (PAGE_SIZE - 80)
-
-#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS)
-static int prism2_debug_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
- int i;
-
- seq_printf(m, "next_txfid=%d next_alloc=%d\n",
- local->next_txfid, local->next_alloc);
- for (i = 0; i < PRISM2_TXFID_COUNT; i++)
- seq_printf(m, "FID: tx=%04X intransmit=%04X\n",
- local->txfid[i], local->intransmitfid[i]);
- seq_printf(m, "FW TX rate control: %d\n", local->fw_tx_rate_control);
- seq_printf(m, "beacon_int=%d\n", local->beacon_int);
- seq_printf(m, "dtim_period=%d\n", local->dtim_period);
- seq_printf(m, "wds_max_connections=%d\n", local->wds_max_connections);
- seq_printf(m, "dev_enabled=%d\n", local->dev_enabled);
- seq_printf(m, "sw_tick_stuck=%d\n", local->sw_tick_stuck);
- for (i = 0; i < WEP_KEYS; i++) {
- if (local->crypt_info.crypt[i] &&
- local->crypt_info.crypt[i]->ops) {
- seq_printf(m, "crypt[%d]=%s\n", i,
- local->crypt_info.crypt[i]->ops->name);
- }
- }
- seq_printf(m, "pri_only=%d\n", local->pri_only);
- seq_printf(m, "pci=%d\n", local->func->hw_type == HOSTAP_HW_PCI);
- seq_printf(m, "sram_type=%d\n", local->sram_type);
- seq_printf(m, "no_pri=%d\n", local->no_pri);
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_PROC_FS
-static int prism2_stats_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
- struct comm_tallies_sums *sums = &local->comm_tallies;
-
- seq_printf(m, "TxUnicastFrames=%u\n", sums->tx_unicast_frames);
- seq_printf(m, "TxMulticastframes=%u\n", sums->tx_multicast_frames);
- seq_printf(m, "TxFragments=%u\n", sums->tx_fragments);
- seq_printf(m, "TxUnicastOctets=%u\n", sums->tx_unicast_octets);
- seq_printf(m, "TxMulticastOctets=%u\n", sums->tx_multicast_octets);
- seq_printf(m, "TxDeferredTransmissions=%u\n",
- sums->tx_deferred_transmissions);
- seq_printf(m, "TxSingleRetryFrames=%u\n", sums->tx_single_retry_frames);
- seq_printf(m, "TxMultipleRetryFrames=%u\n",
- sums->tx_multiple_retry_frames);
- seq_printf(m, "TxRetryLimitExceeded=%u\n",
- sums->tx_retry_limit_exceeded);
- seq_printf(m, "TxDiscards=%u\n", sums->tx_discards);
- seq_printf(m, "RxUnicastFrames=%u\n", sums->rx_unicast_frames);
- seq_printf(m, "RxMulticastFrames=%u\n", sums->rx_multicast_frames);
- seq_printf(m, "RxFragments=%u\n", sums->rx_fragments);
- seq_printf(m, "RxUnicastOctets=%u\n", sums->rx_unicast_octets);
- seq_printf(m, "RxMulticastOctets=%u\n", sums->rx_multicast_octets);
- seq_printf(m, "RxFCSErrors=%u\n", sums->rx_fcs_errors);
- seq_printf(m, "RxDiscardsNoBuffer=%u\n", sums->rx_discards_no_buffer);
- seq_printf(m, "TxDiscardsWrongSA=%u\n", sums->tx_discards_wrong_sa);
- seq_printf(m, "RxDiscardsWEPUndecryptable=%u\n",
- sums->rx_discards_wep_undecryptable);
- seq_printf(m, "RxMessageInMsgFragments=%u\n",
- sums->rx_message_in_msg_fragments);
- seq_printf(m, "RxMessageInBadMsgFragments=%u\n",
- sums->rx_message_in_bad_msg_fragments);
- /* FIX: this may grow too long for one page(?) */
-
- return 0;
-}
-#endif
-
-static int prism2_wds_proc_show(struct seq_file *m, void *v)
-{
- struct list_head *ptr = v;
- struct hostap_interface *iface;
-
- iface = list_entry(ptr, struct hostap_interface, list);
- if (iface->type == HOSTAP_INTERFACE_WDS)
- seq_printf(m, "%s\t%pM\n",
- iface->dev->name, iface->u.wds.remote_addr);
- return 0;
-}
-
-static void *prism2_wds_proc_start(struct seq_file *m, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- read_lock_bh(&local->iface_lock);
- return seq_list_start(&local->hostap_interfaces, *_pos);
-}
-
-static void *prism2_wds_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- return seq_list_next(v, &local->hostap_interfaces, _pos);
-}
-
-static void prism2_wds_proc_stop(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- read_unlock_bh(&local->iface_lock);
-}
-
-static const struct seq_operations prism2_wds_proc_seqops = {
- .start = prism2_wds_proc_start,
- .next = prism2_wds_proc_next,
- .stop = prism2_wds_proc_stop,
- .show = prism2_wds_proc_show,
-};
-
-static int prism2_bss_list_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- struct list_head *ptr = v;
- struct hostap_bss_info *bss;
-
- if (ptr == &local->bss_list) {
- seq_printf(m, "#BSSID\tlast_update\tcount\tcapab_info\tSSID(txt)\t"
- "SSID(hex)\tWPA IE\n");
- return 0;
- }
-
- bss = list_entry(ptr, struct hostap_bss_info, list);
- seq_printf(m, "%pM\t%lu\t%u\t0x%x\t",
- bss->bssid, bss->last_update,
- bss->count, bss->capab_info);
-
- seq_printf(m, "%*pE", (int)bss->ssid_len, bss->ssid);
-
- seq_putc(m, '\t');
- seq_printf(m, "%*phN", (int)bss->ssid_len, bss->ssid);
- seq_putc(m, '\t');
- seq_printf(m, "%*phN", (int)bss->wpa_ie_len, bss->wpa_ie);
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *prism2_bss_list_proc_start(struct seq_file *m, loff_t *_pos)
- __acquires(&local->lock)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_lock_bh(&local->lock);
- return seq_list_start_head(&local->bss_list, *_pos);
-}
-
-static void *prism2_bss_list_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- return seq_list_next(v, &local->bss_list, _pos);
-}
-
-static void prism2_bss_list_proc_stop(struct seq_file *m, void *v)
- __releases(&local->lock)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_unlock_bh(&local->lock);
-}
-
-static const struct seq_operations prism2_bss_list_proc_seqops = {
- .start = prism2_bss_list_proc_start,
- .next = prism2_bss_list_proc_next,
- .stop = prism2_bss_list_proc_stop,
- .show = prism2_bss_list_proc_show,
-};
-
-#ifdef CONFIG_PROC_FS
-static int prism2_crypt_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = m->private;
- int i;
-
- seq_printf(m, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx);
- for (i = 0; i < WEP_KEYS; i++) {
- if (local->crypt_info.crypt[i] &&
- local->crypt_info.crypt[i]->ops &&
- local->crypt_info.crypt[i]->ops->print_stats) {
- local->crypt_info.crypt[i]->ops->print_stats(
- m, local->crypt_info.crypt[i]->priv);
- }
- }
- return 0;
-}
-#endif
-
-static ssize_t prism2_pda_proc_read(struct file *file, char __user *buf,
- size_t count, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(file));
- size_t off;
-
- if (local->pda == NULL || *_pos >= PRISM2_PDA_SIZE)
- return 0;
-
- off = *_pos;
- if (count > PRISM2_PDA_SIZE - off)
- count = PRISM2_PDA_SIZE - off;
- if (copy_to_user(buf, local->pda + off, count) != 0)
- return -EFAULT;
- *_pos += count;
- return count;
-}
-
-static const struct proc_ops prism2_pda_proc_ops = {
- .proc_read = prism2_pda_proc_read,
- .proc_lseek = generic_file_llseek,
-};
-
-
-static ssize_t prism2_aux_dump_proc_no_read(struct file *file, char __user *buf,
- size_t bufsize, loff_t *_pos)
-{
- return 0;
-}
-
-static const struct proc_ops prism2_aux_dump_proc_ops = {
- .proc_read = prism2_aux_dump_proc_no_read,
- .proc_lseek = default_llseek,
-};
-
-
-#ifdef PRISM2_IO_DEBUG
-static int prism2_io_debug_proc_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- local_info_t *local = (local_info_t *) data;
- int head = local->io_debug_head;
- int start_bytes, left, copy;
-
- if (off + count > PRISM2_IO_DEBUG_SIZE * 4) {
- *eof = 1;
- if (off >= PRISM2_IO_DEBUG_SIZE * 4)
- return 0;
- count = PRISM2_IO_DEBUG_SIZE * 4 - off;
- }
-
- start_bytes = (PRISM2_IO_DEBUG_SIZE - head) * 4;
- left = count;
-
- if (off < start_bytes) {
- copy = start_bytes - off;
- if (copy > count)
- copy = count;
- memcpy(page, ((u8 *) &local->io_debug[head]) + off, copy);
- left -= copy;
- if (left > 0)
- memcpy(&page[copy], local->io_debug, left);
- } else {
- memcpy(page, ((u8 *) local->io_debug) + (off - start_bytes),
- left);
- }
-
- *start = page;
-
- return count;
-}
-#endif /* PRISM2_IO_DEBUG */
-
-
-#ifndef PRISM2_NO_STATION_MODES
-static int prism2_scan_results_proc_show(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- unsigned long entry;
- int i, len;
- struct hfa384x_hostscan_result *scanres;
- u8 *p;
-
- if (v == SEQ_START_TOKEN) {
- seq_printf(m,
- "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates SSID\n");
- return 0;
- }
-
- entry = (unsigned long)v - 2;
- scanres = &local->last_scan_results[entry];
-
- seq_printf(m, "%d %d %d %d 0x%02x %d %pM %d ",
- le16_to_cpu(scanres->chid),
- (s16) le16_to_cpu(scanres->anl),
- (s16) le16_to_cpu(scanres->sl),
- le16_to_cpu(scanres->beacon_interval),
- le16_to_cpu(scanres->capability),
- le16_to_cpu(scanres->rate),
- scanres->bssid,
- le16_to_cpu(scanres->atim));
-
- p = scanres->sup_rates;
- for (i = 0; i < sizeof(scanres->sup_rates); i++) {
- if (p[i] == 0)
- break;
- seq_printf(m, "<%02x>", p[i]);
- }
- seq_putc(m, ' ');
-
- p = scanres->ssid;
- len = le16_to_cpu(scanres->ssid_len);
- if (len > 32)
- len = 32;
- for (i = 0; i < len; i++) {
- unsigned char c = p[i];
- if (c >= 32 && c < 127)
- seq_putc(m, c);
- else
- seq_printf(m, "<%02x>", c);
- }
- seq_putc(m, '\n');
- return 0;
-}
-
-static void *prism2_scan_results_proc_start(struct seq_file *m, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_lock_bh(&local->lock);
-
- /* We have a header (pos 0) + N results to show (pos 1...N) */
- if (*_pos > local->last_scan_results_count)
- return NULL;
- return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
-}
-
-static void *prism2_scan_results_proc_next(struct seq_file *m, void *v, loff_t *_pos)
-{
- local_info_t *local = pde_data(file_inode(m->file));
-
- ++*_pos;
- if (*_pos > local->last_scan_results_count)
- return NULL;
- return (void *)(unsigned long)(*_pos + 1); /* 0 would be EOF */
-}
-
-static void prism2_scan_results_proc_stop(struct seq_file *m, void *v)
-{
- local_info_t *local = pde_data(file_inode(m->file));
- spin_unlock_bh(&local->lock);
-}
-
-static const struct seq_operations prism2_scan_results_proc_seqops = {
- .start = prism2_scan_results_proc_start,
- .next = prism2_scan_results_proc_next,
- .stop = prism2_scan_results_proc_stop,
- .show = prism2_scan_results_proc_show,
-};
-#endif /* PRISM2_NO_STATION_MODES */
-
-
-void hostap_init_proc(local_info_t *local)
-{
- local->proc = NULL;
-
- if (hostap_proc == NULL) {
- printk(KERN_WARNING "%s: hostap proc directory not created\n",
- local->dev->name);
- return;
- }
-
- local->proc = proc_mkdir(local->ddev->name, hostap_proc);
- if (local->proc == NULL) {
- printk(KERN_INFO "/proc/net/hostap/%s creation failed\n",
- local->ddev->name);
- return;
- }
-
-#ifndef PRISM2_NO_PROCFS_DEBUG
- proc_create_single_data("debug", 0, local->proc,
- prism2_debug_proc_show, local);
-#endif /* PRISM2_NO_PROCFS_DEBUG */
- proc_create_single_data("stats", 0, local->proc, prism2_stats_proc_show,
- local);
- proc_create_seq_data("wds", 0, local->proc,
- &prism2_wds_proc_seqops, local);
- proc_create_data("pda", 0, local->proc,
- &prism2_pda_proc_ops, local);
- proc_create_data("aux_dump", 0, local->proc,
- local->func->read_aux_proc_ops ?: &prism2_aux_dump_proc_ops,
- local);
- proc_create_seq_data("bss_list", 0, local->proc,
- &prism2_bss_list_proc_seqops, local);
- proc_create_single_data("crypt", 0, local->proc, prism2_crypt_proc_show,
- local);
-#ifdef PRISM2_IO_DEBUG
- proc_create_single_data("io_debug", 0, local->proc,
- prism2_debug_proc_show, local);
-#endif /* PRISM2_IO_DEBUG */
-#ifndef PRISM2_NO_STATION_MODES
- proc_create_seq_data("scan_results", 0, local->proc,
- &prism2_scan_results_proc_seqops, local);
-#endif /* PRISM2_NO_STATION_MODES */
-}
-
-
-void hostap_remove_proc(local_info_t *local)
-{
- proc_remove(local->proc);
-}
-
-
-EXPORT_SYMBOL(hostap_init_proc);
-EXPORT_SYMBOL(hostap_remove_proc);
diff --git a/drivers/net/wireless/intersil/hostap/hostap_wlan.h b/drivers/net/wireless/intersil/hostap/hostap_wlan.h
deleted file mode 100644
index c25cd21d18bd9..0000000000000
--- a/drivers/net/wireless/intersil/hostap/hostap_wlan.h
+++ /dev/null
@@ -1,1051 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef HOSTAP_WLAN_H
-#define HOSTAP_WLAN_H
-
-#include <linux/interrupt.h>
-#include <linux/wireless.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/mutex.h>
-#include <linux/refcount.h>
-#include <net/iw_handler.h>
-#include <net/ieee80211_radiotap.h>
-#include <net/lib80211.h>
-
-#include "hostap_config.h"
-#include "hostap_common.h"
-
-#define MAX_PARM_DEVICES 8
-#define PARM_MIN_MAX "1-" __MODULE_STRING(MAX_PARM_DEVICES)
-#define DEF_INTS -1, -1, -1, -1, -1, -1, -1
-#define GET_INT_PARM(var,idx) var[var[idx] < 0 ? 0 : idx]
-
-
-/* Specific skb->protocol value that indicates that the packet already contains
- * txdesc header.
- * FIX: This might need own value that would be allocated especially for Prism2
- * txdesc; ETH_P_CONTROL is commented as "Card specific control frames".
- * However, these skb's should have only minimal path in the kernel side since
- * prism2_send_mgmt() sends these with dev_queue_xmit() to prism2_tx(). */
-#define ETH_P_HOSTAP ETH_P_CONTROL
-
-/* ARPHRD_IEEE80211_PRISM uses a bloated version of Prism2 RX frame header
- * (from linux-wlan-ng) */
-struct linux_wlan_ng_val {
- u32 did;
- u16 status, len;
- u32 data;
-} __packed;
-
-struct linux_wlan_ng_prism_hdr {
- u32 msgcode, msglen;
- char devname[16];
- struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal,
- noise, rate, istx, frmlen;
-} __packed;
-
-struct linux_wlan_ng_cap_hdr {
- __be32 version;
- __be32 length;
- __be64 mactime;
- __be64 hosttime;
- __be32 phytype;
- __be32 channel;
- __be32 datarate;
- __be32 antenna;
- __be32 priority;
- __be32 ssi_type;
- __be32 ssi_signal;
- __be32 ssi_noise;
- __be32 preamble;
- __be32 encoding;
-} __packed;
-
-struct hostap_radiotap_rx {
- struct ieee80211_radiotap_header hdr;
- __le64 tsft;
- u8 rate;
- u8 padding;
- __le16 chan_freq;
- __le16 chan_flags;
- s8 dbm_antsignal;
- s8 dbm_antnoise;
-} __packed;
-
-#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */
-#define LWNG_CAPHDR_VERSION 0x80211001
-
-struct hfa384x_rx_frame {
- /* HFA384X RX frame descriptor */
- __le16 status; /* HFA384X_RX_STATUS_ flags */
- __le32 time; /* timestamp, 1 microsecond resolution */
- u8 silence; /* 27 .. 154; seems to be 0 */
- u8 signal; /* 27 .. 154 */
- u8 rate; /* 10, 20, 55, or 110 */
- u8 rxflow;
- __le32 reserved;
-
- /* 802.11 */
- __le16 frame_control;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctrl;
- u8 addr4[ETH_ALEN];
- __le16 data_len;
-
- /* 802.3 */
- u8 dst_addr[ETH_ALEN];
- u8 src_addr[ETH_ALEN];
- __be16 len;
-
- /* followed by frame data; max 2304 bytes */
-} __packed;
-
-
-struct hfa384x_tx_frame {
- /* HFA384X TX frame descriptor */
- __le16 status; /* HFA384X_TX_STATUS_ flags */
- __le16 reserved1;
- __le16 reserved2;
- __le32 sw_support;
- u8 retry_count; /* not yet implemented */
- u8 tx_rate; /* Host AP only; 0 = firmware, or 10, 20, 55, 110 */
- __le16 tx_control; /* HFA384X_TX_CTRL_ flags */
-
- /* 802.11 */
- struct_group(header,
- __le16 frame_control; /* parts not used */
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN]; /* filled by firmware */
- u8 addr3[ETH_ALEN];
- __le16 seq_ctrl; /* filled by firmware */
- );
- u8 addr4[ETH_ALEN];
- __le16 data_len;
-
- /* 802.3 */
- u8 dst_addr[ETH_ALEN];
- u8 src_addr[ETH_ALEN];
- __be16 len;
-
- /* followed by frame data; max 2304 bytes */
-} __packed;
-
-
-struct hfa384x_rid_hdr
-{
- __le16 len;
- __le16 rid;
-} __packed;
-
-
-/* Macro for converting signal levels (range 27 .. 154) to wireless ext
- * dBm value with some accuracy */
-#define HFA384X_LEVEL_TO_dBm(v) 0x100 + (v) * 100 / 255 - 100
-
-#define HFA384X_LEVEL_TO_dBm_sign(v) (v) * 100 / 255 - 100
-
-struct hfa384x_scan_request {
- __le16 channel_list;
- __le16 txrate; /* HFA384X_RATES_* */
-} __packed;
-
-struct hfa384x_hostscan_request {
- __le16 channel_list;
- __le16 txrate;
- __le16 target_ssid_len;
- u8 target_ssid[32];
-} __packed;
-
-struct hfa384x_join_request {
- u8 bssid[ETH_ALEN];
- __le16 channel;
-} __packed;
-
-struct hfa384x_info_frame {
- __le16 len;
- __le16 type;
-} __packed;
-
-struct hfa384x_comm_tallies {
- __le16 tx_unicast_frames;
- __le16 tx_multicast_frames;
- __le16 tx_fragments;
- __le16 tx_unicast_octets;
- __le16 tx_multicast_octets;
- __le16 tx_deferred_transmissions;
- __le16 tx_single_retry_frames;
- __le16 tx_multiple_retry_frames;
- __le16 tx_retry_limit_exceeded;
- __le16 tx_discards;
- __le16 rx_unicast_frames;
- __le16 rx_multicast_frames;
- __le16 rx_fragments;
- __le16 rx_unicast_octets;
- __le16 rx_multicast_octets;
- __le16 rx_fcs_errors;
- __le16 rx_discards_no_buffer;
- __le16 tx_discards_wrong_sa;
- __le16 rx_discards_wep_undecryptable;
- __le16 rx_message_in_msg_fragments;
- __le16 rx_message_in_bad_msg_fragments;
-} __packed;
-
-struct hfa384x_comm_tallies32 {
- __le32 tx_unicast_frames;
- __le32 tx_multicast_frames;
- __le32 tx_fragments;
- __le32 tx_unicast_octets;
- __le32 tx_multicast_octets;
- __le32 tx_deferred_transmissions;
- __le32 tx_single_retry_frames;
- __le32 tx_multiple_retry_frames;
- __le32 tx_retry_limit_exceeded;
- __le32 tx_discards;
- __le32 rx_unicast_frames;
- __le32 rx_multicast_frames;
- __le32 rx_fragments;
- __le32 rx_unicast_octets;
- __le32 rx_multicast_octets;
- __le32 rx_fcs_errors;
- __le32 rx_discards_no_buffer;
- __le32 tx_discards_wrong_sa;
- __le32 rx_discards_wep_undecryptable;
- __le32 rx_message_in_msg_fragments;
- __le32 rx_message_in_bad_msg_fragments;
-} __packed;
-
-struct hfa384x_scan_result_hdr {
- __le16 reserved;
- __le16 scan_reason;
-#define HFA384X_SCAN_IN_PROGRESS 0 /* no results available yet */
-#define HFA384X_SCAN_HOST_INITIATED 1
-#define HFA384X_SCAN_FIRMWARE_INITIATED 2
-#define HFA384X_SCAN_INQUIRY_FROM_HOST 3
-} __packed;
-
-#define HFA384X_SCAN_MAX_RESULTS 32
-
-struct hfa384x_scan_result {
- __le16 chid;
- __le16 anl;
- __le16 sl;
- u8 bssid[ETH_ALEN];
- __le16 beacon_interval;
- __le16 capability;
- __le16 ssid_len;
- u8 ssid[32];
- u8 sup_rates[10];
- __le16 rate;
-} __packed;
-
-struct hfa384x_hostscan_result {
- __le16 chid;
- __le16 anl;
- __le16 sl;
- u8 bssid[ETH_ALEN];
- __le16 beacon_interval;
- __le16 capability;
- __le16 ssid_len;
- u8 ssid[32];
- u8 sup_rates[10];
- __le16 rate;
- __le16 atim;
-} __packed;
-
-struct comm_tallies_sums {
- unsigned int tx_unicast_frames;
- unsigned int tx_multicast_frames;
- unsigned int tx_fragments;
- unsigned int tx_unicast_octets;
- unsigned int tx_multicast_octets;
- unsigned int tx_deferred_transmissions;
- unsigned int tx_single_retry_frames;
- unsigned int tx_multiple_retry_frames;
- unsigned int tx_retry_limit_exceeded;
- unsigned int tx_discards;
- unsigned int rx_unicast_frames;
- unsigned int rx_multicast_frames;
- unsigned int rx_fragments;
- unsigned int rx_unicast_octets;
- unsigned int rx_multicast_octets;
- unsigned int rx_fcs_errors;
- unsigned int rx_discards_no_buffer;
- unsigned int tx_discards_wrong_sa;
- unsigned int rx_discards_wep_undecryptable;
- unsigned int rx_message_in_msg_fragments;
- unsigned int rx_message_in_bad_msg_fragments;
-};
-
-
-struct hfa384x_regs {
- u16 cmd;
- u16 evstat;
- u16 offset0;
- u16 offset1;
- u16 swsupport0;
-};
-
-
-#if defined(PRISM2_PCCARD) || defined(PRISM2_PLX)
-/* I/O ports for HFA384X Controller access */
-#define HFA384X_CMD_OFF 0x00
-#define HFA384X_PARAM0_OFF 0x02
-#define HFA384X_PARAM1_OFF 0x04
-#define HFA384X_PARAM2_OFF 0x06
-#define HFA384X_STATUS_OFF 0x08
-#define HFA384X_RESP0_OFF 0x0A
-#define HFA384X_RESP1_OFF 0x0C
-#define HFA384X_RESP2_OFF 0x0E
-#define HFA384X_INFOFID_OFF 0x10
-#define HFA384X_CONTROL_OFF 0x14
-#define HFA384X_SELECT0_OFF 0x18
-#define HFA384X_SELECT1_OFF 0x1A
-#define HFA384X_OFFSET0_OFF 0x1C
-#define HFA384X_OFFSET1_OFF 0x1E
-#define HFA384X_RXFID_OFF 0x20
-#define HFA384X_ALLOCFID_OFF 0x22
-#define HFA384X_TXCOMPLFID_OFF 0x24
-#define HFA384X_SWSUPPORT0_OFF 0x28
-#define HFA384X_SWSUPPORT1_OFF 0x2A
-#define HFA384X_SWSUPPORT2_OFF 0x2C
-#define HFA384X_EVSTAT_OFF 0x30
-#define HFA384X_INTEN_OFF 0x32
-#define HFA384X_EVACK_OFF 0x34
-#define HFA384X_DATA0_OFF 0x36
-#define HFA384X_DATA1_OFF 0x38
-#define HFA384X_AUXPAGE_OFF 0x3A
-#define HFA384X_AUXOFFSET_OFF 0x3C
-#define HFA384X_AUXDATA_OFF 0x3E
-#endif /* PRISM2_PCCARD || PRISM2_PLX */
-
-#ifdef PRISM2_PCI
-/* Memory addresses for ISL3874 controller access */
-#define HFA384X_CMD_OFF 0x00
-#define HFA384X_PARAM0_OFF 0x04
-#define HFA384X_PARAM1_OFF 0x08
-#define HFA384X_PARAM2_OFF 0x0C
-#define HFA384X_STATUS_OFF 0x10
-#define HFA384X_RESP0_OFF 0x14
-#define HFA384X_RESP1_OFF 0x18
-#define HFA384X_RESP2_OFF 0x1C
-#define HFA384X_INFOFID_OFF 0x20
-#define HFA384X_CONTROL_OFF 0x28
-#define HFA384X_SELECT0_OFF 0x30
-#define HFA384X_SELECT1_OFF 0x34
-#define HFA384X_OFFSET0_OFF 0x38
-#define HFA384X_OFFSET1_OFF 0x3C
-#define HFA384X_RXFID_OFF 0x40
-#define HFA384X_ALLOCFID_OFF 0x44
-#define HFA384X_TXCOMPLFID_OFF 0x48
-#define HFA384X_PCICOR_OFF 0x4C
-#define HFA384X_SWSUPPORT0_OFF 0x50
-#define HFA384X_SWSUPPORT1_OFF 0x54
-#define HFA384X_SWSUPPORT2_OFF 0x58
-#define HFA384X_PCIHCR_OFF 0x5C
-#define HFA384X_EVSTAT_OFF 0x60
-#define HFA384X_INTEN_OFF 0x64
-#define HFA384X_EVACK_OFF 0x68
-#define HFA384X_DATA0_OFF 0x6C
-#define HFA384X_DATA1_OFF 0x70
-#define HFA384X_AUXPAGE_OFF 0x74
-#define HFA384X_AUXOFFSET_OFF 0x78
-#define HFA384X_AUXDATA_OFF 0x7C
-#define HFA384X_PCI_M0_ADDRH_OFF 0x80
-#define HFA384X_PCI_M0_ADDRL_OFF 0x84
-#define HFA384X_PCI_M0_LEN_OFF 0x88
-#define HFA384X_PCI_M0_CTL_OFF 0x8C
-#define HFA384X_PCI_STATUS_OFF 0x98
-#define HFA384X_PCI_M1_ADDRH_OFF 0xA0
-#define HFA384X_PCI_M1_ADDRL_OFF 0xA4
-#define HFA384X_PCI_M1_LEN_OFF 0xA8
-#define HFA384X_PCI_M1_CTL_OFF 0xAC
-
-/* PCI bus master control bits (these are undocumented; based on guessing and
- * experimenting..) */
-#define HFA384X_PCI_CTL_FROM_BAP (BIT(5) | BIT(1) | BIT(0))
-#define HFA384X_PCI_CTL_TO_BAP (BIT(5) | BIT(0))
-
-#endif /* PRISM2_PCI */
-
-
-/* Command codes for CMD reg. */
-#define HFA384X_CMDCODE_INIT 0x00
-#define HFA384X_CMDCODE_ENABLE 0x01
-#define HFA384X_CMDCODE_DISABLE 0x02
-#define HFA384X_CMDCODE_ALLOC 0x0A
-#define HFA384X_CMDCODE_TRANSMIT 0x0B
-#define HFA384X_CMDCODE_INQUIRE 0x11
-#define HFA384X_CMDCODE_ACCESS 0x21
-#define HFA384X_CMDCODE_ACCESS_WRITE (0x21 | BIT(8))
-#define HFA384X_CMDCODE_DOWNLOAD 0x22
-#define HFA384X_CMDCODE_READMIF 0x30
-#define HFA384X_CMDCODE_WRITEMIF 0x31
-#define HFA384X_CMDCODE_TEST 0x38
-
-#define HFA384X_CMDCODE_MASK 0x3F
-
-/* Test mode operations */
-#define HFA384X_TEST_CHANGE_CHANNEL 0x08
-#define HFA384X_TEST_MONITOR 0x0B
-#define HFA384X_TEST_STOP 0x0F
-#define HFA384X_TEST_CFG_BITS 0x15
-#define HFA384X_TEST_CFG_BIT_ALC BIT(3)
-
-#define HFA384X_CMD_BUSY BIT(15)
-
-#define HFA384X_CMD_TX_RECLAIM BIT(8)
-
-#define HFA384X_OFFSET_ERR BIT(14)
-#define HFA384X_OFFSET_BUSY BIT(15)
-
-
-/* ProgMode for download command */
-#define HFA384X_PROGMODE_DISABLE 0
-#define HFA384X_PROGMODE_ENABLE_VOLATILE 1
-#define HFA384X_PROGMODE_ENABLE_NON_VOLATILE 2
-#define HFA384X_PROGMODE_PROGRAM_NON_VOLATILE 3
-
-#define HFA384X_AUX_MAGIC0 0xfe01
-#define HFA384X_AUX_MAGIC1 0xdc23
-#define HFA384X_AUX_MAGIC2 0xba45
-
-#define HFA384X_AUX_PORT_DISABLED 0
-#define HFA384X_AUX_PORT_DISABLE BIT(14)
-#define HFA384X_AUX_PORT_ENABLE BIT(15)
-#define HFA384X_AUX_PORT_ENABLED (BIT(14) | BIT(15))
-#define HFA384X_AUX_PORT_MASK (BIT(14) | BIT(15))
-
-#define PRISM2_PDA_SIZE 1024
-
-
-/* Events; EvStat, Interrupt mask (IntEn), and acknowledge bits (EvAck) */
-#define HFA384X_EV_TICK BIT(15)
-#define HFA384X_EV_WTERR BIT(14)
-#define HFA384X_EV_INFDROP BIT(13)
-#ifdef PRISM2_PCI
-#define HFA384X_EV_PCI_M1 BIT(9)
-#define HFA384X_EV_PCI_M0 BIT(8)
-#endif /* PRISM2_PCI */
-#define HFA384X_EV_INFO BIT(7)
-#define HFA384X_EV_DTIM BIT(5)
-#define HFA384X_EV_CMD BIT(4)
-#define HFA384X_EV_ALLOC BIT(3)
-#define HFA384X_EV_TXEXC BIT(2)
-#define HFA384X_EV_TX BIT(1)
-#define HFA384X_EV_RX BIT(0)
-
-
-/* HFA384X Information frames */
-#define HFA384X_INFO_HANDOVERADDR 0xF000 /* AP f/w ? */
-#define HFA384X_INFO_HANDOVERDEAUTHADDR 0xF001 /* AP f/w 1.3.7 */
-#define HFA384X_INFO_COMMTALLIES 0xF100
-#define HFA384X_INFO_SCANRESULTS 0xF101
-#define HFA384X_INFO_CHANNELINFORESULTS 0xF102 /* AP f/w only */
-#define HFA384X_INFO_HOSTSCANRESULTS 0xF103
-#define HFA384X_INFO_LINKSTATUS 0xF200
-#define HFA384X_INFO_ASSOCSTATUS 0xF201 /* ? */
-#define HFA384X_INFO_AUTHREQ 0xF202 /* ? */
-#define HFA384X_INFO_PSUSERCNT 0xF203 /* ? */
-#define HFA384X_INFO_KEYIDCHANGED 0xF204 /* ? */
-
-enum { HFA384X_LINKSTATUS_CONNECTED = 1,
- HFA384X_LINKSTATUS_DISCONNECTED = 2,
- HFA384X_LINKSTATUS_AP_CHANGE = 3,
- HFA384X_LINKSTATUS_AP_OUT_OF_RANGE = 4,
- HFA384X_LINKSTATUS_AP_IN_RANGE = 5,
- HFA384X_LINKSTATUS_ASSOC_FAILED = 6 };
-
-enum { HFA384X_PORTTYPE_BSS = 1, HFA384X_PORTTYPE_WDS = 2,
- HFA384X_PORTTYPE_PSEUDO_IBSS = 3, HFA384X_PORTTYPE_IBSS = 0,
- HFA384X_PORTTYPE_HOSTAP = 6 };
-
-#define HFA384X_RATES_1MBPS BIT(0)
-#define HFA384X_RATES_2MBPS BIT(1)
-#define HFA384X_RATES_5MBPS BIT(2)
-#define HFA384X_RATES_11MBPS BIT(3)
-
-#define HFA384X_ROAMING_FIRMWARE 1
-#define HFA384X_ROAMING_HOST 2
-#define HFA384X_ROAMING_DISABLED 3
-
-#define HFA384X_WEPFLAGS_PRIVACYINVOKED BIT(0)
-#define HFA384X_WEPFLAGS_EXCLUDEUNENCRYPTED BIT(1)
-#define HFA384X_WEPFLAGS_HOSTENCRYPT BIT(4)
-#define HFA384X_WEPFLAGS_HOSTDECRYPT BIT(7)
-
-#define HFA384X_RX_STATUS_MSGTYPE (BIT(15) | BIT(14) | BIT(13))
-#define HFA384X_RX_STATUS_PCF BIT(12)
-#define HFA384X_RX_STATUS_MACPORT (BIT(10) | BIT(9) | BIT(8))
-#define HFA384X_RX_STATUS_UNDECR BIT(1)
-#define HFA384X_RX_STATUS_FCSERR BIT(0)
-
-#define HFA384X_RX_STATUS_GET_MSGTYPE(s) \
-(((s) & HFA384X_RX_STATUS_MSGTYPE) >> 13)
-#define HFA384X_RX_STATUS_GET_MACPORT(s) \
-(((s) & HFA384X_RX_STATUS_MACPORT) >> 8)
-
-enum { HFA384X_RX_MSGTYPE_NORMAL = 0, HFA384X_RX_MSGTYPE_RFC1042 = 1,
- HFA384X_RX_MSGTYPE_BRIDGETUNNEL = 2, HFA384X_RX_MSGTYPE_MGMT = 4 };
-
-
-#define HFA384X_TX_CTRL_ALT_RTRY BIT(5)
-#define HFA384X_TX_CTRL_802_11 BIT(3)
-#define HFA384X_TX_CTRL_802_3 0
-#define HFA384X_TX_CTRL_TX_EX BIT(2)
-#define HFA384X_TX_CTRL_TX_OK BIT(1)
-
-#define HFA384X_TX_STATUS_RETRYERR BIT(0)
-#define HFA384X_TX_STATUS_AGEDERR BIT(1)
-#define HFA384X_TX_STATUS_DISCON BIT(2)
-#define HFA384X_TX_STATUS_FORMERR BIT(3)
-
-/* HFA3861/3863 (BBP) Control Registers */
-#define HFA386X_CR_TX_CONFIGURE 0x12 /* CR9 */
-#define HFA386X_CR_RX_CONFIGURE 0x14 /* CR10 */
-#define HFA386X_CR_A_D_TEST_MODES2 0x1A /* CR13 */
-#define HFA386X_CR_MANUAL_TX_POWER 0x3E /* CR31 */
-#define HFA386X_CR_MEASURED_TX_POWER 0x74 /* CR58 */
-
-
-#ifdef __KERNEL__
-
-#define PRISM2_TXFID_COUNT 8
-#define PRISM2_DATA_MAXLEN 2304
-#define PRISM2_TXFID_LEN (PRISM2_DATA_MAXLEN + sizeof(struct hfa384x_tx_frame))
-#define PRISM2_TXFID_EMPTY 0xffff
-#define PRISM2_TXFID_RESERVED 0xfffe
-#define PRISM2_DUMMY_FID 0xffff
-#define MAX_SSID_LEN 32
-#define MAX_NAME_LEN 32 /* this is assumed to be equal to MAX_SSID_LEN */
-
-#define PRISM2_DUMP_RX_HDR BIT(0)
-#define PRISM2_DUMP_TX_HDR BIT(1)
-#define PRISM2_DUMP_TXEXC_HDR BIT(2)
-
-struct hostap_tx_callback_info {
- u16 idx;
- void (*func)(struct sk_buff *, int ok, void *);
- void *data;
- struct hostap_tx_callback_info *next;
-};
-
-
-/* IEEE 802.11 requires that STA supports concurrent reception of at least
- * three fragmented frames. This define can be increased to support more
- * concurrent frames, but it should be noted that each entry can consume about
- * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
-#define PRISM2_FRAG_CACHE_LEN 4
-
-struct prism2_frag_entry {
- unsigned long first_frag_time;
- unsigned int seq;
- unsigned int last_frag;
- struct sk_buff *skb;
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
-};
-
-
-struct hostap_cmd_queue {
- struct list_head list;
- wait_queue_head_t compl;
- volatile enum { CMD_SLEEP, CMD_CALLBACK, CMD_COMPLETED } type;
- void (*callback)(struct net_device *dev, long context, u16 resp0,
- u16 res);
- long context;
- u16 cmd, param0, param1;
- u16 resp0, res;
- volatile int issued, issuing;
-
- refcount_t usecnt;
- int del_req;
-};
-
-/* options for hw_shutdown */
-#define HOSTAP_HW_NO_DISABLE BIT(0)
-#define HOSTAP_HW_ENABLE_CMDCOMPL BIT(1)
-
-typedef struct local_info local_info_t;
-
-struct prism2_helper_functions {
- /* these functions are defined in hardware model specific files
- * (hostap_{cs,plx,pci}.c */
- int (*card_present)(local_info_t *local);
- void (*cor_sreset)(local_info_t *local);
- void (*genesis_reset)(local_info_t *local, int hcr);
-
- /* the following functions are from hostap_hw.c, but they may have some
- * hardware model specific code */
-
- /* FIX: low-level commands like cmd might disappear at some point to
- * make it easier to change them if needed (e.g., cmd would be replaced
- * with write_mif/read_mif/testcmd/inquire); at least get_rid and
- * set_rid might move to hostap_{cs,plx,pci}.c */
- int (*cmd)(struct net_device *dev, u16 cmd, u16 param0, u16 *param1,
- u16 *resp0);
- void (*read_regs)(struct net_device *dev, struct hfa384x_regs *regs);
- int (*get_rid)(struct net_device *dev, u16 rid, void *buf, int len,
- int exact_len);
- int (*set_rid)(struct net_device *dev, u16 rid, void *buf, int len);
- int (*hw_enable)(struct net_device *dev, int initial);
- int (*hw_config)(struct net_device *dev, int initial);
- void (*hw_reset)(struct net_device *dev);
- void (*hw_shutdown)(struct net_device *dev, int no_disable);
- int (*reset_port)(struct net_device *dev);
- void (*schedule_reset)(local_info_t *local);
- int (*download)(local_info_t *local,
- struct prism2_download_param *param);
- int (*tx)(struct sk_buff *skb, struct net_device *dev);
- int (*set_tim)(struct net_device *dev, int aid, int set);
- const struct proc_ops *read_aux_proc_ops;
-
- int need_tx_headroom; /* number of bytes of headroom needed before
- * IEEE 802.11 header */
- enum { HOSTAP_HW_PCCARD, HOSTAP_HW_PLX, HOSTAP_HW_PCI } hw_type;
-};
-
-
-struct prism2_download_data {
- u32 dl_cmd;
- u32 start_addr;
- u32 num_areas;
- struct prism2_download_data_area {
- u32 addr; /* wlan card address */
- u32 len;
- u8 *data; /* allocated data */
- } data[];
-};
-
-
-#define HOSTAP_MAX_BSS_COUNT 64
-#define MAX_WPA_IE_LEN 64
-
-struct hostap_bss_info {
- struct list_head list;
- unsigned long last_update;
- unsigned int count;
- u8 bssid[ETH_ALEN];
- u16 capab_info;
- u8 ssid[32];
- size_t ssid_len;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
- int chan;
- int included;
-};
-
-
-/* Per radio private Host AP data - shared by all net devices interfaces used
- * by each radio (wlan#, wlan#ap, wlan#sta, WDS).
- * ((struct hostap_interface *) netdev_priv(dev))->local points to this
- * structure. */
-struct local_info {
- struct module *hw_module;
- int card_idx;
- int dev_enabled;
- int master_dev_auto_open; /* was master device opened automatically */
- int num_dev_open; /* number of open devices */
- struct net_device *dev; /* master radio device */
- struct net_device *ddev; /* main data device */
- struct list_head hostap_interfaces; /* Host AP interface list (contains
- * struct hostap_interface entries)
- */
- rwlock_t iface_lock; /* hostap_interfaces read lock; use write lock
- * when removing entries from the list.
- * TX and RX paths can use read lock. */
- spinlock_t cmdlock, baplock, lock, irq_init_lock;
- struct mutex rid_bap_mtx;
- u16 infofid; /* MAC buffer id for info frame */
- /* txfid, intransmitfid, next_txtid, and next_alloc are protected by
- * txfidlock */
- spinlock_t txfidlock;
- int txfid_len; /* length of allocated TX buffers */
- u16 txfid[PRISM2_TXFID_COUNT]; /* buffer IDs for TX frames */
- /* buffer IDs for intransmit frames or PRISM2_TXFID_EMPTY if
- * corresponding txfid is free for next TX frame */
- u16 intransmitfid[PRISM2_TXFID_COUNT];
- int next_txfid; /* index to the next txfid to be checked for
- * availability */
- int next_alloc; /* index to the next intransmitfid to be checked for
- * allocation events */
-
- /* bitfield for atomic bitops */
-#define HOSTAP_BITS_TRANSMIT 0
-#define HOSTAP_BITS_BAP_TASKLET 1
-#define HOSTAP_BITS_BAP_TASKLET2 2
- unsigned long bits;
-
- struct ap_data *ap;
-
- char essid[MAX_SSID_LEN + 1];
- char name[MAX_NAME_LEN + 1];
- int name_set;
- u16 channel_mask; /* mask of allowed channels */
- u16 scan_channel_mask; /* mask of channels to be scanned */
- struct comm_tallies_sums comm_tallies;
- struct proc_dir_entry *proc;
- int iw_mode; /* operating mode (IW_MODE_*) */
- int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS
- * 1: IW_MODE_ADHOC is "pseudo IBSS" */
- char bssid[ETH_ALEN];
- int channel;
- int beacon_int;
- int dtim_period;
- int mtu;
- int frame_dump; /* dump RX/TX frame headers, PRISM2_DUMP_ flags */
- int fw_tx_rate_control;
- u16 tx_rate_control;
- u16 basic_rates;
- int hw_resetting;
- int hw_ready;
- int hw_reset_tries; /* how many times reset has been tried */
- int hw_downloading;
- int shutdown;
- int pri_only;
- int no_pri; /* no PRI f/w present */
- int sram_type; /* 8 = x8 SRAM, 16 = x16 SRAM, -1 = unknown */
-
- enum {
- PRISM2_TXPOWER_AUTO = 0, PRISM2_TXPOWER_OFF,
- PRISM2_TXPOWER_FIXED, PRISM2_TXPOWER_UNKNOWN
- } txpower_type;
- int txpower; /* if txpower_type == PRISM2_TXPOWER_FIXED */
-
- /* command queue for hfa384x_cmd(); protected with cmdlock */
- struct list_head cmd_queue;
- /* max_len for cmd_queue; in addition, cmd_callback can use two
- * additional entries to prevent sleeping commands from stopping
- * transmits */
-#define HOSTAP_CMD_QUEUE_MAX_LEN 16
- int cmd_queue_len; /* number of entries in cmd_queue */
-
- /* if card timeout is detected in interrupt context, reset_queue is
- * used to schedule card reseting to be done in user context */
- struct work_struct reset_queue;
-
- /* For scheduling a change of the promiscuous mode RID */
- int is_promisc;
- struct work_struct set_multicast_list_queue;
-
- struct work_struct set_tim_queue;
- struct list_head set_tim_list;
- spinlock_t set_tim_lock;
-
- int wds_max_connections;
- int wds_connections;
-#define HOSTAP_WDS_BROADCAST_RA BIT(0)
-#define HOSTAP_WDS_AP_CLIENT BIT(1)
-#define HOSTAP_WDS_STANDARD_FRAME BIT(2)
- u32 wds_type;
- u16 tx_control; /* flags to be used in TX description */
- int manual_retry_count; /* -1 = use f/w default; otherwise retry count
- * to be used with all frames */
-
- struct iw_statistics wstats;
- unsigned long scan_timestamp; /* Time started to scan */
- enum {
- PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
- PRISM2_MONITOR_CAPHDR = 2, PRISM2_MONITOR_RADIOTAP = 3
- } monitor_type;
- int monitor_allow_fcserr;
-
- int hostapd; /* whether user space daemon, hostapd, is used for AP
- * management */
- int hostapd_sta; /* whether hostapd is used with an extra STA interface
- */
- struct net_device *apdev;
- struct net_device_stats apdevstats;
-
- char assoc_ap_addr[ETH_ALEN];
- struct net_device *stadev;
- struct net_device_stats stadevstats;
-
-#define WEP_KEYS 4
-#define WEP_KEY_LEN 13
- struct lib80211_crypt_info crypt_info;
-
- int open_wep; /* allow unencrypted frames */
- int host_encrypt;
- int host_decrypt;
- int privacy_invoked; /* force privacy invoked flag even if no keys are
- * configured */
- int fw_encrypt_ok; /* whether firmware-based WEP encrypt is working
- * in Host AP mode (STA f/w 1.4.9 or newer) */
- int bcrx_sta_key; /* use individual keys to override default keys even
- * with RX of broad/multicast frames */
-
- struct prism2_frag_entry frag_cache[PRISM2_FRAG_CACHE_LEN];
- unsigned int frag_next_idx;
-
- int ieee_802_1x; /* is IEEE 802.1X used */
-
- int antsel_tx, antsel_rx;
- int rts_threshold; /* dot11RTSThreshold */
- int fragm_threshold; /* dot11FragmentationThreshold */
- int auth_algs; /* PRISM2_AUTH_ flags */
-
- int enh_sec; /* cnfEnhSecurity options (broadcast SSID hide/ignore) */
- int tallies32; /* 32-bit tallies in use */
-
- struct prism2_helper_functions *func;
-
- u8 *pda;
- int fw_ap;
-#define PRISM2_FW_VER(major, minor, variant) \
-(((major) << 16) | ((minor) << 8) | variant)
- u32 sta_fw_ver;
-
- /* Tasklets for handling hardware IRQ related operations outside hw IRQ
- * handler */
- struct tasklet_struct bap_tasklet;
-
- struct tasklet_struct info_tasklet;
- struct sk_buff_head info_list; /* info frames as skb's for
- * info_tasklet */
-
- struct hostap_tx_callback_info *tx_callback; /* registered TX callbacks
- */
-
- struct tasklet_struct rx_tasklet;
- struct sk_buff_head rx_list;
-
- struct tasklet_struct sta_tx_exc_tasklet;
- struct sk_buff_head sta_tx_exc_list;
-
- int host_roaming;
- unsigned long last_join_time; /* time of last JoinRequest */
- struct hfa384x_hostscan_result *last_scan_results;
- int last_scan_results_count;
- enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type;
- struct work_struct info_queue;
- unsigned long pending_info; /* bit field of pending info_queue items */
-#define PRISM2_INFO_PENDING_LINKSTATUS 0
-#define PRISM2_INFO_PENDING_SCANRESULTS 1
- int prev_link_status; /* previous received LinkStatus info */
- int prev_linkstatus_connected;
- u8 preferred_ap[ETH_ALEN]; /* use this AP if possible */
-
-#ifdef PRISM2_CALLBACK
- void *callback_data; /* Can be used in callbacks; e.g., allocate
- * on enable event and free on disable event.
- * Host AP driver code does not touch this. */
-#endif /* PRISM2_CALLBACK */
-
- wait_queue_head_t hostscan_wq;
-
- /* Passive scan in Host AP mode */
- struct timer_list passive_scan_timer;
- int passive_scan_interval; /* in seconds, 0 = disabled */
- int passive_scan_channel;
- enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state;
-
- struct timer_list tick_timer;
- unsigned long last_tick_timer;
- unsigned int sw_tick_stuck;
-
- /* commsQuality / dBmCommsQuality data from periodic polling; only
- * valid for Managed and Ad-hoc modes */
- unsigned long last_comms_qual_update;
- int comms_qual; /* in some odd unit.. */
- int avg_signal; /* in dB (note: negative) */
- int avg_noise; /* in dB (note: negative) */
- struct work_struct comms_qual_update;
-
- /* RSSI to dBm adjustment (for RX descriptor fields) */
- int rssi_to_dBm; /* subtract from RSSI to get approximate dBm value */
-
- /* BSS list / protected by local->lock */
- struct list_head bss_list;
- int num_bss_info;
- int wpa; /* WPA support enabled */
- int tkip_countermeasures;
- int drop_unencrypted;
- /* Generic IEEE 802.11 info element to be added to
- * ProbeResp/Beacon/(Re)AssocReq */
- u8 *generic_elem;
- size_t generic_elem_len;
-
-#ifdef PRISM2_DOWNLOAD_SUPPORT
- /* Persistent volatile download data */
- struct prism2_download_data *dl_pri;
- struct prism2_download_data *dl_sec;
-#endif /* PRISM2_DOWNLOAD_SUPPORT */
-
-#ifdef PRISM2_IO_DEBUG
-#define PRISM2_IO_DEBUG_SIZE 10000
- u32 io_debug[PRISM2_IO_DEBUG_SIZE];
- int io_debug_head;
- int io_debug_enabled;
-#endif /* PRISM2_IO_DEBUG */
-
- /* Pointer to hardware model specific (cs,pci,plx) private data. */
- void *hw_priv;
-};
-
-
-/* Per interface private Host AP data
- * Allocated for each net device that Host AP uses (wlan#, wlan#ap, wlan#sta,
- * WDS) and netdev_priv(dev) points to this structure. */
-struct hostap_interface {
- struct list_head list; /* list entry in Host AP interface list */
- struct net_device *dev; /* pointer to this device */
- struct local_info *local; /* pointer to shared private data */
- struct net_device_stats stats;
- struct iw_spy_data spy_data; /* iwspy support */
- struct iw_public_data wireless_data;
-
- enum {
- HOSTAP_INTERFACE_MASTER,
- HOSTAP_INTERFACE_MAIN,
- HOSTAP_INTERFACE_AP,
- HOSTAP_INTERFACE_STA,
- HOSTAP_INTERFACE_WDS,
- } type;
-
- union {
- struct hostap_interface_wds {
- u8 remote_addr[ETH_ALEN];
- } wds;
- } u;
-};
-
-
-#define HOSTAP_SKB_TX_DATA_MAGIC 0xf08a36a2
-
-/*
- * TX meta data - stored in skb->cb buffer, so this must not be increased over
- * the 48-byte limit.
- * THE PADDING THIS STARTS WITH IS A HORRIBLE HACK THAT SHOULD NOT LIVE
- * TO SEE THE DAY.
- */
-struct hostap_skb_tx_data {
- unsigned int __padding_for_default_qdiscs;
- u32 magic; /* HOSTAP_SKB_TX_DATA_MAGIC */
- u8 rate; /* transmit rate */
-#define HOSTAP_TX_FLAGS_WDS BIT(0)
-#define HOSTAP_TX_FLAGS_BUFFERED_FRAME BIT(1)
-#define HOSTAP_TX_FLAGS_ADD_MOREDATA BIT(2)
- u8 flags; /* HOSTAP_TX_FLAGS_* */
- u16 tx_cb_idx;
- struct hostap_interface *iface;
- unsigned long jiffies; /* queueing timestamp */
- unsigned short ethertype;
-};
-
-
-#ifndef PRISM2_NO_DEBUG
-
-#define DEBUG_FID BIT(0)
-#define DEBUG_PS BIT(1)
-#define DEBUG_FLOW BIT(2)
-#define DEBUG_AP BIT(3)
-#define DEBUG_HW BIT(4)
-#define DEBUG_EXTRA BIT(5)
-#define DEBUG_EXTRA2 BIT(6)
-#define DEBUG_PS2 BIT(7)
-#define DEBUG_MASK (DEBUG_PS | DEBUG_AP | DEBUG_HW | DEBUG_EXTRA)
-#define PDEBUG(n, args...) \
-do { if ((n) & DEBUG_MASK) printk(KERN_DEBUG args); } while (0)
-#define PDEBUG2(n, args...) \
-do { if ((n) & DEBUG_MASK) printk(args); } while (0)
-
-#else /* PRISM2_NO_DEBUG */
-
-#define PDEBUG(n, args...)
-#define PDEBUG2(n, args...)
-
-#endif /* PRISM2_NO_DEBUG */
-
-enum { BAP0 = 0, BAP1 = 1 };
-
-#define PRISM2_IO_DEBUG_CMD_INB 0
-#define PRISM2_IO_DEBUG_CMD_INW 1
-#define PRISM2_IO_DEBUG_CMD_INSW 2
-#define PRISM2_IO_DEBUG_CMD_OUTB 3
-#define PRISM2_IO_DEBUG_CMD_OUTW 4
-#define PRISM2_IO_DEBUG_CMD_OUTSW 5
-#define PRISM2_IO_DEBUG_CMD_ERROR 6
-#define PRISM2_IO_DEBUG_CMD_INTERRUPT 7
-
-#ifdef PRISM2_IO_DEBUG
-
-#define PRISM2_IO_DEBUG_ENTRY(cmd, reg, value) \
-(((cmd) << 24) | ((reg) << 16) | value)
-
-static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
- int reg, int value)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
-
- if (!local->io_debug_enabled)
- return;
-
- local->io_debug[local->io_debug_head] = jiffies & 0xffffffff;
- if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
- local->io_debug_head = 0;
- local->io_debug[local->io_debug_head] =
- PRISM2_IO_DEBUG_ENTRY(cmd, reg, value);
- if (++local->io_debug_head >= PRISM2_IO_DEBUG_SIZE)
- local->io_debug_head = 0;
-}
-
-
-static inline void prism2_io_debug_error(struct net_device *dev, int err)
-{
- struct hostap_interface *iface = netdev_priv(dev);
- local_info_t *local = iface->local;
- unsigned long flags;
-
- if (!local->io_debug_enabled)
- return;
-
- spin_lock_irqsave(&local->lock, flags);
- prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_ERROR, 0, err);
- if (local->io_debug_enabled == 1) {
- local->io_debug_enabled = 0;
- printk(KERN_DEBUG "%s: I/O debug stopped\n", dev->name);
- }
- spin_unlock_irqrestore(&local->lock, flags);
-}
-
-#else /* PRISM2_IO_DEBUG */
-
-static inline void prism2_io_debug_add(struct net_device *dev, int cmd,
- int reg, int value)
-{
-}
-
-static inline void prism2_io_debug_error(struct net_device *dev, int err)
-{
-}
-
-#endif /* PRISM2_IO_DEBUG */
-
-
-#ifdef PRISM2_CALLBACK
-enum {
- /* Called when card is enabled */
- PRISM2_CALLBACK_ENABLE,
-
- /* Called when card is disabled */
- PRISM2_CALLBACK_DISABLE,
-
- /* Called when RX/TX starts/ends */
- PRISM2_CALLBACK_RX_START, PRISM2_CALLBACK_RX_END,
- PRISM2_CALLBACK_TX_START, PRISM2_CALLBACK_TX_END
-};
-void prism2_callback(local_info_t *local, int event);
-#else /* PRISM2_CALLBACK */
-#define prism2_callback(d, e) do { } while (0)
-#endif /* PRISM2_CALLBACK */
-
-#endif /* __KERNEL__ */
-
-#endif /* HOSTAP_WLAN_H */
--
2.39.2

2023-10-23 13:21:52

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 05/10] wifi: remove orphaned zd1201 driver

From: Arnd Bergmann <[email protected]>

This is a wireless extensions style driver for 802.11b USB dongles,
with partial support for cfg80211 interfaces.

As these are all external dongles, there are probably few users that
have not yet replaced them with cheap 802.11n devices that work better.

Signed-off-by: Arnd Bergmann <[email protected]>
---
MAINTAINERS | 6 -
drivers/net/wireless/zydas/Kconfig | 19 -
drivers/net/wireless/zydas/Makefile | 2 -
drivers/net/wireless/zydas/zd1201.c | 1909 ---------------------------
drivers/net/wireless/zydas/zd1201.h | 144 --
5 files changed, 2080 deletions(-)
delete mode 100644 drivers/net/wireless/zydas/zd1201.c
delete mode 100644 drivers/net/wireless/zydas/zd1201.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 78fa9932ba28f..be59dc66c8133 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22426,12 +22426,6 @@ S: Supported
F: drivers/usb/host/pci-quirks*
F: drivers/usb/host/xhci*

-USB ZD1201 DRIVER
-L: [email protected]
-S: Orphan
-W: http://linux-lc100020.sourceforge.net
-F: drivers/net/wireless/zydas/zd1201.*
-
USER DATAGRAM PROTOCOL (UDP)
M: Willem de Bruijn <[email protected]>
S: Maintained
diff --git a/drivers/net/wireless/zydas/Kconfig b/drivers/net/wireless/zydas/Kconfig
index 08574433df66f..839e1217e855c 100644
--- a/drivers/net/wireless/zydas/Kconfig
+++ b/drivers/net/wireless/zydas/Kconfig
@@ -12,25 +12,6 @@ config WLAN_VENDOR_ZYDAS

if WLAN_VENDOR_ZYDAS

-config USB_ZD1201
- tristate "USB ZD1201 based Wireless device support"
- depends on CFG80211 && USB
- select WIRELESS_EXT
- select WEXT_PRIV
- select FW_LOADER
- help
- Say Y if you want to use wireless LAN adapters based on the ZyDAS
- ZD1201 chip.
-
- This driver makes the adapter appear as a normal Ethernet interface,
- typically on wlan0.
-
- The zd1201 device requires external firmware to be loaded.
- This can be found at http://linux-lc100020.sourceforge.net/
-
- To compile this driver as a module, choose M here: the
- module will be called zd1201.
-
source "drivers/net/wireless/zydas/zd1211rw/Kconfig"

endif # WLAN_VENDOR_ZYDAS
diff --git a/drivers/net/wireless/zydas/Makefile b/drivers/net/wireless/zydas/Makefile
index c70003d30a8fb..3e0a51db98742 100644
--- a/drivers/net/wireless/zydas/Makefile
+++ b/drivers/net/wireless/zydas/Makefile
@@ -1,4 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ZD1211RW) += zd1211rw/
-
-obj-$(CONFIG_USB_ZD1201) += zd1201.o
diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c
deleted file mode 100644
index 2814df1ecc78f..0000000000000
--- a/drivers/net/wireless/zydas/zd1201.c
+++ /dev/null
@@ -1,1909 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for ZyDAS zd1201 based USB wireless devices.
- *
- * Copyright (c) 2004, 2005 Jeroen Vreeken ([email protected])
- *
- * Parts of this driver have been derived from a wlan-ng version
- * modified by ZyDAS. They also made documentation available, thanks!
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- */
-
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/slab.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-#include <net/iw_handler.h>
-#include <linux/string.h>
-#include <linux/if_arp.h>
-#include <linux/firmware.h>
-#include "zd1201.h"
-
-static const struct usb_device_id zd1201_table[] = {
- {USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */
- {USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */
- {USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb adapter */
- {USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb adapter */
- {USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */
- {USB_DEVICE(0x1044, 0x8005)}, /* GIGABYTE GN-WLBZ201 usb adapter */
- {}
-};
-
-static int ap; /* Are we an AP or a normal station? */
-
-#define ZD1201_VERSION "0.15"
-
-MODULE_AUTHOR("Jeroen Vreeken <[email protected]>");
-MODULE_DESCRIPTION("Driver for ZyDAS ZD1201 based USB Wireless adapters");
-MODULE_VERSION(ZD1201_VERSION);
-MODULE_LICENSE("GPL");
-module_param(ap, int, 0);
-MODULE_PARM_DESC(ap, "If non-zero Access Point firmware will be loaded");
-MODULE_DEVICE_TABLE(usb, zd1201_table);
-
-
-static int zd1201_fw_upload(struct usb_device *dev, int apfw)
-{
- const struct firmware *fw_entry;
- const char *data;
- unsigned long len;
- int err;
- unsigned char ret;
- char *buf;
- char *fwfile;
-
- if (apfw)
- fwfile = "zd1201-ap.fw";
- else
- fwfile = "zd1201.fw";
-
- err = request_firmware(&fw_entry, fwfile, &dev->dev);
- if (err) {
- dev_err(&dev->dev, "Failed to load %s firmware file!\n", fwfile);
- dev_err(&dev->dev, "Make sure the hotplug firmware loader is installed.\n");
- dev_err(&dev->dev, "Goto http://linux-lc100020.sourceforge.net for more info.\n");
- return err;
- }
-
- data = fw_entry->data;
- len = fw_entry->size;
-
- buf = kmalloc(1024, GFP_ATOMIC);
- if (!buf) {
- err = -ENOMEM;
- goto exit;
- }
-
- while (len > 0) {
- int translen = (len > 1024) ? 1024 : len;
- memcpy(buf, data, translen);
-
- err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0,
- USB_DIR_OUT | 0x40, 0, 0, buf, translen,
- ZD1201_FW_TIMEOUT);
- if (err < 0)
- goto exit;
-
- len -= translen;
- data += translen;
- }
-
- err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x2,
- USB_DIR_OUT | 0x40, 0, 0, NULL, 0, ZD1201_FW_TIMEOUT);
- if (err < 0)
- goto exit;
-
- err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4,
- USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT);
- if (err < 0)
- goto exit;
-
- memcpy(&ret, buf, sizeof(ret));
-
- if (ret & 0x80) {
- err = -EIO;
- goto exit;
- }
-
- err = 0;
-exit:
- kfree(buf);
- release_firmware(fw_entry);
- return err;
-}
-
-MODULE_FIRMWARE("zd1201-ap.fw");
-MODULE_FIRMWARE("zd1201.fw");
-
-static void zd1201_usbfree(struct urb *urb)
-{
- struct zd1201 *zd = urb->context;
-
- switch(urb->status) {
- case -EILSEQ:
- case -ENODEV:
- case -ETIME:
- case -ENOENT:
- case -EPIPE:
- case -EOVERFLOW:
- case -ESHUTDOWN:
- dev_warn(&zd->usb->dev, "%s: urb failed: %d\n",
- zd->dev->name, urb->status);
- }
-
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
-}
-
-/* cmdreq message:
- u32 type
- u16 cmd
- u16 parm0
- u16 parm1
- u16 parm2
- u8 pad[4]
-
- total: 4 + 2 + 2 + 2 + 2 + 4 = 16
-*/
-static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0,
- int parm1, int parm2)
-{
- unsigned char *command;
- int ret;
- struct urb *urb;
-
- command = kmalloc(16, GFP_ATOMIC);
- if (!command)
- return -ENOMEM;
-
- *((__le32*)command) = cpu_to_le32(ZD1201_USB_CMDREQ);
- *((__le16*)&command[4]) = cpu_to_le16(cmd);
- *((__le16*)&command[6]) = cpu_to_le16(parm0);
- *((__le16*)&command[8]) = cpu_to_le16(parm1);
- *((__le16*)&command[10])= cpu_to_le16(parm2);
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!urb) {
- kfree(command);
- return -ENOMEM;
- }
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
- command, 16, zd1201_usbfree, zd);
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret) {
- kfree(command);
- usb_free_urb(urb);
- }
-
- return ret;
-}
-
-/* Callback after sending out a packet */
-static void zd1201_usbtx(struct urb *urb)
-{
- struct zd1201 *zd = urb->context;
- netif_wake_queue(zd->dev);
-}
-
-/* Incoming data */
-static void zd1201_usbrx(struct urb *urb)
-{
- struct zd1201 *zd = urb->context;
- int free = 0;
- unsigned char *data = urb->transfer_buffer;
- struct sk_buff *skb;
- unsigned char type;
-
- if (!zd)
- return;
-
- switch(urb->status) {
- case -EILSEQ:
- case -ENODEV:
- case -ETIME:
- case -ENOENT:
- case -EPIPE:
- case -EOVERFLOW:
- case -ESHUTDOWN:
- dev_warn(&zd->usb->dev, "%s: rx urb failed: %d\n",
- zd->dev->name, urb->status);
- free = 1;
- goto exit;
- }
-
- if (urb->status != 0 || urb->actual_length == 0)
- goto resubmit;
-
- type = data[0];
- if (type == ZD1201_PACKET_EVENTSTAT || type == ZD1201_PACKET_RESOURCE) {
- memcpy(zd->rxdata, data, urb->actual_length);
- zd->rxlen = urb->actual_length;
- zd->rxdatas = 1;
- wake_up(&zd->rxdataq);
- }
- /* Info frame */
- if (type == ZD1201_PACKET_INQUIRE) {
- int i = 0;
- unsigned short infotype, copylen;
- infotype = le16_to_cpu(*(__le16*)&data[6]);
-
- if (infotype == ZD1201_INF_LINKSTATUS) {
- short linkstatus;
-
- linkstatus = le16_to_cpu(*(__le16*)&data[8]);
- switch(linkstatus) {
- case 1:
- netif_carrier_on(zd->dev);
- break;
- case 2:
- netif_carrier_off(zd->dev);
- break;
- case 3:
- netif_carrier_off(zd->dev);
- break;
- case 4:
- netif_carrier_on(zd->dev);
- break;
- default:
- netif_carrier_off(zd->dev);
- }
- goto resubmit;
- }
- if (infotype == ZD1201_INF_ASSOCSTATUS) {
- short status = le16_to_cpu(*(__le16*)(data+8));
- int event;
- union iwreq_data wrqu;
-
- switch (status) {
- case ZD1201_ASSOCSTATUS_STAASSOC:
- case ZD1201_ASSOCSTATUS_REASSOC:
- event = IWEVREGISTERED;
- break;
- case ZD1201_ASSOCSTATUS_DISASSOC:
- case ZD1201_ASSOCSTATUS_ASSOCFAIL:
- case ZD1201_ASSOCSTATUS_AUTHFAIL:
- default:
- event = IWEVEXPIRED;
- }
- memcpy(wrqu.addr.sa_data, data+10, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(zd->dev, event, &wrqu, NULL);
-
- goto resubmit;
- }
- if (infotype == ZD1201_INF_AUTHREQ) {
- union iwreq_data wrqu;
-
- memcpy(wrqu.addr.sa_data, data+8, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
- /* There isn't a event that trully fits this request.
- We assume that userspace will be smart enough to
- see a new station being expired and sends back a
- authstation ioctl to authorize it. */
- wireless_send_event(zd->dev, IWEVEXPIRED, &wrqu, NULL);
- goto resubmit;
- }
- /* Other infotypes are handled outside this handler */
- zd->rxlen = 0;
- while (i < urb->actual_length) {
- copylen = le16_to_cpu(*(__le16*)&data[i+2]);
- /* Sanity check, sometimes we get junk */
- if (copylen+zd->rxlen > sizeof(zd->rxdata))
- break;
- memcpy(zd->rxdata+zd->rxlen, data+i+4, copylen);
- zd->rxlen += copylen;
- i += 64;
- }
- if (i >= urb->actual_length) {
- zd->rxdatas = 1;
- wake_up(&zd->rxdataq);
- }
- goto resubmit;
- }
- /* Actual data */
- if (data[urb->actual_length-1] == ZD1201_PACKET_RXDATA) {
- int datalen = urb->actual_length-1;
- unsigned short len, fc, seq;
-
- len = ntohs(*(__be16 *)&data[datalen-2]);
- if (len>datalen)
- len=datalen;
- fc = le16_to_cpu(*(__le16 *)&data[datalen-16]);
- seq = le16_to_cpu(*(__le16 *)&data[datalen-24]);
-
- if (zd->monitor) {
- if (datalen < 24)
- goto resubmit;
- if (!(skb = dev_alloc_skb(datalen+24)))
- goto resubmit;
-
- skb_put_data(skb, &data[datalen - 16], 2);
- skb_put_data(skb, &data[datalen - 2], 2);
- skb_put_data(skb, &data[datalen - 14], 6);
- skb_put_data(skb, &data[datalen - 22], 6);
- skb_put_data(skb, &data[datalen - 8], 6);
- skb_put_data(skb, &data[datalen - 24], 2);
- skb_put_data(skb, data, len);
- skb->protocol = eth_type_trans(skb, zd->dev);
- zd->dev->stats.rx_packets++;
- zd->dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- goto resubmit;
- }
-
- if ((seq & IEEE80211_SCTL_FRAG) ||
- (fc & IEEE80211_FCTL_MOREFRAGS)) {
- struct zd1201_frag *frag = NULL;
- char *ptr;
-
- if (datalen<14)
- goto resubmit;
- if ((seq & IEEE80211_SCTL_FRAG) == 0) {
- frag = kmalloc(sizeof(*frag), GFP_ATOMIC);
- if (!frag)
- goto resubmit;
- skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2);
- if (!skb) {
- kfree(frag);
- goto resubmit;
- }
- frag->skb = skb;
- frag->seq = seq & IEEE80211_SCTL_SEQ;
- skb_reserve(skb, 2);
- skb_put_data(skb, &data[datalen - 14], 12);
- skb_put_data(skb, &data[6], 2);
- skb_put_data(skb, data + 8, len);
- hlist_add_head(&frag->fnode, &zd->fraglist);
- goto resubmit;
- }
- hlist_for_each_entry(frag, &zd->fraglist, fnode)
- if (frag->seq == (seq&IEEE80211_SCTL_SEQ))
- break;
- if (!frag)
- goto resubmit;
- skb = frag->skb;
- ptr = skb_put(skb, len);
- if (ptr)
- memcpy(ptr, data+8, len);
- if (fc & IEEE80211_FCTL_MOREFRAGS)
- goto resubmit;
- hlist_del_init(&frag->fnode);
- kfree(frag);
- } else {
- if (datalen<14)
- goto resubmit;
- skb = dev_alloc_skb(len + 14 + 2);
- if (!skb)
- goto resubmit;
- skb_reserve(skb, 2);
- skb_put_data(skb, &data[datalen - 14], 12);
- skb_put_data(skb, &data[6], 2);
- skb_put_data(skb, data + 8, len);
- }
- skb->protocol = eth_type_trans(skb, zd->dev);
- zd->dev->stats.rx_packets++;
- zd->dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- }
-resubmit:
- memset(data, 0, ZD1201_RXSIZE);
-
- urb->status = 0;
- urb->dev = zd->usb;
- if(usb_submit_urb(urb, GFP_ATOMIC))
- free = 1;
-
-exit:
- if (free) {
- zd->rxlen = 0;
- zd->rxdatas = 1;
- wake_up(&zd->rxdataq);
- kfree(urb->transfer_buffer);
- }
-}
-
-static int zd1201_getconfig(struct zd1201 *zd, int rid, void *riddata,
- unsigned int riddatalen)
-{
- int err;
- int i = 0;
- int code;
- int rid_fid;
- int length;
- unsigned char *pdata;
-
- zd->rxdatas = 0;
- err = zd1201_docmd(zd, ZD1201_CMDCODE_ACCESS, rid, 0, 0);
- if (err)
- return err;
-
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen)
- return -EIO;
-
- code = le16_to_cpu(*(__le16*)(&zd->rxdata[4]));
- rid_fid = le16_to_cpu(*(__le16*)(&zd->rxdata[6]));
- length = le16_to_cpu(*(__le16*)(&zd->rxdata[8]));
- if (length > zd->rxlen)
- length = zd->rxlen-6;
-
- /* If access bit is not on, then error */
- if ((code & ZD1201_ACCESSBIT) != ZD1201_ACCESSBIT || rid_fid != rid )
- return -EINVAL;
-
- /* Not enough buffer for allocating data */
- if (riddatalen != (length - 4)) {
- dev_dbg(&zd->usb->dev, "riddatalen mismatches, expected=%u, (packet=%u) length=%u, rid=0x%04X, rid_fid=0x%04X\n",
- riddatalen, zd->rxlen, length, rid, rid_fid);
- return -ENODATA;
- }
-
- zd->rxdatas = 0;
- /* Issue SetRxRid commnd */
- err = zd1201_docmd(zd, ZD1201_CMDCODE_SETRXRID, rid, 0, length);
- if (err)
- return err;
-
- /* Receive RID record from resource packets */
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen)
- return -EIO;
-
- if (zd->rxdata[zd->rxlen - 1] != ZD1201_PACKET_RESOURCE) {
- dev_dbg(&zd->usb->dev, "Packet type mismatch: 0x%x not 0x3\n",
- zd->rxdata[zd->rxlen-1]);
- return -EINVAL;
- }
-
- /* Set the data pointer and received data length */
- pdata = zd->rxdata;
- length = zd->rxlen;
-
- do {
- int actual_length;
-
- actual_length = (length > 64) ? 64 : length;
-
- if (pdata[0] != 0x3) {
- dev_dbg(&zd->usb->dev, "Rx Resource packet type error: %02X\n",
- pdata[0]);
- return -EINVAL;
- }
-
- if (actual_length != 64) {
- /* Trim the last packet type byte */
- actual_length--;
- }
-
- /* Skip the 4 bytes header (RID length and RID) */
- if (i == 0) {
- pdata += 8;
- actual_length -= 8;
- } else {
- pdata += 4;
- actual_length -= 4;
- }
-
- memcpy(riddata, pdata, actual_length);
- riddata += actual_length;
- pdata += actual_length;
- length -= 64;
- i++;
- } while (length > 0);
-
- return 0;
-}
-
-/*
- * resreq:
- * byte type
- * byte sequence
- * u16 reserved
- * byte data[12]
- * total: 16
- */
-static int zd1201_setconfig(struct zd1201 *zd, int rid, const void *buf, int len, int wait)
-{
- int err;
- unsigned char *request;
- int reqlen;
- char seq=0;
- struct urb *urb;
- gfp_t gfp_mask = wait ? GFP_NOIO : GFP_ATOMIC;
-
- len += 4; /* first 4 are for header */
-
- zd->rxdatas = 0;
- zd->rxlen = 0;
- for (seq=0; len > 0; seq++) {
- request = kzalloc(16, gfp_mask);
- if (!request)
- return -ENOMEM;
- urb = usb_alloc_urb(0, gfp_mask);
- if (!urb) {
- kfree(request);
- return -ENOMEM;
- }
- reqlen = len>12 ? 12 : len;
- request[0] = ZD1201_USB_RESREQ;
- request[1] = seq;
- request[2] = 0;
- request[3] = 0;
- if (request[1] == 0) {
- /* add header */
- *(__le16*)&request[4] = cpu_to_le16((len-2+1)/2);
- *(__le16*)&request[6] = cpu_to_le16(rid);
- memcpy(request+8, buf, reqlen-4);
- buf += reqlen-4;
- } else {
- memcpy(request+4, buf, reqlen);
- buf += reqlen;
- }
-
- len -= reqlen;
-
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb,
- zd->endp_out2), request, 16, zd1201_usbfree, zd);
- err = usb_submit_urb(urb, gfp_mask);
- if (err)
- goto err;
- }
-
- request = kmalloc(16, gfp_mask);
- if (!request)
- return -ENOMEM;
- urb = usb_alloc_urb(0, gfp_mask);
- if (!urb) {
- kfree(request);
- return -ENOMEM;
- }
- *((__le32*)request) = cpu_to_le32(ZD1201_USB_CMDREQ);
- *((__le16*)&request[4]) =
- cpu_to_le16(ZD1201_CMDCODE_ACCESS|ZD1201_ACCESSBIT);
- *((__le16*)&request[6]) = cpu_to_le16(rid);
- *((__le16*)&request[8]) = cpu_to_le16(0);
- *((__le16*)&request[10]) = cpu_to_le16(0);
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out2),
- request, 16, zd1201_usbfree, zd);
- err = usb_submit_urb(urb, gfp_mask);
- if (err)
- goto err;
-
- if (wait) {
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen || le16_to_cpu(*(__le16*)&zd->rxdata[6]) != rid) {
- dev_dbg(&zd->usb->dev, "wrong or no RID received\n");
- }
- }
-
- return 0;
-err:
- kfree(request);
- usb_free_urb(urb);
- return err;
-}
-
-static inline int zd1201_getconfig16(struct zd1201 *zd, int rid, short *val)
-{
- int err;
- __le16 zdval;
-
- err = zd1201_getconfig(zd, rid, &zdval, sizeof(__le16));
- if (err)
- return err;
- *val = le16_to_cpu(zdval);
- return 0;
-}
-
-static inline int zd1201_setconfig16(struct zd1201 *zd, int rid, short val)
-{
- __le16 zdval = cpu_to_le16(val);
- return (zd1201_setconfig(zd, rid, &zdval, sizeof(__le16), 1));
-}
-
-static int zd1201_drvr_start(struct zd1201 *zd)
-{
- int err, i;
- short max;
- __le16 zdmax;
- unsigned char *buffer;
-
- buffer = kzalloc(ZD1201_RXSIZE, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- usb_fill_bulk_urb(zd->rx_urb, zd->usb,
- usb_rcvbulkpipe(zd->usb, zd->endp_in), buffer, ZD1201_RXSIZE,
- zd1201_usbrx, zd);
-
- err = usb_submit_urb(zd->rx_urb, GFP_KERNEL);
- if (err)
- goto err_buffer;
-
- err = zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
- if (err)
- goto err_urb;
-
- err = zd1201_getconfig(zd, ZD1201_RID_CNFMAXTXBUFFERNUMBER, &zdmax,
- sizeof(__le16));
- if (err)
- goto err_urb;
-
- max = le16_to_cpu(zdmax);
- for (i=0; i<max; i++) {
- err = zd1201_docmd(zd, ZD1201_CMDCODE_ALLOC, 1514, 0, 0);
- if (err)
- goto err_urb;
- }
-
- return 0;
-
-err_urb:
- usb_kill_urb(zd->rx_urb);
- return err;
-err_buffer:
- kfree(buffer);
- return err;
-}
-
-/* Magic alert: The firmware doesn't seem to like the MAC state being
- * toggled in promisc (aka monitor) mode.
- * (It works a number of times, but will halt eventually)
- * So we turn it of before disabling and on after enabling if needed.
- */
-static int zd1201_enable(struct zd1201 *zd)
-{
- int err;
-
- if (zd->mac_enabled)
- return 0;
-
- err = zd1201_docmd(zd, ZD1201_CMDCODE_ENABLE, 0, 0, 0);
- if (!err)
- zd->mac_enabled = 1;
-
- if (zd->monitor)
- err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 1);
-
- return err;
-}
-
-static int zd1201_disable(struct zd1201 *zd)
-{
- int err;
-
- if (!zd->mac_enabled)
- return 0;
- if (zd->monitor) {
- err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
- if (err)
- return err;
- }
-
- err = zd1201_docmd(zd, ZD1201_CMDCODE_DISABLE, 0, 0, 0);
- if (!err)
- zd->mac_enabled = 0;
- return err;
-}
-
-static int zd1201_mac_reset(struct zd1201 *zd)
-{
- if (!zd->mac_enabled)
- return 0;
- zd1201_disable(zd);
- return zd1201_enable(zd);
-}
-
-static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen)
-{
- int err, val;
- char buf[IW_ESSID_MAX_SIZE+2];
-
- err = zd1201_disable(zd);
- if (err)
- return err;
-
- val = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
- val |= ZD1201_CNFAUTHENTICATION_SHAREDKEY;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, val);
- if (err)
- return err;
-
- *(__le16 *)buf = cpu_to_le16(essidlen);
- memcpy(buf+2, essid, essidlen);
- if (!zd->ap) { /* Normal station */
- err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
- IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- return err;
- } else { /* AP */
- err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNSSID, buf,
- IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- return err;
- }
-
- err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR,
- zd->dev->dev_addr, zd->dev->addr_len, 1);
- if (err)
- return err;
-
- err = zd1201_enable(zd);
- if (err)
- return err;
-
- msleep(100);
- return 0;
-}
-
-static int zd1201_net_open(struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- /* Start MAC with wildcard if no essid set */
- if (!zd->mac_enabled)
- zd1201_join(zd, zd->essid, zd->essidlen);
- netif_start_queue(dev);
-
- return 0;
-}
-
-static int zd1201_net_stop(struct net_device *dev)
-{
- netif_stop_queue(dev);
- return 0;
-}
-
-/*
- RFC 1042 encapsulates Ethernet frames in 802.11 frames
- by prefixing them with 0xaa, 0xaa, 0x03) followed by a SNAP OID of 0
- (0x00, 0x00, 0x00). Zd requires an additional padding, copy
- of ethernet addresses, length of the standard RFC 1042 packet
- and a command byte (which is nul for tx).
-
- tx frame (from Wlan NG):
- RFC 1042:
- llc 0xAA 0xAA 0x03 (802.2 LLC)
- snap 0x00 0x00 0x00 (Ethernet encapsulated)
- type 2 bytes, Ethernet type field
- payload (minus eth header)
- Zydas specific:
- padding 1B if (skb->len+8+1)%64==0
- Eth MAC addr 12 bytes, Ethernet MAC addresses
- length 2 bytes, RFC 1042 packet length
- (llc+snap+type+payload)
- zd 1 null byte, zd1201 packet type
- */
-static netdev_tx_t zd1201_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
- unsigned char *txbuf = zd->txdata;
- int txbuflen, pad = 0, err;
- struct urb *urb = zd->tx_urb;
-
- if (!zd->mac_enabled || zd->monitor) {
- dev->stats.tx_dropped++;
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
- netif_stop_queue(dev);
-
- txbuflen = skb->len + 8 + 1;
- if (txbuflen%64 == 0) {
- pad = 1;
- txbuflen++;
- }
- txbuf[0] = 0xAA;
- txbuf[1] = 0xAA;
- txbuf[2] = 0x03;
- txbuf[3] = 0x00; /* rfc1042 */
- txbuf[4] = 0x00;
- txbuf[5] = 0x00;
-
- skb_copy_from_linear_data_offset(skb, 12, txbuf + 6, skb->len - 12);
- if (pad)
- txbuf[skb->len-12+6]=0;
- skb_copy_from_linear_data(skb, txbuf + skb->len - 12 + 6 + pad, 12);
- *(__be16*)&txbuf[skb->len+6+pad] = htons(skb->len-12+6);
- txbuf[txbuflen-1] = 0;
-
- usb_fill_bulk_urb(urb, zd->usb, usb_sndbulkpipe(zd->usb, zd->endp_out),
- txbuf, txbuflen, zd1201_usbtx, zd);
-
- err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC);
- if (err) {
- dev->stats.tx_errors++;
- netif_start_queue(dev);
- } else {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
- }
- kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
-static void zd1201_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- if (!zd)
- return;
- dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
- dev->name);
- usb_unlink_urb(zd->tx_urb);
- dev->stats.tx_errors++;
- /* Restart the timeout to quiet the watchdog: */
- netif_trans_update(dev); /* prevent tx timeout */
-}
-
-static int zd1201_set_mac_address(struct net_device *dev, void *p)
-{
- struct sockaddr *addr = p;
- struct zd1201 *zd = netdev_priv(dev);
- int err;
-
- if (!zd)
- return -ENODEV;
-
- err = zd1201_setconfig(zd, ZD1201_RID_CNFOWNMACADDR,
- addr->sa_data, dev->addr_len, 1);
- if (err)
- return err;
- eth_hw_addr_set(dev, addr->sa_data);
-
- return zd1201_mac_reset(zd);
-}
-
-static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- return &zd->iwstats;
-}
-
-static void zd1201_set_multicast(struct net_device *dev)
-{
- struct zd1201 *zd = netdev_priv(dev);
- struct netdev_hw_addr *ha;
- unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI];
- int i;
-
- if (netdev_mc_count(dev) > ZD1201_MAXMULTI)
- return;
-
- i = 0;
- netdev_for_each_mc_addr(ha, dev)
- memcpy(reqbuf + i++ * ETH_ALEN, ha->addr, ETH_ALEN);
- zd1201_setconfig(zd, ZD1201_RID_CNFGROUPADDRESS, reqbuf,
- netdev_mc_count(dev) * ETH_ALEN, 0);
-}
-
-static int zd1201_config_commit(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
-{
- struct zd1201 *zd = netdev_priv(dev);
-
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_name(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- strcpy(wrqu->name, "IEEE 802.11b");
- return 0;
-}
-
-static int zd1201_set_freq(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct zd1201 *zd = netdev_priv(dev);
- short channel = 0;
- int err;
-
- if (freq->e == 0)
- channel = freq->m;
- else
- channel = ieee80211_frequency_to_channel(freq->m);
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, channel);
- if (err)
- return err;
-
- zd1201_mac_reset(zd);
-
- return 0;
-}
-
-static int zd1201_get_freq(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_freq *freq = &wrqu->freq;
- struct zd1201 *zd = netdev_priv(dev);
- short channel;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFOWNCHANNEL, &channel);
- if (err)
- return err;
- freq->e = 0;
- freq->m = channel;
-
- return 0;
-}
-
-static int zd1201_set_mode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct zd1201 *zd = netdev_priv(dev);
- short porttype, monitor = 0;
- unsigned char buffer[IW_ESSID_MAX_SIZE+2];
- int err;
-
- if (zd->ap) {
- if (*mode != IW_MODE_MASTER)
- return -EINVAL;
- return 0;
- }
-
- err = zd1201_setconfig16(zd, ZD1201_RID_PROMISCUOUSMODE, 0);
- if (err)
- return err;
- zd->dev->type = ARPHRD_ETHER;
- switch(*mode) {
- case IW_MODE_MONITOR:
- monitor = 1;
- zd->dev->type = ARPHRD_IEEE80211;
- /* Make sure we are no longer associated with by
- setting an 'impossible' essid.
- (otherwise we mess up firmware)
- */
- zd1201_join(zd, "\0-*#\0", 5);
- /* Put port in pIBSS */
- fallthrough;
- case 8: /* No pseudo-IBSS in wireless extensions (yet) */
- porttype = ZD1201_PORTTYPE_PSEUDOIBSS;
- break;
- case IW_MODE_ADHOC:
- porttype = ZD1201_PORTTYPE_IBSS;
- break;
- case IW_MODE_INFRA:
- porttype = ZD1201_PORTTYPE_BSS;
- break;
- default:
- return -EINVAL;
- }
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
- if (err)
- return err;
- if (zd->monitor && !monitor) {
- zd1201_disable(zd);
- *(__le16 *)buffer = cpu_to_le16(zd->essidlen);
- memcpy(buffer+2, zd->essid, zd->essidlen);
- err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID,
- buffer, IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- return err;
- }
- zd->monitor = monitor;
- /* If monitor mode is set we don't actually turn it on here since it
- * is done during mac reset anyway (see zd1201_mac_enable).
- */
- zd1201_mac_reset(zd);
-
- return 0;
-}
-
-static int zd1201_get_mode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- __u32 *mode = &wrqu->mode;
- struct zd1201 *zd = netdev_priv(dev);
- short porttype;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFPORTTYPE, &porttype);
- if (err)
- return err;
- switch(porttype) {
- case ZD1201_PORTTYPE_IBSS:
- *mode = IW_MODE_ADHOC;
- break;
- case ZD1201_PORTTYPE_BSS:
- *mode = IW_MODE_INFRA;
- break;
- case ZD1201_PORTTYPE_WDS:
- *mode = IW_MODE_REPEAT;
- break;
- case ZD1201_PORTTYPE_PSEUDOIBSS:
- *mode = 8;/* No Pseudo-IBSS... */
- break;
- case ZD1201_PORTTYPE_AP:
- *mode = IW_MODE_MASTER;
- break;
- default:
- dev_dbg(&zd->usb->dev, "Unknown porttype: %d\n",
- porttype);
- *mode = IW_MODE_AUTO;
- }
- if (zd->monitor)
- *mode = IW_MODE_MONITOR;
-
- return 0;
-}
-
-static int zd1201_get_range(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *wrq = &wrqu->data;
- struct iw_range *range = (struct iw_range *)extra;
-
- wrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(struct iw_range));
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = WIRELESS_EXT;
-
- range->max_qual.qual = 128;
- range->max_qual.level = 128;
- range->max_qual.noise = 128;
- range->max_qual.updated = 7;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- range->max_encoding_tokens = ZD1201_NUMKEYS;
-
- range->num_bitrates = 4;
- range->bitrate[0] = 1000000;
- range->bitrate[1] = 2000000;
- range->bitrate[2] = 5500000;
- range->bitrate[3] = 11000000;
-
- range->min_rts = 0;
- range->min_frag = ZD1201_FRAGMIN;
- range->max_rts = ZD1201_RTSMAX;
- range->min_frag = ZD1201_FRAGMAX;
-
- return 0;
-}
-
-/* Little bit of magic here: we only get the quality if we poll
- * for it, and we never get an actual request to trigger such
- * a poll. Therefore we 'assume' that the user will soon ask for
- * the stats after asking the bssid.
- */
-static int zd1201_get_wap(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct zd1201 *zd = netdev_priv(dev);
- unsigned char buffer[6];
-
- if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) {
- /* Unfortunately the quality and noise reported is useless.
- they seem to be accumulators that increase until you
- read them, unless we poll on a fixed interval we can't
- use them
- */
- /*zd->iwstats.qual.qual = le16_to_cpu(((__le16 *)buffer)[0]);*/
- zd->iwstats.qual.level = le16_to_cpu(((__le16 *)buffer)[1]);
- /*zd->iwstats.qual.noise = le16_to_cpu(((__le16 *)buffer)[2]);*/
- zd->iwstats.qual.updated = 2;
- }
-
- return zd1201_getconfig(zd, ZD1201_RID_CURRENTBSSID, ap_addr->sa_data, 6);
-}
-
-static int zd1201_set_scan(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- /* We do everything in get_scan */
- return 0;
-}
-
-static int zd1201_get_scan(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *srq = &wrqu->data;
- struct zd1201 *zd = netdev_priv(dev);
- int err, i, j, enabled_save;
- struct iw_event iwe;
- char *cev = extra;
- char *end_buf = extra + IW_SCAN_MAX_DATA;
-
- /* No scanning in AP mode */
- if (zd->ap)
- return -EOPNOTSUPP;
-
- /* Scan doesn't seem to work if disabled */
- enabled_save = zd->mac_enabled;
- zd1201_enable(zd);
-
- zd->rxdatas = 0;
- err = zd1201_docmd(zd, ZD1201_CMDCODE_INQUIRE,
- ZD1201_INQ_SCANRESULTS, 0, 0);
- if (err)
- return err;
-
- wait_event_interruptible(zd->rxdataq, zd->rxdatas);
- if (!zd->rxlen)
- return -EIO;
-
- if (le16_to_cpu(*(__le16*)&zd->rxdata[2]) != ZD1201_INQ_SCANRESULTS)
- return -EIO;
-
- for(i=8; i<zd->rxlen; i+=62) {
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, zd->rxdata+i+6, 6);
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.length = zd->rxdata[i+16];
- iwe.u.data.flags = 1;
- cev = iwe_stream_add_point(info, cev, end_buf,
- &iwe, zd->rxdata+i+18);
-
- iwe.cmd = SIOCGIWMODE;
- if (zd->rxdata[i+14]&0x01)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_UINT_LEN);
-
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = zd->rxdata[i+0];
- iwe.u.freq.e = 0;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- iwe.cmd = SIOCGIWRATE;
- iwe.u.bitrate.fixed = 0;
- iwe.u.bitrate.disabled = 0;
- for (j=0; j<10; j++) if (zd->rxdata[i+50+j]) {
- iwe.u.bitrate.value = (zd->rxdata[i+50+j]&0x7f)*500000;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
-
- iwe.cmd = SIOCGIWENCODE;
- iwe.u.data.length = 0;
- if (zd->rxdata[i+14]&0x10)
- iwe.u.data.flags = IW_ENCODE_ENABLED;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- cev = iwe_stream_add_point(info, cev, end_buf, &iwe, NULL);
-
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.qual = zd->rxdata[i+4];
- iwe.u.qual.noise= zd->rxdata[i+2]/10-100;
- iwe.u.qual.level = (256+zd->rxdata[i+4]*100)/255-100;
- iwe.u.qual.updated = 7;
- cev = iwe_stream_add_event(info, cev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
- }
-
- if (!enabled_save)
- zd1201_disable(zd);
-
- srq->length = cev - extra;
- srq->flags = 0;
-
- return 0;
-}
-
-static int zd1201_set_essid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
-{
- struct iw_point *data = &wrqu->data;
- struct zd1201 *zd = netdev_priv(dev);
-
- if (data->length > IW_ESSID_MAX_SIZE)
- return -EINVAL;
- if (data->length < 1)
- data->length = 1;
- zd->essidlen = data->length;
- memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
- memcpy(zd->essid, essid, data->length);
- return zd1201_join(zd, zd->essid, zd->essidlen);
-}
-
-static int zd1201_get_essid(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *essid)
-{
- struct iw_point *data = &wrqu->data;
- struct zd1201 *zd = netdev_priv(dev);
-
- memcpy(essid, zd->essid, zd->essidlen);
- data->flags = 1;
- data->length = zd->essidlen;
-
- return 0;
-}
-
-static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *nick)
-{
- struct iw_point *data = &wrqu->data;
- strcpy(nick, "zd1201");
- data->flags = 1;
- data->length = strlen(nick);
- return 0;
-}
-
-static int zd1201_set_rate(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct zd1201 *zd = netdev_priv(dev);
- short rate;
- int err;
-
- switch (rrq->value) {
- case 1000000:
- rate = ZD1201_RATEB1;
- break;
- case 2000000:
- rate = ZD1201_RATEB2;
- break;
- case 5500000:
- rate = ZD1201_RATEB5;
- break;
- case 11000000:
- default:
- rate = ZD1201_RATEB11;
- break;
- }
- if (!rrq->fixed) { /* Also enable all lower bitrates */
- rate |= rate-1;
- }
-
- err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL, rate);
- if (err)
- return err;
-
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_rate(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct zd1201 *zd = netdev_priv(dev);
- short rate;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CURRENTTXRATE, &rate);
- if (err)
- return err;
-
- switch(rate) {
- case 1:
- rrq->value = 1000000;
- break;
- case 2:
- rrq->value = 2000000;
- break;
- case 5:
- rrq->value = 5500000;
- break;
- case 11:
- rrq->value = 11000000;
- break;
- default:
- rrq->value = 0;
- }
- rrq->fixed = 0;
- rrq->disabled = 0;
-
- return 0;
-}
-
-static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct zd1201 *zd = netdev_priv(dev);
- int err;
- short val = rts->value;
-
- if (rts->disabled || !rts->fixed)
- val = ZD1201_RTSMAX;
- if (val > ZD1201_RTSMAX)
- return -EINVAL;
- if (val < 0)
- return -EINVAL;
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, val);
- if (err)
- return err;
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rts = &wrqu->rts;
- struct zd1201 *zd = netdev_priv(dev);
- short rtst;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFRTSTHRESHOLD, &rtst);
- if (err)
- return err;
- rts->value = rtst;
- rts->disabled = (rts->value == ZD1201_RTSMAX);
- rts->fixed = 1;
-
- return 0;
-}
-
-static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *frag = &wrqu->frag;
- struct zd1201 *zd = netdev_priv(dev);
- int err;
- short val = frag->value;
-
- if (frag->disabled || !frag->fixed)
- val = ZD1201_FRAGMAX;
- if (val > ZD1201_FRAGMAX)
- return -EINVAL;
- if (val < ZD1201_FRAGMIN)
- return -EINVAL;
- if (val & 1)
- return -EINVAL;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, val);
- if (err)
- return err;
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *frag = &wrqu->frag;
- struct zd1201 *zd = netdev_priv(dev);
- short fragt;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFFRAGTHRESHOLD, &fragt);
- if (err)
- return err;
- frag->value = fragt;
- frag->disabled = (frag->value == ZD1201_FRAGMAX);
- frag->fixed = 1;
-
- return 0;
-}
-
-static int zd1201_set_retry(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- return 0;
-}
-
-static int zd1201_get_retry(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- return 0;
-}
-
-static int zd1201_set_encode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *key)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct zd1201 *zd = netdev_priv(dev);
- short i;
- int err, rid;
-
- if (erq->length > ZD1201_MAXKEYLEN)
- return -EINVAL;
-
- i = (erq->flags & IW_ENCODE_INDEX)-1;
- if (i == -1) {
- err = zd1201_getconfig16(zd,ZD1201_RID_CNFDEFAULTKEYID,&i);
- if (err)
- return err;
- } else {
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, i);
- if (err)
- return err;
- }
-
- if (i < 0 || i >= ZD1201_NUMKEYS)
- return -EINVAL;
-
- rid = ZD1201_RID_CNFDEFAULTKEY0 + i;
- err = zd1201_setconfig(zd, rid, key, erq->length, 1);
- if (err)
- return err;
- zd->encode_keylen[i] = erq->length;
- memcpy(zd->encode_keys[i], key, erq->length);
-
- i=0;
- if (!(erq->flags & IW_ENCODE_DISABLED & IW_ENCODE_MODE)) {
- i |= 0x01;
- zd->encode_enabled = 1;
- } else
- zd->encode_enabled = 0;
- if (erq->flags & IW_ENCODE_RESTRICTED & IW_ENCODE_MODE) {
- i |= 0x02;
- zd->encode_restricted = 1;
- } else
- zd->encode_restricted = 0;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFWEBFLAGS, i);
- if (err)
- return err;
-
- if (zd->encode_enabled)
- i = ZD1201_CNFAUTHENTICATION_SHAREDKEY;
- else
- i = ZD1201_CNFAUTHENTICATION_OPENSYSTEM;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFAUTHENTICATION, i);
- if (err)
- return err;
-
- return zd1201_mac_reset(zd);
-}
-
-static int zd1201_get_encode(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *key)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct zd1201 *zd = netdev_priv(dev);
- short i;
- int err;
-
- if (zd->encode_enabled)
- erq->flags = IW_ENCODE_ENABLED;
- else
- erq->flags = IW_ENCODE_DISABLED;
- if (zd->encode_restricted)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- i = (erq->flags & IW_ENCODE_INDEX) -1;
- if (i == -1) {
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFDEFAULTKEYID, &i);
- if (err)
- return err;
- }
- if (i<0 || i>= ZD1201_NUMKEYS)
- return -EINVAL;
-
- erq->flags |= i+1;
-
- erq->length = zd->encode_keylen[i];
- memcpy(key, zd->encode_keys[i], erq->length);
-
- return 0;
-}
-
-static int zd1201_set_power(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct zd1201 *zd = netdev_priv(dev);
- short enabled, duration, level;
- int err;
-
- enabled = vwrq->disabled ? 0 : 1;
- if (enabled) {
- if (vwrq->flags & IW_POWER_PERIOD) {
- duration = vwrq->value;
- err = zd1201_setconfig16(zd,
- ZD1201_RID_CNFMAXSLEEPDURATION, duration);
- if (err)
- return err;
- goto out;
- }
- if (vwrq->flags & IW_POWER_TIMEOUT) {
- err = zd1201_getconfig16(zd,
- ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
- if (err)
- return err;
- level = vwrq->value * 4 / duration;
- if (level > 4)
- level = 4;
- if (level < 0)
- level = 0;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFPMEPS,
- level);
- if (err)
- return err;
- goto out;
- }
- return -EINVAL;
- }
-out:
- return zd1201_setconfig16(zd, ZD1201_RID_CNFPMENABLED, enabled);
-}
-
-static int zd1201_get_power(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct zd1201 *zd = netdev_priv(dev);
- short enabled, level, duration;
- int err;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMENABLED, &enabled);
- if (err)
- return err;
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFPMEPS, &level);
- if (err)
- return err;
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXSLEEPDURATION, &duration);
- if (err)
- return err;
- vwrq->disabled = enabled ? 0 : 1;
- if (vwrq->flags & IW_POWER_TYPE) {
- if (vwrq->flags & IW_POWER_PERIOD) {
- vwrq->value = duration;
- vwrq->flags = IW_POWER_PERIOD;
- } else {
- vwrq->value = duration * level / 4;
- vwrq->flags = IW_POWER_TIMEOUT;
- }
- }
- if (vwrq->flags & IW_POWER_MODE) {
- if (enabled && level)
- vwrq->flags = IW_POWER_UNICAST_R;
- else
- vwrq->flags = IW_POWER_ALL_R;
- }
-
- return 0;
-}
-
-
-static const iw_handler zd1201_iw_handler[] =
-{
- IW_HANDLER(SIOCSIWCOMMIT, zd1201_config_commit),
- IW_HANDLER(SIOCGIWNAME, zd1201_get_name),
- IW_HANDLER(SIOCSIWFREQ, zd1201_set_freq),
- IW_HANDLER(SIOCGIWFREQ, zd1201_get_freq),
- IW_HANDLER(SIOCSIWMODE, zd1201_set_mode),
- IW_HANDLER(SIOCGIWMODE, zd1201_get_mode),
- IW_HANDLER(SIOCGIWRANGE, zd1201_get_range),
- IW_HANDLER(SIOCGIWAP, zd1201_get_wap),
- IW_HANDLER(SIOCSIWSCAN, zd1201_set_scan),
- IW_HANDLER(SIOCGIWSCAN, zd1201_get_scan),
- IW_HANDLER(SIOCSIWESSID, zd1201_set_essid),
- IW_HANDLER(SIOCGIWESSID, zd1201_get_essid),
- IW_HANDLER(SIOCGIWNICKN, zd1201_get_nick),
- IW_HANDLER(SIOCSIWRATE, zd1201_set_rate),
- IW_HANDLER(SIOCGIWRATE, zd1201_get_rate),
- IW_HANDLER(SIOCSIWRTS, zd1201_set_rts),
- IW_HANDLER(SIOCGIWRTS, zd1201_get_rts),
- IW_HANDLER(SIOCSIWFRAG, zd1201_set_frag),
- IW_HANDLER(SIOCGIWFRAG, zd1201_get_frag),
- IW_HANDLER(SIOCSIWRETRY, zd1201_set_retry),
- IW_HANDLER(SIOCGIWRETRY, zd1201_get_retry),
- IW_HANDLER(SIOCSIWENCODE, zd1201_set_encode),
- IW_HANDLER(SIOCGIWENCODE, zd1201_get_encode),
- IW_HANDLER(SIOCSIWPOWER, zd1201_set_power),
- IW_HANDLER(SIOCGIWPOWER, zd1201_get_power),
-};
-
-static int zd1201_set_hostauth(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- return zd1201_setconfig16(zd, ZD1201_RID_CNFHOSTAUTH, rrq->value);
-}
-
-static int zd1201_get_hostauth(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
- short hostauth;
- int err;
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFHOSTAUTH, &hostauth);
- if (err)
- return err;
- rrq->value = hostauth;
- rrq->fixed = 1;
-
- return 0;
-}
-
-static int zd1201_auth_sta(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct sockaddr *sta = &wrqu->ap_addr;
- struct zd1201 *zd = netdev_priv(dev);
- unsigned char buffer[10];
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- memcpy(buffer, sta->sa_data, ETH_ALEN);
- *(short*)(buffer+6) = 0; /* 0==success, 1==failure */
- *(short*)(buffer+8) = 0;
-
- return zd1201_setconfig(zd, ZD1201_RID_AUTHENTICATESTA, buffer, 10, 1);
-}
-
-static int zd1201_set_maxassoc(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- return zd1201_setconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, rrq->value);
-}
-
-static int zd1201_get_maxassoc(struct net_device *dev,
- struct iw_request_info *info, union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *rrq = &wrqu->param;
- struct zd1201 *zd = netdev_priv(dev);
- short maxassoc;
- int err;
-
- if (!zd->ap)
- return -EOPNOTSUPP;
-
- err = zd1201_getconfig16(zd, ZD1201_RID_CNFMAXASSOCSTATIONS, &maxassoc);
- if (err)
- return err;
- rrq->value = maxassoc;
- rrq->fixed = 1;
-
- return 0;
-}
-
-static const iw_handler zd1201_private_handler[] = {
- zd1201_set_hostauth, /* ZD1201SIWHOSTAUTH */
- zd1201_get_hostauth, /* ZD1201GIWHOSTAUTH */
- zd1201_auth_sta, /* ZD1201SIWAUTHSTA */
- NULL, /* nothing to get */
- zd1201_set_maxassoc, /* ZD1201SIMAXASSOC */
- zd1201_get_maxassoc, /* ZD1201GIMAXASSOC */
-};
-
-static const struct iw_priv_args zd1201_private_args[] = {
- { ZD1201SIWHOSTAUTH, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_NONE, "sethostauth" },
- { ZD1201GIWHOSTAUTH, IW_PRIV_TYPE_NONE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostauth" },
- { ZD1201SIWAUTHSTA, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_NONE, "authstation" },
- { ZD1201SIWMAXASSOC, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- IW_PRIV_TYPE_NONE, "setmaxassoc" },
- { ZD1201GIWMAXASSOC, IW_PRIV_TYPE_NONE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getmaxassoc" },
-};
-
-static const struct iw_handler_def zd1201_iw_handlers = {
- .num_standard = ARRAY_SIZE(zd1201_iw_handler),
- .num_private = ARRAY_SIZE(zd1201_private_handler),
- .num_private_args = ARRAY_SIZE(zd1201_private_args),
- .standard = zd1201_iw_handler,
- .private = zd1201_private_handler,
- .private_args = (struct iw_priv_args *) zd1201_private_args,
- .get_wireless_stats = zd1201_get_wireless_stats,
-};
-
-static const struct net_device_ops zd1201_netdev_ops = {
- .ndo_open = zd1201_net_open,
- .ndo_stop = zd1201_net_stop,
- .ndo_start_xmit = zd1201_hard_start_xmit,
- .ndo_tx_timeout = zd1201_tx_timeout,
- .ndo_set_rx_mode = zd1201_set_multicast,
- .ndo_set_mac_address = zd1201_set_mac_address,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int zd1201_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct zd1201 *zd;
- struct net_device *dev;
- struct usb_device *usb;
- int err;
- short porttype;
- char buf[IW_ESSID_MAX_SIZE+2];
- u8 addr[ETH_ALEN];
-
- usb = interface_to_usbdev(interface);
-
- dev = alloc_etherdev(sizeof(*zd));
- if (!dev)
- return -ENOMEM;
- zd = netdev_priv(dev);
- zd->dev = dev;
-
- zd->ap = ap;
- zd->usb = usb;
- zd->removed = 0;
- init_waitqueue_head(&zd->rxdataq);
- INIT_HLIST_HEAD(&zd->fraglist);
-
- err = zd1201_fw_upload(usb, zd->ap);
- if (err) {
- dev_err(&usb->dev, "zd1201 firmware upload failed: %d\n", err);
- goto err_zd;
- }
-
- zd->endp_in = 1;
- zd->endp_out = 1;
- zd->endp_out2 = 2;
- zd->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- zd->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!zd->rx_urb || !zd->tx_urb) {
- err = -ENOMEM;
- goto err_zd;
- }
-
- mdelay(100);
- err = zd1201_drvr_start(zd);
- if (err)
- goto err_zd;
-
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFMAXDATALEN, 2312);
- if (err)
- goto err_start;
-
- err = zd1201_setconfig16(zd, ZD1201_RID_TXRATECNTL,
- ZD1201_RATEB1 | ZD1201_RATEB2 | ZD1201_RATEB5 | ZD1201_RATEB11);
- if (err)
- goto err_start;
-
- dev->netdev_ops = &zd1201_netdev_ops;
- dev->wireless_handlers = &zd1201_iw_handlers;
- dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
- strcpy(dev->name, "wlan%d");
-
- err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, addr, ETH_ALEN);
- if (err)
- goto err_start;
- eth_hw_addr_set(dev, addr);
-
- /* Set wildcard essid to match zd->essid */
- *(__le16 *)buf = cpu_to_le16(0);
- err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf,
- IW_ESSID_MAX_SIZE+2, 1);
- if (err)
- goto err_start;
-
- if (zd->ap)
- porttype = ZD1201_PORTTYPE_AP;
- else
- porttype = ZD1201_PORTTYPE_BSS;
- err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype);
- if (err)
- goto err_start;
-
- SET_NETDEV_DEV(dev, &usb->dev);
-
- err = register_netdev(dev);
- if (err)
- goto err_start;
- dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n",
- dev->name);
-
- usb_set_intfdata(interface, zd);
- zd1201_enable(zd); /* zd1201 likes to startup enabled, */
- zd1201_disable(zd); /* interfering with all the wifis in range */
- return 0;
-
-err_start:
- /* Leave the device in reset state */
- zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0);
-err_zd:
- usb_free_urb(zd->tx_urb);
- usb_free_urb(zd->rx_urb);
- free_netdev(dev);
- return err;
-}
-
-static void zd1201_disconnect(struct usb_interface *interface)
-{
- struct zd1201 *zd = usb_get_intfdata(interface);
- struct hlist_node *node2;
- struct zd1201_frag *frag;
-
- if (!zd)
- return;
- usb_set_intfdata(interface, NULL);
-
- hlist_for_each_entry_safe(frag, node2, &zd->fraglist, fnode) {
- hlist_del_init(&frag->fnode);
- kfree_skb(frag->skb);
- kfree(frag);
- }
-
- if (zd->tx_urb) {
- usb_kill_urb(zd->tx_urb);
- usb_free_urb(zd->tx_urb);
- }
- if (zd->rx_urb) {
- usb_kill_urb(zd->rx_urb);
- usb_free_urb(zd->rx_urb);
- }
-
- if (zd->dev) {
- unregister_netdev(zd->dev);
- free_netdev(zd->dev);
- }
-}
-
-#ifdef CONFIG_PM
-
-static int zd1201_suspend(struct usb_interface *interface,
- pm_message_t message)
-{
- struct zd1201 *zd = usb_get_intfdata(interface);
-
- netif_device_detach(zd->dev);
-
- zd->was_enabled = zd->mac_enabled;
-
- if (zd->was_enabled)
- return zd1201_disable(zd);
- else
- return 0;
-}
-
-static int zd1201_resume(struct usb_interface *interface)
-{
- struct zd1201 *zd = usb_get_intfdata(interface);
-
- if (!zd || !zd->dev)
- return -ENODEV;
-
- netif_device_attach(zd->dev);
-
- if (zd->was_enabled)
- return zd1201_enable(zd);
- else
- return 0;
-}
-
-#else
-
-#define zd1201_suspend NULL
-#define zd1201_resume NULL
-
-#endif
-
-static struct usb_driver zd1201_usb = {
- .name = "zd1201",
- .probe = zd1201_probe,
- .disconnect = zd1201_disconnect,
- .id_table = zd1201_table,
- .suspend = zd1201_suspend,
- .resume = zd1201_resume,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(zd1201_usb);
diff --git a/drivers/net/wireless/zydas/zd1201.h b/drivers/net/wireless/zydas/zd1201.h
deleted file mode 100644
index c46ac87550d1b..0000000000000
--- a/drivers/net/wireless/zydas/zd1201.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (c) 2004, 2005 Jeroen Vreeken ([email protected])
- *
- * Parts of this driver have been derived from a wlan-ng version
- * modified by ZyDAS.
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- */
-
-#ifndef _INCLUDE_ZD1201_H_
-#define _INCLUDE_ZD1201_H_
-
-#define ZD1201_NUMKEYS 4
-#define ZD1201_MAXKEYLEN 13
-#define ZD1201_MAXMULTI 16
-#define ZD1201_FRAGMAX 2500
-#define ZD1201_FRAGMIN 256
-#define ZD1201_RTSMAX 2500
-
-#define ZD1201_RXSIZE 3000
-
-struct zd1201 {
- struct usb_device *usb;
- int removed;
- struct net_device *dev;
- struct iw_statistics iwstats;
-
- int endp_in;
- int endp_out;
- int endp_out2;
- struct urb *rx_urb;
- struct urb *tx_urb;
-
- unsigned char rxdata[ZD1201_RXSIZE];
- int rxlen;
- wait_queue_head_t rxdataq;
- int rxdatas;
- struct hlist_head fraglist;
- unsigned char txdata[ZD1201_RXSIZE];
-
- int ap;
- char essid[IW_ESSID_MAX_SIZE+1];
- int essidlen;
- int mac_enabled;
- int was_enabled;
- int monitor;
- int encode_enabled;
- int encode_restricted;
- unsigned char encode_keys[ZD1201_NUMKEYS][ZD1201_MAXKEYLEN];
- int encode_keylen[ZD1201_NUMKEYS];
-};
-
-struct zd1201_frag {
- struct hlist_node fnode;
- int seq;
- struct sk_buff *skb;
-};
-
-#define ZD1201SIWHOSTAUTH SIOCIWFIRSTPRIV
-#define ZD1201GIWHOSTAUTH ZD1201SIWHOSTAUTH+1
-#define ZD1201SIWAUTHSTA SIOCIWFIRSTPRIV+2
-#define ZD1201SIWMAXASSOC SIOCIWFIRSTPRIV+4
-#define ZD1201GIWMAXASSOC ZD1201SIWMAXASSOC+1
-
-#define ZD1201_FW_TIMEOUT (1000)
-
-#define ZD1201_TX_TIMEOUT (2000)
-
-#define ZD1201_USB_CMDREQ 0
-#define ZD1201_USB_RESREQ 1
-
-#define ZD1201_CMDCODE_INIT 0x00
-#define ZD1201_CMDCODE_ENABLE 0x01
-#define ZD1201_CMDCODE_DISABLE 0x02
-#define ZD1201_CMDCODE_ALLOC 0x0a
-#define ZD1201_CMDCODE_INQUIRE 0x11
-#define ZD1201_CMDCODE_SETRXRID 0x17
-#define ZD1201_CMDCODE_ACCESS 0x21
-
-#define ZD1201_PACKET_EVENTSTAT 0x0
-#define ZD1201_PACKET_RXDATA 0x1
-#define ZD1201_PACKET_INQUIRE 0x2
-#define ZD1201_PACKET_RESOURCE 0x3
-
-#define ZD1201_ACCESSBIT 0x0100
-
-#define ZD1201_RID_CNFPORTTYPE 0xfc00
-#define ZD1201_RID_CNFOWNMACADDR 0xfc01
-#define ZD1201_RID_CNFDESIREDSSID 0xfc02
-#define ZD1201_RID_CNFOWNCHANNEL 0xfc03
-#define ZD1201_RID_CNFOWNSSID 0xfc04
-#define ZD1201_RID_CNFMAXDATALEN 0xfc07
-#define ZD1201_RID_CNFPMENABLED 0xfc09
-#define ZD1201_RID_CNFPMEPS 0xfc0a
-#define ZD1201_RID_CNFMAXSLEEPDURATION 0xfc0c
-#define ZD1201_RID_CNFDEFAULTKEYID 0xfc23
-#define ZD1201_RID_CNFDEFAULTKEY0 0xfc24
-#define ZD1201_RID_CNFDEFAULTKEY1 0xfc25
-#define ZD1201_RID_CNFDEFAULTKEY2 0xfc26
-#define ZD1201_RID_CNFDEFAULTKEY3 0xfc27
-#define ZD1201_RID_CNFWEBFLAGS 0xfc28
-#define ZD1201_RID_CNFAUTHENTICATION 0xfc2a
-#define ZD1201_RID_CNFMAXASSOCSTATIONS 0xfc2b
-#define ZD1201_RID_CNFHOSTAUTH 0xfc2e
-#define ZD1201_RID_CNFGROUPADDRESS 0xfc80
-#define ZD1201_RID_CNFFRAGTHRESHOLD 0xfc82
-#define ZD1201_RID_CNFRTSTHRESHOLD 0xfc83
-#define ZD1201_RID_TXRATECNTL 0xfc84
-#define ZD1201_RID_PROMISCUOUSMODE 0xfc85
-#define ZD1201_RID_CNFBASICRATES 0xfcb3
-#define ZD1201_RID_AUTHENTICATESTA 0xfce3
-#define ZD1201_RID_CURRENTBSSID 0xfd42
-#define ZD1201_RID_COMMSQUALITY 0xfd43
-#define ZD1201_RID_CURRENTTXRATE 0xfd44
-#define ZD1201_RID_CNFMAXTXBUFFERNUMBER 0xfda0
-#define ZD1201_RID_CURRENTCHANNEL 0xfdc1
-
-#define ZD1201_INQ_SCANRESULTS 0xf101
-
-#define ZD1201_INF_LINKSTATUS 0xf200
-#define ZD1201_INF_ASSOCSTATUS 0xf201
-#define ZD1201_INF_AUTHREQ 0xf202
-
-#define ZD1201_ASSOCSTATUS_STAASSOC 0x1
-#define ZD1201_ASSOCSTATUS_REASSOC 0x2
-#define ZD1201_ASSOCSTATUS_DISASSOC 0x3
-#define ZD1201_ASSOCSTATUS_ASSOCFAIL 0x4
-#define ZD1201_ASSOCSTATUS_AUTHFAIL 0x5
-
-#define ZD1201_PORTTYPE_IBSS 0
-#define ZD1201_PORTTYPE_BSS 1
-#define ZD1201_PORTTYPE_WDS 2
-#define ZD1201_PORTTYPE_PSEUDOIBSS 3
-#define ZD1201_PORTTYPE_AP 6
-
-#define ZD1201_RATEB1 1
-#define ZD1201_RATEB2 2
-#define ZD1201_RATEB5 4 /* 5.5 really, but 5 is shorter :) */
-#define ZD1201_RATEB11 8
-
-#define ZD1201_CNFAUTHENTICATION_OPENSYSTEM 0x0001
-#define ZD1201_CNFAUTHENTICATION_SHAREDKEY 0x0002
-
-#endif /* _INCLUDE_ZD1201_H_ */
--
2.39.2

2023-10-23 13:22:16

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 01/10] wifi: libertas: drop 16-bit PCMCIA support

From: Arnd Bergmann <[email protected]>

With all the other PCMCIA WLAN adapters gone from the kernel, this is now
the last remaining device with this interface, but as far as I can tell,
all the actual libertas users were actually using either SDIO or USB.

Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/net/wireless/marvell/libertas/Kconfig | 7 +-
.../net/wireless/marvell/libertas/Makefile | 1 -
drivers/net/wireless/marvell/libertas/if_cs.c | 957 ------------------
3 files changed, 1 insertion(+), 964 deletions(-)
delete mode 100644 drivers/net/wireless/marvell/libertas/if_cs.c

diff --git a/drivers/net/wireless/marvell/libertas/Kconfig b/drivers/net/wireless/marvell/libertas/Kconfig
index 6d62ab49aa8d4..5bc92cb6b0fed 100644
--- a/drivers/net/wireless/marvell/libertas/Kconfig
+++ b/drivers/net/wireless/marvell/libertas/Kconfig
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config LIBERTAS
tristate "Marvell 8xxx Libertas WLAN driver support"
+ depends on USB || SDIO || SPI
depends on CFG80211
select WIRELESS_EXT
select WEXT_SPY
@@ -15,12 +16,6 @@ config LIBERTAS_USB
help
A driver for Marvell Libertas 8388 USB devices.

-config LIBERTAS_CS
- tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
- depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP
- help
- A driver for Marvell Libertas 8385 CompactFlash devices.
-
config LIBERTAS_SDIO
tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards"
depends on LIBERTAS && MMC
diff --git a/drivers/net/wireless/marvell/libertas/Makefile b/drivers/net/wireless/marvell/libertas/Makefile
index 41b9b440a5422..2ac04f4d61a52 100644
--- a/drivers/net/wireless/marvell/libertas/Makefile
+++ b/drivers/net/wireless/marvell/libertas/Makefile
@@ -17,6 +17,5 @@ libertas_spi-objs += if_spi.o

obj-$(CONFIG_LIBERTAS) += libertas.o
obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
-obj-$(CONFIG_LIBERTAS_CS) += libertas_cs.o
obj-$(CONFIG_LIBERTAS_SDIO) += libertas_sdio.o
obj-$(CONFIG_LIBERTAS_SPI) += libertas_spi.o
diff --git a/drivers/net/wireless/marvell/libertas/if_cs.c b/drivers/net/wireless/marvell/libertas/if_cs.c
deleted file mode 100644
index 4103f15bca6bf..0000000000000
--- a/drivers/net/wireless/marvell/libertas/if_cs.c
+++ /dev/null
@@ -1,957 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
-
- Driver for the Marvell 8385 based compact flash WLAN cards.
-
- (C) 2007 by Holger Schurig <[email protected]>
-
-
-*/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/moduleparam.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
-#include <linux/io.h>
-
-#define DRV_NAME "libertas_cs"
-
-#include "decl.h"
-#include "defs.h"
-#include "dev.h"
-
-
-/********************************************************************/
-/* Module stuff */
-/********************************************************************/
-
-MODULE_AUTHOR("Holger Schurig <[email protected]>");
-MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
-MODULE_LICENSE("GPL");
-
-
-
-/********************************************************************/
-/* Data structures */
-/********************************************************************/
-
-struct if_cs_card {
- struct pcmcia_device *p_dev;
- struct lbs_private *priv;
- void __iomem *iobase;
- bool align_regs;
- u32 model;
-};
-
-
-enum {
- MODEL_UNKNOWN = 0x00,
- MODEL_8305 = 0x01,
- MODEL_8381 = 0x02,
- MODEL_8385 = 0x03
-};
-
-static const struct lbs_fw_table fw_table[] = {
- { MODEL_8305, "libertas/cf8305.bin", NULL },
- { MODEL_8305, "libertas_cs_helper.fw", NULL },
- { MODEL_8381, "libertas/cf8381_helper.bin", "libertas/cf8381.bin" },
- { MODEL_8381, "libertas_cs_helper.fw", "libertas_cs.fw" },
- { MODEL_8385, "libertas/cf8385_helper.bin", "libertas/cf8385.bin" },
- { MODEL_8385, "libertas_cs_helper.fw", "libertas_cs.fw" },
- { 0, NULL, NULL }
-};
-MODULE_FIRMWARE("libertas/cf8305.bin");
-MODULE_FIRMWARE("libertas/cf8381_helper.bin");
-MODULE_FIRMWARE("libertas/cf8381.bin");
-MODULE_FIRMWARE("libertas/cf8385_helper.bin");
-MODULE_FIRMWARE("libertas/cf8385.bin");
-MODULE_FIRMWARE("libertas_cs_helper.fw");
-MODULE_FIRMWARE("libertas_cs.fw");
-
-
-/********************************************************************/
-/* Hardware access */
-/********************************************************************/
-
-/* This define enables wrapper functions which allow you
- to dump all register accesses. You normally won't this,
- except for development */
-/* #define DEBUG_IO */
-
-#ifdef DEBUG_IO
-static int debug_output = 0;
-#else
-/* This way the compiler optimizes the printk's away */
-#define debug_output 0
-#endif
-
-static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
-{
- unsigned int val = ioread8(card->iobase + reg);
- if (debug_output)
- printk(KERN_INFO "inb %08x<%02x\n", reg, val);
- return val;
-}
-static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
-{
- unsigned int val = ioread16(card->iobase + reg);
- if (debug_output)
- printk(KERN_INFO "inw %08x<%04x\n", reg, val);
- return val;
-}
-static inline void if_cs_read16_rep(
- struct if_cs_card *card,
- uint reg,
- void *buf,
- unsigned long count)
-{
- if (debug_output)
- printk(KERN_INFO "insw %08x<(0x%lx words)\n",
- reg, count);
- ioread16_rep(card->iobase + reg, buf, count);
-}
-
-static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
-{
- if (debug_output)
- printk(KERN_INFO "outb %08x>%02x\n", reg, val);
- iowrite8(val, card->iobase + reg);
-}
-
-static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
-{
- if (debug_output)
- printk(KERN_INFO "outw %08x>%04x\n", reg, val);
- iowrite16(val, card->iobase + reg);
-}
-
-static inline void if_cs_write16_rep(
- struct if_cs_card *card,
- uint reg,
- const void *buf,
- unsigned long count)
-{
- if (debug_output)
- printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
- reg, count);
- iowrite16_rep(card->iobase + reg, buf, count);
-}
-
-
-/*
- * I know that polling/delaying is frowned upon. However, this procedure
- * with polling is needed while downloading the firmware. At this stage,
- * the hardware does unfortunately not create any interrupts.
- *
- * Fortunately, this function is never used once the firmware is in
- * the card. :-)
- *
- * As a reference, see the "Firmware Specification v5.1", page 18
- * and 19. I did not follow their suggested timing to the word,
- * but this works nice & fast anyway.
- */
-static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
-{
- int i;
-
- for (i = 0; i < 100000; i++) {
- u8 val = if_cs_read8(card, addr);
- if (val == reg)
- return 0;
- udelay(5);
- }
- return -ETIME;
-}
-
-
-
-/*
- * First the bitmasks for the host/card interrupt/status registers:
- */
-#define IF_CS_BIT_TX 0x0001
-#define IF_CS_BIT_RX 0x0002
-#define IF_CS_BIT_COMMAND 0x0004
-#define IF_CS_BIT_RESP 0x0008
-#define IF_CS_BIT_EVENT 0x0010
-#define IF_CS_BIT_MASK 0x001f
-
-
-
-/*
- * It's not really clear to me what the host status register is for. It
- * needs to be set almost in union with "host int cause". The following
- * bits from above are used:
- *
- * IF_CS_BIT_TX driver downloaded a data packet
- * IF_CS_BIT_RX driver got a data packet
- * IF_CS_BIT_COMMAND driver downloaded a command
- * IF_CS_BIT_RESP not used (has some meaning with powerdown)
- * IF_CS_BIT_EVENT driver read a host event
- */
-#define IF_CS_HOST_STATUS 0x00000000
-
-/*
- * With the host int cause register can the host (that is, Linux) cause
- * an interrupt in the firmware, to tell the firmware about those events:
- *
- * IF_CS_BIT_TX a data packet has been downloaded
- * IF_CS_BIT_RX a received data packet has retrieved
- * IF_CS_BIT_COMMAND a firmware block or a command has been downloaded
- * IF_CS_BIT_RESP not used (has some meaning with powerdown)
- * IF_CS_BIT_EVENT a host event (link lost etc) has been retrieved
- */
-#define IF_CS_HOST_INT_CAUSE 0x00000002
-
-/*
- * The host int mask register is used to enable/disable interrupt. However,
- * I have the suspicion that disabled interrupts are lost.
- */
-#define IF_CS_HOST_INT_MASK 0x00000004
-
-/*
- * Used to send or receive data packets:
- */
-#define IF_CS_WRITE 0x00000016
-#define IF_CS_WRITE_LEN 0x00000014
-#define IF_CS_READ 0x00000010
-#define IF_CS_READ_LEN 0x00000024
-
-/*
- * Used to send commands (and to send firmware block) and to
- * receive command responses:
- */
-#define IF_CS_CMD 0x0000001A
-#define IF_CS_CMD_LEN 0x00000018
-#define IF_CS_RESP 0x00000012
-#define IF_CS_RESP_LEN 0x00000030
-
-/*
- * The card status registers shows what the card/firmware actually
- * accepts:
- *
- * IF_CS_BIT_TX you may send a data packet
- * IF_CS_BIT_RX you may retrieve a data packet
- * IF_CS_BIT_COMMAND you may send a command
- * IF_CS_BIT_RESP you may retrieve a command response
- * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc)
- *
- * When reading this register several times, you will get back the same
- * results --- with one exception: the IF_CS_BIT_EVENT clear itself
- * automatically.
- *
- * Not that we don't rely on BIT_RX,_BIT_RESP or BIT_EVENT because
- * we handle this via the card int cause register.
- */
-#define IF_CS_CARD_STATUS 0x00000020
-#define IF_CS_CARD_STATUS_MASK 0x7f00
-
-/*
- * The card int cause register is used by the card/firmware to notify us
- * about the following events:
- *
- * IF_CS_BIT_TX a data packet has successfully been sentx
- * IF_CS_BIT_RX a data packet has been received and can be retrieved
- * IF_CS_BIT_COMMAND not used
- * IF_CS_BIT_RESP the firmware has a command response for us
- * IF_CS_BIT_EVENT the card has a event for use (link lost, snr low etc)
- */
-#define IF_CS_CARD_INT_CAUSE 0x00000022
-
-/*
- * This is used to for handshaking with the card's bootloader/helper image
- * to synchronize downloading of firmware blocks.
- */
-#define IF_CS_SQ_READ_LOW 0x00000028
-#define IF_CS_SQ_HELPER_OK 0x10
-
-/*
- * The scratch register tells us ...
- *
- * IF_CS_SCRATCH_BOOT_OK the bootloader runs
- * IF_CS_SCRATCH_HELPER_OK the helper firmware already runs
- */
-#define IF_CS_SCRATCH 0x0000003F
-#define IF_CS_SCRATCH_BOOT_OK 0x00
-#define IF_CS_SCRATCH_HELPER_OK 0x5a
-
-/*
- * Used to detect ancient chips:
- */
-#define IF_CS_PRODUCT_ID 0x0000001C
-#define IF_CS_CF8385_B1_REV 0x12
-#define IF_CS_CF8381_B3_REV 0x04
-#define IF_CS_CF8305_B1_REV 0x03
-
-/*
- * 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 CF8305_MANFID 0x02db
-#define CF8305_CARDID 0x8103
-#define CF8381_MANFID 0x02db
-#define CF8381_CARDID 0x6064
-#define CF8385_MANFID 0x02df
-#define CF8385_CARDID 0x8103
-
-/*
- * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
- * that gets fixed. Currently there's no way to access it from the probe hook.
- */
-static inline u32 get_model(u16 manf_id, u16 card_id)
-{
- /* NOTE: keep in sync with if_cs_ids */
- if (manf_id == CF8305_MANFID && card_id == CF8305_CARDID)
- return MODEL_8305;
- else if (manf_id == CF8381_MANFID && card_id == CF8381_CARDID)
- return MODEL_8381;
- else if (manf_id == CF8385_MANFID && card_id == CF8385_CARDID)
- return MODEL_8385;
- return MODEL_UNKNOWN;
-}
-
-/********************************************************************/
-/* I/O and interrupt handling */
-/********************************************************************/
-
-static inline void if_cs_enable_ints(struct if_cs_card *card)
-{
- if_cs_write16(card, IF_CS_HOST_INT_MASK, 0);
-}
-
-static inline void if_cs_disable_ints(struct if_cs_card *card)
-{
- if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_BIT_MASK);
-}
-
-/*
- * Called from if_cs_host_to_card to send a command to the hardware
- */
-static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
-{
- struct if_cs_card *card = (struct if_cs_card *)priv->card;
- int ret = -1;
- int loops = 0;
-
- if_cs_disable_ints(card);
-
- /* Is hardware ready? */
- while (1) {
- u16 status = if_cs_read16(card, IF_CS_CARD_STATUS);
- if (status & IF_CS_BIT_COMMAND)
- break;
- if (++loops > 100) {
- netdev_err(priv->dev, "card not ready for commands\n");
- goto done;
- }
- mdelay(1);
- }
-
- if_cs_write16(card, IF_CS_CMD_LEN, nb);
-
- if_cs_write16_rep(card, IF_CS_CMD, buf, nb / 2);
- /* Are we supposed to transfer an odd amount of bytes? */
- if (nb & 1)
- if_cs_write8(card, IF_CS_CMD, buf[nb-1]);
-
- /* "Assert the download over interrupt command in the Host
- * status register" */
- if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
-
- /* "Assert the download over interrupt command in the Card
- * interrupt case register" */
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
- ret = 0;
-
-done:
- if_cs_enable_ints(card);
- return ret;
-}
-
-/*
- * Called from if_cs_host_to_card to send a data to the hardware
- */
-static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
-{
- struct if_cs_card *card = (struct if_cs_card *)priv->card;
- u16 status;
-
- if_cs_disable_ints(card);
-
- status = if_cs_read16(card, IF_CS_CARD_STATUS);
- BUG_ON((status & IF_CS_BIT_TX) == 0);
-
- if_cs_write16(card, IF_CS_WRITE_LEN, nb);
-
- /* write even number of bytes, then odd byte if necessary */
- if_cs_write16_rep(card, IF_CS_WRITE, buf, nb / 2);
- if (nb & 1)
- if_cs_write8(card, IF_CS_WRITE, buf[nb-1]);
-
- if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_BIT_TX);
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_TX);
- if_cs_enable_ints(card);
-}
-
-/*
- * Get the command result out of the card.
- */
-static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
-{
- unsigned long flags;
- int ret = -1;
- u16 status;
-
- /* is hardware ready? */
- status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
- if ((status & IF_CS_BIT_RESP) == 0) {
- netdev_err(priv->dev, "no cmd response in card\n");
- *len = 0;
- goto out;
- }
-
- *len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
- if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
- netdev_err(priv->dev,
- "card cmd buffer has invalid # of bytes (%d)\n",
- *len);
- goto out;
- }
-
- /* read even number of bytes, then odd byte if necessary */
- if_cs_read16_rep(priv->card, IF_CS_RESP, data, *len/sizeof(u16));
- if (*len & 1)
- data[*len-1] = if_cs_read8(priv->card, IF_CS_RESP);
-
- /* This is a workaround for a firmware that reports too much
- * bytes */
- *len -= 8;
- ret = 0;
-
- /* Clear this flag again */
- spin_lock_irqsave(&priv->driver_lock, flags);
- priv->dnld_sent = DNLD_RES_RECEIVED;
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
-out:
- return ret;
-}
-
-static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
-{
- struct sk_buff *skb = NULL;
- u16 len;
- u8 *data;
-
- len = if_cs_read16(priv->card, IF_CS_READ_LEN);
- if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- netdev_err(priv->dev,
- "card data buffer has invalid # of bytes (%d)\n",
- len);
- priv->dev->stats.rx_dropped++;
- goto dat_err;
- }
-
- skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
- if (!skb)
- goto out;
- skb_put(skb, len);
- skb_reserve(skb, 2);/* 16 byte align */
- data = skb->data;
-
- /* read even number of bytes, then odd byte if necessary */
- if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16));
- if (len & 1)
- data[len-1] = if_cs_read8(priv->card, IF_CS_READ);
-
-dat_err:
- if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_BIT_RX);
- if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_RX);
-
-out:
- return skb;
-}
-
-static irqreturn_t if_cs_interrupt(int irq, void *data)
-{
- struct if_cs_card *card = data;
- struct lbs_private *priv = card->priv;
- u16 cause;
-
- /* Ask card interrupt cause register if there is something for us */
- cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE);
- lbs_deb_cs("cause 0x%04x\n", cause);
-
- if (cause == 0) {
- /* Not for us */
- return IRQ_NONE;
- }
-
- if (cause == 0xffff) {
- /* Read in junk, the card has probably been removed */
- card->priv->surpriseremoved = 1;
- return IRQ_HANDLED;
- }
-
- if (cause & IF_CS_BIT_RX) {
- struct sk_buff *skb;
- lbs_deb_cs("rx packet\n");
- skb = if_cs_receive_data(priv);
- if (skb)
- lbs_process_rxed_packet(priv, skb);
- }
-
- if (cause & IF_CS_BIT_TX) {
- lbs_deb_cs("tx done\n");
- lbs_host_to_card_done(priv);
- }
-
- if (cause & IF_CS_BIT_RESP) {
- unsigned long flags;
- u8 i;
-
- lbs_deb_cs("cmd resp\n");
- spin_lock_irqsave(&priv->driver_lock, flags);
- i = (priv->resp_idx == 0) ? 1 : 0;
- spin_unlock_irqrestore(&priv->driver_lock, flags);
-
- BUG_ON(priv->resp_len[i]);
- if_cs_receive_cmdres(priv, priv->resp_buf[i],
- &priv->resp_len[i]);
-
- spin_lock_irqsave(&priv->driver_lock, flags);
- lbs_notify_command_response(priv, i);
- spin_unlock_irqrestore(&priv->driver_lock, flags);
- }
-
- if (cause & IF_CS_BIT_EVENT) {
- u16 status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
- if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE,
- IF_CS_BIT_EVENT);
- lbs_queue_event(priv, (status & IF_CS_CARD_STATUS_MASK) >> 8);
- }
-
- /* Clear interrupt cause */
- if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_BIT_MASK);
-
- return IRQ_HANDLED;
-}
-
-
-
-
-/********************************************************************/
-/* Firmware */
-/********************************************************************/
-
-/*
- * Tries to program the helper firmware.
- *
- * Return 0 on success
- */
-static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
-{
- int ret = 0;
- int sent = 0;
- u8 scratch;
-
- /*
- * This is the only place where an unaligned register access happens on
- * the CF8305 card, therefore for the sake of speed of the driver, we do
- * the alignment correction here.
- */
- if (card->align_regs)
- scratch = if_cs_read16(card, IF_CS_SCRATCH) >> 8;
- else
- scratch = if_cs_read8(card, IF_CS_SCRATCH);
-
- /* "If the value is 0x5a, the firmware is already
- * downloaded successfully"
- */
- if (scratch == IF_CS_SCRATCH_HELPER_OK)
- goto done;
-
- /* "If the value is != 00, it is invalid value of register */
- if (scratch != IF_CS_SCRATCH_BOOT_OK) {
- ret = -ENODEV;
- goto done;
- }
-
- lbs_deb_cs("helper size %td\n", fw->size);
-
- /* "Set the 5 bytes of the helper image to 0" */
- /* Not needed, this contains an ARM branch instruction */
-
- for (;;) {
- /* "the number of bytes to send is 256" */
- int count = 256;
- int remain = fw->size - sent;
-
- if (remain < count)
- count = remain;
-
- /*
- * "write the number of bytes to be sent to the I/O Command
- * write length register"
- */
- if_cs_write16(card, IF_CS_CMD_LEN, count);
-
- /* "write this to I/O Command port register as 16 bit writes */
- if (count)
- if_cs_write16_rep(card, IF_CS_CMD,
- &fw->data[sent],
- count >> 1);
-
- /*
- * "Assert the download over interrupt command in the Host
- * status register"
- */
- if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
-
- /*
- * "Assert the download over interrupt command in the Card
- * interrupt case register"
- */
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
-
- /*
- * "The host polls the Card Status register ... for 50 ms before
- * declaring a failure"
- */
- ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
- IF_CS_BIT_COMMAND);
- if (ret < 0) {
- pr_err("can't download helper at 0x%x, ret %d\n",
- sent, ret);
- goto done;
- }
-
- if (count == 0)
- break;
-
- sent += count;
- }
-
-done:
- return ret;
-}
-
-
-static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
-{
- int ret = 0;
- int retry = 0;
- int len = 0;
- int sent;
-
- lbs_deb_cs("fw size %td\n", fw->size);
-
- ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
- IF_CS_SQ_HELPER_OK);
- if (ret < 0) {
- pr_err("helper firmware doesn't answer\n");
- goto done;
- }
-
- for (sent = 0; sent < fw->size; sent += len) {
- len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
- if (len & 1) {
- retry++;
- pr_info("odd, need to retry this firmware block\n");
- } else {
- retry = 0;
- }
-
- if (retry > 20) {
- pr_err("could not download firmware\n");
- ret = -ENODEV;
- goto done;
- }
- if (retry) {
- sent -= len;
- }
-
-
- if_cs_write16(card, IF_CS_CMD_LEN, len);
-
- if_cs_write16_rep(card, IF_CS_CMD,
- &fw->data[sent],
- (len+1) >> 1);
- if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
- if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
-
- ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
- IF_CS_BIT_COMMAND);
- if (ret < 0) {
- pr_err("can't download firmware at 0x%x\n", sent);
- goto done;
- }
- }
-
- ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
- if (ret < 0)
- pr_err("firmware download failed\n");
-
-done:
- return ret;
-}
-
-static void if_cs_prog_firmware(struct lbs_private *priv, int ret,
- const struct firmware *helper,
- const struct firmware *mainfw)
-{
- struct if_cs_card *card = priv->card;
-
- if (ret) {
- pr_err("failed to find firmware (%d)\n", ret);
- return;
- }
-
- /* Load the firmware */
- ret = if_cs_prog_helper(card, helper);
- if (ret == 0 && (card->model != MODEL_8305))
- ret = if_cs_prog_real(card, mainfw);
- if (ret)
- return;
-
- /* Now actually get the IRQ */
- ret = request_irq(card->p_dev->irq, if_cs_interrupt,
- IRQF_SHARED, DRV_NAME, card);
- if (ret) {
- pr_err("error in request_irq\n");
- return;
- }
-
- /*
- * Clear any interrupt cause that happened while sending
- * firmware/initializing card
- */
- if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
- if_cs_enable_ints(card);
-
- /* And finally bring the card up */
- priv->fw_ready = 1;
- if (lbs_start_card(priv) != 0) {
- pr_err("could not activate card\n");
- free_irq(card->p_dev->irq, card);
- }
-}
-
-
-/********************************************************************/
-/* Callback functions for libertas.ko */
-/********************************************************************/
-
-/* Send commands or data packets to the card */
-static int if_cs_host_to_card(struct lbs_private *priv,
- u8 type,
- u8 *buf,
- u16 nb)
-{
- int ret = -1;
-
- switch (type) {
- case MVMS_DAT:
- priv->dnld_sent = DNLD_DATA_SENT;
- if_cs_send_data(priv, buf, nb);
- ret = 0;
- break;
- case MVMS_CMD:
- priv->dnld_sent = DNLD_CMD_SENT;
- ret = if_cs_send_cmd(priv, buf, nb);
- break;
- default:
- netdev_err(priv->dev, "%s: unsupported type %d\n",
- __func__, type);
- }
-
- return ret;
-}
-
-
-static void if_cs_release(struct pcmcia_device *p_dev)
-{
- struct if_cs_card *card = p_dev->priv;
-
- free_irq(p_dev->irq, card);
- pcmcia_disable_device(p_dev);
- if (card->iobase)
- ioport_unmap(card->iobase);
-}
-
-
-static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
-{
- p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
- if (p_dev->resource[1]->end) {
- pr_err("wrong CIS (check number of IO windows)\n");
- return -ENODEV;
- }
-
- /* This reserves IO space but doesn't actually enable it */
- return pcmcia_request_io(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;
-
- card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
- if (!card)
- goto out;
-
- card->p_dev = p_dev;
- p_dev->priv = card;
-
- p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
-
- if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
- pr_err("error in pcmcia_loop_config\n");
- goto out1;
- }
-
- /*
- * Allocate an interrupt line. Note that this does not assign
- * a handler to the interrupt, unless the 'Handler' member of
- * the irq structure is initialized.
- */
- if (!p_dev->irq)
- goto out1;
-
- /* Initialize io access */
- card->iobase = ioport_map(p_dev->resource[0]->start,
- resource_size(p_dev->resource[0]));
- if (!card->iobase) {
- pr_err("error in ioport_map\n");
- ret = -EIO;
- goto out1;
- }
-
- ret = pcmcia_enable_device(p_dev);
- if (ret) {
- pr_err("error in pcmcia_enable_device\n");
- goto out2;
- }
-
- /* Finally, report what we've done */
- lbs_deb_cs("irq %d, io %pR", p_dev->irq, p_dev->resource[0]);
-
- /*
- * Most of the libertas cards can do unaligned register access, but some
- * weird ones cannot. That's especially true for the CF8305 card.
- */
- card->align_regs = false;
-
- card->model = get_model(p_dev->manf_id, p_dev->card_id);
- if (card->model == MODEL_UNKNOWN) {
- pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
- p_dev->manf_id, p_dev->card_id);
- ret = -ENODEV;
- goto out2;
- }
-
- /* Check if we have a current silicon */
- prod_id = if_cs_read8(card, IF_CS_PRODUCT_ID);
- if (card->model == MODEL_8305) {
- card->align_regs = true;
- if (prod_id < IF_CS_CF8305_B1_REV) {
- pr_err("8305 rev B0 and older are not supported\n");
- ret = -ENODEV;
- goto out2;
- }
- }
-
- if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
- pr_err("8381 rev B2 and older are not supported\n");
- ret = -ENODEV;
- goto out2;
- }
-
- if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
- pr_err("8385 rev B0 and older are not supported\n");
- ret = -ENODEV;
- goto out2;
- }
-
- /* Make this card known to the libertas driver */
- priv = lbs_add_card(card, &p_dev->dev);
- if (IS_ERR(priv)) {
- ret = PTR_ERR(priv);
- goto out2;
- }
-
- /* Set up fields in lbs_private */
- card->priv = priv;
- priv->card = card;
- priv->hw_host_to_card = if_cs_host_to_card;
- priv->enter_deep_sleep = NULL;
- priv->exit_deep_sleep = NULL;
- priv->reset_deep_sleep_wakeup = NULL;
-
- /* Get firmware */
- ret = lbs_get_firmware_async(priv, &p_dev->dev, card->model, fw_table,
- if_cs_prog_firmware);
- if (ret) {
- pr_err("failed to find firmware (%d)\n", ret);
- goto out3;
- }
-
- goto out;
-
-out3:
- lbs_remove_card(priv);
-out2:
- ioport_unmap(card->iobase);
-out1:
- pcmcia_disable_device(p_dev);
-out:
- return ret;
-}
-
-
-static void if_cs_detach(struct pcmcia_device *p_dev)
-{
- struct if_cs_card *card = p_dev->priv;
-
- lbs_stop_card(card->priv);
- lbs_remove_card(card->priv);
- if_cs_disable_ints(card);
- if_cs_release(p_dev);
- kfree(card);
-}
-
-
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-static const struct pcmcia_device_id if_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
- PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
- PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
- /* NOTE: keep in sync with get_model() */
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
-
-static struct pcmcia_driver lbs_driver = {
- .owner = THIS_MODULE,
- .name = DRV_NAME,
- .probe = if_cs_probe,
- .remove = if_cs_detach,
- .id_table = if_cs_ids,
-};
-module_pcmcia_driver(lbs_driver);
--
2.39.2

2023-10-23 13:22:19

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 03/10] wifi: remove orphaned cisco/aironet driver

From: Arnd Bergmann <[email protected]>

Cisco Aironet is an 802.11b PCMCIA and mini-PCI with limited support
for Cardbus DMA and for CFG80211.

Both PCMCIA and WEXT are deprecated, and there is little chance
that anyone is still using this driver, so remove it.

Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/net/wireless/Kconfig | 1 -
drivers/net/wireless/Makefile | 1 -
drivers/net/wireless/cisco/Kconfig | 59 -
drivers/net/wireless/cisco/Makefile | 3 -
drivers/net/wireless/cisco/airo.c | 8288 --------------------------
drivers/net/wireless/cisco/airo.h | 10 -
drivers/net/wireless/cisco/airo_cs.c | 218 -
7 files changed, 8580 deletions(-)
delete mode 100644 drivers/net/wireless/cisco/Kconfig
delete mode 100644 drivers/net/wireless/cisco/Makefile
delete mode 100644 drivers/net/wireless/cisco/airo.c
delete mode 100644 drivers/net/wireless/cisco/airo.h
delete mode 100644 drivers/net/wireless/cisco/airo_cs.c

diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7555af5195ec3..834d3725f1a50 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -22,7 +22,6 @@ source "drivers/net/wireless/admtek/Kconfig"
source "drivers/net/wireless/ath/Kconfig"
source "drivers/net/wireless/atmel/Kconfig"
source "drivers/net/wireless/broadcom/Kconfig"
-source "drivers/net/wireless/cisco/Kconfig"
source "drivers/net/wireless/intel/Kconfig"
source "drivers/net/wireless/intersil/Kconfig"
source "drivers/net/wireless/marvell/Kconfig"
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 4d7374d567d18..ee722439d452c 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/
obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/
obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/
obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/
-obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/
obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/
obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/
obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/
diff --git a/drivers/net/wireless/cisco/Kconfig b/drivers/net/wireless/cisco/Kconfig
deleted file mode 100644
index b40ee25aca995..0000000000000
--- a/drivers/net/wireless/cisco/Kconfig
+++ /dev/null
@@ -1,59 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config WLAN_VENDOR_CISCO
- bool "Cisco devices"
- default y
- help
- If you have a wireless card belonging to this class, say Y.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all the
- questions about these cards. If you say Y, you will be asked for
- your specific card in the following questions.
-
-if WLAN_VENDOR_CISCO
-
-config AIRO
- tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
- depends on CFG80211 && (PCI || BROKEN)
- select WIRELESS_EXT
- select CRYPTO
- select CRYPTO_SKCIPHER
- select WEXT_SPY
- select WEXT_PRIV
- help
- This is the standard Linux driver to support Cisco/Aironet ISA and
- PCI 802.11 wireless cards.
- It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
- - with or without encryption) as well as card before the Cisco
- acquisition (Aironet 4500, Aironet 4800, Aironet 4800B).
-
- This driver support both the standard Linux Wireless Extensions
- and Cisco proprietary API, so both the Linux Wireless Tools and the
- Cisco Linux utilities can be used to configure the card.
-
- The driver can be compiled as a module and will be named "airo".
-
-config AIRO_CS
- tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
- depends on CFG80211 && PCMCIA
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select CRYPTO
- select CRYPTO_AES
- select CRYPTO_CTR
- help
- This is the standard Linux driver to support Cisco/Aironet PCMCIA
- 802.11 wireless cards. This driver is the same as the Aironet
- driver part of the Linux Pcmcia package.
- It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X
- - with or without encryption) as well as card before the Cisco
- acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also
- supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom
- 802.11b cards.
-
- This driver support both the standard Linux Wireless Extensions
- and Cisco proprietary API, so both the Linux Wireless Tools and the
- Cisco Linux utilities can be used to configure the card.
-
-endif # WLAN_VENDOR_CISCO
diff --git a/drivers/net/wireless/cisco/Makefile b/drivers/net/wireless/cisco/Makefile
deleted file mode 100644
index 506a19ce375f4..0000000000000
--- a/drivers/net/wireless/cisco/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_AIRO) += airo.o
-obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
deleted file mode 100644
index dbd13f7aa3e6e..0000000000000
--- a/drivers/net/wireless/cisco/airo.c
+++ /dev/null
@@ -1,8288 +0,0 @@
-/*======================================================================
-
- Aironet driver for 4500 and 4800 series cards
-
- This code is released under both the GPL version 2 and BSD licenses.
- Either license may be used. The respective licenses are found at
- the end of this file.
-
- This code was developed by Benjamin Reed <[email protected]>
- including portions of which come from the Aironet PC4500
- Developer's Reference Manual and used with permission. Copyright
- (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use
- code in the Developer's manual was granted for this driver by
- Aironet. Major code contributions were received from Javier Achirica
- <[email protected]> and Jean Tourrilhes <[email protected]>.
- Code was also integrated from the Cisco Aironet driver for Linux.
- Support for MPI350 cards was added by Fabrice Bellet
- <[email protected]>.
-
-======================================================================*/
-
-#include <linux/err.h>
-#include <linux/init.h>
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/bitops.h>
-#include <linux/scatterlist.h>
-#include <linux/crypto.h>
-#include <linux/io.h>
-#include <asm/unaligned.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/uaccess.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
-
-#include <crypto/aes.h>
-#include <crypto/skcipher.h>
-
-#include <net/cfg80211.h>
-#include <net/iw_handler.h>
-
-#include "airo.h"
-
-#define DRV_NAME "airo"
-
-#ifdef CONFIG_PCI
-static const struct pci_device_id card_ids[] = {
- { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID },
- { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, },
- { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, card_ids);
-
-static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *);
-static void airo_pci_remove(struct pci_dev *);
-static int __maybe_unused airo_pci_suspend(struct device *dev);
-static int __maybe_unused airo_pci_resume(struct device *dev);
-
-static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops,
- airo_pci_suspend,
- airo_pci_resume);
-
-static struct pci_driver airo_driver = {
- .name = DRV_NAME,
- .id_table = card_ids,
- .probe = airo_pci_probe,
- .remove = airo_pci_remove,
- .driver.pm = &airo_pci_pm_ops,
-};
-#endif /* CONFIG_PCI */
-
-/* Include Wireless Extension definition and check version - Jean II */
-#include <linux/wireless.h>
-#define WIRELESS_SPY /* enable iwspy support */
-
-#define CISCO_EXT /* enable Cisco extensions */
-#ifdef CISCO_EXT
-#include <linux/delay.h>
-#endif
-
-/* Hack to do some power saving */
-#define POWER_ON_DOWN
-
-/* As you can see this list is HUGH!
- I really don't know what a lot of these counts are about, but they
- are all here for completeness. If the IGNLABEL macro is put in
- infront of the label, that statistic will not be included in the list
- of statistics in the /proc filesystem */
-
-#define IGNLABEL(comment) NULL
-static const char *statsLabels[] = {
- "RxOverrun",
- IGNLABEL("RxPlcpCrcErr"),
- IGNLABEL("RxPlcpFormatErr"),
- IGNLABEL("RxPlcpLengthErr"),
- "RxMacCrcErr",
- "RxMacCrcOk",
- "RxWepErr",
- "RxWepOk",
- "RetryLong",
- "RetryShort",
- "MaxRetries",
- "NoAck",
- "NoCts",
- "RxAck",
- "RxCts",
- "TxAck",
- "TxRts",
- "TxCts",
- "TxMc",
- "TxBc",
- "TxUcFrags",
- "TxUcPackets",
- "TxBeacon",
- "RxBeacon",
- "TxSinColl",
- "TxMulColl",
- "DefersNo",
- "DefersProt",
- "DefersEngy",
- "DupFram",
- "RxFragDisc",
- "TxAged",
- "RxAged",
- "LostSync-MaxRetry",
- "LostSync-MissedBeacons",
- "LostSync-ArlExceeded",
- "LostSync-Deauth",
- "LostSync-Disassoced",
- "LostSync-TsfTiming",
- "HostTxMc",
- "HostTxBc",
- "HostTxUc",
- "HostTxFail",
- "HostRxMc",
- "HostRxBc",
- "HostRxUc",
- "HostRxDiscard",
- IGNLABEL("HmacTxMc"),
- IGNLABEL("HmacTxBc"),
- IGNLABEL("HmacTxUc"),
- IGNLABEL("HmacTxFail"),
- IGNLABEL("HmacRxMc"),
- IGNLABEL("HmacRxBc"),
- IGNLABEL("HmacRxUc"),
- IGNLABEL("HmacRxDiscard"),
- IGNLABEL("HmacRxAccepted"),
- "SsidMismatch",
- "ApMismatch",
- "RatesMismatch",
- "AuthReject",
- "AuthTimeout",
- "AssocReject",
- "AssocTimeout",
- IGNLABEL("ReasonOutsideTable"),
- IGNLABEL("ReasonStatus1"),
- IGNLABEL("ReasonStatus2"),
- IGNLABEL("ReasonStatus3"),
- IGNLABEL("ReasonStatus4"),
- IGNLABEL("ReasonStatus5"),
- IGNLABEL("ReasonStatus6"),
- IGNLABEL("ReasonStatus7"),
- IGNLABEL("ReasonStatus8"),
- IGNLABEL("ReasonStatus9"),
- IGNLABEL("ReasonStatus10"),
- IGNLABEL("ReasonStatus11"),
- IGNLABEL("ReasonStatus12"),
- IGNLABEL("ReasonStatus13"),
- IGNLABEL("ReasonStatus14"),
- IGNLABEL("ReasonStatus15"),
- IGNLABEL("ReasonStatus16"),
- IGNLABEL("ReasonStatus17"),
- IGNLABEL("ReasonStatus18"),
- IGNLABEL("ReasonStatus19"),
- "RxMan",
- "TxMan",
- "RxRefresh",
- "TxRefresh",
- "RxPoll",
- "TxPoll",
- "HostRetries",
- "LostSync-HostReq",
- "HostTxBytes",
- "HostRxBytes",
- "ElapsedUsec",
- "ElapsedSec",
- "LostSyncBetterAP",
- "PrivacyMismatch",
- "Jammed",
- "DiscRxNotWepped",
- "PhyEleMismatch",
- (char*)-1 };
-#ifndef RUN_AT
-#define RUN_AT(x) (jiffies+(x))
-#endif
-
-
-/* These variables are for insmod, since it seems that the rates
- can only be set in setup_card. Rates should be a comma separated
- (no spaces) list of rates (up to 8). */
-
-static int rates[8];
-static char *ssids[3];
-
-static int io[4];
-static int irq[4];
-
-static
-int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at.
- 0 means no limit. For old cards this was 4 */
-
-static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
-static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
- the bap, needed on some older cards and buses. */
-static int adhoc;
-
-static int probe = 1;
-
-static kuid_t proc_kuid;
-static int proc_uid /* = 0 */;
-
-static kgid_t proc_kgid;
-static int proc_gid /* = 0 */;
-
-static int airo_perm = 0555;
-
-static int proc_perm = 0644;
-
-MODULE_AUTHOR("Benjamin Reed");
-MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards. "
- "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs.");
-MODULE_LICENSE("Dual BSD/GPL");
-module_param_hw_array(io, int, ioport, NULL, 0);
-module_param_hw_array(irq, int, irq, NULL, 0);
-module_param_array(rates, int, NULL, 0);
-module_param_array(ssids, charp, NULL, 0);
-module_param(auto_wep, int, 0);
-MODULE_PARM_DESC(auto_wep,
- "If non-zero, the driver will keep looping through the authentication options until an association is made. "
- "The value of auto_wep is number of the wep keys to check. "
- "A value of 2 will try using the key at index 0 and index 1.");
-module_param(aux_bap, int, 0);
-MODULE_PARM_DESC(aux_bap,
- "If non-zero, the driver will switch into a mode that seems to work better for older cards with some older buses. "
- "Before switching it checks that the switch is needed.");
-module_param(maxencrypt, int, 0);
-MODULE_PARM_DESC(maxencrypt,
- "The maximum speed that the card can do encryption. "
- "Units are in 512kbs. "
- "Zero (default) means there is no limit. "
- "Older cards used to be limited to 2mbs (4).");
-module_param(adhoc, int, 0);
-MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode.");
-module_param(probe, int, 0);
-MODULE_PARM_DESC(probe, "If zero, the driver won't start the card.");
-
-module_param(proc_uid, int, 0);
-MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to.");
-module_param(proc_gid, int, 0);
-MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to.");
-module_param(airo_perm, int, 0);
-MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet.");
-module_param(proc_perm, int, 0);
-MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc");
-
-/* This is a kind of sloppy hack to get this information to OUT4500 and
- IN4500. I would be extremely interested in the situation where this
- doesn't work though!!! */
-static int do8bitIO /* = 0 */;
-
-/* Return codes */
-#define SUCCESS 0
-#define ERROR -1
-#define NO_PACKET -2
-
-/* Commands */
-#define NOP2 0x0000
-#define MAC_ENABLE 0x0001
-#define MAC_DISABLE 0x0002
-#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
-#define CMD_SOFTRESET 0x0004
-#define HOSTSLEEP 0x0005
-#define CMD_MAGIC_PKT 0x0006
-#define CMD_SETWAKEMASK 0x0007
-#define CMD_READCFG 0x0008
-#define CMD_SETMODE 0x0009
-#define CMD_ALLOCATETX 0x000a
-#define CMD_TRANSMIT 0x000b
-#define CMD_DEALLOCATETX 0x000c
-#define NOP 0x0010
-#define CMD_WORKAROUND 0x0011
-#define CMD_ALLOCATEAUX 0x0020
-#define CMD_ACCESS 0x0021
-#define CMD_PCIBAP 0x0022
-#define CMD_PCIAUX 0x0023
-#define CMD_ALLOCBUF 0x0028
-#define CMD_GETTLV 0x0029
-#define CMD_PUTTLV 0x002a
-#define CMD_DELTLV 0x002b
-#define CMD_FINDNEXTTLV 0x002c
-#define CMD_PSPNODES 0x0030
-#define CMD_SETCW 0x0031
-#define CMD_SETPCF 0x0032
-#define CMD_SETPHYREG 0x003e
-#define CMD_TXTEST 0x003f
-#define MAC_ENABLETX 0x0101
-#define CMD_LISTBSS 0x0103
-#define CMD_SAVECFG 0x0108
-#define CMD_ENABLEAUX 0x0111
-#define CMD_WRITERID 0x0121
-#define CMD_USEPSPNODES 0x0130
-#define MAC_ENABLERX 0x0201
-
-/* Command errors */
-#define ERROR_QUALIF 0x00
-#define ERROR_ILLCMD 0x01
-#define ERROR_ILLFMT 0x02
-#define ERROR_INVFID 0x03
-#define ERROR_INVRID 0x04
-#define ERROR_LARGE 0x05
-#define ERROR_NDISABL 0x06
-#define ERROR_ALLOCBSY 0x07
-#define ERROR_NORD 0x0B
-#define ERROR_NOWR 0x0C
-#define ERROR_INVFIDTX 0x0D
-#define ERROR_TESTACT 0x0E
-#define ERROR_TAGNFND 0x12
-#define ERROR_DECODE 0x20
-#define ERROR_DESCUNAV 0x21
-#define ERROR_BADLEN 0x22
-#define ERROR_MODE 0x80
-#define ERROR_HOP 0x81
-#define ERROR_BINTER 0x82
-#define ERROR_RXMODE 0x83
-#define ERROR_MACADDR 0x84
-#define ERROR_RATES 0x85
-#define ERROR_ORDER 0x86
-#define ERROR_SCAN 0x87
-#define ERROR_AUTH 0x88
-#define ERROR_PSMODE 0x89
-#define ERROR_RTYPE 0x8A
-#define ERROR_DIVER 0x8B
-#define ERROR_SSID 0x8C
-#define ERROR_APLIST 0x8D
-#define ERROR_AUTOWAKE 0x8E
-#define ERROR_LEAP 0x8F
-
-/* Registers */
-#define COMMAND 0x00
-#define PARAM0 0x02
-#define PARAM1 0x04
-#define PARAM2 0x06
-#define STATUS 0x08
-#define RESP0 0x0a
-#define RESP1 0x0c
-#define RESP2 0x0e
-#define LINKSTAT 0x10
-#define SELECT0 0x18
-#define OFFSET0 0x1c
-#define RXFID 0x20
-#define TXALLOCFID 0x22
-#define TXCOMPLFID 0x24
-#define DATA0 0x36
-#define EVSTAT 0x30
-#define EVINTEN 0x32
-#define EVACK 0x34
-#define SWS0 0x28
-#define SWS1 0x2a
-#define SWS2 0x2c
-#define SWS3 0x2e
-#define AUXPAGE 0x3A
-#define AUXOFF 0x3C
-#define AUXDATA 0x3E
-
-#define FID_TX 1
-#define FID_RX 2
-/* Offset into aux memory for descriptors */
-#define AUX_OFFSET 0x800
-/* Size of allocated packets */
-#define PKTSIZE 1840
-#define RIDSIZE 2048
-/* Size of the transmit queue */
-#define MAXTXQ 64
-
-/* BAP selectors */
-#define BAP0 0 /* Used for receiving packets */
-#define BAP1 2 /* Used for xmiting packets and working with RIDS */
-
-/* Flags */
-#define COMMAND_BUSY 0x8000
-
-#define BAP_BUSY 0x8000
-#define BAP_ERR 0x4000
-#define BAP_DONE 0x2000
-
-#define PROMISC 0xffff
-#define NOPROMISC 0x0000
-
-#define EV_CMD 0x10
-#define EV_CLEARCOMMANDBUSY 0x4000
-#define EV_RX 0x01
-#define EV_TX 0x02
-#define EV_TXEXC 0x04
-#define EV_ALLOC 0x08
-#define EV_LINK 0x80
-#define EV_AWAKE 0x100
-#define EV_TXCPY 0x400
-#define EV_UNKNOWN 0x800
-#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */
-#define EV_AWAKEN 0x2000
-#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC)
-
-#ifdef CHECK_UNKNOWN_INTS
-#define IGNORE_INTS (EV_CMD | EV_UNKNOWN)
-#else
-#define IGNORE_INTS (~STATUS_INTS)
-#endif
-
-/* RID TYPES */
-#define RID_RW 0x20
-
-/* The RIDs */
-#define RID_CAPABILITIES 0xFF00
-#define RID_APINFO 0xFF01
-#define RID_RADIOINFO 0xFF02
-#define RID_UNKNOWN3 0xFF03
-#define RID_RSSI 0xFF04
-#define RID_CONFIG 0xFF10
-#define RID_SSID 0xFF11
-#define RID_APLIST 0xFF12
-#define RID_DRVNAME 0xFF13
-#define RID_ETHERENCAP 0xFF14
-#define RID_WEP_TEMP 0xFF15
-#define RID_WEP_PERM 0xFF16
-#define RID_MODULATION 0xFF17
-#define RID_OPTIONS 0xFF18
-#define RID_ACTUALCONFIG 0xFF20 /*readonly*/
-#define RID_FACTORYCONFIG 0xFF21
-#define RID_UNKNOWN22 0xFF22
-#define RID_LEAPUSERNAME 0xFF23
-#define RID_LEAPPASSWORD 0xFF24
-#define RID_STATUS 0xFF50
-#define RID_BEACON_HST 0xFF51
-#define RID_BUSY_HST 0xFF52
-#define RID_RETRIES_HST 0xFF53
-#define RID_UNKNOWN54 0xFF54
-#define RID_UNKNOWN55 0xFF55
-#define RID_UNKNOWN56 0xFF56
-#define RID_MIC 0xFF57
-#define RID_STATS16 0xFF60
-#define RID_STATS16DELTA 0xFF61
-#define RID_STATS16DELTACLEAR 0xFF62
-#define RID_STATS 0xFF68
-#define RID_STATSDELTA 0xFF69
-#define RID_STATSDELTACLEAR 0xFF6A
-#define RID_ECHOTEST_RID 0xFF70
-#define RID_ECHOTEST_RESULTS 0xFF71
-#define RID_BSSLISTFIRST 0xFF72
-#define RID_BSSLISTNEXT 0xFF73
-#define RID_WPA_BSSLISTFIRST 0xFF74
-#define RID_WPA_BSSLISTNEXT 0xFF75
-
-typedef struct {
- u16 cmd;
- u16 parm0;
- u16 parm1;
- u16 parm2;
-} Cmd;
-
-typedef struct {
- u16 status;
- u16 rsp0;
- u16 rsp1;
- u16 rsp2;
-} Resp;
-
-/*
- * Rids and endian-ness: The Rids will always be in cpu endian, since
- * this all the patches from the big-endian guys end up doing that.
- * so all rid access should use the read/writeXXXRid routines.
- */
-
-/* This structure came from an email sent to me from an engineer at
- aironet for inclusion into this driver */
-typedef struct WepKeyRid WepKeyRid;
-struct WepKeyRid {
- __le16 len;
- __le16 kindex;
- u8 mac[ETH_ALEN];
- __le16 klen;
- u8 key[16];
-} __packed;
-
-/* These structures are from the Aironet's PC4500 Developers Manual */
-typedef struct Ssid Ssid;
-struct Ssid {
- __le16 len;
- u8 ssid[32];
-} __packed;
-
-typedef struct SsidRid SsidRid;
-struct SsidRid {
- __le16 len;
- Ssid ssids[3];
-} __packed;
-
-typedef struct ModulationRid ModulationRid;
-struct ModulationRid {
- __le16 len;
- __le16 modulation;
-#define MOD_DEFAULT cpu_to_le16(0)
-#define MOD_CCK cpu_to_le16(1)
-#define MOD_MOK cpu_to_le16(2)
-} __packed;
-
-typedef struct ConfigRid ConfigRid;
-struct ConfigRid {
- __le16 len; /* sizeof(ConfigRid) */
- __le16 opmode; /* operating mode */
-#define MODE_STA_IBSS cpu_to_le16(0)
-#define MODE_STA_ESS cpu_to_le16(1)
-#define MODE_AP cpu_to_le16(2)
-#define MODE_AP_RPTR cpu_to_le16(3)
-#define MODE_CFG_MASK cpu_to_le16(0xff)
-#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */
-#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */
-#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extensions */
-#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */
-#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */
-#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */
-#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */
-#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */
-#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */
- __le16 rmode; /* receive mode */
-#define RXMODE_BC_MC_ADDR cpu_to_le16(0)
-#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */
-#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */
-#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */
-#define RXMODE_RFMON_ANYBSS cpu_to_le16(4)
-#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */
-#define RXMODE_MASK cpu_to_le16(255)
-#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */
-#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER)
-#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */
- __le16 fragThresh;
- __le16 rtsThres;
- u8 macAddr[ETH_ALEN];
- u8 rates[8];
- __le16 shortRetryLimit;
- __le16 longRetryLimit;
- __le16 txLifetime; /* in kusec */
- __le16 rxLifetime; /* in kusec */
- __le16 stationary;
- __le16 ordering;
- __le16 u16deviceType; /* for overriding device type */
- __le16 cfpRate;
- __le16 cfpDuration;
- __le16 _reserved1[3];
- /*---------- Scanning/Associating ----------*/
- __le16 scanMode;
-#define SCANMODE_ACTIVE cpu_to_le16(0)
-#define SCANMODE_PASSIVE cpu_to_le16(1)
-#define SCANMODE_AIROSCAN cpu_to_le16(2)
- __le16 probeDelay; /* in kusec */
- __le16 probeEnergyTimeout; /* in kusec */
- __le16 probeResponseTimeout;
- __le16 beaconListenTimeout;
- __le16 joinNetTimeout;
- __le16 authTimeout;
- __le16 authType;
-#define AUTH_OPEN cpu_to_le16(0x1)
-#define AUTH_ENCRYPT cpu_to_le16(0x101)
-#define AUTH_SHAREDKEY cpu_to_le16(0x102)
-#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200)
- __le16 associationTimeout;
- __le16 specifiedApTimeout;
- __le16 offlineScanInterval;
- __le16 offlineScanDuration;
- __le16 linkLossDelay;
- __le16 maxBeaconLostTime;
- __le16 refreshInterval;
-#define DISABLE_REFRESH cpu_to_le16(0xFFFF)
- __le16 _reserved1a[1];
- /*---------- Power save operation ----------*/
- __le16 powerSaveMode;
-#define POWERSAVE_CAM cpu_to_le16(0)
-#define POWERSAVE_PSP cpu_to_le16(1)
-#define POWERSAVE_PSPCAM cpu_to_le16(2)
- __le16 sleepForDtims;
- __le16 listenInterval;
- __le16 fastListenInterval;
- __le16 listenDecay;
- __le16 fastListenDelay;
- __le16 _reserved2[2];
- /*---------- Ap/Ibss config items ----------*/
- __le16 beaconPeriod;
- __le16 atimDuration;
- __le16 hopPeriod;
- __le16 channelSet;
- __le16 channel;
- __le16 dtimPeriod;
- __le16 bridgeDistance;
- __le16 radioID;
- /*---------- Radio configuration ----------*/
- __le16 radioType;
-#define RADIOTYPE_DEFAULT cpu_to_le16(0)
-#define RADIOTYPE_802_11 cpu_to_le16(1)
-#define RADIOTYPE_LEGACY cpu_to_le16(2)
- u8 rxDiversity;
- u8 txDiversity;
- __le16 txPower;
-#define TXPOWER_DEFAULT 0
- __le16 rssiThreshold;
-#define RSSI_DEFAULT 0
- __le16 modulation;
-#define PREAMBLE_AUTO cpu_to_le16(0)
-#define PREAMBLE_LONG cpu_to_le16(1)
-#define PREAMBLE_SHORT cpu_to_le16(2)
- __le16 preamble;
- __le16 homeProduct;
- __le16 radioSpecific;
- /*---------- Aironet Extensions ----------*/
- u8 nodeName[16];
- __le16 arlThreshold;
- __le16 arlDecay;
- __le16 arlDelay;
- __le16 _reserved4[1];
- /*---------- Aironet Extensions ----------*/
- u8 magicAction;
-#define MAGIC_ACTION_STSCHG 1
-#define MAGIC_ACTION_RESUME 2
-#define MAGIC_IGNORE_MCAST (1<<8)
-#define MAGIC_IGNORE_BCAST (1<<9)
-#define MAGIC_SWITCH_TO_PSP (0<<10)
-#define MAGIC_STAY_IN_CAM (1<<10)
- u8 magicControl;
- __le16 autoWake;
-} __packed;
-
-typedef struct StatusRid StatusRid;
-struct StatusRid {
- __le16 len;
- u8 mac[ETH_ALEN];
- __le16 mode;
- __le16 errorCode;
- __le16 sigQuality;
- __le16 SSIDlen;
- char SSID[32];
- char apName[16];
- u8 bssid[4][ETH_ALEN];
- __le16 beaconPeriod;
- __le16 dimPeriod;
- __le16 atimDuration;
- __le16 hopPeriod;
- __le16 channelSet;
- __le16 channel;
- __le16 hopsToBackbone;
- __le16 apTotalLoad;
- __le16 generatedLoad;
- __le16 accumulatedArl;
- __le16 signalQuality;
- __le16 currentXmitRate;
- __le16 apDevExtensions;
- __le16 normalizedSignalStrength;
- __le16 shortPreamble;
- u8 apIP[4];
- u8 noisePercent; /* Noise percent in last second */
- u8 noisedBm; /* Noise dBm in last second */
- u8 noiseAvePercent; /* Noise percent in last minute */
- u8 noiseAvedBm; /* Noise dBm in last minute */
- u8 noiseMaxPercent; /* Highest noise percent in last minute */
- u8 noiseMaxdBm; /* Highest noise dbm in last minute */
- __le16 load;
- u8 carrier[4];
- __le16 assocStatus;
-#define STAT_NOPACKETS 0
-#define STAT_NOCARRIERSET 10
-#define STAT_GOTCARRIERSET 11
-#define STAT_WRONGSSID 20
-#define STAT_BADCHANNEL 25
-#define STAT_BADBITRATES 30
-#define STAT_BADPRIVACY 35
-#define STAT_APFOUND 40
-#define STAT_APREJECTED 50
-#define STAT_AUTHENTICATING 60
-#define STAT_DEAUTHENTICATED 61
-#define STAT_AUTHTIMEOUT 62
-#define STAT_ASSOCIATING 70
-#define STAT_DEASSOCIATED 71
-#define STAT_ASSOCTIMEOUT 72
-#define STAT_NOTAIROAP 73
-#define STAT_ASSOCIATED 80
-#define STAT_LEAPING 90
-#define STAT_LEAPFAILED 91
-#define STAT_LEAPTIMEDOUT 92
-#define STAT_LEAPCOMPLETE 93
-} __packed;
-
-typedef struct StatsRid StatsRid;
-struct StatsRid {
- __le16 len;
- __le16 spacer;
- __le32 vals[100];
-} __packed;
-
-typedef struct APListRid APListRid;
-struct APListRid {
- __le16 len;
- u8 ap[4][ETH_ALEN];
-} __packed;
-
-typedef struct CapabilityRid CapabilityRid;
-struct CapabilityRid {
- __le16 len;
- char oui[3];
- char zero;
- __le16 prodNum;
- char manName[32];
- char prodName[16];
- char prodVer[8];
- char factoryAddr[ETH_ALEN];
- char aironetAddr[ETH_ALEN];
- __le16 radioType;
- __le16 country;
- char callid[ETH_ALEN];
- char supportedRates[8];
- char rxDiversity;
- char txDiversity;
- __le16 txPowerLevels[8];
- __le16 hardVer;
- __le16 hardCap;
- __le16 tempRange;
- __le16 softVer;
- __le16 softSubVer;
- __le16 interfaceVer;
- __le16 softCap;
- __le16 bootBlockVer;
- __le16 requiredHard;
- __le16 extSoftCap;
-} __packed;
-
-/* Only present on firmware >= 5.30.17 */
-typedef struct BSSListRidExtra BSSListRidExtra;
-struct BSSListRidExtra {
- __le16 unknown[4];
- u8 fixed[12]; /* WLAN management frame */
- u8 iep[624];
-} __packed;
-
-typedef struct BSSListRid BSSListRid;
-struct BSSListRid {
- __le16 len;
- __le16 index; /* First is 0 and 0xffff means end of list */
-#define RADIO_FH 1 /* Frequency hopping radio type */
-#define RADIO_DS 2 /* Direct sequence radio type */
-#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
- __le16 radioType;
- u8 bssid[ETH_ALEN]; /* Mac address of the BSS */
- u8 zero;
- u8 ssidLen;
- u8 ssid[32];
- __le16 dBm;
-#define CAP_ESS cpu_to_le16(1<<0)
-#define CAP_IBSS cpu_to_le16(1<<1)
-#define CAP_PRIVACY cpu_to_le16(1<<4)
-#define CAP_SHORTHDR cpu_to_le16(1<<5)
- __le16 cap;
- __le16 beaconInterval;
- u8 rates[8]; /* Same as rates for config rid */
- struct { /* For frequency hopping only */
- __le16 dwell;
- u8 hopSet;
- u8 hopPattern;
- u8 hopIndex;
- u8 fill;
- } fh;
- __le16 dsChannel;
- __le16 atimWindow;
-
- /* Only present on firmware >= 5.30.17 */
- BSSListRidExtra extra;
-} __packed;
-
-typedef struct {
- BSSListRid bss;
- struct list_head list;
-} BSSListElement;
-
-typedef struct tdsRssiEntry tdsRssiEntry;
-struct tdsRssiEntry {
- u8 rssipct;
- u8 rssidBm;
-} __packed;
-
-typedef struct tdsRssiRid tdsRssiRid;
-struct tdsRssiRid {
- u16 len;
- tdsRssiEntry x[256];
-} __packed;
-
-typedef struct MICRid MICRid;
-struct MICRid {
- __le16 len;
- __le16 state;
- __le16 multicastValid;
- u8 multicast[16];
- __le16 unicastValid;
- u8 unicast[16];
-} __packed;
-
-typedef struct MICBuffer MICBuffer;
-struct MICBuffer {
- __be16 typelen;
-
- union {
- u8 snap[8];
- struct {
- u8 dsap;
- u8 ssap;
- u8 control;
- u8 orgcode[3];
- u8 fieldtype[2];
- } llc;
- } u;
- __be32 mic;
- __be32 seq;
-} __packed;
-
-typedef struct {
- u8 da[ETH_ALEN];
- u8 sa[ETH_ALEN];
-} etherHead;
-
-#define TXCTL_TXOK (1<<1) /* report if tx is ok */
-#define TXCTL_TXEX (1<<2) /* report if tx fails */
-#define TXCTL_802_3 (0<<3) /* 802.3 packet */
-#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */
-#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */
-#define TXCTL_LLC (1<<4) /* payload is llc */
-#define TXCTL_RELEASE (0<<5) /* release after completion */
-#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */
-
-#define BUSY_FID 0x10000
-
-#ifdef CISCO_EXT
-#define AIROMAGIC 0xa55a
-/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */
-#ifdef SIOCIWFIRSTPRIV
-#ifdef SIOCDEVPRIVATE
-#define AIROOLDIOCTL SIOCDEVPRIVATE
-#define AIROOLDIDIFC AIROOLDIOCTL + 1
-#endif /* SIOCDEVPRIVATE */
-#else /* SIOCIWFIRSTPRIV */
-#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably
- * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root
- * only and don't return the modified struct ifreq to the application which
- * is usually a problem. - Jean II */
-#define AIROIOCTL SIOCIWFIRSTPRIV
-#define AIROIDIFC AIROIOCTL + 1
-
-/* Ioctl constants to be used in airo_ioctl.command */
-
-#define AIROGCAP 0 // Capability rid
-#define AIROGCFG 1 // USED A LOT
-#define AIROGSLIST 2 // System ID list
-#define AIROGVLIST 3 // List of specified AP's
-#define AIROGDRVNAM 4 // NOTUSED
-#define AIROGEHTENC 5 // NOTUSED
-#define AIROGWEPKTMP 6
-#define AIROGWEPKNV 7
-#define AIROGSTAT 8
-#define AIROGSTATSC32 9
-#define AIROGSTATSD32 10
-#define AIROGMICRID 11
-#define AIROGMICSTATS 12
-#define AIROGFLAGS 13
-#define AIROGID 14
-#define AIRORRID 15
-#define AIRORSWVERSION 17
-
-/* Leave gap of 40 commands after AIROGSTATSD32 for future */
-
-#define AIROPCAP AIROGSTATSD32 + 40
-#define AIROPVLIST AIROPCAP + 1
-#define AIROPSLIST AIROPVLIST + 1
-#define AIROPCFG AIROPSLIST + 1
-#define AIROPSIDS AIROPCFG + 1
-#define AIROPAPLIST AIROPSIDS + 1
-#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */
-#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */
-#define AIROPSTCLR AIROPMACOFF + 1
-#define AIROPWEPKEY AIROPSTCLR + 1
-#define AIROPWEPKEYNV AIROPWEPKEY + 1
-#define AIROPLEAPPWD AIROPWEPKEYNV + 1
-#define AIROPLEAPUSR AIROPLEAPPWD + 1
-
-/* Flash codes */
-
-#define AIROFLSHRST AIROPWEPKEYNV + 40
-#define AIROFLSHGCHR AIROFLSHRST + 1
-#define AIROFLSHSTFL AIROFLSHGCHR + 1
-#define AIROFLSHPCHR AIROFLSHSTFL + 1
-#define AIROFLPUTBUF AIROFLSHPCHR + 1
-#define AIRORESTART AIROFLPUTBUF + 1
-
-#define FLASHSIZE 32768
-#define AUXMEMSIZE (256 * 1024)
-
-typedef struct aironet_ioctl {
- unsigned short command; // What to do
- unsigned short len; // Len of data
- unsigned short ridnum; // rid number
- unsigned char __user *data; // d-data
-} aironet_ioctl;
-
-static const char swversion[] = "2.1";
-#endif /* CISCO_EXT */
-
-#define NUM_MODULES 2
-#define MIC_MSGLEN_MAX 2400
-#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX
-#define AIRO_DEF_MTU 2312
-
-typedef struct {
- u32 size; // size
- u8 enabled; // MIC enabled or not
- u32 rxSuccess; // successful packets received
- u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison
- u32 rxNotMICed; // pkts dropped due to not being MIC'd
- u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed
- u32 rxWrongSequence; // pkts dropped due to sequence number violation
- u32 reserve[32];
-} mic_statistics;
-
-typedef struct {
- __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2];
- u64 accum; // accumulated mic, reduced to u32 in final()
- int position; // current position (byte offset) in message
- union {
- u8 d8[4];
- __be32 d32;
- } part; // saves partial message word across update() calls
-} emmh32_context;
-
-typedef struct {
- emmh32_context seed; // Context - the seed
- u32 rx; // Received sequence number
- u32 tx; // Tx sequence number
- u32 window; // Start of window
- u8 valid; // Flag to say if context is valid or not
- u8 key[16];
-} miccntx;
-
-typedef struct {
- miccntx mCtx; // Multicast context
- miccntx uCtx; // Unicast context
-} mic_module;
-
-typedef struct {
- unsigned int rid: 16;
- unsigned int len: 15;
- unsigned int valid: 1;
- dma_addr_t host_addr;
-} Rid;
-
-typedef struct {
- unsigned int offset: 15;
- unsigned int eoc: 1;
- unsigned int len: 15;
- unsigned int valid: 1;
- dma_addr_t host_addr;
-} TxFid;
-
-struct rx_hdr {
- __le16 status, len;
- u8 rssi[2];
- u8 rate;
- u8 freq;
- __le16 tmp[4];
-} __packed;
-
-typedef struct {
- unsigned int ctl: 15;
- unsigned int rdy: 1;
- unsigned int len: 15;
- unsigned int valid: 1;
- dma_addr_t host_addr;
-} RxFid;
-
-/*
- * Host receive descriptor
- */
-typedef struct {
- unsigned char __iomem *card_ram_off; /* offset into card memory of the
- desc */
- RxFid rx_desc; /* card receive descriptor */
- char *virtual_host_addr; /* virtual address of host receive
- buffer */
- int pending;
-} HostRxDesc;
-
-/*
- * Host transmit descriptor
- */
-typedef struct {
- unsigned char __iomem *card_ram_off; /* offset into card memory of the
- desc */
- TxFid tx_desc; /* card transmit descriptor */
- char *virtual_host_addr; /* virtual address of host receive
- buffer */
- int pending;
-} HostTxDesc;
-
-/*
- * Host RID descriptor
- */
-typedef struct {
- unsigned char __iomem *card_ram_off; /* offset into card memory of the
- descriptor */
- Rid rid_desc; /* card RID descriptor */
- char *virtual_host_addr; /* virtual address of host receive
- buffer */
-} HostRidDesc;
-
-typedef struct {
- u16 sw0;
- u16 sw1;
- u16 status;
- u16 len;
-#define HOST_SET (1 << 0)
-#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */
-#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */
-#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */
-#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */
-#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */
-#define HOST_CLR_AID (1 << 7) /* clear AID failure */
-#define HOST_RTS (1 << 9) /* Force RTS use */
-#define HOST_SHORT (1 << 10) /* Do short preamble */
- u16 ctl;
- u16 aid;
- u16 retries;
- u16 fill;
-} TxCtlHdr;
-
-typedef struct {
- u16 ctl;
- u16 duration;
- char addr1[6];
- char addr2[6];
- char addr3[6];
- u16 seq;
- char addr4[6];
-} WifiHdr;
-
-
-typedef struct {
- TxCtlHdr ctlhdr;
- u16 fill1;
- u16 fill2;
- WifiHdr wifihdr;
- u16 gaplen;
- u16 status;
-} WifiCtlHdr;
-
-static WifiCtlHdr wifictlhdr8023 = {
- .ctlhdr = {
- .ctl = HOST_DONT_RLSE,
- }
-};
-
-// A few details needed for WEP (Wireless Equivalent Privacy)
-#define MAX_KEY_SIZE 13 // 128 (?) bits
-#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP
-typedef struct wep_key_t {
- u16 len;
- u8 key[16]; /* 40-bit and 104-bit keys */
-} wep_key_t;
-
-/* List of Wireless Handlers (new API) */
-static const struct iw_handler_def airo_handler_def;
-
-static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)";
-
-struct airo_info;
-
-static int get_dec_u16(char *buffer, int *start, int limit);
-static void OUT4500(struct airo_info *, u16 reg, u16 value);
-static unsigned short IN4500(struct airo_info *, u16 reg);
-static u16 setup_card(struct airo_info*, struct net_device *dev, int lock);
-static int enable_MAC(struct airo_info *ai, int lock);
-static void disable_MAC(struct airo_info *ai, int lock);
-static void enable_interrupts(struct airo_info*);
-static void disable_interrupts(struct airo_info*);
-static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp,
- bool may_sleep);
-static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
-static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
- int whichbap);
-static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen,
- int whichbap);
-static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen,
- int whichbap);
-static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
-static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock);
-static int PC4500_writerid(struct airo_info*, u16 rid, const void
- *pBuf, int len, int lock);
-static int do_writerid(struct airo_info*, u16 rid, const void *rid_data,
- int len, int dummy);
-static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw);
-static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket,
- bool may_sleep);
-static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket,
- bool may_sleep);
-
-static int mpi_send_packet(struct net_device *dev);
-static void mpi_unmap_card(struct pci_dev *pci);
-static void mpi_receive_802_3(struct airo_info *ai);
-static void mpi_receive_802_11(struct airo_info *ai);
-static int waitbusy(struct airo_info *ai);
-
-static irqreturn_t airo_interrupt(int irq, void* dev_id);
-static int airo_thread(void *data);
-static void timer_func(struct net_device *dev);
-static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *, int cmd);
-static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev);
-#ifdef CISCO_EXT
-static int readrids(struct net_device *dev, aironet_ioctl *comp);
-static int writerids(struct net_device *dev, aironet_ioctl *comp);
-static int flashcard(struct net_device *dev, aironet_ioctl *comp);
-#endif /* CISCO_EXT */
-static void micinit(struct airo_info *ai);
-static int micsetup(struct airo_info *ai);
-static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len);
-static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen);
-
-static u8 airo_rssi_to_dbm(tdsRssiEntry *rssi_rid, u8 rssi);
-static u8 airo_dbm_to_pct(tdsRssiEntry *rssi_rid, u8 dbm);
-
-static void airo_networks_free(struct airo_info *ai);
-
-struct airo_info {
- struct net_device *dev;
- struct list_head dev_list;
- /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we
- use the high bit to mark whether it is in use. */
-#define MAX_FIDS 6
-#define MPI_MAX_FIDS 1
- u32 fids[MAX_FIDS];
- ConfigRid config;
- char keyindex; // Used with auto wep
- char defindex; // Used with auto wep
- struct proc_dir_entry *proc_entry;
- spinlock_t aux_lock;
-#define FLAG_RADIO_OFF 0 /* User disabling of MAC */
-#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */
-#define FLAG_RADIO_MASK 0x03
-#define FLAG_ENABLED 2
-#define FLAG_ADHOC 3 /* Needed by MIC */
-#define FLAG_MIC_CAPABLE 4
-#define FLAG_UPDATE_MULTI 5
-#define FLAG_UPDATE_UNI 6
-#define FLAG_802_11 7
-#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */
-#define FLAG_PENDING_XMIT 9
-#define FLAG_PENDING_XMIT11 10
-#define FLAG_MPI 11
-#define FLAG_REGISTERED 12
-#define FLAG_COMMIT 13
-#define FLAG_RESET 14
-#define FLAG_FLASHING 15
-#define FLAG_WPA_CAPABLE 16
- unsigned long flags;
-#define JOB_DIE 0
-#define JOB_XMIT 1
-#define JOB_XMIT11 2
-#define JOB_STATS 3
-#define JOB_PROMISC 4
-#define JOB_MIC 5
-#define JOB_EVENT 6
-#define JOB_AUTOWEP 7
-#define JOB_SCAN_RESULTS 9
- unsigned long jobs;
- int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen,
- int whichbap);
- unsigned short *flash;
- tdsRssiEntry *rssi;
- struct task_struct *list_bss_task;
- struct task_struct *airo_thread_task;
- struct semaphore sem;
- wait_queue_head_t thr_wait;
- unsigned long expires;
- struct {
- struct sk_buff *skb;
- int fid;
- } xmit, xmit11;
- struct net_device *wifidev;
- struct iw_statistics wstats; // wireless stats
- unsigned long scan_timeout; /* Time scan should be read */
- struct iw_spy_data spy_data;
- struct iw_public_data wireless_data;
- /* MIC stuff */
- struct crypto_sync_skcipher *tfm;
- mic_module mod[2];
- mic_statistics micstats;
- HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
- HostTxDesc txfids[MPI_MAX_FIDS];
- HostRidDesc config_desc;
- unsigned long ridbus; // phys addr of config_desc
- struct sk_buff_head txq;// tx queue used by mpi350 code
- struct pci_dev *pci;
- unsigned char __iomem *pcimem;
- unsigned char __iomem *pciaux;
- unsigned char *shared;
- dma_addr_t shared_dma;
- pm_message_t power;
- SsidRid *SSID;
- APListRid APList;
-#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
- char proc_name[IFNAMSIZ];
-
- int wep_capable;
- int max_wep_idx;
- int last_auth;
-
- /* WPA-related stuff */
- unsigned int bssListFirst;
- unsigned int bssListNext;
- unsigned int bssListRidLen;
-
- struct list_head network_list;
- struct list_head network_free_list;
- BSSListElement *networks;
-};
-
-static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen,
- int whichbap)
-{
- return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
-}
-
-static int setup_proc_entry(struct net_device *dev,
- struct airo_info *apriv);
-static int takedown_proc_entry(struct net_device *dev,
- struct airo_info *apriv);
-
-static int cmdreset(struct airo_info *ai);
-static int setflashmode(struct airo_info *ai);
-static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime);
-static int flashputbuf(struct airo_info *ai);
-static int flashrestart(struct airo_info *ai, struct net_device *dev);
-
-#define airo_print(type, name, fmt, args...) \
- printk(type DRV_NAME "(%s): " fmt "\n", name, ##args)
-
-#define airo_print_info(name, fmt, args...) \
- airo_print(KERN_INFO, name, fmt, ##args)
-
-#define airo_print_dbg(name, fmt, args...) \
- airo_print(KERN_DEBUG, name, fmt, ##args)
-
-#define airo_print_warn(name, fmt, args...) \
- airo_print(KERN_WARNING, name, fmt, ##args)
-
-#define airo_print_err(name, fmt, args...) \
- airo_print(KERN_ERR, name, fmt, ##args)
-
-#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash)
-
-/***********************************************************************
- * MIC ROUTINES *
- ***********************************************************************
- */
-
-static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq);
-static void MoveWindow(miccntx *context, u32 micSeq);
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
- struct crypto_sync_skcipher *tfm);
-static void emmh32_init(emmh32_context *context);
-static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
-static void emmh32_final(emmh32_context *context, u8 digest[4]);
-static int flashpchar(struct airo_info *ai, int byte, int dwelltime);
-
-static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len,
- struct crypto_sync_skcipher *tfm)
-{
- /* If the current MIC context is valid and its key is the same as
- * the MIC register, there's nothing to do.
- */
- if (cur->valid && (memcmp(cur->key, key, key_len) == 0))
- return;
-
- /* Age current mic Context */
- memcpy(old, cur, sizeof(*cur));
-
- /* Initialize new context */
- memcpy(cur->key, key, key_len);
- cur->window = 33; /* Window always points to the middle */
- cur->rx = 0; /* Rx Sequence numbers */
- cur->tx = 0; /* Tx sequence numbers */
- cur->valid = 1; /* Key is now valid */
-
- /* Give key to mic seed */
- emmh32_setseed(&cur->seed, key, key_len, tfm);
-}
-
-/* micinit - Initialize mic seed */
-
-static void micinit(struct airo_info *ai)
-{
- MICRid mic_rid;
-
- clear_bit(JOB_MIC, &ai->jobs);
- PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0);
- up(&ai->sem);
-
- ai->micstats.enabled = (le16_to_cpu(mic_rid.state) & 0x00FF) ? 1 : 0;
- if (!ai->micstats.enabled) {
- /* So next time we have a valid key and mic is enabled, we will
- * update the sequence number if the key is the same as before.
- */
- ai->mod[0].uCtx.valid = 0;
- ai->mod[0].mCtx.valid = 0;
- return;
- }
-
- if (mic_rid.multicastValid) {
- age_mic_context(&ai->mod[0].mCtx, &ai->mod[1].mCtx,
- mic_rid.multicast, sizeof(mic_rid.multicast),
- ai->tfm);
- }
-
- if (mic_rid.unicastValid) {
- age_mic_context(&ai->mod[0].uCtx, &ai->mod[1].uCtx,
- mic_rid.unicast, sizeof(mic_rid.unicast),
- ai->tfm);
- }
-}
-
-/* micsetup - Get ready for business */
-
-static int micsetup(struct airo_info *ai)
-{
- int i;
-
- if (ai->tfm == NULL)
- ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0);
-
- if (IS_ERR(ai->tfm)) {
- airo_print_err(ai->dev->name, "failed to load transform for AES");
- ai->tfm = NULL;
- return ERROR;
- }
-
- for (i = 0; i < NUM_MODULES; i++) {
- memset(&ai->mod[i].mCtx, 0, sizeof(miccntx));
- memset(&ai->mod[i].uCtx, 0, sizeof(miccntx));
- }
- return SUCCESS;
-}
-
-static const u8 micsnap[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02};
-
-/*===========================================================================
- * Description: Mic a packet
- *
- * Inputs: etherHead * pointer to an 802.3 frame
- *
- * Returns: BOOLEAN if successful, otherwise false.
- * PacketTxLen will be updated with the mic'd packets size.
- *
- * Caveats: It is assumed that the frame buffer will already
- * be big enough to hold the largets mic message possible.
- * (No memory allocation is done here).
- *
- * Author: sbraneky (10/15/01)
- * Merciless hacks by rwilcher (1/14/02)
- */
-
-static int encapsulate(struct airo_info *ai, etherHead *frame, MICBuffer *mic, int payLen)
-{
- miccntx *context;
-
- // Determine correct context
- // If not adhoc, always use unicast key
-
- if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1))
- context = &ai->mod[0].mCtx;
- else
- context = &ai->mod[0].uCtx;
-
- if (!context->valid)
- return ERROR;
-
- mic->typelen = htons(payLen + 16); //Length of Mic'd packet
-
- memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap
-
- // Add Tx sequence
- mic->seq = htonl(context->tx);
- context->tx += 2;
-
- emmh32_init(&context->seed); // Mic the packet
- emmh32_update(&context->seed, frame->da, ETH_ALEN * 2); // DA, SA
- emmh32_update(&context->seed, (u8*)&mic->typelen, 10); // Type/Length and Snap
- emmh32_update(&context->seed, (u8*)&mic->seq, sizeof(mic->seq)); //SEQ
- emmh32_update(&context->seed, (u8*)(frame + 1), payLen); //payload
- emmh32_final(&context->seed, (u8*)&mic->mic);
-
- /* New Type/length ?????????? */
- mic->typelen = 0; //Let NIC know it could be an oversized packet
- return SUCCESS;
-}
-
-typedef enum {
- NONE,
- NOMIC,
- NOMICPLUMMED,
- SEQUENCE,
- INCORRECTMIC,
-} mic_error;
-
-/*===========================================================================
- * Description: Decapsulates a MIC'd packet and returns the 802.3 packet
- * (removes the MIC stuff) if packet is a valid packet.
- *
- * Inputs: etherHead pointer to the 802.3 packet
- *
- * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE
- *
- * Author: sbraneky (10/15/01)
- * Merciless hacks by rwilcher (1/14/02)
- *---------------------------------------------------------------------------
- */
-
-static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen)
-{
- int i;
- u32 micSEQ;
- miccntx *context;
- u8 digest[4];
- mic_error micError = NONE;
-
- // Check if the packet is a Mic'd packet
-
- if (!ai->micstats.enabled) {
- //No Mic set or Mic OFF but we received a MIC'd packet.
- if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) {
- ai->micstats.rxMICPlummed++;
- return ERROR;
- }
- return SUCCESS;
- }
-
- if (ntohs(mic->typelen) == 0x888E)
- return SUCCESS;
-
- if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) {
- // Mic enabled but packet isn't Mic'd
- ai->micstats.rxMICPlummed++;
- return ERROR;
- }
-
- micSEQ = ntohl(mic->seq); //store SEQ as CPU order
-
- //At this point we a have a mic'd packet and mic is enabled
- //Now do the mic error checking.
-
- //Receive seq must be odd
- if ((micSEQ & 1) == 0) {
- ai->micstats.rxWrongSequence++;
- return ERROR;
- }
-
- for (i = 0; i < NUM_MODULES; i++) {
- int mcast = eth->da[0] & 1;
- //Determine proper context
- context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx;
-
- //Make sure context is valid
- if (!context->valid) {
- if (i == 0)
- micError = NOMICPLUMMED;
- continue;
- }
- //DeMic it
-
- if (!mic->typelen)
- mic->typelen = htons(payLen + sizeof(MICBuffer) - 2);
-
- emmh32_init(&context->seed);
- emmh32_update(&context->seed, eth->da, ETH_ALEN*2);
- emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap));
- emmh32_update(&context->seed, (u8 *)&mic->seq, sizeof(mic->seq));
- emmh32_update(&context->seed, (u8 *)(eth + 1), payLen);
- //Calculate MIC
- emmh32_final(&context->seed, digest);
-
- if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match
- //Invalid Mic
- if (i == 0)
- micError = INCORRECTMIC;
- continue;
- }
-
- //Check Sequence number if mics pass
- if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) {
- ai->micstats.rxSuccess++;
- return SUCCESS;
- }
- if (i == 0)
- micError = SEQUENCE;
- }
-
- // Update statistics
- switch (micError) {
- case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break;
- case SEQUENCE: ai->micstats.rxWrongSequence++; break;
- case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break;
- case NONE: break;
- case NOMIC: break;
- }
- return ERROR;
-}
-
-/*===========================================================================
- * Description: Checks the Rx Seq number to make sure it is valid
- * and hasn't already been received
- *
- * Inputs: miccntx - mic context to check seq against
- * micSeq - the Mic seq number
- *
- * Returns: TRUE if valid otherwise FALSE.
- *
- * Author: sbraneky (10/15/01)
- * Merciless hacks by rwilcher (1/14/02)
- *---------------------------------------------------------------------------
- */
-
-static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq)
-{
- u32 seq, index;
-
- //Allow for the ap being rebooted - if it is then use the next
- //sequence number of the current sequence number - might go backwards
-
- if (mcast) {
- if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) {
- clear_bit (FLAG_UPDATE_MULTI, &ai->flags);
- context->window = (micSeq > 33) ? micSeq : 33;
- context->rx = 0; // Reset rx
- }
- } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) {
- clear_bit (FLAG_UPDATE_UNI, &ai->flags);
- context->window = (micSeq > 33) ? micSeq : 33; // Move window
- context->rx = 0; // Reset rx
- }
-
- //Make sequence number relative to START of window
- seq = micSeq - (context->window - 33);
-
- //Too old of a SEQ number to check.
- if ((s32)seq < 0)
- return ERROR;
-
- if (seq > 64) {
- //Window is infinite forward
- MoveWindow(context, micSeq);
- return SUCCESS;
- }
-
- // We are in the window. Now check the context rx bit to see if it was already sent
- seq >>= 1; //divide by 2 because we only have odd numbers
- index = 1 << seq; //Get an index number
-
- if (!(context->rx & index)) {
- //micSEQ falls inside the window.
- //Add seqence number to the list of received numbers.
- context->rx |= index;
-
- MoveWindow(context, micSeq);
-
- return SUCCESS;
- }
- return ERROR;
-}
-
-static void MoveWindow(miccntx *context, u32 micSeq)
-{
- u32 shift;
-
- //Move window if seq greater than the middle of the window
- if (micSeq > context->window) {
- shift = (micSeq - context->window) >> 1;
-
- //Shift out old
- if (shift < 32)
- context->rx >>= shift;
- else
- context->rx = 0;
-
- context->window = micSeq; //Move window
- }
-}
-
-/*==============================================*/
-/*========== EMMH ROUTINES ====================*/
-/*==============================================*/
-
-/* mic accumulate */
-#define MIC_ACCUM(val) \
- context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]);
-
-/* expand the key to fill the MMH coefficient array */
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
- struct crypto_sync_skcipher *tfm)
-{
- /* take the keying material, expand if necessary, truncate at 16-bytes */
- /* run through AES counter mode to generate context->coeff[] */
-
- SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
- struct scatterlist sg;
- u8 iv[AES_BLOCK_SIZE] = {};
- int ret;
-
- crypto_sync_skcipher_setkey(tfm, pkey, 16);
-
- memset(context->coeff, 0, sizeof(context->coeff));
- sg_init_one(&sg, context->coeff, sizeof(context->coeff));
-
- skcipher_request_set_sync_tfm(req, tfm);
- skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, &sg, &sg, sizeof(context->coeff), iv);
-
- ret = crypto_skcipher_encrypt(req);
- WARN_ON_ONCE(ret);
-}
-
-/* prepare for calculation of a new mic */
-static void emmh32_init(emmh32_context *context)
-{
- /* prepare for new mic calculation */
- context->accum = 0;
- context->position = 0;
-}
-
-/* add some bytes to the mic calculation */
-static void emmh32_update(emmh32_context *context, u8 *pOctets, int len)
-{
- int coeff_position, byte_position;
-
- if (len == 0) return;
-
- coeff_position = context->position >> 2;
-
- /* deal with partial 32-bit word left over from last update */
- byte_position = context->position & 3;
- if (byte_position) {
- /* have a partial word in part to deal with */
- do {
- if (len == 0) return;
- context->part.d8[byte_position++] = *pOctets++;
- context->position++;
- len--;
- } while (byte_position < 4);
- MIC_ACCUM(ntohl(context->part.d32));
- }
-
- /* deal with full 32-bit words */
- while (len >= 4) {
- MIC_ACCUM(ntohl(*(__be32 *)pOctets));
- context->position += 4;
- pOctets += 4;
- len -= 4;
- }
-
- /* deal with partial 32-bit word that will be left over from this update */
- byte_position = 0;
- while (len > 0) {
- context->part.d8[byte_position++] = *pOctets++;
- context->position++;
- len--;
- }
-}
-
-/* mask used to zero empty bytes for final partial word */
-static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L };
-
-/* calculate the mic */
-static void emmh32_final(emmh32_context *context, u8 digest[4])
-{
- int coeff_position, byte_position;
- u32 val;
-
- u64 sum, utmp;
- s64 stmp;
-
- coeff_position = context->position >> 2;
-
- /* deal with partial 32-bit word left over from last update */
- byte_position = context->position & 3;
- if (byte_position) {
- /* have a partial word in part to deal with */
- val = ntohl(context->part.d32);
- MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */
- }
-
- /* reduce the accumulated u64 to a 32-bit MIC */
- sum = context->accum;
- stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15);
- utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15);
- sum = utmp & 0xffffffffLL;
- if (utmp > 0x10000000fLL)
- sum -= 15;
-
- val = (u32)sum;
- digest[0] = (val>>24) & 0xFF;
- digest[1] = (val>>16) & 0xFF;
- digest[2] = (val>>8) & 0xFF;
- digest[3] = val & 0xFF;
-}
-
-static int readBSSListRid(struct airo_info *ai, int first,
- BSSListRid *list)
-{
- Cmd cmd;
- Resp rsp;
-
- if (first == 1) {
- if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LISTBSS;
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
- ai->list_bss_task = current;
- issuecommand(ai, &cmd, &rsp, true);
- up(&ai->sem);
- /* Let the command take effect */
- schedule_timeout_uninterruptible(3 * HZ);
- ai->list_bss_task = NULL;
- }
- return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
- list, ai->bssListRidLen, 1);
-}
-
-static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock)
-{
- return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
- wkr, sizeof(*wkr), lock);
-}
-
-static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock)
-{
- int rc;
- rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock);
- if (rc!=SUCCESS)
- airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc);
- if (perm) {
- rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock);
- if (rc!=SUCCESS)
- airo_print_err(ai->dev->name, "WEP_PERM set %x", rc);
- }
- return rc;
-}
-
-static int readSsidRid(struct airo_info*ai, SsidRid *ssidr)
-{
- return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1);
-}
-
-static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock)
-{
- return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock);
-}
-
-static int readConfigRid(struct airo_info *ai, int lock)
-{
- int rc;
- ConfigRid cfg;
-
- if (ai->config.len)
- return SUCCESS;
-
- rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock);
- if (rc != SUCCESS)
- return rc;
-
- ai->config = cfg;
- return SUCCESS;
-}
-
-static inline void checkThrottle(struct airo_info *ai)
-{
- int i;
-/* Old hardware had a limit on encryption speed */
- if (ai->config.authType != AUTH_OPEN && maxencrypt) {
- for (i = 0; i<8; i++) {
- if (ai->config.rates[i] > maxencrypt) {
- ai->config.rates[i] = 0;
- }
- }
- }
-}
-
-static int writeConfigRid(struct airo_info *ai, int lock)
-{
- ConfigRid cfgr;
-
- if (!test_bit (FLAG_COMMIT, &ai->flags))
- return SUCCESS;
-
- clear_bit (FLAG_COMMIT, &ai->flags);
- clear_bit (FLAG_RESET, &ai->flags);
- checkThrottle(ai);
- cfgr = ai->config;
-
- if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS)
- set_bit(FLAG_ADHOC, &ai->flags);
- else
- clear_bit(FLAG_ADHOC, &ai->flags);
-
- return PC4500_writerid(ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock);
-}
-
-static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock)
-{
- return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock);
-}
-
-static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock)
-{
- return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock);
-}
-
-static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock)
-{
- return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock);
-}
-
-static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock)
-{
- return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock);
-}
-
-static void try_auto_wep(struct airo_info *ai)
-{
- if (auto_wep && !test_bit(FLAG_RADIO_DOWN, &ai->flags)) {
- ai->expires = RUN_AT(3*HZ);
- wake_up_interruptible(&ai->thr_wait);
- }
-}
-
-static int airo_open(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
- int rc = 0;
-
- if (test_bit(FLAG_FLASHING, &ai->flags))
- return -EIO;
-
- /* Make sure the card is configured.
- * Wireless Extensions may postpone config changes until the card
- * is open (to pipeline changes and speed-up card setup). If
- * those changes are not yet committed, do it now - Jean II */
- if (test_bit(FLAG_COMMIT, &ai->flags)) {
- disable_MAC(ai, 1);
- writeConfigRid(ai, 1);
- }
-
- if (ai->wifidev != dev) {
- clear_bit(JOB_DIE, &ai->jobs);
- ai->airo_thread_task = kthread_run(airo_thread, dev, "%s",
- dev->name);
- if (IS_ERR(ai->airo_thread_task))
- return (int)PTR_ERR(ai->airo_thread_task);
-
- rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
- dev->name, dev);
- if (rc) {
- airo_print_err(dev->name,
- "register interrupt %d failed, rc %d",
- dev->irq, rc);
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
- return rc;
- }
-
- /* Power on the MAC controller (which may have been disabled) */
- clear_bit(FLAG_RADIO_DOWN, &ai->flags);
- enable_interrupts(ai);
-
- try_auto_wep(ai);
- }
- enable_MAC(ai, 1);
-
- netif_start_queue(dev);
- return 0;
-}
-
-static netdev_tx_t mpi_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- int npacks, pending;
- unsigned long flags;
- struct airo_info *ai = dev->ml_priv;
-
- if (!skb) {
- airo_print_err(dev->name, "%s: skb == NULL!",__func__);
- return NETDEV_TX_OK;
- }
- if (skb_padto(skb, ETH_ZLEN)) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
- npacks = skb_queue_len (&ai->txq);
-
- if (npacks >= MAXTXQ - 1) {
- netif_stop_queue (dev);
- if (npacks > MAXTXQ) {
- dev->stats.tx_fifo_errors++;
- return NETDEV_TX_BUSY;
- }
- skb_queue_tail (&ai->txq, skb);
- return NETDEV_TX_OK;
- }
-
- spin_lock_irqsave(&ai->aux_lock, flags);
- skb_queue_tail (&ai->txq, skb);
- pending = test_bit(FLAG_PENDING_XMIT, &ai->flags);
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- netif_wake_queue (dev);
-
- if (pending == 0) {
- set_bit(FLAG_PENDING_XMIT, &ai->flags);
- mpi_send_packet (dev);
- }
- return NETDEV_TX_OK;
-}
-
-/*
- * @mpi_send_packet
- *
- * Attempt to transmit a packet. Can be called from interrupt
- * or transmit . return number of packets we tried to send
- */
-
-static int mpi_send_packet (struct net_device *dev)
-{
- struct sk_buff *skb;
- unsigned char *buffer;
- s16 len;
- __le16 *payloadLen;
- struct airo_info *ai = dev->ml_priv;
- u8 *sendbuf;
-
- /* get a packet to send */
-
- if ((skb = skb_dequeue(&ai->txq)) == NULL) {
- airo_print_err(dev->name,
- "%s: Dequeue'd zero in send_packet()",
- __func__);
- return 0;
- }
-
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- buffer = skb->data;
-
- ai->txfids[0].tx_desc.offset = 0;
- ai->txfids[0].tx_desc.valid = 1;
- ai->txfids[0].tx_desc.eoc = 1;
- ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr);
-
-/*
- * Magic, the cards firmware needs a length count (2 bytes) in the host buffer
- * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen
- * is immediately after it. ------------------------------------------------
- * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA|
- * ------------------------------------------------
- */
-
- memcpy(ai->txfids[0].virtual_host_addr,
- (char *)&wifictlhdr8023, sizeof(wifictlhdr8023));
-
- payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr +
- sizeof(wifictlhdr8023));
- sendbuf = ai->txfids[0].virtual_host_addr +
- sizeof(wifictlhdr8023) + 2 ;
-
- /*
- * Firmware automatically puts 802 header on so
- * we don't need to account for it in the length
- */
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
- (ntohs(((__be16 *)buffer)[6]) != 0x888E)) {
- MICBuffer pMic;
-
- if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS)
- return ERROR;
-
- *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic));
- ai->txfids[0].tx_desc.len += sizeof(pMic);
- /* copy data into airo dma buffer */
- memcpy (sendbuf, buffer, sizeof(etherHead));
- buffer += sizeof(etherHead);
- sendbuf += sizeof(etherHead);
- memcpy (sendbuf, &pMic, sizeof(pMic));
- sendbuf += sizeof(pMic);
- memcpy (sendbuf, buffer, len - sizeof(etherHead));
- } else {
- *payloadLen = cpu_to_le16(len - sizeof(etherHead));
-
- netif_trans_update(dev);
-
- /* copy data into airo dma buffer */
- memcpy(sendbuf, buffer, len);
- }
-
- memcpy_toio(ai->txfids[0].card_ram_off,
- &ai->txfids[0].tx_desc, sizeof(TxFid));
-
- OUT4500(ai, EVACK, 8);
-
- dev_kfree_skb_any(skb);
- return 1;
-}
-
-static void get_tx_error(struct airo_info *ai, s32 fid)
-{
- __le16 status;
-
- if (fid < 0)
- status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status;
- else {
- if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS)
- return;
- bap_read(ai, &status, 2, BAP0);
- }
- if (le16_to_cpu(status) & 2) /* Too many retries */
- ai->dev->stats.tx_aborted_errors++;
- if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */
- ai->dev->stats.tx_heartbeat_errors++;
- if (le16_to_cpu(status) & 8) /* Aid fail */
- { }
- if (le16_to_cpu(status) & 0x10) /* MAC disabled */
- ai->dev->stats.tx_carrier_errors++;
- if (le16_to_cpu(status) & 0x20) /* Association lost */
- { }
- /* We produce a TXDROP event only for retry or lifetime
- * exceeded, because that's the only status that really mean
- * that this particular node went away.
- * Other errors means that *we* screwed up. - Jean II */
- if ((le16_to_cpu(status) & 2) ||
- (le16_to_cpu(status) & 4)) {
- union iwreq_data wrqu;
- char junk[0x18];
-
- /* Faster to skip over useless data than to do
- * another bap_setup(). We are at offset 0x6 and
- * need to go to 0x18 and read 6 bytes - Jean II */
- bap_read(ai, (__le16 *) junk, 0x18, BAP0);
-
- /* Copy 802.11 dest address.
- * We use the 802.11 header because the frame may
- * not be 802.3 or may be mangled...
- * In Ad-Hoc mode, it will be the node address.
- * In managed mode, it will be most likely the AP addr
- * User space will figure out how to convert it to
- * whatever it needs (IP address or else).
- * - Jean II */
- memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL);
- }
-}
-
-static void airo_end_xmit(struct net_device *dev, bool may_sleep)
-{
- u16 status;
- int i;
- struct airo_info *priv = dev->ml_priv;
- struct sk_buff *skb = priv->xmit.skb;
- int fid = priv->xmit.fid;
- u32 *fids = priv->fids;
-
- clear_bit(JOB_XMIT, &priv->jobs);
- clear_bit(FLAG_PENDING_XMIT, &priv->flags);
- status = transmit_802_3_packet(priv, fids[fid], skb->data, may_sleep);
- up(&priv->sem);
-
- i = 0;
- if (status == SUCCESS) {
- netif_trans_update(dev);
- for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++);
- } else {
- priv->fids[fid] &= 0xffff;
- dev->stats.tx_window_errors++;
- }
- if (i < MAX_FIDS / 2)
- netif_wake_queue(dev);
- dev_kfree_skb(skb);
-}
-
-static netdev_tx_t airo_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- s16 len;
- int i, j;
- struct airo_info *priv = dev->ml_priv;
- u32 *fids = priv->fids;
-
- if (skb == NULL) {
- airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return NETDEV_TX_OK;
- }
- if (skb_padto(skb, ETH_ZLEN)) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
-
- /* Find a vacant FID */
- for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++);
- for (j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++);
-
- if (j >= MAX_FIDS / 2) {
- netif_stop_queue(dev);
-
- if (i == MAX_FIDS / 2) {
- dev->stats.tx_fifo_errors++;
- return NETDEV_TX_BUSY;
- }
- }
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- /* Mark fid as used & save length for later */
- fids[i] |= (len << 16);
- priv->xmit.skb = skb;
- priv->xmit.fid = i;
- if (down_trylock(&priv->sem) != 0) {
- set_bit(FLAG_PENDING_XMIT, &priv->flags);
- netif_stop_queue(dev);
- set_bit(JOB_XMIT, &priv->jobs);
- wake_up_interruptible(&priv->thr_wait);
- } else
- airo_end_xmit(dev, false);
- return NETDEV_TX_OK;
-}
-
-static void airo_end_xmit11(struct net_device *dev, bool may_sleep)
-{
- u16 status;
- int i;
- struct airo_info *priv = dev->ml_priv;
- struct sk_buff *skb = priv->xmit11.skb;
- int fid = priv->xmit11.fid;
- u32 *fids = priv->fids;
-
- clear_bit(JOB_XMIT11, &priv->jobs);
- clear_bit(FLAG_PENDING_XMIT11, &priv->flags);
- status = transmit_802_11_packet(priv, fids[fid], skb->data, may_sleep);
- up(&priv->sem);
-
- i = MAX_FIDS / 2;
- if (status == SUCCESS) {
- netif_trans_update(dev);
- for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++);
- } else {
- priv->fids[fid] &= 0xffff;
- dev->stats.tx_window_errors++;
- }
- if (i < MAX_FIDS)
- netif_wake_queue(dev);
- dev_kfree_skb(skb);
-}
-
-static netdev_tx_t airo_start_xmit11(struct sk_buff *skb,
- struct net_device *dev)
-{
- s16 len;
- int i, j;
- struct airo_info *priv = dev->ml_priv;
- u32 *fids = priv->fids;
-
- if (test_bit(FLAG_MPI, &priv->flags)) {
- /* Not implemented yet for MPI350 */
- netif_stop_queue(dev);
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
-
- if (skb == NULL) {
- airo_print_err(dev->name, "%s: skb == NULL!", __func__);
- return NETDEV_TX_OK;
- }
- if (skb_padto(skb, ETH_ZLEN)) {
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- }
-
- /* Find a vacant FID */
- for (i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++);
- for (j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++);
-
- if (j >= MAX_FIDS) {
- netif_stop_queue(dev);
-
- if (i == MAX_FIDS) {
- dev->stats.tx_fifo_errors++;
- return NETDEV_TX_BUSY;
- }
- }
- /* check min length*/
- len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- /* Mark fid as used & save length for later */
- fids[i] |= (len << 16);
- priv->xmit11.skb = skb;
- priv->xmit11.fid = i;
- if (down_trylock(&priv->sem) != 0) {
- set_bit(FLAG_PENDING_XMIT11, &priv->flags);
- netif_stop_queue(dev);
- set_bit(JOB_XMIT11, &priv->jobs);
- wake_up_interruptible(&priv->thr_wait);
- } else
- airo_end_xmit11(dev, false);
- return NETDEV_TX_OK;
-}
-
-static void airo_read_stats(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
- StatsRid stats_rid;
- __le32 *vals = stats_rid.vals;
-
- clear_bit(JOB_STATS, &ai->jobs);
- if (ai->power.event) {
- up(&ai->sem);
- return;
- }
- readStatsRid(ai, &stats_rid, RID_STATS, 0);
- up(&ai->sem);
-
- dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) +
- le32_to_cpu(vals[45]);
- dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) +
- le32_to_cpu(vals[41]);
- dev->stats.rx_bytes = le32_to_cpu(vals[92]);
- dev->stats.tx_bytes = le32_to_cpu(vals[91]);
- dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) +
- le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]);
- dev->stats.tx_errors = le32_to_cpu(vals[42]) +
- dev->stats.tx_fifo_errors;
- dev->stats.multicast = le32_to_cpu(vals[43]);
- dev->stats.collisions = le32_to_cpu(vals[89]);
-
- /* detailed rx_errors: */
- dev->stats.rx_length_errors = le32_to_cpu(vals[3]);
- dev->stats.rx_crc_errors = le32_to_cpu(vals[4]);
- dev->stats.rx_frame_errors = le32_to_cpu(vals[2]);
- dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]);
-}
-
-static struct net_device_stats *airo_get_stats(struct net_device *dev)
-{
- struct airo_info *local = dev->ml_priv;
-
- if (!test_bit(JOB_STATS, &local->jobs)) {
- set_bit(JOB_STATS, &local->jobs);
- wake_up_interruptible(&local->thr_wait);
- }
-
- return &dev->stats;
-}
-
-static void airo_set_promisc(struct airo_info *ai, bool may_sleep)
-{
- Cmd cmd;
- Resp rsp;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_SETMODE;
- clear_bit(JOB_PROMISC, &ai->jobs);
- cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
- issuecommand(ai, &cmd, &rsp, may_sleep);
- up(&ai->sem);
-}
-
-static void airo_set_multicast_list(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
-
- if ((dev->flags ^ ai->flags) & IFF_PROMISC) {
- change_bit(FLAG_PROMISC, &ai->flags);
- if (down_trylock(&ai->sem) != 0) {
- set_bit(JOB_PROMISC, &ai->jobs);
- wake_up_interruptible(&ai->thr_wait);
- } else
- airo_set_promisc(ai, false);
- }
-
- if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) {
- /* Turn on multicast. (Should be already setup...) */
- }
-}
-
-static int airo_set_mac_address(struct net_device *dev, void *p)
-{
- struct airo_info *ai = dev->ml_priv;
- struct sockaddr *addr = p;
-
- readConfigRid(ai, 1);
- memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
- set_bit (FLAG_COMMIT, &ai->flags);
- disable_MAC(ai, 1);
- writeConfigRid (ai, 1);
- enable_MAC(ai, 1);
- dev_addr_set(ai->dev, addr->sa_data);
- if (ai->wifidev)
- dev_addr_set(ai->wifidev, addr->sa_data);
- return 0;
-}
-
-static LIST_HEAD(airo_devices);
-
-static void add_airo_dev(struct airo_info *ai)
-{
- /* Upper layers already keep track of PCI devices,
- * so we only need to remember our non-PCI cards. */
- if (!ai->pci)
- list_add_tail(&ai->dev_list, &airo_devices);
-}
-
-static void del_airo_dev(struct airo_info *ai)
-{
- if (!ai->pci)
- list_del(&ai->dev_list);
-}
-
-static int airo_close(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
-
- netif_stop_queue(dev);
-
- if (ai->wifidev != dev) {
-#ifdef POWER_ON_DOWN
- /* Shut power to the card. The idea is that the user can save
- * power when he doesn't need the card with "ifconfig down".
- * That's the method that is most friendly towards the network
- * stack (i.e. the network stack won't try to broadcast
- * anything on the interface and routes are gone. Jean II */
- set_bit(FLAG_RADIO_DOWN, &ai->flags);
- disable_MAC(ai, 1);
-#endif
- disable_interrupts(ai);
-
- free_irq(dev->irq, dev);
-
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
- }
- return 0;
-}
-
-void stop_airo_card(struct net_device *dev, int freeres)
-{
- struct airo_info *ai = dev->ml_priv;
-
- set_bit(FLAG_RADIO_DOWN, &ai->flags);
- disable_MAC(ai, 1);
- disable_interrupts(ai);
- takedown_proc_entry(dev, ai);
- if (test_bit(FLAG_REGISTERED, &ai->flags)) {
- unregister_netdev(dev);
- if (ai->wifidev) {
- unregister_netdev(ai->wifidev);
- free_netdev(ai->wifidev);
- ai->wifidev = NULL;
- }
- clear_bit(FLAG_REGISTERED, &ai->flags);
- }
- /*
- * Clean out tx queue
- */
- if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
- struct sk_buff *skb = NULL;
- for (;(skb = skb_dequeue(&ai->txq));)
- dev_kfree_skb(skb);
- }
-
- airo_networks_free (ai);
-
- kfree(ai->flash);
- kfree(ai->rssi);
- kfree(ai->SSID);
- if (freeres) {
- /* PCMCIA frees this stuff, so only for PCI and ISA */
- release_region(dev->base_addr, 64);
- if (test_bit(FLAG_MPI, &ai->flags)) {
- if (ai->pci)
- mpi_unmap_card(ai->pci);
- if (ai->pcimem)
- iounmap(ai->pcimem);
- if (ai->pciaux)
- iounmap(ai->pciaux);
- dma_free_coherent(&ai->pci->dev, PCI_SHARED_LEN,
- ai->shared, ai->shared_dma);
- }
- }
- crypto_free_sync_skcipher(ai->tfm);
- del_airo_dev(ai);
- free_netdev(dev);
-}
-
-EXPORT_SYMBOL(stop_airo_card);
-
-static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
-{
- memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
- return ETH_ALEN;
-}
-
-static void mpi_unmap_card(struct pci_dev *pci)
-{
- unsigned long mem_start = pci_resource_start(pci, 1);
- unsigned long mem_len = pci_resource_len(pci, 1);
- unsigned long aux_start = pci_resource_start(pci, 2);
- unsigned long aux_len = AUXMEMSIZE;
-
- release_mem_region(aux_start, aux_len);
- release_mem_region(mem_start, mem_len);
-}
-
-/*************************************************************
- * This routine assumes that descriptors have been setup .
- * Run at insmod time or after reset when the descriptors
- * have been initialized . Returns 0 if all is well nz
- * otherwise . Does not allocate memory but sets up card
- * using previously allocated descriptors.
- */
-static int mpi_init_descriptors (struct airo_info *ai)
-{
- Cmd cmd;
- Resp rsp;
- int i;
- int rc = SUCCESS;
-
- /* Alloc card RX descriptors */
- netif_stop_queue(ai->dev);
-
- memset(&rsp, 0, sizeof(rsp));
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.cmd = CMD_ALLOCATEAUX;
- cmd.parm0 = FID_RX;
- cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux);
- cmd.parm2 = MPI_MAX_FIDS;
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc != SUCCESS) {
- airo_print_err(ai->dev->name, "Couldn't allocate RX FID");
- return rc;
- }
-
- for (i = 0; i<MPI_MAX_FIDS; i++) {
- memcpy_toio(ai->rxfids[i].card_ram_off,
- &ai->rxfids[i].rx_desc, sizeof(RxFid));
- }
-
- /* Alloc card TX descriptors */
-
- memset(&rsp, 0, sizeof(rsp));
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.cmd = CMD_ALLOCATEAUX;
- cmd.parm0 = FID_TX;
- cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux);
- cmd.parm2 = MPI_MAX_FIDS;
-
- for (i = 0; i<MPI_MAX_FIDS; i++) {
- ai->txfids[i].tx_desc.valid = 1;
- memcpy_toio(ai->txfids[i].card_ram_off,
- &ai->txfids[i].tx_desc, sizeof(TxFid));
- }
- ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
-
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc != SUCCESS) {
- airo_print_err(ai->dev->name, "Couldn't allocate TX FID");
- return rc;
- }
-
- /* Alloc card Rid descriptor */
- memset(&rsp, 0, sizeof(rsp));
- memset(&cmd, 0, sizeof(cmd));
-
- cmd.cmd = CMD_ALLOCATEAUX;
- cmd.parm0 = RID_RW;
- cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux);
- cmd.parm2 = 1; /* Magic number... */
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc != SUCCESS) {
- airo_print_err(ai->dev->name, "Couldn't allocate RID");
- return rc;
- }
-
- memcpy_toio(ai->config_desc.card_ram_off,
- &ai->config_desc.rid_desc, sizeof(Rid));
-
- return rc;
-}
-
-/*
- * We are setting up three things here:
- * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid.
- * 2) Map PCI memory for issuing commands.
- * 3) Allocate memory (shared) to send and receive ethernet frames.
- */
-static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
-{
- unsigned long mem_start, mem_len, aux_start, aux_len;
- int rc = -1;
- int i;
- dma_addr_t busaddroff;
- unsigned char *vpackoff;
- unsigned char __iomem *pciaddroff;
-
- mem_start = pci_resource_start(pci, 1);
- mem_len = pci_resource_len(pci, 1);
- aux_start = pci_resource_start(pci, 2);
- aux_len = AUXMEMSIZE;
-
- if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
- airo_print_err("", "Couldn't get region %x[%x]",
- (int)mem_start, (int)mem_len);
- goto out;
- }
- if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
- airo_print_err("", "Couldn't get region %x[%x]",
- (int)aux_start, (int)aux_len);
- goto free_region1;
- }
-
- ai->pcimem = ioremap(mem_start, mem_len);
- if (!ai->pcimem) {
- airo_print_err("", "Couldn't map region %x[%x]",
- (int)mem_start, (int)mem_len);
- goto free_region2;
- }
- ai->pciaux = ioremap(aux_start, aux_len);
- if (!ai->pciaux) {
- airo_print_err("", "Couldn't map region %x[%x]",
- (int)aux_start, (int)aux_len);
- goto free_memmap;
- }
-
- /* Reserve PKTSIZE for each fid and 2K for the Rids */
- ai->shared = dma_alloc_coherent(&pci->dev, PCI_SHARED_LEN,
- &ai->shared_dma, GFP_KERNEL);
- if (!ai->shared) {
- airo_print_err("", "Couldn't alloc_coherent %d",
- PCI_SHARED_LEN);
- goto free_auxmap;
- }
-
- /*
- * Setup descriptor RX, TX, CONFIG
- */
- busaddroff = ai->shared_dma;
- pciaddroff = ai->pciaux + AUX_OFFSET;
- vpackoff = ai->shared;
-
- /* RX descriptor setup */
- for (i = 0; i < MPI_MAX_FIDS; i++) {
- ai->rxfids[i].pending = 0;
- ai->rxfids[i].card_ram_off = pciaddroff;
- ai->rxfids[i].virtual_host_addr = vpackoff;
- ai->rxfids[i].rx_desc.host_addr = busaddroff;
- ai->rxfids[i].rx_desc.valid = 1;
- ai->rxfids[i].rx_desc.len = PKTSIZE;
- ai->rxfids[i].rx_desc.rdy = 0;
-
- pciaddroff += sizeof(RxFid);
- busaddroff += PKTSIZE;
- vpackoff += PKTSIZE;
- }
-
- /* TX descriptor setup */
- for (i = 0; i < MPI_MAX_FIDS; i++) {
- ai->txfids[i].card_ram_off = pciaddroff;
- ai->txfids[i].virtual_host_addr = vpackoff;
- ai->txfids[i].tx_desc.valid = 1;
- ai->txfids[i].tx_desc.host_addr = busaddroff;
- memcpy(ai->txfids[i].virtual_host_addr,
- &wifictlhdr8023, sizeof(wifictlhdr8023));
-
- pciaddroff += sizeof(TxFid);
- busaddroff += PKTSIZE;
- vpackoff += PKTSIZE;
- }
- ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */
-
- /* Rid descriptor setup */
- ai->config_desc.card_ram_off = pciaddroff;
- ai->config_desc.virtual_host_addr = vpackoff;
- ai->config_desc.rid_desc.host_addr = busaddroff;
- ai->ridbus = busaddroff;
- ai->config_desc.rid_desc.rid = 0;
- ai->config_desc.rid_desc.len = RIDSIZE;
- ai->config_desc.rid_desc.valid = 1;
- pciaddroff += sizeof(Rid);
- busaddroff += RIDSIZE;
- vpackoff += RIDSIZE;
-
- /* Tell card about descriptors */
- if (mpi_init_descriptors (ai) != SUCCESS)
- goto free_shared;
-
- return 0;
- free_shared:
- dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared,
- ai->shared_dma);
- free_auxmap:
- iounmap(ai->pciaux);
- free_memmap:
- iounmap(ai->pcimem);
- free_region2:
- release_mem_region(aux_start, aux_len);
- free_region1:
- release_mem_region(mem_start, mem_len);
- out:
- return rc;
-}
-
-static const struct header_ops airo_header_ops = {
- .parse = wll_header_parse,
-};
-
-static const struct net_device_ops airo11_netdev_ops = {
- .ndo_open = airo_open,
- .ndo_stop = airo_close,
- .ndo_start_xmit = airo_start_xmit11,
- .ndo_get_stats = airo_get_stats,
- .ndo_set_mac_address = airo_set_mac_address,
- .ndo_siocdevprivate = airo_siocdevprivate,
-};
-
-static void wifi_setup(struct net_device *dev)
-{
- dev->netdev_ops = &airo11_netdev_ops;
- dev->header_ops = &airo_header_ops;
- dev->wireless_handlers = &airo_handler_def;
-
- dev->type = ARPHRD_IEEE80211;
- dev->hard_header_len = ETH_HLEN;
- dev->mtu = AIRO_DEF_MTU;
- dev->min_mtu = 68;
- dev->max_mtu = MIC_MSGLEN_MAX;
- dev->addr_len = ETH_ALEN;
- dev->tx_queue_len = 100;
-
- eth_broadcast_addr(dev->broadcast);
-
- dev->flags = IFF_BROADCAST|IFF_MULTICAST;
-}
-
-static struct net_device *init_wifidev(struct airo_info *ai,
- struct net_device *ethdev)
-{
- int err;
- struct net_device *dev = alloc_netdev(0, "wifi%d", NET_NAME_UNKNOWN,
- wifi_setup);
- if (!dev)
- return NULL;
- dev->ml_priv = ethdev->ml_priv;
- dev->irq = ethdev->irq;
- dev->base_addr = ethdev->base_addr;
- dev->wireless_data = ethdev->wireless_data;
- SET_NETDEV_DEV(dev, ethdev->dev.parent);
- eth_hw_addr_inherit(dev, ethdev);
- err = register_netdev(dev);
- if (err<0) {
- free_netdev(dev);
- return NULL;
- }
- return dev;
-}
-
-static int reset_card(struct net_device *dev, int lock)
-{
- struct airo_info *ai = dev->ml_priv;
-
- if (lock && down_interruptible(&ai->sem))
- return -1;
- waitbusy (ai);
- OUT4500(ai, COMMAND, CMD_SOFTRESET);
- msleep(200);
- waitbusy (ai);
- msleep(200);
- if (lock)
- up(&ai->sem);
- return 0;
-}
-
-#define AIRO_MAX_NETWORK_COUNT 64
-static int airo_networks_allocate(struct airo_info *ai)
-{
- if (ai->networks)
- return 0;
-
- ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement),
- GFP_KERNEL);
- if (!ai->networks) {
- airo_print_warn("", "Out of memory allocating beacons");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void airo_networks_free(struct airo_info *ai)
-{
- kfree(ai->networks);
- ai->networks = NULL;
-}
-
-static void airo_networks_initialize(struct airo_info *ai)
-{
- int i;
-
- INIT_LIST_HEAD(&ai->network_free_list);
- INIT_LIST_HEAD(&ai->network_list);
- for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++)
- list_add_tail(&ai->networks[i].list,
- &ai->network_free_list);
-}
-
-static const struct net_device_ops airo_netdev_ops = {
- .ndo_open = airo_open,
- .ndo_stop = airo_close,
- .ndo_start_xmit = airo_start_xmit,
- .ndo_get_stats = airo_get_stats,
- .ndo_set_rx_mode = airo_set_multicast_list,
- .ndo_set_mac_address = airo_set_mac_address,
- .ndo_siocdevprivate = airo_siocdevprivate,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static const struct net_device_ops mpi_netdev_ops = {
- .ndo_open = airo_open,
- .ndo_stop = airo_close,
- .ndo_start_xmit = mpi_start_xmit,
- .ndo_get_stats = airo_get_stats,
- .ndo_set_rx_mode = airo_set_multicast_list,
- .ndo_set_mac_address = airo_set_mac_address,
- .ndo_siocdevprivate = airo_siocdevprivate,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-
-static struct net_device *_init_airo_card(unsigned short irq, int port,
- int is_pcmcia, struct pci_dev *pci,
- struct device *dmdev)
-{
- struct net_device *dev;
- struct airo_info *ai;
- int i, rc;
- CapabilityRid cap_rid;
-
- /* Create the network device object. */
- dev = alloc_netdev(sizeof(*ai), "", NET_NAME_UNKNOWN, ether_setup);
- if (!dev) {
- airo_print_err("", "Couldn't alloc_etherdev");
- return NULL;
- }
-
- ai = dev->ml_priv = netdev_priv(dev);
- ai->wifidev = NULL;
- ai->flags = 1 << FLAG_RADIO_DOWN;
- ai->jobs = 0;
- ai->dev = dev;
- if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
- airo_print_dbg("", "Found an MPI350 card");
- set_bit(FLAG_MPI, &ai->flags);
- }
- spin_lock_init(&ai->aux_lock);
- sema_init(&ai->sem, 1);
- ai->config.len = 0;
- ai->pci = pci;
- init_waitqueue_head (&ai->thr_wait);
- ai->tfm = NULL;
- add_airo_dev(ai);
- ai->APList.len = cpu_to_le16(sizeof(struct APListRid));
-
- if (airo_networks_allocate (ai))
- goto err_out_free;
- airo_networks_initialize (ai);
-
- skb_queue_head_init (&ai->txq);
-
- /* The Airo-specific entries in the device structure. */
- if (test_bit(FLAG_MPI,&ai->flags))
- dev->netdev_ops = &mpi_netdev_ops;
- else
- dev->netdev_ops = &airo_netdev_ops;
- dev->wireless_handlers = &airo_handler_def;
- ai->wireless_data.spy_data = &ai->spy_data;
- dev->wireless_data = &ai->wireless_data;
- dev->irq = irq;
- dev->base_addr = port;
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- dev->max_mtu = MIC_MSGLEN_MAX;
-
- SET_NETDEV_DEV(dev, dmdev);
-
- reset_card (dev, 1);
- msleep(400);
-
- if (!is_pcmcia) {
- if (!request_region(dev->base_addr, 64, DRV_NAME)) {
- rc = -EBUSY;
- airo_print_err(dev->name, "Couldn't request region");
- goto err_out_nets;
- }
- }
-
- if (test_bit(FLAG_MPI,&ai->flags)) {
- if (mpi_map_card(ai, pci)) {
- airo_print_err("", "Could not map memory");
- goto err_out_res;
- }
- }
-
- if (probe) {
- if (setup_card(ai, dev, 1) != SUCCESS) {
- airo_print_err(dev->name, "MAC could not be enabled");
- rc = -EIO;
- goto err_out_map;
- }
- } else if (!test_bit(FLAG_MPI,&ai->flags)) {
- ai->bap_read = fast_bap_read;
- set_bit(FLAG_FLASHING, &ai->flags);
- }
-
- strcpy(dev->name, "eth%d");
- rc = register_netdev(dev);
- if (rc) {
- airo_print_err(dev->name, "Couldn't register_netdev");
- goto err_out_map;
- }
- ai->wifidev = init_wifidev(ai, dev);
- if (!ai->wifidev)
- goto err_out_reg;
-
- rc = readCapabilityRid(ai, &cap_rid, 1);
- if (rc != SUCCESS) {
- rc = -EIO;
- goto err_out_wifi;
- }
- /* WEP capability discovery */
- ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0;
- ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0;
-
- airo_print_info(dev->name, "Firmware version %x.%x.%02d",
- ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF),
- (le16_to_cpu(cap_rid.softVer) & 0xFF),
- le16_to_cpu(cap_rid.softSubVer));
-
- /* Test for WPA support */
- /* Only firmware versions 5.30.17 or better can do WPA */
- if (le16_to_cpu(cap_rid.softVer) > 0x530
- || (le16_to_cpu(cap_rid.softVer) == 0x530
- && le16_to_cpu(cap_rid.softSubVer) >= 17)) {
- airo_print_info(ai->dev->name, "WPA supported.");
-
- set_bit(FLAG_WPA_CAPABLE, &ai->flags);
- ai->bssListFirst = RID_WPA_BSSLISTFIRST;
- ai->bssListNext = RID_WPA_BSSLISTNEXT;
- ai->bssListRidLen = sizeof(BSSListRid);
- } else {
- airo_print_info(ai->dev->name, "WPA unsupported with firmware "
- "versions older than 5.30.17.");
-
- ai->bssListFirst = RID_BSSLISTFIRST;
- ai->bssListNext = RID_BSSLISTNEXT;
- ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
- }
-
- set_bit(FLAG_REGISTERED,&ai->flags);
- airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
-
- /* Allocate the transmit buffers */
- if (probe && !test_bit(FLAG_MPI,&ai->flags))
- for (i = 0; i < MAX_FIDS; i++)
- ai->fids[i] = transmit_allocate(ai, AIRO_DEF_MTU, i>=MAX_FIDS/2);
-
- if (setup_proc_entry(dev, dev->ml_priv) < 0)
- goto err_out_wifi;
-
- return dev;
-
-err_out_wifi:
- unregister_netdev(ai->wifidev);
- free_netdev(ai->wifidev);
-err_out_reg:
- unregister_netdev(dev);
-err_out_map:
- if (test_bit(FLAG_MPI,&ai->flags) && pci) {
- dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared,
- ai->shared_dma);
- iounmap(ai->pciaux);
- iounmap(ai->pcimem);
- mpi_unmap_card(ai->pci);
- }
-err_out_res:
- if (!is_pcmcia)
- release_region(dev->base_addr, 64);
-err_out_nets:
- airo_networks_free(ai);
-err_out_free:
- del_airo_dev(ai);
- free_netdev(dev);
- return NULL;
-}
-
-struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia,
- struct device *dmdev)
-{
- return _init_airo_card (irq, port, is_pcmcia, NULL, dmdev);
-}
-
-EXPORT_SYMBOL(init_airo_card);
-
-static int waitbusy (struct airo_info *ai)
-{
- int delay = 0;
- while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) {
- udelay (10);
- if ((++delay % 20) == 0)
- OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
- }
- return delay < 10000;
-}
-
-int reset_airo_card(struct net_device *dev)
-{
- int i;
- struct airo_info *ai = dev->ml_priv;
-
- if (reset_card (dev, 1))
- return -1;
-
- if (setup_card(ai, dev, 1) != SUCCESS) {
- airo_print_err(dev->name, "MAC could not be enabled");
- return -1;
- }
- airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr);
- /* Allocate the transmit buffers if needed */
- if (!test_bit(FLAG_MPI,&ai->flags))
- for (i = 0; i < MAX_FIDS; i++)
- ai->fids[i] = transmit_allocate (ai, AIRO_DEF_MTU, i>=MAX_FIDS/2);
-
- enable_interrupts(ai);
- netif_wake_queue(dev);
- return 0;
-}
-
-EXPORT_SYMBOL(reset_airo_card);
-
-static void airo_send_event(struct net_device *dev)
-{
- struct airo_info *ai = dev->ml_priv;
- union iwreq_data wrqu;
- StatusRid status_rid;
-
- clear_bit(JOB_EVENT, &ai->jobs);
- PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0);
- up(&ai->sem);
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void airo_process_scan_results (struct airo_info *ai)
-{
- union iwreq_data wrqu;
- BSSListRid bss;
- int rc;
- BSSListElement * loop_net;
- BSSListElement * tmp_net;
-
- /* Blow away current list of scan results */
- list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) {
- list_move_tail (&loop_net->list, &ai->network_free_list);
- /* Don't blow away ->list, just BSS data */
- memset (loop_net, 0, sizeof (loop_net->bss));
- }
-
- /* Try to read the first entry of the scan result */
- rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0);
- if ((rc) || (bss.index == cpu_to_le16(0xffff))) {
- /* No scan results */
- goto out;
- }
-
- /* Read and parse all entries */
- tmp_net = NULL;
- while ((!rc) && (bss.index != cpu_to_le16(0xffff))) {
- /* Grab a network off the free list */
- if (!list_empty(&ai->network_free_list)) {
- tmp_net = list_entry(ai->network_free_list.next,
- BSSListElement, list);
- list_del(ai->network_free_list.next);
- }
-
- if (tmp_net != NULL) {
- memcpy(tmp_net, &bss, sizeof(tmp_net->bss));
- list_add_tail(&tmp_net->list, &ai->network_list);
- tmp_net = NULL;
- }
-
- /* Read next entry */
- rc = PC4500_readrid(ai, ai->bssListNext,
- &bss, ai->bssListRidLen, 0);
- }
-
-out:
- /* write APList back (we cleared it in airo_set_scan) */
- disable_MAC(ai, 2);
- writeAPListRid(ai, &ai->APList, 0);
- enable_MAC(ai, 0);
-
- ai->scan_timeout = 0;
- clear_bit(JOB_SCAN_RESULTS, &ai->jobs);
- up(&ai->sem);
-
- /* Send an empty event to user space.
- * We don't send the received data on
- * the event because it would require
- * us to do complex transcoding, and
- * we want to minimise the work done in
- * the irq handler. Use a request to
- * extract the data - Jean II */
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static int airo_thread(void *data)
-{
- struct net_device *dev = data;
- struct airo_info *ai = dev->ml_priv;
- int locked;
-
- set_freezable();
- while (1) {
- /* make swsusp happy with our thread */
- try_to_freeze();
-
- if (test_bit(JOB_DIE, &ai->jobs))
- break;
-
- if (ai->jobs) {
- locked = down_interruptible(&ai->sem);
- } else {
- wait_queue_entry_t wait;
-
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&ai->thr_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (ai->jobs)
- break;
- if (ai->expires || ai->scan_timeout) {
- if (ai->scan_timeout &&
- time_after_eq(jiffies, ai->scan_timeout)) {
- set_bit(JOB_SCAN_RESULTS, &ai->jobs);
- break;
- } else if (ai->expires &&
- time_after_eq(jiffies, ai->expires)) {
- set_bit(JOB_AUTOWEP, &ai->jobs);
- break;
- }
- if (!kthread_should_stop() &&
- !freezing(current)) {
- unsigned long wake_at;
- if (!ai->expires || !ai->scan_timeout) {
- wake_at = max(ai->expires,
- ai->scan_timeout);
- } else {
- wake_at = min(ai->expires,
- ai->scan_timeout);
- }
- schedule_timeout(wake_at - jiffies);
- continue;
- }
- } else if (!kthread_should_stop() &&
- !freezing(current)) {
- schedule();
- continue;
- }
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&ai->thr_wait, &wait);
- locked = 1;
- }
-
- if (locked)
- continue;
-
- if (test_bit(JOB_DIE, &ai->jobs)) {
- up(&ai->sem);
- break;
- }
-
- if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) {
- up(&ai->sem);
- continue;
- }
-
- if (test_bit(JOB_XMIT, &ai->jobs))
- airo_end_xmit(dev, true);
- else if (test_bit(JOB_XMIT11, &ai->jobs))
- airo_end_xmit11(dev, true);
- else if (test_bit(JOB_STATS, &ai->jobs))
- airo_read_stats(dev);
- else if (test_bit(JOB_PROMISC, &ai->jobs))
- airo_set_promisc(ai, true);
- else if (test_bit(JOB_MIC, &ai->jobs))
- micinit(ai);
- else if (test_bit(JOB_EVENT, &ai->jobs))
- airo_send_event(dev);
- else if (test_bit(JOB_AUTOWEP, &ai->jobs))
- timer_func(dev);
- else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs))
- airo_process_scan_results(ai);
- else /* Shouldn't get here, but we make sure to unlock */
- up(&ai->sem);
- }
-
- return 0;
-}
-
-static int header_len(__le16 ctl)
-{
- u16 fc = le16_to_cpu(ctl);
- switch (fc & 0xc) {
- case 4:
- if ((fc & 0xe0) == 0xc0)
- return 10; /* one-address control packet */
- return 16; /* two-address control packet */
- case 8:
- if ((fc & 0x300) == 0x300)
- return 30; /* WDS packet */
- }
- return 24;
-}
-
-static void airo_handle_cisco_mic(struct airo_info *ai)
-{
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) {
- set_bit(JOB_MIC, &ai->jobs);
- wake_up_interruptible(&ai->thr_wait);
- }
-}
-
-/* Airo Status codes */
-#define STAT_NOBEACON 0x8000 /* Loss of sync - missed beacons */
-#define STAT_MAXRETRIES 0x8001 /* Loss of sync - max retries */
-#define STAT_MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
-#define STAT_FORCELOSS 0x8003 /* Loss of sync - host request */
-#define STAT_TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
-#define STAT_DEAUTH 0x8100 /* low byte is 802.11 reason code */
-#define STAT_DISASSOC 0x8200 /* low byte is 802.11 reason code */
-#define STAT_ASSOC_FAIL 0x8400 /* low byte is 802.11 reason code */
-#define STAT_AUTH_FAIL 0x0300 /* low byte is 802.11 reason code */
-#define STAT_ASSOC 0x0400 /* Associated */
-#define STAT_REASSOC 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */
-
-static void airo_print_status(const char *devname, u16 status)
-{
- u8 reason = status & 0xFF;
-
- switch (status & 0xFF00) {
- case STAT_NOBEACON:
- switch (status) {
- case STAT_NOBEACON:
- airo_print_dbg(devname, "link lost (missed beacons)");
- break;
- case STAT_MAXRETRIES:
- case STAT_MAXARL:
- airo_print_dbg(devname, "link lost (max retries)");
- break;
- case STAT_FORCELOSS:
- airo_print_dbg(devname, "link lost (local choice)");
- break;
- case STAT_TSFSYNC:
- airo_print_dbg(devname, "link lost (TSF sync lost)");
- break;
- default:
- airo_print_dbg(devname, "unknown status %x\n", status);
- break;
- }
- break;
- case STAT_DEAUTH:
- airo_print_dbg(devname, "deauthenticated (reason: %d)", reason);
- break;
- case STAT_DISASSOC:
- airo_print_dbg(devname, "disassociated (reason: %d)", reason);
- break;
- case STAT_ASSOC_FAIL:
- airo_print_dbg(devname, "association failed (reason: %d)",
- reason);
- break;
- case STAT_AUTH_FAIL:
- airo_print_dbg(devname, "authentication failed (reason: %d)",
- reason);
- break;
- case STAT_ASSOC:
- case STAT_REASSOC:
- break;
- default:
- airo_print_dbg(devname, "unknown status %x\n", status);
- break;
- }
-}
-
-static void airo_handle_link(struct airo_info *ai)
-{
- union iwreq_data wrqu;
- int scan_forceloss = 0;
- u16 status;
-
- /* Get new status and acknowledge the link change */
- status = le16_to_cpu(IN4500(ai, LINKSTAT));
- OUT4500(ai, EVACK, EV_LINK);
-
- if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0))
- scan_forceloss = 1;
-
- airo_print_status(ai->dev->name, status);
-
- if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) {
- if (auto_wep)
- ai->expires = 0;
- if (ai->list_bss_task)
- wake_up_process(ai->list_bss_task);
- set_bit(FLAG_UPDATE_UNI, &ai->flags);
- set_bit(FLAG_UPDATE_MULTI, &ai->flags);
-
- set_bit(JOB_EVENT, &ai->jobs);
- wake_up_interruptible(&ai->thr_wait);
-
- netif_carrier_on(ai->dev);
- } else if (!scan_forceloss) {
- if (auto_wep && !ai->expires) {
- ai->expires = RUN_AT(3*HZ);
- wake_up_interruptible(&ai->thr_wait);
- }
-
- /* Send event to user space */
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL);
- netif_carrier_off(ai->dev);
- } else {
- netif_carrier_off(ai->dev);
- }
-}
-
-static void airo_handle_rx(struct airo_info *ai)
-{
- struct sk_buff *skb = NULL;
- __le16 fc, v, *buffer, tmpbuf[4];
- u16 len, hdrlen = 0, gap, fid;
- struct rx_hdr hdr;
- int success = 0;
-
- if (test_bit(FLAG_MPI, &ai->flags)) {
- if (test_bit(FLAG_802_11, &ai->flags))
- mpi_receive_802_11(ai);
- else
- mpi_receive_802_3(ai);
- OUT4500(ai, EVACK, EV_RX);
- return;
- }
-
- fid = IN4500(ai, RXFID);
-
- /* Get the packet length */
- if (test_bit(FLAG_802_11, &ai->flags)) {
- bap_setup (ai, fid, 4, BAP0);
- bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0);
- /* Bad CRC. Ignore packet */
- if (le16_to_cpu(hdr.status) & 2)
- hdr.len = 0;
- if (ai->wifidev == NULL)
- hdr.len = 0;
- } else {
- bap_setup(ai, fid, 0x36, BAP0);
- bap_read(ai, &hdr.len, 2, BAP0);
- }
- len = le16_to_cpu(hdr.len);
-
- if (len > AIRO_DEF_MTU) {
- airo_print_err(ai->dev->name, "Bad size %d", len);
- goto done;
- }
- if (len == 0)
- goto done;
-
- if (test_bit(FLAG_802_11, &ai->flags)) {
- bap_read(ai, &fc, sizeof (fc), BAP0);
- hdrlen = header_len(fc);
- } else
- hdrlen = ETH_ALEN * 2;
-
- skb = dev_alloc_skb(len + hdrlen + 2 + 2);
- if (!skb) {
- ai->dev->stats.rx_dropped++;
- goto done;
- }
-
- skb_reserve(skb, 2); /* This way the IP header is aligned */
- buffer = skb_put(skb, len + hdrlen);
- if (test_bit(FLAG_802_11, &ai->flags)) {
- buffer[0] = fc;
- bap_read(ai, buffer + 1, hdrlen - 2, BAP0);
- if (hdrlen == 24)
- bap_read(ai, tmpbuf, 6, BAP0);
-
- bap_read(ai, &v, sizeof(v), BAP0);
- gap = le16_to_cpu(v);
- if (gap) {
- if (gap <= 8) {
- bap_read(ai, tmpbuf, gap, BAP0);
- } else {
- airo_print_err(ai->dev->name, "gaplen too "
- "big. Problems will follow...");
- }
- }
- bap_read(ai, buffer + hdrlen/2, len, BAP0);
- } else {
- MICBuffer micbuf;
-
- bap_read(ai, buffer, ETH_ALEN * 2, BAP0);
- if (ai->micstats.enabled) {
- bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0);
- if (ntohs(micbuf.typelen) > 0x05DC)
- bap_setup(ai, fid, 0x44, BAP0);
- else {
- if (len <= sizeof (micbuf)) {
- dev_kfree_skb_irq(skb);
- goto done;
- }
-
- len -= sizeof(micbuf);
- skb_trim(skb, len + hdrlen);
- }
- }
-
- bap_read(ai, buffer + ETH_ALEN, len, BAP0);
- if (decapsulate(ai, &micbuf, (etherHead*) buffer, len))
- dev_kfree_skb_irq (skb);
- else
- success = 1;
- }
-
-#ifdef WIRELESS_SPY
- if (success && (ai->spy_data.spy_number > 0)) {
- char *sa;
- struct iw_quality wstats;
-
- /* Prepare spy data : addr + qual */
- if (!test_bit(FLAG_802_11, &ai->flags)) {
- sa = (char *) buffer + 6;
- bap_setup(ai, fid, 8, BAP0);
- bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0);
- } else
- sa = (char *) buffer + 10;
- wstats.qual = hdr.rssi[0];
- if (ai->rssi)
- wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
- else
- wstats.level = (hdr.rssi[1] + 321) / 2;
- wstats.noise = ai->wstats.qual.noise;
- wstats.updated = IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_QUAL_UPDATED
- | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(ai->dev, sa, &wstats);
- }
-#endif /* WIRELESS_SPY */
-
-done:
- OUT4500(ai, EVACK, EV_RX);
-
- if (success) {
- if (test_bit(FLAG_802_11, &ai->flags)) {
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->dev = ai->wifidev;
- skb->protocol = htons(ETH_P_802_2);
- } else
- skb->protocol = eth_type_trans(skb, ai->dev);
- skb->ip_summed = CHECKSUM_NONE;
-
- netif_rx(skb);
- }
-}
-
-static void airo_handle_tx(struct airo_info *ai, u16 status)
-{
- int i, index = -1;
- u16 fid;
-
- if (test_bit(FLAG_MPI, &ai->flags)) {
- unsigned long flags;
-
- if (status & EV_TXEXC)
- get_tx_error(ai, -1);
-
- spin_lock_irqsave(&ai->aux_lock, flags);
- if (!skb_queue_empty(&ai->txq)) {
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- mpi_send_packet(ai->dev);
- } else {
- clear_bit(FLAG_PENDING_XMIT, &ai->flags);
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- netif_wake_queue(ai->dev);
- }
- OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
- return;
- }
-
- fid = IN4500(ai, TXCOMPLFID);
-
- for (i = 0; i < MAX_FIDS; i++) {
- if ((ai->fids[i] & 0xffff) == fid)
- index = i;
- }
-
- if (index != -1) {
- if (status & EV_TXEXC)
- get_tx_error(ai, index);
-
- OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC));
-
- /* Set up to be used again */
- ai->fids[index] &= 0xffff;
- if (index < MAX_FIDS / 2) {
- if (!test_bit(FLAG_PENDING_XMIT, &ai->flags))
- netif_wake_queue(ai->dev);
- } else {
- if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags))
- netif_wake_queue(ai->wifidev);
- }
- } else {
- OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC));
- airo_print_err(ai->dev->name, "Unallocated FID was used to xmit");
- }
-}
-
-static irqreturn_t airo_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- u16 status, savedInterrupts = 0;
- struct airo_info *ai = dev->ml_priv;
- int handled = 0;
-
- if (!netif_device_present(dev))
- return IRQ_NONE;
-
- for (;;) {
- status = IN4500(ai, EVSTAT);
- if (!(status & STATUS_INTS) || (status == 0xffff))
- break;
-
- handled = 1;
-
- if (status & EV_AWAKE) {
- OUT4500(ai, EVACK, EV_AWAKE);
- OUT4500(ai, EVACK, EV_AWAKE);
- }
-
- if (!savedInterrupts) {
- savedInterrupts = IN4500(ai, EVINTEN);
- OUT4500(ai, EVINTEN, 0);
- }
-
- if (status & EV_MIC) {
- OUT4500(ai, EVACK, EV_MIC);
- airo_handle_cisco_mic(ai);
- }
-
- if (status & EV_LINK) {
- /* Link status changed */
- airo_handle_link(ai);
- }
-
- /* Check to see if there is something to receive */
- if (status & EV_RX)
- airo_handle_rx(ai);
-
- /* Check to see if a packet has been transmitted */
- if (status & (EV_TX | EV_TXCPY | EV_TXEXC))
- airo_handle_tx(ai, status);
-
- if (status & ~STATUS_INTS & ~IGNORE_INTS) {
- airo_print_warn(ai->dev->name, "Got weird status %x",
- status & ~STATUS_INTS & ~IGNORE_INTS);
- }
- }
-
- if (savedInterrupts)
- OUT4500(ai, EVINTEN, savedInterrupts);
-
- return IRQ_RETVAL(handled);
-}
-
-/*
- * Routines to talk to the card
- */
-
-/*
- * This was originally written for the 4500, hence the name
- * NOTE: If use with 8bit mode and SMP bad things will happen!
- * Why would some one do 8 bit IO in an SMP machine?!?
- */
-static void OUT4500(struct airo_info *ai, u16 reg, u16 val)
-{
- if (test_bit(FLAG_MPI,&ai->flags))
- reg <<= 1;
- if (!do8bitIO)
- outw(val, ai->dev->base_addr + reg);
- else {
- outb(val & 0xff, ai->dev->base_addr + reg);
- outb(val >> 8, ai->dev->base_addr + reg + 1);
- }
-}
-
-static u16 IN4500(struct airo_info *ai, u16 reg)
-{
- unsigned short rc;
-
- if (test_bit(FLAG_MPI,&ai->flags))
- reg <<= 1;
- if (!do8bitIO)
- rc = inw(ai->dev->base_addr + reg);
- else {
- rc = inb(ai->dev->base_addr + reg);
- rc += ((int)inb(ai->dev->base_addr + reg + 1)) << 8;
- }
- return rc;
-}
-
-static int enable_MAC(struct airo_info *ai, int lock)
-{
- int rc;
- Cmd cmd;
- Resp rsp;
-
- /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
- * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
- * Note : we could try to use !netif_running(dev) in enable_MAC()
- * instead of this flag, but I don't trust it *within* the
- * open/close functions, and testing both flags together is
- * "cheaper" - Jean II */
- if (ai->flags & FLAG_RADIO_MASK) return SUCCESS;
-
- if (lock && down_interruptible(&ai->sem))
- return -ERESTARTSYS;
-
- if (!test_bit(FLAG_ENABLED, &ai->flags)) {
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = MAC_ENABLE;
- rc = issuecommand(ai, &cmd, &rsp, true);
- if (rc == SUCCESS)
- set_bit(FLAG_ENABLED, &ai->flags);
- } else
- rc = SUCCESS;
-
- if (lock)
- up(&ai->sem);
-
- if (rc)
- airo_print_err(ai->dev->name, "Cannot enable MAC");
- else if ((rsp.status & 0xFF00) != 0) {
- airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, "
- "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2);
- rc = ERROR;
- }
- return rc;
-}
-
-static void disable_MAC(struct airo_info *ai, int lock)
-{
- Cmd cmd;
- Resp rsp;
-
- if (lock == 1 && down_interruptible(&ai->sem))
- return;
-
- if (test_bit(FLAG_ENABLED, &ai->flags)) {
- if (lock != 2) /* lock == 2 means don't disable carrier */
- netif_carrier_off(ai->dev);
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = MAC_DISABLE; // disable in case already enabled
- issuecommand(ai, &cmd, &rsp, true);
- clear_bit(FLAG_ENABLED, &ai->flags);
- }
- if (lock == 1)
- up(&ai->sem);
-}
-
-static void enable_interrupts(struct airo_info *ai)
-{
- /* Enable the interrupts */
- OUT4500(ai, EVINTEN, STATUS_INTS);
-}
-
-static void disable_interrupts(struct airo_info *ai)
-{
- OUT4500(ai, EVINTEN, 0);
-}
-
-static void mpi_receive_802_3(struct airo_info *ai)
-{
- RxFid rxd;
- int len = 0;
- struct sk_buff *skb;
- char *buffer;
- int off = 0;
- MICBuffer micbuf;
-
- memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
- /* Make sure we got something */
- if (rxd.rdy && rxd.valid == 0) {
- len = rxd.len + 12;
- if (len < 12 || len > 2048)
- goto badrx;
-
- skb = dev_alloc_skb(len);
- if (!skb) {
- ai->dev->stats.rx_dropped++;
- goto badrx;
- }
- buffer = skb_put(skb, len);
- memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2);
- if (ai->micstats.enabled) {
- memcpy(&micbuf,
- ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2,
- sizeof(micbuf));
- if (ntohs(micbuf.typelen) <= 0x05DC) {
- if (len <= sizeof(micbuf) + ETH_ALEN * 2)
- goto badmic;
-
- off = sizeof(micbuf);
- skb_trim (skb, len - off);
- }
- }
- memcpy(buffer + ETH_ALEN * 2,
- ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off,
- len - ETH_ALEN * 2 - off);
- if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) {
-badmic:
- dev_kfree_skb_irq (skb);
- goto badrx;
- }
-#ifdef WIRELESS_SPY
- if (ai->spy_data.spy_number > 0) {
- char *sa;
- struct iw_quality wstats;
- /* Prepare spy data : addr + qual */
- sa = buffer + ETH_ALEN;
- wstats.qual = 0; /* XXX Where do I get that info from ??? */
- wstats.level = 0;
- wstats.updated = 0;
- /* Update spy records */
- wireless_spy_update(ai->dev, sa, &wstats);
- }
-#endif /* WIRELESS_SPY */
-
- skb->ip_summed = CHECKSUM_NONE;
- skb->protocol = eth_type_trans(skb, ai->dev);
- netif_rx(skb);
- }
-badrx:
- if (rxd.valid == 0) {
- rxd.valid = 1;
- rxd.rdy = 0;
- rxd.len = PKTSIZE;
- memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
- }
-}
-
-static void mpi_receive_802_11(struct airo_info *ai)
-{
- RxFid rxd;
- struct sk_buff *skb = NULL;
- u16 len, hdrlen = 0;
- __le16 fc;
- struct rx_hdr hdr;
- u16 gap;
- u16 *buffer;
- char *ptr = ai->rxfids[0].virtual_host_addr + 4;
-
- memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd));
- memcpy ((char *)&hdr, ptr, sizeof(hdr));
- ptr += sizeof(hdr);
- /* Bad CRC. Ignore packet */
- if (le16_to_cpu(hdr.status) & 2)
- hdr.len = 0;
- if (ai->wifidev == NULL)
- hdr.len = 0;
- len = le16_to_cpu(hdr.len);
- if (len > AIRO_DEF_MTU) {
- airo_print_err(ai->dev->name, "Bad size %d", len);
- goto badrx;
- }
- if (len == 0)
- goto badrx;
-
- fc = get_unaligned((__le16 *)ptr);
- hdrlen = header_len(fc);
-
- skb = dev_alloc_skb(len + hdrlen + 2);
- if (!skb) {
- ai->dev->stats.rx_dropped++;
- goto badrx;
- }
- buffer = skb_put(skb, len + hdrlen);
- memcpy ((char *)buffer, ptr, hdrlen);
- ptr += hdrlen;
- if (hdrlen == 24)
- ptr += 6;
- gap = get_unaligned_le16(ptr);
- ptr += sizeof(__le16);
- if (gap) {
- if (gap <= 8)
- ptr += gap;
- else
- airo_print_err(ai->dev->name,
- "gaplen too big. Problems will follow...");
- }
- memcpy ((char *)buffer + hdrlen, ptr, len);
- ptr += len;
-#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
- if (ai->spy_data.spy_number > 0) {
- char *sa;
- struct iw_quality wstats;
- /* Prepare spy data : addr + qual */
- sa = (char*)buffer + 10;
- wstats.qual = hdr.rssi[0];
- if (ai->rssi)
- wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm;
- else
- wstats.level = (hdr.rssi[1] + 321) / 2;
- wstats.noise = ai->wstats.qual.noise;
- wstats.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(ai->dev, sa, &wstats);
- }
-#endif /* IW_WIRELESS_SPY */
- skb_reset_mac_header(skb);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->dev = ai->wifidev;
- skb->protocol = htons(ETH_P_802_2);
- skb->ip_summed = CHECKSUM_NONE;
- netif_rx(skb);
-
-badrx:
- if (rxd.valid == 0) {
- rxd.valid = 1;
- rxd.rdy = 0;
- rxd.len = PKTSIZE;
- memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd));
- }
-}
-
-static inline void set_auth_type(struct airo_info *local, int auth_type)
-{
- local->config.authType = auth_type;
- /* Cache the last auth type used (of AUTH_OPEN and AUTH_ENCRYPT).
- * Used by airo_set_auth()
- */
- if (auth_type == AUTH_OPEN || auth_type == AUTH_ENCRYPT)
- local->last_auth = auth_type;
-}
-
-static int noinline_for_stack airo_readconfig(struct airo_info *ai,
- struct net_device *dev, int lock)
-{
- int i, status;
- /* large variables, so don't inline this function,
- * maybe change to kmalloc
- */
- tdsRssiRid rssi_rid;
- CapabilityRid cap_rid;
-
- kfree(ai->SSID);
- ai->SSID = NULL;
- // general configuration (read/modify/write)
- status = readConfigRid(ai, lock);
- if (status != SUCCESS) return ERROR;
-
- status = readCapabilityRid(ai, &cap_rid, lock);
- if (status != SUCCESS) return ERROR;
-
- status = PC4500_readrid(ai, RID_RSSI, &rssi_rid, sizeof(rssi_rid), lock);
- if (status == SUCCESS) {
- if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL)
- memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */
- }
- else {
- kfree(ai->rssi);
- ai->rssi = NULL;
- if (cap_rid.softCap & cpu_to_le16(8))
- ai->config.rmode |= RXMODE_NORMALIZED_RSSI;
- else
- airo_print_warn(ai->dev->name, "unknown received signal "
- "level scale");
- }
- ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
- set_auth_type(ai, AUTH_OPEN);
- ai->config.modulation = MOD_CCK;
-
- if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) &&
- (cap_rid.extSoftCap & cpu_to_le16(1)) &&
- micsetup(ai) == SUCCESS) {
- ai->config.opmode |= MODE_MIC;
- set_bit(FLAG_MIC_CAPABLE, &ai->flags);
- }
-
- /* Save off the MAC */
- eth_hw_addr_set(dev, ai->config.macAddr);
-
- /* Check to see if there are any insmod configured
- rates to add */
- if (rates[0]) {
- memset(ai->config.rates, 0, sizeof(ai->config.rates));
- for (i = 0; i < 8 && rates[i]; i++) {
- ai->config.rates[i] = rates[i];
- }
- }
- set_bit (FLAG_COMMIT, &ai->flags);
-
- return SUCCESS;
-}
-
-
-static u16 setup_card(struct airo_info *ai, struct net_device *dev, int lock)
-{
- Cmd cmd;
- Resp rsp;
- int status;
- SsidRid mySsid;
- __le16 lastindex;
- WepKeyRid wkr;
- int rc;
-
- memset(&mySsid, 0, sizeof(mySsid));
- kfree (ai->flash);
- ai->flash = NULL;
-
- /* The NOP is the first step in getting the card going */
- cmd.cmd = NOP;
- cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
- if (lock && down_interruptible(&ai->sem))
- return ERROR;
- if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
- if (lock)
- up(&ai->sem);
- return ERROR;
- }
- disable_MAC(ai, 0);
-
- // Let's figure out if we need to use the AUX port
- if (!test_bit(FLAG_MPI,&ai->flags)) {
- cmd.cmd = CMD_ENABLEAUX;
- if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
- if (lock)
- up(&ai->sem);
- airo_print_err(ai->dev->name, "Error checking for AUX port");
- return ERROR;
- }
- if (!aux_bap || rsp.status & 0xff00) {
- ai->bap_read = fast_bap_read;
- airo_print_dbg(ai->dev->name, "Doing fast bap_reads");
- } else {
- ai->bap_read = aux_bap_read;
- airo_print_dbg(ai->dev->name, "Doing AUX bap_reads");
- }
- }
- if (lock)
- up(&ai->sem);
- if (ai->config.len == 0) {
- status = airo_readconfig(ai, dev, lock);
- if (status != SUCCESS)
- return ERROR;
- }
-
- /* Setup the SSIDs if present */
- if (ssids[0]) {
- int i;
- for (i = 0; i < 3 && ssids[i]; i++) {
- size_t len = strlen(ssids[i]);
- if (len > 32)
- len = 32;
- mySsid.ssids[i].len = cpu_to_le16(len);
- memcpy(mySsid.ssids[i].ssid, ssids[i], len);
- }
- mySsid.len = cpu_to_le16(sizeof(mySsid));
- }
-
- status = writeConfigRid(ai, lock);
- if (status != SUCCESS) return ERROR;
-
- /* Set up the SSID list */
- if (ssids[0]) {
- status = writeSsidRid(ai, &mySsid, lock);
- if (status != SUCCESS) return ERROR;
- }
-
- status = enable_MAC(ai, lock);
- if (status != SUCCESS)
- return ERROR;
-
- /* Grab the initial wep key, we gotta save it for auto_wep */
- rc = readWepKeyRid(ai, &wkr, 1, lock);
- if (rc == SUCCESS) do {
- lastindex = wkr.kindex;
- if (wkr.kindex == cpu_to_le16(0xffff)) {
- ai->defindex = wkr.mac[0];
- }
- rc = readWepKeyRid(ai, &wkr, 0, lock);
- } while (lastindex != wkr.kindex);
-
- try_auto_wep(ai);
-
- return SUCCESS;
-}
-
-static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp,
- bool may_sleep)
-{
- // Im really paranoid about letting it run forever!
- int max_tries = 600000;
-
- if (IN4500(ai, EVSTAT) & EV_CMD)
- OUT4500(ai, EVACK, EV_CMD);
-
- OUT4500(ai, PARAM0, pCmd->parm0);
- OUT4500(ai, PARAM1, pCmd->parm1);
- OUT4500(ai, PARAM2, pCmd->parm2);
- OUT4500(ai, COMMAND, pCmd->cmd);
-
- while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) {
- if ((IN4500(ai, COMMAND)) == pCmd->cmd)
- // PC4500 didn't notice command, try again
- OUT4500(ai, COMMAND, pCmd->cmd);
- if (may_sleep && (max_tries & 255) == 0)
- cond_resched();
- }
-
- if (max_tries == -1) {
- airo_print_err(ai->dev->name,
- "Max tries exceeded when issuing command");
- if (IN4500(ai, COMMAND) & COMMAND_BUSY)
- OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
- return ERROR;
- }
-
- // command completed
- pRsp->status = IN4500(ai, STATUS);
- pRsp->rsp0 = IN4500(ai, RESP0);
- pRsp->rsp1 = IN4500(ai, RESP1);
- pRsp->rsp2 = IN4500(ai, RESP2);
- if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
- airo_print_err(ai->dev->name,
- "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
- pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
- pRsp->rsp2);
-
- // clear stuck command busy if necessary
- if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
- OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
- }
- // acknowledge processing the status/response
- OUT4500(ai, EVACK, EV_CMD);
-
- return SUCCESS;
-}
-
-/* Sets up the bap to start exchange data. whichbap should
- * be one of the BAP0 or BAP1 defines. Locks should be held before
- * calling! */
-static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap)
-{
- int timeout = 50;
- int max_tries = 3;
-
- OUT4500(ai, SELECT0+whichbap, rid);
- OUT4500(ai, OFFSET0+whichbap, offset);
- while (1) {
- int status = IN4500(ai, OFFSET0+whichbap);
- if (status & BAP_BUSY) {
- /* This isn't really a timeout, but its kinda
- close */
- if (timeout--) {
- continue;
- }
- } else if (status & BAP_ERR) {
- /* invalid rid or offset */
- airo_print_err(ai->dev->name, "BAP error %x %d",
- status, whichbap);
- return ERROR;
- } else if (status & BAP_DONE) { // success
- return SUCCESS;
- }
- if (!(max_tries--)) {
- airo_print_err(ai->dev->name,
- "BAP setup error too many retries\n");
- return ERROR;
- }
- // -- PC4500 missed it, try again
- OUT4500(ai, SELECT0+whichbap, rid);
- OUT4500(ai, OFFSET0+whichbap, offset);
- timeout = 50;
- }
-}
-
-/* should only be called by aux_bap_read. This aux function and the
- following use concepts not documented in the developers guide. I
- got them from a patch given to my by Aironet */
-static u16 aux_setup(struct airo_info *ai, u16 page,
- u16 offset, u16 *len)
-{
- u16 next;
-
- OUT4500(ai, AUXPAGE, page);
- OUT4500(ai, AUXOFF, 0);
- next = IN4500(ai, AUXDATA);
- *len = IN4500(ai, AUXDATA)&0xff;
- if (offset != 4) OUT4500(ai, AUXOFF, offset);
- return next;
-}
-
-/* requires call to bap_setup() first */
-static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst,
- int bytelen, int whichbap)
-{
- u16 len;
- u16 page;
- u16 offset;
- u16 next;
- int words;
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&ai->aux_lock, flags);
- page = IN4500(ai, SWS0+whichbap);
- offset = IN4500(ai, SWS2+whichbap);
- next = aux_setup(ai, page, offset, &len);
- words = (bytelen+1)>>1;
-
- for (i = 0; i<words;) {
- int count;
- count = (len>>1) < (words-i) ? (len>>1) : (words-i);
- if (!do8bitIO)
- insw(ai->dev->base_addr+DATA0+whichbap,
- pu16Dst+i, count);
- else
- insb(ai->dev->base_addr+DATA0+whichbap,
- pu16Dst+i, count << 1);
- i += count;
- if (i<words) {
- next = aux_setup(ai, next, 4, &len);
- }
- }
- spin_unlock_irqrestore(&ai->aux_lock, flags);
- return SUCCESS;
-}
-
-
-/* requires call to bap_setup() first */
-static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst,
- int bytelen, int whichbap)
-{
- bytelen = (bytelen + 1) & (~1); // round up to even value
- if (!do8bitIO)
- insw(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1);
- else
- insb(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen);
- return SUCCESS;
-}
-
-/* requires call to bap_setup() first */
-static int bap_write(struct airo_info *ai, const __le16 *pu16Src,
- int bytelen, int whichbap)
-{
- bytelen = (bytelen + 1) & (~1); // round up to even value
- if (!do8bitIO)
- outsw(ai->dev->base_addr+DATA0+whichbap,
- pu16Src, bytelen>>1);
- else
- outsb(ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen);
- return SUCCESS;
-}
-
-static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
-{
- Cmd cmd; /* for issuing commands */
- Resp rsp; /* response from commands */
- u16 status;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = accmd;
- cmd.parm0 = rid;
- status = issuecommand(ai, &cmd, &rsp, true);
- if (status != 0) return status;
- if ((rsp.status & 0x7F00) != 0) {
- return (accmd << 8) + (rsp.rsp0 & 0xFF);
- }
- return 0;
-}
-
-/* Note, that we are using BAP1 which is also used by transmit, so
- * we must get a lock. */
-static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock)
-{
- u16 status;
- int rc = SUCCESS;
-
- if (lock) {
- if (down_interruptible(&ai->sem))
- return ERROR;
- }
- if (test_bit(FLAG_MPI,&ai->flags)) {
- Cmd cmd;
- Resp rsp;
-
- memset(&cmd, 0, sizeof(cmd));
- memset(&rsp, 0, sizeof(rsp));
- ai->config_desc.rid_desc.valid = 1;
- ai->config_desc.rid_desc.len = RIDSIZE;
- ai->config_desc.rid_desc.rid = 0;
- ai->config_desc.rid_desc.host_addr = ai->ridbus;
-
- cmd.cmd = CMD_ACCESS;
- cmd.parm0 = rid;
-
- memcpy_toio(ai->config_desc.card_ram_off,
- &ai->config_desc.rid_desc, sizeof(Rid));
-
- rc = issuecommand(ai, &cmd, &rsp, true);
-
- if (rsp.status & 0x7f00)
- rc = rsp.rsp0;
- if (!rc)
- memcpy(pBuf, ai->config_desc.virtual_host_addr, len);
- goto done;
- } else {
- if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) {
- rc = status;
- goto done;
- }
- if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
- rc = ERROR;
- goto done;
- }
- // read the rid length field
- bap_read(ai, pBuf, 2, BAP1);
- // length for remaining part of rid
- len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
-
- if (len <= 2) {
- airo_print_err(ai->dev->name,
- "Rid %x has a length of %d which is too short",
- (int)rid, (int)len);
- rc = ERROR;
- goto done;
- }
- // read remainder of the rid
- rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);
- }
-done:
- if (lock)
- up(&ai->sem);
- return rc;
-}
-
-/* Note, that we are using BAP1 which is also used by transmit, so
- * make sure this isn't called when a transmit is happening */
-static int PC4500_writerid(struct airo_info *ai, u16 rid,
- const void *pBuf, int len, int lock)
-{
- u16 status;
- int rc = SUCCESS;
-
- *(__le16*)pBuf = cpu_to_le16((u16)len);
-
- if (lock) {
- if (down_interruptible(&ai->sem))
- return ERROR;
- }
- if (test_bit(FLAG_MPI,&ai->flags)) {
- Cmd cmd;
- Resp rsp;
-
- if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid))
- airo_print_err(ai->dev->name,
- "%s: MAC should be disabled (rid=%04x)",
- __func__, rid);
- memset(&cmd, 0, sizeof(cmd));
- memset(&rsp, 0, sizeof(rsp));
-
- ai->config_desc.rid_desc.valid = 1;
- ai->config_desc.rid_desc.len = *((u16 *)pBuf);
- ai->config_desc.rid_desc.rid = 0;
-
- cmd.cmd = CMD_WRITERID;
- cmd.parm0 = rid;
-
- memcpy_toio(ai->config_desc.card_ram_off,
- &ai->config_desc.rid_desc, sizeof(Rid));
-
- if (len < 4 || len > 2047) {
- airo_print_err(ai->dev->name, "%s: len=%d", __func__, len);
- rc = -1;
- } else {
- memcpy(ai->config_desc.virtual_host_addr,
- pBuf, len);
-
- rc = issuecommand(ai, &cmd, &rsp, true);
- if ((rc & 0xff00) != 0) {
- airo_print_err(ai->dev->name, "%s: Write rid Error %d",
- __func__, rc);
- airo_print_err(ai->dev->name, "%s: Cmd=%04x",
- __func__, cmd.cmd);
- }
-
- if ((rsp.status & 0x7f00))
- rc = rsp.rsp0;
- }
- } else {
- // --- first access so that we can write the rid data
- if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
- rc = status;
- goto done;
- }
- // --- now write the rid data
- if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
- rc = ERROR;
- goto done;
- }
- bap_write(ai, pBuf, len, BAP1);
- // ---now commit the rid data
- rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
- }
-done:
- if (lock)
- up(&ai->sem);
- return rc;
-}
-
-/* Allocates a FID to be used for transmitting packets. We only use
- one for now. */
-static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw)
-{
- unsigned int loop = 3000;
- Cmd cmd;
- Resp rsp;
- u16 txFid;
- __le16 txControl;
-
- cmd.cmd = CMD_ALLOCATETX;
- cmd.parm0 = lenPayload;
- if (down_interruptible(&ai->sem))
- return ERROR;
- if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) {
- txFid = ERROR;
- goto done;
- }
- if ((rsp.status & 0xFF00) != 0) {
- txFid = ERROR;
- goto done;
- }
- /* wait for the allocate event/indication
- * It makes me kind of nervous that this can just sit here and spin,
- * but in practice it only loops like four times. */
- while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop);
- if (!loop) {
- txFid = ERROR;
- goto done;
- }
-
- // get the allocated fid and acknowledge
- txFid = IN4500(ai, TXALLOCFID);
- OUT4500(ai, EVACK, EV_ALLOC);
-
- /* The CARD is pretty cool since it converts the ethernet packet
- * into 802.11. Also note that we don't release the FID since we
- * will be using the same one over and over again. */
- /* We only have to setup the control once since we are not
- * releasing the fid. */
- if (raw)
- txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11
- | TXCTL_ETHERNET | TXCTL_NORELEASE);
- else
- txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
- | TXCTL_ETHERNET | TXCTL_NORELEASE);
- if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS)
- txFid = ERROR;
- else
- bap_write(ai, &txControl, sizeof(txControl), BAP1);
-
-done:
- up(&ai->sem);
-
- return txFid;
-}
-
-/* In general BAP1 is dedicated to transmiting packets. However,
- since we need a BAP when accessing RIDs, we also use BAP1 for that.
- Make sure the BAP1 spinlock is held when this is called. */
-static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket,
- bool may_sleep)
-{
- __le16 payloadLen;
- Cmd cmd;
- Resp rsp;
- int miclen = 0;
- u16 txFid = len;
- MICBuffer pMic;
-
- len >>= 16;
-
- if (len <= ETH_ALEN * 2) {
- airo_print_warn(ai->dev->name, "Short packet %d", len);
- return ERROR;
- }
- len -= ETH_ALEN * 2;
-
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled &&
- (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) {
- if (encapsulate(ai, (etherHead *)pPacket,&pMic, len) != SUCCESS)
- return ERROR;
- miclen = sizeof(pMic);
- }
- // packet is destination[6], source[6], payload[len-12]
- // write the payload length and dst/src/payload
- if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
- /* The hardware addresses aren't counted as part of the payload, so
- * we have to subtract the 12 bytes for the addresses off */
- payloadLen = cpu_to_le16(len + miclen);
- bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1);
- bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1);
- if (miclen)
- bap_write(ai, (__le16*)&pMic, miclen, BAP1);
- bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1);
- // issue the transmit command
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_TRANSMIT;
- cmd.parm0 = txFid;
- if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS)
- return ERROR;
- if ((rsp.status & 0xFF00) != 0) return ERROR;
- return SUCCESS;
-}
-
-static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket,
- bool may_sleep)
-{
- __le16 fc, payloadLen;
- Cmd cmd;
- Resp rsp;
- int hdrlen;
- static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6};
- /* padding of header to full size + le16 gaplen (6) + gaplen bytes */
- u16 txFid = len;
- len >>= 16;
-
- fc = *(__le16*)pPacket;
- hdrlen = header_len(fc);
-
- if (len < hdrlen) {
- airo_print_warn(ai->dev->name, "Short packet %d", len);
- return ERROR;
- }
-
- /* packet is 802.11 header + payload
- * write the payload length and dst/src/payload */
- if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR;
- /* The 802.11 header aren't counted as part of the payload, so
- * we have to subtract the header bytes off */
- payloadLen = cpu_to_le16(len-hdrlen);
- bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1);
- if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR;
- bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1);
- bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1);
-
- bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1);
- // issue the transmit command
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_TRANSMIT;
- cmd.parm0 = txFid;
- if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS)
- return ERROR;
- if ((rsp.status & 0xFF00) != 0) return ERROR;
- return SUCCESS;
-}
-
-/*
- * This is the proc_fs routines. It is a bit messier than I would
- * like! Feel free to clean it up!
- */
-
-static ssize_t proc_read(struct file *file,
- char __user *buffer,
- size_t len,
- loff_t *offset);
-
-static ssize_t proc_write(struct file *file,
- const char __user *buffer,
- size_t len,
- loff_t *offset);
-static int proc_close(struct inode *inode, struct file *file);
-
-static int proc_stats_open(struct inode *inode, struct file *file);
-static int proc_statsdelta_open(struct inode *inode, struct file *file);
-static int proc_status_open(struct inode *inode, struct file *file);
-static int proc_SSID_open(struct inode *inode, struct file *file);
-static int proc_APList_open(struct inode *inode, struct file *file);
-static int proc_BSSList_open(struct inode *inode, struct file *file);
-static int proc_config_open(struct inode *inode, struct file *file);
-static int proc_wepkey_open(struct inode *inode, struct file *file);
-
-static const struct proc_ops proc_statsdelta_ops = {
- .proc_read = proc_read,
- .proc_open = proc_statsdelta_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_stats_ops = {
- .proc_read = proc_read,
- .proc_open = proc_stats_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_status_ops = {
- .proc_read = proc_read,
- .proc_open = proc_status_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_SSID_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_SSID_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_BSSList_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_BSSList_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_APList_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_APList_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_config_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_config_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static const struct proc_ops proc_wepkey_ops = {
- .proc_read = proc_read,
- .proc_write = proc_write,
- .proc_open = proc_wepkey_open,
- .proc_release = proc_close,
- .proc_lseek = default_llseek,
-};
-
-static struct proc_dir_entry *airo_entry;
-
-struct proc_data {
- int release_buffer;
- int readlen;
- char *rbuffer;
- int writelen;
- int maxwritelen;
- char *wbuffer;
- void (*on_close) (struct inode *, struct file *);
-};
-
-static int setup_proc_entry(struct net_device *dev,
- struct airo_info *apriv)
-{
- struct proc_dir_entry *entry;
-
- /* First setup the device directory */
- strcpy(apriv->proc_name, dev->name);
- apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,
- airo_entry);
- if (!apriv->proc_entry)
- return -ENOMEM;
- proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid);
-
- /* Setup the StatsDelta */
- entry = proc_create_data("StatsDelta", 0444 & proc_perm,
- apriv->proc_entry, &proc_statsdelta_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the Stats */
- entry = proc_create_data("Stats", 0444 & proc_perm,
- apriv->proc_entry, &proc_stats_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the Status */
- entry = proc_create_data("Status", 0444 & proc_perm,
- apriv->proc_entry, &proc_status_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the Config */
- entry = proc_create_data("Config", proc_perm,
- apriv->proc_entry, &proc_config_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the SSID */
- entry = proc_create_data("SSID", proc_perm,
- apriv->proc_entry, &proc_SSID_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the APList */
- entry = proc_create_data("APList", proc_perm,
- apriv->proc_entry, &proc_APList_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the BSSList */
- entry = proc_create_data("BSSList", proc_perm,
- apriv->proc_entry, &proc_BSSList_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
-
- /* Setup the WepKey */
- entry = proc_create_data("WepKey", proc_perm,
- apriv->proc_entry, &proc_wepkey_ops, dev);
- if (!entry)
- goto fail;
- proc_set_user(entry, proc_kuid, proc_kgid);
- return 0;
-
-fail:
- remove_proc_subtree(apriv->proc_name, airo_entry);
- return -ENOMEM;
-}
-
-static int takedown_proc_entry(struct net_device *dev,
- struct airo_info *apriv)
-{
- remove_proc_subtree(apriv->proc_name, airo_entry);
- return 0;
-}
-
-/*
- * What we want from the proc_fs is to be able to efficiently read
- * and write the configuration. To do this, we want to read the
- * configuration when the file is opened and write it when the file is
- * closed. So basically we allocate a read buffer at open and fill it
- * with data, and allocate a write buffer and read it at close.
- */
-
-/*
- * The read routine is generic, it relies on the preallocated rbuffer
- * to supply the data.
- */
-static ssize_t proc_read(struct file *file,
- char __user *buffer,
- size_t len,
- loff_t *offset)
-{
- struct proc_data *priv = file->private_data;
-
- if (!priv->rbuffer)
- return -EINVAL;
-
- return simple_read_from_buffer(buffer, len, offset, priv->rbuffer,
- priv->readlen);
-}
-
-/*
- * The write routine is generic, it fills in a preallocated rbuffer
- * to supply the data.
- */
-static ssize_t proc_write(struct file *file,
- const char __user *buffer,
- size_t len,
- loff_t *offset)
-{
- ssize_t ret;
- struct proc_data *priv = file->private_data;
-
- if (!priv->wbuffer)
- return -EINVAL;
-
- ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset,
- buffer, len);
- if (ret > 0)
- priv->writelen = max_t(int, priv->writelen, *offset);
-
- return ret;
-}
-
-static int proc_status_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *apriv = dev->ml_priv;
- CapabilityRid cap_rid;
- StatusRid status_rid;
- u16 mode;
- int i;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
-
- readStatusRid(apriv, &status_rid, 1);
- readCapabilityRid(apriv, &cap_rid, 1);
-
- mode = le16_to_cpu(status_rid.mode);
-
- i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
- mode & 1 ? "CFG ": "",
- mode & 2 ? "ACT ": "",
- mode & 0x10 ? "SYN ": "",
- mode & 0x20 ? "LNK ": "",
- mode & 0x40 ? "LEAP ": "",
- mode & 0x80 ? "PRIV ": "",
- mode & 0x100 ? "KEY ": "",
- mode & 0x200 ? "WEP ": "",
- mode & 0x8000 ? "ERR ": "");
- sprintf(data->rbuffer+i, "Mode: %x\n"
- "Signal Strength: %d\n"
- "Signal Quality: %d\n"
- "SSID: %-.*s\n"
- "AP: %-.16s\n"
- "Freq: %d\n"
- "BitRate: %dmbs\n"
- "Driver Version: %s\n"
- "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
- "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
- "Software Version: %x\nSoftware Subversion: %x\n"
- "Boot block version: %x\n",
- le16_to_cpu(status_rid.mode),
- le16_to_cpu(status_rid.normalizedSignalStrength),
- le16_to_cpu(status_rid.signalQuality),
- le16_to_cpu(status_rid.SSIDlen),
- status_rid.SSID,
- status_rid.apName,
- le16_to_cpu(status_rid.channel),
- le16_to_cpu(status_rid.currentXmitRate) / 2,
- version,
- cap_rid.prodName,
- cap_rid.manName,
- cap_rid.prodVer,
- le16_to_cpu(cap_rid.radioType),
- le16_to_cpu(cap_rid.country),
- le16_to_cpu(cap_rid.hardVer),
- le16_to_cpu(cap_rid.softVer),
- le16_to_cpu(cap_rid.softSubVer),
- le16_to_cpu(cap_rid.bootBlockVer));
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_stats_rid_open(struct inode*, struct file*, u16);
-static int proc_statsdelta_open(struct inode *inode,
- struct file *file)
-{
- if (file->f_mode&FMODE_WRITE) {
- return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
- }
- return proc_stats_rid_open(inode, file, RID_STATSDELTA);
-}
-
-static int proc_stats_open(struct inode *inode, struct file *file)
-{
- return proc_stats_rid_open(inode, file, RID_STATS);
-}
-
-static int proc_stats_rid_open(struct inode *inode,
- struct file *file,
- u16 rid)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *apriv = dev->ml_priv;
- StatsRid stats;
- int i, j;
- __le32 *vals = stats.vals;
- int len;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(4096, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
-
- readStatsRid(apriv, &stats, rid, 1);
- len = le16_to_cpu(stats.len);
-
- j = 0;
- for (i = 0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
- if (!statsLabels[i]) continue;
- if (j+strlen(statsLabels[i])+16>4096) {
- airo_print_warn(apriv->dev->name,
- "Potentially disastrous buffer overflow averted!");
- break;
- }
- j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i],
- le32_to_cpu(vals[i]));
- }
- if (i*4 >= len) {
- airo_print_warn(apriv->dev->name, "Got a short rid");
- }
- data->readlen = j;
- return 0;
-}
-
-static int get_dec_u16(char *buffer, int *start, int limit)
-{
- u16 value;
- int valid = 0;
- for (value = 0; *start < limit && buffer[*start] >= '0' &&
- buffer[*start] <= '9'; (*start)++) {
- valid = 1;
- value *= 10;
- value += buffer[*start] - '0';
- }
- if (!valid) return -1;
- return value;
-}
-
-static int airo_config_commit(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra);
-
-static inline int sniffing_mode(struct airo_info *ai)
-{
- return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >=
- le16_to_cpu(RXMODE_RFMON);
-}
-
-static void proc_config_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- char *line;
-
- if (!data->writelen) return;
-
- readConfigRid(ai, 1);
- set_bit (FLAG_COMMIT, &ai->flags);
-
- line = data->wbuffer;
- while (line[0]) {
-/*** Mode processing */
- if (!strncmp(line, "Mode: ", 6)) {
- line += 6;
- if (sniffing_mode(ai))
- set_bit (FLAG_RESET, &ai->flags);
- ai->config.rmode &= ~RXMODE_FULL_MASK;
- clear_bit (FLAG_802_11, &ai->flags);
- ai->config.opmode &= ~MODE_CFG_MASK;
- ai->config.scanMode = SCANMODE_ACTIVE;
- if (line[0] == 'a') {
- ai->config.opmode |= MODE_STA_IBSS;
- } else {
- ai->config.opmode |= MODE_STA_ESS;
- if (line[0] == 'r') {
- ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
- ai->config.scanMode = SCANMODE_PASSIVE;
- set_bit (FLAG_802_11, &ai->flags);
- } else if (line[0] == 'y') {
- ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER;
- ai->config.scanMode = SCANMODE_PASSIVE;
- set_bit (FLAG_802_11, &ai->flags);
- } else if (line[0] == 'l')
- ai->config.rmode |= RXMODE_LANMON;
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- }
-
-/*** Radio status */
- else if (!strncmp(line,"Radio: ", 7)) {
- line += 7;
- if (!strncmp(line,"off", 3)) {
- set_bit (FLAG_RADIO_OFF, &ai->flags);
- } else {
- clear_bit (FLAG_RADIO_OFF, &ai->flags);
- }
- }
-/*** NodeName processing */
- else if (!strncmp(line, "NodeName: ", 10)) {
- int j;
-
- line += 10;
- memset(ai->config.nodeName, 0, 16);
-/* Do the name, assume a space between the mode and node name */
- for (j = 0; j < 16 && line[j] != '\n'; j++) {
- ai->config.nodeName[j] = line[j];
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- }
-
-/*** PowerMode processing */
- else if (!strncmp(line, "PowerMode: ", 11)) {
- line += 11;
- if (!strncmp(line, "PSPCAM", 6)) {
- ai->config.powerSaveMode = POWERSAVE_PSPCAM;
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "PSP", 3)) {
- ai->config.powerSaveMode = POWERSAVE_PSP;
- set_bit (FLAG_COMMIT, &ai->flags);
- } else {
- ai->config.powerSaveMode = POWERSAVE_CAM;
- set_bit (FLAG_COMMIT, &ai->flags);
- }
- } else if (!strncmp(line, "DataRates: ", 11)) {
- int v, i = 0, k = 0; /* i is index into line,
- k is index to rates */
-
- line += 11;
- while ((v = get_dec_u16(line, &i, 3))!=-1) {
- ai->config.rates[k++] = (u8)v;
- line += i + 1;
- i = 0;
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "Channel: ", 9)) {
- int v, i = 0;
- line += 9;
- v = get_dec_u16(line, &i, i+3);
- if (v != -1) {
- ai->config.channelSet = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- }
- } else if (!strncmp(line, "XmitPower: ", 11)) {
- int v, i = 0;
- line += 11;
- v = get_dec_u16(line, &i, i+3);
- if (v != -1) {
- ai->config.txPower = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- }
- } else if (!strncmp(line, "WEP: ", 5)) {
- line += 5;
- switch(line[0]) {
- case 's':
- set_auth_type(ai, AUTH_SHAREDKEY);
- break;
- case 'e':
- set_auth_type(ai, AUTH_ENCRYPT);
- break;
- default:
- set_auth_type(ai, AUTH_OPEN);
- break;
- }
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "LongRetryLimit: ", 16)) {
- int v, i = 0;
-
- line += 16;
- v = get_dec_u16(line, &i, 3);
- v = (v<0) ? 0 : ((v>255) ? 255 : v);
- ai->config.longRetryLimit = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "ShortRetryLimit: ", 17)) {
- int v, i = 0;
-
- line += 17;
- v = get_dec_u16(line, &i, 3);
- v = (v<0) ? 0 : ((v>255) ? 255 : v);
- ai->config.shortRetryLimit = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "RTSThreshold: ", 14)) {
- int v, i = 0;
-
- line += 14;
- v = get_dec_u16(line, &i, 4);
- v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
- ai->config.rtsThres = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "TXMSDULifetime: ", 16)) {
- int v, i = 0;
-
- line += 16;
- v = get_dec_u16(line, &i, 5);
- v = (v<0) ? 0 : v;
- ai->config.txLifetime = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "RXMSDULifetime: ", 16)) {
- int v, i = 0;
-
- line += 16;
- v = get_dec_u16(line, &i, 5);
- v = (v<0) ? 0 : v;
- ai->config.rxLifetime = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "TXDiversity: ", 13)) {
- ai->config.txDiversity =
- (line[13]=='l') ? 1 :
- ((line[13]=='r')? 2: 3);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "RXDiversity: ", 13)) {
- ai->config.rxDiversity =
- (line[13]=='l') ? 1 :
- ((line[13]=='r')? 2: 3);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "FragThreshold: ", 15)) {
- int v, i = 0;
-
- line += 15;
- v = get_dec_u16(line, &i, 4);
- v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v);
- v = v & 0xfffe; /* Make sure its even */
- ai->config.fragThresh = cpu_to_le16(v);
- set_bit (FLAG_COMMIT, &ai->flags);
- } else if (!strncmp(line, "Modulation: ", 12)) {
- line += 12;
- switch(*line) {
- case 'd': ai->config.modulation = MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 'c': ai->config.modulation = MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 'm': ai->config.modulation = MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break;
- default: airo_print_warn(ai->dev->name, "Unknown modulation");
- }
- } else if (!strncmp(line, "Preamble: ", 10)) {
- line += 10;
- switch(*line) {
- case 'a': ai->config.preamble = PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 'l': ai->config.preamble = PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break;
- case 's': ai->config.preamble = PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break;
- default: airo_print_warn(ai->dev->name, "Unknown preamble");
- }
- } else {
- airo_print_warn(ai->dev->name, "Couldn't figure out %s", line);
- }
- while (line[0] && line[0] != '\n') line++;
- if (line[0]) line++;
- }
- airo_config_commit(dev, NULL, NULL, NULL);
-}
-
-static const char *get_rmode(__le16 mode)
-{
- switch(mode & RXMODE_MASK) {
- case RXMODE_RFMON: return "rfmon";
- case RXMODE_RFMON_ANYBSS: return "yna (any) bss rfmon";
- case RXMODE_LANMON: return "lanmon";
- }
- return "ESS";
-}
-
-static int proc_config_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i;
- __le16 mode;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- if ((data->wbuffer = kzalloc(2048, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->maxwritelen = 2048;
- data->on_close = proc_config_on_close;
-
- readConfigRid(ai, 1);
-
- mode = ai->config.opmode & MODE_CFG_MASK;
- i = sprintf(data->rbuffer,
- "Mode: %s\n"
- "Radio: %s\n"
- "NodeName: %-16s\n"
- "PowerMode: %s\n"
- "DataRates: %d %d %d %d %d %d %d %d\n"
- "Channel: %d\n"
- "XmitPower: %d\n",
- mode == MODE_STA_IBSS ? "adhoc" :
- mode == MODE_STA_ESS ? get_rmode(ai->config.rmode):
- mode == MODE_AP ? "AP" :
- mode == MODE_AP_RPTR ? "AP RPTR" : "Error",
- test_bit(FLAG_RADIO_OFF, &ai->flags) ? "off" : "on",
- ai->config.nodeName,
- ai->config.powerSaveMode == POWERSAVE_CAM ? "CAM" :
- ai->config.powerSaveMode == POWERSAVE_PSP ? "PSP" :
- ai->config.powerSaveMode == POWERSAVE_PSPCAM ? "PSPCAM" :
- "Error",
- (int)ai->config.rates[0],
- (int)ai->config.rates[1],
- (int)ai->config.rates[2],
- (int)ai->config.rates[3],
- (int)ai->config.rates[4],
- (int)ai->config.rates[5],
- (int)ai->config.rates[6],
- (int)ai->config.rates[7],
- le16_to_cpu(ai->config.channelSet),
- le16_to_cpu(ai->config.txPower)
- );
- sprintf(data->rbuffer + i,
- "LongRetryLimit: %d\n"
- "ShortRetryLimit: %d\n"
- "RTSThreshold: %d\n"
- "TXMSDULifetime: %d\n"
- "RXMSDULifetime: %d\n"
- "TXDiversity: %s\n"
- "RXDiversity: %s\n"
- "FragThreshold: %d\n"
- "WEP: %s\n"
- "Modulation: %s\n"
- "Preamble: %s\n",
- le16_to_cpu(ai->config.longRetryLimit),
- le16_to_cpu(ai->config.shortRetryLimit),
- le16_to_cpu(ai->config.rtsThres),
- le16_to_cpu(ai->config.txLifetime),
- le16_to_cpu(ai->config.rxLifetime),
- ai->config.txDiversity == 1 ? "left" :
- ai->config.txDiversity == 2 ? "right" : "both",
- ai->config.rxDiversity == 1 ? "left" :
- ai->config.rxDiversity == 2 ? "right" : "both",
- le16_to_cpu(ai->config.fragThresh),
- ai->config.authType == AUTH_ENCRYPT ? "encrypt" :
- ai->config.authType == AUTH_SHAREDKEY ? "shared" : "open",
- ai->config.modulation == MOD_DEFAULT ? "default" :
- ai->config.modulation == MOD_CCK ? "cck" :
- ai->config.modulation == MOD_MOK ? "mok" : "error",
- ai->config.preamble == PREAMBLE_AUTO ? "auto" :
- ai->config.preamble == PREAMBLE_LONG ? "long" :
- ai->config.preamble == PREAMBLE_SHORT ? "short" : "error"
- );
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static void proc_SSID_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- SsidRid SSID_rid;
- int i;
- char *p = data->wbuffer;
- char *end = p + data->writelen;
-
- if (!data->writelen)
- return;
-
- *end = '\n'; /* sentinel; we have space for it */
-
- memset(&SSID_rid, 0, sizeof(SSID_rid));
-
- for (i = 0; i < 3 && p < end; i++) {
- int j = 0;
- /* copy up to 32 characters from this line */
- while (*p != '\n' && j < 32)
- SSID_rid.ssids[i].ssid[j++] = *p++;
- if (j == 0)
- break;
- SSID_rid.ssids[i].len = cpu_to_le16(j);
- /* skip to the beginning of the next line */
- while (*p++ != '\n')
- ;
- }
- if (i)
- SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
- disable_MAC(ai, 1);
- writeSsidRid(ai, &SSID_rid, 1);
- enable_MAC(ai, 1);
-}
-
-static void proc_APList_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- APListRid *APList_rid = &ai->APList;
- int i;
-
- if (!data->writelen) return;
-
- memset(APList_rid, 0, sizeof(*APList_rid));
- APList_rid->len = cpu_to_le16(sizeof(*APList_rid));
-
- for (i = 0; i < 4 && data->writelen >= (i + 1) * 6 * 3; i++)
- mac_pton(data->wbuffer + i * 6 * 3, APList_rid->ap[i]);
-
- disable_MAC(ai, 1);
- writeAPListRid(ai, APList_rid, 1);
- enable_MAC(ai, 1);
-}
-
-/* This function wraps PC4500_writerid with a MAC disable */
-static int do_writerid(struct airo_info *ai, u16 rid, const void *rid_data,
- int len, int dummy)
-{
- int rc;
-
- disable_MAC(ai, 1);
- rc = PC4500_writerid(ai, rid, rid_data, len, 1);
- enable_MAC(ai, 1);
- return rc;
-}
-
-/* Returns the WEP key at the specified index, or -1 if that key does
- * not exist. The buffer is assumed to be at least 16 bytes in length.
- */
-static int get_wep_key(struct airo_info *ai, u16 index, char *buf, u16 buflen)
-{
- WepKeyRid wkr;
- int rc;
- __le16 lastindex;
-
- rc = readWepKeyRid(ai, &wkr, 1, 1);
- if (rc != SUCCESS)
- return -1;
- do {
- lastindex = wkr.kindex;
- if (le16_to_cpu(wkr.kindex) == index) {
- int klen = min_t(int, buflen, le16_to_cpu(wkr.klen));
- memcpy(buf, wkr.key, klen);
- return klen;
- }
- rc = readWepKeyRid(ai, &wkr, 0, 1);
- if (rc != SUCCESS)
- return -1;
- } while (lastindex != wkr.kindex);
- return -1;
-}
-
-static int get_wep_tx_idx(struct airo_info *ai)
-{
- WepKeyRid wkr;
- int rc;
- __le16 lastindex;
-
- rc = readWepKeyRid(ai, &wkr, 1, 1);
- if (rc != SUCCESS)
- return -1;
- do {
- lastindex = wkr.kindex;
- if (wkr.kindex == cpu_to_le16(0xffff))
- return wkr.mac[0];
- rc = readWepKeyRid(ai, &wkr, 0, 1);
- if (rc != SUCCESS)
- return -1;
- } while (lastindex != wkr.kindex);
- return -1;
-}
-
-static int set_wep_key(struct airo_info *ai, u16 index, const u8 *key,
- u16 keylen, int perm, int lock)
-{
- static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
- WepKeyRid wkr;
- int rc;
-
- if (WARN_ON(keylen == 0))
- return -1;
-
- memset(&wkr, 0, sizeof(wkr));
- wkr.len = cpu_to_le16(sizeof(wkr));
- wkr.kindex = cpu_to_le16(index);
- wkr.klen = cpu_to_le16(keylen);
- memcpy(wkr.key, key, keylen);
- memcpy(wkr.mac, macaddr, ETH_ALEN);
-
- if (perm) disable_MAC(ai, lock);
- rc = writeWepKeyRid(ai, &wkr, perm, lock);
- if (perm) enable_MAC(ai, lock);
- return rc;
-}
-
-static int set_wep_tx_idx(struct airo_info *ai, u16 index, int perm, int lock)
-{
- WepKeyRid wkr;
- int rc;
-
- memset(&wkr, 0, sizeof(wkr));
- wkr.len = cpu_to_le16(sizeof(wkr));
- wkr.kindex = cpu_to_le16(0xffff);
- wkr.mac[0] = (char)index;
-
- if (perm) {
- ai->defindex = (char)index;
- disable_MAC(ai, lock);
- }
-
- rc = writeWepKeyRid(ai, &wkr, perm, lock);
-
- if (perm)
- enable_MAC(ai, lock);
- return rc;
-}
-
-static void proc_wepkey_on_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i, rc;
- u8 key[16];
- u16 index = 0;
- int j = 0;
-
- memset(key, 0, sizeof(key));
-
- data = file->private_data;
- if (!data->writelen) return;
-
- if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
- (data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
- index = data->wbuffer[0] - '0';
- if (data->wbuffer[1] == '\n') {
- rc = set_wep_tx_idx(ai, index, 1, 1);
- if (rc < 0) {
- airo_print_err(ai->dev->name, "failed to set "
- "WEP transmit index to %d: %d.",
- index, rc);
- }
- return;
- }
- j = 2;
- } else {
- airo_print_err(ai->dev->name, "WepKey passed invalid key index");
- return;
- }
-
- for (i = 0; i < 16*3 && data->wbuffer[i+j]; i++) {
- int val;
-
- if (i % 3 == 2)
- continue;
-
- val = hex_to_bin(data->wbuffer[i+j]);
- if (val < 0) {
- airo_print_err(ai->dev->name, "WebKey passed invalid key hex");
- return;
- }
- switch(i%3) {
- case 0:
- key[i/3] = (u8)val << 4;
- break;
- case 1:
- key[i/3] |= (u8)val;
- break;
- }
- }
-
- rc = set_wep_key(ai, index, key, i/3, 1, 1);
- if (rc < 0) {
- airo_print_err(ai->dev->name, "failed to set WEP key at index "
- "%d: %d.", index, rc);
- }
-}
-
-static int proc_wepkey_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- char *ptr;
- WepKeyRid wkr;
- __le16 lastindex;
- int j = 0;
- int rc;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- memset(&wkr, 0, sizeof(wkr));
- data = file->private_data;
- if ((data->rbuffer = kzalloc(180, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 80;
- if ((data->wbuffer = kzalloc(80, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->on_close = proc_wepkey_on_close;
-
- ptr = data->rbuffer;
- strcpy(ptr, "No wep keys\n");
- rc = readWepKeyRid(ai, &wkr, 1, 1);
- if (rc == SUCCESS) do {
- lastindex = wkr.kindex;
- if (wkr.kindex == cpu_to_le16(0xffff)) {
- j += sprintf(ptr+j, "Tx key = %d\n",
- (int)wkr.mac[0]);
- } else {
- j += sprintf(ptr+j, "Key %d set with length = %d\n",
- le16_to_cpu(wkr.kindex),
- le16_to_cpu(wkr.klen));
- }
- readWepKeyRid(ai, &wkr, 0, 1);
- } while ((lastindex != wkr.kindex) && (j < 180-30));
-
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_SSID_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i;
- char *ptr;
- SsidRid SSID_rid;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 33*3;
- /* allocate maxwritelen + 1; we'll want a sentinel */
- if ((data->wbuffer = kzalloc(33*3 + 1, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->on_close = proc_SSID_on_close;
-
- readSsidRid(ai, &SSID_rid);
- ptr = data->rbuffer;
- for (i = 0; i < 3; i++) {
- int j;
- size_t len = le16_to_cpu(SSID_rid.ssids[i].len);
- if (!len)
- break;
- if (len > 32)
- len = 32;
- for (j = 0; j < len && SSID_rid.ssids[i].ssid[j]; j++)
- *ptr++ = SSID_rid.ssids[i].ssid[j];
- *ptr++ = '\n';
- }
- *ptr = '\0';
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_APList_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- int i;
- char *ptr;
- APListRid *APList_rid = &ai->APList;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(104, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 4*6*3;
- if ((data->wbuffer = kzalloc(data->maxwritelen, GFP_KERNEL)) == NULL) {
- kfree (data->rbuffer);
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->on_close = proc_APList_on_close;
-
- ptr = data->rbuffer;
- for (i = 0; i < 4; i++) {
-// We end when we find a zero MAC
- if (!*(int*)APList_rid->ap[i] &&
- !*(int*)&APList_rid->ap[i][2]) break;
- ptr += sprintf(ptr, "%pM\n", APList_rid->ap[i]);
- }
- if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
-
- *ptr = '\0';
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_BSSList_open(struct inode *inode, struct file *file)
-{
- struct proc_data *data;
- struct net_device *dev = pde_data(inode);
- struct airo_info *ai = dev->ml_priv;
- char *ptr;
- BSSListRid BSSList_rid;
- int rc;
- /* If doLoseSync is not 1, we won't do a Lose Sync */
- int doLoseSync = -1;
-
- if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL)
- return -ENOMEM;
- data = file->private_data;
- if ((data->rbuffer = kmalloc(1024, GFP_KERNEL)) == NULL) {
- kfree (file->private_data);
- return -ENOMEM;
- }
- data->writelen = 0;
- data->maxwritelen = 0;
- data->wbuffer = NULL;
- data->on_close = NULL;
-
- if (file->f_mode & FMODE_WRITE) {
- if (!(file->f_mode & FMODE_READ)) {
- Cmd cmd;
- Resp rsp;
-
- if (ai->flags & FLAG_RADIO_MASK) {
- kfree(data->rbuffer);
- kfree(file->private_data);
- return -ENETDOWN;
- }
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LISTBSS;
- if (down_interruptible(&ai->sem)) {
- kfree(data->rbuffer);
- kfree(file->private_data);
- return -ERESTARTSYS;
- }
- issuecommand(ai, &cmd, &rsp, true);
- up(&ai->sem);
- data->readlen = 0;
- return 0;
- }
- doLoseSync = 1;
- }
- ptr = data->rbuffer;
- /* There is a race condition here if there are concurrent opens.
- Since it is a rare condition, we'll just live with it, otherwise
- we have to add a spin lock... */
- rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
- while (rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) {
- ptr += sprintf(ptr, "%pM %.*s rssi = %d",
- BSSList_rid.bssid,
- (int)BSSList_rid.ssidLen,
- BSSList_rid.ssid,
- le16_to_cpu(BSSList_rid.dBm));
- ptr += sprintf(ptr, " channel = %d %s %s %s %s\n",
- le16_to_cpu(BSSList_rid.dsChannel),
- BSSList_rid.cap & CAP_ESS ? "ESS" : "",
- BSSList_rid.cap & CAP_IBSS ? "adhoc" : "",
- BSSList_rid.cap & CAP_PRIVACY ? "wep" : "",
- BSSList_rid.cap & CAP_SHORTHDR ? "shorthdr" : "");
- rc = readBSSListRid(ai, 0, &BSSList_rid);
- }
- *ptr = '\0';
- data->readlen = strlen(data->rbuffer);
- return 0;
-}
-
-static int proc_close(struct inode *inode, struct file *file)
-{
- struct proc_data *data = file->private_data;
-
- if (data->on_close != NULL)
- data->on_close(inode, file);
- kfree(data->rbuffer);
- kfree(data->wbuffer);
- kfree(data);
- return 0;
-}
-
-/* Since the card doesn't automatically switch to the right WEP mode,
- we will make it do it. If the card isn't associated, every secs we
- will switch WEP modes to see if that will help. If the card is
- associated we will check every minute to see if anything has
- changed. */
-static void timer_func(struct net_device *dev)
-{
- struct airo_info *apriv = dev->ml_priv;
-
-/* We don't have a link so try changing the authtype */
- readConfigRid(apriv, 0);
- disable_MAC(apriv, 0);
- switch(apriv->config.authType) {
- case AUTH_ENCRYPT:
-/* So drop to OPEN */
- apriv->config.authType = AUTH_OPEN;
- break;
- case AUTH_SHAREDKEY:
- if (apriv->keyindex < auto_wep) {
- set_wep_tx_idx(apriv, apriv->keyindex, 0, 0);
- apriv->config.authType = AUTH_SHAREDKEY;
- apriv->keyindex++;
- } else {
- /* Drop to ENCRYPT */
- apriv->keyindex = 0;
- set_wep_tx_idx(apriv, apriv->defindex, 0, 0);
- apriv->config.authType = AUTH_ENCRYPT;
- }
- break;
- default: /* We'll escalate to SHAREDKEY */
- apriv->config.authType = AUTH_SHAREDKEY;
- }
- set_bit (FLAG_COMMIT, &apriv->flags);
- writeConfigRid(apriv, 0);
- enable_MAC(apriv, 0);
- up(&apriv->sem);
-
-/* Schedule check to see if the change worked */
- clear_bit(JOB_AUTOWEP, &apriv->jobs);
- apriv->expires = RUN_AT(HZ*3);
-}
-
-#ifdef CONFIG_PCI
-static int airo_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *pent)
-{
- struct net_device *dev;
-
- if (pci_enable_device(pdev))
- return -ENODEV;
- pci_set_master(pdev);
-
- if (pdev->device == 0x5000 || pdev->device == 0xa504)
- dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
- else
- dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
- if (!dev) {
- pci_disable_device(pdev);
- return -ENODEV;
- }
-
- pci_set_drvdata(pdev, dev);
- return 0;
-}
-
-static void airo_pci_remove(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
-
- airo_print_info(dev->name, "Unregistering...");
- stop_airo_card(dev, 1);
- pci_disable_device(pdev);
-}
-
-static int __maybe_unused airo_pci_suspend(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
- struct airo_info *ai = dev->ml_priv;
- Cmd cmd;
- Resp rsp;
-
- if (!ai->SSID)
- ai->SSID = kmalloc(sizeof(SsidRid), GFP_KERNEL);
- if (!ai->SSID)
- return -ENOMEM;
- readSsidRid(ai, ai->SSID);
- memset(&cmd, 0, sizeof(cmd));
- /* the lock will be released at the end of the resume callback */
- if (down_interruptible(&ai->sem))
- return -EAGAIN;
- disable_MAC(ai, 0);
- netif_device_detach(dev);
- ai->power = PMSG_SUSPEND;
- cmd.cmd = HOSTSLEEP;
- issuecommand(ai, &cmd, &rsp, true);
-
- device_wakeup_enable(dev_d);
- return 0;
-}
-
-static int __maybe_unused airo_pci_resume(struct device *dev_d)
-{
- struct net_device *dev = dev_get_drvdata(dev_d);
- struct airo_info *ai = dev->ml_priv;
- pci_power_t prev_state = to_pci_dev(dev_d)->current_state;
-
- device_wakeup_disable(dev_d);
-
- if (prev_state != PCI_D1) {
- reset_card(dev, 0);
- mpi_init_descriptors(ai);
- setup_card(ai, dev, 0);
- clear_bit(FLAG_RADIO_OFF, &ai->flags);
- clear_bit(FLAG_PENDING_XMIT, &ai->flags);
- } else {
- OUT4500(ai, EVACK, EV_AWAKEN);
- OUT4500(ai, EVACK, EV_AWAKEN);
- msleep(100);
- }
-
- set_bit(FLAG_COMMIT, &ai->flags);
- disable_MAC(ai, 0);
- msleep(200);
- if (ai->SSID) {
- writeSsidRid(ai, ai->SSID, 0);
- kfree(ai->SSID);
- ai->SSID = NULL;
- }
- writeAPListRid(ai, &ai->APList, 0);
- writeConfigRid(ai, 0);
- enable_MAC(ai, 0);
- ai->power = PMSG_ON;
- netif_device_attach(dev);
- netif_wake_queue(dev);
- enable_interrupts(ai);
- up(&ai->sem);
- return 0;
-}
-#endif
-
-static int __init airo_init_module(void)
-{
- int i;
-
- proc_kuid = make_kuid(&init_user_ns, proc_uid);
- proc_kgid = make_kgid(&init_user_ns, proc_gid);
- if (!uid_valid(proc_kuid) || !gid_valid(proc_kgid))
- return -EINVAL;
-
- airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL);
-
- if (airo_entry)
- proc_set_user(airo_entry, proc_kuid, proc_kgid);
-
- for (i = 0; i < 4 && io[i] && irq[i]; i++) {
- airo_print_info("", "Trying to configure ISA adapter at irq=%d "
- "io = 0x%x", irq[i], io[i]);
- if (init_airo_card(irq[i], io[i], 0, NULL)) {
- /* do nothing */ ;
- }
- }
-
-#ifdef CONFIG_PCI
- airo_print_info("", "Probing for PCI adapters");
- i = pci_register_driver(&airo_driver);
- airo_print_info("", "Finished probing for PCI adapters");
-
- if (i) {
- remove_proc_entry("driver/aironet", NULL);
- return i;
- }
-#endif
-
- /* Always exit with success, as we are a library module
- * as well as a driver module
- */
- return 0;
-}
-
-static void __exit airo_cleanup_module(void)
-{
- struct airo_info *ai;
- while (!list_empty(&airo_devices)) {
- ai = list_entry(airo_devices.next, struct airo_info, dev_list);
- airo_print_info(ai->dev->name, "Unregistering...");
- stop_airo_card(ai->dev, 1);
- }
-#ifdef CONFIG_PCI
- pci_unregister_driver(&airo_driver);
-#endif
- remove_proc_entry("driver/aironet", NULL);
-}
-
-/*
- * Initial Wireless Extension code for Aironet driver by :
- * Jean Tourrilhes <[email protected]> - HPL - 17 November 00
- * Conversion to new driver API by :
- * Jean Tourrilhes <[email protected]> - HPL - 26 March 02
- * Javier also did a good amount of work here, adding some new extensions
- * and fixing my code. Let's just say that without him this code just
- * would not work at all... - Jean II
- */
-
-static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi)
-{
- if (!rssi_rid)
- return 0;
-
- return (0x100 - rssi_rid[rssi].rssidBm);
-}
-
-static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm)
-{
- int i;
-
- if (!rssi_rid)
- return 0;
-
- for (i = 0; i < 256; i++)
- if (rssi_rid[i].rssidBm == dbm)
- return rssi_rid[i].rssipct;
-
- return 0;
-}
-
-
-static int airo_get_quality (StatusRid *status_rid, CapabilityRid *cap_rid)
-{
- int quality = 0;
- u16 sq;
-
- if ((status_rid->mode & cpu_to_le16(0x3f)) != cpu_to_le16(0x3f))
- return 0;
-
- if (!(cap_rid->hardCap & cpu_to_le16(8)))
- return 0;
-
- sq = le16_to_cpu(status_rid->signalQuality);
- if (memcmp(cap_rid->prodName, "350", 3))
- if (sq > 0x20)
- quality = 0;
- else
- quality = 0x20 - sq;
- else
- if (sq > 0xb0)
- quality = 0;
- else if (sq < 0x10)
- quality = 0xa0;
- else
- quality = 0xb0 - sq;
- return quality;
-}
-
-#define airo_get_max_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x20 : 0xa0)
-#define airo_get_avg_quality(cap_rid) (memcmp((cap_rid)->prodName, "350", 3) ? 0x10 : 0x50)
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get protocol name
- */
-static int airo_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *cwrq,
- char *extra)
-{
- strcpy(cwrq->name, "IEEE 802.11-DS");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set frequency
- */
-static int airo_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *fwrq = &wrqu->freq;
- struct airo_info *local = dev->ml_priv;
- int rc = -EINPROGRESS; /* Call commit handler */
-
- /* If setting by frequency, convert to a channel */
- if (fwrq->e == 1) {
- int f = fwrq->m / 100000;
-
- /* Hack to fall through... */
- fwrq->e = 0;
- fwrq->m = ieee80211_frequency_to_channel(f);
- }
- /* Setting by channel number */
- if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0)
- rc = -EOPNOTSUPP;
- else {
- int channel = fwrq->m;
- /* We should do a better check than that,
- * based on the card capability !!! */
- if ((channel < 1) || (channel > 14)) {
- airo_print_dbg(dev->name, "New channel value of %d is invalid!",
- fwrq->m);
- rc = -EINVAL;
- } else {
- readConfigRid(local, 1);
- /* Yes ! We can set it !!! */
- local->config.channelSet = cpu_to_le16(channel);
- set_bit (FLAG_COMMIT, &local->flags);
- }
- }
- return rc;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get frequency
- */
-static int airo_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *fwrq = &wrqu->freq;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
- int ch;
-
- readConfigRid(local, 1);
- if ((local->config.opmode & MODE_CFG_MASK) == MODE_STA_ESS)
- status_rid.channel = local->config.channelSet;
- else
- readStatusRid(local, &status_rid, 1);
-
- ch = le16_to_cpu(status_rid.channel);
- if ((ch > 0) && (ch < 15)) {
- fwrq->m = 100000 *
- ieee80211_channel_to_frequency(ch, NL80211_BAND_2GHZ);
- fwrq->e = 1;
- } else {
- fwrq->m = ch;
- fwrq->e = 0;
- }
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set ESSID
- */
-static int airo_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->essid;
- struct airo_info *local = dev->ml_priv;
- SsidRid SSID_rid; /* SSIDs */
-
- /* Reload the list of current SSID */
- readSsidRid(local, &SSID_rid);
-
- /* Check if we asked for `any' */
- if (dwrq->flags == 0) {
- /* Just send an empty SSID list */
- memset(&SSID_rid, 0, sizeof(SSID_rid));
- } else {
- unsigned index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
-
- /* Check the size of the string */
- if (dwrq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG ;
-
- /* Check if index is valid */
- if (index >= ARRAY_SIZE(SSID_rid.ssids))
- return -EINVAL;
-
- /* Set the SSID */
- memset(SSID_rid.ssids[index].ssid, 0,
- sizeof(SSID_rid.ssids[index].ssid));
- memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
- SSID_rid.ssids[index].len = cpu_to_le16(dwrq->length);
- }
- SSID_rid.len = cpu_to_le16(sizeof(SSID_rid));
- /* Write it to the card */
- disable_MAC(local, 1);
- writeSsidRid(local, &SSID_rid, 1);
- enable_MAC(local, 1);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get ESSID
- */
-static int airo_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->essid;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
-
- readStatusRid(local, &status_rid, 1);
-
- /* Note : if dwrq->flags != 0, we should
- * get the relevant SSID from the SSID list... */
-
- /* Get the current SSID */
- memcpy(extra, status_rid.SSID, le16_to_cpu(status_rid.SSIDlen));
- /* If none, we may want to get the one that was set */
-
- /* Push it out ! */
- dwrq->length = le16_to_cpu(status_rid.SSIDlen);
- dwrq->flags = 1; /* active */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set AP address
- */
-static int airo_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *awrq = &wrqu->ap_addr;
- struct airo_info *local = dev->ml_priv;
- Cmd cmd;
- Resp rsp;
- APListRid *APList_rid = &local->APList;
-
- if (awrq->sa_family != ARPHRD_ETHER)
- return -EINVAL;
- else if (is_broadcast_ether_addr(awrq->sa_data) ||
- is_zero_ether_addr(awrq->sa_data)) {
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LOSE_SYNC;
- if (down_interruptible(&local->sem))
- return -ERESTARTSYS;
- issuecommand(local, &cmd, &rsp, true);
- up(&local->sem);
- } else {
- memset(APList_rid, 0, sizeof(*APList_rid));
- APList_rid->len = cpu_to_le16(sizeof(*APList_rid));
- memcpy(APList_rid->ap[0], awrq->sa_data, ETH_ALEN);
- disable_MAC(local, 1);
- writeAPListRid(local, APList_rid, 1);
- enable_MAC(local, 1);
- }
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get AP address
- */
-static int airo_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *awrq = &wrqu->ap_addr;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
-
- readStatusRid(local, &status_rid, 1);
-
- /* Tentative. This seems to work, wow, I'm lucky !!! */
- memcpy(awrq->sa_data, status_rid.bssid[0], ETH_ALEN);
- awrq->sa_family = ARPHRD_ETHER;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Nickname
- */
-static int airo_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
-
- /* Check the size of the string */
- if (dwrq->length > 16) {
- return -E2BIG;
- }
- readConfigRid(local, 1);
- memset(local->config.nodeName, 0, sizeof(local->config.nodeName));
- memcpy(local->config.nodeName, extra, dwrq->length);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Nickname
- */
-static int airo_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- strncpy(extra, local->config.nodeName, 16);
- extra[16] = '\0';
- dwrq->length = strlen(extra);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Bit-Rate
- */
-static int airo_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->bitrate;
- struct airo_info *local = dev->ml_priv;
- CapabilityRid cap_rid; /* Card capability info */
- u8 brate = 0;
- int i;
-
- /* First : get a valid bit rate value */
- readCapabilityRid(local, &cap_rid, 1);
-
- /* Which type of value ? */
- if ((vwrq->value < 8) && (vwrq->value >= 0)) {
- /* Setting by rate index */
- /* Find value in the magic rate table */
- brate = cap_rid.supportedRates[vwrq->value];
- } else {
- /* Setting by frequency value */
- u8 normvalue = (u8) (vwrq->value/500000);
-
- /* Check if rate is valid */
- for (i = 0 ; i < 8 ; i++) {
- if (normvalue == cap_rid.supportedRates[i]) {
- brate = normvalue;
- break;
- }
- }
- }
- /* -1 designed the max rate (mostly auto mode) */
- if (vwrq->value == -1) {
- /* Get the highest available rate */
- for (i = 0 ; i < 8 ; i++) {
- if (cap_rid.supportedRates[i] == 0)
- break;
- }
- if (i != 0)
- brate = cap_rid.supportedRates[i - 1];
- }
- /* Check that it is valid */
- if (brate == 0) {
- return -EINVAL;
- }
-
- readConfigRid(local, 1);
- /* Now, check if we want a fixed or auto value */
- if (vwrq->fixed == 0) {
- /* Fill all the rates up to this max rate */
- memset(local->config.rates, 0, 8);
- for (i = 0 ; i < 8 ; i++) {
- local->config.rates[i] = cap_rid.supportedRates[i];
- if (local->config.rates[i] == brate)
- break;
- }
- } else {
- /* Fixed mode */
- /* One rate, fixed */
- memset(local->config.rates, 0, 8);
- local->config.rates[0] = brate;
- }
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Bit-Rate
- */
-static int airo_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->bitrate;
- struct airo_info *local = dev->ml_priv;
- StatusRid status_rid; /* Card status info */
- int ret;
-
- ret = readStatusRid(local, &status_rid, 1);
- if (ret)
- return -EBUSY;
-
- vwrq->value = le16_to_cpu(status_rid.currentXmitRate) * 500000;
- /* If more than one rate, set auto */
- readConfigRid(local, 1);
- vwrq->fixed = (local->config.rates[1] == 0);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set RTS threshold
- */
-static int airo_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->rts;
- struct airo_info *local = dev->ml_priv;
- int rthr = vwrq->value;
-
- if (vwrq->disabled)
- rthr = AIRO_DEF_MTU;
- if ((rthr < 0) || (rthr > AIRO_DEF_MTU)) {
- return -EINVAL;
- }
- readConfigRid(local, 1);
- local->config.rtsThres = cpu_to_le16(rthr);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get RTS threshold
- */
-static int airo_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->rts;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.rtsThres);
- vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Fragmentation threshold
- */
-static int airo_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->frag;
- struct airo_info *local = dev->ml_priv;
- int fthr = vwrq->value;
-
- if (vwrq->disabled)
- fthr = AIRO_DEF_MTU;
- if ((fthr < 256) || (fthr > AIRO_DEF_MTU)) {
- return -EINVAL;
- }
- fthr &= ~0x1; /* Get an even value - is it really needed ??? */
- readConfigRid(local, 1);
- local->config.fragThresh = cpu_to_le16(fthr);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Fragmentation threshold
- */
-static int airo_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->frag;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.fragThresh);
- vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Mode of Operation
- */
-static int airo_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *uwrq,
- char *extra)
-{
- __u32 mode = uwrq->mode;
- struct airo_info *local = dev->ml_priv;
- int reset = 0;
-
- readConfigRid(local, 1);
- if (sniffing_mode(local))
- reset = 1;
-
- switch (mode) {
- case IW_MODE_ADHOC:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_STA_IBSS;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_INFRA:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_STA_ESS;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_MASTER:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_AP;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_REPEAT:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_AP_RPTR;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.scanMode = SCANMODE_ACTIVE;
- clear_bit (FLAG_802_11, &local->flags);
- break;
- case IW_MODE_MONITOR:
- local->config.opmode &= ~MODE_CFG_MASK;
- local->config.opmode |= MODE_STA_ESS;
- local->config.rmode &= ~RXMODE_FULL_MASK;
- local->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER;
- local->config.scanMode = SCANMODE_PASSIVE;
- set_bit (FLAG_802_11, &local->flags);
- break;
- default:
- return -EINVAL;
- }
- if (reset)
- set_bit (FLAG_RESET, &local->flags);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Mode of Operation
- */
-static int airo_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *uwrq,
- char *extra)
-{
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- /* If not managed, assume it's ad-hoc */
- switch (local->config.opmode & MODE_CFG_MASK) {
- case MODE_STA_ESS:
- uwrq->mode = IW_MODE_INFRA;
- break;
- case MODE_AP:
- uwrq->mode = IW_MODE_MASTER;
- break;
- case MODE_AP_RPTR:
- uwrq->mode = IW_MODE_REPEAT;
- break;
- default:
- uwrq->mode = IW_MODE_ADHOC;
- }
-
- return 0;
-}
-
-static inline int valid_index(struct airo_info *ai, int index)
-{
- return (index >= 0) && (index <= ai->max_wep_idx);
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Encryption Key
- */
-static int airo_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->encoding;
- struct airo_info *local = dev->ml_priv;
- int perm = (dwrq->flags & IW_ENCODE_TEMP ? 0 : 1);
- __le16 currentAuthType = local->config.authType;
- int rc = 0;
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- /* Basic checking: do we have a key to set ?
- * Note : with the new API, it's impossible to get a NULL pointer.
- * Therefore, we need to check a key size == 0 instead.
- * New version of iwconfig properly set the IW_ENCODE_NOKEY flag
- * when no key is present (only change flags), but older versions
- * don't do it. - Jean II */
- if (dwrq->length > 0) {
- wep_key_t key;
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- int current_index;
-
- /* Check the size of the key */
- if (dwrq->length > MAX_KEY_SIZE) {
- return -EINVAL;
- }
-
- current_index = get_wep_tx_idx(local);
- if (current_index < 0)
- current_index = 0;
-
- /* Check the index (none -> use current) */
- if (!valid_index(local, index))
- index = current_index;
-
- /* Set the length */
- if (dwrq->length > MIN_KEY_SIZE)
- key.len = MAX_KEY_SIZE;
- else
- key.len = MIN_KEY_SIZE;
- /* Check if the key is not marked as invalid */
- if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
- /* Cleanup */
- memset(key.key, 0, MAX_KEY_SIZE);
- /* Copy the key in the driver */
- memcpy(key.key, extra, dwrq->length);
- /* Send the key to the card */
- rc = set_wep_key(local, index, key.key, key.len, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set"
- " WEP key at index %d: %d.",
- index, rc);
- return rc;
- }
- }
- /* WE specify that if a valid key is set, encryption
- * should be enabled (user may turn it off later)
- * This is also how "iwconfig ethX key on" works */
- if ((index == current_index) && (key.len > 0) &&
- (local->config.authType == AUTH_OPEN))
- set_auth_type(local, AUTH_ENCRYPT);
- } else {
- /* Do we want to just set the transmit key index ? */
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- if (valid_index(local, index)) {
- rc = set_wep_tx_idx(local, index, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set"
- " WEP transmit index to %d: %d.",
- index, rc);
- return rc;
- }
- } else {
- /* Don't complain if only change the mode */
- if (!(dwrq->flags & IW_ENCODE_MODE))
- return -EINVAL;
- }
- }
- /* Read the flags */
- if (dwrq->flags & IW_ENCODE_DISABLED)
- set_auth_type(local, AUTH_OPEN); /* disable encryption */
- if (dwrq->flags & IW_ENCODE_RESTRICTED)
- set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */
- if (dwrq->flags & IW_ENCODE_OPEN)
- set_auth_type(local, AUTH_ENCRYPT); /* Only Wep */
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Encryption Key
- */
-static int airo_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->encoding;
- struct airo_info *local = dev->ml_priv;
- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
- int wep_key_len;
- u8 buf[16];
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- /* Check encryption mode */
- switch(local->config.authType) {
- case AUTH_ENCRYPT:
- dwrq->flags = IW_ENCODE_OPEN;
- break;
- case AUTH_SHAREDKEY:
- dwrq->flags = IW_ENCODE_RESTRICTED;
- break;
- default:
- case AUTH_OPEN:
- dwrq->flags = IW_ENCODE_DISABLED;
- break;
- }
- /* We can't return the key, so set the proper flag and return zero */
- dwrq->flags |= IW_ENCODE_NOKEY;
- memset(extra, 0, 16);
-
- /* Which key do we want ? -1 -> tx index */
- if (!valid_index(local, index)) {
- index = get_wep_tx_idx(local);
- if (index < 0)
- index = 0;
- }
- dwrq->flags |= index + 1;
-
- /* Copy the key to the user buffer */
- wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf));
- if (wep_key_len < 0) {
- dwrq->length = 0;
- } else {
- dwrq->length = wep_key_len;
- memcpy(extra, buf, dwrq->length);
- }
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set extended Encryption parameters
- */
-static int airo_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int perm = (encoding->flags & IW_ENCODE_TEMP ? 0 : 1);
- __le16 currentAuthType = local->config.authType;
- int idx, key_len, alg = ext->alg, set_key = 1, rc;
- wep_key_t key;
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- /* Determine and validate the key index */
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (!valid_index(local, idx - 1))
- return -EINVAL;
- idx--;
- } else {
- idx = get_wep_tx_idx(local);
- if (idx < 0)
- idx = 0;
- }
-
- if (encoding->flags & IW_ENCODE_DISABLED)
- alg = IW_ENCODE_ALG_NONE;
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- /* Only set transmit key index here, actual
- * key is set below if needed.
- */
- rc = set_wep_tx_idx(local, idx, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set "
- "WEP transmit index to %d: %d.",
- idx, rc);
- return rc;
- }
- set_key = ext->key_len > 0 ? 1 : 0;
- }
-
- if (set_key) {
- /* Set the requested key first */
- memset(key.key, 0, MAX_KEY_SIZE);
- switch (alg) {
- case IW_ENCODE_ALG_NONE:
- key.len = 0;
- break;
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len > MIN_KEY_SIZE) {
- key.len = MAX_KEY_SIZE;
- } else if (ext->key_len > 0) {
- key.len = MIN_KEY_SIZE;
- } else {
- return -EINVAL;
- }
- key_len = min (ext->key_len, key.len);
- memcpy(key.key, ext->key, key_len);
- break;
- default:
- return -EINVAL;
- }
- if (key.len == 0) {
- rc = set_wep_tx_idx(local, idx, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name,
- "failed to set WEP transmit index to %d: %d.",
- idx, rc);
- return rc;
- }
- } else {
- rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name,
- "failed to set WEP key at index %d: %d.",
- idx, rc);
- return rc;
- }
- }
- }
-
- /* Read the flags */
- if (encoding->flags & IW_ENCODE_DISABLED)
- set_auth_type(local, AUTH_OPEN); /* disable encryption */
- if (encoding->flags & IW_ENCODE_RESTRICTED)
- set_auth_type(local, AUTH_SHAREDKEY); /* Only Both */
- if (encoding->flags & IW_ENCODE_OPEN)
- set_auth_type(local, AUTH_ENCRYPT);
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get extended Encryption parameters
- */
-static int airo_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, max_key_len, wep_key_len;
- u8 buf[16];
-
- if (!local->wep_capable)
- return -EOPNOTSUPP;
-
- readConfigRid(local, 1);
-
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (!valid_index(local, idx - 1))
- return -EINVAL;
- idx--;
- } else {
- idx = get_wep_tx_idx(local);
- if (idx < 0)
- idx = 0;
- }
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- /* Check encryption mode */
- switch(local->config.authType) {
- case AUTH_ENCRYPT:
- encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
- break;
- case AUTH_SHAREDKEY:
- encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED;
- break;
- default:
- case AUTH_OPEN:
- encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED;
- break;
- }
- /* We can't return the key, so set the proper flag and return zero */
- encoding->flags |= IW_ENCODE_NOKEY;
- memset(extra, 0, 16);
-
- /* Copy the key to the user buffer */
- wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf));
- if (wep_key_len < 0) {
- ext->key_len = 0;
- } else {
- ext->key_len = wep_key_len;
- memcpy(extra, buf, ext->key_len);
- }
-
- return 0;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set extended authentication parameters
- */
-static int airo_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_param *param = &wrqu->param;
- __le16 currentAuthType = local->config.authType;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_PRIVACY_INVOKED:
- /*
- * airo does not use these parameters
- */
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- if (param->value) {
- /* Only change auth type if unencrypted */
- if (currentAuthType == AUTH_OPEN)
- set_auth_type(local, AUTH_ENCRYPT);
- } else {
- set_auth_type(local, AUTH_OPEN);
- }
-
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
- break;
-
- case IW_AUTH_80211_AUTH_ALG: {
- if (param->value & IW_AUTH_ALG_SHARED_KEY) {
- set_auth_type(local, AUTH_SHAREDKEY);
- } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
- /* We don't know here if WEP open system or
- * unencrypted mode was requested - so use the
- * last mode (of these two) used last time
- */
- set_auth_type(local, local->last_auth);
- } else
- return -EINVAL;
-
- /* Commit the changes to flags if needed */
- if (local->config.authType != currentAuthType)
- set_bit (FLAG_COMMIT, &local->flags);
- break;
- }
-
- case IW_AUTH_WPA_ENABLED:
- /* Silently accept disable of WPA */
- if (param->value > 0)
- return -EOPNOTSUPP;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return -EINPROGRESS;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get extended authentication parameters
- */
-static int airo_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct airo_info *local = dev->ml_priv;
- struct iw_param *param = &wrqu->param;
- __le16 currentAuthType = local->config.authType;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_DROP_UNENCRYPTED:
- switch (currentAuthType) {
- case AUTH_SHAREDKEY:
- case AUTH_ENCRYPT:
- param->value = 1;
- break;
- default:
- param->value = 0;
- break;
- }
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- switch (currentAuthType) {
- case AUTH_SHAREDKEY:
- param->value = IW_AUTH_ALG_SHARED_KEY;
- break;
- case AUTH_ENCRYPT:
- default:
- param->value = IW_AUTH_ALG_OPEN_SYSTEM;
- break;
- }
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = 0;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Tx-Power
- */
-static int airo_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->txpower;
- struct airo_info *local = dev->ml_priv;
- CapabilityRid cap_rid; /* Card capability info */
- int i;
- int rc = -EINVAL;
- __le16 v = cpu_to_le16(vwrq->value);
-
- readCapabilityRid(local, &cap_rid, 1);
-
- if (vwrq->disabled) {
- set_bit (FLAG_RADIO_OFF, &local->flags);
- set_bit (FLAG_COMMIT, &local->flags);
- return -EINPROGRESS; /* Call commit handler */
- }
- if (vwrq->flags != IW_TXPOW_MWATT) {
- return -EINVAL;
- }
- clear_bit (FLAG_RADIO_OFF, &local->flags);
- for (i = 0; i < 8 && cap_rid.txPowerLevels[i]; i++)
- if (v == cap_rid.txPowerLevels[i]) {
- readConfigRid(local, 1);
- local->config.txPower = v;
- set_bit (FLAG_COMMIT, &local->flags);
- rc = -EINPROGRESS; /* Call commit handler */
- break;
- }
- return rc;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Tx-Power
- */
-static int airo_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->txpower;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.txPower);
- vwrq->fixed = 1; /* No power control */
- vwrq->disabled = test_bit(FLAG_RADIO_OFF, &local->flags);
- vwrq->flags = IW_TXPOW_MWATT;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Retry limits
- */
-static int airo_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->retry;
- struct airo_info *local = dev->ml_priv;
- int rc = -EINVAL;
-
- if (vwrq->disabled) {
- return -EINVAL;
- }
- readConfigRid(local, 1);
- if (vwrq->flags & IW_RETRY_LIMIT) {
- __le16 v = cpu_to_le16(vwrq->value);
- if (vwrq->flags & IW_RETRY_LONG)
- local->config.longRetryLimit = v;
- else if (vwrq->flags & IW_RETRY_SHORT)
- local->config.shortRetryLimit = v;
- else {
- /* No modifier : set both */
- local->config.longRetryLimit = v;
- local->config.shortRetryLimit = v;
- }
- set_bit (FLAG_COMMIT, &local->flags);
- rc = -EINPROGRESS; /* Call commit handler */
- }
- if (vwrq->flags & IW_RETRY_LIFETIME) {
- local->config.txLifetime = cpu_to_le16(vwrq->value / 1024);
- set_bit (FLAG_COMMIT, &local->flags);
- rc = -EINPROGRESS; /* Call commit handler */
- }
- return rc;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Retry limits
- */
-static int airo_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->retry;
- struct airo_info *local = dev->ml_priv;
-
- vwrq->disabled = 0; /* Can't be disabled */
-
- readConfigRid(local, 1);
- /* Note : by default, display the min retry number */
- if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- vwrq->flags = IW_RETRY_LIFETIME;
- vwrq->value = le16_to_cpu(local->config.txLifetime) * 1024;
- } else if ((vwrq->flags & IW_RETRY_LONG)) {
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- vwrq->value = le16_to_cpu(local->config.longRetryLimit);
- } else {
- vwrq->flags = IW_RETRY_LIMIT;
- vwrq->value = le16_to_cpu(local->config.shortRetryLimit);
- if (local->config.shortRetryLimit != local->config.longRetryLimit)
- vwrq->flags |= IW_RETRY_SHORT;
- }
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get range info
- */
-static int airo_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
- struct iw_range *range = (struct iw_range *) extra;
- CapabilityRid cap_rid; /* Card capability info */
- int i;
- int k;
-
- readCapabilityRid(local, &cap_rid, 1);
-
- dwrq->length = sizeof(struct iw_range);
- memset(range, 0, sizeof(*range));
- range->min_nwid = 0x0000;
- range->max_nwid = 0x0000;
- range->num_channels = 14;
- /* Should be based on cap_rid.country to give only
- * what the current card support */
- k = 0;
- for (i = 0; i < 14; i++) {
- range->freq[k].i = i + 1; /* List index */
- range->freq[k].m = 100000 *
- ieee80211_channel_to_frequency(i + 1, NL80211_BAND_2GHZ);
- range->freq[k++].e = 1; /* Values in MHz -> * 10^5 * 10 */
- }
- range->num_frequency = k;
-
- range->sensitivity = 65535;
-
- /* Hum... Should put the right values there */
- if (local->rssi)
- range->max_qual.qual = 100; /* % */
- else
- range->max_qual.qual = airo_get_max_quality(&cap_rid);
- range->max_qual.level = 0x100 - 120; /* -120 dBm */
- range->max_qual.noise = 0x100 - 120; /* -120 dBm */
-
- /* Experimental measurements - boundary 11/5.5 Mb/s */
- /* Note : with or without the (local->rssi), results
- * are somewhat different. - Jean II */
- if (local->rssi) {
- range->avg_qual.qual = 50; /* % */
- range->avg_qual.level = 0x100 - 70; /* -70 dBm */
- } else {
- range->avg_qual.qual = airo_get_avg_quality(&cap_rid);
- range->avg_qual.level = 0x100 - 80; /* -80 dBm */
- }
- range->avg_qual.noise = 0x100 - 85; /* -85 dBm */
-
- for (i = 0 ; i < 8 ; i++) {
- range->bitrate[i] = cap_rid.supportedRates[i] * 500000;
- if (range->bitrate[i] == 0)
- break;
- }
- range->num_bitrates = i;
-
- /* Set an indication of the max TCP throughput
- * in bit/s that we can expect using this interface.
- * May be use for QoS stuff... Jean II */
- if (i > 2)
- range->throughput = 5000 * 1000;
- else
- range->throughput = 1500 * 1000;
-
- range->min_rts = 0;
- range->max_rts = AIRO_DEF_MTU;
- range->min_frag = 256;
- range->max_frag = AIRO_DEF_MTU;
-
- if (cap_rid.softCap & cpu_to_le16(2)) {
- // WEP: RC4 40 bits
- range->encoding_size[0] = 5;
- // RC4 ~128 bits
- if (cap_rid.softCap & cpu_to_le16(0x100)) {
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- } else
- range->num_encoding_sizes = 1;
- range->max_encoding_tokens =
- cap_rid.softCap & cpu_to_le16(0x80) ? 4 : 1;
- } else {
- range->num_encoding_sizes = 0;
- range->max_encoding_tokens = 0;
- }
- range->min_pmp = 0;
- range->max_pmp = 5000000; /* 5 secs */
- range->min_pmt = 0;
- range->max_pmt = 65535 * 1024; /* ??? */
- range->pmp_flags = IW_POWER_PERIOD;
- range->pmt_flags = IW_POWER_TIMEOUT;
- range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
-
- /* Transmit Power - values are in mW */
- for (i = 0 ; i < 8 ; i++) {
- range->txpower[i] = le16_to_cpu(cap_rid.txPowerLevels[i]);
- if (range->txpower[i] == 0)
- break;
- }
- range->num_txpower = i;
- range->txpower_capa = IW_TXPOW_MWATT;
- range->we_version_source = 19;
- range->we_version_compiled = WIRELESS_EXT;
- range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range->retry_flags = IW_RETRY_LIMIT;
- range->r_time_flags = IW_RETRY_LIFETIME;
- range->min_retry = 1;
- range->max_retry = 65535;
- range->min_r_time = 1024;
- range->max_r_time = 65535 * 1024;
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
- range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Power Management
- */
-static int airo_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- if (vwrq->disabled) {
- if (sniffing_mode(local))
- return -EINVAL;
- local->config.powerSaveMode = POWERSAVE_CAM;
- local->config.rmode &= ~RXMODE_MASK;
- local->config.rmode |= RXMODE_BC_MC_ADDR;
- set_bit (FLAG_COMMIT, &local->flags);
- return -EINPROGRESS; /* Call commit handler */
- }
- if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- local->config.fastListenDelay = cpu_to_le16((vwrq->value + 500) / 1024);
- local->config.powerSaveMode = POWERSAVE_PSPCAM;
- set_bit (FLAG_COMMIT, &local->flags);
- } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {
- local->config.fastListenInterval =
- local->config.listenInterval =
- cpu_to_le16((vwrq->value + 500) / 1024);
- local->config.powerSaveMode = POWERSAVE_PSPCAM;
- set_bit (FLAG_COMMIT, &local->flags);
- }
- switch (vwrq->flags & IW_POWER_MODE) {
- case IW_POWER_UNICAST_R:
- if (sniffing_mode(local))
- return -EINVAL;
- local->config.rmode &= ~RXMODE_MASK;
- local->config.rmode |= RXMODE_ADDR;
- set_bit (FLAG_COMMIT, &local->flags);
- break;
- case IW_POWER_ALL_R:
- if (sniffing_mode(local))
- return -EINVAL;
- local->config.rmode &= ~RXMODE_MASK;
- local->config.rmode |= RXMODE_BC_MC_ADDR;
- set_bit (FLAG_COMMIT, &local->flags);
- break;
- case IW_POWER_ON:
- /* This is broken, fixme ;-) */
- break;
- default:
- return -EINVAL;
- }
- // Note : we may want to factor local->need_commit here
- // Note2 : may also want to factor RXMODE_RFMON test
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Power Management
- */
-static int airo_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->power;
- struct airo_info *local = dev->ml_priv;
- __le16 mode;
-
- readConfigRid(local, 1);
- mode = local->config.powerSaveMode;
- if ((vwrq->disabled = (mode == POWERSAVE_CAM)))
- return 0;
- if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- vwrq->value = le16_to_cpu(local->config.fastListenDelay) * 1024;
- vwrq->flags = IW_POWER_TIMEOUT;
- } else {
- vwrq->value = le16_to_cpu(local->config.fastListenInterval) * 1024;
- vwrq->flags = IW_POWER_PERIOD;
- }
- if ((local->config.rmode & RXMODE_MASK) == RXMODE_ADDR)
- vwrq->flags |= IW_POWER_UNICAST_R;
- else
- vwrq->flags |= IW_POWER_ALL_R;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Sensitivity
- */
-static int airo_set_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->sens;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- local->config.rssiThreshold =
- cpu_to_le16(vwrq->disabled ? RSSI_DEFAULT : vwrq->value);
- set_bit (FLAG_COMMIT, &local->flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Sensitivity
- */
-static int airo_get_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *vwrq = &wrqu->sens;
- struct airo_info *local = dev->ml_priv;
-
- readConfigRid(local, 1);
- vwrq->value = le16_to_cpu(local->config.rssiThreshold);
- vwrq->disabled = (vwrq->value == 0);
- vwrq->fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get AP List
- * Note : this is deprecated in favor of IWSCAN
- */
-static int airo_get_aplist(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *local = dev->ml_priv;
- struct sockaddr *address = (struct sockaddr *) extra;
- struct iw_quality *qual;
- BSSListRid BSSList;
- int i;
- int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
-
- qual = kmalloc_array(IW_MAX_AP, sizeof(*qual), GFP_KERNEL);
- if (!qual)
- return -ENOMEM;
-
- for (i = 0; i < IW_MAX_AP; i++) {
- u16 dBm;
- if (readBSSListRid(local, loseSync, &BSSList))
- break;
- loseSync = 0;
- memcpy(address[i].sa_data, BSSList.bssid, ETH_ALEN);
- address[i].sa_family = ARPHRD_ETHER;
- dBm = le16_to_cpu(BSSList.dBm);
- if (local->rssi) {
- qual[i].level = 0x100 - dBm;
- qual[i].qual = airo_dbm_to_pct(local->rssi, dBm);
- qual[i].updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- } else {
- qual[i].level = (dBm + 321) / 2;
- qual[i].qual = 0;
- qual[i].updated = IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- }
- qual[i].noise = local->wstats.qual.noise;
- if (BSSList.index == cpu_to_le16(0xffff))
- break;
- }
- if (!i) {
- StatusRid status_rid; /* Card status info */
- readStatusRid(local, &status_rid, 1);
- for (i = 0;
- i < min(IW_MAX_AP, 4) &&
- (status_rid.bssid[i][0]
- & status_rid.bssid[i][1]
- & status_rid.bssid[i][2]
- & status_rid.bssid[i][3]
- & status_rid.bssid[i][4]
- & status_rid.bssid[i][5])!=0xff &&
- (status_rid.bssid[i][0]
- | status_rid.bssid[i][1]
- | status_rid.bssid[i][2]
- | status_rid.bssid[i][3]
- | status_rid.bssid[i][4]
- | status_rid.bssid[i][5]);
- i++) {
- memcpy(address[i].sa_data,
- status_rid.bssid[i], ETH_ALEN);
- address[i].sa_family = ARPHRD_ETHER;
- }
- } else {
- dwrq->flags = 1; /* Should be define'd */
- memcpy(extra + sizeof(struct sockaddr) * i, qual,
- sizeof(struct iw_quality) * i);
- }
- dwrq->length = i;
-
- kfree(qual);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : Initiate Scan
- */
-static int airo_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct airo_info *ai = dev->ml_priv;
- Cmd cmd;
- Resp rsp;
- int wake = 0;
- APListRid APList_rid_empty;
-
- /* Note : you may have realised that, as this is a SET operation,
- * this is privileged and therefore a normal user can't
- * perform scanning.
- * This is not an error, while the device perform scanning,
- * traffic doesn't flow, so it's a perfect DoS...
- * Jean II */
- if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN;
-
- if (down_interruptible(&ai->sem))
- return -ERESTARTSYS;
-
- /* If there's already a scan in progress, don't
- * trigger another one. */
- if (ai->scan_timeout > 0)
- goto out;
-
- /* Clear APList as it affects scan results */
- memset(&APList_rid_empty, 0, sizeof(APList_rid_empty));
- APList_rid_empty.len = cpu_to_le16(sizeof(APList_rid_empty));
- disable_MAC(ai, 2);
- writeAPListRid(ai, &APList_rid_empty, 0);
- enable_MAC(ai, 0);
-
- /* Initiate a scan command */
- ai->scan_timeout = RUN_AT(3*HZ);
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = CMD_LISTBSS;
- issuecommand(ai, &cmd, &rsp, true);
- wake = 1;
-
-out:
- up(&ai->sem);
- if (wake)
- wake_up_interruptible(&ai->thr_wait);
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Translate scan data returned from the card to a card independent
- * format that the Wireless Tools will understand - Jean II
- */
-static inline char *airo_translate_scan(struct net_device *dev,
- struct iw_request_info *info,
- char *current_ev,
- char *end_buf,
- BSSListRid *bss)
-{
- struct airo_info *ai = dev->ml_priv;
- struct iw_event iwe; /* Temporary buffer */
- __le16 capabilities;
- char * current_val; /* For rates */
- int i;
- char * buf;
- u16 dBm;
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_ADDR_LEN);
-
- /* Other entries will be displayed in the order we give them */
-
- /* Add the ESSID */
- iwe.u.data.length = bss->ssidLen;
- if (iwe.u.data.length > 32)
- iwe.u.data.length = 32;
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->ssid);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- capabilities = bss->cap;
- if (capabilities & (CAP_ESS | CAP_IBSS)) {
- if (capabilities & CAP_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_UINT_LEN);
- }
-
- /* Add frequency */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = le16_to_cpu(bss->dsChannel);
- iwe.u.freq.m = 100000 *
- ieee80211_channel_to_frequency(iwe.u.freq.m, NL80211_BAND_2GHZ);
- iwe.u.freq.e = 1;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_FREQ_LEN);
-
- dBm = le16_to_cpu(bss->dBm);
-
- /* Add quality statistics */
- iwe.cmd = IWEVQUAL;
- if (ai->rssi) {
- iwe.u.qual.level = 0x100 - dBm;
- iwe.u.qual.qual = airo_dbm_to_pct(ai->rssi, dBm);
- iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- } else {
- iwe.u.qual.level = (dBm + 321) / 2;
- iwe.u.qual.qual = 0;
- iwe.u.qual.updated = IW_QUAL_QUAL_INVALID
- | IW_QUAL_LEVEL_UPDATED
- | IW_QUAL_DBM;
- }
- iwe.u.qual.noise = ai->wstats.qual.noise;
- current_ev = iwe_stream_add_event(info, current_ev, end_buf,
- &iwe, IW_EV_QUAL_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (capabilities & CAP_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, bss->ssid);
-
- /* Rate : stuffing multiple values in a single event require a bit
- * more of magic - Jean II */
- current_val = current_ev + iwe_stream_lcp_len(info);
-
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
- /* Max 8 values */
- for (i = 0 ; i < 8 ; i++) {
- /* NULL terminated */
- if (bss->rates[i] == 0)
- break;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((bss->rates[i] & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, current_ev,
- current_val, end_buf,
- &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any event */
- if ((current_val - current_ev) > iwe_stream_lcp_len(info))
- current_ev = current_val;
-
- /* Beacon interval */
- buf = kmalloc(30, GFP_KERNEL);
- if (buf) {
- iwe.cmd = IWEVCUSTOM;
- sprintf(buf, "bcn_int=%d", bss->beaconInterval);
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(info, current_ev, end_buf,
- &iwe, buf);
- kfree(buf);
- }
-
- /* Put WPA/RSN Information Elements into the event stream */
- if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) {
- unsigned int num_null_ies = 0;
- u16 length = sizeof (bss->extra.iep);
- u8 *ie = (void *)&bss->extra.iep;
-
- while ((length >= 2) && (num_null_ies < 2)) {
- if (2 + ie[1] > length) {
- /* Invalid element, don't continue parsing IE */
- break;
- }
-
- switch (ie[0]) {
- case WLAN_EID_SSID:
- /* Two zero-length SSID elements
- * mean we're done parsing elements */
- if (!ie[1])
- num_null_ies++;
- break;
-
- case WLAN_EID_VENDOR_SPECIFIC:
- if (ie[1] >= 4 &&
- ie[2] == 0x00 &&
- ie[3] == 0x50 &&
- ie[4] == 0xf2 &&
- ie[5] == 0x01) {
- iwe.cmd = IWEVGENIE;
- /* 64 is an arbitrary cut-off */
- iwe.u.data.length = min(ie[1] + 2,
- 64);
- current_ev = iwe_stream_add_point(
- info, current_ev,
- end_buf, &iwe, ie);
- }
- break;
-
- case WLAN_EID_RSN:
- iwe.cmd = IWEVGENIE;
- /* 64 is an arbitrary cut-off */
- iwe.u.data.length = min(ie[1] + 2, 64);
- current_ev = iwe_stream_add_point(
- info, current_ev, end_buf,
- &iwe, ie);
- break;
-
- default:
- break;
- }
-
- length -= 2 + ie[1];
- ie += 2 + ie[1];
- }
- }
- return current_ev;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : Read Scan Results
- */
-static int airo_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *dwrq = &wrqu->data;
- struct airo_info *ai = dev->ml_priv;
- BSSListElement *net;
- int err = 0;
- char *current_ev = extra;
-
- /* If a scan is in-progress, return -EAGAIN */
- if (ai->scan_timeout > 0)
- return -EAGAIN;
-
- if (down_interruptible(&ai->sem))
- return -EAGAIN;
-
- list_for_each_entry (net, &ai->network_list, list) {
- /* Translate to WE format this entry */
- current_ev = airo_translate_scan(dev, info, current_ev,
- extra + dwrq->length,
- &net->bss);
-
- /* Check if there is space for one more entry */
- if ((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
- /* Ask user space to try again with a bigger buffer */
- err = -E2BIG;
- goto out;
- }
- }
-
- /* Length of data */
- dwrq->length = (current_ev - extra);
- dwrq->flags = 0; /* todo */
-
-out:
- up(&ai->sem);
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Commit handler : called after a bunch of SET operations
- */
-static int airo_config_commit(struct net_device *dev,
- struct iw_request_info *info, /* NULL */
- union iwreq_data *wrqu, /* NULL */
- char *extra) /* NULL */
-{
- struct airo_info *local = dev->ml_priv;
-
- if (!test_bit (FLAG_COMMIT, &local->flags))
- return 0;
-
- /* Some of the "SET" function may have modified some of the
- * parameters. It's now time to commit them in the card */
- disable_MAC(local, 1);
- if (test_bit (FLAG_RESET, &local->flags)) {
- SsidRid SSID_rid;
-
- readSsidRid(local, &SSID_rid);
- if (test_bit(FLAG_MPI,&local->flags))
- setup_card(local, dev, 1);
- else
- reset_airo_card(dev);
- disable_MAC(local, 1);
- writeSsidRid(local, &SSID_rid, 1);
- writeAPListRid(local, &local->APList, 1);
- }
- if (down_interruptible(&local->sem))
- return -ERESTARTSYS;
- writeConfigRid(local, 0);
- enable_MAC(local, 0);
- if (test_bit (FLAG_RESET, &local->flags))
- airo_set_promisc(local, true);
- else
- up(&local->sem);
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Structures to export the Wireless Handlers
- */
-
-static const struct iw_priv_args airo_private_args[] = {
-/*{ cmd, set_args, get_args, name } */
- { AIROIOCTL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
- IW_PRIV_TYPE_BYTE | 2047, "airoioctl" },
- { AIROIDIFC, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (aironet_ioctl),
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "airoidifc" },
-};
-
-static const iw_handler airo_handler[] =
-{
- IW_HANDLER(SIOCSIWCOMMIT, airo_config_commit),
- IW_HANDLER(SIOCGIWNAME, airo_get_name),
- IW_HANDLER(SIOCSIWFREQ, airo_set_freq),
- IW_HANDLER(SIOCGIWFREQ, airo_get_freq),
- IW_HANDLER(SIOCSIWMODE, airo_set_mode),
- IW_HANDLER(SIOCGIWMODE, airo_get_mode),
- IW_HANDLER(SIOCSIWSENS, airo_set_sens),
- IW_HANDLER(SIOCGIWSENS, airo_get_sens),
- IW_HANDLER(SIOCGIWRANGE, airo_get_range),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, airo_set_wap),
- IW_HANDLER(SIOCGIWAP, airo_get_wap),
- IW_HANDLER(SIOCGIWAPLIST, airo_get_aplist),
- IW_HANDLER(SIOCSIWSCAN, airo_set_scan),
- IW_HANDLER(SIOCGIWSCAN, airo_get_scan),
- IW_HANDLER(SIOCSIWESSID, airo_set_essid),
- IW_HANDLER(SIOCGIWESSID, airo_get_essid),
- IW_HANDLER(SIOCSIWNICKN, airo_set_nick),
- IW_HANDLER(SIOCGIWNICKN, airo_get_nick),
- IW_HANDLER(SIOCSIWRATE, airo_set_rate),
- IW_HANDLER(SIOCGIWRATE, airo_get_rate),
- IW_HANDLER(SIOCSIWRTS, airo_set_rts),
- IW_HANDLER(SIOCGIWRTS, airo_get_rts),
- IW_HANDLER(SIOCSIWFRAG, airo_set_frag),
- IW_HANDLER(SIOCGIWFRAG, airo_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, airo_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, airo_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, airo_set_retry),
- IW_HANDLER(SIOCGIWRETRY, airo_get_retry),
- IW_HANDLER(SIOCSIWENCODE, airo_set_encode),
- IW_HANDLER(SIOCGIWENCODE, airo_get_encode),
- IW_HANDLER(SIOCSIWPOWER, airo_set_power),
- IW_HANDLER(SIOCGIWPOWER, airo_get_power),
- IW_HANDLER(SIOCSIWAUTH, airo_set_auth),
- IW_HANDLER(SIOCGIWAUTH, airo_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, airo_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, airo_get_encodeext),
-};
-
-/* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here.
- * We want to force the use of the ioctl code, because those can't be
- * won't work the iw_handler code (because they simultaneously read
- * and write data and iw_handler can't do that).
- * Note that it's perfectly legal to read/write on a single ioctl command,
- * you just can't use iwpriv and need to force it via the ioctl handler.
- * Jean II */
-static const iw_handler airo_private_handler[] =
-{
- NULL, /* SIOCIWFIRSTPRIV */
-};
-
-static const struct iw_handler_def airo_handler_def =
-{
- .num_standard = ARRAY_SIZE(airo_handler),
- .num_private = ARRAY_SIZE(airo_private_handler),
- .num_private_args = ARRAY_SIZE(airo_private_args),
- .standard = airo_handler,
- .private = airo_private_handler,
- .private_args = airo_private_args,
- .get_wireless_stats = airo_get_wireless_stats,
-};
-
-/*
- * This defines the configuration part of the Wireless Extensions
- * Note : irq and spinlock protection will occur in the subroutines
- *
- * TODO :
- * o Check input value more carefully and fill correct values in range
- * o Test and shakeout the bugs (if any)
- *
- * Jean II
- *
- * Javier Achirica did a great job of merging code from the unnamed CISCO
- * developer that added support for flashing the card.
- */
-static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq,
- void __user *data, int cmd)
-{
- int rc = 0;
- struct airo_info *ai = dev->ml_priv;
-
- if (ai->power.event)
- return 0;
-
- switch (cmd) {
-#ifdef CISCO_EXT
- case AIROIDIFC:
-#ifdef AIROOLDIDIFC
- case AIROOLDIDIFC:
-#endif
- {
- int val = AIROMAGIC;
- aironet_ioctl com;
- if (copy_from_user(&com, data, sizeof(com)))
- rc = -EFAULT;
- else if (copy_to_user(com.data, (char *)&val, sizeof(val)))
- rc = -EFAULT;
- }
- break;
-
- case AIROIOCTL:
-#ifdef AIROOLDIOCTL
- case AIROOLDIOCTL:
-#endif
- /* Get the command struct and hand it off for evaluation by
- * the proper subfunction
- */
- {
- aironet_ioctl com;
- if (copy_from_user(&com, data, sizeof(com))) {
- rc = -EFAULT;
- break;
- }
-
- /* Separate R/W functions bracket legality here
- */
- if (com.command == AIRORSWVERSION) {
- if (copy_to_user(com.data, swversion, sizeof(swversion)))
- rc = -EFAULT;
- else
- rc = 0;
- }
- else if (com.command <= AIRORRID)
- rc = readrids(dev,&com);
- else if (com.command >= AIROPCAP && com.command <= (AIROPLEAPUSR+2))
- rc = writerids(dev,&com);
- else if (com.command >= AIROFLSHRST && com.command <= AIRORESTART)
- rc = flashcard(dev,&com);
- else
- rc = -EINVAL; /* Bad command in ioctl */
- }
- break;
-#endif /* CISCO_EXT */
-
- // All other calls are currently unsupported
- default:
- rc = -EOPNOTSUPP;
- }
- return rc;
-}
-
-/*
- * Get the Wireless stats out of the driver
- * Note : irq and spinlock protection will occur in the subroutines
- *
- * TODO :
- * o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
- *
- * Jean
- */
-static void airo_read_wireless_stats(struct airo_info *local)
-{
- StatusRid status_rid;
- StatsRid stats_rid;
- CapabilityRid cap_rid;
- __le32 *vals = stats_rid.vals;
-
- /* Get stats out of the card */
- if (local->power.event)
- return;
-
- readCapabilityRid(local, &cap_rid, 0);
- readStatusRid(local, &status_rid, 0);
- readStatsRid(local, &stats_rid, RID_STATS, 0);
-
- /* The status */
- local->wstats.status = le16_to_cpu(status_rid.mode);
-
- /* Signal quality and co */
- if (local->rssi) {
- local->wstats.qual.level =
- airo_rssi_to_dbm(local->rssi,
- le16_to_cpu(status_rid.sigQuality));
- /* normalizedSignalStrength appears to be a percentage */
- local->wstats.qual.qual =
- le16_to_cpu(status_rid.normalizedSignalStrength);
- } else {
- local->wstats.qual.level =
- (le16_to_cpu(status_rid.normalizedSignalStrength) + 321) / 2;
- local->wstats.qual.qual = airo_get_quality(&status_rid, &cap_rid);
- }
- if (le16_to_cpu(status_rid.len) >= 124) {
- local->wstats.qual.noise = 0x100 - status_rid.noisedBm;
- local->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- } else {
- local->wstats.qual.noise = 0;
- local->wstats.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | IW_QUAL_DBM;
- }
-
- /* Packets discarded in the wireless adapter due to wireless
- * specific problems */
- local->wstats.discard.nwid = le32_to_cpu(vals[56]) +
- le32_to_cpu(vals[57]) +
- le32_to_cpu(vals[58]); /* SSID Mismatch */
- local->wstats.discard.code = le32_to_cpu(vals[6]);/* RxWepErr */
- local->wstats.discard.fragment = le32_to_cpu(vals[30]);
- local->wstats.discard.retries = le32_to_cpu(vals[10]);
- local->wstats.discard.misc = le32_to_cpu(vals[1]) +
- le32_to_cpu(vals[32]);
- local->wstats.miss.beacon = le32_to_cpu(vals[34]);
-}
-
-static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
-{
- struct airo_info *local = dev->ml_priv;
-
- if (!down_interruptible(&local->sem)) {
- airo_read_wireless_stats(local);
- up(&local->sem);
- }
- return &local->wstats;
-}
-
-#ifdef CISCO_EXT
-/*
- * This just translates from driver IOCTL codes to the command codes to
- * feed to the radio's host interface. Things can be added/deleted
- * as needed. This represents the READ side of control I/O to
- * the card
- */
-static int readrids(struct net_device *dev, aironet_ioctl *comp)
-{
- unsigned short ridcode;
- unsigned char *iobuf;
- int len;
- struct airo_info *ai = dev->ml_priv;
-
- if (test_bit(FLAG_FLASHING, &ai->flags))
- return -EIO;
-
- switch(comp->command)
- {
- case AIROGCAP: ridcode = RID_CAPABILITIES; break;
- case AIROGCFG: ridcode = RID_CONFIG;
- if (test_bit(FLAG_COMMIT, &ai->flags)) {
- disable_MAC (ai, 1);
- writeConfigRid (ai, 1);
- enable_MAC(ai, 1);
- }
- break;
- case AIROGSLIST: ridcode = RID_SSID; break;
- case AIROGVLIST: ridcode = RID_APLIST; break;
- case AIROGDRVNAM: ridcode = RID_DRVNAME; break;
- case AIROGEHTENC: ridcode = RID_ETHERENCAP; break;
- case AIROGWEPKTMP: ridcode = RID_WEP_TEMP; break;
- case AIROGWEPKNV: ridcode = RID_WEP_PERM; break;
- case AIROGSTAT: ridcode = RID_STATUS; break;
- case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
- case AIROGSTATSC32: ridcode = RID_STATS; break;
- case AIROGMICSTATS:
- if (copy_to_user(comp->data, &ai->micstats,
- min((int)comp->len, (int)sizeof(ai->micstats))))
- return -EFAULT;
- return 0;
- case AIRORRID: ridcode = comp->ridnum; break;
- default:
- return -EINVAL;
- }
-
- if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) {
- /* Only super-user can read WEP keys */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- }
-
- if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- PC4500_readrid(ai, ridcode, iobuf, RIDSIZE, 1);
- /* get the count of bytes in the rid docs say 1st 2 bytes is it.
- * then return it to the user
- * 9/22/2000 Honor user given length
- */
- len = comp->len;
-
- if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
- kfree (iobuf);
- return -EFAULT;
- }
- kfree (iobuf);
- return 0;
-}
-
-/*
- * Danger Will Robinson write the rids here
- */
-
-static int writerids(struct net_device *dev, aironet_ioctl *comp)
-{
- struct airo_info *ai = dev->ml_priv;
- int ridcode;
- int enabled;
- int (*writer)(struct airo_info *, u16 rid, const void *, int, int);
- unsigned char *iobuf;
-
- /* Only super-user can write RIDs */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (test_bit(FLAG_FLASHING, &ai->flags))
- return -EIO;
-
- ridcode = 0;
- writer = do_writerid;
-
- switch(comp->command)
- {
- case AIROPSIDS: ridcode = RID_SSID; break;
- case AIROPCAP: ridcode = RID_CAPABILITIES; break;
- case AIROPAPLIST: ridcode = RID_APLIST; break;
- case AIROPCFG: ai->config.len = 0;
- clear_bit(FLAG_COMMIT, &ai->flags);
- ridcode = RID_CONFIG; break;
- case AIROPWEPKEYNV: ridcode = RID_WEP_PERM; break;
- case AIROPLEAPUSR: ridcode = RID_LEAPUSERNAME; break;
- case AIROPLEAPPWD: ridcode = RID_LEAPPASSWORD; break;
- case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
- break;
- case AIROPLEAPUSR+1: ridcode = 0xFF2A; break;
- case AIROPLEAPUSR+2: ridcode = 0xFF2B; break;
-
- /* this is not really a rid but a command given to the card
- * same with MAC off
- */
- case AIROPMACON:
- if (enable_MAC(ai, 1) != 0)
- return -EIO;
- return 0;
-
- /*
- * Evidently this code in the airo driver does not get a symbol
- * as disable_MAC. it's probably so short the compiler does not gen one.
- */
- case AIROPMACOFF:
- disable_MAC(ai, 1);
- return 0;
-
- /* This command merely clears the counts does not actually store any data
- * only reads rid. But as it changes the cards state, I put it in the
- * writerid routines.
- */
- case AIROPSTCLR:
- if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- PC4500_readrid(ai, RID_STATSDELTACLEAR, iobuf, RIDSIZE, 1);
-
- enabled = ai->micstats.enabled;
- memset(&ai->micstats, 0, sizeof(ai->micstats));
- ai->micstats.enabled = enabled;
-
- if (copy_to_user(comp->data, iobuf,
- min((int)comp->len, (int)RIDSIZE))) {
- kfree (iobuf);
- return -EFAULT;
- }
- kfree (iobuf);
- return 0;
-
- default:
- return -EOPNOTSUPP; /* Blarg! */
- }
- if (comp->len > RIDSIZE)
- return -EINVAL;
-
- if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- if (copy_from_user(iobuf, comp->data, comp->len)) {
- kfree (iobuf);
- return -EFAULT;
- }
-
- if (comp->command == AIROPCFG) {
- ConfigRid *cfg = (ConfigRid *)iobuf;
-
- if (test_bit(FLAG_MIC_CAPABLE, &ai->flags))
- cfg->opmode |= MODE_MIC;
-
- if ((cfg->opmode & MODE_CFG_MASK) == MODE_STA_IBSS)
- set_bit (FLAG_ADHOC, &ai->flags);
- else
- clear_bit (FLAG_ADHOC, &ai->flags);
- }
-
- if ((*writer)(ai, ridcode, iobuf, comp->len, 1)) {
- kfree (iobuf);
- return -EIO;
- }
- kfree (iobuf);
- return 0;
-}
-
-/*****************************************************************************
- * Ancillary flash / mod functions much black magic lurkes here *
- *****************************************************************************
- */
-
-/*
- * Flash command switch table
- */
-
-static int flashcard(struct net_device *dev, aironet_ioctl *comp)
-{
- int z;
-
- /* Only super-user can modify flash */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- switch(comp->command)
- {
- case AIROFLSHRST:
- return cmdreset((struct airo_info *)dev->ml_priv);
-
- case AIROFLSHSTFL:
- if (!AIRO_FLASH(dev) &&
- (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- return setflashmode((struct airo_info *)dev->ml_priv);
-
- case AIROFLSHGCHR: /* Get char from aux */
- if (comp->len != sizeof(int))
- return -EINVAL;
- if (copy_from_user(&z, comp->data, comp->len))
- return -EFAULT;
- return flashgchar((struct airo_info *)dev->ml_priv, z, 8000);
-
- case AIROFLSHPCHR: /* Send char to card. */
- if (comp->len != sizeof(int))
- return -EINVAL;
- if (copy_from_user(&z, comp->data, comp->len))
- return -EFAULT;
- return flashpchar((struct airo_info *)dev->ml_priv, z, 8000);
-
- case AIROFLPUTBUF: /* Send 32k to card */
- if (!AIRO_FLASH(dev))
- return -ENOMEM;
- if (comp->len > FLASHSIZE)
- return -EINVAL;
- if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len))
- return -EFAULT;
-
- flashputbuf((struct airo_info *)dev->ml_priv);
- return 0;
-
- case AIRORESTART:
- if (flashrestart((struct airo_info *)dev->ml_priv, dev))
- return -EIO;
- return 0;
- }
- return -EINVAL;
-}
-
-#define FLASH_COMMAND 0x7e7e
-
-/*
- * STEP 1)
- * Disable MAC and do soft reset on
- * card.
- */
-
-static int cmdreset(struct airo_info *ai)
-{
- disable_MAC(ai, 1);
-
- if (!waitbusy (ai)) {
- airo_print_info(ai->dev->name, "Waitbusy hang before RESET");
- return -EBUSY;
- }
-
- OUT4500(ai, COMMAND, CMD_SOFTRESET);
-
- ssleep(1); /* WAS 600 12/7/00 */
-
- if (!waitbusy (ai)) {
- airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET");
- return -EBUSY;
- }
- return 0;
-}
-
-/* STEP 2)
- * Put the card in legendary flash
- * mode
- */
-
-static int setflashmode (struct airo_info *ai)
-{
- set_bit (FLAG_FLASHING, &ai->flags);
-
- OUT4500(ai, SWS0, FLASH_COMMAND);
- OUT4500(ai, SWS1, FLASH_COMMAND);
- if (probe) {
- OUT4500(ai, SWS0, FLASH_COMMAND);
- OUT4500(ai, COMMAND, 0x10);
- } else {
- OUT4500(ai, SWS2, FLASH_COMMAND);
- OUT4500(ai, SWS3, FLASH_COMMAND);
- OUT4500(ai, COMMAND, 0);
- }
- msleep(500); /* 500ms delay */
-
- if (!waitbusy(ai)) {
- clear_bit (FLAG_FLASHING, &ai->flags);
- airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode");
- return -EIO;
- }
- return 0;
-}
-
-/* Put character to SWS0 wait for dwelltime
- * x 50us for echo .
- */
-
-static int flashpchar(struct airo_info *ai, int byte, int dwelltime)
-{
- int echo;
- int waittime;
-
- byte |= 0x8000;
-
- if (dwelltime == 0)
- dwelltime = 200;
-
- waittime = dwelltime;
-
- /* Wait for busy bit d15 to go false indicating buffer empty */
- while ((IN4500 (ai, SWS0) & 0x8000) && waittime > 0) {
- udelay (50);
- waittime -= 50;
- }
-
- /* timeout for busy clear wait */
- if (waittime <= 0) {
- airo_print_info(ai->dev->name, "flash putchar busywait timeout!");
- return -EBUSY;
- }
-
- /* Port is clear now write byte and wait for it to echo back */
- do {
- OUT4500(ai, SWS0, byte);
- udelay(50);
- dwelltime -= 50;
- echo = IN4500(ai, SWS1);
- } while (dwelltime >= 0 && echo != byte);
-
- OUT4500(ai, SWS1, 0);
-
- return (echo == byte) ? 0 : -EIO;
-}
-
-/*
- * Get a character from the card matching matchbyte
- * Step 3)
- */
-static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime)
-{
- int rchar;
- unsigned char rbyte = 0;
-
- do {
- rchar = IN4500(ai, SWS1);
-
- if (dwelltime && !(0x8000 & rchar)) {
- dwelltime -= 10;
- mdelay(10);
- continue;
- }
- rbyte = 0xff & rchar;
-
- if ((rbyte == matchbyte) && (0x8000 & rchar)) {
- OUT4500(ai, SWS1, 0);
- return 0;
- }
- if (rbyte == 0x81 || rbyte == 0x82 || rbyte == 0x83 || rbyte == 0x1a || 0xffff == rchar)
- break;
- OUT4500(ai, SWS1, 0);
-
- } while (dwelltime > 0);
- return -EIO;
-}
-
-/*
- * Transfer 32k of firmware data from user buffer to our buffer and
- * send to the card
- */
-
-static int flashputbuf(struct airo_info *ai)
-{
- int nwords;
-
- /* Write stuff */
- if (test_bit(FLAG_MPI,&ai->flags))
- memcpy_toio(ai->pciaux + 0x8000, ai->flash, FLASHSIZE);
- else {
- OUT4500(ai, AUXPAGE, 0x100);
- OUT4500(ai, AUXOFF, 0);
-
- for (nwords = 0; nwords != FLASHSIZE / 2; nwords++) {
- OUT4500(ai, AUXDATA, ai->flash[nwords] & 0xffff);
- }
- }
- OUT4500(ai, SWS0, 0x8000);
-
- return 0;
-}
-
-/*
- *
- */
-static int flashrestart(struct airo_info *ai, struct net_device *dev)
-{
- int i, status;
-
- ssleep(1); /* Added 12/7/00 */
- clear_bit (FLAG_FLASHING, &ai->flags);
- if (test_bit(FLAG_MPI, &ai->flags)) {
- status = mpi_init_descriptors(ai);
- if (status != SUCCESS)
- return status;
- }
- status = setup_card(ai, dev, 1);
-
- if (!test_bit(FLAG_MPI,&ai->flags))
- for (i = 0; i < MAX_FIDS; i++) {
- ai->fids[i] = transmit_allocate
- (ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2);
- }
-
- ssleep(1); /* Added 12/7/00 */
- return status;
-}
-#endif /* CISCO_EXT */
-
-/*
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- In addition:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
-
-module_init(airo_init_module);
-module_exit(airo_cleanup_module);
diff --git a/drivers/net/wireless/cisco/airo.h b/drivers/net/wireless/cisco/airo.h
deleted file mode 100644
index 8a02977a2e2ba..0000000000000
--- a/drivers/net/wireless/cisco/airo.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _AIRO_H_
-#define _AIRO_H_
-
-struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia,
- struct device *dmdev);
-int reset_airo_card(struct net_device *dev);
-void stop_airo_card(struct net_device *dev, int freeres);
-
-#endif /* _AIRO_H_ */
diff --git a/drivers/net/wireless/cisco/airo_cs.c b/drivers/net/wireless/cisco/airo_cs.c
deleted file mode 100644
index fcfe4c6d62f04..0000000000000
--- a/drivers/net/wireless/cisco/airo_cs.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/*======================================================================
-
- Aironet driver for 4500 and 4800 series cards
-
- This code is released under both the GPL version 2 and BSD licenses.
- Either license may be used. The respective licenses are found at
- the end of this file.
-
- This code was developed by Benjamin Reed <[email protected]>
- including portions of which come from the Aironet PC4500
- Developer's Reference Manual and used with permission. Copyright
- (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use
- code in the Developer's manual was granted for this driver by
- Aironet.
-
- In addition this module was derived from dummy_cs.
- The initial developer of dummy_cs is David A. Hinds
- <[email protected]>. Portions created by David A. Hinds
- are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
-
-======================================================================*/
-
-#ifdef __IN_PCMCIA_PACKAGE__
-#include <pcmcia/k_compat.h>
-#endif
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/netdevice.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <linux/io.h>
-
-#include "airo.h"
-
-
-/*====================================================================*/
-
-MODULE_AUTHOR("Benjamin Reed");
-MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet "
- "cards. This is the module that links the PCMCIA card "
- "with the airo module.");
-MODULE_LICENSE("Dual BSD/GPL");
-
-/*====================================================================*/
-
-static int airo_config(struct pcmcia_device *link);
-static void airo_release(struct pcmcia_device *link);
-
-static void airo_detach(struct pcmcia_device *p_dev);
-
-struct local_info {
- struct net_device *eth_dev;
-};
-
-static int airo_probe(struct pcmcia_device *p_dev)
-{
- struct local_info *local;
-
- dev_dbg(&p_dev->dev, "airo_attach()\n");
-
- /* Allocate space for private device-specific data */
- local = kzalloc(sizeof(*local), GFP_KERNEL);
- if (!local)
- return -ENOMEM;
-
- p_dev->priv = local;
-
- return airo_config(p_dev);
-} /* airo_attach */
-
-static void airo_detach(struct pcmcia_device *link)
-{
- dev_dbg(&link->dev, "airo_detach\n");
-
- airo_release(link);
-
- if (((struct local_info *)link->priv)->eth_dev) {
- stop_airo_card(((struct local_info *)link->priv)->eth_dev,
- 0);
- }
- ((struct local_info *)link->priv)->eth_dev = NULL;
-
- kfree(link->priv);
-} /* airo_detach */
-
-static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-}
-
-
-static int airo_config(struct pcmcia_device *link)
-{
- int ret;
-
- dev_dbg(&link->dev, "airo_config\n");
-
- link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
- CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
-
- ret = pcmcia_loop_config(link, airo_cs_config_check, NULL);
- if (ret)
- goto failed;
-
- if (!link->irq)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
- ((struct local_info *)link->priv)->eth_dev =
- init_airo_card(link->irq,
- link->resource[0]->start, 1, &link->dev);
- if (!((struct local_info *)link->priv)->eth_dev)
- goto failed;
-
- return 0;
-
- failed:
- airo_release(link);
- return -ENODEV;
-} /* airo_config */
-
-static void airo_release(struct pcmcia_device *link)
-{
- dev_dbg(&link->dev, "airo_release\n");
- pcmcia_disable_device(link);
-}
-
-static int airo_suspend(struct pcmcia_device *link)
-{
- struct local_info *local = link->priv;
-
- netif_device_detach(local->eth_dev);
-
- return 0;
-}
-
-static int airo_resume(struct pcmcia_device *link)
-{
- struct local_info *local = link->priv;
-
- if (link->open) {
- reset_airo_card(local->eth_dev);
- netif_device_attach(local->eth_dev);
- }
-
- return 0;
-}
-
-static const struct pcmcia_device_id airo_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
- PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
- PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
- PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007),
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, airo_ids);
-
-static struct pcmcia_driver airo_driver = {
- .owner = THIS_MODULE,
- .name = "airo_cs",
- .probe = airo_probe,
- .remove = airo_detach,
- .id_table = airo_ids,
- .suspend = airo_suspend,
- .resume = airo_resume,
-};
-module_pcmcia_driver(airo_driver);
-
-/*
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- In addition:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote
- products derived from this software without specific prior written
- permission.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
-*/
--
2.39.2

2023-10-23 13:22:31

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 06/10] wifi: remove orphaned orinoco driver

From: Arnd Bergmann <[email protected]>

Orinoco is a PIO-only ISA/PCMCIA 802.11b device with extra bus interface
connections for PCI/Cardbus/mini-PCI and a few pre-2002 Apple PowerMac
variants. It supports both wireless extensions and CFG80211, but I could
not tell if it requires using both.

This device used to be one of the most common ones 20 years ago, but
has been orphaned for most of the time since then, and the conversion
to cfg80211 has stalled in 2010.

Signed-off-by: Arnd Bergmann <[email protected]>
---
MAINTAINERS | 7 -
drivers/net/wireless/intersil/Kconfig | 1 -
drivers/net/wireless/intersil/Makefile | 1 -
drivers/net/wireless/intersil/orinoco/Kconfig | 143 -
.../net/wireless/intersil/orinoco/Makefile | 15 -
.../net/wireless/intersil/orinoco/airport.c | 268 --
drivers/net/wireless/intersil/orinoco/cfg.c | 291 --
drivers/net/wireless/intersil/orinoco/cfg.h | 15 -
drivers/net/wireless/intersil/orinoco/fw.c | 387 ---
drivers/net/wireless/intersil/orinoco/fw.h | 21 -
.../net/wireless/intersil/orinoco/hermes.c | 778 ------
.../net/wireless/intersil/orinoco/hermes.h | 534 ----
.../wireless/intersil/orinoco/hermes_dld.c | 477 ----
.../wireless/intersil/orinoco/hermes_dld.h | 52 -
.../wireless/intersil/orinoco/hermes_rid.h | 165 --
drivers/net/wireless/intersil/orinoco/hw.c | 1362 ----------
drivers/net/wireless/intersil/orinoco/hw.h | 60 -
drivers/net/wireless/intersil/orinoco/main.c | 2414 -----------------
drivers/net/wireless/intersil/orinoco/main.h | 50 -
drivers/net/wireless/intersil/orinoco/mic.c | 89 -
drivers/net/wireless/intersil/orinoco/mic.h | 23 -
.../net/wireless/intersil/orinoco/orinoco.h | 251 --
.../wireless/intersil/orinoco/orinoco_cs.c | 350 ---
.../intersil/orinoco/orinoco_nortel.c | 314 ---
.../wireless/intersil/orinoco/orinoco_pci.c | 257 --
.../wireless/intersil/orinoco/orinoco_pci.h | 54 -
.../wireless/intersil/orinoco/orinoco_plx.c | 362 ---
.../wireless/intersil/orinoco/orinoco_tmd.c | 237 --
.../wireless/intersil/orinoco/orinoco_usb.c | 1787 ------------
drivers/net/wireless/intersil/orinoco/scan.c | 259 --
drivers/net/wireless/intersil/orinoco/scan.h | 21 -
.../wireless/intersil/orinoco/spectrum_cs.c | 328 ---
drivers/net/wireless/intersil/orinoco/wext.c | 1428 ----------
drivers/net/wireless/intersil/orinoco/wext.h | 13 -
34 files changed, 12814 deletions(-)
delete mode 100644 drivers/net/wireless/intersil/orinoco/Kconfig
delete mode 100644 drivers/net/wireless/intersil/orinoco/Makefile
delete mode 100644 drivers/net/wireless/intersil/orinoco/airport.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/cfg.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/cfg.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/fw.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/fw.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_dld.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_dld.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hermes_rid.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/hw.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/hw.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/main.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/main.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/mic.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/mic.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_cs.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_nortel.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_pci.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_pci.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_plx.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_tmd.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/orinoco_usb.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/scan.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/scan.h
delete mode 100644 drivers/net/wireless/intersil/orinoco/spectrum_cs.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/wext.c
delete mode 100644 drivers/net/wireless/intersil/orinoco/wext.h

diff --git a/MAINTAINERS b/MAINTAINERS
index be59dc66c8133..e5c669d9bca00 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16053,13 +16053,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git
F: Documentation/filesystems/orangefs.rst
F: fs/orangefs/

-ORINOCO DRIVER
-L: [email protected]
-S: Orphan
-W: https://wireless.wiki.kernel.org/en/users/Drivers/orinoco
-W: http://www.nongnu.org/orinoco/
-F: drivers/net/wireless/intersil/orinoco/
-
OV2659 OMNIVISION SENSOR DRIVER
M: "Lad, Prabhakar" <[email protected]>
L: [email protected]
diff --git a/drivers/net/wireless/intersil/Kconfig b/drivers/net/wireless/intersil/Kconfig
index f2455ef45d995..201b1534a9ca2 100644
--- a/drivers/net/wireless/intersil/Kconfig
+++ b/drivers/net/wireless/intersil/Kconfig
@@ -12,7 +12,6 @@ config WLAN_VENDOR_INTERSIL

if WLAN_VENDOR_INTERSIL

-source "drivers/net/wireless/intersil/orinoco/Kconfig"
source "drivers/net/wireless/intersil/p54/Kconfig"

endif # WLAN_VENDOR_INTERSIL
diff --git a/drivers/net/wireless/intersil/Makefile b/drivers/net/wireless/intersil/Makefile
index 773147110c54e..27e9b2869da1a 100644
--- a/drivers/net/wireless/intersil/Makefile
+++ b/drivers/net/wireless/intersil/Makefile
@@ -1,3 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_HERMES) += orinoco/
obj-$(CONFIG_P54_COMMON) += p54/
diff --git a/drivers/net/wireless/intersil/orinoco/Kconfig b/drivers/net/wireless/intersil/orinoco/Kconfig
deleted file mode 100644
index f62730aa7be30..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/Kconfig
+++ /dev/null
@@ -1,143 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config HERMES
- tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
- depends on (PPC_PMAC || PCI || PCMCIA)
- depends on CFG80211
- select CFG80211_WEXT_EXPORT
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select CRYPTO
- select CRYPTO_MICHAEL_MIC
- help
- A driver for 802.11b wireless cards based on the "Hermes" or
- Intersil HFA384x (Prism 2) MAC controller. This includes the vast
- majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
- - except for the Cisco/Aironet cards. Cards supported include the
- Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco,
- Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya,
- IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear
- MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel
- IPW2011, and Symbol Spectrum24 High Rate amongst others.
-
- This option includes the guts of the driver, but in order to
- actually use a card you will also need to enable support for PCMCIA
- Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below.
-
- You will also very likely also need the Wireless Tools in order to
- configure your card and that /etc/pcmcia/wireless.opts works :
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
-
-config HERMES_PRISM
- bool "Support Prism 2/2.5 chipset"
- depends on HERMES
- help
-
- Say Y to enable support for Prism 2 and 2.5 chipsets. These
- chipsets are better handled by the hostap driver. This driver
- would not support WPA or firmware download for Prism chipset.
-
- If you are not sure, say N.
-
-config HERMES_CACHE_FW_ON_INIT
- bool "Cache Hermes firmware on driver initialisation"
- depends on HERMES
- default y
- help
- Say Y to cache any firmware required by the Hermes drivers
- on startup. The firmware will remain cached until the
- driver is unloaded. The cache uses 64K of RAM.
-
- Otherwise load the firmware from userspace as required. In
- this case the driver should be unloaded and restarted
- whenever the firmware is changed.
-
- If you are not sure, say Y.
-
-config APPLE_AIRPORT
- tristate "Apple Airport support (built-in)"
- depends on PPC_PMAC && HERMES
- help
- Say Y here to support the Airport 802.11b wireless Ethernet hardware
- built into the Macintosh iBook and other recent PowerPC-based
- Macintosh machines. This is essentially a Lucent Orinoco card with
- a non-standard interface.
-
- This driver does not support the Airport Extreme (802.11b/g). Use
- the BCM43xx driver for Airport Extreme cards.
-
-config PLX_HERMES
- tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
- depends on PCI && HERMES
- help
- Enable support for PCMCIA cards supported by the "Hermes" (aka
- orinoco) driver when used in PLX9052 based PCI adaptors. These
- adaptors are not a full PCMCIA controller but act as a more limited
- PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
- 802.11b PCMCIA cards can be used in desktop machines. The Netgear
- MA301 is such an adaptor.
-
-config TMD_HERMES
- tristate "Hermes in TMD7160 based PCI adaptor support"
- depends on PCI && HERMES
- help
- Enable support for PCMCIA cards supported by the "Hermes" (aka
- orinoco) driver when used in TMD7160 based PCI adaptors. These
- adaptors are not a full PCMCIA controller but act as a more limited
- PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
- 802.11b PCMCIA cards can be used in desktop machines.
-
-config NORTEL_HERMES
- tristate "Nortel emobility PCI adaptor support"
- depends on PCI && HERMES
- help
- Enable support for PCMCIA cards supported by the "Hermes" (aka
- orinoco) driver when used in Nortel emobility PCI adaptors. These
- adaptors are not full PCMCIA controllers, but act as a more limited
- PCI <-> PCMCIA bridge.
-
-config PCI_HERMES
- tristate "Prism 2.5 PCI 802.11b adaptor support"
- depends on PCI && HERMES && HERMES_PRISM
- help
- Enable support for PCI and mini-PCI 802.11b wireless NICs based on
- the Prism 2.5 chipset. These are true PCI cards, not the 802.11b
- PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also
- common. Some of the built-in wireless adaptors in laptops are of
- this variety.
-
-config PCMCIA_HERMES
- tristate "Hermes PCMCIA card support"
- depends on PCMCIA && HERMES && HAS_IOPORT_MAP
- help
- A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
- EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and
- others). It should also be usable on various Prism II based cards
- such as the Linksys, D-Link and Farallon Skyline. It should also
- work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
-
- You will very likely need the Wireless Tools in order to
- configure your card and that /etc/pcmcia/wireless.opts works:
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
-config PCMCIA_SPECTRUM
- tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
- depends on PCMCIA && HERMES && HAS_IOPORT_MAP
- help
-
- This is a driver for 802.11b cards using RAM-loadable Symbol
- firmware, such as Symbol Wireless Networker LA4100, CompactFlash
- cards by Socket Communications and Intel PRO/Wireless 2011B.
-
- This driver requires firmware download on startup. Utilities
- for downloading Symbol firmware are available at
- <http://sourceforge.net/projects/orinoco/>
-
-config ORINOCO_USB
- tristate "Agere Orinoco USB support"
- depends on USB && HERMES
- select FW_LOADER
- help
- This driver is for USB versions of the Agere Orinoco card.
diff --git a/drivers/net/wireless/intersil/orinoco/Makefile b/drivers/net/wireless/intersil/orinoco/Makefile
deleted file mode 100644
index 0c29c56c88d6d..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the orinoco wireless device drivers.
-#
-orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
-
-obj-$(CONFIG_HERMES) += orinoco.o
-obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
-obj-$(CONFIG_APPLE_AIRPORT) += airport.o
-obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
-obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
-obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
-obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
-obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
-obj-$(CONFIG_ORINOCO_USB) += orinoco_usb.o
diff --git a/drivers/net/wireless/intersil/orinoco/airport.c b/drivers/net/wireless/intersil/orinoco/airport.c
deleted file mode 100644
index 45ac00fdafa58..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/airport.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/* airport.c
- *
- * A driver for "Hermes" chipset based Apple Airport wireless
- * card.
- *
- * Copyright notice & release notes in file main.c
- *
- * Note specific to airport stub:
- *
- * 0.05 : first version of the new split driver
- * 0.06 : fix possible hang on powerup, add sleep support
- */
-
-#define DRIVER_NAME "airport"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/mod_devicetable.h>
-#include <asm/pmac_feature.h>
-
-#include "orinoco.h"
-
-#define AIRPORT_IO_LEN (0x1000) /* one page */
-
-struct airport {
- struct macio_dev *mdev;
- void __iomem *vaddr;
- unsigned int irq;
- int irq_requested;
- int ndev_registered;
-};
-
-static int
-airport_suspend(struct macio_dev *mdev, pm_message_t state)
-{
- struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
- struct net_device *dev = priv->ndev;
- struct airport *card = priv->card;
- unsigned long flags;
- int err;
-
- printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
-
- err = orinoco_lock(priv, &flags);
- if (err) {
- printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
- dev->name);
- return 0;
- }
-
- orinoco_down(priv);
- orinoco_unlock(priv, &flags);
-
- disable_irq(card->irq);
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 0);
-
- return 0;
-}
-
-static int
-airport_resume(struct macio_dev *mdev)
-{
- struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
- struct net_device *dev = priv->ndev;
- struct airport *card = priv->card;
- unsigned long flags;
- int err;
-
- printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
-
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 1);
- msleep(200);
-
- enable_irq(card->irq);
-
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- err = orinoco_up(priv);
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- return err;
-}
-
-static int
-airport_detach(struct macio_dev *mdev)
-{
- struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
- struct airport *card = priv->card;
-
- if (card->ndev_registered)
- orinoco_if_del(priv);
- card->ndev_registered = 0;
-
- if (card->irq_requested)
- free_irq(card->irq, priv);
- card->irq_requested = 0;
-
- if (card->vaddr)
- iounmap(card->vaddr);
- card->vaddr = NULL;
-
- macio_release_resource(mdev, 0);
-
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 0);
- ssleep(1);
-
- macio_set_drvdata(mdev, NULL);
- free_orinocodev(priv);
-
- return 0;
-}
-
-static int airport_hard_reset(struct orinoco_private *priv)
-{
- /* It would be nice to power cycle the Airport for a real hard
- * reset, but for some reason although it appears to
- * re-initialize properly, it falls in a screaming heap
- * shortly afterwards. */
-#if 0
- struct airport *card = priv->card;
-
- /* Vitally important. If we don't do this it seems we get an
- * interrupt somewhere during the power cycle, since
- * hw_unavailable is already set it doesn't get ACKed, we get
- * into an interrupt loop and the PMU decides to turn us
- * off. */
- disable_irq(card->irq);
-
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(card->mdev), 0, 0);
- ssleep(1);
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(card->mdev), 0, 1);
- ssleep(1);
-
- enable_irq(card->irq);
- ssleep(1);
-#endif
-
- return 0;
-}
-
-static int
-airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
-{
- struct orinoco_private *priv;
- struct airport *card;
- unsigned long phys_addr;
- struct hermes *hw;
-
- if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
- printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
- return -ENODEV;
- }
-
- /* Allocate space for private device-specific data */
- priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
- airport_hard_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- return -ENODEV;
- }
- card = priv->card;
-
- hw = &priv->hw;
- card->mdev = mdev;
-
- if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
- printk(KERN_ERR PFX "can't request IO resource !\n");
- free_orinocodev(priv);
- return -EBUSY;
- }
-
- macio_set_drvdata(mdev, priv);
-
- /* Setup interrupts & base address */
- card->irq = macio_irq(mdev, 0);
- phys_addr = macio_resource_start(mdev, 0); /* Physical address */
- printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
- card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
- if (!card->vaddr) {
- printk(KERN_ERR PFX "ioremap() failed\n");
- goto failed;
- }
-
- hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING);
-
- /* Power up card */
- pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
- macio_get_of_node(mdev), 0, 1);
- ssleep(1);
-
- /* Reset it before we get the interrupt */
- hw->ops->init(hw);
-
- if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
- printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
- goto failed;
- }
- card->irq_requested = 1;
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto failed;
- }
-
- /* Register an interface with the stack */
- if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto failed;
- }
- card->ndev_registered = 1;
- return 0;
- failed:
- airport_detach(mdev);
- return -ENODEV;
-} /* airport_attach */
-
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Benjamin Herrenschmidt <[email protected]>)";
-MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");
-MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static const struct of_device_id airport_match[] = {
- {
- .name = "radio",
- },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, airport_match);
-
-static struct macio_driver airport_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = airport_match,
- },
- .probe = airport_attach,
- .remove = airport_detach,
- .suspend = airport_suspend,
- .resume = airport_resume,
-};
-
-static int __init
-init_airport(void)
-{
- printk(KERN_DEBUG "%s\n", version);
-
- return macio_register_driver(&airport_driver);
-}
-
-static void __exit
-exit_airport(void)
-{
- macio_unregister_driver(&airport_driver);
-}
-
-module_init(init_airport);
-module_exit(exit_airport);
diff --git a/drivers/net/wireless/intersil/orinoco/cfg.c b/drivers/net/wireless/intersil/orinoco/cfg.c
deleted file mode 100644
index b2d5ec8634b5d..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/cfg.c
+++ /dev/null
@@ -1,291 +0,0 @@
-/* cfg80211 support
- *
- * See copyright notice in main.c
- */
-#include <linux/ieee80211.h>
-#include <net/cfg80211.h>
-#include "hw.h"
-#include "main.h"
-#include "orinoco.h"
-
-#include "cfg.h"
-
-/* Supported bitrates. Must agree with hw.c */
-static struct ieee80211_rate orinoco_rates[] = {
- { .bitrate = 10 },
- { .bitrate = 20 },
- { .bitrate = 55 },
- { .bitrate = 110 },
-};
-
-static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
-
-/* Called after orinoco_private is allocated. */
-void orinoco_wiphy_init(struct wiphy *wiphy)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
-
- wiphy->privid = orinoco_wiphy_privid;
-
- set_wiphy_dev(wiphy, priv->dev);
-}
-
-/* Called after firmware is initialised */
-int orinoco_wiphy_register(struct wiphy *wiphy)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int i, channels = 0;
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- wiphy->max_scan_ssids = 1;
- else
- wiphy->max_scan_ssids = 0;
-
- wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
-
- /* TODO: should we set if we only have demo ad-hoc?
- * (priv->has_port3)
- */
- if (priv->has_ibss)
- wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
-
- if (!priv->broken_monitor || force_monitor)
- wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
-
- priv->band.bitrates = orinoco_rates;
- priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
-
- /* Only support channels allowed by the card EEPROM */
- for (i = 0; i < NUM_CHANNELS; i++) {
- if (priv->channel_mask & (1 << i)) {
- priv->channels[i].center_freq =
- ieee80211_channel_to_frequency(i + 1,
- NL80211_BAND_2GHZ);
- channels++;
- }
- }
- priv->band.channels = priv->channels;
- priv->band.n_channels = channels;
-
- wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
- wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
-
- i = 0;
- if (priv->has_wep) {
- priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
- i++;
-
- if (priv->has_big_wep) {
- priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
- i++;
- }
- }
- if (priv->has_wpa) {
- priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
- i++;
- }
- wiphy->cipher_suites = priv->cipher_suites;
- wiphy->n_cipher_suites = i;
-
- wiphy->rts_threshold = priv->rts_thresh;
- if (!priv->has_mwo)
- wiphy->frag_threshold = priv->frag_thresh + 1;
- wiphy->retry_short = priv->short_retry_limit;
- wiphy->retry_long = priv->long_retry_limit;
-
- return wiphy_register(wiphy);
-}
-
-static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
- enum nl80211_iftype type,
- struct vif_params *params)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int err = 0;
- unsigned long lock;
-
- if (orinoco_lock(priv, &lock) != 0)
- return -EBUSY;
-
- switch (type) {
- case NL80211_IFTYPE_ADHOC:
- if (!priv->has_ibss && !priv->has_port3)
- err = -EINVAL;
- break;
-
- case NL80211_IFTYPE_STATION:
- break;
-
- case NL80211_IFTYPE_MONITOR:
- if (priv->broken_monitor && !force_monitor) {
- wiphy_warn(wiphy,
- "Monitor mode support is buggy in this firmware, not enabling\n");
- err = -EINVAL;
- }
- break;
-
- default:
- err = -EINVAL;
- }
-
- if (!err) {
- priv->iw_mode = type;
- set_port_type(priv);
- err = orinoco_commit(priv);
- }
-
- orinoco_unlock(priv, &lock);
-
- return err;
-}
-
-static int orinoco_scan(struct wiphy *wiphy,
- struct cfg80211_scan_request *request)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int err;
-
- if (!request)
- return -EINVAL;
-
- if (priv->scan_request && priv->scan_request != request)
- return -EBUSY;
-
- priv->scan_request = request;
-
- err = orinoco_hw_trigger_scan(priv, request->ssids);
- /* On error the we aren't processing the request */
- if (err)
- priv->scan_request = NULL;
-
- return err;
-}
-
-static int orinoco_set_monitor_channel(struct wiphy *wiphy,
- struct cfg80211_chan_def *chandef)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int err = 0;
- unsigned long flags;
- int channel;
-
- if (!chandef->chan)
- return -EINVAL;
-
- if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
- return -EINVAL;
-
- if (chandef->chan->band != NL80211_BAND_2GHZ)
- return -EINVAL;
-
- channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
-
- if ((channel < 1) || (channel > NUM_CHANNELS) ||
- !(priv->channel_mask & (1 << (channel - 1))))
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- priv->channel = channel;
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- /* Fast channel change - no commit if successful */
- struct hermes *hw = &priv->hw;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_SET_CHANNEL,
- channel, NULL);
- }
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
-{
- struct orinoco_private *priv = wiphy_priv(wiphy);
- int frag_value = -1;
- int rts_value = -1;
- int err = 0;
-
- if (changed & WIPHY_PARAM_RETRY_SHORT) {
- /* Setting short retry not supported */
- err = -EINVAL;
- }
-
- if (changed & WIPHY_PARAM_RETRY_LONG) {
- /* Setting long retry not supported */
- err = -EINVAL;
- }
-
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
- /* Set fragmentation */
- if (priv->has_mwo) {
- if (wiphy->frag_threshold == -1)
- frag_value = 0;
- else {
- printk(KERN_WARNING "%s: Fixed fragmentation "
- "is not supported on this firmware. "
- "Using MWO robust instead.\n",
- priv->ndev->name);
- frag_value = 1;
- }
- } else {
- if (wiphy->frag_threshold == -1)
- frag_value = 2346;
- else if ((wiphy->frag_threshold < 257) ||
- (wiphy->frag_threshold > 2347))
- err = -EINVAL;
- else
- /* cfg80211 value is 257-2347 (odd only)
- * orinoco rid has range 256-2346 (even only) */
- frag_value = wiphy->frag_threshold & ~0x1;
- }
- }
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- /* Set RTS.
- *
- * Prism documentation suggests default of 2432,
- * and a range of 0-3000.
- *
- * Current implementation uses 2347 as the default and
- * the upper limit.
- */
-
- if (wiphy->rts_threshold == -1)
- rts_value = 2347;
- else if (wiphy->rts_threshold > 2347)
- err = -EINVAL;
- else
- rts_value = wiphy->rts_threshold;
- }
-
- if (!err) {
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (frag_value >= 0) {
- if (priv->has_mwo)
- priv->mwo_robust = frag_value;
- else
- priv->frag_thresh = frag_value;
- }
- if (rts_value >= 0)
- priv->rts_thresh = rts_value;
-
- err = orinoco_commit(priv);
-
- orinoco_unlock(priv, &flags);
- }
-
- return err;
-}
-
-const struct cfg80211_ops orinoco_cfg_ops = {
- .change_virtual_intf = orinoco_change_vif,
- .set_monitor_channel = orinoco_set_monitor_channel,
- .scan = orinoco_scan,
- .set_wiphy_params = orinoco_set_wiphy_params,
-};
diff --git a/drivers/net/wireless/intersil/orinoco/cfg.h b/drivers/net/wireless/intersil/orinoco/cfg.h
deleted file mode 100644
index 3ddc96a06cd78..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/cfg.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* cfg80211 support.
- *
- * See copyright notice in main.c
- */
-#ifndef ORINOCO_CFG_H
-#define ORINOCO_CFG_H
-
-#include <net/cfg80211.h>
-
-extern const struct cfg80211_ops orinoco_cfg_ops;
-
-void orinoco_wiphy_init(struct wiphy *wiphy);
-int orinoco_wiphy_register(struct wiphy *wiphy);
-
-#endif /* ORINOCO_CFG_H */
diff --git a/drivers/net/wireless/intersil/orinoco/fw.c b/drivers/net/wireless/intersil/orinoco/fw.c
deleted file mode 100644
index 015af782881bf..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/fw.c
+++ /dev/null
@@ -1,387 +0,0 @@
-/* Firmware file reading and download helpers
- *
- * See copyright notice in main.c
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/device.h>
-#include <linux/module.h>
-
-#include "hermes.h"
-#include "hermes_dld.h"
-#include "orinoco.h"
-
-#include "fw.h"
-
-/* End markers (for Symbol firmware only) */
-#define TEXT_END 0x1A /* End of text header */
-
-struct fw_info {
- char *pri_fw;
- char *sta_fw;
- char *ap_fw;
- u32 pda_addr;
- u16 pda_size;
-};
-
-static const struct fw_info orinoco_fw[] = {
- { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
- { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
- { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
-};
-MODULE_FIRMWARE("agere_sta_fw.bin");
-MODULE_FIRMWARE("agere_ap_fw.bin");
-MODULE_FIRMWARE("prism_sta_fw.bin");
-MODULE_FIRMWARE("prism_ap_fw.bin");
-MODULE_FIRMWARE("symbol_sp24t_prim_fw");
-MODULE_FIRMWARE("symbol_sp24t_sec_fw");
-
-/* Structure used to access fields in FW
- * Make sure LE decoding macros are used
- */
-struct orinoco_fw_header {
- char hdr_vers[6]; /* ASCII string for header version */
- __le16 headersize; /* Total length of header */
- __le32 entry_point; /* NIC entry point */
- __le32 blocks; /* Number of blocks to program */
- __le32 block_offset; /* Offset of block data from eof header */
- __le32 pdr_offset; /* Offset to PDR data from eof header */
- __le32 pri_offset; /* Offset to primary plug data */
- __le32 compat_offset; /* Offset to compatibility data*/
- char signature[]; /* FW signature length headersize-20 */
-} __packed;
-
-/* Check the range of various header entries. Return a pointer to a
- * description of the problem, or NULL if everything checks out. */
-static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len)
-{
- u16 hdrsize;
-
- if (len < sizeof(*hdr))
- return "image too small";
- if (memcmp(hdr->hdr_vers, "HFW", 3) != 0)
- return "format not recognised";
-
- hdrsize = le16_to_cpu(hdr->headersize);
- if (hdrsize > len)
- return "bad headersize";
- if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len)
- return "bad block offset";
- if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len)
- return "bad PDR offset";
- if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len)
- return "bad PRI offset";
- if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len)
- return "bad compat offset";
-
- /* TODO: consider adding a checksum or CRC to the firmware format */
- return NULL;
-}
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
-static inline const struct firmware *
-orinoco_cached_fw_get(struct orinoco_private *priv, bool primary)
-{
- if (primary)
- return priv->cached_pri_fw;
- else
- return priv->cached_fw;
-}
-#else
-#define orinoco_cached_fw_get(priv, primary) (NULL)
-#endif
-
-/* Download either STA or AP firmware into the card. */
-static int
-orinoco_dl_firmware(struct orinoco_private *priv,
- const struct fw_info *fw,
- int ap)
-{
- /* Plug Data Area (PDA) */
- __le16 *pda;
-
- struct hermes *hw = &priv->hw;
- const struct firmware *fw_entry;
- const struct orinoco_fw_header *hdr;
- const unsigned char *first_block;
- const void *end;
- const char *firmware;
- const char *fw_err;
- struct device *dev = priv->dev;
- int err = 0;
-
- pda = kzalloc(fw->pda_size, GFP_KERNEL);
- if (!pda)
- return -ENOMEM;
-
- if (ap)
- firmware = fw->ap_fw;
- else
- firmware = fw->sta_fw;
-
- dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
-
- /* Read current plug data */
- err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
- dev_dbg(dev, "Read PDA returned %d\n", err);
- if (err)
- goto free;
-
- if (!orinoco_cached_fw_get(priv, false)) {
- err = request_firmware(&fw_entry, firmware, priv->dev);
-
- if (err) {
- dev_err(dev, "Cannot find firmware %s\n", firmware);
- err = -ENOENT;
- goto free;
- }
- } else
- fw_entry = orinoco_cached_fw_get(priv, false);
-
- hdr = (const struct orinoco_fw_header *) fw_entry->data;
-
- fw_err = validate_fw(hdr, fw_entry->size);
- if (fw_err) {
- dev_warn(dev, "Invalid firmware image detected (%s). "
- "Aborting download\n", fw_err);
- err = -EINVAL;
- goto abort;
- }
-
- /* Enable aux port to allow programming */
- err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point));
- dev_dbg(dev, "Program init returned %d\n", err);
- if (err != 0)
- goto abort;
-
- /* Program data */
- first_block = (fw_entry->data +
- le16_to_cpu(hdr->headersize) +
- le32_to_cpu(hdr->block_offset));
- end = fw_entry->data + fw_entry->size;
-
- err = hermes_program(hw, first_block, end);
- dev_dbg(dev, "Program returned %d\n", err);
- if (err != 0)
- goto abort;
-
- /* Update production data */
- first_block = (fw_entry->data +
- le16_to_cpu(hdr->headersize) +
- le32_to_cpu(hdr->pdr_offset));
-
- err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
- &pda[fw->pda_size / sizeof(*pda)]);
- dev_dbg(dev, "Apply PDA returned %d\n", err);
- if (err)
- goto abort;
-
- /* Tell card we've finished */
- err = hw->ops->program_end(hw);
- dev_dbg(dev, "Program end returned %d\n", err);
- if (err != 0)
- goto abort;
-
- /* Check if we're running */
- dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
-
-abort:
- /* If we requested the firmware, release it. */
- if (!orinoco_cached_fw_get(priv, false))
- release_firmware(fw_entry);
-
-free:
- kfree(pda);
- return err;
-}
-
-/*
- * Process a firmware image - stop the card, load the firmware, reset
- * the card and make sure it responds. For the secondary firmware take
- * care of the PDA - read it and then write it on top of the firmware.
- */
-static int
-symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
- const unsigned char *image, const void *end,
- int secondary)
-{
- struct hermes *hw = &priv->hw;
- int ret = 0;
- const unsigned char *ptr;
- const unsigned char *first_block;
-
- /* Plug Data Area (PDA) */
- __le16 *pda = NULL;
-
- /* Binary block begins after the 0x1A marker */
- ptr = image;
- while (*ptr++ != TEXT_END);
- first_block = ptr;
-
- /* Read the PDA from EEPROM */
- if (secondary) {
- pda = kzalloc(fw->pda_size, GFP_KERNEL);
- if (!pda)
- return -ENOMEM;
-
- ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
- if (ret)
- goto free;
- }
-
- /* Stop the firmware, so that it can be safely rewritten */
- if (priv->stop_fw) {
- ret = priv->stop_fw(priv, 1);
- if (ret)
- goto free;
- }
-
- /* Program the adapter with new firmware */
- ret = hermes_program(hw, first_block, end);
- if (ret)
- goto free;
-
- /* Write the PDA to the adapter */
- if (secondary) {
- size_t len = hermes_blocks_length(first_block, end);
- ptr = first_block + len;
- ret = hermes_apply_pda(hw, ptr, end, pda,
- &pda[fw->pda_size / sizeof(*pda)]);
- kfree(pda);
- if (ret)
- return ret;
- }
-
- /* Run the firmware */
- if (priv->stop_fw) {
- ret = priv->stop_fw(priv, 0);
- if (ret)
- return ret;
- }
-
- /* Reset hermes chip and make sure it responds */
- ret = hw->ops->init(hw);
-
- /* hermes_reset() should return 0 with the secondary firmware */
- if (secondary && ret != 0)
- return -ENODEV;
-
- /* And this should work with any firmware */
- if (!hermes_present(hw))
- return -ENODEV;
-
- return 0;
-
-free:
- kfree(pda);
- return ret;
-}
-
-
-/*
- * Download the firmware into the card, this also does a PCMCIA soft
- * reset on the card, to make sure it's in a sane state.
- */
-static int
-symbol_dl_firmware(struct orinoco_private *priv,
- const struct fw_info *fw)
-{
- struct device *dev = priv->dev;
- int ret;
- const struct firmware *fw_entry;
-
- if (!orinoco_cached_fw_get(priv, true)) {
- if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
- dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
- return -ENOENT;
- }
- } else
- fw_entry = orinoco_cached_fw_get(priv, true);
-
- /* Load primary firmware */
- ret = symbol_dl_image(priv, fw, fw_entry->data,
- fw_entry->data + fw_entry->size, 0);
-
- if (!orinoco_cached_fw_get(priv, true))
- release_firmware(fw_entry);
- if (ret) {
- dev_err(dev, "Primary firmware download failed\n");
- return ret;
- }
-
- if (!orinoco_cached_fw_get(priv, false)) {
- if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
- dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
- return -ENOENT;
- }
- } else
- fw_entry = orinoco_cached_fw_get(priv, false);
-
- /* Load secondary firmware */
- ret = symbol_dl_image(priv, fw, fw_entry->data,
- fw_entry->data + fw_entry->size, 1);
- if (!orinoco_cached_fw_get(priv, false))
- release_firmware(fw_entry);
- if (ret)
- dev_err(dev, "Secondary firmware download failed\n");
-
- return ret;
-}
-
-int orinoco_download(struct orinoco_private *priv)
-{
- int err = 0;
- /* Reload firmware */
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* case FIRMWARE_TYPE_INTERSIL: */
- err = orinoco_dl_firmware(priv,
- &orinoco_fw[priv->firmware_type], 0);
- break;
-
- case FIRMWARE_TYPE_SYMBOL:
- err = symbol_dl_firmware(priv,
- &orinoco_fw[priv->firmware_type]);
- break;
- case FIRMWARE_TYPE_INTERSIL:
- break;
- }
- /* TODO: if we fail we probably need to reinitialise
- * the driver */
-
- return err;
-}
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
-void orinoco_cache_fw(struct orinoco_private *priv, int ap)
-{
- const struct firmware *fw_entry = NULL;
- const char *pri_fw;
- const char *fw;
-
- pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
- if (ap)
- fw = orinoco_fw[priv->firmware_type].ap_fw;
- else
- fw = orinoco_fw[priv->firmware_type].sta_fw;
-
- if (pri_fw) {
- if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
- priv->cached_pri_fw = fw_entry;
- }
-
- if (fw) {
- if (request_firmware(&fw_entry, fw, priv->dev) == 0)
- priv->cached_fw = fw_entry;
- }
-}
-
-void orinoco_uncache_fw(struct orinoco_private *priv)
-{
- release_firmware(priv->cached_pri_fw);
- release_firmware(priv->cached_fw);
- priv->cached_pri_fw = NULL;
- priv->cached_fw = NULL;
-}
-#endif
diff --git a/drivers/net/wireless/intersil/orinoco/fw.h b/drivers/net/wireless/intersil/orinoco/fw.h
deleted file mode 100644
index aca63e3c4b5b6..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/fw.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Firmware file reading and download helpers
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_FW_H_
-#define _ORINOCO_FW_H_
-
-/* Forward declations */
-struct orinoco_private;
-
-int orinoco_download(struct orinoco_private *priv);
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
-void orinoco_cache_fw(struct orinoco_private *priv, int ap);
-void orinoco_uncache_fw(struct orinoco_private *priv);
-#else
-#define orinoco_cache_fw(priv, ap) do { } while (0)
-#define orinoco_uncache_fw(priv) do { } while (0)
-#endif
-
-#endif /* _ORINOCO_FW_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/hermes.c b/drivers/net/wireless/intersil/orinoco/hermes.c
deleted file mode 100644
index 4888286727ff1..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes.c
+++ /dev/null
@@ -1,778 +0,0 @@
-/* hermes.c
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
- * particular order).
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia.
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#include <linux/net.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-
-#include "hermes.h"
-
-/* These are maximum timeouts. Most often, card wil react much faster */
-#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
-#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
-#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
-#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
-
-/*
- * AUX port access. To unlock the AUX port write the access keys to the
- * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
- * register. Then read it and make sure it's HERMES_AUX_ENABLED.
- */
-#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
-#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
-#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
-#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
-
-#define HERMES_AUX_PW0 0xFE01
-#define HERMES_AUX_PW1 0xDC23
-#define HERMES_AUX_PW2 0xBA45
-
-/* HERMES_CMD_DOWNLD */
-#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
-#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
-
-/*
- * Debugging helpers
- */
-
-#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
- printk(stuff); } while (0)
-
-#undef HERMES_DEBUG
-#ifdef HERMES_DEBUG
-
-#define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff)
-
-#else /* ! HERMES_DEBUG */
-
-#define DEBUG(lvl, stuff...) do { } while (0)
-
-#endif /* ! HERMES_DEBUG */
-
-static const struct hermes_ops hermes_ops_local;
-
-/*
- * Internal functions
- */
-
-/* Issue a command to the chip. Waiting for it to complete is the caller's
- problem.
-
- Returns -EBUSY if the command register is busy, 0 on success.
-
- Callable from any context.
-*/
-static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0,
- u16 param1, u16 param2)
-{
- int k = CMD_BUSY_TIMEOUT;
- u16 reg;
-
- /* First wait for the command register to unbusy */
- reg = hermes_read_regn(hw, CMD);
- while ((reg & HERMES_CMD_BUSY) && k) {
- k--;
- udelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
- if (reg & HERMES_CMD_BUSY)
- return -EBUSY;
-
- hermes_write_regn(hw, PARAM2, param2);
- hermes_write_regn(hw, PARAM1, param1);
- hermes_write_regn(hw, PARAM0, param0);
- hermes_write_regn(hw, CMD, cmd);
-
- return 0;
-}
-
-/*
- * Function definitions
- */
-
-/* For doing cmds that wipe the magic constant in SWSUPPORT0 */
-static int hermes_doicmd_wait(struct hermes *hw, u16 cmd,
- u16 parm0, u16 parm1, u16 parm2,
- struct hermes_response *resp)
-{
- int err = 0;
- int k;
- u16 status, reg;
-
- err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
- if (err)
- return err;
-
- reg = hermes_read_regn(hw, EVSTAT);
- k = CMD_INIT_TIMEOUT;
- while ((!(reg & HERMES_EV_CMD)) && k) {
- k--;
- udelay(10);
- reg = hermes_read_regn(hw, EVSTAT);
- }
-
- hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
-
- if (!hermes_present(hw)) {
- DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
- hw->iobase);
- err = -ENODEV;
- goto out;
- }
-
- if (!(reg & HERMES_EV_CMD)) {
- printk(KERN_ERR "hermes @ %p: "
- "Timeout waiting for card to reset (reg=0x%04x)!\n",
- hw->iobase, reg);
- err = -ETIMEDOUT;
- goto out;
- }
-
- status = hermes_read_regn(hw, STATUS);
- if (resp) {
- resp->status = status;
- resp->resp0 = hermes_read_regn(hw, RESP0);
- resp->resp1 = hermes_read_regn(hw, RESP1);
- resp->resp2 = hermes_read_regn(hw, RESP2);
- }
-
- hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
- if (status & HERMES_STATUS_RESULT)
- err = -EIO;
-out:
- return err;
-}
-
-void hermes_struct_init(struct hermes *hw, void __iomem *address,
- int reg_spacing)
-{
- hw->iobase = address;
- hw->reg_spacing = reg_spacing;
- hw->inten = 0x0;
- hw->eeprom_pda = false;
- hw->ops = &hermes_ops_local;
-}
-EXPORT_SYMBOL(hermes_struct_init);
-
-static int hermes_init(struct hermes *hw)
-{
- u16 reg;
- int err = 0;
- int k;
-
- /* We don't want to be interrupted while resetting the chipset */
- hw->inten = 0x0;
- hermes_write_regn(hw, INTEN, 0);
- hermes_write_regn(hw, EVACK, 0xffff);
-
- /* Normally it's a "can't happen" for the command register to
- be busy when we go to issue a command because we are
- serializing all commands. However we want to have some
- chance of resetting the card even if it gets into a stupid
- state, so we actually wait to see if the command register
- will unbusy itself here. */
- k = CMD_BUSY_TIMEOUT;
- reg = hermes_read_regn(hw, CMD);
- while (k && (reg & HERMES_CMD_BUSY)) {
- if (reg == 0xffff) /* Special case - the card has probably been
- removed, so don't wait for the timeout */
- return -ENODEV;
-
- k--;
- udelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* No need to explicitly handle the timeout - if we've timed
- out hermes_issue_cmd() will probably return -EBUSY below */
-
- /* According to the documentation, EVSTAT may contain
- obsolete event occurrence information. We have to acknowledge
- it by writing EVACK. */
- reg = hermes_read_regn(hw, EVSTAT);
- hermes_write_regn(hw, EVACK, reg);
-
- /* We don't use hermes_docmd_wait here, because the reset wipes
- the magic constant in SWSUPPORT0 away, and it gets confused */
- err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
-
- return err;
-}
-
-/* Issue a command to the chip, and (busy!) wait for it to
- * complete.
- *
- * Returns:
- * < 0 on internal error
- * 0 on success
- * > 0 on error returned by the firmware
- *
- * Callable from any context, but locking is your problem. */
-static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp)
-{
- int err;
- int k;
- u16 reg;
- u16 status;
-
- err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
- if (err) {
- if (!hermes_present(hw)) {
- if (net_ratelimit())
- printk(KERN_WARNING "hermes @ %p: "
- "Card removed while issuing command "
- "0x%04x.\n", hw->iobase, cmd);
- err = -ENODEV;
- } else
- if (net_ratelimit())
- printk(KERN_ERR "hermes @ %p: "
- "Error %d issuing command 0x%04x.\n",
- hw->iobase, err, cmd);
- goto out;
- }
-
- reg = hermes_read_regn(hw, EVSTAT);
- k = CMD_COMPL_TIMEOUT;
- while ((!(reg & HERMES_EV_CMD)) && k) {
- k--;
- udelay(10);
- reg = hermes_read_regn(hw, EVSTAT);
- }
-
- if (!hermes_present(hw)) {
- printk(KERN_WARNING "hermes @ %p: Card removed "
- "while waiting for command 0x%04x completion.\n",
- hw->iobase, cmd);
- err = -ENODEV;
- goto out;
- }
-
- if (!(reg & HERMES_EV_CMD)) {
- printk(KERN_ERR "hermes @ %p: Timeout waiting for "
- "command 0x%04x completion.\n", hw->iobase, cmd);
- err = -ETIMEDOUT;
- goto out;
- }
-
- status = hermes_read_regn(hw, STATUS);
- if (resp) {
- resp->status = status;
- resp->resp0 = hermes_read_regn(hw, RESP0);
- resp->resp1 = hermes_read_regn(hw, RESP1);
- resp->resp2 = hermes_read_regn(hw, RESP2);
- }
-
- hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
-
- if (status & HERMES_STATUS_RESULT)
- err = -EIO;
-
- out:
- return err;
-}
-
-static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid)
-{
- int err = 0;
- int k;
- u16 reg;
-
- if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))
- return -EINVAL;
-
- err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
- if (err)
- return err;
-
- reg = hermes_read_regn(hw, EVSTAT);
- k = ALLOC_COMPL_TIMEOUT;
- while ((!(reg & HERMES_EV_ALLOC)) && k) {
- k--;
- udelay(10);
- reg = hermes_read_regn(hw, EVSTAT);
- }
-
- if (!hermes_present(hw)) {
- printk(KERN_WARNING "hermes @ %p: "
- "Card removed waiting for frame allocation.\n",
- hw->iobase);
- return -ENODEV;
- }
-
- if (!(reg & HERMES_EV_ALLOC)) {
- printk(KERN_ERR "hermes @ %p: "
- "Timeout waiting for frame allocation\n",
- hw->iobase);
- return -ETIMEDOUT;
- }
-
- *fid = hermes_read_regn(hw, ALLOCFID);
- hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
-
- return 0;
-}
-
-/* Set up a BAP to read a particular chunk of data from card's internal buffer.
- *
- * Returns:
- * < 0 on internal failure (errno)
- * 0 on success
- * > 0 on error
- * from firmware
- *
- * Callable from any context */
-static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset)
-{
- int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
- int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
- int k;
- u16 reg;
-
- /* Paranoia.. */
- if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2))
- return -EINVAL;
-
- k = HERMES_BAP_BUSY_TIMEOUT;
- reg = hermes_read_reg(hw, oreg);
- while ((reg & HERMES_OFFSET_BUSY) && k) {
- k--;
- udelay(1);
- reg = hermes_read_reg(hw, oreg);
- }
-
- if (reg & HERMES_OFFSET_BUSY)
- return -ETIMEDOUT;
-
- /* Now we actually set up the transfer */
- hermes_write_reg(hw, sreg, id);
- hermes_write_reg(hw, oreg, offset);
-
- /* Wait for the BAP to be ready */
- k = HERMES_BAP_BUSY_TIMEOUT;
- reg = hermes_read_reg(hw, oreg);
- while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
- k--;
- udelay(1);
- reg = hermes_read_reg(hw, oreg);
- }
-
- if (reg != offset) {
- printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
- "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
- (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
- reg, id, offset);
-
- if (reg & HERMES_OFFSET_BUSY)
- return -ETIMEDOUT;
-
- return -EIO; /* error or wrong offset */
- }
-
- return 0;
-}
-
-/* Read a block of data from the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem. len
- * must be even.
- *
- * Returns:
- * < 0 on internal failure (errno)
- * 0 on success
- * > 0 on error from firmware
- */
-static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len,
- u16 id, u16 offset)
-{
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- int err = 0;
-
- if ((len < 0) || (len % 2))
- return -EINVAL;
-
- err = hermes_bap_seek(hw, bap, id, offset);
- if (err)
- goto out;
-
- /* Actually do the transfer */
- hermes_read_words(hw, dreg, buf, len / 2);
-
- out:
- return err;
-}
-
-/* Write a block of data to the chip's buffer, via the
- * BAP. Synchronization/serialization is the caller's problem.
- *
- * Returns:
- * < 0 on internal failure (errno)
- * 0 on success
- * > 0 on error from firmware
- */
-static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf,
- int len, u16 id, u16 offset)
-{
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- int err = 0;
-
- if (len < 0)
- return -EINVAL;
-
- err = hermes_bap_seek(hw, bap, id, offset);
- if (err)
- goto out;
-
- /* Actually do the transfer */
- hermes_write_bytes(hw, dreg, buf, len);
-
- out:
- return err;
-}
-
-/* Read a Length-Type-Value record from the card.
- *
- * If length is NULL, we ignore the length read from the card, and
- * read the entire buffer regardless. This is useful because some of
- * the configuration records appear to have incorrect lengths in
- * practice.
- *
- * Callable from user or bh context. */
-static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf)
-{
- int err = 0;
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- u16 rlength, rtype;
- unsigned nwords;
-
- if (bufsize % 2)
- return -EINVAL;
-
- err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
- if (err)
- return err;
-
- err = hermes_bap_seek(hw, bap, rid, 0);
- if (err)
- return err;
-
- rlength = hermes_read_reg(hw, dreg);
-
- if (!rlength)
- return -ENODATA;
-
- rtype = hermes_read_reg(hw, dreg);
-
- if (length)
- *length = rlength;
-
- if (rtype != rid)
- printk(KERN_WARNING "hermes @ %p: %s(): "
- "rid (0x%04x) does not match type (0x%04x)\n",
- hw->iobase, __func__, rid, rtype);
- if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
- printk(KERN_WARNING "hermes @ %p: "
- "Truncating LTV record from %d to %d bytes. "
- "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
- HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
-
- nwords = min((unsigned)rlength - 1, bufsize / 2);
- hermes_read_words(hw, dreg, buf, nwords);
-
- return 0;
-}
-
-static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *value)
-{
- int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
- int err = 0;
- unsigned count;
-
- if (length == 0)
- return -EINVAL;
-
- err = hermes_bap_seek(hw, bap, rid, 0);
- if (err)
- return err;
-
- hermes_write_reg(hw, dreg, length);
- hermes_write_reg(hw, dreg, rid);
-
- count = length - 1;
-
- hermes_write_bytes(hw, dreg, value, count << 1);
-
- err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
- rid, NULL);
-
- return err;
-}
-
-/*** Hermes AUX control ***/
-
-static inline void
-hermes_aux_setaddr(struct hermes *hw, u32 addr)
-{
- hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
- hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
-}
-
-static inline int
-hermes_aux_control(struct hermes *hw, int enabled)
-{
- int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
- int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
- int i;
-
- /* Already open? */
- if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
- return 0;
-
- hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
- hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
- hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
- hermes_write_reg(hw, HERMES_CONTROL, action);
-
- for (i = 0; i < 20; i++) {
- udelay(10);
- if (hermes_read_reg(hw, HERMES_CONTROL) ==
- desired_state)
- return 0;
- }
-
- return -EBUSY;
-}
-
-/*** Hermes programming ***/
-
-/* About to start programming data (Hermes I)
- * offset is the entry point
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-static int hermesi_program_init(struct hermes *hw, u32 offset)
-{
- int err;
-
- /* Disable interrupts?*/
- /*hw->inten = 0x0;*/
- /*hermes_write_regn(hw, INTEN, 0);*/
- /*hermes_set_irqmask(hw, 0);*/
-
- /* Acknowledge any outstanding command */
- hermes_write_regn(hw, EVACK, 0xFFFF);
-
- /* Using init_cmd_wait rather than cmd_wait */
- err = hw->ops->init_cmd_wait(hw,
- 0x0100 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
- if (err)
- return err;
-
- err = hw->ops->init_cmd_wait(hw,
- 0x0000 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
- if (err)
- return err;
-
- err = hermes_aux_control(hw, 1);
- pr_debug("AUX enable returned %d\n", err);
-
- if (err)
- return err;
-
- pr_debug("Enabling volatile, EP 0x%08x\n", offset);
- err = hw->ops->init_cmd_wait(hw,
- HERMES_PROGRAM_ENABLE_VOLATILE,
- offset & 0xFFFFu,
- offset >> 16,
- 0,
- NULL);
- pr_debug("PROGRAM_ENABLE returned %d\n", err);
-
- return err;
-}
-
-/* Done programming data (Hermes I)
- *
- * Spectrum_cs' Symbol fw does not require this
- * wl_lkm Agere fw does
- * Don't know about intersil
- */
-static int hermesi_program_end(struct hermes *hw)
-{
- struct hermes_response resp;
- int rc = 0;
- int err;
-
- rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
-
- pr_debug("PROGRAM_DISABLE returned %d, "
- "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
- rc, resp.resp0, resp.resp1, resp.resp2);
-
- if ((rc == 0) &&
- ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
- rc = -EIO;
-
- err = hermes_aux_control(hw, 0);
- pr_debug("AUX disable returned %d\n", err);
-
- /* Acknowledge any outstanding command */
- hermes_write_regn(hw, EVACK, 0xFFFF);
-
- /* Reinitialise, ignoring return */
- (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
- 0, 0, 0, NULL);
-
- return rc ? rc : err;
-}
-
-static int hermes_program_bytes(struct hermes *hw, const char *data,
- u32 addr, u32 len)
-{
- /* wl lkm splits the programming into chunks of 2000 bytes.
- * This restriction appears to come from USB. The PCMCIA
- * adapters can program the whole lot in one go */
- hermes_aux_setaddr(hw, addr);
- hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
- return 0;
-}
-
-/* Read PDA from the adapter */
-static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr,
- u16 pda_len)
-{
- int ret;
- u16 pda_size;
- u16 data_len = pda_len;
- __le16 *data = pda;
-
- if (hw->eeprom_pda) {
- /* PDA of spectrum symbol is in eeprom */
-
- /* Issue command to read EEPROM */
- ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
- if (ret)
- return ret;
- } else {
- /* wl_lkm does not include PDA size in the PDA area.
- * We will pad the information into pda, so other routines
- * don't have to be modified */
- pda[0] = cpu_to_le16(pda_len - 2);
- /* Includes CFG_PROD_DATA but not itself */
- pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
- data_len = pda_len - 4;
- data = pda + 2;
- }
-
- /* Open auxiliary port */
- ret = hermes_aux_control(hw, 1);
- pr_debug("AUX enable returned %d\n", ret);
- if (ret)
- return ret;
-
- /* Read PDA */
- hermes_aux_setaddr(hw, pda_addr);
- hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
-
- /* Close aux port */
- ret = hermes_aux_control(hw, 0);
- pr_debug("AUX disable returned %d\n", ret);
-
- /* Check PDA length */
- pda_size = le16_to_cpu(pda[0]);
- pr_debug("Actual PDA length %d, Max allowed %d\n",
- pda_size, pda_len);
- if (pda_size > pda_len)
- return -EINVAL;
-
- return 0;
-}
-
-static void hermes_lock_irqsave(spinlock_t *lock,
- unsigned long *flags) __acquires(lock)
-{
- spin_lock_irqsave(lock, *flags);
-}
-
-static void hermes_unlock_irqrestore(spinlock_t *lock,
- unsigned long *flags) __releases(lock)
-{
- spin_unlock_irqrestore(lock, *flags);
-}
-
-static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
-{
- spin_lock_irq(lock);
-}
-
-static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
-{
- spin_unlock_irq(lock);
-}
-
-/* Hermes operations for local buses */
-static const struct hermes_ops hermes_ops_local = {
- .init = hermes_init,
- .cmd_wait = hermes_docmd_wait,
- .init_cmd_wait = hermes_doicmd_wait,
- .allocate = hermes_allocate,
- .read_ltv = hermes_read_ltv,
- .read_ltv_pr = hermes_read_ltv,
- .write_ltv = hermes_write_ltv,
- .bap_pread = hermes_bap_pread,
- .bap_pwrite = hermes_bap_pwrite,
- .read_pda = hermes_read_pda,
- .program_init = hermesi_program_init,
- .program_end = hermesi_program_end,
- .program = hermes_program_bytes,
- .lock_irqsave = hermes_lock_irqsave,
- .unlock_irqrestore = hermes_unlock_irqrestore,
- .lock_irq = hermes_lock_irq,
- .unlock_irq = hermes_unlock_irq,
-};
diff --git a/drivers/net/wireless/intersil/orinoco/hermes.h b/drivers/net/wireless/intersil/orinoco/hermes.h
deleted file mode 100644
index 3dc561a5cb7ae..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes.h
+++ /dev/null
@@ -1,534 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/* hermes.h
- *
- * Driver core for the "Hermes" wireless MAC controller, as used in
- * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
- * work on the hfa3841 and hfa3842 MAC controller chips used in the
- * Prism I & II chipsets.
- *
- * This is not a complete driver, just low-level access routines for
- * the MAC controller itself.
- *
- * Based on the prism2 driver from Absolute Value Systems' linux-wlan
- * project, the Linux wvlan_cs driver, Lucent's HCF-Light
- * (wvlan_hcf.c) library, and the NetBSD wireless driver.
- *
- * Copyright (C) 2000, David Gibson, Linuxcare Australia.
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- *
- * Portions taken from hfa384x.h.
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- */
-
-#ifndef _HERMES_H
-#define _HERMES_H
-
-/* Notes on locking:
- *
- * As a module of low level hardware access routines, there is no
- * locking. Users of this module should ensure that they serialize
- * access to the hermes structure, and to the hardware
-*/
-
-#include <linux/if_ether.h>
-#include <linux/io.h>
-
-/*
- * Limits and constants
- */
-#define HERMES_ALLOC_LEN_MIN (4)
-#define HERMES_ALLOC_LEN_MAX (2400)
-#define HERMES_LTV_LEN_MAX (34)
-#define HERMES_BAP_DATALEN_MAX (4096)
-#define HERMES_BAP_OFFSET_MAX (4096)
-#define HERMES_PORTID_MAX (7)
-#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX + 1)
-#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */
-#define HERMES_PDA_RECS_MAX (200) /* a guess */
-#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */
-#define HERMES_SCANRESULT_MAX (35)
-#define HERMES_CHINFORESULT_MAX (8)
-#define HERMES_MAX_MULTICAST (16)
-#define HERMES_MAGIC (0x7d1f)
-
-/*
- * Hermes register offsets
- */
-#define HERMES_CMD (0x00)
-#define HERMES_PARAM0 (0x02)
-#define HERMES_PARAM1 (0x04)
-#define HERMES_PARAM2 (0x06)
-#define HERMES_STATUS (0x08)
-#define HERMES_RESP0 (0x0A)
-#define HERMES_RESP1 (0x0C)
-#define HERMES_RESP2 (0x0E)
-#define HERMES_INFOFID (0x10)
-#define HERMES_RXFID (0x20)
-#define HERMES_ALLOCFID (0x22)
-#define HERMES_TXCOMPLFID (0x24)
-#define HERMES_SELECT0 (0x18)
-#define HERMES_OFFSET0 (0x1C)
-#define HERMES_DATA0 (0x36)
-#define HERMES_SELECT1 (0x1A)
-#define HERMES_OFFSET1 (0x1E)
-#define HERMES_DATA1 (0x38)
-#define HERMES_EVSTAT (0x30)
-#define HERMES_INTEN (0x32)
-#define HERMES_EVACK (0x34)
-#define HERMES_CONTROL (0x14)
-#define HERMES_SWSUPPORT0 (0x28)
-#define HERMES_SWSUPPORT1 (0x2A)
-#define HERMES_SWSUPPORT2 (0x2C)
-#define HERMES_AUXPAGE (0x3A)
-#define HERMES_AUXOFFSET (0x3C)
-#define HERMES_AUXDATA (0x3E)
-
-/*
- * CMD register bitmasks
- */
-#define HERMES_CMD_BUSY (0x8000)
-#define HERMES_CMD_AINFO (0x7f00)
-#define HERMES_CMD_MACPORT (0x0700)
-#define HERMES_CMD_RECL (0x0100)
-#define HERMES_CMD_WRITE (0x0100)
-#define HERMES_CMD_PROGMODE (0x0300)
-#define HERMES_CMD_CMDCODE (0x003f)
-
-/*
- * STATUS register bitmasks
- */
-#define HERMES_STATUS_RESULT (0x7f00)
-#define HERMES_STATUS_CMDCODE (0x003f)
-
-/*
- * OFFSET register bitmasks
- */
-#define HERMES_OFFSET_BUSY (0x8000)
-#define HERMES_OFFSET_ERR (0x4000)
-#define HERMES_OFFSET_DATAOFF (0x0ffe)
-
-/*
- * Event register bitmasks (INTEN, EVSTAT, EVACK)
- */
-#define HERMES_EV_TICK (0x8000)
-#define HERMES_EV_WTERR (0x4000)
-#define HERMES_EV_INFDROP (0x2000)
-#define HERMES_EV_INFO (0x0080)
-#define HERMES_EV_DTIM (0x0020)
-#define HERMES_EV_CMD (0x0010)
-#define HERMES_EV_ALLOC (0x0008)
-#define HERMES_EV_TXEXC (0x0004)
-#define HERMES_EV_TX (0x0002)
-#define HERMES_EV_RX (0x0001)
-
-/*
- * Command codes
- */
-/*--- Controller Commands ----------------------------*/
-#define HERMES_CMD_INIT (0x0000)
-#define HERMES_CMD_ENABLE (0x0001)
-#define HERMES_CMD_DISABLE (0x0002)
-#define HERMES_CMD_DIAG (0x0003)
-
-/*--- Buffer Mgmt Commands ---------------------------*/
-#define HERMES_CMD_ALLOC (0x000A)
-#define HERMES_CMD_TX (0x000B)
-
-/*--- Regulate Commands ------------------------------*/
-#define HERMES_CMD_NOTIFY (0x0010)
-#define HERMES_CMD_INQUIRE (0x0011)
-
-/*--- Configure Commands -----------------------------*/
-#define HERMES_CMD_ACCESS (0x0021)
-#define HERMES_CMD_DOWNLD (0x0022)
-
-/*--- Serial I/O Commands ----------------------------*/
-#define HERMES_CMD_READMIF (0x0030)
-#define HERMES_CMD_WRITEMIF (0x0031)
-
-/*--- Debugging Commands -----------------------------*/
-#define HERMES_CMD_TEST (0x0038)
-
-
-/* Test command arguments */
-#define HERMES_TEST_SET_CHANNEL 0x0800
-#define HERMES_TEST_MONITOR 0x0b00
-#define HERMES_TEST_STOP 0x0f00
-
-/* Authentication algorithms */
-#define HERMES_AUTH_OPEN 1
-#define HERMES_AUTH_SHARED_KEY 2
-
-/* WEP settings */
-#define HERMES_WEP_PRIVACY_INVOKED 0x0001
-#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002
-#define HERMES_WEP_HOST_ENCRYPT 0x0010
-#define HERMES_WEP_HOST_DECRYPT 0x0080
-
-/* Symbol hostscan options */
-#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001
-#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002
-#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040
-#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080
-
-/*
- * Frame structures and constants
- */
-
-#define HERMES_DESCRIPTOR_OFFSET 0
-#define HERMES_802_11_OFFSET (14)
-#define HERMES_802_3_OFFSET (14 + 32)
-#define HERMES_802_2_OFFSET (14 + 32 + 14)
-#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2)
-
-#define HERMES_RXSTAT_ERR (0x0003)
-#define HERMES_RXSTAT_BADCRC (0x0001)
-#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002)
-#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */
-#define HERMES_RXSTAT_MACPORT (0x0700)
-#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */
-#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */
-#define HERMES_RXSTAT_MSGTYPE (0xE000)
-#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */
-#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */
-#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */
-
-/* Shift amount for key ID in RXSTAT and TXCTRL */
-#define HERMES_MIC_KEY_ID_SHIFT 11
-
-struct hermes_tx_descriptor {
- __le16 status;
- __le16 reserved1;
- __le16 reserved2;
- __le32 sw_support;
- u8 retry_count;
- u8 tx_rate;
- __le16 tx_control;
-} __packed;
-
-#define HERMES_TXSTAT_RETRYERR (0x0001)
-#define HERMES_TXSTAT_AGEDERR (0x0002)
-#define HERMES_TXSTAT_DISCON (0x0004)
-#define HERMES_TXSTAT_FORMERR (0x0008)
-
-#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */
-#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */
-#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */
-#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */
-#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */
-#define HERMES_TXCTRL_ALT_RTRY (0x0020)
-
-/* Inquiry constants and data types */
-
-#define HERMES_INQ_TALLIES (0xF100)
-#define HERMES_INQ_SCAN (0xF101)
-#define HERMES_INQ_CHANNELINFO (0xF102)
-#define HERMES_INQ_HOSTSCAN (0xF103)
-#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104)
-#define HERMES_INQ_LINKSTATUS (0xF200)
-#define HERMES_INQ_SEC_STAT_AGERE (0xF202)
-
-struct hermes_tallies_frame {
- __le16 TxUnicastFrames;
- __le16 TxMulticastFrames;
- __le16 TxFragments;
- __le16 TxUnicastOctets;
- __le16 TxMulticastOctets;
- __le16 TxDeferredTransmissions;
- __le16 TxSingleRetryFrames;
- __le16 TxMultipleRetryFrames;
- __le16 TxRetryLimitExceeded;
- __le16 TxDiscards;
- __le16 RxUnicastFrames;
- __le16 RxMulticastFrames;
- __le16 RxFragments;
- __le16 RxUnicastOctets;
- __le16 RxMulticastOctets;
- __le16 RxFCSErrors;
- __le16 RxDiscards_NoBuffer;
- __le16 TxDiscardsWrongSA;
- __le16 RxWEPUndecryptable;
- __le16 RxMsgInMsgFragments;
- __le16 RxMsgInBadMsgFragments;
- /* Those last are probably not available in very old firmwares */
- __le16 RxDiscards_WEPICVError;
- __le16 RxDiscards_WEPExcluded;
-} __packed;
-
-/* Grabbed from wlan-ng - Thanks Mark... - Jean II
- * This is the result of a scan inquiry command */
-/* Structure describing info about an Access Point */
-struct prism2_scan_apinfo {
- __le16 channel; /* Channel where the AP sits */
- __le16 noise; /* Noise level */
- __le16 level; /* Signal level */
- u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- __le16 beacon_interv; /* Beacon interval */
- __le16 capabilities; /* Capabilities */
- __le16 essid_len; /* ESSID length */
- u8 essid[32]; /* ESSID of the network */
- u8 rates[10]; /* Bit rate supported */
- __le16 proberesp_rate; /* Data rate of the response frame */
- __le16 atim; /* ATIM window time, Kus (hostscan only) */
-} __packed;
-
-/* Same stuff for the Lucent/Agere card.
- * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
-struct agere_scan_apinfo {
- __le16 channel; /* Channel where the AP sits */
- __le16 noise; /* Noise level */
- __le16 level; /* Signal level */
- u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- __le16 beacon_interv; /* Beacon interval */
- __le16 capabilities; /* Capabilities */
- /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
- __le16 essid_len; /* ESSID length */
- u8 essid[32]; /* ESSID of the network */
-} __packed;
-
-/* Moustafa: Scan structure for Symbol cards */
-struct symbol_scan_apinfo {
- u8 channel; /* Channel where the AP sits */
- u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */
- __le16 noise; /* Noise level */
- __le16 level; /* Signal level */
- u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
- __le16 beacon_interv; /* Beacon interval */
- __le16 capabilities; /* Capabilities */
- /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
- __le16 essid_len; /* ESSID length */
- u8 essid[32]; /* ESSID of the network */
- __le16 rates[5]; /* Bit rate supported */
- __le16 basic_rates; /* Basic rates bitmask */
- u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */
- u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */
-} __packed;
-
-union hermes_scan_info {
- struct agere_scan_apinfo a;
- struct prism2_scan_apinfo p;
- struct symbol_scan_apinfo s;
-};
-
-/* Extended scan struct for HERMES_INQ_CHANNELINFO.
- * wl_lkm calls this an ACS scan (Automatic Channel Select).
- * Keep out of union hermes_scan_info because it is much bigger than
- * the older scan structures. */
-struct agere_ext_scan_info {
- __le16 reserved0;
-
- u8 noise;
- u8 level;
- u8 rx_flow;
- u8 rate;
- __le16 reserved1[2];
-
- __le16 frame_control;
- __le16 dur_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- __le16 sequence;
- u8 addr4[ETH_ALEN];
-
- __le16 data_length;
-
- /* Next 3 fields do not get filled in. */
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
- __le16 len_type;
-
- __le64 timestamp;
- __le16 beacon_interval;
- __le16 capabilities;
- u8 data[];
-} __packed;
-
-#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
-#define HERMES_LINKSTATUS_CONNECTED (0x0001)
-#define HERMES_LINKSTATUS_DISCONNECTED (0x0002)
-#define HERMES_LINKSTATUS_AP_CHANGE (0x0003)
-#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
-#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005)
-#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006)
-
-struct hermes_linkstatus {
- __le16 linkstatus; /* Link status */
-} __packed;
-
-struct hermes_response {
- u16 status, resp0, resp1, resp2;
-};
-
-/* "ID" structure - used for ESSID and station nickname */
-struct hermes_idstring {
- __le16 len;
- __le16 val[16];
-} __packed;
-
-struct hermes_multicast {
- u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __packed;
-
-/* Timeouts */
-#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
-
-struct hermes;
-
-/* Functions to access hardware */
-struct hermes_ops {
- int (*init)(struct hermes *hw);
- int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp);
- int (*init_cmd_wait)(struct hermes *hw, u16 cmd,
- u16 parm0, u16 parm1, u16 parm2,
- struct hermes_response *resp);
- int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
- int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
- u16 *length, void *buf);
- int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid,
- unsigned buflen, u16 *length, void *buf);
- int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *value);
- int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len,
- u16 id, u16 offset);
- int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
- int len, u16 id, u16 offset);
- int (*read_pda)(struct hermes *hw, __le16 *pda,
- u32 pda_addr, u16 pda_len);
- int (*program_init)(struct hermes *hw, u32 entry_point);
- int (*program_end)(struct hermes *hw);
- int (*program)(struct hermes *hw, const char *buf,
- u32 addr, u32 len);
- void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
- void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
- void (*lock_irq)(spinlock_t *lock);
- void (*unlock_irq)(spinlock_t *lock);
-};
-
-/* Basic control structure */
-struct hermes {
- void __iomem *iobase;
- int reg_spacing;
-#define HERMES_16BIT_REGSPACING 0
-#define HERMES_32BIT_REGSPACING 1
- u16 inten; /* Which interrupts should be enabled? */
- bool eeprom_pda;
- const struct hermes_ops *ops;
- void *priv;
-};
-
-/* Register access convenience macros */
-#define hermes_read_reg(hw, off) \
- (ioread16((hw)->iobase + ((off) << (hw)->reg_spacing)))
-#define hermes_write_reg(hw, off, val) \
- (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing)))
-#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name)
-#define hermes_write_regn(hw, name, val) \
- hermes_write_reg((hw), HERMES_##name, (val))
-
-/* Function prototypes */
-void hermes_struct_init(struct hermes *hw, void __iomem *address,
- int reg_spacing);
-
-/* Inline functions */
-
-static inline int hermes_present(struct hermes *hw)
-{
- return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
-}
-
-static inline void hermes_set_irqmask(struct hermes *hw, u16 events)
-{
- hw->inten = events;
- hermes_write_regn(hw, INTEN, events);
-}
-
-static inline int hermes_enable_port(struct hermes *hw, int port)
-{
- return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
- 0, NULL);
-}
-
-static inline int hermes_disable_port(struct hermes *hw, int port)
-{
- return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
- 0, NULL);
-}
-
-/* Initiate an INQUIRE command (tallies or scan). The result will come as an
- * information frame in __orinoco_ev_info() */
-static inline int hermes_inquire(struct hermes *hw, u16 rid)
-{
- return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
-}
-
-#define HERMES_BYTES_TO_RECLEN(n) ((((n) + 1) / 2) + 1)
-#define HERMES_RECLEN_TO_BYTES(n) (((n) - 1) * 2)
-
-/* Note that for the next two, the count is in 16-bit words, not bytes */
-static inline void hermes_read_words(struct hermes *hw, int off,
- void *buf, unsigned count)
-{
- off = off << hw->reg_spacing;
- ioread16_rep(hw->iobase + off, buf, count);
-}
-
-static inline void hermes_write_bytes(struct hermes *hw, int off,
- const char *buf, unsigned count)
-{
- off = off << hw->reg_spacing;
- iowrite16_rep(hw->iobase + off, buf, count >> 1);
- if (unlikely(count & 1))
- iowrite8(buf[count - 1], hw->iobase + off);
-}
-
-static inline void hermes_clear_words(struct hermes *hw, int off,
- unsigned count)
-{
- unsigned i;
-
- off = off << hw->reg_spacing;
-
- for (i = 0; i < count; i++)
- iowrite16(0, hw->iobase + off);
-}
-
-#define HERMES_READ_RECORD(hw, bap, rid, buf) \
- (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
-#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \
- (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
-#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
- (hw->ops->write_ltv((hw), (bap), (rid), \
- HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
-
-static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid,
- u16 *word)
-{
- __le16 rec;
- int err;
-
- err = HERMES_READ_RECORD(hw, bap, rid, &rec);
- *word = le16_to_cpu(rec);
- return err;
-}
-
-static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid,
- u16 *word)
-{
- __le16 rec;
- int err;
-
- err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec);
- *word = le16_to_cpu(rec);
- return err;
-}
-
-static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid,
- u16 word)
-{
- __le16 rec = cpu_to_le16(word);
- return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
-}
-
-#endif /* _HERMES_H */
diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.c b/drivers/net/wireless/intersil/orinoco/hermes_dld.c
deleted file mode 100644
index dbeadfcfefe26..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes_dld.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Hermes download helper.
- *
- * This helper:
- * - is capable of writing to the volatile area of the hermes device
- * - is currently not capable of writing to non-volatile areas
- * - provide helpers to identify and update plugin data
- * - is not capable of interpreting a fw image directly. That is up to
- * the main card driver.
- * - deals with Hermes I devices. It can probably be modified to deal
- * with Hermes II devices
- *
- * Copyright (C) 2007, David Kilroy
- *
- * Plug data code slightly modified from spectrum_cs driver
- * Copyright (C) 2002-2005 Pavel Roskin <[email protected]>
- * Portions based on information in wl_lkm_718 Agere driver
- * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include "hermes.h"
-#include "hermes_dld.h"
-
-#define PFX "hermes_dld: "
-
-/* End markers used in dblocks */
-#define PDI_END 0x00000000 /* End of PDA */
-#define BLOCK_END 0xFFFFFFFF /* Last image block */
-#define TEXT_END 0x1A /* End of text header */
-
-/*
- * The following structures have little-endian fields denoted by
- * the leading underscore. Don't access them directly - use inline
- * functions defined below.
- */
-
-/*
- * The binary image to be downloaded consists of series of data blocks.
- * Each block has the following structure.
- */
-struct dblock {
- __le32 addr; /* adapter address where to write the block */
- __le16 len; /* length of the data only, in bytes */
- char data[]; /* data to be written */
-} __packed;
-
-/*
- * Plug Data References are located in the image after the last data
- * block. They refer to areas in the adapter memory where the plug data
- * items with matching ID should be written.
- */
-struct pdr {
- __le32 id; /* record ID */
- __le32 addr; /* adapter address where to write the data */
- __le32 len; /* expected length of the data, in bytes */
- char next[]; /* next PDR starts here */
-} __packed;
-
-/*
- * Plug Data Items are located in the EEPROM read from the adapter by
- * primary firmware. They refer to the device-specific data that should
- * be plugged into the secondary firmware.
- */
-struct pdi {
- __le16 len; /* length of ID and data, in words */
- __le16 id; /* record ID */
- char data[]; /* plug data */
-} __packed;
-
-/*** FW data block access functions ***/
-
-static inline u32
-dblock_addr(const struct dblock *blk)
-{
- return le32_to_cpu(blk->addr);
-}
-
-static inline u32
-dblock_len(const struct dblock *blk)
-{
- return le16_to_cpu(blk->len);
-}
-
-/*** PDR Access functions ***/
-
-static inline u32
-pdr_id(const struct pdr *pdr)
-{
- return le32_to_cpu(pdr->id);
-}
-
-static inline u32
-pdr_addr(const struct pdr *pdr)
-{
- return le32_to_cpu(pdr->addr);
-}
-
-static inline u32
-pdr_len(const struct pdr *pdr)
-{
- return le32_to_cpu(pdr->len);
-}
-
-/*** PDI Access functions ***/
-
-static inline u32
-pdi_id(const struct pdi *pdi)
-{
- return le16_to_cpu(pdi->id);
-}
-
-/* Return length of the data only, in bytes */
-static inline u32
-pdi_len(const struct pdi *pdi)
-{
- return 2 * (le16_to_cpu(pdi->len) - 1);
-}
-
-/*** Plug Data Functions ***/
-
-/*
- * Scan PDR for the record with the specified RECORD_ID.
- * If it's not found, return NULL.
- */
-static const struct pdr *
-hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
-{
- const struct pdr *pdr = first_pdr;
-
- end -= sizeof(struct pdr);
-
- while (((void *) pdr <= end) &&
- (pdr_id(pdr) != PDI_END)) {
- /*
- * PDR area is currently not terminated by PDI_END.
- * It's followed by CRC records, which have the type
- * field where PDR has length. The type can be 0 or 1.
- */
- if (pdr_len(pdr) < 2)
- return NULL;
-
- /* If the record ID matches, we are done */
- if (pdr_id(pdr) == record_id)
- return pdr;
-
- pdr = (struct pdr *) pdr->next;
- }
- return NULL;
-}
-
-/* Scan production data items for a particular entry */
-static const struct pdi *
-hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
-{
- const struct pdi *pdi = first_pdi;
-
- end -= sizeof(struct pdi);
-
- while (((void *) pdi <= end) &&
- (pdi_id(pdi) != PDI_END)) {
-
- /* If the record ID matches, we are done */
- if (pdi_id(pdi) == record_id)
- return pdi;
-
- pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
- }
- return NULL;
-}
-
-/* Process one Plug Data Item - find corresponding PDR and plug it */
-static int
-hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr,
- const struct pdi *pdi, const void *pdr_end)
-{
- const struct pdr *pdr;
-
- /* Find the PDR corresponding to this PDI */
- pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
-
- /* No match is found, safe to ignore */
- if (!pdr)
- return 0;
-
- /* Lengths of the data in PDI and PDR must match */
- if (pdi_len(pdi) != pdr_len(pdr))
- return -EINVAL;
-
- /* do the actual plugging */
- hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
-
- return 0;
-}
-
-/* Parse PDA and write the records into the adapter
- *
- * Attempt to write every records that is in the specified pda
- * which also has a valid production data record for the firmware.
- */
-int hermes_apply_pda(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end)
-{
- int ret;
- const struct pdi *pdi;
- const struct pdr *pdr;
-
- pdr = (const struct pdr *) first_pdr;
- pda_end -= sizeof(struct pdi);
-
- /* Go through every PDI and plug them into the adapter */
- pdi = (const struct pdi *) (pda + 2);
- while (((void *) pdi <= pda_end) &&
- (pdi_id(pdi) != PDI_END)) {
- ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
- if (ret)
- return ret;
-
- /* Increment to the next PDI */
- pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
- }
- return 0;
-}
-
-/* Identify the total number of bytes in all blocks
- * including the header data.
- */
-size_t
-hermes_blocks_length(const char *first_block, const void *end)
-{
- const struct dblock *blk = (const struct dblock *) first_block;
- int total_len = 0;
- int len;
-
- end -= sizeof(*blk);
-
- /* Skip all blocks to locate Plug Data References
- * (Spectrum CS) */
- while (((void *) blk <= end) &&
- (dblock_addr(blk) != BLOCK_END)) {
- len = dblock_len(blk);
- total_len += sizeof(*blk) + len;
- blk = (struct dblock *) &blk->data[len];
- }
-
- return total_len;
-}
-
-/*** Hermes programming ***/
-
-/* Program the data blocks */
-int hermes_program(struct hermes *hw, const char *first_block, const void *end)
-{
- const struct dblock *blk;
- u32 blkaddr;
- u32 blklen;
- int err = 0;
-
- blk = (const struct dblock *) first_block;
-
- if ((void *) blk > (end - sizeof(*blk)))
- return -EIO;
-
- blkaddr = dblock_addr(blk);
- blklen = dblock_len(blk);
-
- while ((blkaddr != BLOCK_END) &&
- (((void *) blk + blklen) <= end)) {
- pr_debug(PFX "Programming block of length %d "
- "to address 0x%08x\n", blklen, blkaddr);
-
- err = hw->ops->program(hw, blk->data, blkaddr, blklen);
- if (err)
- break;
-
- blk = (const struct dblock *) &blk->data[blklen];
-
- if ((void *) blk > (end - sizeof(*blk)))
- return -EIO;
-
- blkaddr = dblock_addr(blk);
- blklen = dblock_len(blk);
- }
- return err;
-}
-
-/*** Default plugging data for Hermes I ***/
-/* Values from wl_lkm_718/hcf/dhf.c */
-
-#define DEFINE_DEFAULT_PDR(pid, length, data) \
-static const struct { \
- __le16 len; \
- __le16 id; \
- u8 val[length]; \
-} __packed default_pdr_data_##pid = { \
- cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
- sizeof(__le16)) - 1), \
- cpu_to_le16(pid), \
- data \
-}
-
-#define DEFAULT_PDR(pid) default_pdr_data_##pid
-
-/* HWIF Compatibility */
-DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
-
-/* PPPPSign */
-DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
-
-/* PPPPProf */
-DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
-
-/* Antenna diversity */
-DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
-
-/* Modem VCO band Set-up */
-DEFINE_DEFAULT_PDR(0x0160, 28,
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00\x00\x00\x00\x00"
- "\x00\x00\x00\x00");
-
-/* Modem Rx Gain Table Values */
-DEFINE_DEFAULT_PDR(0x0161, 256,
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
- "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
- "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
- "\x3B\x01\x3A\01\x3A\x01\x39\x01"
- "\x39\x01\x38\01\x38\x01\x37\x01"
- "\x37\x01\x36\01\x36\x01\x35\x01"
- "\x35\x01\x34\01\x34\x01\x33\x01"
- "\x33\x01\x32\x01\x32\x01\x31\x01"
- "\x31\x01\x30\x01\x30\x01\x7B\x01"
- "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
- "\x79\x01\x78\x01\x78\x01\x77\x01"
- "\x77\x01\x76\x01\x76\x01\x75\x01"
- "\x75\x01\x74\x01\x74\x01\x73\x01"
- "\x73\x01\x72\x01\x72\x01\x71\x01"
- "\x71\x01\x70\x01\x70\x01\x68\x01"
- "\x68\x01\x67\x01\x67\x01\x66\x01"
- "\x66\x01\x65\x01\x65\x01\x57\x01"
- "\x57\x01\x56\x01\x56\x01\x55\x01"
- "\x55\x01\x54\x01\x54\x01\x53\x01"
- "\x53\x01\x52\x01\x52\x01\x51\x01"
- "\x51\x01\x50\x01\x50\x01\x48\x01"
- "\x48\x01\x47\x01\x47\x01\x46\x01"
- "\x46\x01\x45\x01\x45\x01\x44\x01"
- "\x44\x01\x43\x01\x43\x01\x42\x01"
- "\x42\x01\x41\x01\x41\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01"
- "\x40\x01\x40\x01\x40\x01\x40\x01");
-
-/* Write PDA according to certain rules.
- *
- * For every production data record, look for a previous setting in
- * the pda, and use that.
- *
- * For certain records, use defaults if they are not found in pda.
- */
-int hermes_apply_pda_with_defaults(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end)
-{
- const struct pdr *pdr = (const struct pdr *) first_pdr;
- const struct pdi *first_pdi = (const struct pdi *) &pda[2];
- const struct pdi *pdi;
- const struct pdi *default_pdi = NULL;
- const struct pdi *outdoor_pdi;
- int record_id;
-
- pdr_end -= sizeof(struct pdr);
-
- while (((void *) pdr <= pdr_end) &&
- (pdr_id(pdr) != PDI_END)) {
- /*
- * For spectrum_cs firmwares,
- * PDR area is currently not terminated by PDI_END.
- * It's followed by CRC records, which have the type
- * field where PDR has length. The type can be 0 or 1.
- */
- if (pdr_len(pdr) < 2)
- break;
- record_id = pdr_id(pdr);
-
- pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
- if (pdi)
- pr_debug(PFX "Found record 0x%04x at %p\n",
- record_id, pdi);
-
- switch (record_id) {
- case 0x110: /* Modem REFDAC values */
- case 0x120: /* Modem VGDAC values */
- outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
- pda_end);
- default_pdi = NULL;
- if (outdoor_pdi) {
- pdi = outdoor_pdi;
- pr_debug(PFX
- "Using outdoor record 0x%04x at %p\n",
- record_id + 1, pdi);
- }
- break;
- case 0x5: /* HWIF Compatibility */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
- break;
- case 0x108: /* PPPPSign */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
- break;
- case 0x109: /* PPPPProf */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
- break;
- case 0x150: /* Antenna diversity */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
- break;
- case 0x160: /* Modem VCO band Set-up */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
- break;
- case 0x161: /* Modem Rx Gain Table Values */
- default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
- break;
- default:
- default_pdi = NULL;
- break;
- }
- if (!pdi && default_pdi) {
- /* Use default */
- pdi = default_pdi;
- pr_debug(PFX "Using default record 0x%04x at %p\n",
- record_id, pdi);
- }
-
- if (pdi) {
- /* Lengths of the data in PDI and PDR must match */
- if ((pdi_len(pdi) == pdr_len(pdr)) &&
- ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
- /* do the actual plugging */
- hw->ops->program(hw, pdi->data, pdr_addr(pdr),
- pdi_len(pdi));
- }
- }
-
- pdr++;
- }
- return 0;
-}
diff --git a/drivers/net/wireless/intersil/orinoco/hermes_dld.h b/drivers/net/wireless/intersil/orinoco/hermes_dld.h
deleted file mode 100644
index b5377e232c636..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes_dld.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2007, David Kilroy
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-#ifndef _HERMES_DLD_H
-#define _HERMES_DLD_H
-
-#include "hermes.h"
-
-int hermesi_program_init(struct hermes *hw, u32 offset);
-int hermesi_program_end(struct hermes *hw);
-int hermes_program(struct hermes *hw, const char *first_block, const void *end);
-
-int hermes_read_pda(struct hermes *hw,
- __le16 *pda,
- u32 pda_addr,
- u16 pda_len,
- int use_eeprom);
-int hermes_apply_pda(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end);
-int hermes_apply_pda_with_defaults(struct hermes *hw,
- const char *first_pdr,
- const void *pdr_end,
- const __le16 *pda,
- const void *pda_end);
-
-size_t hermes_blocks_length(const char *first_block, const void *end);
-
-#endif /* _HERMES_DLD_H */
diff --git a/drivers/net/wireless/intersil/orinoco/hermes_rid.h b/drivers/net/wireless/intersil/orinoco/hermes_rid.h
deleted file mode 100644
index 42eb67dea1df2..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/hermes_rid.h
+++ /dev/null
@@ -1,165 +0,0 @@
-#ifndef _HERMES_RID_H
-#define _HERMES_RID_H
-
-/*
- * Configuration RIDs
- */
-#define HERMES_RID_CNFPORTTYPE 0xFC00
-#define HERMES_RID_CNFOWNMACADDR 0xFC01
-#define HERMES_RID_CNFDESIREDSSID 0xFC02
-#define HERMES_RID_CNFOWNCHANNEL 0xFC03
-#define HERMES_RID_CNFOWNSSID 0xFC04
-#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05
-#define HERMES_RID_CNFSYSTEMSCALE 0xFC06
-#define HERMES_RID_CNFMAXDATALEN 0xFC07
-#define HERMES_RID_CNFWDSADDRESS 0xFC08
-#define HERMES_RID_CNFPMENABLED 0xFC09
-#define HERMES_RID_CNFPMEPS 0xFC0A
-#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B
-#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C
-#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D
-#define HERMES_RID_CNFOWNNAME 0xFC0E
-#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10
-#define HERMES_RID_CNFWDSADDRESS1 0xFC11
-#define HERMES_RID_CNFWDSADDRESS2 0xFC12
-#define HERMES_RID_CNFWDSADDRESS3 0xFC13
-#define HERMES_RID_CNFWDSADDRESS4 0xFC14
-#define HERMES_RID_CNFWDSADDRESS5 0xFC15
-#define HERMES_RID_CNFWDSADDRESS6 0xFC16
-#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17
-#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20
-#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21
-#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21
-#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22
-#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23
-#define HERMES_RID_CNFDEFAULTKEY0 0xFC24
-#define HERMES_RID_CNFDEFAULTKEY1 0xFC25
-#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25
-#define HERMES_RID_CNFDEFAULTKEY2 0xFC26
-#define HERMES_RID_CNFDEFAULTKEY3 0xFC27
-#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28
-#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
-#define HERMES_RID_CNFAUTHENTICATION 0xFC2A
-#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B
-#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B
-#define HERMES_RID_CNFTXCONTROL 0xFC2C
-#define HERMES_RID_CNFROAMINGMODE 0xFC2D
-#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E
-#define HERMES_RID_CNFRCVCRCERROR 0xFC30
-#define HERMES_RID_CNFMMLIFE 0xFC31
-#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32
-#define HERMES_RID_CNFBEACONINT 0xFC33
-#define HERMES_RID_CNFAPPCFINFO 0xFC34
-#define HERMES_RID_CNFSTAPCFINFO 0xFC35
-#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37
-#define HERMES_RID_CNFTIMCTRL 0xFC40
-#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42
-#define HERMES_RID_CNFENHSECURITY 0xFC43
-#define HERMES_RID_CNFGROUPADDRESSES 0xFC80
-#define HERMES_RID_CNFCREATEIBSS 0xFC81
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82
-#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83
-#define HERMES_RID_CNFTXRATECONTROL 0xFC84
-#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85
-#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A
-#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95
-#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96
-#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97
-#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98
-#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99
-#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A
-#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B
-#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C
-#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D
-#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB
-#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0
-#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0
-#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
-#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1
-#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
-#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2
-#define HERMES_RID_CNFBASICRATES 0xFCB3
-#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4
-#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4
-#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5
-#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6
-#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7
-#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8
-#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9
-#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA
-#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB
-#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2
-#define HERMES_RID_CNFDISASSOCIATE 0xFCC8
-#define HERMES_RID_CNFTICKTIME 0xFCE0
-#define HERMES_RID_CNFSCANREQUEST 0xFCE1
-#define HERMES_RID_CNFJOINREQUEST 0xFCE2
-#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3
-#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4
-#define HERMES_RID_CNFHOSTSCAN 0xFCE5
-
-/*
- * Information RIDs
- */
-#define HERMES_RID_MAXLOADTIME 0xFD00
-#define HERMES_RID_DOWNLOADBUFFER 0xFD01
-#define HERMES_RID_PRIID 0xFD02
-#define HERMES_RID_PRISUPRANGE 0xFD03
-#define HERMES_RID_CFIACTRANGES 0xFD04
-#define HERMES_RID_NICSERNUM 0xFD0A
-#define HERMES_RID_NICID 0xFD0B
-#define HERMES_RID_MFISUPRANGE 0xFD0C
-#define HERMES_RID_CFISUPRANGE 0xFD0D
-#define HERMES_RID_CHANNELLIST 0xFD10
-#define HERMES_RID_REGULATORYDOMAINS 0xFD11
-#define HERMES_RID_TEMPTYPE 0xFD12
-#define HERMES_RID_CIS 0xFD13
-#define HERMES_RID_STAID 0xFD20
-#define HERMES_RID_STASUPRANGE 0xFD21
-#define HERMES_RID_MFIACTRANGES 0xFD22
-#define HERMES_RID_CFIACTRANGES2 0xFD23
-#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24
-#define HERMES_RID_PORTSTATUS 0xFD40
-#define HERMES_RID_CURRENTSSID 0xFD41
-#define HERMES_RID_CURRENTBSSID 0xFD42
-#define HERMES_RID_COMMSQUALITY 0xFD43
-#define HERMES_RID_CURRENTTXRATE 0xFD44
-#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45
-#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46
-#define HERMES_RID_PROTOCOLRSPTIME 0xFD47
-#define HERMES_RID_SHORTRETRYLIMIT 0xFD48
-#define HERMES_RID_LONGRETRYLIMIT 0xFD49
-#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A
-#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B
-#define HERMES_RID_CFPOLLABLE 0xFD4C
-#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D
-#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
-#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51
-#define HERMES_RID_CURRENTTXRATE1 0xFD80
-#define HERMES_RID_CURRENTTXRATE2 0xFD81
-#define HERMES_RID_CURRENTTXRATE3 0xFD82
-#define HERMES_RID_CURRENTTXRATE4 0xFD83
-#define HERMES_RID_CURRENTTXRATE5 0xFD84
-#define HERMES_RID_CURRENTTXRATE6 0xFD85
-#define HERMES_RID_OWNMACADDR 0xFD86
-#define HERMES_RID_SCANRESULTSTABLE 0xFD88
-#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89
-#define HERMES_RID_CURRENT_WPA_IE 0xFD8A
-#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B
-#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C
-#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D
-#define HERMES_RID_TXQUEUEEMPTY 0xFD91
-#define HERMES_RID_PHYTYPE 0xFDC0
-#define HERMES_RID_CURRENTCHANNEL 0xFDC1
-#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2
-#define HERMES_RID_CCAMODE 0xFDC3
-#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6
-#define HERMES_RID_BUILDSEQ 0xFFFE
-#define HERMES_RID_FWID 0xFFFF
-
-#endif
diff --git a/drivers/net/wireless/intersil/orinoco/hw.c b/drivers/net/wireless/intersil/orinoco/hw.c
deleted file mode 100644
index 4fcca08e50de2..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/hw.c
+++ /dev/null
@@ -1,1362 +0,0 @@
-/* Encapsulate basic setting changes and retrieval on Hermes hardware
- *
- * See copyright notice in main.c
- */
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/if_arp.h>
-#include <linux/ieee80211.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-#include "hermes.h"
-#include "hermes_rid.h"
-#include "orinoco.h"
-
-#include "hw.h"
-
-#define SYMBOL_MAX_VER_LEN (14)
-
-/* Symbol firmware has a bug allocating buffers larger than this */
-#define TX_NICBUF_SIZE_BUG 1585
-
-/********************************************************************/
-/* Data tables */
-/********************************************************************/
-
-/* This tables gives the actual meanings of the bitrate IDs returned
- * by the firmware. */
-static const struct {
- int bitrate; /* in 100s of kilobits */
- int automatic;
- u16 agere_txratectrl;
- u16 intersil_txratectrl;
-} bitrate_table[] = {
- {110, 1, 3, 15}, /* Entry 0 is the default */
- {10, 0, 1, 1},
- {10, 1, 1, 1},
- {20, 0, 2, 2},
- {20, 1, 6, 3},
- {55, 0, 4, 4},
- {55, 1, 7, 7},
- {110, 0, 5, 8},
-};
-#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
-
-/* Firmware version encoding */
-struct comp_id {
- u16 id, variant, major, minor;
-} __packed;
-
-static inline enum fwtype determine_firmware_type(struct comp_id *nic_id)
-{
- if (nic_id->id < 0x8000)
- return FIRMWARE_TYPE_AGERE;
- else if (nic_id->id == 0x8000 && nic_id->major == 0)
- return FIRMWARE_TYPE_SYMBOL;
- else
- return FIRMWARE_TYPE_INTERSIL;
-}
-
-/* Set priv->firmware type, determine firmware properties
- * This function can be called before we have registerred with netdev,
- * so all errors go out with dev_* rather than printk
- *
- * If non-NULL stores a firmware description in fw_name.
- * If non-NULL stores a HW version in hw_ver
- *
- * These are output via generic cfg80211 ethtool support.
- */
-int determine_fw_capabilities(struct orinoco_private *priv,
- char *fw_name, size_t fw_name_len,
- u32 *hw_ver)
-{
- struct device *dev = priv->dev;
- struct hermes *hw = &priv->hw;
- int err;
- struct comp_id nic_id, sta_id;
- unsigned int firmver;
- char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2)));
-
- /* Get the hardware version */
- err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
- if (err) {
- dev_err(dev, "Cannot read hardware identity: error %d\n",
- err);
- return err;
- }
-
- le16_to_cpus(&nic_id.id);
- le16_to_cpus(&nic_id.variant);
- le16_to_cpus(&nic_id.major);
- le16_to_cpus(&nic_id.minor);
- dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
- nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
-
- if (hw_ver)
- *hw_ver = (((nic_id.id & 0xff) << 24) |
- ((nic_id.variant & 0xff) << 16) |
- ((nic_id.major & 0xff) << 8) |
- (nic_id.minor & 0xff));
-
- priv->firmware_type = determine_firmware_type(&nic_id);
-
- /* Get the firmware version */
- err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
- if (err) {
- dev_err(dev, "Cannot read station identity: error %d\n",
- err);
- return err;
- }
-
- le16_to_cpus(&sta_id.id);
- le16_to_cpus(&sta_id.variant);
- le16_to_cpus(&sta_id.major);
- le16_to_cpus(&sta_id.minor);
- dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n",
- sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
-
- switch (sta_id.id) {
- case 0x15:
- dev_err(dev, "Primary firmware is active\n");
- return -ENODEV;
- case 0x14b:
- dev_err(dev, "Tertiary firmware is active\n");
- return -ENODEV;
- case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
- case 0x21: /* Symbol Spectrum24 Trilogy */
- break;
- default:
- dev_notice(dev, "Unknown station ID, please report\n");
- break;
- }
-
- /* Default capabilities */
- priv->has_sensitivity = 1;
- priv->has_mwo = 0;
- priv->has_preamble = 0;
- priv->has_port3 = 1;
- priv->has_ibss = 1;
- priv->has_wep = 0;
- priv->has_big_wep = 0;
- priv->has_alt_txcntl = 0;
- priv->has_ext_scan = 0;
- priv->has_wpa = 0;
- priv->do_fw_download = 0;
-
- /* Determine capabilities from the firmware version */
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
- ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
- if (fw_name)
- snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d",
- sta_id.major, sta_id.minor);
-
- firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
-
- priv->has_ibss = (firmver >= 0x60006);
- priv->has_wep = (firmver >= 0x40020);
- priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
- Gold cards from the others? */
- priv->has_mwo = (firmver >= 0x60000);
- priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
- priv->ibss_port = 1;
- priv->has_hostscan = (firmver >= 0x8000a);
- priv->do_fw_download = 1;
- priv->broken_monitor = (firmver >= 0x80000);
- priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
- priv->has_wpa = (firmver >= 0x9002a);
- /* Tested with Agere firmware :
- * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
- * Tested CableTron firmware : 4.32 => Anton */
- break;
- case FIRMWARE_TYPE_SYMBOL:
- /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
- /* Intel MAC : 00:02:B3:* */
- /* 3Com MAC : 00:50:DA:* */
- memset(tmp, 0, sizeof(tmp));
- /* Get the Symbol firmware version */
- err = hw->ops->read_ltv_pr(hw, USER_BAP,
- HERMES_RID_SECONDARYVERSION_SYMBOL,
- SYMBOL_MAX_VER_LEN, NULL, &tmp);
- if (err) {
- dev_warn(dev, "Error %d reading Symbol firmware info. "
- "Wildly guessing capabilities...\n", err);
- firmver = 0;
- tmp[0] = '\0';
- } else {
- /* The firmware revision is a string, the format is
- * something like : "V2.20-01".
- * Quick and dirty parsing... - Jean II
- */
- firmver = ((tmp[1] - '0') << 16)
- | ((tmp[3] - '0') << 12)
- | ((tmp[4] - '0') << 8)
- | ((tmp[6] - '0') << 4)
- | (tmp[7] - '0');
-
- tmp[SYMBOL_MAX_VER_LEN] = '\0';
- }
-
- if (fw_name)
- snprintf(fw_name, fw_name_len, "Symbol %s", tmp);
-
- priv->has_ibss = (firmver >= 0x20000);
- priv->has_wep = (firmver >= 0x15012);
- priv->has_big_wep = (firmver >= 0x20000);
- priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
- (firmver >= 0x29000 && firmver < 0x30000) ||
- firmver >= 0x31000;
- priv->has_preamble = (firmver >= 0x20000);
- priv->ibss_port = 4;
-
- /* Symbol firmware is found on various cards, but
- * there has been no attempt to check firmware
- * download on non-spectrum_cs based cards.
- *
- * Given that the Agere firmware download works
- * differently, we should avoid doing a firmware
- * download with the Symbol algorithm on non-spectrum
- * cards.
- *
- * For now we can identify a spectrum_cs based card
- * because it has a firmware reset function.
- */
- priv->do_fw_download = (priv->stop_fw != NULL);
-
- priv->broken_disableport = (firmver == 0x25013) ||
- (firmver >= 0x30000 && firmver <= 0x31000);
- priv->has_hostscan = (firmver >= 0x31001) ||
- (firmver >= 0x29057 && firmver < 0x30000);
- /* Tested with Intel firmware : 0x20015 => Jean II */
- /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- /* D-Link, Linksys, Adtron, ZoomAir, and many others...
- * Samsung, Compaq 100/200 and Proxim are slightly
- * different and less well tested */
- /* D-Link MAC : 00:40:05:* */
- /* Addtron MAC : 00:90:D1:* */
- if (fw_name)
- snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d",
- sta_id.major, sta_id.minor, sta_id.variant);
-
- firmver = ((unsigned long)sta_id.major << 16) |
- ((unsigned long)sta_id.minor << 8) | sta_id.variant;
-
- priv->has_ibss = (firmver >= 0x000700); /* FIXME */
- priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
- priv->has_pm = (firmver >= 0x000700);
- priv->has_hostscan = (firmver >= 0x010301);
-
- if (firmver >= 0x000800)
- priv->ibss_port = 0;
- else {
- dev_notice(dev, "Intersil firmware earlier than v0.8.x"
- " - several features not supported\n");
- priv->ibss_port = 1;
- }
- break;
- }
- if (fw_name)
- dev_info(dev, "Firmware determined as %s\n", fw_name);
-
-#ifndef CONFIG_HERMES_PRISM
- if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
- dev_err(dev, "Support for Prism chipset is not enabled\n");
- return -ENODEV;
- }
-#endif
-
- return 0;
-}
-
-/* Read settings from EEPROM into our private structure.
- * MAC address gets dropped into callers buffer
- * Can be called before netdev registration.
- */
-int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
-{
- struct device *dev = priv->dev;
- struct hermes_idstring nickbuf;
- struct hermes *hw = &priv->hw;
- int len;
- int err;
- u16 reclen;
-
- /* Get the MAC address */
- err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- ETH_ALEN, NULL, dev_addr);
- if (err) {
- dev_warn(dev, "Failed to read MAC address!\n");
- goto out;
- }
-
- dev_dbg(dev, "MAC address %pM\n", dev_addr);
-
- /* Get the station name */
- err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- sizeof(nickbuf), &reclen, &nickbuf);
- if (err) {
- dev_err(dev, "failed to read station name\n");
- goto out;
- }
- if (nickbuf.len)
- len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
- else
- len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
- memcpy(priv->nick, &nickbuf.val, len);
- priv->nick[len] = '\0';
-
- dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
-
- /* Get allowed channels */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST,
- &priv->channel_mask);
- if (err) {
- dev_err(dev, "Failed to read channel list!\n");
- goto out;
- }
-
- /* Get initial AP density */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
- &priv->ap_density);
- if (err || priv->ap_density < 1 || priv->ap_density > 3)
- priv->has_sensitivity = 0;
-
- /* Get initial RTS threshold */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- &priv->rts_thresh);
- if (err) {
- dev_err(dev, "Failed to read RTS threshold!\n");
- goto out;
- }
-
- /* Get initial fragmentation settings */
- if (priv->has_mwo)
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- &priv->mwo_robust);
- else
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- &priv->frag_thresh);
- if (err) {
- dev_err(dev, "Failed to read fragmentation settings!\n");
- goto out;
- }
-
- /* Power management setup */
- if (priv->has_pm) {
- priv->pm_on = 0;
- priv->pm_mcast = 1;
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- &priv->pm_period);
- if (err) {
- dev_err(dev, "Failed to read power management "
- "period!\n");
- goto out;
- }
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- &priv->pm_timeout);
- if (err) {
- dev_err(dev, "Failed to read power management "
- "timeout!\n");
- goto out;
- }
- }
-
- /* Preamble setup */
- if (priv->has_preamble) {
- err = hermes_read_wordrec_pr(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- &priv->preamble);
- if (err) {
- dev_err(dev, "Failed to read preamble setup\n");
- goto out;
- }
- }
-
- /* Retry settings */
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
- &priv->short_retry_limit);
- if (err) {
- dev_err(dev, "Failed to read short retry limit\n");
- goto out;
- }
-
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
- &priv->long_retry_limit);
- if (err) {
- dev_err(dev, "Failed to read long retry limit\n");
- goto out;
- }
-
- err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
- &priv->retry_lifetime);
- if (err) {
- dev_err(dev, "Failed to read max retry lifetime\n");
- goto out;
- }
-
-out:
- return err;
-}
-
-/* Can be called before netdev registration */
-int orinoco_hw_allocate_fid(struct orinoco_private *priv)
-{
- struct device *dev = priv->dev;
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
- if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
- /* Try workaround for old Symbol firmware bug */
- priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
- err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
-
- dev_warn(dev, "Firmware ALLOC bug detected "
- "(old Symbol firmware?). Work around %s\n",
- err ? "failed!" : "ok.");
- }
-
- return err;
-}
-
-int orinoco_get_bitratemode(int bitrate, int automatic)
-{
- int ratemode = -1;
- int i;
-
- if ((bitrate != 10) && (bitrate != 20) &&
- (bitrate != 55) && (bitrate != 110))
- return ratemode;
-
- for (i = 0; i < BITRATE_TABLE_SIZE; i++) {
- if ((bitrate_table[i].bitrate == bitrate) &&
- (bitrate_table[i].automatic == automatic)) {
- ratemode = i;
- break;
- }
- }
- return ratemode;
-}
-
-void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
-{
- BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
-
- *bitrate = bitrate_table[ratemode].bitrate * 100000;
- *automatic = bitrate_table[ratemode].automatic;
-}
-
-int orinoco_hw_program_rids(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct wireless_dev *wdev = netdev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err;
- struct hermes_idstring idbuf;
-
- /* Set the MAC address */
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
- HERMES_BYTES_TO_RECLEN(ETH_ALEN),
- dev->dev_addr);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting MAC address\n",
- dev->name, err);
- return err;
- }
-
- /* Set up the link mode */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
- priv->port_type);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting port type\n",
- dev->name, err);
- return err;
- }
- /* Set the channel/frequency */
- if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFOWNCHANNEL,
- priv->channel);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting channel %d\n",
- dev->name, err, priv->channel);
- return err;
- }
- }
-
- if (priv->has_ibss) {
- u16 createibss;
-
- if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
- printk(KERN_WARNING "%s: This firmware requires an "
- "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
- /* With wvlan_cs, in this case, we would crash.
- * hopefully, this driver will behave better...
- * Jean II */
- createibss = 0;
- } else {
- createibss = priv->createibss;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFCREATEIBSS,
- createibss);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set the desired BSSID */
- err = __orinoco_hw_set_wap(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting AP address\n",
- dev->name, err);
- return err;
- }
-
- /* Set the desired ESSID */
- idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
- memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
- /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
- dev->name, err);
- return err;
- }
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
- HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
- dev->name, err);
- return err;
- }
-
- /* Set the station name */
- idbuf.len = cpu_to_le16(strlen(priv->nick));
- memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
- err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
- HERMES_BYTES_TO_RECLEN(strlen(priv->nick) + 2),
- &idbuf);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting nickname\n",
- dev->name, err);
- return err;
- }
-
- /* Set AP density */
- if (priv->has_sensitivity) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE,
- priv->ap_density);
- if (err) {
- printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
- "Disabling sensitivity control\n",
- dev->name, err);
-
- priv->has_sensitivity = 0;
- }
- }
-
- /* Set RTS threshold */
- err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
- priv->rts_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
- dev->name, err);
- return err;
- }
-
- /* Set fragmentation threshold or MWO robustness */
- if (priv->has_mwo)
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMWOROBUST_AGERE,
- priv->mwo_robust);
- else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
- priv->frag_thresh);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting fragmentation\n",
- dev->name, err);
- return err;
- }
-
- /* Set bitrate */
- err = __orinoco_hw_set_bitrate(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting bitrate\n",
- dev->name, err);
- return err;
- }
-
- /* Set power management */
- if (priv->has_pm) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED,
- priv->pm_on);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE,
- priv->pm_mcast);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION,
- priv->pm_period);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION,
- priv->pm_timeout);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting up PM\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set preamble - only for Symbol so far... */
- if (priv->has_preamble) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPREAMBLE_SYMBOL,
- priv->preamble);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting preamble\n",
- dev->name, err);
- return err;
- }
- }
-
- /* Set up encryption */
- if (priv->has_wep || priv->has_wpa) {
- err = __orinoco_hw_setup_enc(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d activating encryption\n",
- dev->name, err);
- return err;
- }
- }
-
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- /* Enable monitor mode */
- dev->type = ARPHRD_IEEE80211;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_MONITOR, 0, NULL);
- } else {
- /* Disable monitor mode */
- dev->type = ARPHRD_ETHER;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_STOP, 0, NULL);
- }
- if (err)
- return err;
-
- /* Reset promiscuity / multicast*/
- priv->promiscuous = 0;
- priv->mc_count = 0;
-
- /* Record mode change */
- wdev->iftype = priv->iw_mode;
-
- return 0;
-}
-
-/* Get tsc from the firmware */
-int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- u8 tsc_arr[4][ORINOCO_SEQ_LEN];
-
- if ((key < 0) || (key >= 4))
- return -EINVAL;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
- sizeof(tsc_arr), NULL, &tsc_arr);
- if (!err)
- memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
-
- return err;
-}
-
-int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int ratemode = priv->bitratemode;
- int err = 0;
-
- if (ratemode >= BITRATE_TABLE_SIZE) {
- printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
- priv->ndev->name, ratemode);
- return -EINVAL;
- }
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFTXRATECONTROL,
- bitrate_table[ratemode].agere_txratectrl);
- break;
- case FIRMWARE_TYPE_INTERSIL:
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFTXRATECONTROL,
- bitrate_table[ratemode].intersil_txratectrl);
- break;
- default:
- BUG();
- }
-
- return err;
-}
-
-int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
-{
- struct hermes *hw = &priv->hw;
- int i;
- int err = 0;
- u16 val;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CURRENTTXRATE, &val);
- if (err)
- return err;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
- /* Note : in Lucent firmware, the return value of
- * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
- * and therefore is totally different from the
- * encoding of HERMES_RID_CNFTXRATECONTROL.
- * Don't forget that 6Mb/s is really 5.5Mb/s */
- if (val == 6)
- *bitrate = 5500000;
- else
- *bitrate = val * 1000000;
- break;
- case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
- case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
- for (i = 0; i < BITRATE_TABLE_SIZE; i++)
- if (bitrate_table[i].intersil_txratectrl == val) {
- *bitrate = bitrate_table[i].bitrate * 100000;
- break;
- }
-
- if (i >= BITRATE_TABLE_SIZE) {
- printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
- priv->ndev->name, val);
- err = -EIO;
- }
-
- break;
- default:
- BUG();
- }
-
- return err;
-}
-
-/* Set fixed AP address */
-int __orinoco_hw_set_wap(struct orinoco_private *priv)
-{
- int roaming_flag;
- int err = 0;
- struct hermes *hw = &priv->hw;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- /* not supported */
- break;
- case FIRMWARE_TYPE_INTERSIL:
- if (priv->bssid_fixed)
- roaming_flag = 2;
- else
- roaming_flag = 1;
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFROAMINGMODE,
- roaming_flag);
- break;
- case FIRMWARE_TYPE_SYMBOL:
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
- &priv->desired_bssid);
- break;
- }
- return err;
-}
-
-/* Change the WEP keys and/or the current keys. Can be called
- * either from __orinoco_hw_setup_enc() or directly from
- * orinoco_ioctl_setiwencode(). In the later case the association
- * with the AP is not broken (if the firmware can handle it),
- * which is needed for 802.1x implementations. */
-int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- int i;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- {
- struct orinoco_key keys[ORINOCO_MAX_KEYS];
-
- memset(&keys, 0, sizeof(keys));
- for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
- int len = min(priv->keys[i].key_len,
- ORINOCO_MAX_KEY_SIZE);
- memcpy(&keys[i].data, priv->keys[i].key, len);
- if (len > SMALL_KEY_SIZE)
- keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
- else if (len > 0)
- keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
- else
- keys[i].len = cpu_to_le16(0);
- }
-
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFWEPKEYS_AGERE,
- &keys);
- if (err)
- return err;
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFTXKEY_AGERE,
- priv->tx_key);
- if (err)
- return err;
- break;
- }
- case FIRMWARE_TYPE_INTERSIL:
- case FIRMWARE_TYPE_SYMBOL:
- {
- int keylen;
-
- /* Force uniform key length to work around
- * firmware bugs */
- keylen = priv->keys[priv->tx_key].key_len;
-
- if (keylen > LARGE_KEY_SIZE) {
- printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
- priv->ndev->name, priv->tx_key, keylen);
- return -E2BIG;
- } else if (keylen > SMALL_KEY_SIZE)
- keylen = LARGE_KEY_SIZE;
- else if (keylen > 0)
- keylen = SMALL_KEY_SIZE;
- else
- keylen = 0;
-
- /* Write all 4 keys */
- for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
- u8 key[LARGE_KEY_SIZE] = { 0 };
-
- memcpy(key, priv->keys[i].key,
- priv->keys[i].key_len);
-
- err = hw->ops->write_ltv(hw, USER_BAP,
- HERMES_RID_CNFDEFAULTKEY0 + i,
- HERMES_BYTES_TO_RECLEN(keylen),
- key);
- if (err)
- return err;
- }
-
- /* Write the index of the key used in transmission */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFWEPDEFAULTKEYID,
- priv->tx_key);
- if (err)
- return err;
- }
- break;
- }
-
- return 0;
-}
-
-int __orinoco_hw_setup_enc(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- int master_wep_flag;
- int auth_flag;
- int enc_flag;
-
- /* Setup WEP keys */
- if (priv->encode_alg == ORINOCO_ALG_WEP)
- __orinoco_hw_setup_wepkeys(priv);
-
- if (priv->wep_restrict)
- auth_flag = HERMES_AUTH_SHARED_KEY;
- else
- auth_flag = HERMES_AUTH_OPEN;
-
- if (priv->wpa_enabled)
- enc_flag = 2;
- else if (priv->encode_alg == ORINOCO_ALG_WEP)
- enc_flag = 1;
- else
- enc_flag = 0;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
- if (priv->encode_alg == ORINOCO_ALG_WEP) {
- /* Enable the shared-key authentication. */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFAUTHENTICATION_AGERE,
- auth_flag);
- if (err)
- return err;
- }
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFWEPENABLED_AGERE,
- enc_flag);
- if (err)
- return err;
-
- if (priv->has_wpa) {
- /* Set WPA key management */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
- priv->key_mgmt);
- if (err)
- return err;
- }
-
- break;
-
- case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
- case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
- if (priv->encode_alg == ORINOCO_ALG_WEP) {
- if (priv->wep_restrict ||
- (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
- master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
- HERMES_WEP_EXCL_UNENCRYPTED;
- else
- master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFAUTHENTICATION,
- auth_flag);
- if (err)
- return err;
- } else
- master_wep_flag = 0;
-
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
- master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
-
- /* Master WEP setting : on/off */
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFWEPFLAGS_INTERSIL,
- master_wep_flag);
- if (err)
- return err;
-
- break;
- }
-
- return 0;
-}
-
-/* key must be 32 bytes, including the tx and rx MIC keys.
- * rsc must be NULL or up to 8 bytes
- * tsc must be NULL or up to 8 bytes
- */
-int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
- int set_tx, const u8 *key, size_t key_len,
- const u8 *rsc, size_t rsc_len,
- const u8 *tsc, size_t tsc_len)
-{
- struct {
- __le16 idx;
- u8 rsc[ORINOCO_SEQ_LEN];
- struct {
- u8 key[TKIP_KEYLEN];
- u8 tx_mic[MIC_KEYLEN];
- u8 rx_mic[MIC_KEYLEN];
- } tkip;
- u8 tsc[ORINOCO_SEQ_LEN];
- } __packed buf;
- struct hermes *hw = &priv->hw;
- int ret;
- int err;
- int k;
- u16 xmitting;
-
- key_idx &= 0x3;
-
- if (set_tx)
- key_idx |= 0x8000;
-
- buf.idx = cpu_to_le16(key_idx);
- if (key_len != sizeof(buf.tkip))
- return -EINVAL;
- memcpy(&buf.tkip, key, sizeof(buf.tkip));
-
- if (rsc_len > sizeof(buf.rsc))
- rsc_len = sizeof(buf.rsc);
-
- if (tsc_len > sizeof(buf.tsc))
- tsc_len = sizeof(buf.tsc);
-
- memset(buf.rsc, 0, sizeof(buf.rsc));
- memset(buf.tsc, 0, sizeof(buf.tsc));
-
- if (rsc != NULL)
- memcpy(buf.rsc, rsc, rsc_len);
-
- if (tsc != NULL)
- memcpy(buf.tsc, tsc, tsc_len);
- else
- buf.tsc[4] = 0x10;
-
- /* Wait up to 100ms for tx queue to empty */
- for (k = 100; k > 0; k--) {
- udelay(1000);
- ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
- &xmitting);
- if (ret || !xmitting)
- break;
- }
-
- if (k == 0)
- ret = -ETIMEDOUT;
-
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
- &buf);
-
- return ret ? ret : err;
-}
-
-int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
- key_idx);
- if (err)
- printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
- priv->ndev->name, err, key_idx);
- return err;
-}
-
-int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
- struct net_device *dev,
- int mc_count, int promisc)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
-
- if (promisc != priv->promiscuous) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPROMISCUOUSMODE,
- promisc);
- if (err) {
- printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
- priv->ndev->name, err);
- } else
- priv->promiscuous = promisc;
- }
-
- /* If we're not in promiscuous mode, then we need to set the
- * group address if either we want to multicast, or if we were
- * multicasting and want to stop */
- if (!promisc && (mc_count || priv->mc_count)) {
- struct netdev_hw_addr *ha;
- struct hermes_multicast mclist;
- int i = 0;
-
- netdev_for_each_mc_addr(ha, dev) {
- if (i == mc_count)
- break;
- memcpy(mclist.addr[i++], ha->addr, ETH_ALEN);
- }
-
- err = hw->ops->write_ltv(hw, USER_BAP,
- HERMES_RID_CNFGROUPADDRESSES,
- HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
- &mclist);
- if (err)
- printk(KERN_ERR "%s: Error %d setting multicast list.\n",
- priv->ndev->name, err);
- else
- priv->mc_count = mc_count;
- }
- return err;
-}
-
-/* Return : < 0 -> error code ; >= 0 -> length */
-int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
- char buf[IW_ESSID_MAX_SIZE + 1])
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- struct hermes_idstring essidbuf;
- char *p = (char *)(&essidbuf.val);
- int len;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (strlen(priv->desired_essid) > 0) {
- /* We read the desired SSID from the hardware rather
- than from priv->desired_essid, just in case the
- firmware is allowed to change it on us. I'm not
- sure about this */
- /* My guess is that the OWNSSID should always be whatever
- * we set to the card, whereas CURRENT_SSID is the one that
- * may change... - Jean II */
- u16 rid;
-
- *active = 1;
-
- rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
- HERMES_RID_CNFDESIREDSSID;
-
- err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
- NULL, &essidbuf);
- if (err)
- goto fail_unlock;
- } else {
- *active = 0;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
- sizeof(essidbuf), NULL, &essidbuf);
- if (err)
- goto fail_unlock;
- }
-
- len = le16_to_cpu(essidbuf.len);
- BUG_ON(len > IW_ESSID_MAX_SIZE);
-
- memset(buf, 0, IW_ESSID_MAX_SIZE);
- memcpy(buf, p, len);
- err = len;
-
- fail_unlock:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-int orinoco_hw_get_freq(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err = 0;
- u16 channel;
- int freq = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
- &channel);
- if (err)
- goto out;
-
- /* Intersil firmware 1.3.5 returns 0 when the interface is down */
- if (channel == 0) {
- err = -EBUSY;
- goto out;
- }
-
- if ((channel < 1) || (channel > NUM_CHANNELS)) {
- printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
- priv->ndev->name, channel);
- err = -EBUSY;
- goto out;
-
- }
- freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
-
- out:
- orinoco_unlock(priv, &flags);
-
- if (err > 0)
- err = -EBUSY;
- return err ? err : freq;
-}
-
-int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
- int *numrates, s32 *rates, int max)
-{
- struct hermes *hw = &priv->hw;
- struct hermes_idstring list;
- unsigned char *p = (unsigned char *)&list.val;
- int err = 0;
- int num;
- int i;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
- sizeof(list), NULL, &list);
- orinoco_unlock(priv, &flags);
-
- if (err)
- return err;
-
- num = le16_to_cpu(list.len);
- *numrates = num;
- num = min(num, max);
-
- for (i = 0; i < num; i++)
- rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
-
- return 0;
-}
-
-int orinoco_hw_trigger_scan(struct orinoco_private *priv,
- const struct cfg80211_ssid *ssid)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- unsigned long flags;
- int err = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Scanning with port 0 disabled would fail */
- if (!netif_running(dev)) {
- err = -ENETDOWN;
- goto out;
- }
-
- /* In monitor mode, the scan results are always empty.
- * Probe responses are passed to the driver as received
- * frames and could be processed in software. */
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (priv->has_hostscan) {
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN_SYMBOL,
- HERMES_HOSTSCAN_SYMBOL_ONCE |
- HERMES_HOSTSCAN_SYMBOL_BCAST);
- break;
- case FIRMWARE_TYPE_INTERSIL: {
- __le16 req[3];
-
- req[0] = cpu_to_le16(0x3fff); /* All channels */
- req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
- req[2] = 0; /* Any ESSID */
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFHOSTSCAN, &req);
- break;
- }
- case FIRMWARE_TYPE_AGERE:
- if (ssid->ssid_len > 0) {
- struct hermes_idstring idbuf;
- size_t len = ssid->ssid_len;
-
- idbuf.len = cpu_to_le16(len);
- memcpy(idbuf.val, ssid->ssid, len);
-
- err = hw->ops->write_ltv(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- HERMES_BYTES_TO_RECLEN(len + 2),
- &idbuf);
- } else
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANSSID_AGERE,
- 0); /* Any ESSID */
- if (err)
- break;
-
- if (priv->has_ext_scan) {
- err = hermes_write_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSCANCHANNELS2GHZ,
- 0x7FFF);
- if (err)
- goto out;
-
- err = hermes_inquire(hw,
- HERMES_INQ_CHANNELINFO);
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- break;
- }
- } else
- err = hermes_inquire(hw, HERMES_INQ_SCAN);
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-/* Disassociate from node with BSSID addr */
-int orinoco_hw_disassociate(struct orinoco_private *priv,
- u8 *addr, u16 reason_code)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- struct {
- u8 addr[ETH_ALEN];
- __le16 reason_code;
- } __packed buf;
-
- /* Currently only supported by WPA enabled Agere fw */
- if (!priv->has_wpa)
- return -EOPNOTSUPP;
-
- memcpy(buf.addr, addr, ETH_ALEN);
- buf.reason_code = cpu_to_le16(reason_code);
- err = HERMES_WRITE_RECORD(hw, USER_BAP,
- HERMES_RID_CNFDISASSOCIATE,
- &buf);
- return err;
-}
-
-int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
- u8 *addr)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
- ETH_ALEN, NULL, addr);
-
- return err;
-}
diff --git a/drivers/net/wireless/intersil/orinoco/hw.h b/drivers/net/wireless/intersil/orinoco/hw.h
deleted file mode 100644
index da5804dbdf34c..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/hw.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Encapsulate basic setting changes on Hermes hardware
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_HW_H_
-#define _ORINOCO_HW_H_
-
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-
-/* Hardware BAPs */
-#define USER_BAP 0
-#define IRQ_BAP 1
-
-/* WEP key sizes */
-#define SMALL_KEY_SIZE 5
-#define LARGE_KEY_SIZE 13
-
-/* Number of supported channels */
-#define NUM_CHANNELS 14
-
-/* Forward declarations */
-struct orinoco_private;
-
-int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name,
- size_t fw_name_len, u32 *hw_ver);
-int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
-int orinoco_hw_allocate_fid(struct orinoco_private *priv);
-int orinoco_get_bitratemode(int bitrate, int automatic);
-void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
-
-int orinoco_hw_program_rids(struct orinoco_private *priv);
-int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
-int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
-int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
-int __orinoco_hw_set_wap(struct orinoco_private *priv);
-int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
-int __orinoco_hw_setup_enc(struct orinoco_private *priv);
-int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
- int set_tx, const u8 *key, size_t key_len,
- const u8 *rsc, size_t rsc_len,
- const u8 *tsc, size_t tsc_len);
-int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
-int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
- struct net_device *dev,
- int mc_count, int promisc);
-int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
- char buf[IW_ESSID_MAX_SIZE + 1]);
-int orinoco_hw_get_freq(struct orinoco_private *priv);
-int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
- int *numrates, s32 *rates, int max);
-int orinoco_hw_trigger_scan(struct orinoco_private *priv,
- const struct cfg80211_ssid *ssid);
-int orinoco_hw_disassociate(struct orinoco_private *priv,
- u8 *addr, u16 reason_code);
-int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
- u8 *addr);
-
-#endif /* _ORINOCO_HW_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/main.c b/drivers/net/wireless/intersil/orinoco/main.c
deleted file mode 100644
index 7df88d20ff3dc..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/main.c
+++ /dev/null
@@ -1,2414 +0,0 @@
-/* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c)
- *
- * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
- * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
- *
- * Current maintainers (as of 29 September 2003) are:
- * Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * (C) Copyright David Gibson, IBM Corporation 2001-2003.
- * Copyright (C) 2000 David Gibson, Linuxcare Australia.
- * With some help from :
- * Copyright (C) 2001 Jean Tourrilhes, HP Labs
- * Copyright (C) 2001 Benjamin Herrenschmidt
- *
- * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
- *
- * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
- * AT fasta.fh-dortmund.de>
- * http://www.stud.fh-dortmund.de/~andy/wvlan/
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds AT users.sourceforge.net>. Portions created by David
- * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights
- * Reserved.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL. */
-
-/*
- * TODO
- * o Handle de-encapsulation within network layer, provide 802.11
- * headers (patch from Thomas 'Dent' Mirlacher)
- * o Fix possible races in SPY handling.
- * o Disconnect wireless extensions from fundamental configuration.
- * o (maybe) Software WEP support (patch from Stano Meduna).
- * o (maybe) Use multiple Tx buffers - driver handling queue
- * rather than firmware.
- */
-
-/* Locking and synchronization:
- *
- * The basic principle is that everything is serialized through a
- * single spinlock, priv->lock. The lock is used in user, bh and irq
- * context, so when taken outside hardirq context it should always be
- * taken with interrupts disabled. The lock protects both the
- * hardware and the struct orinoco_private.
- *
- * Another flag, priv->hw_unavailable indicates that the hardware is
- * unavailable for an extended period of time (e.g. suspended, or in
- * the middle of a hard reset). This flag is protected by the
- * spinlock. All code which touches the hardware should check the
- * flag after taking the lock, and if it is set, give up on whatever
- * they are doing and drop the lock again. The orinoco_lock()
- * function handles this (it unlocks and returns -EBUSY if
- * hw_unavailable is non-zero).
- */
-
-#define DRIVER_NAME "orinoco"
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/suspend.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <net/iw_handler.h>
-#include <net/cfg80211.h>
-
-#include "hermes_rid.h"
-#include "hermes_dld.h"
-#include "hw.h"
-#include "scan.h"
-#include "mic.h"
-#include "fw.h"
-#include "wext.h"
-#include "cfg.h"
-#include "main.h"
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module information */
-/********************************************************************/
-
-MODULE_AUTHOR("Pavel Roskin <[email protected]> & "
- "David Gibson <[email protected]>");
-MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based "
- "and similar wireless cards");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Level of debugging. Used in the macros in orinoco.h */
-#ifdef ORINOCO_DEBUG
-int orinoco_debug = ORINOCO_DEBUG;
-EXPORT_SYMBOL(orinoco_debug);
-module_param(orinoco_debug, int, 0644);
-MODULE_PARM_DESC(orinoco_debug, "Debug level");
-#endif
-
-static bool suppress_linkstatus; /* = 0 */
-module_param(suppress_linkstatus, bool, 0644);
-MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
-
-static int ignore_disconnect; /* = 0 */
-module_param(ignore_disconnect, int, 0644);
-MODULE_PARM_DESC(ignore_disconnect,
- "Don't report lost link to the network layer");
-
-int force_monitor; /* = 0 */
-module_param(force_monitor, int, 0644);
-MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
-
-/********************************************************************/
-/* Internal constants */
-/********************************************************************/
-
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
-
-#define ORINOCO_MIN_MTU 256
-#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
-
-#define MAX_IRQLOOPS_PER_IRQ 10
-#define MAX_IRQLOOPS_PER_JIFFY (20000 / HZ) /* Based on a guestimate of
- * how many events the
- * device could
- * legitimately generate */
-
-#define DUMMY_FID 0xFFFF
-
-/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
- HERMES_MAX_MULTICAST : 0)*/
-#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST)
-
-#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \
- | HERMES_EV_TX | HERMES_EV_TXEXC \
- | HERMES_EV_WTERR | HERMES_EV_INFO \
- | HERMES_EV_INFDROP)
-
-/********************************************************************/
-/* Data types */
-/********************************************************************/
-
-/* Beginning of the Tx descriptor, used in TxExc handling */
-struct hermes_txexc_data {
- struct hermes_tx_descriptor desc;
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
-} __packed;
-
-/* Rx frame header except compatibility 802.3 header */
-struct hermes_rx_descriptor {
- /* Control */
- __le16 status;
- __le32 time;
- u8 silence;
- u8 signal;
- u8 rate;
- u8 rxflow;
- __le32 reserved;
-
- /* 802.11 header */
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
-
- /* Data length */
- __le16 data_len;
-} __packed;
-
-struct orinoco_rx_data {
- struct hermes_rx_descriptor *desc;
- struct sk_buff *skb;
- struct list_head list;
-};
-
-struct orinoco_scan_data {
- void *buf;
- size_t len;
- int type;
- struct list_head list;
-};
-
-/********************************************************************/
-/* Function prototypes */
-/********************************************************************/
-
-static int __orinoco_set_multicast_list(struct net_device *dev);
-static int __orinoco_up(struct orinoco_private *priv);
-static int __orinoco_down(struct orinoco_private *priv);
-static int __orinoco_commit(struct orinoco_private *priv);
-
-/********************************************************************/
-/* Internal helper functions */
-/********************************************************************/
-
-void set_port_type(struct orinoco_private *priv)
-{
- switch (priv->iw_mode) {
- case NL80211_IFTYPE_STATION:
- priv->port_type = 1;
- priv->createibss = 0;
- break;
- case NL80211_IFTYPE_ADHOC:
- if (priv->prefer_port3) {
- priv->port_type = 3;
- priv->createibss = 0;
- } else {
- priv->port_type = priv->ibss_port;
- priv->createibss = 1;
- }
- break;
- case NL80211_IFTYPE_MONITOR:
- priv->port_type = 3;
- priv->createibss = 0;
- break;
- default:
- printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
- priv->ndev->name);
- }
-}
-
-/********************************************************************/
-/* Device methods */
-/********************************************************************/
-
-int orinoco_open(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int err;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = __orinoco_up(priv);
-
- if (!err)
- priv->open = 1;
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-EXPORT_SYMBOL(orinoco_open);
-
-int orinoco_stop(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int err = 0;
-
- /* We mustn't use orinoco_lock() here, because we need to be
- able to close the interface even if hw_unavailable is set
- (e.g. as we're released after a PC Card removal) */
- orinoco_lock_irq(priv);
-
- priv->open = 0;
-
- err = __orinoco_down(priv);
-
- orinoco_unlock_irq(priv);
-
- return err;
-}
-EXPORT_SYMBOL(orinoco_stop);
-
-void orinoco_set_multicast_list(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0) {
- printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
- "called when hw_unavailable\n", dev->name);
- return;
- }
-
- __orinoco_set_multicast_list(dev);
- orinoco_unlock(priv, &flags);
-}
-EXPORT_SYMBOL(orinoco_set_multicast_list);
-
-int orinoco_change_mtu(struct net_device *dev, int new_mtu)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- /* MTU + encapsulation + header length */
- if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
- (priv->nicbuf_size - ETH_HLEN))
- return -EINVAL;
-
- dev->mtu = new_mtu;
-
- return 0;
-}
-EXPORT_SYMBOL(orinoco_change_mtu);
-
-/********************************************************************/
-/* Tx path */
-/********************************************************************/
-
-/* Add encapsulation and MIC to the existing SKB.
- * The main xmit routine will then send the whole lot to the card.
- * Need 8 bytes headroom
- * Need 8 bytes tailroom
- *
- * With encapsulated ethernet II frame
- * --------
- * 803.3 header (14 bytes)
- * dst[6]
- * -------- src[6]
- * 803.3 header (14 bytes) len[2]
- * dst[6] 803.2 header (8 bytes)
- * src[6] encaps[6]
- * len[2] <- leave alone -> len[2]
- * -------- -------- <-- 0
- * Payload Payload
- * ... ...
- *
- * -------- --------
- * MIC (8 bytes)
- * --------
- *
- * returns 0 on success, -ENOMEM on error.
- */
-int orinoco_process_xmit_skb(struct sk_buff *skb,
- struct net_device *dev,
- struct orinoco_private *priv,
- int *tx_control,
- u8 *mic_buf)
-{
- struct orinoco_tkip_key *key;
- struct ethhdr *eh;
- int do_mic;
-
- key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
-
- do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
- (key != NULL));
-
- if (do_mic)
- *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
- HERMES_TXCTRL_MIC;
-
- eh = (struct ethhdr *)skb->data;
-
- /* Encapsulate Ethernet-II frames */
- if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
- struct header_struct {
- struct ethhdr eth; /* 802.3 header */
- u8 encap[6]; /* 802.2 header */
- } __packed hdr;
- int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
-
- if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
- if (net_ratelimit())
- printk(KERN_ERR
- "%s: Not enough headroom for 802.2 headers %d\n",
- dev->name, skb_headroom(skb));
- return -ENOMEM;
- }
-
- /* Fill in new header */
- memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
- hdr.eth.h_proto = htons(len);
- memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
-
- /* Make room for the new header, and copy it in */
- eh = skb_push(skb, ENCAPS_OVERHEAD);
- memcpy(eh, &hdr, sizeof(hdr));
- }
-
- /* Calculate Michael MIC */
- if (do_mic) {
- size_t len = skb->len - ETH_HLEN;
- u8 *mic = &mic_buf[0];
-
- /* Have to write to an even address, so copy the spare
- * byte across */
- if (skb->len % 2) {
- *mic = skb->data[skb->len - 1];
- mic++;
- }
-
- orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
- eh->h_dest, eh->h_source, 0 /* priority */,
- skb->data + ETH_HLEN,
- len, mic);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(orinoco_process_xmit_skb);
-
-static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct hermes *hw = &priv->hw;
- int err = 0;
- u16 txfid = priv->txfid;
- int tx_control;
- unsigned long flags;
- u8 mic_buf[MICHAEL_MIC_LEN + 1];
-
- if (!netif_running(dev)) {
- printk(KERN_ERR "%s: Tx on stopped device!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (netif_queue_stopped(dev)) {
- printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (orinoco_lock(priv, &flags) != 0) {
- printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (!netif_carrier_ok(dev) ||
- (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
- /* Oops, the firmware hasn't established a connection,
- silently drop the packet (this seems to be the
- safest approach). */
- goto drop;
- }
-
- /* Check packet length */
- if (skb->len < ETH_HLEN)
- goto drop;
-
- tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
-
- err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
- &mic_buf[0]);
- if (err)
- goto drop;
-
- if (priv->has_alt_txcntl) {
- /* WPA enabled firmwares have tx_cntl at the end of
- * the 802.11 header. So write zeroed descriptor and
- * 802.11 header at the same time
- */
- char desc[HERMES_802_3_OFFSET];
- __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
-
- memset(&desc, 0, sizeof(desc));
-
- *txcntl = cpu_to_le16(tx_control);
- err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
- txfid, 0);
- if (err) {
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d writing Tx "
- "descriptor to BAP\n", dev->name, err);
- goto busy;
- }
- } else {
- struct hermes_tx_descriptor desc;
-
- memset(&desc, 0, sizeof(desc));
-
- desc.tx_control = cpu_to_le16(tx_control);
- err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
- txfid, 0);
- if (err) {
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d writing Tx "
- "descriptor to BAP\n", dev->name, err);
- goto busy;
- }
-
- /* Clear the 802.11 header and data length fields - some
- * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
- * if this isn't done. */
- hermes_clear_words(hw, HERMES_DATA0,
- HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
- }
-
- err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
- txfid, HERMES_802_3_OFFSET);
- if (err) {
- printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
- dev->name, err);
- goto busy;
- }
-
- if (tx_control & HERMES_TXCTRL_MIC) {
- size_t offset = HERMES_802_3_OFFSET + skb->len;
- size_t len = MICHAEL_MIC_LEN;
-
- if (offset % 2) {
- offset--;
- len++;
- }
- err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
- txfid, offset);
- if (err) {
- printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
- dev->name, err);
- goto busy;
- }
- }
-
- /* Finally, we actually initiate the send */
- netif_stop_queue(dev);
-
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
- txfid, NULL);
- if (err) {
- netif_start_queue(dev);
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d transmitting packet\n",
- dev->name, err);
- goto busy;
- }
-
- stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
- goto ok;
-
- drop:
- stats->tx_errors++;
- stats->tx_dropped++;
-
- ok:
- orinoco_unlock(priv, &flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-
- busy:
- if (err == -EIO)
- schedule_work(&priv->reset_work);
- orinoco_unlock(priv, &flags);
- return NETDEV_TX_BUSY;
-}
-
-static void __orinoco_ev_alloc(struct net_device *dev, struct hermes *hw)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- u16 fid = hermes_read_regn(hw, ALLOCFID);
-
- if (fid != priv->txfid) {
- if (fid != DUMMY_FID)
- printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
- dev->name, fid);
- return;
- }
-
- hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_tx(struct net_device *dev, struct hermes *hw)
-{
- dev->stats.tx_packets++;
-
- netif_wake_queue(dev);
-
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
-}
-
-static void __orinoco_ev_txexc(struct net_device *dev, struct hermes *hw)
-{
- struct net_device_stats *stats = &dev->stats;
- u16 fid = hermes_read_regn(hw, TXCOMPLFID);
- u16 status;
- struct hermes_txexc_data hdr;
- int err = 0;
-
- if (fid == DUMMY_FID)
- return; /* Nothing's really happened */
-
- /* Read part of the frame header - we need status and addr1 */
- err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
- sizeof(struct hermes_txexc_data),
- fid, 0);
-
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
- stats->tx_errors++;
-
- if (err) {
- printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
- "(FID=%04X error %d)\n",
- dev->name, fid, err);
- return;
- }
-
- DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
- err, fid);
-
- /* We produce a TXDROP event only for retry or lifetime
- * exceeded, because that's the only status that really mean
- * that this particular node went away.
- * Other errors means that *we* screwed up. - Jean II */
- status = le16_to_cpu(hdr.desc.status);
- if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
- union iwreq_data wrqu;
-
- /* Copy 802.11 dest address.
- * We use the 802.11 header because the frame may
- * not be 802.3 or may be mangled...
- * In Ad-Hoc mode, it will be the node address.
- * In managed mode, it will be most likely the AP addr
- * User space will figure out how to convert it to
- * whatever it needs (IP address or else).
- * - Jean II */
- memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
- wrqu.addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
- }
-
- netif_wake_queue(dev);
-}
-
-void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct hermes *hw = &priv->hw;
-
- printk(KERN_WARNING "%s: Tx timeout! "
- "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
- dev->name, hermes_read_regn(hw, ALLOCFID),
- hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
-
- stats->tx_errors++;
-
- schedule_work(&priv->reset_work);
-}
-EXPORT_SYMBOL(orinoco_tx_timeout);
-
-/********************************************************************/
-/* Rx path (data frames) */
-/********************************************************************/
-
-/* Does the frame have a SNAP header indicating it should be
- * de-encapsulated to Ethernet-II? */
-static inline int is_ethersnap(void *_hdr)
-{
- u8 *hdr = _hdr;
-
- /* We de-encapsulate all packets which, a) have SNAP headers
- * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
- * and where b) the OUI of the SNAP header is 00:00:00 or
- * 00:00:f8 - we need both because different APs appear to use
- * different OUIs for some reason */
- return (memcmp(hdr, &encaps_hdr, 5) == 0)
- && ((hdr[5] == 0x00) || (hdr[5] == 0xf8));
-}
-
-static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
- int level, int noise)
-{
- struct iw_quality wstats;
- wstats.level = level - 0x95;
- wstats.noise = noise - 0x95;
- wstats.qual = (level > noise) ? (level - noise) : 0;
- wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- /* Update spy records */
- wireless_spy_update(dev, mac, &wstats);
-}
-
-static void orinoco_stat_gather(struct net_device *dev,
- struct sk_buff *skb,
- struct hermes_rx_descriptor *desc)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- /* Using spy support with lots of Rx packets, like in an
- * infrastructure (AP), will really slow down everything, because
- * the MAC address must be compared to each entry of the spy list.
- * If the user really asks for it (set some address in the
- * spy list), we do it, but he will pay the price.
- * Note that to get here, you need both WIRELESS_SPY
- * compiled in AND some addresses in the list !!!
- */
- /* Note : gcc will optimise the whole section away if
- * WIRELESS_SPY is not defined... - Jean II */
- if (SPY_NUMBER(priv)) {
- orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
- desc->signal, desc->silence);
- }
-}
-
-/*
- * orinoco_rx_monitor - handle received monitor frames.
- *
- * Arguments:
- * dev network device
- * rxfid received FID
- * desc rx descriptor of the frame
- *
- * Call context: interrupt
- */
-static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
- struct hermes_rx_descriptor *desc)
-{
- u32 hdrlen = 30; /* return full header by default */
- u32 datalen = 0;
- u16 fc;
- int err;
- int len;
- struct sk_buff *skb;
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct hermes *hw = &priv->hw;
-
- len = le16_to_cpu(desc->data_len);
-
- /* Determine the size of the header and the data */
- fc = le16_to_cpu(desc->frame_ctl);
- switch (fc & IEEE80211_FCTL_FTYPE) {
- case IEEE80211_FTYPE_DATA:
- if ((fc & IEEE80211_FCTL_TODS)
- && (fc & IEEE80211_FCTL_FROMDS))
- hdrlen = 30;
- else
- hdrlen = 24;
- datalen = len;
- break;
- case IEEE80211_FTYPE_MGMT:
- hdrlen = 24;
- datalen = len;
- break;
- case IEEE80211_FTYPE_CTL:
- switch (fc & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_PSPOLL:
- case IEEE80211_STYPE_RTS:
- case IEEE80211_STYPE_CFEND:
- case IEEE80211_STYPE_CFENDACK:
- hdrlen = 16;
- break;
- case IEEE80211_STYPE_CTS:
- case IEEE80211_STYPE_ACK:
- hdrlen = 10;
- break;
- }
- break;
- default:
- /* Unknown frame type */
- break;
- }
-
- /* sanity check the length */
- if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
- printk(KERN_DEBUG "%s: oversized monitor frame, "
- "data length = %d\n", dev->name, datalen);
- stats->rx_length_errors++;
- goto update_stats;
- }
-
- skb = dev_alloc_skb(hdrlen + datalen);
- if (!skb) {
- printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
- dev->name);
- goto update_stats;
- }
-
- /* Copy the 802.11 header to the skb */
- skb_put_data(skb, &(desc->frame_ctl), hdrlen);
- skb_reset_mac_header(skb);
-
- /* If any, copy the data from the card to the skb */
- if (datalen > 0) {
- err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
- ALIGN(datalen, 2), rxfid,
- HERMES_802_2_OFFSET);
- if (err) {
- printk(KERN_ERR "%s: error %d reading monitor frame\n",
- dev->name, err);
- goto drop;
- }
- }
-
- skb->dev = dev;
- skb->ip_summed = CHECKSUM_NONE;
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_802_2);
-
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
-
- netif_rx(skb);
- return;
-
- drop:
- dev_kfree_skb_irq(skb);
- update_stats:
- stats->rx_errors++;
- stats->rx_dropped++;
-}
-
-void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct iw_statistics *wstats = &priv->wstats;
- struct sk_buff *skb = NULL;
- u16 rxfid, status;
- int length;
- struct hermes_rx_descriptor *desc;
- struct orinoco_rx_data *rx_data;
- int err;
-
- desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
- if (!desc)
- goto update_stats;
-
- rxfid = hermes_read_regn(hw, RXFID);
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
- rxfid, 0);
- if (err) {
- printk(KERN_ERR "%s: error %d reading Rx descriptor. "
- "Frame dropped.\n", dev->name, err);
- goto update_stats;
- }
-
- status = le16_to_cpu(desc->status);
-
- if (status & HERMES_RXSTAT_BADCRC) {
- DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
- dev->name);
- stats->rx_crc_errors++;
- goto update_stats;
- }
-
- /* Handle frames in monitor mode */
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- orinoco_rx_monitor(dev, rxfid, desc);
- goto out;
- }
-
- if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
- DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
- dev->name);
- wstats->discard.code++;
- goto update_stats;
- }
-
- length = le16_to_cpu(desc->data_len);
-
- /* Sanity checks */
- if (length < 3) { /* No for even an 802.2 LLC header */
- /* At least on Symbol firmware with PCF we get quite a
- lot of these legitimately - Poll frames with no
- data. */
- goto out;
- }
- if (length > IEEE80211_MAX_DATA_LEN) {
- printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
- dev->name, length);
- stats->rx_length_errors++;
- goto update_stats;
- }
-
- /* Payload size does not include Michael MIC. Increase payload
- * size to read it together with the data. */
- if (status & HERMES_RXSTAT_MIC)
- length += MICHAEL_MIC_LEN;
-
- /* We need space for the packet data itself, plus an ethernet
- header, plus 2 bytes so we can align the IP header on a
- 32bit boundary, plus 1 byte so we can read in odd length
- packets from the card, which has an IO granularity of 16
- bits */
- skb = dev_alloc_skb(length + ETH_HLEN + 2 + 1);
- if (!skb) {
- printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
- dev->name);
- goto update_stats;
- }
-
- /* We'll prepend the header, so reserve space for it. The worst
- case is no decapsulation, when 802.3 header is prepended and
- nothing is removed. 2 is for aligning the IP header. */
- skb_reserve(skb, ETH_HLEN + 2);
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
- ALIGN(length, 2), rxfid,
- HERMES_802_2_OFFSET);
- if (err) {
- printk(KERN_ERR "%s: error %d reading frame. "
- "Frame dropped.\n", dev->name, err);
- goto drop;
- }
-
- /* Add desc and skb to rx queue */
- rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
- if (!rx_data)
- goto drop;
-
- rx_data->desc = desc;
- rx_data->skb = skb;
- list_add_tail(&rx_data->list, &priv->rx_list);
- tasklet_schedule(&priv->rx_tasklet);
-
- return;
-
-drop:
- dev_kfree_skb_irq(skb);
-update_stats:
- stats->rx_errors++;
- stats->rx_dropped++;
-out:
- kfree(desc);
-}
-EXPORT_SYMBOL(__orinoco_ev_rx);
-
-static void orinoco_rx(struct net_device *dev,
- struct hermes_rx_descriptor *desc,
- struct sk_buff *skb)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- u16 status, fc;
- int length;
- struct ethhdr *hdr;
-
- status = le16_to_cpu(desc->status);
- length = le16_to_cpu(desc->data_len);
- fc = le16_to_cpu(desc->frame_ctl);
-
- /* Calculate and check MIC */
- if (status & HERMES_RXSTAT_MIC) {
- struct orinoco_tkip_key *key;
- int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
- HERMES_MIC_KEY_ID_SHIFT);
- u8 mic[MICHAEL_MIC_LEN];
- u8 *rxmic;
- u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
- desc->addr3 : desc->addr2;
-
- /* Extract Michael MIC from payload */
- rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
-
- skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
- length -= MICHAEL_MIC_LEN;
-
- key = (struct orinoco_tkip_key *) priv->keys[key_id].key;
-
- if (!key) {
- printk(KERN_WARNING "%s: Received encrypted frame from "
- "%pM using key %i, but key is not installed\n",
- dev->name, src, key_id);
- goto drop;
- }
-
- orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src,
- 0, /* priority or QoS? */
- skb->data, skb->len, &mic[0]);
-
- if (memcmp(mic, rxmic,
- MICHAEL_MIC_LEN)) {
- union iwreq_data wrqu;
- struct iw_michaelmicfailure wxmic;
-
- printk(KERN_WARNING "%s: "
- "Invalid Michael MIC in data frame from %pM, "
- "using key %i\n",
- dev->name, src, key_id);
-
- /* TODO: update stats */
-
- /* Notify userspace */
- memset(&wxmic, 0, sizeof(wxmic));
- wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
- wxmic.flags |= (desc->addr1[0] & 1) ?
- IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
- wxmic.src_addr.sa_family = ARPHRD_ETHER;
- memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
-
- (void) orinoco_hw_get_tkip_iv(priv, key_id,
- &wxmic.tsc[0]);
-
- memset(&wrqu, 0, sizeof(wrqu));
- wrqu.data.length = sizeof(wxmic);
- wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
- (char *) &wxmic);
-
- goto drop;
- }
- }
-
- /* Handle decapsulation
- * In most cases, the firmware tell us about SNAP frames.
- * For some reason, the SNAP frames sent by LinkSys APs
- * are not properly recognised by most firmwares.
- * So, check ourselves */
- if (length >= ENCAPS_OVERHEAD &&
- (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
- ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
- is_ethersnap(skb->data))) {
- /* These indicate a SNAP within 802.2 LLC within
- 802.11 frame which we'll need to de-encapsulate to
- the original EthernetII frame. */
- hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
- } else {
- /* 802.3 frame - prepend 802.3 header as is */
- hdr = skb_push(skb, ETH_HLEN);
- hdr->h_proto = htons(length);
- }
- memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
- if (fc & IEEE80211_FCTL_FROMDS)
- memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
- else
- memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
-
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_NONE;
- if (fc & IEEE80211_FCTL_TODS)
- skb->pkt_type = PACKET_OTHERHOST;
-
- /* Process the wireless stats if needed */
- orinoco_stat_gather(dev, skb, desc);
-
- /* Pass the packet to the networking stack */
- netif_rx(skb);
- stats->rx_packets++;
- stats->rx_bytes += length;
-
- return;
-
- drop:
- dev_kfree_skb(skb);
- stats->rx_errors++;
- stats->rx_dropped++;
-}
-
-static void orinoco_rx_isr_tasklet(struct tasklet_struct *t)
-{
- struct orinoco_private *priv = from_tasklet(priv, t, rx_tasklet);
- struct net_device *dev = priv->ndev;
- struct orinoco_rx_data *rx_data, *temp;
- struct hermes_rx_descriptor *desc;
- struct sk_buff *skb;
- unsigned long flags;
-
- /* orinoco_rx requires the driver lock, and we also need to
- * protect priv->rx_list, so just hold the lock over the
- * lot.
- *
- * If orinoco_lock fails, we've unplugged the card. In this
- * case just abort. */
- if (orinoco_lock(priv, &flags) != 0)
- return;
-
- /* extract desc and skb from queue */
- list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
- desc = rx_data->desc;
- skb = rx_data->skb;
- list_del(&rx_data->list);
- kfree(rx_data);
-
- orinoco_rx(dev, desc, skb);
-
- kfree(desc);
- }
-
- orinoco_unlock(priv, &flags);
-}
-
-/********************************************************************/
-/* Rx path (info frames) */
-/********************************************************************/
-
-static void print_linkstatus(struct net_device *dev, u16 status)
-{
- char *s;
-
- if (suppress_linkstatus)
- return;
-
- switch (status) {
- case HERMES_LINKSTATUS_NOT_CONNECTED:
- s = "Not Connected";
- break;
- case HERMES_LINKSTATUS_CONNECTED:
- s = "Connected";
- break;
- case HERMES_LINKSTATUS_DISCONNECTED:
- s = "Disconnected";
- break;
- case HERMES_LINKSTATUS_AP_CHANGE:
- s = "AP Changed";
- break;
- case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
- s = "AP Out of Range";
- break;
- case HERMES_LINKSTATUS_AP_IN_RANGE:
- s = "AP In Range";
- break;
- case HERMES_LINKSTATUS_ASSOC_FAILED:
- s = "Association Failed";
- break;
- default:
- s = "UNKNOWN";
- }
-
- printk(KERN_DEBUG "%s: New link status: %s (%04x)\n",
- dev->name, s, status);
-}
-
-/* Search scan results for requested BSSID, join it if found */
-static void orinoco_join_ap(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, join_work);
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
- unsigned long flags;
- struct join_req {
- u8 bssid[ETH_ALEN];
- __le16 channel;
- } __packed req;
- const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
- struct prism2_scan_apinfo *atom = NULL;
- int offset = 4;
- int found = 0;
- u8 *buf;
- u16 len;
-
- /* Allocate buffer for scan results */
- buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
- if (!buf)
- return;
-
- if (orinoco_lock(priv, &flags) != 0)
- goto fail_lock;
-
- /* Sanity checks in case user changed something in the meantime */
- if (!priv->bssid_fixed)
- goto out;
-
- if (strlen(priv->desired_essid) == 0)
- goto out;
-
- /* Read scan results from the firmware */
- err = hw->ops->read_ltv(hw, USER_BAP,
- HERMES_RID_SCANRESULTSTABLE,
- MAX_SCAN_LEN, &len, buf);
- if (err) {
- printk(KERN_ERR "%s: Cannot read scan results\n",
- dev->name);
- goto out;
- }
-
- len = HERMES_RECLEN_TO_BYTES(len);
-
- /* Go through the scan results looking for the channel of the AP
- * we were requested to join */
- for (; offset + atom_len <= len; offset += atom_len) {
- atom = (struct prism2_scan_apinfo *) (buf + offset);
- if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- DEBUG(1, "%s: Requested AP not found in scan results\n",
- dev->name);
- goto out;
- }
-
- memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
- req.channel = atom->channel; /* both are little-endian */
- err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
- &req);
- if (err)
- printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
-
- out:
- orinoco_unlock(priv, &flags);
-
- fail_lock:
- kfree(buf);
-}
-
-/* Send new BSSID to userspace */
-static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- union iwreq_data wrqu;
- int err;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
- ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
- if (err != 0)
- return;
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /* Send event to user space */
- wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- union iwreq_data wrqu;
- int err;
- u8 buf[88];
- u8 *ie;
-
- if (!priv->has_wpa)
- return;
-
- err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
- sizeof(buf), NULL, &buf);
- if (err != 0)
- return;
-
- ie = orinoco_get_wpa_ie(buf, sizeof(buf));
- if (ie) {
- int rem = sizeof(buf) - (ie - &buf[0]);
- wrqu.data.length = ie[1] + 2;
- if (wrqu.data.length > rem)
- wrqu.data.length = rem;
-
- if (wrqu.data.length)
- /* Send event to user space */
- wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
- }
-}
-
-static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- union iwreq_data wrqu;
- int err;
- u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
- u8 *ie;
-
- if (!priv->has_wpa)
- return;
-
- err = hw->ops->read_ltv(hw, USER_BAP,
- HERMES_RID_CURRENT_ASSOC_RESP_INFO,
- sizeof(buf), NULL, &buf);
- if (err != 0)
- return;
-
- ie = orinoco_get_wpa_ie(buf, sizeof(buf));
- if (ie) {
- int rem = sizeof(buf) - (ie - &buf[0]);
- wrqu.data.length = ie[1] + 2;
- if (wrqu.data.length > rem)
- wrqu.data.length = rem;
-
- if (wrqu.data.length)
- /* Send event to user space */
- wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
- }
-}
-
-static void orinoco_send_wevents(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, wevent_work);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return;
-
- orinoco_send_assocreqie_wevent(priv);
- orinoco_send_assocrespie_wevent(priv);
- orinoco_send_bssid_wevent(priv);
-
- orinoco_unlock(priv, &flags);
-}
-
-static void qbuf_scan(struct orinoco_private *priv, void *buf,
- int len, int type)
-{
- struct orinoco_scan_data *sd;
- unsigned long flags;
-
- sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
- if (!sd)
- return;
-
- sd->buf = buf;
- sd->len = len;
- sd->type = type;
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- list_add_tail(&sd->list, &priv->scan_list);
- spin_unlock_irqrestore(&priv->scan_lock, flags);
-
- schedule_work(&priv->process_scan);
-}
-
-static void qabort_scan(struct orinoco_private *priv)
-{
- struct orinoco_scan_data *sd;
- unsigned long flags;
-
- sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
- if (!sd)
- return;
-
- sd->len = -1; /* Abort */
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- list_add_tail(&sd->list, &priv->scan_list);
- spin_unlock_irqrestore(&priv->scan_lock, flags);
-
- schedule_work(&priv->process_scan);
-}
-
-static void orinoco_process_scan_results(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, process_scan);
- struct orinoco_scan_data *sd, *temp;
- unsigned long flags;
- void *buf;
- int len;
- int type;
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
-
- buf = sd->buf;
- len = sd->len;
- type = sd->type;
-
- list_del(&sd->list);
- spin_unlock_irqrestore(&priv->scan_lock, flags);
- kfree(sd);
-
- if (len > 0) {
- if (type == HERMES_INQ_CHANNELINFO)
- orinoco_add_extscan_result(priv, buf, len);
- else
- orinoco_add_hostscan_results(priv, buf, len);
-
- kfree(buf);
- } else {
- /* Either abort or complete the scan */
- orinoco_scan_done(priv, (len < 0));
- }
-
- spin_lock_irqsave(&priv->scan_lock, flags);
- }
- spin_unlock_irqrestore(&priv->scan_lock, flags);
-}
-
-void __orinoco_ev_info(struct net_device *dev, struct hermes *hw)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- u16 infofid;
- struct {
- __le16 len;
- __le16 type;
- } __packed info;
- int len, type;
- int err;
-
- /* This is an answer to an INQUIRE command that we did earlier,
- * or an information "event" generated by the card
- * The controller return to us a pseudo frame containing
- * the information in question - Jean II */
- infofid = hermes_read_regn(hw, INFOFID);
-
- /* Read the info frame header - don't try too hard */
- err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
- infofid, 0);
- if (err) {
- printk(KERN_ERR "%s: error %d reading info frame. "
- "Frame dropped.\n", dev->name, err);
- return;
- }
-
- len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
- type = le16_to_cpu(info.type);
-
- switch (type) {
- case HERMES_INQ_TALLIES: {
- struct hermes_tallies_frame tallies;
- struct iw_statistics *wstats = &priv->wstats;
-
- if (len > sizeof(tallies)) {
- printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
- dev->name, len);
- len = sizeof(tallies);
- }
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
- infofid, sizeof(info));
- if (err)
- break;
-
- /* Increment our various counters */
- /* wstats->discard.nwid - no wrong BSSID stuff */
- wstats->discard.code +=
- le16_to_cpu(tallies.RxWEPUndecryptable);
- if (len == sizeof(tallies))
- wstats->discard.code +=
- le16_to_cpu(tallies.RxDiscards_WEPICVError) +
- le16_to_cpu(tallies.RxDiscards_WEPExcluded);
- wstats->discard.misc +=
- le16_to_cpu(tallies.TxDiscardsWrongSA);
- wstats->discard.fragment +=
- le16_to_cpu(tallies.RxMsgInBadMsgFragments);
- wstats->discard.retries +=
- le16_to_cpu(tallies.TxRetryLimitExceeded);
- /* wstats->miss.beacon - no match */
- }
- break;
- case HERMES_INQ_LINKSTATUS: {
- struct hermes_linkstatus linkstatus;
- u16 newstatus;
- int connected;
-
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
- break;
-
- if (len != sizeof(linkstatus)) {
- printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
- dev->name, len);
- break;
- }
-
- err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
- infofid, sizeof(info));
- if (err)
- break;
- newstatus = le16_to_cpu(linkstatus.linkstatus);
-
- /* Symbol firmware uses "out of range" to signal that
- * the hostscan frame can be requested. */
- if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
- priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
- priv->has_hostscan && priv->scan_request) {
- hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
- break;
- }
-
- connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
- || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
- || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
-
- if (connected)
- netif_carrier_on(dev);
- else if (!ignore_disconnect)
- netif_carrier_off(dev);
-
- if (newstatus != priv->last_linkstatus) {
- priv->last_linkstatus = newstatus;
- print_linkstatus(dev, newstatus);
- /* The info frame contains only one word which is the
- * status (see hermes.h). The status is pretty boring
- * in itself, that's why we export the new BSSID...
- * Jean II */
- schedule_work(&priv->wevent_work);
- }
- }
- break;
- case HERMES_INQ_SCAN:
- if (!priv->scan_request && priv->bssid_fixed &&
- priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
- schedule_work(&priv->join_work);
- break;
- }
- fallthrough;
- case HERMES_INQ_HOSTSCAN:
- case HERMES_INQ_HOSTSCAN_SYMBOL: {
- /* Result of a scanning. Contains information about
- * cells in the vicinity - Jean II */
- unsigned char *buf;
-
- /* Sanity check */
- if (len > 4096) {
- printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
- dev->name, len);
- qabort_scan(priv);
- break;
- }
-
- /* Allocate buffer for results */
- buf = kmalloc(len, GFP_ATOMIC);
- if (buf == NULL) {
- /* No memory, so can't printk()... */
- qabort_scan(priv);
- break;
- }
-
- /* Read scan data */
- err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
- infofid, sizeof(info));
- if (err) {
- kfree(buf);
- qabort_scan(priv);
- break;
- }
-
-#ifdef ORINOCO_DEBUG
- {
- int i;
- printk(KERN_DEBUG "Scan result [%02X", buf[0]);
- for (i = 1; i < (len * 2); i++)
- printk(":%02X", buf[i]);
- printk("]\n");
- }
-#endif /* ORINOCO_DEBUG */
-
- qbuf_scan(priv, buf, len, type);
- }
- break;
- case HERMES_INQ_CHANNELINFO:
- {
- struct agere_ext_scan_info *bss;
-
- if (!priv->scan_request) {
- printk(KERN_DEBUG "%s: Got chaninfo without scan, "
- "len=%d\n", dev->name, len);
- break;
- }
-
- /* An empty result indicates that the scan is complete */
- if (len == 0) {
- qbuf_scan(priv, NULL, len, type);
- break;
- }
-
- /* Sanity check */
- else if (len < (offsetof(struct agere_ext_scan_info,
- data) + 2)) {
- /* Drop this result now so we don't have to
- * keep checking later */
- printk(KERN_WARNING
- "%s: Ext scan results too short (%d bytes)\n",
- dev->name, len);
- break;
- }
-
- bss = kmalloc(len, GFP_ATOMIC);
- if (bss == NULL)
- break;
-
- /* Read scan data */
- err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
- infofid, sizeof(info));
- if (err)
- kfree(bss);
- else
- qbuf_scan(priv, bss, len, type);
-
- break;
- }
- case HERMES_INQ_SEC_STAT_AGERE:
- /* Security status (Agere specific) */
- /* Ignore this frame for now */
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
- break;
- fallthrough;
- default:
- printk(KERN_DEBUG "%s: Unknown information frame received: "
- "type 0x%04x, length %d\n", dev->name, type, len);
- /* We don't actually do anything about it */
- break;
- }
-}
-EXPORT_SYMBOL(__orinoco_ev_info);
-
-static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw)
-{
- if (net_ratelimit())
- printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
-}
-
-/********************************************************************/
-/* Internal hardware control routines */
-/********************************************************************/
-
-static int __orinoco_up(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
-
- netif_carrier_off(dev); /* just to make sure */
-
- err = __orinoco_commit(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d configuring card\n",
- dev->name, err);
- return err;
- }
-
- /* Fire things up again */
- hermes_set_irqmask(hw, ORINOCO_INTEN);
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_ERR "%s: Error %d enabling MAC port\n",
- dev->name, err);
- return err;
- }
-
- netif_start_queue(dev);
-
- return 0;
-}
-
-static int __orinoco_down(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
-
- netif_stop_queue(dev);
-
- if (!priv->hw_unavailable) {
- if (!priv->broken_disableport) {
- err = hermes_disable_port(hw, 0);
- if (err) {
- /* Some firmwares (e.g. Intersil 1.3.x) seem
- * to have problems disabling the port, oh
- * well, too bad. */
- printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
- dev->name, err);
- priv->broken_disableport = 1;
- }
- }
- hermes_set_irqmask(hw, 0);
- hermes_write_regn(hw, EVACK, 0xffff);
- }
-
- orinoco_scan_done(priv, true);
-
- /* firmware will have to reassociate */
- netif_carrier_off(dev);
- priv->last_linkstatus = 0xffff;
-
- return 0;
-}
-
-static int orinoco_reinit_firmware(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- int err;
-
- err = hw->ops->init(hw);
- if (priv->do_fw_download && !err) {
- err = orinoco_download(priv);
- if (err)
- priv->do_fw_download = 0;
- }
- if (!err)
- err = orinoco_hw_allocate_fid(priv);
-
- return err;
-}
-
-static int
-__orinoco_set_multicast_list(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int err = 0;
- int promisc, mc_count;
-
- /* The Hermes doesn't seem to have an allmulti mode, so we go
- * into promiscuous mode and let the upper levels deal. */
- if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
- (netdev_mc_count(dev) > MAX_MULTICAST(priv))) {
- promisc = 1;
- mc_count = 0;
- } else {
- promisc = 0;
- mc_count = netdev_mc_count(dev);
- }
-
- err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc);
-
- return err;
-}
-
-/* This must be called from user context, without locks held - use
- * schedule_work() */
-void orinoco_reset(struct work_struct *work)
-{
- struct orinoco_private *priv =
- container_of(work, struct orinoco_private, reset_work);
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- /* When the hardware becomes available again, whatever
- * detects that is responsible for re-initializing
- * it. So no need for anything further */
- return;
-
- netif_stop_queue(dev);
-
- /* Shut off interrupts. Depending on what state the hardware
- * is in, this might not work, but we'll try anyway */
- hermes_set_irqmask(hw, 0);
- hermes_write_regn(hw, EVACK, 0xffff);
-
- priv->hw_unavailable++;
- priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
- netif_carrier_off(dev);
-
- orinoco_unlock(priv, &flags);
-
- /* Scanning support: Notify scan cancellation */
- orinoco_scan_done(priv, true);
-
- if (priv->hard_reset) {
- err = (*priv->hard_reset)(priv);
- if (err) {
- printk(KERN_ERR "%s: orinoco_reset: Error %d "
- "performing hard reset\n", dev->name, err);
- goto disable;
- }
- }
-
- err = orinoco_reinit_firmware(priv);
- if (err) {
- printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
- dev->name, err);
- goto disable;
- }
-
- /* This has to be called from user context */
- orinoco_lock_irq(priv);
-
- priv->hw_unavailable--;
-
- /* priv->open or priv->hw_unavailable might have changed while
- * we dropped the lock */
- if (priv->open && (!priv->hw_unavailable)) {
- err = __orinoco_up(priv);
- if (err) {
- printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
- dev->name, err);
- } else
- netif_trans_update(dev);
- }
-
- orinoco_unlock_irq(priv);
-
- return;
- disable:
- hermes_set_irqmask(hw, 0);
- netif_device_detach(dev);
- printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
-}
-
-static int __orinoco_commit(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- int err = 0;
-
- /* If we've called commit, we are reconfiguring or bringing the
- * interface up. Maintaining countermeasures across this would
- * be confusing, so note that we've disabled them. The port will
- * be enabled later in orinoco_commit or __orinoco_up. */
- priv->tkip_cm_active = 0;
-
- err = orinoco_hw_program_rids(priv);
-
- /* FIXME: what about netif_tx_lock */
- (void) __orinoco_set_multicast_list(dev);
-
- return err;
-}
-
-/* Ensures configuration changes are applied. May result in a reset.
- * The caller should hold priv->lock
- */
-int orinoco_commit(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int err;
-
- if (priv->broken_disableport) {
- schedule_work(&priv->reset_work);
- return 0;
- }
-
- err = hermes_disable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to disable port "
- "while reconfiguring card\n", dev->name);
- priv->broken_disableport = 1;
- goto out;
- }
-
- err = __orinoco_commit(priv);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 0;
- }
- return err;
-}
-
-/********************************************************************/
-/* Interrupt handler */
-/********************************************************************/
-
-static void __orinoco_ev_tick(struct net_device *dev, struct hermes *hw)
-{
- printk(KERN_DEBUG "%s: TICK\n", dev->name);
-}
-
-static void __orinoco_ev_wterr(struct net_device *dev, struct hermes *hw)
-{
- /* This seems to happen a fair bit under load, but ignoring it
- seems to work fine...*/
- printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
- dev->name);
-}
-
-irqreturn_t orinoco_interrupt(int irq, void *dev_id)
-{
- struct orinoco_private *priv = dev_id;
- struct net_device *dev = priv->ndev;
- struct hermes *hw = &priv->hw;
- int count = MAX_IRQLOOPS_PER_IRQ;
- u16 evstat, events;
- /* These are used to detect a runaway interrupt situation.
- *
- * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
- * we panic and shut down the hardware
- */
- /* jiffies value the last time we were called */
- static int last_irq_jiffy; /* = 0 */
- static int loops_this_jiffy; /* = 0 */
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0) {
- /* If hw is unavailable - we don't know if the irq was
- * for us or not */
- return IRQ_HANDLED;
- }
-
- evstat = hermes_read_regn(hw, EVSTAT);
- events = evstat & hw->inten;
- if (!events) {
- orinoco_unlock(priv, &flags);
- return IRQ_NONE;
- }
-
- if (jiffies != last_irq_jiffy)
- loops_this_jiffy = 0;
- last_irq_jiffy = jiffies;
-
- while (events && count--) {
- if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
- printk(KERN_WARNING "%s: IRQ handler is looping too "
- "much! Resetting.\n", dev->name);
- /* Disable interrupts for now */
- hermes_set_irqmask(hw, 0);
- schedule_work(&priv->reset_work);
- break;
- }
-
- /* Check the card hasn't been removed */
- if (!hermes_present(hw)) {
- DEBUG(0, "orinoco_interrupt(): card removed\n");
- break;
- }
-
- if (events & HERMES_EV_TICK)
- __orinoco_ev_tick(dev, hw);
- if (events & HERMES_EV_WTERR)
- __orinoco_ev_wterr(dev, hw);
- if (events & HERMES_EV_INFDROP)
- __orinoco_ev_infdrop(dev, hw);
- if (events & HERMES_EV_INFO)
- __orinoco_ev_info(dev, hw);
- if (events & HERMES_EV_RX)
- __orinoco_ev_rx(dev, hw);
- if (events & HERMES_EV_TXEXC)
- __orinoco_ev_txexc(dev, hw);
- if (events & HERMES_EV_TX)
- __orinoco_ev_tx(dev, hw);
- if (events & HERMES_EV_ALLOC)
- __orinoco_ev_alloc(dev, hw);
-
- hermes_write_regn(hw, EVACK, evstat);
-
- evstat = hermes_read_regn(hw, EVSTAT);
- events = evstat & hw->inten;
- }
-
- orinoco_unlock(priv, &flags);
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(orinoco_interrupt);
-
-/********************************************************************/
-/* Power management */
-/********************************************************************/
-#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
-static int orinoco_pm_notifier(struct notifier_block *notifier,
- unsigned long pm_event,
- void *unused)
-{
- struct orinoco_private *priv = container_of(notifier,
- struct orinoco_private,
- pm_notifier);
-
- /* All we need to do is cache the firmware before suspend, and
- * release it when we come out.
- *
- * Only need to do this if we're downloading firmware. */
- if (!priv->do_fw_download)
- return NOTIFY_DONE;
-
- switch (pm_event) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- orinoco_cache_fw(priv, 0);
- break;
-
- case PM_POST_RESTORE:
- /* Restore from hibernation failed. We need to clean
- * up in exactly the same way, so fall through. */
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- orinoco_uncache_fw(priv);
- break;
-
- case PM_RESTORE_PREPARE:
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static void orinoco_register_pm_notifier(struct orinoco_private *priv)
-{
- priv->pm_notifier.notifier_call = orinoco_pm_notifier;
- register_pm_notifier(&priv->pm_notifier);
-}
-
-static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
-{
- unregister_pm_notifier(&priv->pm_notifier);
-}
-#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
-#define orinoco_register_pm_notifier(priv) do { } while (0)
-#define orinoco_unregister_pm_notifier(priv) do { } while (0)
-#endif
-
-/********************************************************************/
-/* Initialization */
-/********************************************************************/
-
-int orinoco_init(struct orinoco_private *priv)
-{
- struct device *dev = priv->dev;
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct hermes *hw = &priv->hw;
- int err = 0;
-
- /* No need to lock, the hw_unavailable flag is already set in
- * alloc_orinocodev() */
- priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
-
- /* Initialize the firmware */
- err = hw->ops->init(hw);
- if (err != 0) {
- dev_err(dev, "Failed to initialize firmware (err = %d)\n",
- err);
- goto out;
- }
-
- err = determine_fw_capabilities(priv, wiphy->fw_version,
- sizeof(wiphy->fw_version),
- &wiphy->hw_version);
- if (err != 0) {
- dev_err(dev, "Incompatible firmware, aborting\n");
- goto out;
- }
-
- if (priv->do_fw_download) {
-#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
- orinoco_cache_fw(priv, 0);
-#endif
-
- err = orinoco_download(priv);
- if (err)
- priv->do_fw_download = 0;
-
- /* Check firmware version again */
- err = determine_fw_capabilities(priv, wiphy->fw_version,
- sizeof(wiphy->fw_version),
- &wiphy->hw_version);
- if (err != 0) {
- dev_err(dev, "Incompatible firmware, aborting\n");
- goto out;
- }
- }
-
- if (priv->has_port3)
- dev_info(dev, "Ad-hoc demo mode supported\n");
- if (priv->has_ibss)
- dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
- if (priv->has_wep)
- dev_info(dev, "WEP supported, %s-bit key\n",
- priv->has_big_wep ? "104" : "40");
- if (priv->has_wpa) {
- dev_info(dev, "WPA-PSK supported\n");
- if (orinoco_mic_init(priv)) {
- dev_err(dev, "Failed to setup MIC crypto algorithm. "
- "Disabling WPA support\n");
- priv->has_wpa = 0;
- }
- }
-
- err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
- if (err)
- goto out;
-
- err = orinoco_hw_allocate_fid(priv);
- if (err) {
- dev_err(dev, "Failed to allocate NIC buffer!\n");
- goto out;
- }
-
- /* Set up the default configuration */
- priv->iw_mode = NL80211_IFTYPE_STATION;
- /* By default use IEEE/IBSS ad-hoc mode if we have it */
- priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
- set_port_type(priv);
- priv->channel = 0; /* use firmware default */
-
- priv->promiscuous = 0;
- priv->encode_alg = ORINOCO_ALG_NONE;
- priv->tx_key = 0;
- priv->wpa_enabled = 0;
- priv->tkip_cm_active = 0;
- priv->key_mgmt = 0;
- priv->wpa_ie_len = 0;
- priv->wpa_ie = NULL;
-
- if (orinoco_wiphy_register(wiphy)) {
- err = -ENODEV;
- goto out;
- }
-
- /* Make the hardware available, as long as it hasn't been
- * removed elsewhere (e.g. by PCMCIA hot unplug) */
- orinoco_lock_irq(priv);
- priv->hw_unavailable--;
- orinoco_unlock_irq(priv);
-
- dev_dbg(dev, "Ready\n");
-
- out:
- return err;
-}
-EXPORT_SYMBOL(orinoco_init);
-
-static const struct net_device_ops orinoco_netdev_ops = {
- .ndo_open = orinoco_open,
- .ndo_stop = orinoco_stop,
- .ndo_start_xmit = orinoco_xmit,
- .ndo_set_rx_mode = orinoco_set_multicast_list,
- .ndo_change_mtu = orinoco_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_tx_timeout = orinoco_tx_timeout,
-};
-
-/* Allocate private data.
- *
- * This driver has a number of structures associated with it
- * netdev - Net device structure for each network interface
- * wiphy - structure associated with wireless phy
- * wireless_dev (wdev) - structure for each wireless interface
- * hw - structure for hermes chip info
- * card - card specific structure for use by the card driver
- * (airport, orinoco_cs)
- * priv - orinoco private data
- * device - generic linux device structure
- *
- * +---------+ +---------+
- * | wiphy | | netdev |
- * | +-------+ | +-------+
- * | | priv | | | wdev |
- * | | +-----+ +-+-------+
- * | | | hw |
- * | +-+-----+
- * | | card |
- * +-+-------+
- *
- * priv has a link to netdev and device
- * wdev has a link to wiphy
- */
-struct orinoco_private
-*alloc_orinocodev(int sizeof_card,
- struct device *device,
- int (*hard_reset)(struct orinoco_private *),
- int (*stop_fw)(struct orinoco_private *, int))
-{
- struct orinoco_private *priv;
- struct wiphy *wiphy;
-
- /* allocate wiphy
- * NOTE: We only support a single virtual interface
- * but this may change when monitor mode is added
- */
- wiphy = wiphy_new(&orinoco_cfg_ops,
- sizeof(struct orinoco_private) + sizeof_card);
- if (!wiphy)
- return NULL;
-
- priv = wiphy_priv(wiphy);
- priv->dev = device;
-
- if (sizeof_card)
- priv->card = (void *)((unsigned long)priv
- + sizeof(struct orinoco_private));
- else
- priv->card = NULL;
-
- orinoco_wiphy_init(wiphy);
-
-#ifdef WIRELESS_SPY
- priv->wireless_data.spy_data = &priv->spy_data;
-#endif
-
- /* Set up default callbacks */
- priv->hard_reset = hard_reset;
- priv->stop_fw = stop_fw;
-
- spin_lock_init(&priv->lock);
- priv->open = 0;
- priv->hw_unavailable = 1; /* orinoco_init() must clear this
- * before anything else touches the
- * hardware */
- INIT_WORK(&priv->reset_work, orinoco_reset);
- INIT_WORK(&priv->join_work, orinoco_join_ap);
- INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
-
- INIT_LIST_HEAD(&priv->rx_list);
- tasklet_setup(&priv->rx_tasklet, orinoco_rx_isr_tasklet);
-
- spin_lock_init(&priv->scan_lock);
- INIT_LIST_HEAD(&priv->scan_list);
- INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
-
- priv->last_linkstatus = 0xffff;
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
- priv->cached_pri_fw = NULL;
- priv->cached_fw = NULL;
-#endif
-
- /* Register PM notifiers */
- orinoco_register_pm_notifier(priv);
-
- return priv;
-}
-EXPORT_SYMBOL(alloc_orinocodev);
-
-/* We can only support a single interface. We provide a separate
- * function to set it up to distinguish between hardware
- * initialisation and interface setup.
- *
- * The base_addr and irq parameters are passed on to netdev for use
- * with SIOCGIFMAP.
- */
-int orinoco_if_add(struct orinoco_private *priv,
- unsigned long base_addr,
- unsigned int irq,
- const struct net_device_ops *ops)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct wireless_dev *wdev;
- struct net_device *dev;
- int ret;
-
- dev = alloc_etherdev(sizeof(struct wireless_dev));
-
- if (!dev)
- return -ENOMEM;
-
- /* Initialise wireless_dev */
- wdev = netdev_priv(dev);
- wdev->wiphy = wiphy;
- wdev->iftype = NL80211_IFTYPE_STATION;
-
- /* Setup / override net_device fields */
- dev->ieee80211_ptr = wdev;
- dev->watchdog_timeo = HZ; /* 1 second timeout */
- dev->wireless_handlers = &orinoco_handler_def;
-#ifdef WIRELESS_SPY
- dev->wireless_data = &priv->wireless_data;
-#endif
- /* Default to standard ops if not set */
- if (ops)
- dev->netdev_ops = ops;
- else
- dev->netdev_ops = &orinoco_netdev_ops;
-
- /* we use the default eth_mac_addr for setting the MAC addr */
-
- /* Reserve space in skb for the SNAP header */
- dev->needed_headroom = ENCAPS_OVERHEAD;
-
- netif_carrier_off(dev);
-
- eth_hw_addr_set(dev, wiphy->perm_addr);
-
- dev->base_addr = base_addr;
- dev->irq = irq;
-
- dev->min_mtu = ORINOCO_MIN_MTU;
- dev->max_mtu = ORINOCO_MAX_MTU;
-
- SET_NETDEV_DEV(dev, priv->dev);
- ret = register_netdev(dev);
- if (ret)
- goto fail;
-
- priv->ndev = dev;
-
- /* Report what we've done */
- dev_dbg(priv->dev, "Registered interface %s.\n", dev->name);
-
- return 0;
-
- fail:
- free_netdev(dev);
- return ret;
-}
-EXPORT_SYMBOL(orinoco_if_add);
-
-void orinoco_if_del(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
-
- unregister_netdev(dev);
- free_netdev(dev);
-}
-EXPORT_SYMBOL(orinoco_if_del);
-
-void free_orinocodev(struct orinoco_private *priv)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct orinoco_rx_data *rx_data, *temp;
- struct orinoco_scan_data *sd, *sdtemp;
-
- /* If the tasklet is scheduled when we call tasklet_kill it
- * will run one final time. However the tasklet will only
- * drain priv->rx_list if the hw is still available. */
- tasklet_kill(&priv->rx_tasklet);
-
- /* Explicitly drain priv->rx_list */
- list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
- list_del(&rx_data->list);
-
- dev_kfree_skb(rx_data->skb);
- kfree(rx_data->desc);
- kfree(rx_data);
- }
-
- cancel_work_sync(&priv->process_scan);
- /* Explicitly drain priv->scan_list */
- list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
- list_del(&sd->list);
-
- if (sd->len > 0)
- kfree(sd->buf);
- kfree(sd);
- }
-
- orinoco_unregister_pm_notifier(priv);
- orinoco_uncache_fw(priv);
-
- priv->wpa_ie_len = 0;
- kfree(priv->wpa_ie);
- orinoco_mic_free(priv);
- wiphy_free(wiphy);
-}
-EXPORT_SYMBOL(free_orinocodev);
-
-int orinoco_up(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- unsigned long flags;
- int err;
-
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
-
- err = orinoco_reinit_firmware(priv);
- if (err) {
- printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
- dev->name, err);
- goto exit;
- }
-
- netif_device_attach(dev);
- priv->hw_unavailable--;
-
- if (priv->open && !priv->hw_unavailable) {
- err = __orinoco_up(priv);
- if (err)
- printk(KERN_ERR "%s: Error %d restarting card\n",
- dev->name, err);
- }
-
-exit:
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- return 0;
-}
-EXPORT_SYMBOL(orinoco_up);
-
-void orinoco_down(struct orinoco_private *priv)
-{
- struct net_device *dev = priv->ndev;
- unsigned long flags;
- int err;
-
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- err = __orinoco_down(priv);
- if (err)
- printk(KERN_WARNING "%s: Error %d downing interface\n",
- dev->name, err);
-
- netif_device_detach(dev);
- priv->hw_unavailable++;
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-}
-EXPORT_SYMBOL(orinoco_down);
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (David Gibson <[email protected]>, "
- "Pavel Roskin <[email protected]>, et al)";
-
-static int __init init_orinoco(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return 0;
-}
-
-static void __exit exit_orinoco(void)
-{
-}
-
-module_init(init_orinoco);
-module_exit(exit_orinoco);
diff --git a/drivers/net/wireless/intersil/orinoco/main.h b/drivers/net/wireless/intersil/orinoco/main.h
deleted file mode 100644
index 5a8fec26136ef..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/main.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Exports from main to helper modules
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_MAIN_H_
-#define _ORINOCO_MAIN_H_
-
-#include <linux/ieee80211.h>
-#include "orinoco.h"
-
-/********************************************************************/
-/* Compile time configuration and compatibility stuff */
-/********************************************************************/
-
-/* We do this this way to avoid ifdefs in the actual code */
-#ifdef WIRELESS_SPY
-#define SPY_NUMBER(priv) (priv->spy_data.spy_number)
-#else
-#define SPY_NUMBER(priv) 0
-#endif /* WIRELESS_SPY */
-
-/********************************************************************/
-
-/* Export module parameter */
-extern int force_monitor;
-
-/* Forward declarations */
-struct net_device;
-struct work_struct;
-
-void set_port_type(struct orinoco_private *priv);
-int orinoco_commit(struct orinoco_private *priv);
-void orinoco_reset(struct work_struct *work);
-
-/* Information element helpers - find a home for these... */
-#define WPA_OUI_TYPE "\x00\x50\xF2\x01"
-#define WPA_SELECTOR_LEN 4
-static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
-{
- u8 *p = data;
- while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) &&
- (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
- return p;
- p += p[1] + 2;
- }
- return NULL;
-}
-
-#endif /* _ORINOCO_MAIN_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c
deleted file mode 100644
index a324bc4b79388..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/mic.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Orinoco MIC helpers
- *
- * See copyright notice in main.c
- */
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/if_ether.h>
-#include <linux/scatterlist.h>
-#include <crypto/hash.h>
-
-#include "orinoco.h"
-#include "mic.h"
-
-/********************************************************************/
-/* Michael MIC crypto setup */
-/********************************************************************/
-int orinoco_mic_init(struct orinoco_private *priv)
-{
- priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->tx_tfm_mic)) {
- printk(KERN_DEBUG "%s: could not allocate "
- "crypto API michael_mic\n", __func__);
- priv->tx_tfm_mic = NULL;
- return -ENOMEM;
- }
-
- priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
- if (IS_ERR(priv->rx_tfm_mic)) {
- printk(KERN_DEBUG "%s: could not allocate "
- "crypto API michael_mic\n", __func__);
- priv->rx_tfm_mic = NULL;
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void orinoco_mic_free(struct orinoco_private *priv)
-{
- if (priv->tx_tfm_mic)
- crypto_free_shash(priv->tx_tfm_mic);
- if (priv->rx_tfm_mic)
- crypto_free_shash(priv->rx_tfm_mic);
-}
-
-int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
- u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic)
-{
- SHASH_DESC_ON_STACK(desc, tfm_michael);
- u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
- int err;
-
- if (tfm_michael == NULL) {
- printk(KERN_WARNING "%s: tfm_michael == NULL\n", __func__);
- return -1;
- }
-
- /* Copy header into buffer. We need the padding on the end zeroed */
- memcpy(&hdr[0], da, ETH_ALEN);
- memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
- hdr[ETH_ALEN * 2] = priority;
- hdr[ETH_ALEN * 2 + 1] = 0;
- hdr[ETH_ALEN * 2 + 2] = 0;
- hdr[ETH_ALEN * 2 + 3] = 0;
-
- desc->tfm = tfm_michael;
-
- err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
- if (err)
- return err;
-
- err = crypto_shash_init(desc);
- if (err)
- return err;
-
- err = crypto_shash_update(desc, hdr, sizeof(hdr));
- if (err)
- return err;
-
- err = crypto_shash_update(desc, data, data_len);
- if (err)
- return err;
-
- err = crypto_shash_final(desc, mic);
- shash_desc_zero(desc);
-
- return err;
-}
diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h
deleted file mode 100644
index e8724e8892194..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/mic.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Orinoco MIC helpers
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_MIC_H_
-#define _ORINOCO_MIC_H_
-
-#include <linux/types.h>
-#include <crypto/hash.h>
-
-#define MICHAEL_MIC_LEN 8
-
-/* Forward declarations */
-struct orinoco_private;
-struct crypto_ahash;
-
-int orinoco_mic_init(struct orinoco_private *priv);
-void orinoco_mic_free(struct orinoco_private *priv);
-int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
- u8 *da, u8 *sa, u8 priority,
- u8 *data, size_t data_len, u8 *mic);
-
-#endif /* ORINOCO_MIC_H */
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h
deleted file mode 100644
index cdd026af100b6..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/* orinoco.h
- *
- * Common definitions to all pieces of the various orinoco
- * drivers
- */
-
-#ifndef _ORINOCO_H
-#define _ORINOCO_H
-
-#define DRIVER_VERSION "0.15"
-
-#include <linux/interrupt.h>
-#include <linux/suspend.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-#include <net/cfg80211.h>
-
-#include "hermes.h"
-
-/* To enable debug messages */
-/*#define ORINOCO_DEBUG 3*/
-
-#define WIRELESS_SPY /* enable iwspy support */
-
-#define MAX_SCAN_LEN 4096
-
-#define ORINOCO_SEQ_LEN 8
-#define ORINOCO_MAX_KEY_SIZE 14
-#define ORINOCO_MAX_KEYS 4
-
-struct orinoco_key {
- __le16 len; /* always stored as little-endian */
- char data[ORINOCO_MAX_KEY_SIZE];
-} __packed;
-
-#define TKIP_KEYLEN 16
-#define MIC_KEYLEN 8
-
-struct orinoco_tkip_key {
- u8 tkip[TKIP_KEYLEN];
- u8 tx_mic[MIC_KEYLEN];
- u8 rx_mic[MIC_KEYLEN];
-};
-
-enum orinoco_alg {
- ORINOCO_ALG_NONE,
- ORINOCO_ALG_WEP,
- ORINOCO_ALG_TKIP
-};
-
-enum fwtype {
- FIRMWARE_TYPE_AGERE,
- FIRMWARE_TYPE_INTERSIL,
- FIRMWARE_TYPE_SYMBOL
-};
-
-struct firmware;
-
-struct orinoco_private {
- void *card; /* Pointer to card dependent structure */
- struct device *dev;
- int (*hard_reset)(struct orinoco_private *);
- int (*stop_fw)(struct orinoco_private *, int);
-
- struct ieee80211_supported_band band;
- struct ieee80211_channel channels[14];
- u32 cipher_suites[3];
-
- /* Synchronisation stuff */
- spinlock_t lock;
- int hw_unavailable;
- struct work_struct reset_work;
-
- /* Interrupt tasklets */
- struct tasklet_struct rx_tasklet;
- struct list_head rx_list;
-
- /* driver state */
- int open;
- u16 last_linkstatus;
- struct work_struct join_work;
- struct work_struct wevent_work;
-
- /* Net device stuff */
- struct net_device *ndev;
- struct iw_statistics wstats;
-
- /* Hardware control variables */
- struct hermes hw;
- u16 txfid;
-
- /* Capabilities of the hardware/firmware */
- enum fwtype firmware_type;
- int ibss_port;
- int nicbuf_size;
- u16 channel_mask;
-
- /* Boolean capabilities */
- unsigned int has_ibss:1;
- unsigned int has_port3:1;
- unsigned int has_wep:1;
- unsigned int has_big_wep:1;
- unsigned int has_mwo:1;
- unsigned int has_pm:1;
- unsigned int has_preamble:1;
- unsigned int has_sensitivity:1;
- unsigned int has_hostscan:1;
- unsigned int has_alt_txcntl:1;
- unsigned int has_ext_scan:1;
- unsigned int has_wpa:1;
- unsigned int do_fw_download:1;
- unsigned int broken_disableport:1;
- unsigned int broken_monitor:1;
- unsigned int prefer_port3:1;
-
- /* Configuration paramaters */
- enum nl80211_iftype iw_mode;
- enum orinoco_alg encode_alg;
- u16 wep_restrict, tx_key;
- struct key_params keys[ORINOCO_MAX_KEYS];
-
- int bitratemode;
- char nick[IW_ESSID_MAX_SIZE + 1];
- char desired_essid[IW_ESSID_MAX_SIZE + 1];
- char desired_bssid[ETH_ALEN];
- int bssid_fixed;
- u16 frag_thresh, mwo_robust;
- u16 channel;
- u16 ap_density, rts_thresh;
- u16 pm_on, pm_mcast, pm_period, pm_timeout;
- u16 preamble;
- u16 short_retry_limit, long_retry_limit;
- u16 retry_lifetime;
-#ifdef WIRELESS_SPY
- struct iw_spy_data spy_data; /* iwspy support */
- struct iw_public_data wireless_data;
-#endif
-
- /* Configuration dependent variables */
- int port_type, createibss;
- int promiscuous, mc_count;
-
- /* Scanning support */
- struct cfg80211_scan_request *scan_request;
- struct work_struct process_scan;
- struct list_head scan_list;
- spinlock_t scan_lock; /* protects the scan list */
-
- /* WPA support */
- u8 *wpa_ie;
- int wpa_ie_len;
-
- struct crypto_shash *rx_tfm_mic;
- struct crypto_shash *tx_tfm_mic;
-
- unsigned int wpa_enabled:1;
- unsigned int tkip_cm_active:1;
- unsigned int key_mgmt:3;
-
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
- /* Cached in memory firmware to use during ->resume. */
- const struct firmware *cached_pri_fw;
- const struct firmware *cached_fw;
-#endif
-
- struct notifier_block pm_notifier;
-};
-
-#ifdef ORINOCO_DEBUG
-extern int orinoco_debug;
-#define DEBUG(n, args...) do { \
- if (orinoco_debug > (n)) \
- printk(KERN_DEBUG args); \
-} while (0)
-#else
-#define DEBUG(n, args...) do { } while (0)
-#endif /* ORINOCO_DEBUG */
-
-/********************************************************************/
-/* Exported prototypes */
-/********************************************************************/
-
-struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device,
- int (*hard_reset)(struct orinoco_private *),
- int (*stop_fw)(struct orinoco_private *, int));
-void free_orinocodev(struct orinoco_private *priv);
-int orinoco_init(struct orinoco_private *priv);
-int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr,
- unsigned int irq, const struct net_device_ops *ops);
-void orinoco_if_del(struct orinoco_private *priv);
-int orinoco_up(struct orinoco_private *priv);
-void orinoco_down(struct orinoco_private *priv);
-irqreturn_t orinoco_interrupt(int irq, void *dev_id);
-
-void __orinoco_ev_info(struct net_device *dev, struct hermes *hw);
-void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw);
-
-int orinoco_process_xmit_skb(struct sk_buff *skb,
- struct net_device *dev,
- struct orinoco_private *priv,
- int *tx_control,
- u8 *mic);
-
-/* Common ndo functions exported for reuse by orinoco_usb */
-int orinoco_open(struct net_device *dev);
-int orinoco_stop(struct net_device *dev);
-void orinoco_set_multicast_list(struct net_device *dev);
-int orinoco_change_mtu(struct net_device *dev, int new_mtu);
-void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue);
-
-/********************************************************************/
-/* Locking and synchronization functions */
-/********************************************************************/
-
-static inline int orinoco_lock(struct orinoco_private *priv,
- unsigned long *flags)
-{
- priv->hw.ops->lock_irqsave(&priv->lock, flags);
- if (priv->hw_unavailable) {
- DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
- priv->ndev);
- priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
- return -EBUSY;
- }
- return 0;
-}
-
-static inline void orinoco_unlock(struct orinoco_private *priv,
- unsigned long *flags)
-{
- priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
-}
-
-static inline void orinoco_lock_irq(struct orinoco_private *priv)
-{
- priv->hw.ops->lock_irq(&priv->lock);
-}
-
-static inline void orinoco_unlock_irq(struct orinoco_private *priv)
-{
- priv->hw.ops->unlock_irq(&priv->lock);
-}
-
-/*** Navigate from net_device to orinoco_private ***/
-static inline struct orinoco_private *ndev_priv(struct net_device *dev)
-{
- struct wireless_dev *wdev = netdev_priv(dev);
- return wdev_priv(wdev);
-}
-#endif /* _ORINOCO_H */
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c b/drivers/net/wireless/intersil/orinoco/orinoco_cs.c
deleted file mode 100644
index 03bfd2482656c..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_cs.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/* orinoco_cs.c (formerly known as dldwd_cs.c)
- *
- * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
- * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
- * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
- * It should also be usable on various Prism II based cards such as the
- * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
- * cards such as the 3Com AirConnect and Ericsson WLAN.
- *
- * Copyright notice & release notes in file main.c
- */
-
-#define DRIVER_NAME "orinoco_cs"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module stuff */
-/********************************************************************/
-
-MODULE_AUTHOR("David Gibson <[email protected]>");
-MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco,"
- " Prism II based and similar wireless cards");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Module parameters */
-
-/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
- * don't have any CIS entry for it. This workaround it... */
-static int ignore_cis_vcc; /* = 0 */
-module_param(ignore_cis_vcc, int, 0);
-MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
-
-/********************************************************************/
-/* Data structures */
-/********************************************************************/
-
-/* PCMCIA specific device information (goes in the card field of
- * struct orinoco_private */
-struct orinoco_pccard {
- struct pcmcia_device *p_dev;
-
- /* Used to handle hard reset */
- /* yuck, we need this hack to work around the insanity of the
- * PCMCIA layer */
- unsigned long hard_reset_in_progress;
-};
-
-
-/********************************************************************/
-/* Function prototypes */
-/********************************************************************/
-
-static int orinoco_cs_config(struct pcmcia_device *link);
-static void orinoco_cs_release(struct pcmcia_device *link);
-static void orinoco_cs_detach(struct pcmcia_device *p_dev);
-
-/********************************************************************/
-/* Device methods */
-/********************************************************************/
-
-static int
-orinoco_cs_hard_reset(struct orinoco_private *priv)
-{
- struct orinoco_pccard *card = priv->card;
- struct pcmcia_device *link = card->p_dev;
- int err;
-
- /* We need atomic ops here, because we're not holding the lock */
- set_bit(0, &card->hard_reset_in_progress);
-
- err = pcmcia_reset_card(link->socket);
- if (err)
- return err;
-
- msleep(100);
- clear_bit(0, &card->hard_reset_in_progress);
-
- return 0;
-}
-
-/********************************************************************/
-/* PCMCIA stuff */
-/********************************************************************/
-
-static int
-orinoco_cs_probe(struct pcmcia_device *link)
-{
- struct orinoco_private *priv;
- struct orinoco_pccard *card;
- int ret;
-
- priv = alloc_orinocodev(sizeof(*card), &link->dev,
- orinoco_cs_hard_reset, NULL);
- if (!priv)
- return -ENOMEM;
- card = priv->card;
-
- /* Link both structures together */
- card->p_dev = link;
- link->priv = priv;
-
- ret = orinoco_cs_config(link);
- if (ret)
- goto err_free_orinocodev;
-
- return 0;
-
-err_free_orinocodev:
- free_orinocodev(priv);
- return ret;
-}
-
-static void orinoco_cs_detach(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
-
- orinoco_if_del(priv);
-
- orinoco_cs_release(link);
-
- wiphy_unregister(priv_to_wiphy(priv));
- free_orinocodev(priv);
-} /* orinoco_cs_detach */
-
-static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-};
-
-static int
-orinoco_cs_config(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct hermes *hw = &priv->hw;
- int ret;
- void __iomem *mem;
-
- link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
- CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
- if (ignore_cis_vcc)
- link->config_flags &= ~CONF_AUTO_CHECK_VCC;
- ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
- if (ret) {
- if (!ignore_cis_vcc)
- printk(KERN_ERR PFX "GetNextTuple(): No matching "
- "CIS configuration. Maybe you need the "
- "ignore_cis_vcc=1 parameter.\n");
- goto failed;
- }
-
- mem = ioport_map(link->resource[0]->start,
- resource_size(link->resource[0]));
- if (!mem)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
- hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
-
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto failed;
- }
-
- /* Register an interface with the stack */
- if (orinoco_if_add(priv, link->resource[0]->start,
- link->irq, NULL) != 0) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto failed;
- }
-
- return 0;
-
- failed:
- orinoco_cs_release(link);
- return -ENODEV;
-} /* orinoco_cs_config */
-
-static void
-orinoco_cs_release(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- unsigned long flags;
-
- /* We're committed to taking the device away now, so mark the
- * hardware as unavailable */
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- priv->hw_unavailable++;
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- pcmcia_disable_device(link);
- if (priv->hw.iobase)
- ioport_unmap(priv->hw.iobase);
-} /* orinoco_cs_release */
-
-static int orinoco_cs_suspend(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct orinoco_pccard *card = priv->card;
-
- /* This is probably racy, but I can't think of
- a better way, short of rewriting the PCMCIA
- layer to not suck :-( */
- if (!test_bit(0, &card->hard_reset_in_progress))
- orinoco_down(priv);
-
- return 0;
-}
-
-static int orinoco_cs_resume(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct orinoco_pccard *card = priv->card;
- int err = 0;
-
- if (!test_bit(0, &card->hard_reset_in_progress))
- err = orinoco_up(priv);
-
- return err;
-}
-
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-static const struct pcmcia_device_id orinoco_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
- PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
- PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
- PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
- PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */
- PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
- PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
- PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
- PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
- PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
- PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
- PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
- PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
- PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
- PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
- PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
- PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
- PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
- PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
- PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
- PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
- PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
- PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
- PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
- PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
- PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
- PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
- PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
- PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
- PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
- PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */
-#ifdef CONFIG_HERMES_PRISM
- /* Only entries that certainly identify Prism chipset */
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
- PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
- PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
- PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
- PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
- PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
- PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
- PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
- PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
- PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
- PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */
- PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */
- PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
- PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
- PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
- PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
- PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
- PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
- PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
- PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
- PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
- PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
- PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
- PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
- PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
- PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
- PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
- PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
- PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
- PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
- PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
- PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
- PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
- PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
- PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
- PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
- PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
- PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
- PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
- PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
- PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
- PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
-
- /* This may be Agere or Intersil Firmware */
- PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
-#endif
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
-
-static struct pcmcia_driver orinoco_driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- .probe = orinoco_cs_probe,
- .remove = orinoco_cs_detach,
- .id_table = orinoco_cs_ids,
- .suspend = orinoco_cs_suspend,
- .resume = orinoco_cs_resume,
-};
-module_pcmcia_driver(orinoco_driver);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c b/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c
deleted file mode 100644
index 18bd0d9876c23..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* orinoco_nortel.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
- * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
- *
- * Copyright (C) 2002 Tobias Hoffmann
- * (C) 2003 Christoph Jungegger <[email protected]>
- *
- * Some of this code is borrowed from orinoco_plx.c
- * Copyright (C) 2001 Daniel Barlow
- * Some of this code is borrowed from orinoco_pci.c
- * Copyright (C) 2001 Jean Tourrilhes
- * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
- * has been copied from it. linux-wlan-ng-0.1.10 is originally :
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#define DRIVER_NAME "orinoco_nortel"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
-#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- * We need this to get going...
- * This is the part of the code that is strongly inspired from wlan-ng
- *
- * Note bis : Don't try to access HERMES_CMD during the reset phase.
- * It just won't work !
- */
-static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
-{
- struct orinoco_pci_card *card = priv->card;
-
- /* Assert the reset until the card notices */
- iowrite16(8, card->bridge_io + 2);
- ioread16(card->attr_io + COR_OFFSET);
- iowrite16(0x80, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- /* Give time for the card to recover from this hard effort */
- iowrite16(0, card->attr_io + COR_OFFSET);
- iowrite16(0, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- /* Set COR as usual */
- iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
- iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- iowrite16(0x228, card->bridge_io + 2);
-
- return 0;
-}
-
-static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
-{
- int i;
- u32 reg;
-
- /* Setup bridge */
- if (ioread16(card->bridge_io) & 1) {
- printk(KERN_ERR PFX "brg1 answer1 wrong\n");
- return -EBUSY;
- }
- iowrite16(0x118, card->bridge_io + 2);
- iowrite16(0x108, card->bridge_io + 2);
- mdelay(30);
- iowrite16(0x8, card->bridge_io + 2);
- for (i = 0; i < 30; i++) {
- mdelay(30);
- if (ioread16(card->bridge_io) & 0x10)
- break;
- }
- if (i == 30) {
- printk(KERN_ERR PFX "brg1 timed out\n");
- return -EBUSY;
- }
- if (ioread16(card->attr_io + COR_OFFSET) & 1) {
- printk(KERN_ERR PFX "brg2 answer1 wrong\n");
- return -EBUSY;
- }
- if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
- printk(KERN_ERR PFX "brg2 answer2 wrong\n");
- return -EBUSY;
- }
- if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
- printk(KERN_ERR PFX "brg2 answer3 wrong\n");
- return -EBUSY;
- }
-
- /* Set the PCMCIA COR register */
- iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
- mdelay(1);
- reg = ioread16(card->attr_io + COR_OFFSET);
- if (reg != COR_VALUE) {
- printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
- reg);
- return -EBUSY;
- }
-
- /* Set LEDs */
- iowrite16(1, card->bridge_io + 10);
- return 0;
-}
-
-static int orinoco_nortel_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io, *bridge_io, *attr_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- bridge_io = pci_iomap(pdev, 0, 0);
- if (!bridge_io) {
- printk(KERN_ERR PFX "Cannot map bridge registers\n");
- err = -EIO;
- goto fail_map_bridge;
- }
-
- attr_io = pci_iomap(pdev, 1, 0);
- if (!attr_io) {
- printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
- err = -EIO;
- goto fail_map_attr;
- }
-
- hermes_io = pci_iomap(pdev, 2, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot map chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_nortel_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
- card->bridge_io = bridge_io;
- card->attr_io = attr_io;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_nortel_hw_init(card);
- if (err) {
- printk(KERN_ERR PFX "Hardware initialization failed\n");
- goto fail;
- }
-
- err = orinoco_nortel_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail_wiphy;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail_wiphy:
- wiphy_unregister(priv_to_wiphy(priv));
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_iounmap(pdev, attr_io);
-
- fail_map_attr:
- pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_nortel_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct orinoco_pci_card *card = priv->card;
-
- /* Clear LEDs */
- iowrite16(0, card->bridge_io + 10);
-
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(priv));
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_iounmap(pdev, card->attr_io);
- pci_iounmap(pdev, card->bridge_io);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_nortel_id_table[] = {
- /* Nortel emobility PCI */
- {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
- /* Symbol LA-4123 PCI */
- {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,},
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
-
-static struct pci_driver orinoco_nortel_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_nortel_id_table,
- .probe = orinoco_nortel_init_one,
- .remove = orinoco_nortel_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Tobias Hoffmann & Christoph Jungegger <[email protected]>)";
-MODULE_AUTHOR("Christoph Jungegger <[email protected]>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_nortel_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_nortel_driver);
-}
-
-static void __exit orinoco_nortel_exit(void)
-{
- pci_unregister_driver(&orinoco_nortel_driver);
-}
-
-module_init(orinoco_nortel_init);
-module_exit(orinoco_nortel_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c b/drivers/net/wireless/intersil/orinoco/orinoco_pci.c
deleted file mode 100644
index 7e3a6dd60c157..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* orinoco_pci.c
- *
- * Driver for Prism 2.5/3 devices that have a direct PCI interface
- * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
- * The card contains only one PCI region, which contains all the usual
- * hermes registers, as well as the COR register.
- *
- * Current maintainers are:
- * Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * Some of this code is borrowed from orinoco_plx.c
- * Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
- * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
- * has been copied from it. linux-wlan-ng-0.1.10 is originally :
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- * This file originally written by:
- * Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com>
- * And is now maintained by:
- * (C) Copyright David Gibson, IBM Corp. 2002-2003.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- */
-
-#define DRIVER_NAME "orinoco_pci"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-/* Offset of the COR register of the PCI card */
-#define HERMES_PCI_COR (0x26)
-
-/* Bitmask to reset the card */
-#define HERMES_PCI_COR_MASK (0x0080)
-
-/* Magic timeouts for doing the reset.
- * Those times are straight from wlan-ng, and it is claimed that they
- * are necessary. Alan will kill me. Take your time and grab a coffee. */
-#define HERMES_PCI_COR_ONT (250) /* ms */
-#define HERMES_PCI_COR_OFFT (500) /* ms */
-#define HERMES_PCI_COR_BUSYT (500) /* ms */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- * We need this to get going...
- * This is the part of the code that is strongly inspired from wlan-ng
- *
- * Note : This code is done with irq enabled. This mean that many
- * interrupts will occur while we are there. This is why we use the
- * jiffies to regulate time instead of a straight mdelay(). Usually we
- * need only around 245 iteration of the loop to do 250 ms delay.
- *
- * Note bis : Don't try to access HERMES_CMD during the reset phase.
- * It just won't work !
- */
-static int orinoco_pci_cor_reset(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- unsigned long timeout;
- u16 reg;
-
- /* Assert the reset until the card notices */
- hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
- mdelay(HERMES_PCI_COR_ONT);
-
- /* Give time for the card to recover from this hard effort */
- hermes_write_regn(hw, PCI_COR, 0x0000);
- mdelay(HERMES_PCI_COR_OFFT);
-
- /* The card is ready when it's no longer busy */
- timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT);
- reg = hermes_read_regn(hw, CMD);
- while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
- mdelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* Still busy? */
- if (reg & HERMES_CMD_BUSY) {
- printk(KERN_ERR PFX "Busy timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int orinoco_pci_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- hermes_io = pci_iomap(pdev, 0, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot remap chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_pci_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_pci_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail_wiphy;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail_wiphy:
- wiphy_unregister(priv_to_wiphy(priv));
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_pci_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
-
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(priv));
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_pci_id_table[] = {
- /* Intersil Prism 3 */
- {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
- /* Intersil Prism 2.5 */
- {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
- /* Samsung MagicLAN SWL-2210P */
- {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
-
-static struct pci_driver orinoco_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_pci_id_table,
- .probe = orinoco_pci_init_one,
- .remove = orinoco_pci_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Pavel Roskin <[email protected]>,"
- " David Gibson <[email protected]> &"
- " Jean Tourrilhes <[email protected]>)";
-MODULE_AUTHOR("Pavel Roskin <[email protected]> &"
- " David Gibson <[email protected]>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_pci_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_pci_driver);
-}
-
-static void __exit orinoco_pci_exit(void)
-{
- pci_unregister_driver(&orinoco_pci_driver);
-}
-
-module_init(orinoco_pci_init);
-module_exit(orinoco_pci_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h b/drivers/net/wireless/intersil/orinoco/orinoco_pci.h
deleted file mode 100644
index d49d940864b41..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_pci.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* orinoco_pci.h
- *
- * Common code for all Orinoco drivers for PCI devices, including
- * both native PCI and PCMCIA-to-PCI bridges.
- *
- * Copyright (C) 2005, Pavel Roskin.
- * See main.c for license.
- */
-
-#ifndef _ORINOCO_PCI_H
-#define _ORINOCO_PCI_H
-
-#include <linux/netdevice.h>
-
-/* Driver specific data */
-struct orinoco_pci_card {
- void __iomem *bridge_io;
- void __iomem *attr_io;
-};
-
-static int __maybe_unused orinoco_pci_suspend(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct orinoco_private *priv = pci_get_drvdata(pdev);
-
- orinoco_down(priv);
- free_irq(pdev->irq, priv);
-
- return 0;
-}
-
-static int __maybe_unused orinoco_pci_resume(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct net_device *dev = priv->ndev;
- int err;
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- dev->name, priv);
- if (err) {
- printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
- dev->name);
- return -EBUSY;
- }
-
- return orinoco_up(priv);
-}
-
-static SIMPLE_DEV_PM_OPS(orinoco_pci_pm_ops,
- orinoco_pci_suspend,
- orinoco_pci_resume);
-
-#endif /* _ORINOCO_PCI_H */
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c b/drivers/net/wireless/intersil/orinoco/orinoco_plx.c
deleted file mode 100644
index 73e6ae1240130..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_plx.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/* orinoco_plx.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a PLX9052.
- *
- * Current maintainers are:
- * Pavel Roskin <proski AT gnu.org>
- * and David Gibson <hermes AT gibson.dropbear.id.au>
- *
- * (C) Copyright David Gibson, IBM Corp. 2001-2003.
- * Copyright (C) 2001 Daniel Barlow
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * Here's the general details on how the PLX9052 adapter works:
- *
- * - Two PCI I/O address spaces, one 0x80 long which contains the
- * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
- * slot I/O address space.
- *
- * - One PCI memory address space, mapped to the PCMCIA attribute space
- * (containing the CIS).
- *
- * Using the later, you can read through the CIS data to make sure the
- * card is compatible with the driver. Keep in mind that the PCMCIA
- * spec specifies the CIS as the lower 8 bits of each word read from
- * the CIS, so to read the bytes of the CIS, read every other byte
- * (0,2,4,...). Passing that test, you need to enable the I/O address
- * space on the PCMCIA card via the PCMCIA COR register. This is the
- * first byte following the CIS. In my case (which may not have any
- * relation to what's on the PRISM2 cards), COR was at offset 0x800
- * within the PCI memory space. Write 0x41 to the COR register to
- * enable I/O mode and to select level triggered interrupts. To
- * confirm you actually succeeded, read the COR register back and make
- * sure it actually got set to 0x41, in case you have an unexpected
- * card inserted.
- *
- * Following that, you can treat the second PCI I/O address space (the
- * one that's not 0x80 in length) as the PCMCIA I/O space.
- *
- * Note that in the Eumitcom's source for their drivers, they register
- * the interrupt as edge triggered when registering it with the
- * Windows kernel. I don't recall how to register edge triggered on
- * Linux (if it can be done at all). But in some experimentation, I
- * don't see much operational difference between using either
- * interrupt mode. Don't mess with the interrupt mode in the COR
- * register though, as the PLX9052 wants level triggers with the way
- * the serial EEPROM configures it on the WL11000.
- *
- * There's some other little quirks related to timing that I bumped
- * into, but I don't recall right now. Also, there's two variants of
- * the WL11000 I've seen, revision A1 and T2. These seem to differ
- * slightly in the timings configured in the wait-state generator in
- * the PLX9052. There have also been some comments from Eumitcom that
- * cards shouldn't be hot swapped, apparently due to risk of cooking
- * the PLX9052. I'm unsure why they believe this, as I can't see
- * anything in the design that would really cause a problem, except
- * for crashing drivers not written to expect it. And having developed
- * drivers for the WL11000, I'd say it's quite tricky to write code
- * that will successfully deal with a hot unplug. Very odd things
- * happen on the I/O side of things. But anyway, be warned. Despite
- * that, I've hot-swapped a number of times during debugging and
- * driver development for various reasons (stuck WAIT# line after the
- * radio card's firmware locks up).
- */
-
-#define DRIVER_NAME "orinoco_plx"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */
-#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-#define COR_RESET (0x80) /* reset bit in the COR register */
-#define PLX_RESET_TIME (500) /* milliseconds */
-
-#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */
-#define PLX_INTCSR_INTEN (1 << 6) /* Interrupt Enable bit */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- */
-static int orinoco_plx_cor_reset(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- struct orinoco_pci_card *card = priv->card;
- unsigned long timeout;
- u16 reg;
-
- iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
- mdelay(1);
-
- /* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME);
- reg = hermes_read_regn(hw, CMD);
- while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
- mdelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* Still busy? */
- if (reg & HERMES_CMD_BUSY) {
- printk(KERN_ERR PFX "Busy timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static int orinoco_plx_hw_init(struct orinoco_pci_card *card)
-{
- int i;
- u32 csr_reg;
- static const u8 cis_magic[] = {
- 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
- };
-
- printk(KERN_DEBUG PFX "CIS: ");
- for (i = 0; i < 16; i++)
- printk("%02X:", ioread8(card->attr_io + (i << 1)));
- printk("\n");
-
- /* Verify whether a supported PC card is present */
- /* FIXME: we probably need to be smarted about this */
- for (i = 0; i < sizeof(cis_magic); i++) {
- if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
- printk(KERN_ERR PFX "The CIS value of Prism2 PC "
- "card is unexpected\n");
- return -ENODEV;
- }
- }
-
- /* bjoern: We need to tell the card to enable interrupts, in
- case the serial eprom didn't do this already. See the
- PLX9052 data book, p8-1 and 8-24 for reference. */
- csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
- if (!(csr_reg & PLX_INTCSR_INTEN)) {
- csr_reg |= PLX_INTCSR_INTEN;
- iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
- csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
- if (!(csr_reg & PLX_INTCSR_INTEN)) {
- printk(KERN_ERR PFX "Cannot enable interrupts\n");
- return -EIO;
- }
- }
-
- return 0;
-}
-
-static int orinoco_plx_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io, *attr_io, *bridge_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- bridge_io = pci_iomap(pdev, 1, 0);
- if (!bridge_io) {
- printk(KERN_ERR PFX "Cannot map bridge registers\n");
- err = -EIO;
- goto fail_map_bridge;
- }
-
- attr_io = pci_iomap(pdev, 2, 0);
- if (!attr_io) {
- printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
- err = -EIO;
- goto fail_map_attr;
- }
-
- hermes_io = pci_iomap(pdev, 3, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot map chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_plx_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
- card->bridge_io = bridge_io;
- card->attr_io = attr_io;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_plx_hw_init(card);
- if (err) {
- printk(KERN_ERR PFX "Hardware initialization failed\n");
- goto fail;
- }
-
- err = orinoco_plx_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail_wiphy;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail_wiphy:
- wiphy_unregister(priv_to_wiphy(priv));
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_iounmap(pdev, attr_io);
-
- fail_map_attr:
- pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_plx_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct orinoco_pci_card *card = priv->card;
-
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(priv));
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_iounmap(pdev, card->attr_io);
- pci_iounmap(pdev, card->bridge_io);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_plx_id_table[] = {
- {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */
- {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
- {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */
- {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W,
- Eumitcom PCI WL11000,
- Addtron AWA-100 */
- {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */
- {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */
- {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */
- {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */
- {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by
- Brendan W. McAdams <rit AT jacked-in.org> */
- {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by
- Damien Persohn <damien AT persohn.net> */
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
-
-static struct pci_driver orinoco_plx_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_plx_id_table,
- .probe = orinoco_plx_init_one,
- .remove = orinoco_plx_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Pavel Roskin <[email protected]>,"
- " David Gibson <[email protected]>,"
- " Daniel Barlow <[email protected]>)";
-MODULE_AUTHOR("Daniel Barlow <[email protected]>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_plx_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_plx_driver);
-}
-
-static void __exit orinoco_plx_exit(void)
-{
- pci_unregister_driver(&orinoco_plx_driver);
-}
-
-module_init(orinoco_plx_init);
-module_exit(orinoco_plx_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c b/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c
deleted file mode 100644
index 939d5a1dce970..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/* orinoco_tmd.c
- *
- * Driver for Prism II devices which would usually be driven by orinoco_cs,
- * but are connected to the PCI bus by a TMD7160.
- *
- * Copyright (C) 2003 Joerg Dorchain <joerg AT dorchain.net>
- * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * The actual driving is done by main.c, this is just resource
- * allocation stuff.
- *
- * This driver is modeled after the orinoco_plx driver. The main
- * difference is that the TMD chip has only IO port ranges and doesn't
- * provide access to the PCMCIA attribute space.
- *
- * Pheecom sells cards with the TMD chip as "ASIC version"
- */
-
-#define DRIVER_NAME "orinoco_tmd"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <pcmcia/cisreg.h>
-
-#include "orinoco.h"
-#include "orinoco_pci.h"
-
-#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
-#define COR_RESET (0x80) /* reset bit in the COR register */
-#define TMD_RESET_TIME (500) /* milliseconds */
-
-/*
- * Do a soft reset of the card using the Configuration Option Register
- */
-static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
-{
- struct hermes *hw = &priv->hw;
- struct orinoco_pci_card *card = priv->card;
- unsigned long timeout;
- u16 reg;
-
- iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
- mdelay(1);
-
- iowrite8(COR_VALUE, card->bridge_io);
- mdelay(1);
-
- /* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME);
- reg = hermes_read_regn(hw, CMD);
- while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
- mdelay(1);
- reg = hermes_read_regn(hw, CMD);
- }
-
- /* Still busy? */
- if (reg & HERMES_CMD_BUSY) {
- printk(KERN_ERR PFX "Busy timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-
-static int orinoco_tmd_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err;
- struct orinoco_private *priv;
- struct orinoco_pci_card *card;
- void __iomem *hermes_io, *bridge_io;
-
- err = pci_enable_device(pdev);
- if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, DRIVER_NAME);
- if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
- goto fail_resources;
- }
-
- bridge_io = pci_iomap(pdev, 1, 0);
- if (!bridge_io) {
- printk(KERN_ERR PFX "Cannot map bridge registers\n");
- err = -EIO;
- goto fail_map_bridge;
- }
-
- hermes_io = pci_iomap(pdev, 2, 0);
- if (!hermes_io) {
- printk(KERN_ERR PFX "Cannot map chipset registers\n");
- err = -EIO;
- goto fail_map_hermes;
- }
-
- /* Allocate network device */
- priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
- orinoco_tmd_cor_reset, NULL);
- if (!priv) {
- printk(KERN_ERR PFX "Cannot allocate network device\n");
- err = -ENOMEM;
- goto fail_alloc;
- }
-
- card = priv->card;
- card->bridge_io = bridge_io;
-
- hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
-
- err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
- DRIVER_NAME, priv);
- if (err) {
- printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
- err = -EBUSY;
- goto fail_irq;
- }
-
- err = orinoco_tmd_cor_reset(priv);
- if (err) {
- printk(KERN_ERR PFX "Initial reset failed\n");
- goto fail;
- }
-
- err = orinoco_init(priv);
- if (err) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto fail;
- }
-
- err = orinoco_if_add(priv, 0, 0, NULL);
- if (err) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto fail;
- }
-
- pci_set_drvdata(pdev, priv);
-
- return 0;
-
- fail:
- free_irq(pdev->irq, priv);
-
- fail_irq:
- free_orinocodev(priv);
-
- fail_alloc:
- pci_iounmap(pdev, hermes_io);
-
- fail_map_hermes:
- pci_iounmap(pdev, bridge_io);
-
- fail_map_bridge:
- pci_release_regions(pdev);
-
- fail_resources:
- pci_disable_device(pdev);
-
- return err;
-}
-
-static void orinoco_tmd_remove_one(struct pci_dev *pdev)
-{
- struct orinoco_private *priv = pci_get_drvdata(pdev);
- struct orinoco_pci_card *card = priv->card;
-
- orinoco_if_del(priv);
- free_irq(pdev->irq, priv);
- free_orinocodev(priv);
- pci_iounmap(pdev, priv->hw.iobase);
- pci_iounmap(pdev, card->bridge_io);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-}
-
-static const struct pci_device_id orinoco_tmd_id_table[] = {
- {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table);
-
-static struct pci_driver orinoco_tmd_driver = {
- .name = DRIVER_NAME,
- .id_table = orinoco_tmd_id_table,
- .probe = orinoco_tmd_init_one,
- .remove = orinoco_tmd_remove_one,
- .driver.pm = &orinoco_pci_pm_ops,
-};
-
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
- " (Joerg Dorchain <[email protected]>)";
-MODULE_AUTHOR("Joerg Dorchain <[email protected]>");
-MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge");
-MODULE_LICENSE("Dual MPL/GPL");
-
-static int __init orinoco_tmd_init(void)
-{
- printk(KERN_DEBUG "%s\n", version);
- return pci_register_driver(&orinoco_tmd_driver);
-}
-
-static void __exit orinoco_tmd_exit(void)
-{
- pci_unregister_driver(&orinoco_tmd_driver);
-}
-
-module_init(orinoco_tmd_init);
-module_exit(orinoco_tmd_exit);
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
deleted file mode 100644
index 866e0230df251..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+++ /dev/null
@@ -1,1787 +0,0 @@
-/*
- * USB Orinoco driver
- *
- * Copyright (c) 2003 Manuel Estrada Sainz
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License
- * at http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and
- * limitations under the License.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in
- * which case the provisions of the GPL are applicable instead of the
- * above. If you wish to allow the use of your version of this file
- * only under the terms of the GPL and not to allow others to use your
- * version of this file under the MPL, indicate your decision by
- * deleting the provisions above and replace them with the notice and
- * other provisions required by the GPL. If you do not delete the
- * provisions above, a recipient may use your version of this file
- * under either the MPL or the GPL.
- *
- * Queueing code based on linux-wlan-ng 0.2.1-pre5
- *
- * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
- *
- * The license is the same as above.
- *
- * Initialy based on USB Skeleton driver - 0.7
- *
- * Copyright (c) 2001 Greg Kroah-Hartman ([email protected])
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * NOTE: The original USB Skeleton driver is GPL, but all that code is
- * gone so MPL/GPL applies.
- */
-
-#define DRIVER_NAME "orinoco_usb"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/usb.h>
-#include <linux/timer.h>
-
-#include <linux/netdevice.h>
-#include <linux/if_arp.h>
-#include <linux/etherdevice.h>
-#include <linux/wireless.h>
-#include <linux/firmware.h>
-#include <linux/refcount.h>
-
-#include "mic.h"
-#include "orinoco.h"
-
-#ifndef URB_ASYNC_UNLINK
-#define URB_ASYNC_UNLINK 0
-#endif
-
-struct header_struct {
- /* 802.3 */
- u8 dest[ETH_ALEN];
- u8 src[ETH_ALEN];
- __be16 len;
- /* 802.2 */
- u8 dsap;
- u8 ssap;
- u8 ctrl;
- /* SNAP */
- u8 oui[3];
- __be16 ethertype;
-} __packed;
-
-struct ez_usb_fw {
- u16 size;
- const u8 *code;
-};
-
-static struct ez_usb_fw firmware = {
- .size = 0,
- .code = NULL,
-};
-
-/* Debugging macros */
-#undef err
-#define err(format, arg...) \
- do { printk(KERN_ERR PFX format "\n", ## arg); } while (0)
-
-MODULE_FIRMWARE("orinoco_ezusb_fw");
-
-/*
- * Under some conditions, the card gets stuck and stops paying attention
- * to the world (i.e. data communication stalls) until we do something to
- * it. Sending an INQ_TALLIES command seems to be enough and should be
- * harmless otherwise. This behaviour has been observed when using the
- * driver on a systemimager client during installation. In the past a
- * timer was used to send INQ_TALLIES commands when there was no other
- * activity, but it was troublesome and was removed.
- */
-
-#define USB_COMPAQ_VENDOR_ID 0x049f /* Compaq Computer Corp. */
-#define USB_COMPAQ_WL215_ID 0x001f /* Compaq WL215 USB Adapter */
-#define USB_COMPAQ_W200_ID 0x0076 /* Compaq W200 USB Adapter */
-#define USB_HP_WL215_ID 0x0082 /* Compaq WL215 USB Adapter */
-
-#define USB_MELCO_VENDOR_ID 0x0411
-#define USB_BUFFALO_L11_ID 0x0006 /* BUFFALO WLI-USB-L11 */
-#define USB_BUFFALO_L11G_WR_ID 0x000B /* BUFFALO WLI-USB-L11G-WR */
-#define USB_BUFFALO_L11G_ID 0x000D /* BUFFALO WLI-USB-L11G */
-
-#define USB_LUCENT_VENDOR_ID 0x047E /* Lucent Technologies */
-#define USB_LUCENT_ORINOCO_ID 0x0300 /* Lucent/Agere Orinoco USB Client */
-
-#define USB_AVAYA8_VENDOR_ID 0x0D98
-#define USB_AVAYAE_VENDOR_ID 0x0D9E
-#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya USB Wireless Card */
-
-#define USB_AGERE_VENDOR_ID 0x0D4E /* Agere Systems */
-#define USB_AGERE_MODEL0801_ID 0x1000 /* USB Wireless Card Model 0801 */
-#define USB_AGERE_MODEL0802_ID 0x1001 /* USB Wireless Card Model 0802 */
-#define USB_AGERE_REBRANDED_ID 0x047A /* USB WLAN Card */
-
-#define USB_ELSA_VENDOR_ID 0x05CC
-#define USB_ELSA_AIRLANCER_ID 0x3100 /* ELSA AirLancer USB-11 */
-
-#define USB_LEGEND_VENDOR_ID 0x0E7C
-#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet USB WLAN Card */
-
-#define USB_SAMSUNG_VENDOR_ID 0x04E8
-#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
-#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */
-#define USB_SAMSUNG_SEW2003U_ID 0x7011 /* Samsung SEW-2003U Card */
-
-#define USB_IGATE_VENDOR_ID 0x0681
-#define USB_IGATE_IGATE_11M_ID 0x0012 /* I-GATE 11M USB Card */
-
-#define USB_FUJITSU_VENDOR_ID 0x0BF8
-#define USB_FUJITSU_E1100_ID 0x1002 /* connect2AIR WLAN E-1100 USB */
-
-#define USB_2WIRE_VENDOR_ID 0x1630
-#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire USB Wireless adapter */
-
-
-#define EZUSB_REQUEST_FW_TRANS 0xA0
-#define EZUSB_REQUEST_TRIGGER 0xAA
-#define EZUSB_REQUEST_TRIG_AC 0xAC
-#define EZUSB_CPUCS_REG 0x7F92
-
-#define EZUSB_RID_TX 0x0700
-#define EZUSB_RID_RX 0x0701
-#define EZUSB_RID_INIT1 0x0702
-#define EZUSB_RID_ACK 0x0710
-#define EZUSB_RID_READ_PDA 0x0800
-#define EZUSB_RID_PROG_INIT 0x0852
-#define EZUSB_RID_PROG_SET_ADDR 0x0853
-#define EZUSB_RID_PROG_BYTES 0x0854
-#define EZUSB_RID_PROG_END 0x0855
-#define EZUSB_RID_DOCMD 0x0860
-
-/* Recognize info frames */
-#define EZUSB_IS_INFO(id) ((id >= 0xF000) && (id <= 0xF2FF))
-
-#define EZUSB_MAGIC 0x0210
-
-#define EZUSB_FRAME_DATA 1
-#define EZUSB_FRAME_CONTROL 2
-
-#define DEF_TIMEOUT (3 * HZ)
-
-#define BULK_BUF_SIZE 2048
-
-#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet))
-
-#define FW_BUF_SIZE 64
-#define FW_VAR_OFFSET_PTR 0x359
-#define FW_VAR_VALUE 0
-#define FW_HOLE_START 0x100
-#define FW_HOLE_END 0x300
-
-struct ezusb_packet {
- __le16 magic; /* 0x0210 */
- u8 req_reply_count;
- u8 ans_reply_count;
- __le16 frame_type; /* 0x01 for data frames, 0x02 otherwise */
- __le16 size; /* transport size */
- __le16 crc; /* CRC up to here */
- __le16 hermes_len;
- __le16 hermes_rid;
- u8 data[];
-} __packed;
-
-/* Table of devices that work or may work with this driver */
-static const struct usb_device_id ezusb_table[] = {
- {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)},
- {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)},
- {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)},
- {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)},
- {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)},
- {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)},
- {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)},
- {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
- {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
- {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)},
- {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)},
- {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)},
- {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)},
- {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID,
- 0, 0)},
- {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)},
- {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)},
- {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)},
- {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)},
- {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)},
- {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)},
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ezusb_table);
-
-/* Structure to hold all of our device specific stuff */
-struct ezusb_priv {
- struct usb_device *udev;
- struct net_device *dev;
- struct mutex mtx;
- spinlock_t req_lock;
- struct list_head req_pending;
- struct list_head req_active;
- spinlock_t reply_count_lock;
- u16 hermes_reg_fake[0x40];
- u8 *bap_buf;
- struct urb *read_urb;
- int read_pipe;
- int write_pipe;
- u8 reply_count;
-};
-
-enum ezusb_state {
- EZUSB_CTX_START,
- EZUSB_CTX_QUEUED,
- EZUSB_CTX_REQ_SUBMITTED,
- EZUSB_CTX_REQ_COMPLETE,
- EZUSB_CTX_RESP_RECEIVED,
- EZUSB_CTX_REQ_TIMEOUT,
- EZUSB_CTX_REQ_FAILED,
- EZUSB_CTX_RESP_TIMEOUT,
- EZUSB_CTX_REQSUBMIT_FAIL,
- EZUSB_CTX_COMPLETE,
-};
-
-struct request_context {
- struct list_head list;
- refcount_t refcount;
- struct completion done; /* Signals that CTX is dead */
- int killed;
- struct urb *outurb; /* OUT for req pkt */
- struct ezusb_priv *upriv;
- struct ezusb_packet *buf;
- int buf_length;
- struct timer_list timer; /* Timeout handling */
- enum ezusb_state state; /* Current state */
- /* the RID that we will wait for */
- u16 out_rid;
- u16 in_rid;
-};
-
-
-/* Forward declarations */
-static void ezusb_ctx_complete(struct request_context *ctx);
-static void ezusb_req_queue_run(struct ezusb_priv *upriv);
-static void ezusb_bulk_in_callback(struct urb *urb);
-
-static inline u8 ezusb_reply_inc(u8 count)
-{
- if (count < 0x7F)
- return count + 1;
- else
- return 1;
-}
-
-static void ezusb_request_context_put(struct request_context *ctx)
-{
- if (!refcount_dec_and_test(&ctx->refcount))
- return;
-
- WARN_ON(!ctx->done.done);
- BUG_ON(ctx->outurb->status == -EINPROGRESS);
- BUG_ON(timer_pending(&ctx->timer));
- usb_free_urb(ctx->outurb);
- kfree(ctx->buf);
- kfree(ctx);
-}
-
-static inline void ezusb_mod_timer(struct ezusb_priv *upriv,
- struct timer_list *timer,
- unsigned long expire)
-{
- if (!upriv->udev)
- return;
- mod_timer(timer, expire);
-}
-
-static void ezusb_request_timerfn(struct timer_list *t)
-{
- struct request_context *ctx = from_timer(ctx, t, timer);
-
- ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
- if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) {
- ctx->state = EZUSB_CTX_REQ_TIMEOUT;
- } else {
- ctx->state = EZUSB_CTX_RESP_TIMEOUT;
- dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n");
- refcount_inc(&ctx->refcount);
- ctx->killed = 1;
- ezusb_ctx_complete(ctx);
- ezusb_request_context_put(ctx);
- }
-};
-
-static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
- u16 out_rid, u16 in_rid)
-{
- struct request_context *ctx;
-
- ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
- if (!ctx)
- return NULL;
-
- ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
- if (!ctx->buf) {
- kfree(ctx);
- return NULL;
- }
- ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC);
- if (!ctx->outurb) {
- kfree(ctx->buf);
- kfree(ctx);
- return NULL;
- }
-
- ctx->upriv = upriv;
- ctx->state = EZUSB_CTX_START;
- ctx->out_rid = out_rid;
- ctx->in_rid = in_rid;
-
- refcount_set(&ctx->refcount, 1);
- init_completion(&ctx->done);
-
- timer_setup(&ctx->timer, ezusb_request_timerfn, 0);
- return ctx;
-}
-
-static void ezusb_ctx_complete(struct request_context *ctx)
-{
- struct ezusb_priv *upriv = ctx->upriv;
- unsigned long flags;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- list_del_init(&ctx->list);
- if (upriv->udev) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- ezusb_req_queue_run(upriv);
- spin_lock_irqsave(&upriv->req_lock, flags);
- }
-
- switch (ctx->state) {
- case EZUSB_CTX_COMPLETE:
- case EZUSB_CTX_REQSUBMIT_FAIL:
- case EZUSB_CTX_REQ_FAILED:
- case EZUSB_CTX_REQ_TIMEOUT:
- case EZUSB_CTX_RESP_TIMEOUT:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) {
- struct net_device *dev = upriv->dev;
- struct net_device_stats *stats = &dev->stats;
-
- if (ctx->state != EZUSB_CTX_COMPLETE)
- stats->tx_errors++;
- else
- stats->tx_packets++;
-
- netif_wake_queue(dev);
- }
- complete_all(&ctx->done);
- ezusb_request_context_put(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- if (!upriv->udev) {
- /* This is normal, as all request contexts get flushed
- * when the device is disconnected */
- err("Called, CTX not terminating, but device gone");
- complete_all(&ctx->done);
- ezusb_request_context_put(ctx);
- break;
- }
-
- err("Called, CTX not in terminating state.");
- /* Things are really bad if this happens. Just leak
- * the CTX because it may still be linked to the
- * queue or the OUT urb may still be active.
- * Just leaking at least prevents an Oops or Panic.
- */
- break;
- }
-}
-
-/*
- * ezusb_req_queue_run:
- * Description:
- * Note: Only one active CTX at any one time, because there's no
- * other (reliable) way to match the response URB to the correct
- * CTX.
- */
-static void ezusb_req_queue_run(struct ezusb_priv *upriv)
-{
- unsigned long flags;
- struct request_context *ctx;
- int result;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- if (!list_empty(&upriv->req_active))
- goto unlock;
-
- if (list_empty(&upriv->req_pending))
- goto unlock;
-
- ctx =
- list_entry(upriv->req_pending.next, struct request_context,
- list);
-
- if (!ctx->upriv->udev)
- goto unlock;
-
- /* We need to split this off to avoid a race condition */
- list_move_tail(&ctx->list, &upriv->req_active);
-
- if (ctx->state == EZUSB_CTX_QUEUED) {
- refcount_inc(&ctx->refcount);
- result = usb_submit_urb(ctx->outurb, GFP_ATOMIC);
- if (result) {
- ctx->state = EZUSB_CTX_REQSUBMIT_FAIL;
-
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- err("Fatal, failed to submit command urb."
- " error=%d\n", result);
-
- ezusb_ctx_complete(ctx);
- ezusb_request_context_put(ctx);
- goto done;
- }
-
- ctx->state = EZUSB_CTX_REQ_SUBMITTED;
- ezusb_mod_timer(ctx->upriv, &ctx->timer,
- jiffies + DEF_TIMEOUT);
- }
-
- unlock:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- done:
- return;
-}
-
-static void ezusb_req_enqueue_run(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- if (!ctx->upriv->udev) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- goto done;
- }
- refcount_inc(&ctx->refcount);
- list_add_tail(&ctx->list, &upriv->req_pending);
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- ctx->state = EZUSB_CTX_QUEUED;
- ezusb_req_queue_run(upriv);
-
- done:
- return;
-}
-
-static void ezusb_request_out_callback(struct urb *urb)
-{
- unsigned long flags;
- enum ezusb_state state;
- struct request_context *ctx = urb->context;
- struct ezusb_priv *upriv = ctx->upriv;
-
- spin_lock_irqsave(&upriv->req_lock, flags);
-
- del_timer(&ctx->timer);
-
- if (ctx->killed) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- pr_warn("interrupt called with dead ctx\n");
- goto out;
- }
-
- state = ctx->state;
-
- if (urb->status == 0) {
- switch (state) {
- case EZUSB_CTX_REQ_SUBMITTED:
- if (ctx->in_rid) {
- ctx->state = EZUSB_CTX_REQ_COMPLETE;
- /* reply URB still pending */
- ezusb_mod_timer(upriv, &ctx->timer,
- jiffies + DEF_TIMEOUT);
- spin_unlock_irqrestore(&upriv->req_lock,
- flags);
- break;
- }
- fallthrough;
- case EZUSB_CTX_RESP_RECEIVED:
- /* IN already received before this OUT-ACK */
- ctx->state = EZUSB_CTX_COMPLETE;
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- ezusb_ctx_complete(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- err("Unexpected state(0x%x, %d) in OUT URB",
- state, urb->status);
- break;
- }
- } else {
- /* If someone cancels the OUT URB then its status
- * should be either -ECONNRESET or -ENOENT.
- */
- switch (state) {
- case EZUSB_CTX_REQ_SUBMITTED:
- case EZUSB_CTX_RESP_RECEIVED:
- ctx->state = EZUSB_CTX_REQ_FAILED;
- fallthrough;
-
- case EZUSB_CTX_REQ_FAILED:
- case EZUSB_CTX_REQ_TIMEOUT:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- ezusb_ctx_complete(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- err("Unexpected state(0x%x, %d) in OUT URB",
- state, urb->status);
- break;
- }
- }
- out:
- ezusb_request_context_put(ctx);
-}
-
-static void ezusb_request_in_callback(struct ezusb_priv *upriv,
- struct urb *urb)
-{
- struct ezusb_packet *ans = urb->transfer_buffer;
- struct request_context *ctx = NULL;
- enum ezusb_state state;
- unsigned long flags;
-
- /* Find the CTX on the active queue that requested this URB */
- spin_lock_irqsave(&upriv->req_lock, flags);
- if (upriv->udev) {
- struct list_head *item;
-
- list_for_each(item, &upriv->req_active) {
- struct request_context *c;
- int reply_count;
-
- c = list_entry(item, struct request_context, list);
- reply_count =
- ezusb_reply_inc(c->buf->req_reply_count);
- if ((ans->ans_reply_count == reply_count)
- && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) {
- ctx = c;
- break;
- }
- netdev_dbg(upriv->dev, "Skipped (0x%x/0x%x) (%d/%d)\n",
- le16_to_cpu(ans->hermes_rid), c->in_rid,
- ans->ans_reply_count, reply_count);
- }
- }
-
- if (ctx == NULL) {
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- err("%s: got unexpected RID: 0x%04X", __func__,
- le16_to_cpu(ans->hermes_rid));
- ezusb_req_queue_run(upriv);
- return;
- }
-
- /* The data we want is in the in buffer, exchange */
- urb->transfer_buffer = ctx->buf;
- ctx->buf = (void *) ans;
- ctx->buf_length = urb->actual_length;
-
- state = ctx->state;
- switch (state) {
- case EZUSB_CTX_REQ_SUBMITTED:
- /* We have received our response URB before
- * our request has been acknowledged. Do NOT
- * destroy our CTX yet, because our OUT URB
- * is still alive ...
- */
- ctx->state = EZUSB_CTX_RESP_RECEIVED;
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- /* Let the machine continue running. */
- break;
-
- case EZUSB_CTX_REQ_COMPLETE:
- /* This is the usual path: our request
- * has already been acknowledged, and
- * we have now received the reply.
- */
- ctx->state = EZUSB_CTX_COMPLETE;
-
- /* Stop the intimer */
- del_timer(&ctx->timer);
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- /* Call the completion handler */
- ezusb_ctx_complete(ctx);
- break;
-
- default:
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- pr_warn("Matched IN URB, unexpected context state(0x%x)\n",
- state);
- /* Throw this CTX away and try submitting another */
- del_timer(&ctx->timer);
- ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
- usb_unlink_urb(ctx->outurb);
- ezusb_req_queue_run(upriv);
- break;
- } /* switch */
-}
-
-typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *);
-
-static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- switch (ctx->state) {
- case EZUSB_CTX_QUEUED:
- case EZUSB_CTX_REQ_SUBMITTED:
- case EZUSB_CTX_REQ_COMPLETE:
- case EZUSB_CTX_RESP_RECEIVED:
- wait_for_completion(&ctx->done);
- break;
- default:
- /* Done or failed - nothing to wait for */
- break;
- }
-}
-
-static void ezusb_req_ctx_wait_poll(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- int msecs;
-
- switch (ctx->state) {
- case EZUSB_CTX_QUEUED:
- case EZUSB_CTX_REQ_SUBMITTED:
- case EZUSB_CTX_REQ_COMPLETE:
- case EZUSB_CTX_RESP_RECEIVED:
- /* If we get called from a timer or with our lock acquired, then
- * we can't wait for the completion and have to poll. This won't
- * happen if the USB controller completes the URB requests in
- * BH.
- */
- msecs = DEF_TIMEOUT * (1000 / HZ);
-
- while (!try_wait_for_completion(&ctx->done) && msecs--)
- udelay(1000);
- break;
- default:
- /* Done or failed - nothing to wait for */
- break;
- }
-}
-
-static void ezusb_req_ctx_wait_skip(struct ezusb_priv *upriv,
- struct request_context *ctx)
-{
- WARN(1, "Shouldn't be invoked for in_rid\n");
-}
-
-static inline u16 build_crc(struct ezusb_packet *data)
-{
- u16 crc = 0;
- u8 *bytes = (u8 *)data;
- int i;
-
- for (i = 0; i < 8; i++)
- crc = (crc << 1) + bytes[i];
-
- return crc;
-}
-
-/*
- * ezusb_fill_req:
- *
- * if data == NULL and length > 0 the data is assumed to be already in
- * the target buffer and only the header is filled.
- *
- */
-static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid,
- const void *data, u16 frame_type, u8 reply_count)
-{
- int total_size = sizeof(*req) + length;
-
- BUG_ON(total_size > BULK_BUF_SIZE);
-
- req->magic = cpu_to_le16(EZUSB_MAGIC);
- req->req_reply_count = reply_count;
- req->ans_reply_count = 0;
- req->frame_type = cpu_to_le16(frame_type);
- req->size = cpu_to_le16(length + 4);
- req->crc = cpu_to_le16(build_crc(req));
- req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length));
- req->hermes_rid = cpu_to_le16(rid);
- if (data)
- memcpy(req->data, data, length);
- return total_size;
-}
-
-static int ezusb_submit_in_urb(struct ezusb_priv *upriv)
-{
- int retval = 0;
- void *cur_buf = upriv->read_urb->transfer_buffer;
-
- if (upriv->read_urb->status == -EINPROGRESS) {
- netdev_dbg(upriv->dev, "urb busy, not resubmiting\n");
- retval = -EBUSY;
- goto exit;
- }
- usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe,
- cur_buf, BULK_BUF_SIZE,
- ezusb_bulk_in_callback, upriv);
- upriv->read_urb->transfer_flags = 0;
- retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC);
- if (retval)
- err("%s submit failed %d", __func__, retval);
-
- exit:
- return retval;
-}
-
-static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
-{
- int ret;
- u8 *res_val = NULL;
-
- if (!upriv->udev) {
- err("%s: !upriv->udev", __func__);
- return -EFAULT;
- }
-
- res_val = kmalloc(sizeof(*res_val), GFP_KERNEL);
-
- if (!res_val)
- return -ENOMEM;
-
- *res_val = reset; /* avoid argument promotion */
-
- ret = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_FW_TRANS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_OUT, EZUSB_CPUCS_REG, 0, res_val,
- sizeof(*res_val), DEF_TIMEOUT);
-
- kfree(res_val);
-
- return ret;
-}
-
-static int ezusb_firmware_download(struct ezusb_priv *upriv,
- struct ez_usb_fw *fw)
-{
- u8 *fw_buffer;
- int retval, addr;
- int variant_offset;
-
- fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL);
- if (!fw_buffer) {
- printk(KERN_ERR PFX "Out of memory for firmware buffer.\n");
- return -ENOMEM;
- }
- /*
- * This byte is 1 and should be replaced with 0. The offset is
- * 0x10AD in version 0.0.6. The byte in question should follow
- * the end of the code pointed to by the jump in the beginning
- * of the firmware. Also, it is read by code located at 0x358.
- */
- variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]);
- if (variant_offset >= fw->size) {
- printk(KERN_ERR PFX "Invalid firmware variant offset: "
- "0x%04x\n", variant_offset);
- retval = -EINVAL;
- goto fail;
- }
-
- retval = ezusb_8051_cpucs(upriv, 1);
- if (retval < 0)
- goto fail;
- for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) {
- /* 0x100-0x300 should be left alone, it contains card
- * specific data, like USB enumeration information */
- if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END))
- continue;
-
- memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE);
- if (variant_offset >= addr &&
- variant_offset < addr + FW_BUF_SIZE) {
- netdev_dbg(upriv->dev,
- "Patching card_variant byte at 0x%04X\n",
- variant_offset);
- fw_buffer[variant_offset - addr] = FW_VAR_VALUE;
- }
- retval = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_FW_TRANS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE
- | USB_DIR_OUT,
- addr, 0x0,
- fw_buffer, FW_BUF_SIZE,
- DEF_TIMEOUT);
-
- if (retval < 0)
- goto fail;
- }
- retval = ezusb_8051_cpucs(upriv, 0);
- if (retval < 0)
- goto fail;
-
- goto exit;
- fail:
- printk(KERN_ERR PFX "Firmware download failed, error %d\n",
- retval);
- exit:
- kfree(fw_buffer);
- return retval;
-}
-
-static int ezusb_access_ltv(struct ezusb_priv *upriv,
- struct request_context *ctx,
- u16 length, const void *data, u16 frame_type,
- void *ans_buff, unsigned ans_size, u16 *ans_length,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-{
- int req_size;
- int retval = 0;
- enum ezusb_state state;
-
- if (!upriv->udev) {
- retval = -ENODEV;
- goto exit;
- }
-
- if (upriv->read_urb->status != -EINPROGRESS)
- err("%s: in urb not pending", __func__);
-
- /* protect upriv->reply_count, guarantee sequential numbers */
- spin_lock_bh(&upriv->reply_count_lock);
- req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data,
- frame_type, upriv->reply_count);
- usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe,
- ctx->buf, req_size,
- ezusb_request_out_callback, ctx);
-
- if (ctx->in_rid)
- upriv->reply_count = ezusb_reply_inc(upriv->reply_count);
-
- ezusb_req_enqueue_run(upriv, ctx);
-
- spin_unlock_bh(&upriv->reply_count_lock);
-
- if (ctx->in_rid)
- ezusb_ctx_wait_func(upriv, ctx);
-
- state = ctx->state;
- switch (state) {
- case EZUSB_CTX_COMPLETE:
- retval = ctx->outurb->status;
- break;
-
- case EZUSB_CTX_QUEUED:
- case EZUSB_CTX_REQ_SUBMITTED:
- if (!ctx->in_rid)
- break;
- fallthrough;
- default:
- err("%s: Unexpected context state %d", __func__,
- state);
- fallthrough;
- case EZUSB_CTX_REQ_TIMEOUT:
- case EZUSB_CTX_REQ_FAILED:
- case EZUSB_CTX_RESP_TIMEOUT:
- case EZUSB_CTX_REQSUBMIT_FAIL:
- printk(KERN_ERR PFX "Access failed, resetting (state %d,"
- " reply_count %d)\n", state, upriv->reply_count);
- upriv->reply_count = 0;
- if (state == EZUSB_CTX_REQ_TIMEOUT
- || state == EZUSB_CTX_RESP_TIMEOUT) {
- printk(KERN_ERR PFX "ctx timed out\n");
- retval = -ETIMEDOUT;
- } else {
- printk(KERN_ERR PFX "ctx failed\n");
- retval = -EFAULT;
- }
- goto exit;
- }
- if (ctx->in_rid) {
- struct ezusb_packet *ans = ctx->buf;
- unsigned exp_len;
-
- if (ans->hermes_len != 0)
- exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12;
- else
- exp_len = 14;
-
- if (exp_len != ctx->buf_length) {
- err("%s: length mismatch for RID 0x%04x: "
- "expected %d, got %d", __func__,
- ctx->in_rid, exp_len, ctx->buf_length);
- retval = -EIO;
- goto exit;
- }
-
- if (ans_buff)
- memcpy(ans_buff, ans->data, min(exp_len, ans_size));
- if (ans_length)
- *ans_length = le16_to_cpu(ans->hermes_len);
- }
- exit:
- ezusb_request_context_put(ctx);
- return retval;
-}
-
-static int __ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *data,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-{
- struct ezusb_priv *upriv = hw->priv;
- u16 frame_type;
- struct request_context *ctx;
-
- if (length == 0)
- return -EINVAL;
-
- length = HERMES_RECLEN_TO_BYTES(length);
-
- /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be
- * set to be empty, but the USB bridge doesn't like it */
- if (length == 0)
- return 0;
-
- ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- if (rid == EZUSB_RID_TX)
- frame_type = EZUSB_FRAME_DATA;
- else
- frame_type = EZUSB_FRAME_CONTROL;
-
- return ezusb_access_ltv(upriv, ctx, length, data, frame_type,
- NULL, 0, NULL, ezusb_ctx_wait_func);
-}
-
-static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
- u16 length, const void *data)
-{
- return __ezusb_write_ltv(hw, bap, rid, length, data,
- ezusb_req_ctx_wait_poll);
-}
-
-static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
-
- if (bufsize % 2)
- return -EINVAL;
-
- ctx = ezusb_alloc_ctx(upriv, rid, rid);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL,
- buf, bufsize, length, ezusb_req_ctx_wait_poll);
-}
-
-static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf)
-{
- return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
- ezusb_req_ctx_wait_poll);
-}
-
-static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid,
- unsigned bufsize, u16 *length, void *buf)
-{
- return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1,
- u16 parm2, struct hermes_response *resp)
-{
- WARN_ON_ONCE(1);
- return -EINVAL;
-}
-
-static int __ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp,
- ezusb_ctx_wait ezusb_ctx_wait_func)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
-
- __le16 data[4] = {
- cpu_to_le16(cmd),
- cpu_to_le16(parm0),
- 0,
- 0,
- };
- netdev_dbg(upriv->dev, "0x%04X, parm0 0x%04X\n", cmd, parm0);
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_ctx_wait_func);
-}
-
-static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
- struct hermes_response *resp)
-{
- return __ezusb_docmd_wait(hw, cmd, parm0, resp, ezusb_req_ctx_wait_poll);
-}
-
-static int ezusb_bap_pread(struct hermes *hw, int bap,
- void *buf, int len, u16 id, u16 offset)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer;
- int actual_length = upriv->read_urb->actual_length;
-
- if (id == EZUSB_RID_RX) {
- if ((sizeof(*ans) + offset + len) > actual_length) {
- printk(KERN_ERR PFX "BAP read beyond buffer end "
- "in rx frame\n");
- return -EINVAL;
- }
- memcpy(buf, ans->data + offset, len);
- return 0;
- }
-
- if (EZUSB_IS_INFO(id)) {
- /* Include 4 bytes for length/type */
- if ((sizeof(*ans) + offset + len - 4) > actual_length) {
- printk(KERN_ERR PFX "BAP read beyond buffer end "
- "in info frame\n");
- return -EFAULT;
- }
- memcpy(buf, ans->data + offset - 4, len);
- } else {
- printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
- u32 pda_addr, u16 pda_len)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
- __le16 data[] = {
- cpu_to_le16(pda_addr & 0xffff),
- cpu_to_le16(pda_len - 4)
- };
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA);
- if (!ctx)
- return -ENOMEM;
-
- /* wl_lkm does not include PDA size in the PDA area.
- * We will pad the information into pda, so other routines
- * don't have to be modified */
- pda[0] = cpu_to_le16(pda_len - 2);
- /* Includes CFG_PROD_DATA but not itself */
- pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
-
- return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
- NULL, ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program_init(struct hermes *hw, u32 entry_point)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
- __le32 data = cpu_to_le32(entry_point);
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program_end(struct hermes *hw)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, 0, NULL,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program_bytes(struct hermes *hw, const char *buf,
- u32 addr, u32 len)
-{
- struct ezusb_priv *upriv = hw->priv;
- struct request_context *ctx;
- __le32 data = cpu_to_le32(addr);
- int err;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
- if (err)
- return err;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK);
- if (!ctx)
- return -ENOMEM;
-
- return ezusb_access_ltv(upriv, ctx, len, buf,
- EZUSB_FRAME_CONTROL, NULL, 0, NULL,
- ezusb_req_ctx_wait_compl);
-}
-
-static int ezusb_program(struct hermes *hw, const char *buf,
- u32 addr, u32 len)
-{
- u32 ch_addr;
- u32 ch_len;
- int err = 0;
-
- /* We can only send 2048 bytes out of the bulk xmit at a time,
- * so we have to split any programming into chunks of <2048
- * bytes. */
-
- ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE;
- ch_addr = addr;
-
- while (ch_addr < (addr + len)) {
- pr_debug("Programming subblock of length %d "
- "to address 0x%08x. Data @ %p\n",
- ch_len, ch_addr, &buf[ch_addr - addr]);
-
- err = ezusb_program_bytes(hw, &buf[ch_addr - addr],
- ch_addr, ch_len);
- if (err)
- break;
-
- ch_addr += ch_len;
- ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ?
- (addr + len - ch_addr) : MAX_DL_SIZE;
- }
-
- return err;
-}
-
-static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct net_device_stats *stats = &dev->stats;
- struct ezusb_priv *upriv = priv->card;
- u8 mic[MICHAEL_MIC_LEN + 1];
- int err = 0;
- int tx_control;
- unsigned long flags;
- struct request_context *ctx;
- u8 *buf;
- int tx_size;
-
- if (!netif_running(dev)) {
- printk(KERN_ERR "%s: Tx on stopped device!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (netif_queue_stopped(dev)) {
- printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (orinoco_lock(priv, &flags) != 0) {
- printk(KERN_ERR
- "%s: ezusb_xmit() called while hw_unavailable\n",
- dev->name);
- return NETDEV_TX_BUSY;
- }
-
- if (!netif_carrier_ok(dev) ||
- (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
- /* Oops, the firmware hasn't established a connection,
- silently drop the packet (this seems to be the
- safest approach). */
- goto drop;
- }
-
- /* Check packet length */
- if (skb->len < ETH_HLEN)
- goto drop;
-
- tx_control = 0;
-
- err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
- &mic[0]);
- if (err)
- goto drop;
-
- ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
- if (!ctx)
- goto drop;
-
- memset(ctx->buf, 0, BULK_BUF_SIZE);
- buf = ctx->buf->data;
-
- {
- __le16 *tx_cntl = (__le16 *)buf;
- *tx_cntl = cpu_to_le16(tx_control);
- buf += sizeof(*tx_cntl);
- }
-
- memcpy(buf, skb->data, skb->len);
- buf += skb->len;
-
- if (tx_control & HERMES_TXCTRL_MIC) {
- u8 *m = mic;
- /* Mic has been offset so it can be copied to an even
- * address. We're copying eveything anyway, so we
- * don't need to copy that first byte. */
- if (skb->len % 2)
- m++;
- memcpy(buf, m, MICHAEL_MIC_LEN);
- buf += MICHAEL_MIC_LEN;
- }
-
- /* Finally, we actually initiate the send */
- netif_stop_queue(dev);
-
- /* The card may behave better if we send evenly sized usb transfers */
- tx_size = ALIGN(buf - ctx->buf->data, 2);
-
- err = ezusb_access_ltv(upriv, ctx, tx_size, NULL,
- EZUSB_FRAME_DATA, NULL, 0, NULL,
- ezusb_req_ctx_wait_skip);
-
- if (err) {
- netif_start_queue(dev);
- if (net_ratelimit())
- printk(KERN_ERR "%s: Error %d transmitting packet\n",
- dev->name, err);
- goto busy;
- }
-
- netif_trans_update(dev);
- stats->tx_bytes += skb->len;
- goto ok;
-
- drop:
- stats->tx_errors++;
- stats->tx_dropped++;
-
- ok:
- orinoco_unlock(priv, &flags);
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-
- busy:
- orinoco_unlock(priv, &flags);
- return NETDEV_TX_BUSY;
-}
-
-static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid)
-{
- *fid = EZUSB_RID_TX;
- return 0;
-}
-
-
-static int ezusb_hard_reset(struct orinoco_private *priv)
-{
- struct ezusb_priv *upriv = priv->card;
- int retval = ezusb_8051_cpucs(upriv, 1);
-
- if (retval < 0) {
- err("Failed to reset");
- return retval;
- }
-
- retval = ezusb_8051_cpucs(upriv, 0);
- if (retval < 0) {
- err("Failed to unreset");
- return retval;
- }
-
- netdev_dbg(upriv->dev, "sending control message\n");
- retval = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_TRIGGER,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_OUT, 0x0, 0x0, NULL, 0,
- DEF_TIMEOUT);
- if (retval < 0) {
- err("EZUSB_REQUEST_TRIGGER failed retval %d", retval);
- return retval;
- }
-#if 0
- dbg("Sending EZUSB_REQUEST_TRIG_AC");
- retval = usb_control_msg(upriv->udev,
- usb_sndctrlpipe(upriv->udev, 0),
- EZUSB_REQUEST_TRIG_AC,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_OUT, 0x00FA, 0x0, NULL, 0,
- DEF_TIMEOUT);
- if (retval < 0) {
- err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval);
- return retval;
- }
-#endif
-
- return 0;
-}
-
-
-static int ezusb_init(struct hermes *hw)
-{
- struct ezusb_priv *upriv = hw->priv;
- int retval;
-
- if (!upriv)
- return -EINVAL;
-
- upriv->reply_count = 0;
- /* Write the MAGIC number on the simulated registers to keep
- * orinoco.c happy */
- hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
- hermes_write_regn(hw, RXFID, EZUSB_RID_RX);
-
- usb_kill_urb(upriv->read_urb);
- ezusb_submit_in_urb(upriv);
-
- retval = __ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
- HERMES_BYTES_TO_RECLEN(2), "\x10\x00",
- ezusb_req_ctx_wait_compl);
- if (retval < 0) {
- printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval);
- return retval;
- }
-
- retval = __ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL,
- ezusb_req_ctx_wait_compl);
- if (retval < 0) {
- printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval);
- return retval;
- }
-
- return 0;
-}
-
-static void ezusb_bulk_in_callback(struct urb *urb)
-{
- struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context;
- struct ezusb_packet *ans = urb->transfer_buffer;
- u16 crc;
- u16 hermes_rid;
-
- if (upriv->udev == NULL)
- return;
-
- if (urb->status == -ETIMEDOUT) {
- /* When a device gets unplugged we get this every time
- * we resubmit, flooding the logs. Since we don't use
- * USB timeouts, it shouldn't happen any other time*/
- pr_warn("%s: urb timed out, not resubmitting\n", __func__);
- return;
- }
- if (urb->status == -ECONNABORTED) {
- pr_warn("%s: connection abort, resubmitting urb\n",
- __func__);
- goto resubmit;
- }
- if ((urb->status == -EILSEQ)
- || (urb->status == -ENOENT)
- || (urb->status == -ECONNRESET)) {
- netdev_dbg(upriv->dev, "status %d, not resubmiting\n",
- urb->status);
- return;
- }
- if (urb->status)
- netdev_dbg(upriv->dev, "status: %d length: %d\n",
- urb->status, urb->actual_length);
- if (urb->actual_length < sizeof(*ans)) {
- err("%s: short read, ignoring", __func__);
- goto resubmit;
- }
- crc = build_crc(ans);
- if (le16_to_cpu(ans->crc) != crc) {
- err("CRC error, ignoring packet");
- goto resubmit;
- }
-
- hermes_rid = le16_to_cpu(ans->hermes_rid);
- if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) {
- ezusb_request_in_callback(upriv, urb);
- } else if (upriv->dev) {
- struct net_device *dev = upriv->dev;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
-
- if (hermes_rid == EZUSB_RID_RX) {
- __orinoco_ev_rx(dev, hw);
- } else {
- hermes_write_regn(hw, INFOFID,
- le16_to_cpu(ans->hermes_rid));
- __orinoco_ev_info(dev, hw);
- }
- }
-
- resubmit:
- if (upriv->udev)
- ezusb_submit_in_urb(upriv);
-}
-
-static inline void ezusb_delete(struct ezusb_priv *upriv)
-{
- struct list_head *item;
- struct list_head *tmp_item;
- unsigned long flags;
-
- BUG_ON(!upriv);
-
- mutex_lock(&upriv->mtx);
-
- upriv->udev = NULL; /* No timer will be rearmed from here */
-
- usb_kill_urb(upriv->read_urb);
-
- spin_lock_irqsave(&upriv->req_lock, flags);
- list_for_each_safe(item, tmp_item, &upriv->req_active) {
- struct request_context *ctx;
- int err;
-
- ctx = list_entry(item, struct request_context, list);
- refcount_inc(&ctx->refcount);
-
- ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
- err = usb_unlink_urb(ctx->outurb);
-
- spin_unlock_irqrestore(&upriv->req_lock, flags);
- if (err == -EINPROGRESS)
- wait_for_completion(&ctx->done);
-
- del_timer_sync(&ctx->timer);
- /* FIXME: there is an slight chance for the irq handler to
- * be running */
- if (!list_empty(&ctx->list))
- ezusb_ctx_complete(ctx);
-
- ezusb_request_context_put(ctx);
- spin_lock_irqsave(&upriv->req_lock, flags);
- }
- spin_unlock_irqrestore(&upriv->req_lock, flags);
-
- list_for_each_safe(item, tmp_item, &upriv->req_pending)
- ezusb_ctx_complete(list_entry(item,
- struct request_context, list));
-
- if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS)
- printk(KERN_ERR PFX "Some URB in progress\n");
-
- mutex_unlock(&upriv->mtx);
-
- if (upriv->read_urb) {
- kfree(upriv->read_urb->transfer_buffer);
- usb_free_urb(upriv->read_urb);
- }
- kfree(upriv->bap_buf);
- if (upriv->dev) {
- struct orinoco_private *priv = ndev_priv(upriv->dev);
- orinoco_if_del(priv);
- wiphy_unregister(priv_to_wiphy(upriv));
- free_orinocodev(priv);
- }
-}
-
-static void ezusb_lock_irqsave(spinlock_t *lock,
- unsigned long *flags) __acquires(lock)
-{
- spin_lock_bh(lock);
-}
-
-static void ezusb_unlock_irqrestore(spinlock_t *lock,
- unsigned long *flags) __releases(lock)
-{
- spin_unlock_bh(lock);
-}
-
-static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock)
-{
- spin_lock_bh(lock);
-}
-
-static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock)
-{
- spin_unlock_bh(lock);
-}
-
-static const struct hermes_ops ezusb_ops = {
- .init = ezusb_init,
- .cmd_wait = ezusb_docmd_wait,
- .init_cmd_wait = ezusb_doicmd_wait,
- .allocate = ezusb_allocate,
- .read_ltv = ezusb_read_ltv,
- .read_ltv_pr = ezusb_read_ltv_preempt,
- .write_ltv = ezusb_write_ltv,
- .bap_pread = ezusb_bap_pread,
- .read_pda = ezusb_read_pda,
- .program_init = ezusb_program_init,
- .program_end = ezusb_program_end,
- .program = ezusb_program,
- .lock_irqsave = ezusb_lock_irqsave,
- .unlock_irqrestore = ezusb_unlock_irqrestore,
- .lock_irq = ezusb_lock_irq,
- .unlock_irq = ezusb_unlock_irq,
-};
-
-static const struct net_device_ops ezusb_netdev_ops = {
- .ndo_open = orinoco_open,
- .ndo_stop = orinoco_stop,
- .ndo_start_xmit = ezusb_xmit,
- .ndo_set_rx_mode = orinoco_set_multicast_list,
- .ndo_change_mtu = orinoco_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_tx_timeout = orinoco_tx_timeout,
-};
-
-static int ezusb_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(interface);
- struct orinoco_private *priv;
- struct hermes *hw;
- struct ezusb_priv *upriv = NULL;
- struct usb_interface_descriptor *iface_desc;
- struct usb_endpoint_descriptor *ep;
- const struct firmware *fw_entry = NULL;
- int retval = 0;
- int i;
-
- priv = alloc_orinocodev(sizeof(*upriv), &udev->dev,
- ezusb_hard_reset, NULL);
- if (!priv) {
- err("Couldn't allocate orinocodev");
- retval = -ENOMEM;
- goto exit;
- }
-
- hw = &priv->hw;
-
- upriv = priv->card;
-
- mutex_init(&upriv->mtx);
- spin_lock_init(&upriv->reply_count_lock);
-
- spin_lock_init(&upriv->req_lock);
- INIT_LIST_HEAD(&upriv->req_pending);
- INIT_LIST_HEAD(&upriv->req_active);
-
- upriv->udev = udev;
-
- hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake;
- hw->reg_spacing = HERMES_16BIT_REGSPACING;
- hw->priv = upriv;
- hw->ops = &ezusb_ops;
-
- /* set up the endpoint information */
- /* check out the endpoints */
-
- iface_desc = &interface->cur_altsetting->desc;
- for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
- ep = &interface->cur_altsetting->endpoint[i].desc;
-
- if (usb_endpoint_is_bulk_in(ep)) {
- /* we found a bulk in endpoint */
- if (upriv->read_urb != NULL) {
- pr_warn("Found a second bulk in ep, ignored\n");
- continue;
- }
-
- upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!upriv->read_urb)
- goto error;
- if (le16_to_cpu(ep->wMaxPacketSize) != 64)
- pr_warn("bulk in: wMaxPacketSize!= 64\n");
- if (ep->bEndpointAddress != (2 | USB_DIR_IN))
- pr_warn("bulk in: bEndpointAddress: %d\n",
- ep->bEndpointAddress);
- upriv->read_pipe = usb_rcvbulkpipe(udev,
- ep->
- bEndpointAddress);
- upriv->read_urb->transfer_buffer =
- kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
- if (!upriv->read_urb->transfer_buffer) {
- err("Couldn't allocate IN buffer");
- goto error;
- }
- }
-
- if (usb_endpoint_is_bulk_out(ep)) {
- /* we found a bulk out endpoint */
- if (upriv->bap_buf != NULL) {
- pr_warn("Found a second bulk out ep, ignored\n");
- continue;
- }
-
- if (le16_to_cpu(ep->wMaxPacketSize) != 64)
- pr_warn("bulk out: wMaxPacketSize != 64\n");
- if (ep->bEndpointAddress != 2)
- pr_warn("bulk out: bEndpointAddress: %d\n",
- ep->bEndpointAddress);
- upriv->write_pipe = usb_sndbulkpipe(udev,
- ep->
- bEndpointAddress);
- upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
- if (!upriv->bap_buf) {
- err("Couldn't allocate bulk_out_buffer");
- goto error;
- }
- }
- }
- if (!upriv->bap_buf || !upriv->read_urb) {
- err("Didn't find the required bulk endpoints");
- goto error;
- }
-
- if (request_firmware(&fw_entry, "orinoco_ezusb_fw",
- &interface->dev) == 0) {
- firmware.size = fw_entry->size;
- firmware.code = fw_entry->data;
- }
- if (firmware.size && firmware.code) {
- if (ezusb_firmware_download(upriv, &firmware) < 0)
- goto error;
- } else {
- err("No firmware to download");
- goto error;
- }
-
- if (ezusb_hard_reset(priv) < 0) {
- err("Cannot reset the device");
- goto error;
- }
-
- /* If the firmware is already downloaded orinoco.c will call
- * ezusb_init but if the firmware is not already there, that will make
- * the kernel very unstable, so we try initializing here and quit in
- * case of error */
- if (ezusb_init(hw) < 0) {
- err("Couldn't initialize the device");
- err("Firmware may not be downloaded or may be wrong.");
- goto error;
- }
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- err("orinoco_init() failed\n");
- goto error;
- }
-
- if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) {
- upriv->dev = NULL;
- err("%s: orinoco_if_add() failed", __func__);
- wiphy_unregister(priv_to_wiphy(priv));
- goto error;
- }
- upriv->dev = priv->ndev;
-
- goto exit;
-
- error:
- ezusb_delete(upriv);
- if (upriv->dev) {
- /* upriv->dev was 0, so ezusb_delete() didn't free it */
- free_orinocodev(priv);
- }
- upriv = NULL;
- retval = -EFAULT;
- exit:
- if (fw_entry) {
- firmware.code = NULL;
- firmware.size = 0;
- release_firmware(fw_entry);
- }
- usb_set_intfdata(interface, upriv);
- return retval;
-}
-
-
-static void ezusb_disconnect(struct usb_interface *intf)
-{
- struct ezusb_priv *upriv = usb_get_intfdata(intf);
- usb_set_intfdata(intf, NULL);
- ezusb_delete(upriv);
- printk(KERN_INFO PFX "Disconnected\n");
-}
-
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver orinoco_driver = {
- .name = DRIVER_NAME,
- .probe = ezusb_probe,
- .disconnect = ezusb_disconnect,
- .id_table = ezusb_table,
- .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(orinoco_driver);
-
-MODULE_AUTHOR("Manuel Estrada Sainz");
-MODULE_DESCRIPTION("Driver for Orinoco wireless LAN cards using EZUSB bridge");
-MODULE_LICENSE("Dual MPL/GPL");
diff --git a/drivers/net/wireless/intersil/orinoco/scan.c b/drivers/net/wireless/intersil/orinoco/scan.c
deleted file mode 100644
index 6d1d084854fb3..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/scan.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* Helpers for managing scan queues
- *
- * See copyright notice in main.c
- */
-
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ieee80211.h>
-#include <net/cfg80211.h>
-
-#include "hermes.h"
-#include "orinoco.h"
-#include "main.h"
-
-#include "scan.h"
-
-#define ZERO_DBM_OFFSET 0x95
-#define MAX_SIGNAL_LEVEL 0x8A
-#define MIN_SIGNAL_LEVEL 0x2F
-
-#define SIGNAL_TO_DBM(x) \
- (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \
- - ZERO_DBM_OFFSET)
-#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
-
-static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
-{
- int i;
- u8 rate;
-
- buf[0] = WLAN_EID_SUPP_RATES;
- for (i = 0; i < 5; i++) {
- rate = le16_to_cpu(rates[i]);
- /* NULL terminated */
- if (rate == 0x0)
- break;
- buf[i + 2] = rate;
- }
- buf[1] = i;
-
- return i + 2;
-}
-
-static int prism_build_supp_rates(u8 *buf, const u8 *rates)
-{
- int i;
-
- buf[0] = WLAN_EID_SUPP_RATES;
- for (i = 0; i < 8; i++) {
- /* NULL terminated */
- if (rates[i] == 0x0)
- break;
- buf[i + 2] = rates[i];
- }
- buf[1] = i;
-
- /* We might still have another 2 rates, which need to go in
- * extended supported rates */
- if (i == 8 && rates[i] > 0) {
- buf[10] = WLAN_EID_EXT_SUPP_RATES;
- for (; i < 10; i++) {
- /* NULL terminated */
- if (rates[i] == 0x0)
- break;
- buf[i + 2] = rates[i];
- }
- buf[11] = i - 8;
- }
-
- return (i < 8) ? i + 2 : i + 4;
-}
-
-static void orinoco_add_hostscan_result(struct orinoco_private *priv,
- const union hermes_scan_info *bss)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct ieee80211_channel *channel;
- struct cfg80211_bss *cbss;
- u8 *ie;
- u8 ie_buf[46];
- u64 timestamp;
- s32 signal;
- u16 capability;
- u16 beacon_interval;
- int ie_len;
- int freq;
- int len;
-
- len = le16_to_cpu(bss->a.essid_len);
-
- /* Reconstruct SSID and bitrate IEs to pass up */
- ie_buf[0] = WLAN_EID_SSID;
- ie_buf[1] = len;
- memcpy(&ie_buf[2], bss->a.essid, len);
-
- ie = ie_buf + len + 2;
- ie_len = ie_buf[1] + 2;
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_SYMBOL:
- ie_len += symbol_build_supp_rates(ie, bss->s.rates);
- break;
-
- case FIRMWARE_TYPE_INTERSIL:
- ie_len += prism_build_supp_rates(ie, bss->p.rates);
- break;
-
- case FIRMWARE_TYPE_AGERE:
- default:
- break;
- }
-
- freq = ieee80211_channel_to_frequency(
- le16_to_cpu(bss->a.channel), NL80211_BAND_2GHZ);
- channel = ieee80211_get_channel(wiphy, freq);
- if (!channel) {
- printk(KERN_DEBUG "Invalid channel designation %04X(%04X)",
- bss->a.channel, freq);
- return; /* Then ignore it for now */
- }
- timestamp = 0;
- capability = le16_to_cpu(bss->a.capabilities);
- beacon_interval = le16_to_cpu(bss->a.beacon_interv);
- signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
-
- cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
- bss->a.bssid, timestamp, capability,
- beacon_interval, ie_buf, ie_len, signal,
- GFP_KERNEL);
- cfg80211_put_bss(wiphy, cbss);
-}
-
-void orinoco_add_extscan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *bss,
- size_t len)
-{
- struct wiphy *wiphy = priv_to_wiphy(priv);
- struct ieee80211_channel *channel;
- struct cfg80211_bss *cbss;
- const u8 *ie;
- u64 timestamp;
- s32 signal;
- u16 capability;
- u16 beacon_interval;
- size_t ie_len;
- int chan, freq;
-
- ie_len = len - sizeof(*bss);
- ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len);
- chan = ie ? ie[2] : 0;
- freq = ieee80211_channel_to_frequency(chan, NL80211_BAND_2GHZ);
- channel = ieee80211_get_channel(wiphy, freq);
-
- timestamp = le64_to_cpu(bss->timestamp);
- capability = le16_to_cpu(bss->capabilities);
- beacon_interval = le16_to_cpu(bss->beacon_interval);
- ie = bss->data;
- signal = SIGNAL_TO_MBM(bss->level);
-
- cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
- bss->bssid, timestamp, capability,
- beacon_interval, ie, ie_len, signal,
- GFP_KERNEL);
- cfg80211_put_bss(wiphy, cbss);
-}
-
-void orinoco_add_hostscan_results(struct orinoco_private *priv,
- unsigned char *buf,
- size_t len)
-{
- int offset; /* In the scan data */
- size_t atom_len;
- bool abort = false;
-
- switch (priv->firmware_type) {
- case FIRMWARE_TYPE_AGERE:
- atom_len = sizeof(struct agere_scan_apinfo);
- offset = 0;
- break;
-
- case FIRMWARE_TYPE_SYMBOL:
- /* Lack of documentation necessitates this hack.
- * Different firmwares have 68 or 76 byte long atoms.
- * We try modulo first. If the length divides by both,
- * we check what would be the channel in the second
- * frame for a 68-byte atom. 76-byte atoms have 0 there.
- * Valid channel cannot be 0. */
- if (len % 76)
- atom_len = 68;
- else if (len % 68)
- atom_len = 76;
- else if (len >= 1292 && buf[68] == 0)
- atom_len = 76;
- else
- atom_len = 68;
- offset = 0;
- break;
-
- case FIRMWARE_TYPE_INTERSIL:
- offset = 4;
- if (priv->has_hostscan) {
- atom_len = le16_to_cpup((__le16 *)buf);
- /* Sanity check for atom_len */
- if (atom_len < sizeof(struct prism2_scan_apinfo)) {
- printk(KERN_ERR "%s: Invalid atom_len in scan "
- "data: %zu\n", priv->ndev->name,
- atom_len);
- abort = true;
- goto scan_abort;
- }
- } else
- atom_len = offsetof(struct prism2_scan_apinfo, atim);
- break;
-
- default:
- abort = true;
- goto scan_abort;
- }
-
- /* Check that we got an whole number of atoms */
- if ((len - offset) % atom_len) {
- printk(KERN_ERR "%s: Unexpected scan data length %zu, "
- "atom_len %zu, offset %d\n", priv->ndev->name, len,
- atom_len, offset);
- abort = true;
- goto scan_abort;
- }
-
- /* Process the entries one by one */
- for (; offset + atom_len <= len; offset += atom_len) {
- union hermes_scan_info *atom;
-
- atom = (union hermes_scan_info *) (buf + offset);
-
- orinoco_add_hostscan_result(priv, atom);
- }
-
- scan_abort:
- if (priv->scan_request) {
- struct cfg80211_scan_info info = {
- .aborted = abort,
- };
-
- cfg80211_scan_done(priv->scan_request, &info);
- priv->scan_request = NULL;
- }
-}
-
-void orinoco_scan_done(struct orinoco_private *priv, bool abort)
-{
- if (priv->scan_request) {
- struct cfg80211_scan_info info = {
- .aborted = abort,
- };
-
- cfg80211_scan_done(priv->scan_request, &info);
- priv->scan_request = NULL;
- }
-}
diff --git a/drivers/net/wireless/intersil/orinoco/scan.h b/drivers/net/wireless/intersil/orinoco/scan.h
deleted file mode 100644
index 27281fb0a6dc0..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/scan.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Helpers for managing scan queues
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_SCAN_H_
-#define _ORINOCO_SCAN_H_
-
-/* Forward declarations */
-struct orinoco_private;
-struct agere_ext_scan_info;
-
-/* Add scan results */
-void orinoco_add_extscan_result(struct orinoco_private *priv,
- struct agere_ext_scan_info *atom,
- size_t len);
-void orinoco_add_hostscan_results(struct orinoco_private *dev,
- unsigned char *buf,
- size_t len);
-void orinoco_scan_done(struct orinoco_private *priv, bool abort);
-
-#endif /* _ORINOCO_SCAN_H_ */
diff --git a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c b/drivers/net/wireless/intersil/orinoco/spectrum_cs.c
deleted file mode 100644
index 841d623c621ac..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/spectrum_cs.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
- * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
- * Communications and Intel PRO/Wireless 2011B.
- *
- * The driver implements Symbol firmware download. The rest is handled
- * in hermes.c and main.c.
- *
- * Utilities for downloading the Symbol firmware are available at
- * http://sourceforge.net/projects/orinoco/
- *
- * Copyright (C) 2002-2005 Pavel Roskin <[email protected]>
- * Portions based on orinoco_cs.c:
- * Copyright (C) David Gibson, Linuxcare Australia
- * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
- * Copyright (C) Symbol Technologies.
- *
- * See copyright notice in file main.c.
- */
-
-#define DRIVER_NAME "spectrum_cs"
-#define PFX DRIVER_NAME ": "
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include "orinoco.h"
-
-/********************************************************************/
-/* Module stuff */
-/********************************************************************/
-
-MODULE_AUTHOR("Pavel Roskin <[email protected]>");
-MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
-MODULE_LICENSE("Dual MPL/GPL");
-
-/* Module parameters */
-
-/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
- * don't have any CIS entry for it. This workaround it... */
-static int ignore_cis_vcc; /* = 0 */
-module_param(ignore_cis_vcc, int, 0);
-MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
-
-/********************************************************************/
-/* Data structures */
-/********************************************************************/
-
-/* PCMCIA specific device information (goes in the card field of
- * struct orinoco_private */
-struct orinoco_pccard {
- struct pcmcia_device *p_dev;
-};
-
-/********************************************************************/
-/* Function prototypes */
-/********************************************************************/
-
-static int spectrum_cs_config(struct pcmcia_device *link);
-static void spectrum_cs_release(struct pcmcia_device *link);
-
-/* Constants for the CISREG_CCSR register */
-#define HCR_RUN 0x07 /* run firmware after reset */
-#define HCR_IDLE 0x0E /* don't run firmware after reset */
-#define HCR_MEM16 0x10 /* memory width bit, should be preserved */
-
-
-/*
- * Reset the card using configuration registers COR and CCSR.
- * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
- */
-static int
-spectrum_reset(struct pcmcia_device *link, int idle)
-{
- int ret;
- u8 save_cor;
- u8 ccsr;
-
- /* Doing it if hardware is gone is guaranteed crash */
- if (!pcmcia_dev_present(link))
- return -ENODEV;
-
- /* Save original COR value */
- ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor);
- if (ret)
- goto failed;
-
- /* Soft-Reset card */
- ret = pcmcia_write_config_byte(link, CISREG_COR,
- (save_cor | COR_SOFT_RESET));
- if (ret)
- goto failed;
- udelay(1000);
-
- /* Read CCSR */
- ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr);
- if (ret)
- goto failed;
-
- /*
- * Start or stop the firmware. Memory width bit should be
- * preserved from the value we've just read.
- */
- ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16);
- ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr);
- if (ret)
- goto failed;
- udelay(1000);
-
- /* Restore original COR configuration index */
- ret = pcmcia_write_config_byte(link, CISREG_COR,
- (save_cor & ~COR_SOFT_RESET));
- if (ret)
- goto failed;
- udelay(1000);
- return 0;
-
-failed:
- return -ENODEV;
-}
-
-/********************************************************************/
-/* Device methods */
-/********************************************************************/
-
-static int
-spectrum_cs_hard_reset(struct orinoco_private *priv)
-{
- struct orinoco_pccard *card = priv->card;
- struct pcmcia_device *link = card->p_dev;
-
- /* Soft reset using COR and HCR */
- spectrum_reset(link, 0);
-
- return 0;
-}
-
-static int
-spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
-{
- struct orinoco_pccard *card = priv->card;
- struct pcmcia_device *link = card->p_dev;
-
- return spectrum_reset(link, idle);
-}
-
-/********************************************************************/
-/* PCMCIA stuff */
-/********************************************************************/
-
-static int
-spectrum_cs_probe(struct pcmcia_device *link)
-{
- struct orinoco_private *priv;
- struct orinoco_pccard *card;
- int ret;
-
- priv = alloc_orinocodev(sizeof(*card), &link->dev,
- spectrum_cs_hard_reset,
- spectrum_cs_stop_firmware);
- if (!priv)
- return -ENOMEM;
- card = priv->card;
-
- /* Link both structures together */
- card->p_dev = link;
- link->priv = priv;
-
- ret = spectrum_cs_config(link);
- if (ret)
- goto err_free_orinocodev;
-
- return 0;
-
-err_free_orinocodev:
- free_orinocodev(priv);
- return ret;
-}
-
-static void spectrum_cs_detach(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
-
- orinoco_if_del(priv);
-
- spectrum_cs_release(link);
-
- free_orinocodev(priv);
-} /* spectrum_cs_detach */
-
-static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
- void *priv_data)
-{
- if (p_dev->config_index == 0)
- return -EINVAL;
-
- return pcmcia_request_io(p_dev);
-};
-
-static int
-spectrum_cs_config(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- struct hermes *hw = &priv->hw;
- int ret;
- void __iomem *mem;
-
- link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
- CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
- if (ignore_cis_vcc)
- link->config_flags &= ~CONF_AUTO_CHECK_VCC;
- ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
- if (ret) {
- if (!ignore_cis_vcc)
- printk(KERN_ERR PFX "GetNextTuple(): No matching "
- "CIS configuration. Maybe you need the "
- "ignore_cis_vcc=1 parameter.\n");
- goto failed;
- }
-
- mem = ioport_map(link->resource[0]->start,
- resource_size(link->resource[0]));
- if (!mem)
- goto failed;
-
- /* We initialize the hermes structure before completing PCMCIA
- * configuration just in case the interrupt handler gets
- * called. */
- hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
- hw->eeprom_pda = true;
-
- ret = pcmcia_request_irq(link, orinoco_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- /* Reset card */
- if (spectrum_cs_hard_reset(priv) != 0)
- goto failed;
-
- /* Initialise the main driver */
- if (orinoco_init(priv) != 0) {
- printk(KERN_ERR PFX "orinoco_init() failed\n");
- goto failed;
- }
-
- /* Register an interface with the stack */
- if (orinoco_if_add(priv, link->resource[0]->start,
- link->irq, NULL) != 0) {
- printk(KERN_ERR PFX "orinoco_if_add() failed\n");
- goto failed;
- }
-
- return 0;
-
- failed:
- spectrum_cs_release(link);
- return -ENODEV;
-} /* spectrum_cs_config */
-
-static void
-spectrum_cs_release(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- unsigned long flags;
-
- /* We're committed to taking the device away now, so mark the
- * hardware as unavailable */
- priv->hw.ops->lock_irqsave(&priv->lock, &flags);
- priv->hw_unavailable++;
- priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
-
- pcmcia_disable_device(link);
- if (priv->hw.iobase)
- ioport_unmap(priv->hw.iobase);
-} /* spectrum_cs_release */
-
-
-static int
-spectrum_cs_suspend(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
-
- /* Mark the device as stopped, to block IO until later */
- orinoco_down(priv);
-
- return 0;
-}
-
-static int
-spectrum_cs_resume(struct pcmcia_device *link)
-{
- struct orinoco_private *priv = link->priv;
- int err = orinoco_up(priv);
-
- return err;
-}
-
-
-/********************************************************************/
-/* Module initialization */
-/********************************************************************/
-
-static const struct pcmcia_device_id spectrum_cs_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
- PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
- PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
- PCMCIA_DEVICE_NULL,
-};
-MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
-
-static struct pcmcia_driver orinoco_driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- .probe = spectrum_cs_probe,
- .remove = spectrum_cs_detach,
- .suspend = spectrum_cs_suspend,
- .resume = spectrum_cs_resume,
- .id_table = spectrum_cs_ids,
-};
-module_pcmcia_driver(orinoco_driver);
diff --git a/drivers/net/wireless/intersil/orinoco/wext.c b/drivers/net/wireless/intersil/orinoco/wext.c
deleted file mode 100644
index dea1ff044342d..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/wext.c
+++ /dev/null
@@ -1,1428 +0,0 @@
-/* Wireless extensions support.
- *
- * See copyright notice in main.c
- */
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-#include <linux/etherdevice.h>
-#include <net/iw_handler.h>
-#include <net/cfg80211.h>
-#include <net/cfg80211-wext.h>
-
-#include "hermes.h"
-#include "hermes_rid.h"
-#include "orinoco.h"
-
-#include "hw.h"
-#include "mic.h"
-#include "scan.h"
-#include "main.h"
-
-#include "wext.h"
-
-#define MAX_RID_LEN 1024
-
-/* Helper routine to record keys
- * It is called under orinoco_lock so it may not sleep */
-static int orinoco_set_key(struct orinoco_private *priv, int index,
- enum orinoco_alg alg, const u8 *key, int key_len,
- const u8 *seq, int seq_len)
-{
- kfree_sensitive(priv->keys[index].key);
- kfree_sensitive(priv->keys[index].seq);
-
- if (key_len) {
- priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
- if (!priv->keys[index].key)
- goto nomem;
- } else
- priv->keys[index].key = NULL;
-
- if (seq_len) {
- priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
- if (!priv->keys[index].seq)
- goto free_key;
- } else
- priv->keys[index].seq = NULL;
-
- priv->keys[index].key_len = key_len;
- priv->keys[index].seq_len = seq_len;
-
- if (key_len)
- memcpy((void *)priv->keys[index].key, key, key_len);
- if (seq_len)
- memcpy((void *)priv->keys[index].seq, seq, seq_len);
-
- switch (alg) {
- case ORINOCO_ALG_TKIP:
- priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
- break;
-
- case ORINOCO_ALG_WEP:
- priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
- WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
- break;
-
- case ORINOCO_ALG_NONE:
- default:
- priv->keys[index].cipher = 0;
- break;
- }
-
- return 0;
-
-free_key:
- kfree(priv->keys[index].key);
- priv->keys[index].key = NULL;
-
-nomem:
- priv->keys[index].key_len = 0;
- priv->keys[index].seq_len = 0;
- priv->keys[index].cipher = 0;
-
- return -ENOMEM;
-}
-
-static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- struct iw_statistics *wstats = &priv->wstats;
- int err;
- unsigned long flags;
-
- if (!netif_device_present(dev)) {
- printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
- dev->name);
- return NULL; /* FIXME: Can we do better than this? */
- }
-
- /* If busy, return the old stats. Returning NULL may cause
- * the interface to disappear from /proc/net/wireless */
- if (orinoco_lock(priv, &flags) != 0)
- return wstats;
-
- /* We can't really wait for the tallies inquiry command to
- * complete, so we just use the previous results and trigger
- * a new tallies inquiry command for next time - Jean II */
- /* FIXME: Really we should wait for the inquiry to come back -
- * as it is the stats we give don't make a whole lot of sense.
- * Unfortunately, it's not clear how to do that within the
- * wireless extensions framework: I think we're in user
- * context, but a lock seems to be held by the time we get in
- * here so we're not safe to sleep here. */
- hermes_inquire(hw, HERMES_INQ_TALLIES);
-
- if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
- memset(&wstats->qual, 0, sizeof(wstats->qual));
- /* If a spy address is defined, we report stats of the
- * first spy address - Jean II */
- if (SPY_NUMBER(priv)) {
- wstats->qual.qual = priv->spy_data.spy_stat[0].qual;
- wstats->qual.level = priv->spy_data.spy_stat[0].level;
- wstats->qual.noise = priv->spy_data.spy_stat[0].noise;
- wstats->qual.updated =
- priv->spy_data.spy_stat[0].updated;
- }
- } else {
- struct {
- __le16 qual, signal, noise, unused;
- } __packed cq;
-
- err = HERMES_READ_RECORD(hw, USER_BAP,
- HERMES_RID_COMMSQUALITY, &cq);
-
- if (!err) {
- wstats->qual.qual = (int)le16_to_cpu(cq.qual);
- wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
- wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
- wstats->qual.updated =
- IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
- }
- }
-
- orinoco_unlock(priv, &flags);
- return wstats;
-}
-
-/********************************************************************/
-/* Wireless extensions */
-/********************************************************************/
-
-static int orinoco_ioctl_setwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct orinoco_private *priv = ndev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Enable automatic roaming - no sanity checks are needed */
- if (is_zero_ether_addr(ap_addr->sa_data) ||
- is_broadcast_ether_addr(ap_addr->sa_data)) {
- priv->bssid_fixed = 0;
- eth_zero_addr(priv->desired_bssid);
-
- /* "off" means keep existing connection */
- if (ap_addr->sa_data[0] == 0) {
- __orinoco_hw_set_wap(priv);
- err = 0;
- }
- goto out;
- }
-
- if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
- printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
- "support manual roaming\n",
- dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- if (priv->iw_mode != NL80211_IFTYPE_STATION) {
- printk(KERN_WARNING "%s: Manual roaming supported only in "
- "managed mode\n", dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Intersil firmware hangs without Desired ESSID */
- if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
- strlen(priv->desired_essid) == 0) {
- printk(KERN_WARNING "%s: Desired ESSID must be set for "
- "manual roaming\n", dev->name);
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* Finally, enable manual roaming */
- priv->bssid_fixed = 1;
- memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static int orinoco_ioctl_getwap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct sockaddr *ap_addr = &wrqu->ap_addr;
- struct orinoco_private *priv = ndev_priv(dev);
-
- int err = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- ap_addr->sa_family = ARPHRD_ETHER;
- err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_setiwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct orinoco_private *priv = ndev_priv(dev);
- int index = (erq->flags & IW_ENCODE_INDEX) - 1;
- int setindex = priv->tx_key;
- enum orinoco_alg encode_alg = priv->encode_alg;
- int restricted = priv->wep_restrict;
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (!priv->has_wep)
- return -EOPNOTSUPP;
-
- if (erq->pointer) {
- /* We actually have a key to set - check its length */
- if (erq->length > LARGE_KEY_SIZE)
- return -E2BIG;
-
- if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
- return -E2BIG;
- }
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Clear any TKIP key we have */
- if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
- (void) orinoco_clear_tkip_key(priv, setindex);
-
- if (erq->length > 0) {
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
- index = priv->tx_key;
-
- /* Switch on WEP if off */
- if (encode_alg != ORINOCO_ALG_WEP) {
- setindex = index;
- encode_alg = ORINOCO_ALG_WEP;
- }
- } else {
- /* Important note : if the user do "iwconfig eth0 enc off",
- * we will arrive there with an index of -1. This is valid
- * but need to be taken care off... Jean II */
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
- if ((index != -1) || (erq->flags == 0)) {
- err = -EINVAL;
- goto out;
- }
- } else {
- /* Set the index : Check that the key is valid */
- if (priv->keys[index].key_len == 0) {
- err = -EINVAL;
- goto out;
- }
- setindex = index;
- }
- }
-
- if (erq->flags & IW_ENCODE_DISABLED)
- encode_alg = ORINOCO_ALG_NONE;
- if (erq->flags & IW_ENCODE_OPEN)
- restricted = 0;
- if (erq->flags & IW_ENCODE_RESTRICTED)
- restricted = 1;
-
- if (erq->pointer && erq->length > 0) {
- err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
- erq->length, NULL, 0);
- }
- priv->tx_key = setindex;
-
- /* Try fast key change if connected and only keys are changed */
- if ((priv->encode_alg == encode_alg) &&
- (priv->wep_restrict == restricted) &&
- netif_carrier_ok(dev)) {
- err = __orinoco_hw_setup_wepkeys(priv);
- /* No need to commit if successful */
- goto out;
- }
-
- priv->encode_alg = encode_alg;
- priv->wep_restrict = restricted;
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getiwencode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *keybuf)
-{
- struct iw_point *erq = &wrqu->encoding;
- struct orinoco_private *priv = ndev_priv(dev);
- int index = (erq->flags & IW_ENCODE_INDEX) - 1;
- unsigned long flags;
-
- if (!priv->has_wep)
- return -EOPNOTSUPP;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
- index = priv->tx_key;
-
- erq->flags = 0;
- if (!priv->encode_alg)
- erq->flags |= IW_ENCODE_DISABLED;
- erq->flags |= index + 1;
-
- if (priv->wep_restrict)
- erq->flags |= IW_ENCODE_RESTRICTED;
- else
- erq->flags |= IW_ENCODE_OPEN;
-
- erq->length = priv->keys[index].key_len;
-
- memcpy(keybuf, priv->keys[index].key, erq->length);
-
- orinoco_unlock(priv, &flags);
- return 0;
-}
-
-static int orinoco_ioctl_setessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *essidbuf)
-{
- struct iw_point *erq = &wrqu->essid;
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
-
- /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
- * anyway... - Jean II */
-
- /* Hum... Should not use Wireless Extension constant (may change),
- * should use our own... - Jean II */
- if (erq->length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
- memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
-
- /* If not ANY, get the new ESSID */
- if (erq->flags)
- memcpy(priv->desired_essid, essidbuf, erq->length);
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getessid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *essidbuf)
-{
- struct iw_point *erq = &wrqu->essid;
- struct orinoco_private *priv = ndev_priv(dev);
- int active;
- int err = 0;
- unsigned long flags;
-
- if (netif_running(dev)) {
- err = orinoco_hw_get_essid(priv, &active, essidbuf);
- if (err < 0)
- return err;
- erq->length = err;
- } else {
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
- erq->length = strlen(priv->desired_essid);
- orinoco_unlock(priv, &flags);
- }
-
- erq->flags = 1;
-
- return 0;
-}
-
-static int orinoco_ioctl_setfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *frq = &wrqu->freq;
- struct orinoco_private *priv = ndev_priv(dev);
- int chan = -1;
- unsigned long flags;
- int err = -EINPROGRESS; /* Call commit handler */
-
- /* In infrastructure mode the AP sets the channel */
- if (priv->iw_mode == NL80211_IFTYPE_STATION)
- return -EBUSY;
-
- if ((frq->e == 0) && (frq->m <= 1000)) {
- /* Setting by channel number */
- chan = frq->m;
- } else {
- /* Setting by frequency */
- int denom = 1;
- int i;
-
- /* Calculate denominator to rescale to MHz */
- for (i = 0; i < (6 - frq->e); i++)
- denom *= 10;
-
- chan = ieee80211_frequency_to_channel(frq->m / denom);
- }
-
- if ((chan < 1) || (chan > NUM_CHANNELS) ||
- !(priv->channel_mask & (1 << (chan - 1))))
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- priv->channel = chan;
- if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
- /* Fast channel change - no commit if successful */
- struct hermes *hw = &priv->hw;
- err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
- HERMES_TEST_SET_CHANNEL,
- chan, NULL);
- }
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getfreq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_freq *frq = &wrqu->freq;
- struct orinoco_private *priv = ndev_priv(dev);
- int tmp;
-
- /* Locking done in there */
- tmp = orinoco_hw_get_freq(priv);
- if (tmp < 0)
- return tmp;
-
- frq->m = tmp * 100000;
- frq->e = 1;
-
- return 0;
-}
-
-static int orinoco_ioctl_getsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *srq = &wrqu->sens;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- u16 val;
- int err;
- unsigned long flags;
-
- if (!priv->has_sensitivity)
- return -EOPNOTSUPP;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFSYSTEMSCALE, &val);
- orinoco_unlock(priv, &flags);
-
- if (err)
- return err;
-
- srq->value = val;
- srq->fixed = 0; /* auto */
-
- return 0;
-}
-
-static int orinoco_ioctl_setsens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *srq = &wrqu->sens;
- struct orinoco_private *priv = ndev_priv(dev);
- int val = srq->value;
- unsigned long flags;
-
- if (!priv->has_sensitivity)
- return -EOPNOTSUPP;
-
- if ((val < 1) || (val > 3))
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- priv->ap_density = val;
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_setrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct orinoco_private *priv = ndev_priv(dev);
- int ratemode;
- int bitrate; /* 100s of kilobits */
- unsigned long flags;
-
- /* As the user space doesn't know our highest rate, it uses -1
- * to ask us to set the highest rate. Test it using "iwconfig
- * ethX rate auto" - Jean II */
- if (rrq->value == -1)
- bitrate = 110;
- else {
- if (rrq->value % 100000)
- return -EINVAL;
- bitrate = rrq->value / 100000;
- }
-
- ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
-
- if (ratemode == -1)
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- priv->bitratemode = ratemode;
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS;
-}
-
-static int orinoco_ioctl_getrate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *rrq = &wrqu->bitrate;
- struct orinoco_private *priv = ndev_priv(dev);
- int err = 0;
- int bitrate, automatic;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
-
- /* If the interface is running we try to find more about the
- current mode */
- if (netif_running(dev)) {
- int act_bitrate;
- int lerr;
-
- /* Ignore errors if we can't get the actual bitrate */
- lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
- if (!lerr)
- bitrate = act_bitrate;
- }
-
- orinoco_unlock(priv, &flags);
-
- rrq->value = bitrate;
- rrq->fixed = !automatic;
- rrq->disabled = 0;
-
- return err;
-}
-
-static int orinoco_ioctl_setpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *prq = &wrqu->power;
- struct orinoco_private *priv = ndev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (prq->disabled) {
- priv->pm_on = 0;
- } else {
- switch (prq->flags & IW_POWER_MODE) {
- case IW_POWER_UNICAST_R:
- priv->pm_mcast = 0;
- priv->pm_on = 1;
- break;
- case IW_POWER_ALL_R:
- priv->pm_mcast = 1;
- priv->pm_on = 1;
- break;
- case IW_POWER_ON:
- /* No flags : but we may have a value - Jean II */
- break;
- default:
- err = -EINVAL;
- goto out;
- }
-
- if (prq->flags & IW_POWER_TIMEOUT) {
- priv->pm_on = 1;
- priv->pm_timeout = prq->value / 1000;
- }
- if (prq->flags & IW_POWER_PERIOD) {
- priv->pm_on = 1;
- priv->pm_period = prq->value / 1000;
- }
- /* It's valid to not have a value if we are just toggling
- * the flags... Jean II */
- if (!priv->pm_on) {
- err = -EINVAL;
- goto out;
- }
- }
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_param *prq = &wrqu->power;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- int err = 0;
- u16 enable, period, timeout, mcast;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMENABLED, &enable);
- if (err)
- goto out;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMAXSLEEPDURATION, &period);
- if (err)
- goto out;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
- if (err)
- goto out;
-
- err = hermes_read_wordrec(hw, USER_BAP,
- HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
- if (err)
- goto out;
-
- prq->disabled = !enable;
- /* Note : by default, display the period */
- if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
- prq->flags = IW_POWER_TIMEOUT;
- prq->value = timeout * 1000;
- } else {
- prq->flags = IW_POWER_PERIOD;
- prq->value = period * 1000;
- }
- if (mcast)
- prq->flags |= IW_POWER_ALL_R;
- else
- prq->flags |= IW_POWER_UNICAST_R;
-
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, alg = ext->alg, set_key = 1;
- unsigned long flags;
- int err = -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- /* Determine and validate the key index */
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if ((idx < 1) || (idx > 4))
- goto out;
- idx--;
- } else
- idx = priv->tx_key;
-
- if (encoding->flags & IW_ENCODE_DISABLED)
- alg = IW_ENCODE_ALG_NONE;
-
- if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
- /* Clear any TKIP TX key we had */
- (void) orinoco_clear_tkip_key(priv, priv->tx_key);
- }
-
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- priv->tx_key = idx;
- set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
- (ext->key_len > 0)) ? 1 : 0;
- }
-
- if (set_key) {
- /* Set the requested key first */
- switch (alg) {
- case IW_ENCODE_ALG_NONE:
- priv->encode_alg = ORINOCO_ALG_NONE;
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
- NULL, 0, NULL, 0);
- break;
-
- case IW_ENCODE_ALG_WEP:
- if (ext->key_len <= 0)
- goto out;
-
- priv->encode_alg = ORINOCO_ALG_WEP;
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
- ext->key, ext->key_len, NULL, 0);
- break;
-
- case IW_ENCODE_ALG_TKIP:
- {
- u8 *tkip_iv = NULL;
-
- if (!priv->has_wpa ||
- (ext->key_len > sizeof(struct orinoco_tkip_key)))
- goto out;
-
- priv->encode_alg = ORINOCO_ALG_TKIP;
-
- if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
- tkip_iv = &ext->rx_seq[0];
-
- err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
- ext->key, ext->key_len, tkip_iv,
- ORINOCO_SEQ_LEN);
-
- err = __orinoco_hw_set_tkip_key(priv, idx,
- ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
- priv->keys[idx].key, priv->keys[idx].key_len,
- tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
- if (err)
- printk(KERN_ERR "%s: Error %d setting TKIP key"
- "\n", dev->name, err);
-
- goto out;
- }
- default:
- goto out;
- }
- }
- err = -EINPROGRESS;
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int idx, max_key_len;
- unsigned long flags;
- int err;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = -EINVAL;
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- goto out;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if ((idx < 1) || (idx > 4))
- goto out;
- idx--;
- } else
- idx = priv->tx_key;
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- switch (priv->encode_alg) {
- case ORINOCO_ALG_NONE:
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- encoding->flags |= IW_ENCODE_DISABLED;
- break;
- case ORINOCO_ALG_WEP:
- ext->alg = IW_ENCODE_ALG_WEP;
- ext->key_len = min(priv->keys[idx].key_len, max_key_len);
- memcpy(ext->key, priv->keys[idx].key, ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- break;
- case ORINOCO_ALG_TKIP:
- ext->alg = IW_ENCODE_ALG_TKIP;
- ext->key_len = min(priv->keys[idx].key_len, max_key_len);
- memcpy(ext->key, priv->keys[idx].key, ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- break;
- }
-
- err = 0;
- out:
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- struct iw_param *param = &wrqu->param;
- unsigned long flags;
- int ret = -EINPROGRESS;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- case IW_AUTH_PRIVACY_INVOKED:
- case IW_AUTH_DROP_UNENCRYPTED:
- /*
- * orinoco does not use these parameters
- */
- break;
-
- case IW_AUTH_MFP:
- /* Management Frame Protection not supported.
- * Only fail if set to required.
- */
- if (param->value == IW_AUTH_MFP_REQUIRED)
- ret = -EINVAL;
- break;
-
- case IW_AUTH_KEY_MGMT:
- /* wl_lkm implies value 2 == PSK for Hermes I
- * which ties in with WEXT
- * no other hints tho :(
- */
- priv->key_mgmt = param->value;
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- /* When countermeasures are enabled, shut down the
- * card; when disabled, re-enable the card. This must
- * take effect immediately.
- *
- * TODO: Make sure that the EAPOL message is getting
- * out before card disabled
- */
- if (param->value) {
- priv->tkip_cm_active = 1;
- ret = hermes_disable_port(hw, 0);
- } else {
- priv->tkip_cm_active = 0;
- ret = hermes_enable_port(hw, 0);
- }
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (param->value & IW_AUTH_ALG_SHARED_KEY)
- priv->wep_restrict = 1;
- else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
- priv->wep_restrict = 0;
- else
- ret = -EINVAL;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- if (priv->has_wpa) {
- priv->wpa_enabled = param->value ? 1 : 0;
- } else {
- if (param->value)
- ret = -EOPNOTSUPP;
- /* else silently accept disable of WPA */
- priv->wpa_enabled = 0;
- }
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_param *param = &wrqu->param;
- unsigned long flags;
- int ret = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_KEY_MGMT:
- param->value = priv->key_mgmt;
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- param->value = priv->tkip_cm_active;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- if (priv->wep_restrict)
- param->value = IW_AUTH_ALG_SHARED_KEY;
- else
- param->value = IW_AUTH_ALG_OPEN_SYSTEM;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = priv->wpa_enabled;
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- u8 *buf;
- unsigned long flags;
-
- /* cut off at IEEE80211_MAX_DATA_LEN */
- if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
- (wrqu->data.length && (extra == NULL)))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
- } else
- buf = NULL;
-
- if (orinoco_lock(priv, &flags) != 0) {
- kfree(buf);
- return -EBUSY;
- }
-
- kfree(priv->wpa_ie);
- priv->wpa_ie = buf;
- priv->wpa_ie_len = wrqu->data.length;
-
- if (priv->wpa_ie) {
- /* Looks like wl_lkm wants to check the auth alg, and
- * somehow pass it to the firmware.
- * Instead it just calls the key mgmt rid
- * - we do this in set auth.
- */
- }
-
- orinoco_unlock(priv, &flags);
- return 0;
-}
-
-static int orinoco_ioctl_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int err = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
- wrqu->data.length = 0;
- goto out;
- }
-
- if (wrqu->data.length < priv->wpa_ie_len) {
- err = -E2BIG;
- goto out;
- }
-
- wrqu->data.length = priv->wpa_ie_len;
- memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
-
-out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static int orinoco_ioctl_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
- unsigned long flags;
- int ret = 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- /* silently ignore */
- break;
-
- case IW_MLME_DISASSOC:
-
- ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
- mlme->reason_code);
- break;
-
- default:
- ret = -EOPNOTSUPP;
- }
-
- orinoco_unlock(priv, &flags);
- return ret;
-}
-
-static int orinoco_ioctl_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
- printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
-
- /* Firmware reset */
- orinoco_reset(&priv->reset_work);
- } else {
- printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
-
- schedule_work(&priv->reset_work);
- }
-
- return 0;
-}
-
-static int orinoco_ioctl_setibssport(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int val = *((int *) extra);
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- priv->ibss_port = val;
-
- /* Actually update the mode we are using */
- set_port_type(priv);
-
- orinoco_unlock(priv, &flags);
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getibssport(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int *val = (int *) extra;
-
- *val = priv->ibss_port;
- return 0;
-}
-
-static int orinoco_ioctl_setport3(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int val = *((int *) extra);
- int err = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- switch (val) {
- case 0: /* Try to do IEEE ad-hoc mode */
- if (!priv->has_ibss) {
- err = -EINVAL;
- break;
- }
- priv->prefer_port3 = 0;
-
- break;
-
- case 1: /* Try to do Lucent proprietary ad-hoc mode */
- if (!priv->has_port3) {
- err = -EINVAL;
- break;
- }
- priv->prefer_port3 = 1;
- break;
-
- default:
- err = -EINVAL;
- }
-
- if (!err) {
- /* Actually update the mode we are using */
- set_port_type(priv);
- err = -EINPROGRESS;
- }
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
-static int orinoco_ioctl_getport3(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int *val = (int *) extra;
-
- *val = priv->prefer_port3;
- return 0;
-}
-
-static int orinoco_ioctl_setpreamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int val;
-
- if (!priv->has_preamble)
- return -EOPNOTSUPP;
-
- /* 802.11b has recently defined some short preamble.
- * Basically, the Phy header has been reduced in size.
- * This increase performance, especially at high rates
- * (the preamble is transmitted at 1Mb/s), unfortunately
- * this give compatibility troubles... - Jean II */
- val = *((int *) extra);
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- if (val)
- priv->preamble = 1;
- else
- priv->preamble = 0;
-
- orinoco_unlock(priv, &flags);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-static int orinoco_ioctl_getpreamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- int *val = (int *) extra;
-
- if (!priv->has_preamble)
- return -EOPNOTSUPP;
-
- *val = priv->preamble;
- return 0;
-}
-
-/* ioctl interface to hermes_read_ltv()
- * To use with iwpriv, pass the RID as the token argument, e.g.
- * iwpriv get_rid [0xfc00]
- * At least Wireless Tools 25 is required to use iwpriv.
- * For Wireless Tools 25 and 26 append "dummy" are the end. */
-static int orinoco_ioctl_getrid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct iw_point *data = &wrqu->data;
- struct orinoco_private *priv = ndev_priv(dev);
- struct hermes *hw = &priv->hw;
- int rid = data->flags;
- u16 length;
- int err;
- unsigned long flags;
-
- /* It's a "get" function, but we don't want users to access the
- * WEP key and other raw firmware data */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if (rid < 0xfc00 || rid > 0xffff)
- return -EINVAL;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
- extra);
- if (err)
- goto out;
-
- data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
- MAX_RID_LEN);
-
- out:
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-
-/* Commit handler, called after set operations */
-static int orinoco_ioctl_commit(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu,
- char *extra)
-{
- struct orinoco_private *priv = ndev_priv(dev);
- unsigned long flags;
- int err = 0;
-
- if (!priv->open)
- return 0;
-
- if (orinoco_lock(priv, &flags) != 0)
- return err;
-
- err = orinoco_commit(priv);
-
- orinoco_unlock(priv, &flags);
- return err;
-}
-
-static const struct iw_priv_args orinoco_privtab[] = {
- { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
- { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
- { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_port3" },
- { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_port3" },
- { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_preamble" },
- { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_preamble" },
- { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_ibssport" },
- { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_ibssport" },
- { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
- "get_rid" },
-};
-
-
-/*
- * Structures to export the Wireless Handlers
- */
-
-static const iw_handler orinoco_handler[] = {
- IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit),
- IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
- IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq),
- IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq),
- IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode),
- IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode),
- IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens),
- IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens),
- IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap),
- IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap),
- IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan),
- IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan),
- IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid),
- IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid),
- IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
- IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
- IW_HANDLER(SIOCSIWRTS, cfg80211_wext_siwrts),
- IW_HANDLER(SIOCGIWRTS, cfg80211_wext_giwrts),
- IW_HANDLER(SIOCSIWFRAG, cfg80211_wext_siwfrag),
- IW_HANDLER(SIOCGIWFRAG, cfg80211_wext_giwfrag),
- IW_HANDLER(SIOCGIWRETRY, cfg80211_wext_giwretry),
- IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode),
- IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode),
- IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower),
- IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower),
- IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie),
- IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie),
- IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme),
- IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth),
- IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
-};
-
-
-/*
- Added typecasting since we no longer use iwreq_data -- Moustafa
- */
-static const iw_handler orinoco_private_handler[] = {
- [0] = orinoco_ioctl_reset,
- [1] = orinoco_ioctl_reset,
- [2] = orinoco_ioctl_setport3,
- [3] = orinoco_ioctl_getport3,
- [4] = orinoco_ioctl_setpreamble,
- [5] = orinoco_ioctl_getpreamble,
- [6] = orinoco_ioctl_setibssport,
- [7] = orinoco_ioctl_getibssport,
- [9] = orinoco_ioctl_getrid,
-};
-
-const struct iw_handler_def orinoco_handler_def = {
- .num_standard = ARRAY_SIZE(orinoco_handler),
- .num_private = ARRAY_SIZE(orinoco_private_handler),
- .num_private_args = ARRAY_SIZE(orinoco_privtab),
- .standard = orinoco_handler,
- .private = orinoco_private_handler,
- .private_args = orinoco_privtab,
- .get_wireless_stats = orinoco_get_wireless_stats,
-};
diff --git a/drivers/net/wireless/intersil/orinoco/wext.h b/drivers/net/wireless/intersil/orinoco/wext.h
deleted file mode 100644
index 1479f4e26ddee..0000000000000
--- a/drivers/net/wireless/intersil/orinoco/wext.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Wireless extensions support.
- *
- * See copyright notice in main.c
- */
-#ifndef _ORINOCO_WEXT_H_
-#define _ORINOCO_WEXT_H_
-
-#include <net/iw_handler.h>
-
-/* Structure defining all our WEXT handlers */
-extern const struct iw_handler_def orinoco_handler_def;
-
-#endif /* _ORINOCO_WEXT_H_ */
--
2.39.2

2023-10-23 13:22:37

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 07/10] wifi: remove orphaned ray_cs driver

From: Arnd Bergmann <[email protected]>

Aviator/Raytheon is an early PCMCIA driver, apparently predating 802.11b
and only supporting wireless extensions.

The driver has been orphaned since 2010 and only seen cosmetic updates
long before than. Jean Tourrilhes pointed out in a 2005 changelog that
he tested a change on actual hardware, which was apparently already
noteworthy back then.

Signed-off-by: Arnd Bergmann <[email protected]>
---
.../networking/device_drivers/wifi/index.rst | 1 -
.../networking/device_drivers/wifi/ray_cs.rst | 165 -
MAINTAINERS | 5 -
drivers/net/wireless/legacy/Kconfig | 16 -
drivers/net/wireless/legacy/Makefile | 1 -
drivers/net/wireless/legacy/ray_cs.c | 2824 -----------------
drivers/net/wireless/legacy/ray_cs.h | 74 -
drivers/net/wireless/legacy/rayctl.h | 734 -----
8 files changed, 3820 deletions(-)
delete mode 100644 Documentation/networking/device_drivers/wifi/ray_cs.rst
delete mode 100644 drivers/net/wireless/legacy/ray_cs.c
delete mode 100644 drivers/net/wireless/legacy/ray_cs.h
delete mode 100644 drivers/net/wireless/legacy/rayctl.h

diff --git a/Documentation/networking/device_drivers/wifi/index.rst b/Documentation/networking/device_drivers/wifi/index.rst
index bf91a87c7acff..fb394f5de4a94 100644
--- a/Documentation/networking/device_drivers/wifi/index.rst
+++ b/Documentation/networking/device_drivers/wifi/index.rst
@@ -10,7 +10,6 @@ Contents:

intel/ipw2100
intel/ipw2200
- ray_cs

.. only:: subproject and html

diff --git a/Documentation/networking/device_drivers/wifi/ray_cs.rst b/Documentation/networking/device_drivers/wifi/ray_cs.rst
deleted file mode 100644
index 9a46d1ae8f209..0000000000000
--- a/Documentation/networking/device_drivers/wifi/ray_cs.rst
+++ /dev/null
@@ -1,165 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-.. include:: <isonum.txt>
-
-=========================
-Raylink wireless LAN card
-=========================
-
-September 21, 1999
-
-Copyright |copy| 1998 Corey Thomas ([email protected])
-
-This file is the documentation for the Raylink Wireless LAN card driver for
-Linux. The Raylink wireless LAN card is a PCMCIA card which provides IEEE
-802.11 compatible wireless network connectivity at 1 and 2 megabits/second.
-See http://www.raytheon.com/micro/raylink/ for more information on the Raylink
-card. This driver is in early development and does have bugs. See the known
-bugs and limitations at the end of this document for more information.
-This driver also works with WebGear's Aviator 2.4 and Aviator Pro
-wireless LAN cards.
-
-As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel
-source. My web page for the development of ray_cs is at
-http://web.ralinktech.com/ralink/Home/Support/Linux.html
-and I can be emailed at [email protected]
-
-The kernel driver is based on ray_cs-1.62.tgz
-
-The driver at my web page is intended to be used as an add on to
-David Hinds pcmcia package. All the command line parameters are
-available when compiled as a module. When built into the kernel, only
-the essid= string parameter is available via the kernel command line.
-This will change after the method of sorting out parameters for all
-the PCMCIA drivers is agreed upon. If you must have a built in driver
-with nondefault parameters, they can be edited in
-/usr/src/linux/drivers/net/pcmcia/ray_cs.c. Searching for module_param
-will find them all.
-
-Information on card services is available at:
-
- http://pcmcia-cs.sourceforge.net/
-
-
-Card services user programs are still required for PCMCIA devices.
-pcmcia-cs-3.1.1 or greater is required for the kernel version of
-the driver.
-
-Currently, ray_cs is not part of David Hinds card services package,
-so the following magic is required.
-
-At the end of the /etc/pcmcia/config.opts file, add the line:
-source ./ray_cs.opts
-This will make card services read the ray_cs.opts file
-when starting. Create the file /etc/pcmcia/ray_cs.opts containing the
-following::
-
- #### start of /etc/pcmcia/ray_cs.opts ###################
- # Configuration options for Raylink Wireless LAN PCMCIA card
- device "ray_cs"
- class "network" module "misc/ray_cs"
-
- card "RayLink PC Card WLAN Adapter"
- manfid 0x01a6, 0x0000
- bind "ray_cs"
-
- module "misc/ray_cs" opts ""
- #### end of /etc/pcmcia/ray_cs.opts #####################
-
-
-To join an existing network with
-different parameters, contact the network administrator for the
-configuration information, and edit /etc/pcmcia/ray_cs.opts.
-Add the parameters below between the empty quotes.
-
-Parameters for ray_cs driver which may be specified in ray_cs.opts:
-
-=============== =============== =============================================
-bc integer 0 = normal mode (802.11 timing),
- 1 = slow down inter frame timing to allow
- operation with older breezecom access
- points.
-
-beacon_period integer beacon period in Kilo-microseconds,
-
- legal values = must be integer multiple
- of hop dwell
-
- default = 256
-
-country integer 1 = USA (default),
- 2 = Europe,
- 3 = Japan,
- 4 = Korea,
- 5 = Spain,
- 6 = France,
- 7 = Israel,
- 8 = Australia
-
-essid string ESS ID - network name to join
-
- string with maximum length of 32 chars
- default value = "ADHOC_ESSID"
-
-hop_dwell integer hop dwell time in Kilo-microseconds
-
- legal values = 16,32,64,128(default),256
-
-irq_mask integer linux standard 16 bit value 1bit/IRQ
-
- lsb is IRQ 0, bit 1 is IRQ 1 etc.
- Used to restrict choice of IRQ's to use.
- Recommended method for controlling
- interrupts is in /etc/pcmcia/config.opts
-
-net_type integer 0 (default) = adhoc network,
- 1 = infrastructure
-
-phy_addr string string containing new MAC address in
- hex, must start with x eg
- x00008f123456
-
-psm integer 0 = continuously active,
- 1 = power save mode (not useful yet)
-
-pc_debug integer (0-5) larger values for more verbose
- logging. Replaces ray_debug.
-
-ray_debug integer Replaced with pc_debug
-
-ray_mem_speed integer defaults to 500
-
-sniffer integer 0 = not sniffer (default),
- 1 = sniffer which can be used to record all
- network traffic using tcpdump or similar,
- but no normal network use is allowed.
-
-translate integer 0 = no translation (encapsulate frames),
- 1 = translation (RFC1042/802.1)
-=============== =============== =============================================
-
-More on sniffer mode:
-
-tcpdump does not understand 802.11 headers, so it can't
-interpret the contents, but it can record to a file. This is only
-useful for debugging 802.11 lowlevel protocols that are not visible to
-linux. If you want to watch ftp xfers, or do similar things, you
-don't need to use sniffer mode. Also, some packet types are never
-sent up by the card, so you will never see them (ack, rts, cts, probe
-etc.) There is a simple program (showcap) included in the ray_cs
-package which parses the 802.11 headers.
-
-Known Problems and missing features
-
- Does not work with non x86
-
- Does not work with SMP
-
- Support for defragmenting frames is not yet debugged, and in
- fact is known to not work. I have never encountered a net set
- up to fragment, but still, it should be fixed.
-
- The ioctl support is incomplete. The hardware address cannot be set
- using ifconfig yet. If a different hardware address is needed, it may
- be set using the phy_addr parameter in ray_cs.opts. This requires
- a card insertion to take effect.
diff --git a/MAINTAINERS b/MAINTAINERS
index e5c669d9bca00..3123c955bb7f5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17947,11 +17947,6 @@ F: drivers/ras/
F: include/linux/ras.h
F: include/ras/ras_event.h

-RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER
-L: [email protected]
-S: Orphan
-F: drivers/net/wireless/legacy/ray*
-
RC-CORE / LIRC FRAMEWORK
M: Sean Young <[email protected]>
L: [email protected]
diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig
index 3a5275941212d..1d77d53d64409 100644
--- a/drivers/net/wireless/legacy/Kconfig
+++ b/drivers/net/wireless/legacy/Kconfig
@@ -1,19 +1,3 @@
-config PCMCIA_RAYCS
- tristate "Aviator/Raytheon 2.4GHz wireless support"
- depends on PCMCIA
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- help
- Say Y here if you intend to attach an Aviator/Raytheon PCMCIA
- (PC-card) wireless Ethernet networking card to your computer.
- Please read the file
- <file:Documentation/networking/device_drivers/wifi/ray_cs.rst> for
- details.
-
- To compile this driver as a module, choose M here: the module will be
- called ray_cs. If unsure, say N.
-
config PCMCIA_WL3501
tristate "Planet WL3501 PCMCIA cards"
depends on CFG80211 && PCMCIA
diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile
index 36878f080bfc5..d8705ccc5cf5d 100644
--- a/drivers/net/wireless/legacy/Makefile
+++ b/drivers/net/wireless/legacy/Makefile
@@ -1,5 +1,4 @@
# 16-bit wireless PCMCIA client drivers
-obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o

obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o
diff --git a/drivers/net/wireless/legacy/ray_cs.c b/drivers/net/wireless/legacy/ray_cs.c
deleted file mode 100644
index 8ace797ce951c..0000000000000
--- a/drivers/net/wireless/legacy/ray_cs.c
+++ /dev/null
@@ -1,2824 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*=============================================================================
- *
- * A PCMCIA client driver for the Raylink wireless LAN card.
- * The starting point for this module was the skeleton.c in the
- * PCMCIA 2.9.12 package written by David Hinds, [email protected]
- *
- * Copyright (c) 1998 Corey Thomas ([email protected])
- *
- * Changes:
- * Arnaldo Carvalho de Melo <[email protected]> - 08/08/2000
- * - reorganize kmallocs in ray_attach, checking all for failure
- * and releasing the previous allocations if one fails
- *
- * Daniele Bellucci <[email protected]> - 07/10/2003
- * - Audit copy_to_user in ioctl(SIOCGIWESSID)
- *
-=============================================================================*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/proc_fs.h>
-#include <linux/ptrace.h>
-#include <linux/seq_file.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-#include <linux/ieee80211.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <linux/wireless.h>
-#include <net/iw_handler.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <linux/uaccess.h>
-
-/* Warning : these stuff will slow down the driver... */
-#define WIRELESS_SPY /* Enable spying addresses */
-/* Definitions we need for spy */
-typedef struct iw_statistics iw_stats;
-typedef u_char mac_addr[ETH_ALEN]; /* Hardware address */
-
-#include "rayctl.h"
-#include "ray_cs.h"
-
-
-/** Prototypes based on PCMCIA skeleton driver *******************************/
-static int ray_config(struct pcmcia_device *link);
-static void ray_release(struct pcmcia_device *link);
-static void ray_detach(struct pcmcia_device *p_dev);
-
-/***** Prototypes indicated by device structure ******************************/
-static int ray_dev_close(struct net_device *dev);
-static int ray_dev_config(struct net_device *dev, struct ifmap *map);
-static struct net_device_stats *ray_get_stats(struct net_device *dev);
-static int ray_dev_init(struct net_device *dev);
-
-static int ray_open(struct net_device *dev);
-static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
- struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-static void ray_update_multi_list(struct net_device *dev, int all);
-static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
- unsigned char *data, int len);
-static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
- UCHAR msg_type, unsigned char *data);
-static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
-static iw_stats *ray_get_wireless_stats(struct net_device *dev);
-static const struct iw_handler_def ray_handler_def;
-
-/***** Prototypes for raylink functions **************************************/
-static void authenticate(ray_dev_t *local);
-static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
-static void authenticate_timeout(struct timer_list *t);
-static int get_free_ccs(ray_dev_t *local);
-static int get_free_tx_ccs(ray_dev_t *local);
-static void init_startup_params(ray_dev_t *local);
-static int parse_addr(char *in_str, UCHAR *out);
-static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, UCHAR type);
-static int ray_init(struct net_device *dev);
-static int interrupt_ecf(ray_dev_t *local, int ccs);
-static void ray_reset(struct net_device *dev);
-static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len);
-static void verify_dl_startup(struct timer_list *t);
-
-/* Prototypes for interrpt time functions **********************************/
-static irqreturn_t ray_interrupt(int reg, void *dev_id);
-static void clear_interrupt(ray_dev_t *local);
-static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len);
-static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
-static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs);
-static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs);
-static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len);
-static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len);
-static void associate(ray_dev_t *local);
-
-/* Card command functions */
-static int dl_startup_params(struct net_device *dev);
-static void join_net(struct timer_list *t);
-static void start_net(struct timer_list *t);
-
-/*===========================================================================*/
-/* Parameters that can be set with 'insmod' */
-
-/* ADHOC=0, Infrastructure=1 */
-static int net_type = ADHOC;
-
-/* Hop dwell time in Kus (1024 us units defined by 802.11) */
-static int hop_dwell = 128;
-
-/* Beacon period in Kus */
-static int beacon_period = 256;
-
-/* power save mode (0 = off, 1 = save power) */
-static int psm;
-
-/* String for network's Extended Service Set ID. 32 Characters max */
-static char *essid;
-
-/* Default to encapsulation unless translation requested */
-static bool translate = true;
-
-static int country = USA;
-
-static int sniffer;
-
-static int bc;
-
-/* 48 bit physical card address if overriding card's real physical
- * address is required. Since IEEE 802.11 addresses are 48 bits
- * like ethernet, an int can't be used, so a string is used. To
- * allow use of addresses starting with a decimal digit, the first
- * character must be a letter and will be ignored. This letter is
- * followed by up to 12 hex digits which are the address. If less
- * than 12 digits are used, the address will be left filled with 0's.
- * Note that bit 0 of the first byte is the broadcast bit, and evil
- * things will happen if it is not 0 in a card address.
- */
-static char *phy_addr = NULL;
-
-static unsigned int ray_mem_speed = 500;
-
-/* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */
-static struct pcmcia_device *this_device = NULL;
-
-MODULE_AUTHOR("Corey Thomas <[email protected]>");
-MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver");
-MODULE_LICENSE("GPL");
-
-module_param(net_type, int, 0);
-module_param(hop_dwell, int, 0);
-module_param(beacon_period, int, 0);
-module_param(psm, int, 0);
-module_param(essid, charp, 0);
-module_param(translate, bool, 0);
-module_param(country, int, 0);
-module_param(sniffer, int, 0);
-module_param(bc, int, 0);
-module_param(phy_addr, charp, 0);
-module_param(ray_mem_speed, int, 0);
-
-static const UCHAR b5_default_startup_parms[] = {
- 0, 0, /* Adhoc station */
- 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, /* Active scan, CA Mode */
- 0, 0, 0, 0, 0, 0, /* No default MAC addr */
- 0x7f, 0xff, /* Frag threshold */
- 0x00, 0x80, /* Hop time 128 Kus */
- 0x01, 0x00, /* Beacon period 256 Kus */
- 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */
- 0x1d, 0x82, 0x4e, /* SIFS, DIFS, PIFS */
- 0x7f, 0xff, /* RTS threshold */
- 0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */
- 0x05, /* assoc resp timeout thresh */
- 0x08, 0x02, 0x08, /* adhoc, infra, super cycle max */
- 0, /* Promiscuous mode */
- 0x0c, 0x0bd, /* Unique word */
- 0x32, /* Slot time */
- 0xff, 0xff, /* roam-low snr, low snr count */
- 0x05, 0xff, /* Infra, adhoc missed bcn thresh */
- 0x01, 0x0b, 0x4f, /* USA, hop pattern, hop pat length */
-/* b4 - b5 differences start here */
- 0x00, 0x3f, /* CW max */
- 0x00, 0x0f, /* CW min */
- 0x04, 0x08, /* Noise gain, limit offset */
- 0x28, 0x28, /* det rssi, med busy offsets */
- 7, /* det sync thresh */
- 0, 2, 2, /* test mode, min, max */
- 0, /* allow broadcast SSID probe resp */
- 0, 0, /* privacy must start, can join */
- 2, 0, 0, 0, 0, 0, 0, 0 /* basic rate set */
-};
-
-static const UCHAR b4_default_startup_parms[] = {
- 0, 0, /* Adhoc station */
- 'L', 'I', 'N', 'U', 'X', 0, 0, 0, /* 32 char ESSID */
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 0, /* Active scan, CA Mode */
- 0, 0, 0, 0, 0, 0, /* No default MAC addr */
- 0x7f, 0xff, /* Frag threshold */
- 0x02, 0x00, /* Hop time */
- 0x00, 0x01, /* Beacon period */
- 0x01, 0x07, 0xa3, /* DTIM, retries, ack timeout */
- 0x1d, 0x82, 0xce, /* SIFS, DIFS, PIFS */
- 0x7f, 0xff, /* RTS threshold */
- 0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */
- 0x05, /* assoc resp timeout thresh */
- 0x04, 0x02, 0x4, /* adhoc, infra, super cycle max */
- 0, /* Promiscuous mode */
- 0x0c, 0x0bd, /* Unique word */
- 0x4e, /* Slot time (TBD seems wrong) */
- 0xff, 0xff, /* roam-low snr, low snr count */
- 0x05, 0xff, /* Infra, adhoc missed bcn thresh */
- 0x01, 0x0b, 0x4e, /* USA, hop pattern, hop pat length */
-/* b4 - b5 differences start here */
- 0x3f, 0x0f, /* CW max, min */
- 0x04, 0x08, /* Noise gain, limit offset */
- 0x28, 0x28, /* det rssi, med busy offsets */
- 7, /* det sync thresh */
- 0, 2, 2, /* test mode, min, max */
- 0, /* rx/tx delay */
- 0, 0, 0, 0, 0, 0, /* current BSS id */
- 0 /* hop set */
-};
-
-/*===========================================================================*/
-static const u8 eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
-
-static const char hop_pattern_length[] = { 1,
- USA_HOP_MOD, EUROPE_HOP_MOD,
- JAPAN_HOP_MOD, KOREA_HOP_MOD,
- SPAIN_HOP_MOD, FRANCE_HOP_MOD,
- ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD,
- JAPAN_TEST_HOP_MOD
-};
-
-static const char rcsid[] =
- "Raylink/WebGear wireless LAN - Corey <Thomas [email protected]>";
-
-static const struct net_device_ops ray_netdev_ops = {
- .ndo_init = ray_dev_init,
- .ndo_open = ray_open,
- .ndo_stop = ray_dev_close,
- .ndo_start_xmit = ray_dev_start_xmit,
- .ndo_set_config = ray_dev_config,
- .ndo_get_stats = ray_get_stats,
- .ndo_set_rx_mode = set_multicast_list,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ray_probe(struct pcmcia_device *p_dev)
-{
- ray_dev_t *local;
- struct net_device *dev;
- int ret;
-
- dev_dbg(&p_dev->dev, "ray_attach()\n");
-
- /* Allocate space for private device-specific data */
- dev = alloc_etherdev(sizeof(ray_dev_t));
- if (!dev)
- return -ENOMEM;
-
- local = netdev_priv(dev);
- local->finder = p_dev;
-
- /* The io structure describes IO port mapping. None used here */
- p_dev->resource[0]->end = 0;
- p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
- /* General socket configuration */
- p_dev->config_flags |= CONF_ENABLE_IRQ;
- p_dev->config_index = 1;
-
- p_dev->priv = dev;
-
- local->finder = p_dev;
- local->card_status = CARD_INSERTED;
- local->authentication_state = UNAUTHENTICATED;
- local->num_multi = 0;
- dev_dbg(&p_dev->dev, "ray_attach p_dev = %p, dev = %p, local = %p, intr = %p\n",
- p_dev, dev, local, &ray_interrupt);
-
- /* Raylink entries in the device structure */
- dev->netdev_ops = &ray_netdev_ops;
- dev->wireless_handlers = &ray_handler_def;
-#ifdef WIRELESS_SPY
- local->wireless_data.spy_data = &local->spy_data;
- dev->wireless_data = &local->wireless_data;
-#endif /* WIRELESS_SPY */
-
-
- dev_dbg(&p_dev->dev, "ray_cs ray_attach calling ether_setup.)\n");
- netif_stop_queue(dev);
-
- timer_setup(&local->timer, NULL, 0);
-
- this_device = p_dev;
- ret = ray_config(p_dev);
- if (ret)
- goto err_free_dev;
-
- return 0;
-
-err_free_dev:
- free_netdev(dev);
- return ret;
-}
-
-static void ray_detach(struct pcmcia_device *link)
-{
- struct net_device *dev;
-
- dev_dbg(&link->dev, "ray_detach\n");
-
- this_device = NULL;
- dev = link->priv;
-
- ray_release(link);
-
- if (link->priv) {
- unregister_netdev(dev);
- free_netdev(dev);
- }
- dev_dbg(&link->dev, "ray_cs ray_detach ending\n");
-} /* ray_detach */
-
-#define MAX_TUPLE_SIZE 128
-static int ray_config(struct pcmcia_device *link)
-{
- int ret = 0;
- int i;
- struct net_device *dev = (struct net_device *)link->priv;
- ray_dev_t *local = netdev_priv(dev);
-
- dev_dbg(&link->dev, "ray_config\n");
-
- /* Determine card type and firmware version */
- printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n",
- link->prod_id[0] ? link->prod_id[0] : " ",
- link->prod_id[1] ? link->prod_id[1] : " ",
- link->prod_id[2] ? link->prod_id[2] : " ",
- link->prod_id[3] ? link->prod_id[3] : " ");
-
- /* Now allocate an interrupt line. Note that this does not
- actually assign a handler to the interrupt.
- */
- ret = pcmcia_request_irq(link, ray_interrupt);
- if (ret)
- goto failed;
- dev->irq = link->irq;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
-/*** Set up 32k window for shared memory (transmit and control) ************/
- link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
- link->resource[2]->start = 0;
- link->resource[2]->end = 0x8000;
- ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed);
- if (ret)
- goto failed;
- ret = pcmcia_map_mem_page(link, link->resource[2], 0);
- if (ret)
- goto failed;
- local->sram = ioremap(link->resource[2]->start,
- resource_size(link->resource[2]));
- if (!local->sram)
- goto failed;
-
-/*** Set up 16k window for shared memory (receive buffer) ***************/
- link->resource[3]->flags |=
- WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
- link->resource[3]->start = 0;
- link->resource[3]->end = 0x4000;
- ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed);
- if (ret)
- goto failed;
- ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000);
- if (ret)
- goto failed;
- local->rmem = ioremap(link->resource[3]->start,
- resource_size(link->resource[3]));
- if (!local->rmem)
- goto failed;
-
-/*** Set up window for attribute memory ***********************************/
- link->resource[4]->flags |=
- WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
- link->resource[4]->start = 0;
- link->resource[4]->end = 0x1000;
- ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed);
- if (ret)
- goto failed;
- ret = pcmcia_map_mem_page(link, link->resource[4], 0);
- if (ret)
- goto failed;
- local->amem = ioremap(link->resource[4]->start,
- resource_size(link->resource[4]));
- if (!local->amem)
- goto failed;
-
- dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram);
- dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem);
- dev_dbg(&link->dev, "ray_config amem=%p\n", local->amem);
- if (ray_init(dev) < 0) {
- ray_release(link);
- return -ENODEV;
- }
-
- SET_NETDEV_DEV(dev, &link->dev);
- i = register_netdev(dev);
- if (i != 0) {
- printk("ray_config register_netdev() failed\n");
- ray_release(link);
- return i;
- }
-
- printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n",
- dev->name, dev->irq, dev->dev_addr);
-
- return 0;
-
-failed:
- ray_release(link);
- return -ENODEV;
-} /* ray_config */
-
-static inline struct ccs __iomem *ccs_base(ray_dev_t *dev)
-{
- return dev->sram + CCS_BASE;
-}
-
-static inline struct rcs __iomem *rcs_base(ray_dev_t *dev)
-{
- /*
- * This looks nonsensical, since there is a separate
- * RCS_BASE. But the difference between a "struct rcs"
- * and a "struct ccs" ends up being in the _index_ off
- * the base, so the base pointer is the same for both
- * ccs/rcs.
- */
- return dev->sram + CCS_BASE;
-}
-
-/*===========================================================================*/
-static int ray_init(struct net_device *dev)
-{
- int i;
- struct ccs __iomem *pccs;
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- dev_dbg(&link->dev, "ray_init(0x%p)\n", dev);
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_init - device not present\n");
- return -1;
- }
-
- local->net_type = net_type;
- local->sta_type = TYPE_STA;
-
- /* Copy the startup results to local memory */
- memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,
- sizeof(struct startup_res_6));
-
- /* Check Power up test status and get mac address from card */
- if (local->startup_res.startup_word != 0x80) {
- printk(KERN_INFO "ray_init ERROR card status = %2x\n",
- local->startup_res.startup_word);
- local->card_status = CARD_INIT_ERROR;
- return -1;
- }
-
- local->fw_ver = local->startup_res.firmware_version[0];
- local->fw_bld = local->startup_res.firmware_version[1];
- local->fw_var = local->startup_res.firmware_version[2];
- dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver,
- local->fw_bld);
-
- local->tib_length = 0x20;
- if ((local->fw_ver == 5) && (local->fw_bld >= 30))
- local->tib_length = local->startup_res.tib_length;
- dev_dbg(&link->dev, "ray_init tib_length = 0x%02x\n", local->tib_length);
- /* Initialize CCS's to buffer free state */
- pccs = ccs_base(local);
- for (i = 0; i < NUMBER_OF_CCS; i++) {
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- }
- init_startup_params(local);
-
- /* copy mac address to startup parameters */
- if (!parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) {
- memcpy(&local->sparm.b4.a_mac_addr,
- &local->startup_res.station_addr, ADDRLEN);
- }
-
- clear_interrupt(local); /* Clear any interrupt from the card */
- local->card_status = CARD_AWAITING_PARAM;
- dev_dbg(&link->dev, "ray_init ending\n");
- return 0;
-} /* ray_init */
-
-/*===========================================================================*/
-/* Download startup parameters to the card and command it to read them */
-static int dl_startup_params(struct net_device *dev)
-{
- int ccsindex;
- ray_dev_t *local = netdev_priv(dev);
- struct ccs __iomem *pccs;
- struct pcmcia_device *link = local->finder;
-
- dev_dbg(&link->dev, "dl_startup_params entered\n");
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs dl_startup_params - device not present\n");
- return -1;
- }
-
- /* Copy parameters to host to ECF area */
- if (local->fw_ver == 0x55)
- memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4,
- sizeof(struct b4_startup_params));
- else
- memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5,
- sizeof(struct b5_startup_params));
-
- /* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) < 0)
- return -1;
- local->dl_param_ccs = ccsindex;
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
- dev_dbg(&link->dev, "dl_startup_params start ccsindex = %d\n",
- local->dl_param_ccs);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- printk(KERN_INFO "ray dl_startup_params failed - "
- "ECF not ready for intr\n");
- local->card_status = CARD_DL_PARAM_ERROR;
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return -2;
- }
- local->card_status = CARD_DL_PARAM;
- /* Start kernel timer to wait for dl startup to complete. */
- local->timer.expires = jiffies + HZ / 2;
- local->timer.function = verify_dl_startup;
- add_timer(&local->timer);
- dev_dbg(&link->dev,
- "ray_cs dl_startup_params started timer for verify_dl_startup\n");
- return 0;
-} /* dl_startup_params */
-
-/*===========================================================================*/
-static void init_startup_params(ray_dev_t *local)
-{
- int i;
-
- if (country > JAPAN_TEST)
- country = USA;
- else if (country < USA)
- country = USA;
- /* structure for hop time and beacon period is defined here using
- * New 802.11D6.1 format. Card firmware is still using old format
- * until version 6.
- * Before After
- * a_hop_time ms byte a_hop_time ms byte
- * a_hop_time 2s byte a_hop_time ls byte
- * a_hop_time ls byte a_beacon_period ms byte
- * a_beacon_period a_beacon_period ls byte
- *
- * a_hop_time = uS a_hop_time = KuS
- * a_beacon_period = hops a_beacon_period = KuS
- *//* 64ms = 010000 */
- if (local->fw_ver == 0x55) {
- memcpy(&local->sparm.b4, b4_default_startup_parms,
- sizeof(struct b4_startup_params));
- /* Translate sane kus input values to old build 4/5 format */
- /* i = hop time in uS truncated to 3 bytes */
- i = (hop_dwell * 1024) & 0xffffff;
- local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff;
- local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff;
- local->sparm.b4.a_beacon_period[0] = 0;
- local->sparm.b4.a_beacon_period[1] =
- ((beacon_period / hop_dwell) - 1) & 0xff;
- local->sparm.b4.a_curr_country_code = country;
- local->sparm.b4.a_hop_pattern_length =
- hop_pattern_length[(int)country] - 1;
- if (bc) {
- local->sparm.b4.a_ack_timeout = 0x50;
- local->sparm.b4.a_sifs = 0x3f;
- }
- } else { /* Version 5 uses real kus values */
- memcpy((UCHAR *) &local->sparm.b5, b5_default_startup_parms,
- sizeof(struct b5_startup_params));
-
- local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff;
- local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff;
- local->sparm.b5.a_beacon_period[0] =
- (beacon_period >> 8) & 0xff;
- local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff;
- if (psm)
- local->sparm.b5.a_power_mgt_state = 1;
- local->sparm.b5.a_curr_country_code = country;
- local->sparm.b5.a_hop_pattern_length =
- hop_pattern_length[(int)country];
- }
-
- local->sparm.b4.a_network_type = net_type & 0x01;
- local->sparm.b4.a_acting_as_ap_status = TYPE_STA;
-
- if (essid != NULL)
- strscpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
-} /* init_startup_params */
-
-/*===========================================================================*/
-static void verify_dl_startup(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
- struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs;
- UCHAR status;
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs verify_dl_startup - device not present\n");
- return;
- }
-#if 0
- {
- int i;
- printk(KERN_DEBUG
- "verify_dl_startup parameters sent via ccs %d:\n",
- local->dl_param_ccs);
- for (i = 0; i < sizeof(struct b5_startup_params); i++) {
- printk(" %2x",
- (unsigned int)readb(local->sram +
- HOST_TO_ECF_BASE + i));
- }
- printk("\n");
- }
-#endif
-
- status = readb(&pccs->buffer_status);
- if (status != CCS_BUFFER_FREE) {
- printk(KERN_INFO
- "Download startup params failed. Status = %d\n",
- status);
- local->card_status = CARD_DL_PARAM_ERROR;
- return;
- }
- if (local->sparm.b4.a_network_type == ADHOC)
- start_net(&local->timer);
- else
- join_net(&local->timer);
-} /* end verify_dl_startup */
-
-/*===========================================================================*/
-/* Command card to start a network */
-static void start_net(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
- struct ccs __iomem *pccs;
- int ccsindex;
- struct pcmcia_device *link = local->finder;
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs start_net - device not present\n");
- return;
- }
- /* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) < 0)
- return;
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_START_NETWORK, &pccs->cmd);
- writeb(0, &pccs->var.start_network.update_param);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray start net failed - card not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return;
- }
- local->card_status = CARD_DOING_ACQ;
-} /* end start_net */
-
-/*===========================================================================*/
-/* Command card to join a network */
-static void join_net(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
-
- struct ccs __iomem *pccs;
- int ccsindex;
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs join_net - device not present\n");
- return;
- }
- /* Fill in the CCS fields for the ECF */
- if ((ccsindex = get_free_ccs(local)) < 0)
- return;
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_JOIN_NETWORK, &pccs->cmd);
- writeb(0, &pccs->var.join_network.update_param);
- writeb(0, &pccs->var.join_network.net_initiated);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray join net failed - card not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return;
- }
- local->card_status = CARD_DOING_ACQ;
-}
-
-
-static void ray_release(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
- ray_dev_t *local = netdev_priv(dev);
-
- dev_dbg(&link->dev, "ray_release\n");
-
- del_timer_sync(&local->timer);
-
- if (local->sram)
- iounmap(local->sram);
- if (local->rmem)
- iounmap(local->rmem);
- if (local->amem)
- iounmap(local->amem);
- pcmcia_disable_device(link);
-
- dev_dbg(&link->dev, "ray_release ending\n");
-}
-
-static int ray_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open)
- netif_device_detach(dev);
-
- return 0;
-}
-
-static int ray_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- if (link->open) {
- ray_reset(dev);
- netif_device_attach(dev);
- }
-
- return 0;
-}
-
-/*===========================================================================*/
-static int ray_dev_init(struct net_device *dev)
-{
-#ifdef RAY_IMMEDIATE_INIT
- int i;
-#endif /* RAY_IMMEDIATE_INIT */
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
-
- dev_dbg(&link->dev, "ray_dev_init(dev=%p)\n", dev);
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_dev_init - device not present\n");
- return -1;
- }
-#ifdef RAY_IMMEDIATE_INIT
- /* Download startup parameters */
- if ((i = dl_startup_params(dev)) < 0) {
- printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
- "returns 0x%x\n", i);
- return -1;
- }
-#else /* RAY_IMMEDIATE_INIT */
- /* Postpone the card init so that we can still configure the card,
- * for example using the Wireless Extensions. The init will happen
- * in ray_open() - Jean II */
- dev_dbg(&link->dev,
- "ray_dev_init: postponing card init to ray_open() ; Status = %d\n",
- local->card_status);
-#endif /* RAY_IMMEDIATE_INIT */
-
- /* copy mac and broadcast addresses to linux device */
- eth_hw_addr_set(dev, local->sparm.b4.a_mac_addr);
- eth_broadcast_addr(dev->broadcast);
-
- dev_dbg(&link->dev, "ray_dev_init ending\n");
- return 0;
-}
-
-/*===========================================================================*/
-static int ray_dev_config(struct net_device *dev, struct ifmap *map)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- /* Dummy routine to satisfy device structure */
- dev_dbg(&link->dev, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map);
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_dev_config - device not present\n");
- return -1;
- }
-
- return 0;
-}
-
-/*===========================================================================*/
-static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- short length = skb->len;
-
- if (!pcmcia_dev_present(link)) {
- dev_dbg(&link->dev, "ray_dev_start_xmit - device not present\n");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
- dev_dbg(&link->dev, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev);
- if (local->authentication_state == NEED_TO_AUTH) {
- dev_dbg(&link->dev, "ray_cs Sending authentication request.\n");
- if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) {
- local->authentication_state = AUTHENTICATED;
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
- }
- }
-
- if (length < ETH_ZLEN) {
- if (skb_padto(skb, ETH_ZLEN))
- return NETDEV_TX_OK;
- length = ETH_ZLEN;
- }
- switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
- case XMIT_NO_CCS:
- case XMIT_NEED_AUTH:
- netif_stop_queue(dev);
- return NETDEV_TX_BUSY;
- case XMIT_NO_INTR:
- case XMIT_MSG_BAD:
- case XMIT_OK:
- default:
- dev_kfree_skb(skb);
- }
-
- return NETDEV_TX_OK;
-} /* ray_dev_start_xmit */
-
-/*===========================================================================*/
-static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev,
- UCHAR msg_type)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct ccs __iomem *pccs;
- int ccsindex;
- int offset;
- struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */
- short int addr; /* Address of xmit buffer in card space */
-
- pr_debug("ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev);
- if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) {
- printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",
- len);
- return XMIT_MSG_BAD;
- }
- switch (ccsindex = get_free_tx_ccs(local)) {
- case ECCSBUSY:
- pr_debug("ray_hw_xmit tx_ccs table busy\n");
- fallthrough;
- case ECCSFULL:
- pr_debug("ray_hw_xmit No free tx ccs\n");
- fallthrough;
- case ECARDGONE:
- netif_stop_queue(dev);
- return XMIT_NO_CCS;
- default:
- break;
- }
- addr = TX_BUF_BASE + (ccsindex << 11);
-
- if (msg_type == DATA_TYPE) {
- local->stats.tx_bytes += len;
- local->stats.tx_packets++;
- }
-
- ptx = local->sram + addr;
-
- ray_build_header(local, ptx, msg_type, data);
- if (translate) {
- offset = translate_frame(local, ptx, data, len);
- } else { /* Encapsulate frame */
- /* TBD TIB length will move address of ptx->var */
- memcpy_toio(&ptx->var, data, len);
- offset = 0;
- }
-
- /* fill in the CCS */
- pccs = ccs_base(local) + ccsindex;
- len += TX_HEADER_LENGTH + offset;
- writeb(CCS_TX_REQUEST, &pccs->cmd);
- writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]);
- writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]);
- writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]);
- writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);
-/* TBD still need psm_cam? */
- writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode);
- writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate);
- writeb(0, &pccs->var.tx_request.antenna);
- pr_debug("ray_hw_xmit default_tx_rate = 0x%x\n",
- local->net_default_tx_rate);
-
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- pr_debug("ray_hw_xmit failed - ECF not ready for intr\n");
-/* TBD very inefficient to copy packet to buffer, and then not
- send it, but the alternative is to queue the messages and that
- won't be done for a while. Maybe set tbusy until a CCS is free?
-*/
- writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
- return XMIT_NO_INTR;
- }
- return XMIT_OK;
-} /* end ray_hw_xmit */
-
-/*===========================================================================*/
-static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
- unsigned char *data, int len)
-{
- __be16 proto = ((struct ethhdr *)data)->h_proto;
- if (ntohs(proto) >= ETH_P_802_3_MIN) { /* DIX II ethernet frame */
- pr_debug("ray_cs translate_frame DIX II\n");
- /* Copy LLC header to card buffer */
- memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
- memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc),
- (UCHAR *) &proto, 2);
- if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) {
- /* This is the selective translation table, only 2 entries */
- writeb(0xf8,
- &((struct snaphdr_t __iomem *)ptx->var)->org[2]);
- }
- /* Copy body of ethernet packet without ethernet header */
- memcpy_toio((void __iomem *)&ptx->var +
- sizeof(struct snaphdr_t), data + ETH_HLEN,
- len - ETH_HLEN);
- return (int)sizeof(struct snaphdr_t) - ETH_HLEN;
- } else { /* already 802 type, and proto is length */
- pr_debug("ray_cs translate_frame 802\n");
- if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */
- pr_debug("ray_cs translate_frame evil IPX\n");
- memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
- return 0 - ETH_HLEN;
- }
- memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
- return 0 - ETH_HLEN;
- }
- /* TBD do other frame types */
-} /* end translate_frame */
-
-/*===========================================================================*/
-static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
- UCHAR msg_type, unsigned char *data)
-{
- writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
-/*** IEEE 802.11 Address field assignments *************
- TODS FROMDS addr_1 addr_2 addr_3 addr_4
-Adhoc 0 0 dest src (terminal) BSSID N/A
-AP to Terminal 0 1 dest AP(BSSID) source N/A
-Terminal to AP 1 0 AP(BSSID) src (terminal) dest N/A
-AP to AP 1 1 dest AP src AP dest source
-*******************************************************/
- if (local->net_type == ADHOC) {
- writeb(0, &ptx->mac.frame_ctl_2);
- memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest,
- ADDRLEN);
- memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source,
- ADDRLEN);
- memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
- } else { /* infrastructure */
-
- if (local->sparm.b4.a_acting_as_ap_status) {
- writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);
- memcpy_toio(ptx->mac.addr_1,
- ((struct ethhdr *)data)->h_dest, ADDRLEN);
- memcpy_toio(ptx->mac.addr_2, local->bss_id, 6);
- memcpy_toio(ptx->mac.addr_3,
- ((struct ethhdr *)data)->h_source, ADDRLEN);
- } else { /* Terminal */
-
- writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2);
- memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN);
- memcpy_toio(ptx->mac.addr_2,
- ((struct ethhdr *)data)->h_source, ADDRLEN);
- memcpy_toio(ptx->mac.addr_3,
- ((struct ethhdr *)data)->h_dest, ADDRLEN);
- }
- }
-} /* end encapsulate_frame */
-
-/*====================================================================*/
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get protocol name
- */
-static int ray_get_name(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- strcpy(wrqu->name, "IEEE 802.11-FH");
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set frequency
- */
-static int ray_set_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* Setting by channel number */
- if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0))
- err = -EOPNOTSUPP;
- else
- local->sparm.b5.a_hop_pattern = wrqu->freq.m;
-
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get frequency
- */
-static int ray_get_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- wrqu->freq.m = local->sparm.b5.a_hop_pattern;
- wrqu->freq.e = 0;
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set ESSID
- */
-static int ray_set_essid(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* Check if we asked for `any' */
- if (wrqu->essid.flags == 0)
- /* Corey : can you do that ? */
- return -EOPNOTSUPP;
-
- /* Check the size of the string */
- if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- /* Set the ESSID in the card */
- memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE);
- memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length);
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get ESSID
- */
-static int ray_get_essid(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- UCHAR tmp[IW_ESSID_MAX_SIZE + 1];
-
- /* Get the essid that was set */
- memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
- memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
- tmp[IW_ESSID_MAX_SIZE] = '\0';
-
- /* Push it out ! */
- wrqu->essid.length = strlen(tmp);
- wrqu->essid.flags = 1; /* active */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get AP address
- */
-static int ray_get_wap(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN);
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Bit-Rate
- */
-static int ray_set_rate(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* Check if rate is in range */
- if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000))
- return -EINVAL;
-
- /* Hack for 1.5 Mb/s instead of 2 Mb/s */
- if ((local->fw_ver == 0x55) && /* Please check */
- (wrqu->bitrate.value == 2000000))
- local->net_default_tx_rate = 3;
- else
- local->net_default_tx_rate = wrqu->bitrate.value / 500000;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Bit-Rate
- */
-static int ray_get_rate(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- if (local->net_default_tx_rate == 3)
- wrqu->bitrate.value = 2000000; /* Hum... */
- else
- wrqu->bitrate.value = local->net_default_tx_rate * 500000;
- wrqu->bitrate.fixed = 0; /* We are in auto mode */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set RTS threshold
- */
-static int ray_set_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int rthr = wrqu->rts.value;
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* if(wrq->u.rts.fixed == 0) we should complain */
- if (wrqu->rts.disabled)
- rthr = 32767;
- else {
- if ((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
- return -EINVAL;
- }
- local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
- local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get RTS threshold
- */
-static int ray_get_rts(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
- + local->sparm.b5.a_rts_threshold[1];
- wrqu->rts.disabled = (wrqu->rts.value == 32767);
- wrqu->rts.fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Fragmentation threshold
- */
-static int ray_set_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int fthr = wrqu->frag.value;
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- /* if(wrq->u.frag.fixed == 0) should complain */
- if (wrqu->frag.disabled)
- fthr = 32767;
- else {
- if ((fthr < 256) || (fthr > 2347)) /* To check out ! */
- return -EINVAL;
- }
- local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
- local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
-
- return -EINPROGRESS; /* Call commit handler */
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Fragmentation threshold
- */
-static int ray_get_frag(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
- + local->sparm.b5.a_frag_threshold[1];
- wrqu->frag.disabled = (wrqu->frag.value == 32767);
- wrqu->frag.fixed = 1;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set Mode of Operation
- */
-static int ray_set_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
- int err = -EINPROGRESS; /* Call commit handler */
- char card_mode = 1;
-
- /* Reject if card is already initialised */
- if (local->card_status != CARD_AWAITING_PARAM)
- return -EBUSY;
-
- switch (wrqu->mode) {
- case IW_MODE_ADHOC:
- card_mode = 0;
- fallthrough;
- case IW_MODE_INFRA:
- local->sparm.b5.a_network_type = card_mode;
- break;
- default:
- err = -EINVAL;
- }
-
- return err;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get Mode of Operation
- */
-static int ray_get_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- ray_dev_t *local = netdev_priv(dev);
-
- if (local->sparm.b5.a_network_type)
- wrqu->mode = IW_MODE_INFRA;
- else
- wrqu->mode = IW_MODE_ADHOC;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get range info
- */
-static int ray_get_range(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_range *range = (struct iw_range *)extra;
-
- memset(range, 0, sizeof(struct iw_range));
-
- /* Set the length (very important for backward compatibility) */
- wrqu->data.length = sizeof(struct iw_range);
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 9;
-
- /* Set information in the range struct */
- range->throughput = 1.1 * 1000 * 1000; /* Put the right number here */
- range->num_channels = hop_pattern_length[(int)country];
- range->num_frequency = 0;
- range->max_qual.qual = 0;
- range->max_qual.level = 255; /* What's the correct value ? */
- range->max_qual.noise = 255; /* Idem */
- range->num_bitrates = 2;
- range->bitrate[0] = 1000000; /* 1 Mb/s */
- range->bitrate[1] = 2000000; /* 2 Mb/s */
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Private Handler : set framing mode
- */
-static int ray_set_framing(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- translate = !!*(extra); /* Set framing mode */
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Private Handler : get framing mode
- */
-static int ray_get_framing(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- *(extra) = translate;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Private Handler : get country
- */
-static int ray_get_country(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- *(extra) = country;
-
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Commit handler : called after a bunch of SET operations
- */
-static int ray_commit(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- return 0;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Stats handler : return Wireless Stats
- */
-static iw_stats *ray_get_wireless_stats(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- struct status __iomem *p = local->sram + STATUS_BASE;
-
- local->wstats.status = local->card_status;
-#ifdef WIRELESS_SPY
- if ((local->spy_data.spy_number > 0)
- && (local->sparm.b5.a_network_type == 0)) {
- /* Get it from the first node in spy list */
- local->wstats.qual.qual = local->spy_data.spy_stat[0].qual;
- local->wstats.qual.level = local->spy_data.spy_stat[0].level;
- local->wstats.qual.noise = local->spy_data.spy_stat[0].noise;
- local->wstats.qual.updated =
- local->spy_data.spy_stat[0].updated;
- }
-#endif /* WIRELESS_SPY */
-
- if (pcmcia_dev_present(link)) {
- local->wstats.qual.noise = readb(&p->rxnoise);
- local->wstats.qual.updated |= 4;
- }
-
- return &local->wstats;
-} /* end ray_get_wireless_stats */
-
-/*------------------------------------------------------------------*/
-/*
- * Structures to export the Wireless Handlers
- */
-
-static const iw_handler ray_handler[] = {
- IW_HANDLER(SIOCSIWCOMMIT, ray_commit),
- IW_HANDLER(SIOCGIWNAME, ray_get_name),
- IW_HANDLER(SIOCSIWFREQ, ray_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ray_get_freq),
- IW_HANDLER(SIOCSIWMODE, ray_set_mode),
- IW_HANDLER(SIOCGIWMODE, ray_get_mode),
- IW_HANDLER(SIOCGIWRANGE, ray_get_range),
-#ifdef WIRELESS_SPY
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
-#endif /* WIRELESS_SPY */
- IW_HANDLER(SIOCGIWAP, ray_get_wap),
- IW_HANDLER(SIOCSIWESSID, ray_set_essid),
- IW_HANDLER(SIOCGIWESSID, ray_get_essid),
- IW_HANDLER(SIOCSIWRATE, ray_set_rate),
- IW_HANDLER(SIOCGIWRATE, ray_get_rate),
- IW_HANDLER(SIOCSIWRTS, ray_set_rts),
- IW_HANDLER(SIOCGIWRTS, ray_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ray_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ray_get_frag),
-};
-
-#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */
-#define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1 /* Get framing mode */
-#define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3 /* Get country code */
-
-static const iw_handler ray_private_handler[] = {
- [0] = ray_set_framing,
- [1] = ray_get_framing,
- [3] = ray_get_country,
-};
-
-static const struct iw_priv_args ray_private_args[] = {
-/* cmd, set_args, get_args, name */
- {SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0,
- "set_framing"},
- {SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
- "get_framing"},
- {SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
- "get_country"},
-};
-
-static const struct iw_handler_def ray_handler_def = {
- .num_standard = ARRAY_SIZE(ray_handler),
- .num_private = ARRAY_SIZE(ray_private_handler),
- .num_private_args = ARRAY_SIZE(ray_private_args),
- .standard = ray_handler,
- .private = ray_private_handler,
- .private_args = ray_private_args,
- .get_wireless_stats = ray_get_wireless_stats,
-};
-
-/*===========================================================================*/
-static int ray_open(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link;
- link = local->finder;
-
- dev_dbg(&link->dev, "ray_open('%s')\n", dev->name);
-
- if (link->open == 0)
- local->num_multi = 0;
- link->open++;
-
- /* If the card is not started, time to start it ! - Jean II */
- if (local->card_status == CARD_AWAITING_PARAM) {
- int i;
-
- dev_dbg(&link->dev, "ray_open: doing init now !\n");
-
- /* Download startup parameters */
- if ((i = dl_startup_params(dev)) < 0) {
- printk(KERN_INFO
- "ray_dev_init dl_startup_params failed - "
- "returns 0x%x\n", i);
- return -1;
- }
- }
-
- if (sniffer)
- netif_stop_queue(dev);
- else
- netif_start_queue(dev);
-
- dev_dbg(&link->dev, "ray_open ending\n");
- return 0;
-} /* end ray_open */
-
-/*===========================================================================*/
-static int ray_dev_close(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link;
- link = local->finder;
-
- dev_dbg(&link->dev, "ray_dev_close('%s')\n", dev->name);
-
- link->open--;
- netif_stop_queue(dev);
-
- /* In here, we should stop the hardware (stop card from beeing active)
- * and set local->card_status to CARD_AWAITING_PARAM, so that while the
- * card is closed we can chage its configuration.
- * Probably also need a COR reset to get sane state - Jean II */
-
- return 0;
-} /* end ray_dev_close */
-
-/*===========================================================================*/
-static void ray_reset(struct net_device *dev)
-{
- pr_debug("ray_reset entered\n");
-}
-
-/*===========================================================================*/
-/* Cause a firmware interrupt if it is ready for one */
-/* Return nonzero if not ready */
-static int interrupt_ecf(ray_dev_t *local, int ccs)
-{
- int i = 50;
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs interrupt_ecf - device not present\n");
- return -1;
- }
- dev_dbg(&link->dev, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs);
-
- while (i &&
- (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) &
- ECF_INTR_SET))
- i--;
- if (i == 0) {
- dev_dbg(&link->dev, "ray_cs interrupt_ecf card not ready for interrupt\n");
- return -1;
- }
- /* Fill the mailbox, then kick the card */
- writeb(ccs, local->sram + SCB_BASE);
- writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
- return 0;
-} /* interrupt_ecf */
-
-/*===========================================================================*/
-/* Get next free transmit CCS */
-/* Return - index of current tx ccs */
-static int get_free_tx_ccs(ray_dev_t *local)
-{
- int i;
- struct ccs __iomem *pccs = ccs_base(local);
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs get_free_tx_ccs - device not present\n");
- return ECARDGONE;
- }
-
- if (test_and_set_bit(0, &local->tx_ccs_lock)) {
- dev_dbg(&link->dev, "ray_cs tx_ccs_lock busy\n");
- return ECCSBUSY;
- }
-
- for (i = 0; i < NUMBER_OF_TX_CCS; i++) {
- if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
- writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
- writeb(CCS_END_LIST, &(pccs + i)->link);
- local->tx_ccs_lock = 0;
- return i;
- }
- }
- local->tx_ccs_lock = 0;
- dev_dbg(&link->dev, "ray_cs ERROR no free tx CCS for raylink card\n");
- return ECCSFULL;
-} /* get_free_tx_ccs */
-
-/*===========================================================================*/
-/* Get next free CCS */
-/* Return - index of current ccs */
-static int get_free_ccs(ray_dev_t *local)
-{
- int i;
- struct ccs __iomem *pccs = ccs_base(local);
- struct pcmcia_device *link = local->finder;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs get_free_ccs - device not present\n");
- return ECARDGONE;
- }
- if (test_and_set_bit(0, &local->ccs_lock)) {
- dev_dbg(&link->dev, "ray_cs ccs_lock busy\n");
- return ECCSBUSY;
- }
-
- for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
- if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
- writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
- writeb(CCS_END_LIST, &(pccs + i)->link);
- local->ccs_lock = 0;
- return i;
- }
- }
- local->ccs_lock = 0;
- dev_dbg(&link->dev, "ray_cs ERROR no free CCS for raylink card\n");
- return ECCSFULL;
-} /* get_free_ccs */
-
-/*===========================================================================*/
-static void authenticate_timeout(struct timer_list *t)
-{
- ray_dev_t *local = from_timer(local, t, timer);
- del_timer(&local->timer);
- printk(KERN_INFO "ray_cs Authentication with access point failed"
- " - timeout\n");
- join_net(&local->timer);
-}
-
-/*===========================================================================*/
-static int parse_addr(char *in_str, UCHAR *out)
-{
- int i, k;
- int len;
-
- if (in_str == NULL)
- return 0;
- len = strnlen(in_str, ADDRLEN * 2 + 1) - 1;
- if (len < 1)
- return 0;
- memset(out, 0, ADDRLEN);
-
- i = 5;
-
- while (len > 0) {
- if ((k = hex_to_bin(in_str[len--])) != -1)
- out[i] = k;
- else
- return 0;
-
- if (len == 0)
- break;
- if ((k = hex_to_bin(in_str[len--])) != -1)
- out[i] += k << 4;
- else
- return 0;
- if (!i--)
- break;
- }
- return 1;
-}
-
-/*===========================================================================*/
-static struct net_device_stats *ray_get_stats(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- struct status __iomem *p = local->sram + STATUS_BASE;
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs net_device_stats - device not present\n");
- return &local->stats;
- }
- if (readb(&p->mrx_overflow_for_host)) {
- local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow));
- writeb(0, &p->mrx_overflow);
- writeb(0, &p->mrx_overflow_for_host);
- }
- if (readb(&p->mrx_checksum_error_for_host)) {
- local->stats.rx_crc_errors +=
- swab16(readw(&p->mrx_checksum_error));
- writeb(0, &p->mrx_checksum_error);
- writeb(0, &p->mrx_checksum_error_for_host);
- }
- if (readb(&p->rx_hec_error_for_host)) {
- local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error));
- writeb(0, &p->rx_hec_error);
- writeb(0, &p->rx_hec_error_for_host);
- }
- return &local->stats;
-}
-
-/*===========================================================================*/
-static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value,
- int len)
-{
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- int ccsindex;
- int i;
- struct ccs __iomem *pccs;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_update_parm - device not present\n");
- return;
- }
-
- if ((ccsindex = get_free_ccs(local)) < 0) {
- dev_dbg(&link->dev, "ray_update_parm - No free ccs\n");
- return;
- }
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_UPDATE_PARAMS, &pccs->cmd);
- writeb(objid, &pccs->var.update_param.object_id);
- writeb(1, &pccs->var.update_param.number_objects);
- writeb(0, &pccs->var.update_param.failure_cause);
- for (i = 0; i < len; i++) {
- writeb(value[i], local->sram + HOST_TO_ECF_BASE);
- }
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- }
-}
-
-/*===========================================================================*/
-static void ray_update_multi_list(struct net_device *dev, int all)
-{
- int ccsindex;
- struct ccs __iomem *pccs;
- ray_dev_t *local = netdev_priv(dev);
- struct pcmcia_device *link = local->finder;
- void __iomem *p = local->sram + HOST_TO_ECF_BASE;
-
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_update_multi_list - device not present\n");
- return;
- } else
- dev_dbg(&link->dev, "ray_update_multi_list(%p)\n", dev);
- if ((ccsindex = get_free_ccs(local)) < 0) {
- dev_dbg(&link->dev, "ray_update_multi - No free ccs\n");
- return;
- }
- pccs = ccs_base(local) + ccsindex;
- writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd);
-
- if (all) {
- writeb(0xff, &pccs->var);
- local->num_multi = 0xff;
- } else {
- struct netdev_hw_addr *ha;
- int i = 0;
-
- /* Copy the kernel's list of MC addresses to card */
- netdev_for_each_mc_addr(ha, dev) {
- memcpy_toio(p, ha->addr, ETH_ALEN);
- dev_dbg(&link->dev, "ray_update_multi add addr %pm\n",
- ha->addr);
- p += ETH_ALEN;
- i++;
- }
- if (i > 256 / ADDRLEN)
- i = 256 / ADDRLEN;
- writeb((UCHAR) i, &pccs->var);
- dev_dbg(&link->dev, "ray_cs update_multi %d addresses in list\n", i);
- /* Interrupt the firmware to process the command */
- local->num_multi = i;
- }
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev,
- "ray_cs update_multi failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- }
-} /* end ray_update_multi_list */
-
-/*===========================================================================*/
-static void set_multicast_list(struct net_device *dev)
-{
- ray_dev_t *local = netdev_priv(dev);
- UCHAR promisc;
-
- pr_debug("ray_cs set_multicast_list(%p)\n", dev);
-
- if (dev->flags & IFF_PROMISC) {
- if (local->sparm.b5.a_promiscuous_mode == 0) {
- pr_debug("ray_cs set_multicast_list promisc on\n");
- local->sparm.b5.a_promiscuous_mode = 1;
- promisc = 1;
- ray_update_parm(dev, OBJID_promiscuous_mode,
- &promisc, sizeof(promisc));
- }
- } else {
- if (local->sparm.b5.a_promiscuous_mode == 1) {
- pr_debug("ray_cs set_multicast_list promisc off\n");
- local->sparm.b5.a_promiscuous_mode = 0;
- promisc = 0;
- ray_update_parm(dev, OBJID_promiscuous_mode,
- &promisc, sizeof(promisc));
- }
- }
-
- if (dev->flags & IFF_ALLMULTI)
- ray_update_multi_list(dev, 1);
- else {
- if (local->num_multi != netdev_mc_count(dev))
- ray_update_multi_list(dev, 0);
- }
-} /* end set_multicast_list */
-
-/*=============================================================================
- * All routines below here are run at interrupt time.
-=============================================================================*/
-static irqreturn_t ray_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct pcmcia_device *link;
- ray_dev_t *local;
- struct ccs __iomem *pccs;
- struct rcs __iomem *prcs;
- UCHAR rcsindex;
- UCHAR tmp;
- UCHAR cmd;
- UCHAR status;
- UCHAR memtmp[ESSID_SIZE + 1];
-
-
- if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */
- return IRQ_NONE;
-
- pr_debug("ray_cs: interrupt for *dev=%p\n", dev);
-
- local = netdev_priv(dev);
- link = local->finder;
- if (!pcmcia_dev_present(link)) {
- pr_debug(
- "ray_cs interrupt from device not present or suspended.\n");
- return IRQ_NONE;
- }
- rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index);
-
- if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
- dev_dbg(&link->dev, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex);
- clear_interrupt(local);
- return IRQ_HANDLED;
- }
- if (rcsindex < NUMBER_OF_CCS) { /* If it's a returned CCS */
- pccs = ccs_base(local) + rcsindex;
- cmd = readb(&pccs->cmd);
- status = readb(&pccs->buffer_status);
- switch (cmd) {
- case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */
- del_timer(&local->timer);
- if (status == CCS_COMMAND_COMPLETE) {
- dev_dbg(&link->dev,
- "ray_cs interrupt download_startup_parameters OK\n");
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt download_startup_parameters fail\n");
- }
- break;
- case CCS_UPDATE_PARAMS:
- dev_dbg(&link->dev, "ray_cs interrupt update params done\n");
- if (status != CCS_COMMAND_COMPLETE) {
- tmp =
- readb(&pccs->var.update_param.
- failure_cause);
- dev_dbg(&link->dev,
- "ray_cs interrupt update params failed - reason %d\n",
- tmp);
- }
- break;
- case CCS_REPORT_PARAMS:
- dev_dbg(&link->dev, "ray_cs interrupt report params done\n");
- break;
- case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */
- dev_dbg(&link->dev,
- "ray_cs interrupt CCS Update Multicast List done\n");
- break;
- case CCS_UPDATE_POWER_SAVINGS_MODE:
- dev_dbg(&link->dev,
- "ray_cs interrupt update power save mode done\n");
- break;
- case CCS_START_NETWORK:
- case CCS_JOIN_NETWORK:
- memcpy(memtmp, local->sparm.b4.a_current_ess_id,
- ESSID_SIZE);
- memtmp[ESSID_SIZE] = '\0';
-
- if (status == CCS_COMMAND_COMPLETE) {
- if (readb
- (&pccs->var.start_network.net_initiated) ==
- 1) {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" started\n",
- memtmp);
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" joined\n",
- memtmp);
- }
- memcpy_fromio(&local->bss_id,
- pccs->var.start_network.bssid,
- ADDRLEN);
-
- if (local->fw_ver == 0x55)
- local->net_default_tx_rate = 3;
- else
- local->net_default_tx_rate =
- readb(&pccs->var.start_network.
- net_default_tx_rate);
- local->encryption =
- readb(&pccs->var.start_network.encryption);
- if (!sniffer && (local->net_type == INFRA)
- && !(local->sparm.b4.a_acting_as_ap_status)) {
- authenticate(local);
- }
- local->card_status = CARD_ACQ_COMPLETE;
- } else {
- local->card_status = CARD_ACQ_FAILED;
-
- del_timer(&local->timer);
- local->timer.expires = jiffies + HZ * 5;
- if (status == CCS_START_NETWORK) {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" start failed\n",
- memtmp);
- local->timer.function = start_net;
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt network \"%s\" join failed\n",
- memtmp);
- local->timer.function = join_net;
- }
- add_timer(&local->timer);
- }
- break;
- case CCS_START_ASSOCIATION:
- if (status == CCS_COMMAND_COMPLETE) {
- local->card_status = CARD_ASSOC_COMPLETE;
- dev_dbg(&link->dev, "ray_cs association successful\n");
- } else {
- dev_dbg(&link->dev, "ray_cs association failed,\n");
- local->card_status = CARD_ASSOC_FAILED;
- join_net(&local->timer);
- }
- break;
- case CCS_TX_REQUEST:
- if (status == CCS_COMMAND_COMPLETE) {
- dev_dbg(&link->dev,
- "ray_cs interrupt tx request complete\n");
- } else {
- dev_dbg(&link->dev,
- "ray_cs interrupt tx request failed\n");
- }
- if (!sniffer)
- netif_start_queue(dev);
- netif_wake_queue(dev);
- break;
- case CCS_TEST_MEMORY:
- dev_dbg(&link->dev, "ray_cs interrupt mem test done\n");
- break;
- case CCS_SHUTDOWN:
- dev_dbg(&link->dev,
- "ray_cs interrupt Unexpected CCS returned - Shutdown\n");
- break;
- case CCS_DUMP_MEMORY:
- dev_dbg(&link->dev, "ray_cs interrupt dump memory done\n");
- break;
- case CCS_START_TIMER:
- dev_dbg(&link->dev,
- "ray_cs interrupt DING - raylink timer expired\n");
- break;
- default:
- dev_dbg(&link->dev,
- "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",
- rcsindex, cmd);
- }
- writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
- } else { /* It's an RCS */
-
- prcs = rcs_base(local) + rcsindex;
-
- switch (readb(&prcs->interrupt_id)) {
- case PROCESS_RX_PACKET:
- ray_rx(dev, local, prcs);
- break;
- case REJOIN_NET_COMPLETE:
- dev_dbg(&link->dev, "ray_cs interrupt rejoin net complete\n");
- local->card_status = CARD_ACQ_COMPLETE;
- /* do we need to clear tx buffers CCS's? */
- if (local->sparm.b4.a_network_type == ADHOC) {
- if (!sniffer)
- netif_start_queue(dev);
- } else {
- memcpy_fromio(&local->bss_id,
- prcs->var.rejoin_net_complete.
- bssid, ADDRLEN);
- dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n",
- local->bss_id);
- if (!sniffer)
- authenticate(local);
- }
- break;
- case ROAMING_INITIATED:
- dev_dbg(&link->dev, "ray_cs interrupt roaming initiated\n");
- netif_stop_queue(dev);
- local->card_status = CARD_DOING_ACQ;
- break;
- case JAPAN_CALL_SIGN_RXD:
- dev_dbg(&link->dev, "ray_cs interrupt japan call sign rx\n");
- break;
- default:
- dev_dbg(&link->dev,
- "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",
- rcsindex,
- (unsigned int)readb(&prcs->interrupt_id));
- break;
- }
- writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
- }
- clear_interrupt(local);
- return IRQ_HANDLED;
-} /* ray_interrupt */
-
-/*===========================================================================*/
-static void ray_rx(struct net_device *dev, ray_dev_t *local,
- struct rcs __iomem *prcs)
-{
- int rx_len;
- unsigned int pkt_addr;
- void __iomem *pmsg;
- pr_debug("ray_rx process rx packet\n");
-
- /* Calculate address of packet within Rx buffer */
- pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8)
- + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END;
- /* Length of first packet fragment */
- rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
- + readb(&prcs->var.rx_packet.rx_data_length[1]);
-
- local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev);
- pmsg = local->rmem + pkt_addr;
- switch (readb(pmsg)) {
- case DATA_TYPE:
- pr_debug("ray_rx data type\n");
- rx_data(dev, prcs, pkt_addr, rx_len);
- break;
- case AUTHENTIC_TYPE:
- pr_debug("ray_rx authentic type\n");
- if (sniffer)
- rx_data(dev, prcs, pkt_addr, rx_len);
- else
- rx_authenticate(local, prcs, pkt_addr, rx_len);
- break;
- case DEAUTHENTIC_TYPE:
- pr_debug("ray_rx deauth type\n");
- if (sniffer)
- rx_data(dev, prcs, pkt_addr, rx_len);
- else
- rx_deauthenticate(local, prcs, pkt_addr, rx_len);
- break;
- case NULL_MSG_TYPE:
- pr_debug("ray_cs rx NULL msg\n");
- break;
- case BEACON_TYPE:
- pr_debug("ray_rx beacon type\n");
- if (sniffer)
- rx_data(dev, prcs, pkt_addr, rx_len);
-
- copy_from_rx_buff(local, (UCHAR *) &local->last_bcn, pkt_addr,
- rx_len < sizeof(struct beacon_rx) ?
- rx_len : sizeof(struct beacon_rx));
-
- local->beacon_rxed = 1;
- /* Get the statistics so the card counters never overflow */
- ray_get_stats(dev);
- break;
- default:
- pr_debug("ray_cs unknown pkt type %2x\n",
- (unsigned int)readb(pmsg));
- break;
- }
-
-} /* end ray_rx */
-
-/*===========================================================================*/
-static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len)
-{
- struct sk_buff *skb = NULL;
- struct rcs __iomem *prcslink = prcs;
- ray_dev_t *local = netdev_priv(dev);
- UCHAR *rx_ptr;
- int total_len;
- int tmp;
-#ifdef WIRELESS_SPY
- int siglev = local->last_rsl;
- u_char linksrcaddr[ETH_ALEN]; /* Other end of the wireless link */
-#endif
-
- if (!sniffer) {
- if (translate) {
-/* TBD length needs fixing for translated header */
- if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
- rx_len >
- (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
- FCS_LEN)) {
- pr_debug(
- "ray_cs invalid packet length %d received\n",
- rx_len);
- return;
- }
- } else { /* encapsulated ethernet */
-
- if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
- rx_len >
- (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
- FCS_LEN)) {
- pr_debug(
- "ray_cs invalid packet length %d received\n",
- rx_len);
- return;
- }
- }
- }
- pr_debug("ray_cs rx_data packet\n");
- /* If fragmented packet, verify sizes of fragments add up */
- if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
- pr_debug("ray_cs rx'ed fragment\n");
- tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
- + readb(&prcs->var.rx_packet.totalpacketlength[1]);
- total_len = tmp;
- prcslink = prcs;
- do {
- tmp -=
- (readb(&prcslink->var.rx_packet.rx_data_length[0])
- << 8)
- + readb(&prcslink->var.rx_packet.rx_data_length[1]);
- if (readb(&prcslink->var.rx_packet.next_frag_rcs_index)
- == 0xFF || tmp < 0)
- break;
- prcslink = rcs_base(local)
- + readb(&prcslink->link_field);
- } while (1);
-
- if (tmp < 0) {
- pr_debug(
- "ray_cs rx_data fragment lengths don't add up\n");
- local->stats.rx_dropped++;
- release_frag_chain(local, prcs);
- return;
- }
- } else { /* Single unfragmented packet */
- total_len = rx_len;
- }
-
- skb = dev_alloc_skb(total_len + 5);
- if (skb == NULL) {
- pr_debug("ray_cs rx_data could not allocate skb\n");
- local->stats.rx_dropped++;
- if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF)
- release_frag_chain(local, prcs);
- return;
- }
- skb_reserve(skb, 2); /* Align IP on 16 byte (TBD check this) */
-
- pr_debug("ray_cs rx_data total_len = %x, rx_len = %x\n", total_len,
- rx_len);
-
-/************************/
- /* Reserve enough room for the whole damn packet. */
- rx_ptr = skb_put(skb, total_len);
- /* Copy the whole packet to sk_buff */
- rx_ptr +=
- copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
- /* Get source address */
-#ifdef WIRELESS_SPY
- skb_copy_from_linear_data_offset(skb,
- offsetof(struct mac_header, addr_2),
- linksrcaddr, ETH_ALEN);
-#endif
- /* Now, deal with encapsulation/translation/sniffer */
- if (!sniffer) {
- if (!translate) {
- /* Encapsulated ethernet, so just lop off 802.11 MAC header */
-/* TBD reserve skb_reserve( skb, RX_MAC_HEADER_LENGTH); */
- skb_pull(skb, RX_MAC_HEADER_LENGTH);
- } else {
- /* Do translation */
- untranslate(local, skb, total_len);
- }
- } else { /* sniffer mode, so just pass whole packet */
- }
-
-/************************/
- /* Now pick up the rest of the fragments if any */
- tmp = 17;
- if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
- prcslink = prcs;
- pr_debug("ray_cs rx_data in fragment loop\n");
- do {
- prcslink = rcs_base(local)
- +
- readb(&prcslink->var.rx_packet.next_frag_rcs_index);
- rx_len =
- ((readb(&prcslink->var.rx_packet.rx_data_length[0])
- << 8)
- +
- readb(&prcslink->var.rx_packet.rx_data_length[1]))
- & RX_BUFF_END;
- pkt_addr =
- ((readb(&prcslink->var.rx_packet.rx_data_ptr[0]) <<
- 8)
- + readb(&prcslink->var.rx_packet.rx_data_ptr[1]))
- & RX_BUFF_END;
-
- rx_ptr +=
- copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len);
-
- } while (tmp-- &&
- readb(&prcslink->var.rx_packet.next_frag_rcs_index) !=
- 0xFF);
- release_frag_chain(local, prcs);
- }
-
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- local->stats.rx_packets++;
- local->stats.rx_bytes += total_len;
-
- /* Gather signal strength per address */
-#ifdef WIRELESS_SPY
- /* For the Access Point or the node having started the ad-hoc net
- * note : ad-hoc work only in some specific configurations, but we
- * kludge in ray_get_wireless_stats... */
- if (!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) {
- /* Update statistics */
- /*local->wstats.qual.qual = none ? */
- local->wstats.qual.level = siglev;
- /*local->wstats.qual.noise = none ? */
- local->wstats.qual.updated = 0x2;
- }
- /* Now, update the spy stuff */
- {
- struct iw_quality wstats;
- wstats.level = siglev;
- /* wstats.noise = none ? */
- /* wstats.qual = none ? */
- wstats.updated = 0x2;
- /* Update spy records */
- wireless_spy_update(dev, linksrcaddr, &wstats);
- }
-#endif /* WIRELESS_SPY */
-} /* end rx_data */
-
-/*===========================================================================*/
-static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
-{
- snaphdr_t *psnap = (snaphdr_t *) (skb->data + RX_MAC_HEADER_LENGTH);
- struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data;
- __be16 type = *(__be16 *) psnap->ethertype;
- int delta;
- struct ethhdr *peth;
- UCHAR srcaddr[ADDRLEN];
- UCHAR destaddr[ADDRLEN];
- static const UCHAR org_bridge[3] = { 0, 0, 0xf8 };
- static const UCHAR org_1042[3] = { 0, 0, 0 };
-
- memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
- memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
-
-#if 0
- if {
- print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ",
- DUMP_PREFIX_NONE, 16, 1,
- skb->data, 64, true);
- printk(KERN_DEBUG
- "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
- ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl,
- psnap->org[0], psnap->org[1], psnap->org[2]);
- printk(KERN_DEBUG "untranslate skb->data = %p\n", skb->data);
- }
-#endif
-
- if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) {
- /* not a snap type so leave it alone */
- pr_debug("ray_cs untranslate NOT SNAP %02x %02x %02x\n",
- psnap->dsap, psnap->ssap, psnap->ctrl);
-
- delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
- } else { /* Its a SNAP */
- if (memcmp(psnap->org, org_bridge, 3) == 0) {
- /* EtherII and nuke the LLC */
- pr_debug("ray_cs untranslate Bridge encap\n");
- delta = RX_MAC_HEADER_LENGTH
- + sizeof(struct snaphdr_t) - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = type;
- } else if (memcmp(psnap->org, org_1042, 3) == 0) {
- switch (ntohs(type)) {
- case ETH_P_IPX:
- case ETH_P_AARP:
- pr_debug("ray_cs untranslate RFC IPX/AARP\n");
- delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto =
- htons(len - RX_MAC_HEADER_LENGTH);
- break;
- default:
- pr_debug("ray_cs untranslate RFC default\n");
- delta = RX_MAC_HEADER_LENGTH +
- sizeof(struct snaphdr_t) - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = type;
- break;
- }
- } else {
- printk("ray_cs untranslate very confused by packet\n");
- delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
- peth = (struct ethhdr *)(skb->data + delta);
- peth->h_proto = type;
- }
- }
-/* TBD reserve skb_reserve(skb, delta); */
- skb_pull(skb, delta);
- pr_debug("untranslate after skb_pull(%d), skb->data = %p\n", delta,
- skb->data);
- memcpy(peth->h_dest, destaddr, ADDRLEN);
- memcpy(peth->h_source, srcaddr, ADDRLEN);
-#if 0
- {
- int i;
- printk(KERN_DEBUG "skb->data after untranslate:");
- for (i = 0; i < 64; i++)
- printk("%02x ", skb->data[i]);
- printk("\n");
- }
-#endif
-} /* end untranslate */
-
-/*===========================================================================*/
-/* Copy data from circular receive buffer to PC memory.
- * dest = destination address in PC memory
- * pkt_addr = source address in receive buffer
- * len = length of packet to copy
- */
-static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr,
- int length)
-{
- int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
- if (wrap_bytes <= 0) {
- memcpy_fromio(dest, local->rmem + pkt_addr, length);
- } else { /* Packet wrapped in circular buffer */
-
- memcpy_fromio(dest, local->rmem + pkt_addr,
- length - wrap_bytes);
- memcpy_fromio(dest + length - wrap_bytes, local->rmem,
- wrap_bytes);
- }
- return length;
-}
-
-/*===========================================================================*/
-static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs)
-{
- struct rcs __iomem *prcslink = prcs;
- int tmp = 17;
- unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index);
-
- while (tmp--) {
- writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
- if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
- pr_debug("ray_cs interrupt bad rcsindex = 0x%x\n",
- rcsindex);
- break;
- }
- prcslink = rcs_base(local) + rcsindex;
- rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index);
- }
- writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
-}
-
-/*===========================================================================*/
-static void authenticate(ray_dev_t *local)
-{
- struct pcmcia_device *link = local->finder;
- dev_dbg(&link->dev, "ray_cs Starting authentication.\n");
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs authenticate - device not present\n");
- return;
- }
-
- del_timer(&local->timer);
- if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
- local->timer.function = join_net;
- } else {
- local->timer.function = authenticate_timeout;
- }
- local->timer.expires = jiffies + HZ * 2;
- add_timer(&local->timer);
- local->authentication_state = AWAITING_RESPONSE;
-} /* end authenticate */
-
-/*===========================================================================*/
-static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len)
-{
- UCHAR buff[256];
- struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
-
- del_timer(&local->timer);
-
- copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
- /* if we are trying to get authenticated */
- if (local->sparm.b4.a_network_type == ADHOC) {
- pr_debug("ray_cs rx_auth var= %6ph\n", msg->var);
- if (msg->var[2] == 1) {
- pr_debug("ray_cs Sending authentication response.\n");
- if (!build_auth_frame
- (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
- local->authentication_state = NEED_TO_AUTH;
- memcpy(local->auth_id, msg->mac.addr_2,
- ADDRLEN);
- }
- }
- } else { /* Infrastructure network */
-
- if (local->authentication_state == AWAITING_RESPONSE) {
- /* Verify authentication sequence #2 and success */
- if (msg->var[2] == 2) {
- if ((msg->var[3] | msg->var[4]) == 0) {
- pr_debug("Authentication successful\n");
- local->card_status = CARD_AUTH_COMPLETE;
- associate(local);
- local->authentication_state =
- AUTHENTICATED;
- } else {
- pr_debug("Authentication refused\n");
- local->card_status = CARD_AUTH_REFUSED;
- join_net(&local->timer);
- local->authentication_state =
- UNAUTHENTICATED;
- }
- }
- }
- }
-
-} /* end rx_authenticate */
-
-/*===========================================================================*/
-static void associate(ray_dev_t *local)
-{
- struct ccs __iomem *pccs;
- struct pcmcia_device *link = local->finder;
- struct net_device *dev = link->priv;
- int ccsindex;
- if (!(pcmcia_dev_present(link))) {
- dev_dbg(&link->dev, "ray_cs associate - device not present\n");
- return;
- }
- /* If no tx buffers available, return */
- if ((ccsindex = get_free_ccs(local)) < 0) {
-/* TBD should never be here but... what if we are? */
- dev_dbg(&link->dev, "ray_cs associate - No free ccs\n");
- return;
- }
- dev_dbg(&link->dev, "ray_cs Starting association with access point\n");
- pccs = ccs_base(local) + ccsindex;
- /* fill in the CCS */
- writeb(CCS_START_ASSOCIATION, &pccs->cmd);
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-
- del_timer(&local->timer);
- local->timer.expires = jiffies + HZ * 2;
- local->timer.function = join_net;
- add_timer(&local->timer);
- local->card_status = CARD_ASSOC_FAILED;
- return;
- }
- if (!sniffer)
- netif_start_queue(dev);
-
-} /* end associate */
-
-/*===========================================================================*/
-static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
- unsigned int pkt_addr, int rx_len)
-{
-/* UCHAR buff[256];
- struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
-*/
- pr_debug("Deauthentication frame received\n");
- local->authentication_state = UNAUTHENTICATED;
- /* Need to reauthenticate or rejoin depending on reason code */
-/* copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
- */
-}
-
-/*===========================================================================*/
-static void clear_interrupt(ray_dev_t *local)
-{
- writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
-}
-
-/*===========================================================================*/
-#ifdef CONFIG_PROC_FS
-#define MAXDATA (PAGE_SIZE - 80)
-
-static const char *card_status[] = {
- "Card inserted - uninitialized", /* 0 */
- "Card not downloaded", /* 1 */
- "Waiting for download parameters", /* 2 */
- "Card doing acquisition", /* 3 */
- "Acquisition complete", /* 4 */
- "Authentication complete", /* 5 */
- "Association complete", /* 6 */
- "???", "???", "???", "???", /* 7 8 9 10 undefined */
- "Card init error", /* 11 */
- "Download parameters error", /* 12 */
- "???", /* 13 */
- "Acquisition failed", /* 14 */
- "Authentication refused", /* 15 */
- "Association failed" /* 16 */
-};
-
-static const char *nettype[] = { "Adhoc", "Infra " };
-static const char *framing[] = { "Encapsulation", "Translation" }
-
-;
-/*===========================================================================*/
-static int ray_cs_proc_show(struct seq_file *m, void *v)
-{
-/* Print current values which are not available via other means
- * eg ifconfig
- */
- int i;
- struct pcmcia_device *link;
- struct net_device *dev;
- ray_dev_t *local;
- UCHAR *p;
- struct freq_hop_element *pfh;
- UCHAR c[33];
-
- link = this_device;
- if (!link)
- return 0;
- dev = (struct net_device *)link->priv;
- if (!dev)
- return 0;
- local = netdev_priv(dev);
- if (!local)
- return 0;
-
- seq_puts(m, "Raylink Wireless LAN driver status\n");
- seq_printf(m, "%s\n", rcsid);
- /* build 4 does not report version, and field is 0x55 after memtest */
- seq_puts(m, "Firmware version = ");
- if (local->fw_ver == 0x55)
- seq_puts(m, "4 - Use dump_cis for more details\n");
- else
- seq_printf(m, "%2d.%02d.%02d\n",
- local->fw_ver, local->fw_bld, local->fw_var);
-
- for (i = 0; i < 32; i++)
- c[i] = local->sparm.b5.a_current_ess_id[i];
- c[32] = 0;
- seq_printf(m, "%s network ESSID = \"%s\"\n",
- nettype[local->sparm.b5.a_network_type], c);
-
- p = local->bss_id;
- seq_printf(m, "BSSID = %pM\n", p);
-
- seq_printf(m, "Country code = %d\n",
- local->sparm.b5.a_curr_country_code);
-
- i = local->card_status;
- if (i < 0)
- i = 10;
- if (i > 16)
- i = 10;
- seq_printf(m, "Card status = %s\n", card_status[i]);
-
- seq_printf(m, "Framing mode = %s\n", framing[translate]);
-
- seq_printf(m, "Last pkt signal lvl = %d\n", local->last_rsl);
-
- if (local->beacon_rxed) {
- /* Pull some fields out of last beacon received */
- seq_printf(m, "Beacon Interval = %d Kus\n",
- local->last_bcn.beacon_intvl[0]
- + 256 * local->last_bcn.beacon_intvl[1]);
-
- p = local->last_bcn.elements;
- if (p[0] == C_ESSID_ELEMENT_ID)
- p += p[1] + 2;
- else {
- seq_printf(m,
- "Parse beacon failed at essid element id = %d\n",
- p[0]);
- return 0;
- }
-
- if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
- seq_puts(m, "Supported rate codes = ");
- for (i = 2; i < p[1] + 2; i++)
- seq_printf(m, "0x%02x ", p[i]);
- seq_putc(m, '\n');
- p += p[1] + 2;
- } else {
- seq_puts(m, "Parse beacon failed at rates element\n");
- return 0;
- }
-
- if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
- pfh = (struct freq_hop_element *)p;
- seq_printf(m, "Hop dwell = %d Kus\n",
- pfh->dwell_time[0] +
- 256 * pfh->dwell_time[1]);
- seq_printf(m, "Hop set = %d\n",
- pfh->hop_set);
- seq_printf(m, "Hop pattern = %d\n",
- pfh->hop_pattern);
- seq_printf(m, "Hop index = %d\n",
- pfh->hop_index);
- p += p[1] + 2;
- } else {
- seq_puts(m,
- "Parse beacon failed at FH param element\n");
- return 0;
- }
- } else {
- seq_puts(m, "No beacons received\n");
- }
- return 0;
-}
-#endif
-/*===========================================================================*/
-static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
-{
- int addr;
- struct ccs __iomem *pccs;
- struct tx_msg __iomem *ptx;
- int ccsindex;
-
- /* If no tx buffers available, return */
- if ((ccsindex = get_free_tx_ccs(local)) < 0) {
- pr_debug("ray_cs send authenticate - No free tx ccs\n");
- return -1;
- }
-
- pccs = ccs_base(local) + ccsindex;
-
- /* Address in card space */
- addr = TX_BUF_BASE + (ccsindex << 11);
- /* fill in the CCS */
- writeb(CCS_TX_REQUEST, &pccs->cmd);
- writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr);
- writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1);
- writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length);
- writeb(TX_AUTHENTICATE_LENGTH_LSB,
- pccs->var.tx_request.tx_data_length + 1);
- writeb(0, &pccs->var.tx_request.pow_sav_mode);
-
- ptx = local->sram + addr;
- /* fill in the mac header */
- writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1);
- writeb(0, &ptx->mac.frame_ctl_2);
-
- memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN);
- memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN);
- memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
-
- /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */
- memset_io(ptx->var, 0, 6);
- writeb(auth_type & 0xff, ptx->var + 2);
-
- /* Interrupt the firmware to process the command */
- if (interrupt_ecf(local, ccsindex)) {
- pr_debug(
- "ray_cs send authentication request failed - ECF not ready for intr\n");
- writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
- return -1;
- }
- return 0;
-} /* End build_auth_frame */
-
-/*===========================================================================*/
-#ifdef CONFIG_PROC_FS
-static ssize_t ray_cs_essid_proc_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *pos)
-{
- static char proc_essid[33];
- unsigned int len = count;
-
- if (len > 32)
- len = 32;
- memset(proc_essid, 0, 33);
- if (copy_from_user(proc_essid, buffer, len))
- return -EFAULT;
- essid = proc_essid;
- return count;
-}
-
-static const struct proc_ops ray_cs_essid_proc_ops = {
- .proc_write = ray_cs_essid_proc_write,
- .proc_lseek = noop_llseek,
-};
-
-static ssize_t int_proc_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *pos)
-{
- static char proc_number[10];
- char *p;
- int nr, len;
-
- if (!count)
- return 0;
-
- if (count > 9)
- return -EINVAL;
- if (copy_from_user(proc_number, buffer, count))
- return -EFAULT;
- p = proc_number;
- nr = 0;
- len = count;
- do {
- unsigned int c = *p - '0';
- if (c > 9)
- return -EINVAL;
- nr = nr * 10 + c;
- p++;
- } while (--len);
- *(int *)pde_data(file_inode(file)) = nr;
- return count;
-}
-
-static const struct proc_ops int_proc_ops = {
- .proc_write = int_proc_write,
- .proc_lseek = noop_llseek,
-};
-#endif
-
-static const struct pcmcia_device_id ray_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
- PCMCIA_DEVICE_NULL,
-};
-
-MODULE_DEVICE_TABLE(pcmcia, ray_ids);
-
-static struct pcmcia_driver ray_driver = {
- .owner = THIS_MODULE,
- .name = "ray_cs",
- .probe = ray_probe,
- .remove = ray_detach,
- .id_table = ray_ids,
- .suspend = ray_suspend,
- .resume = ray_resume,
-};
-
-static int __init init_ray_cs(void)
-{
- int rc;
-
- pr_debug("%s\n", rcsid);
- rc = pcmcia_register_driver(&ray_driver);
- pr_debug("raylink init_module register_pcmcia_driver returns 0x%x\n",
- rc);
- if (rc)
- return rc;
-
-#ifdef CONFIG_PROC_FS
- proc_mkdir("driver/ray_cs", NULL);
-
- proc_create_single("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_show);
- proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_ops);
- proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_ops,
- &net_type);
- proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_ops,
- &translate);
-#endif
- translate = !!translate;
- return 0;
-} /* init_ray_cs */
-
-/*===========================================================================*/
-
-static void __exit exit_ray_cs(void)
-{
- pr_debug("ray_cs: cleanup_module\n");
-
-#ifdef CONFIG_PROC_FS
- remove_proc_subtree("driver/ray_cs", NULL);
-#endif
-
- pcmcia_unregister_driver(&ray_driver);
-} /* exit_ray_cs */
-
-module_init(init_ray_cs);
-module_exit(exit_ray_cs);
-
-/*===========================================================================*/
diff --git a/drivers/net/wireless/legacy/ray_cs.h b/drivers/net/wireless/legacy/ray_cs.h
deleted file mode 100644
index 0609d86250192..0000000000000
--- a/drivers/net/wireless/legacy/ray_cs.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* Raytheon wireless LAN PCMCIA card driver for Linux
- A PCMCIA client driver for the Raylink wireless network card
- Written by Corey Thomas
-*/
-
-#ifndef _RAY_CS_H_
-#define _RAY_CS_H_
-
-struct beacon_rx {
- struct mac_header mac;
- UCHAR timestamp[8];
- UCHAR beacon_intvl[2];
- UCHAR capability[2];
- UCHAR elements[sizeof(struct essid_element)
- + sizeof(struct rates_element)
- + sizeof(struct freq_hop_element)
- + sizeof(struct japan_call_sign_element)
- + sizeof(struct tim_element)];
-};
-
-/* Return values for get_free{,_tx}_ccs */
-#define ECCSFULL (-1)
-#define ECCSBUSY (-2)
-#define ECARDGONE (-3)
-
-typedef struct ray_dev_t {
- int card_status;
- int authentication_state;
- void __iomem *sram; /* pointer to beginning of shared RAM */
- void __iomem *amem; /* pointer to attribute mem window */
- void __iomem *rmem; /* pointer to receive buffer window */
- struct pcmcia_device *finder; /* pointer back to struct pcmcia_device for card */
- struct timer_list timer;
- unsigned long tx_ccs_lock;
- unsigned long ccs_lock;
- int dl_param_ccs;
- union {
- struct b4_startup_params b4;
- struct b5_startup_params b5;
- } sparm;
- int timeout_flag;
- UCHAR supported_rates[8];
- UCHAR japan_call_sign[12];
- struct startup_res_6 startup_res;
- int num_multi;
- /* Network parameters from start/join */
- UCHAR bss_id[6];
- UCHAR auth_id[6];
- UCHAR net_default_tx_rate;
- UCHAR encryption;
- struct net_device_stats stats;
-
- UCHAR net_type;
- UCHAR sta_type;
- UCHAR fw_ver;
- UCHAR fw_bld;
- UCHAR fw_var;
- UCHAR ASIC_version;
- UCHAR assoc_id[2];
- UCHAR tib_length;
- UCHAR last_rsl;
- int beacon_rxed;
- struct beacon_rx last_bcn;
- iw_stats wstats; /* Wireless specific stats */
-#ifdef WIRELESS_SPY
- struct iw_spy_data spy_data;
- struct iw_public_data wireless_data;
-#endif /* WIRELESS_SPY */
-
-} ray_dev_t;
-/*****************************************************************************/
-
-#endif /* _RAY_CS_H_ */
diff --git a/drivers/net/wireless/legacy/rayctl.h b/drivers/net/wireless/legacy/rayctl.h
deleted file mode 100644
index 1f3bde8ac73d4..0000000000000
--- a/drivers/net/wireless/legacy/rayctl.h
+++ /dev/null
@@ -1,734 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _RAYCTL_H_
-#define _RAYCTL_H_
-
-typedef unsigned char UCHAR;
-
-/****** IEEE 802.11 constants ************************************************/
-#define ADDRLEN 6
-/* Frame control 1 bit fields */
-#define PROTOCOL_VER 0x00
-#define DATA_TYPE 0x08
-#define ASSOC_REQ_TYPE 0x00
-#define ASSOC_RESP_TYPE 0x10
-#define REASSOC_REQ_TYPE 0x20
-#define REASSOC_RESP_TYPE 0x30
-#define NULL_MSG_TYPE 0x48
-#define BEACON_TYPE 0x80
-#define DISASSOC_TYPE 0xA0
-#define PSPOLL_TYPE 0xA4
-#define AUTHENTIC_TYPE 0xB0
-#define DEAUTHENTIC_TYPE 0xC0
-/* Frame control 2 bit fields */
-#define FC2_TO_DS 0x01
-#define FC2_FROM_DS 0x02
-#define FC2_MORE_FRAG 0x04
-#define FC2_RETRY 0x08
-#define FC2_PSM 0x10
-#define FC2_MORE_DATA 0x20
-#define FC2_WEP 0x40
-#define FC2_ORDER 0x80
-/*****************************************************************************/
-/* 802.11 element ID's and lengths */
-#define C_BP_CAPABILITY_ESS 0x01
-#define C_BP_CAPABILITY_IBSS 0x02
-#define C_BP_CAPABILITY_CF_POLLABLE 0x04
-#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08
-#define C_BP_CAPABILITY_PRIVACY 0x10
-
-#define C_ESSID_ELEMENT_ID 0
-#define C_ESSID_ELEMENT_MAX_LENGTH 32
-
-#define C_SUPPORTED_RATES_ELEMENT_ID 1
-#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2
-
-#define C_FH_PARAM_SET_ELEMENT_ID 2
-#define C_FH_PARAM_SET_ELEMENT_LNGTH 5
-
-#define C_CF_PARAM_SET_ELEMENT_ID 4
-#define C_CF_PARAM_SET_ELEMENT_LNGTH 6
-
-#define C_TIM_ELEMENT_ID 5
-#define C_TIM_BITMAP_LENGTH 251
-#define C_TIM_BMCAST_BIT 0x01
-
-#define C_IBSS_ELEMENT_ID 6
-#define C_IBSS_ELEMENT_LENGTH 2
-
-#define C_JAPAN_CALL_SIGN_ELEMENT_ID 51
-#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12
-
-#define C_DISASSOC_REASON_CODE_LEN 2
-#define C_DISASSOC_REASON_CODE_DEFAULT 8
-
-#define C_CRC_LEN 4
-#define C_NUM_SUPPORTED_RATES 8
-/****** IEEE 802.11 mac header for type data packets *************************/
-struct mac_header {
- UCHAR frame_ctl_1;
- UCHAR frame_ctl_2;
- UCHAR duration_lsb;
- UCHAR duration_msb;
- UCHAR addr_1[ADDRLEN];
- UCHAR addr_2[ADDRLEN];
- UCHAR addr_3[ADDRLEN];
- UCHAR seq_frag_num[2];
-/* UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */
-};
-/****** IEEE 802.11 frame element structures *********************************/
-struct essid_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH];
-};
-struct rates_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR value[8];
-};
-struct freq_hop_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR dwell_time[2];
- UCHAR hop_set;
- UCHAR hop_pattern;
- UCHAR hop_index;
-};
-struct tim_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR dtim_count;
- UCHAR dtim_period;
- UCHAR bitmap_control;
- UCHAR tim[C_TIM_BITMAP_LENGTH];
-};
-struct ibss_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR atim_window[2];
-};
-struct japan_call_sign_element
-{
- UCHAR id;
- UCHAR length;
- UCHAR call_sign[12];
-};
-/****** Beacon message structures ********************************************/
-/* .elements is a large lump of max size because elements are variable size */
-struct infra_beacon
-{
- UCHAR timestamp[8];
- UCHAR beacon_intvl[2];
- UCHAR capability[2];
- UCHAR elements[sizeof(struct essid_element)
- + sizeof(struct rates_element)
- + sizeof(struct freq_hop_element)
- + sizeof(struct japan_call_sign_element)
- + sizeof(struct tim_element)];
-};
-struct adhoc_beacon
-{
- UCHAR timestamp[8];
- UCHAR beacon_intvl[2];
- UCHAR capability[2];
- UCHAR elements[sizeof(struct essid_element)
- + sizeof(struct rates_element)
- + sizeof(struct freq_hop_element)
- + sizeof(struct japan_call_sign_element)
- + sizeof(struct ibss_element)];
-};
-/*****************************************************************************/
-/*****************************************************************************/
-/* #define C_MAC_HDR_2_WEP 0x40 */
-/* TX/RX CCS constants */
-#define TX_HEADER_LENGTH 0x1C
-#define RX_MAC_HEADER_LENGTH 0x18
-#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6)
-#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
-#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
-#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2)
-#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
-#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
-#define FCS_LEN 4
-
-#define ADHOC 0
-#define INFRA 1
-
-#define TYPE_STA 0
-#define TYPE_AP 1
-
-#define PASSIVE_SCAN 1
-#define ACTIVE_SCAN 1
-
-#define PSM_CAM 0
-
-/* Country codes */
-#define USA 1
-#define EUROPE 2
-#define JAPAN 3
-#define KOREA 4
-#define SPAIN 5
-#define FRANCE 6
-#define ISRAEL 7
-#define AUSTRALIA 8
-#define JAPAN_TEST 9
-
-/* Hop pattern lengths */
-#define USA_HOP_MOD 79
-#define EUROPE_HOP_MOD 79
-#define JAPAN_HOP_MOD 23
-#define KOREA_HOP_MOD 23
-#define SPAIN_HOP_MOD 27
-#define FRANCE_HOP_MOD 35
-#define ISRAEL_HOP_MOD 35
-#define AUSTRALIA_HOP_MOD 47
-#define JAPAN_TEST_HOP_MOD 23
-
-#define ESSID_SIZE 32
-/**********************************************************************/
-/* CIS Register Constants */
-#define CIS_OFFSET 0x0f00
-/* Configuration Option Register (0x0F00) */
-#define COR_OFFSET 0x00
-#define COR_SOFT_RESET 0x80
-#define COR_LEVEL_IRQ 0x40
-#define COR_CONFIG_NUM 0x01
-#define COR_DEFAULT (COR_LEVEL_IRQ | COR_CONFIG_NUM)
-
-/* Card Configuration and Status Register (0x0F01) */
-#define CCSR_OFFSET 0x01
-#define CCSR_HOST_INTR_PENDING 0x01
-#define CCSR_POWER_DOWN 0x04
-
-/* HCS Interrupt Register (0x0F05) */
-#define HCS_INTR_OFFSET 0x05
-/* #define HCS_INTR_OFFSET 0x0A */
-#define HCS_INTR_CLEAR 0x00
-
-/* ECF Interrupt Register (0x0F06) */
-#define ECF_INTR_OFFSET 0x06
-/* #define ECF_INTR_OFFSET 0x0C */
-#define ECF_INTR_SET 0x01
-
-/* Authorization Register 0 (0x0F08) */
-#define AUTH_0_ON 0x57
-
-/* Authorization Register 1 (0x0F09) */
-#define AUTH_1_ON 0x82
-
-/* Program Mode Register (0x0F0A) */
-#define PC2PM 0x02
-#define PC2CAL 0x10
-#define PC2MLSE 0x20
-
-/* PC Test Mode Register (0x0F0B) */
-#define PC_TEST_MODE 0x08
-
-/* Frequency Control Word (0x0F10) */
-/* Range 0x02 - 0xA6 */
-
-/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */
-
-/**********************************************************************/
-
-/* Shared RAM Area */
-#define SCB_BASE 0x0000
-#define STATUS_BASE 0x0100
-#define HOST_TO_ECF_BASE 0x0200
-#define ECF_TO_HOST_BASE 0x0300
-#define CCS_BASE 0x0400
-#define RCS_BASE 0x0800
-#define INFRA_TIM_BASE 0x0C00
-#define SSID_LIST_BASE 0x0D00
-#define TX_BUF_BASE 0x1000
-#define RX_BUF_BASE 0x8000
-
-#define NUMBER_OF_CCS 64
-#define NUMBER_OF_RCS 64
-/*#define NUMBER_OF_TX_CCS 14 */
-#define NUMBER_OF_TX_CCS 14
-
-#define TX_BUF_SIZE (2048 - sizeof(struct tx_msg))
-#define RX_BUFF_END 0x3FFF
-/* Values for buffer_status */
-#define CCS_BUFFER_FREE 0
-#define CCS_BUFFER_BUSY 1
-#define CCS_COMMAND_COMPLETE 2
-#define CCS_COMMAND_FAILED 3
-
-/* Values for cmd */
-#define CCS_DOWNLOAD_STARTUP_PARAMS 1
-#define CCS_UPDATE_PARAMS 2
-#define CCS_REPORT_PARAMS 3
-#define CCS_UPDATE_MULTICAST_LIST 4
-#define CCS_UPDATE_POWER_SAVINGS_MODE 5
-#define CCS_START_NETWORK 6
-#define CCS_JOIN_NETWORK 7
-#define CCS_START_ASSOCIATION 8
-#define CCS_TX_REQUEST 9
-#define CCS_TEST_MEMORY 0xa
-#define CCS_SHUTDOWN 0xb
-#define CCS_DUMP_MEMORY 0xc
-#define CCS_START_TIMER 0xe
-#define CCS_LAST_CMD CCS_START_TIMER
-
-/* Values for link field */
-#define CCS_END_LIST 0xff
-
-/* values for buffer_status field */
-#define RCS_BUFFER_FREE 0
-#define RCS_BUFFER_BUSY 1
-#define RCS_COMPLETE 2
-#define RCS_FAILED 3
-#define RCS_BUFFER_RELEASE 0xFF
-
-/* values for interrupt_id field */
-#define PROCESS_RX_PACKET 0x80 /* */
-#define REJOIN_NET_COMPLETE 0x81 /* RCS ID: Rejoin Net Complete */
-#define ROAMING_INITIATED 0x82 /* RCS ID: Roaming Initiated */
-#define JAPAN_CALL_SIGN_RXD 0x83 /* RCS ID: New Japan Call Sign */
-
-/*****************************************************************************/
-/* Memory types for dump memory command */
-#define C_MEM_PROG 0
-#define C_MEM_XDATA 1
-#define C_MEM_SFR 2
-#define C_MEM_IDATA 3
-
-/*** Return values for hw_xmit **********/
-#define XMIT_OK (0)
-#define XMIT_MSG_BAD (-1)
-#define XMIT_NO_CCS (-2)
-#define XMIT_NO_INTR (-3)
-#define XMIT_NEED_AUTH (-4)
-
-/*** Values for card status */
-#define CARD_INSERTED (0)
-
-#define CARD_AWAITING_PARAM (1)
-#define CARD_INIT_ERROR (11)
-
-#define CARD_DL_PARAM (2)
-#define CARD_DL_PARAM_ERROR (12)
-
-#define CARD_DOING_ACQ (3)
-
-#define CARD_ACQ_COMPLETE (4)
-#define CARD_ACQ_FAILED (14)
-
-#define CARD_AUTH_COMPLETE (5)
-#define CARD_AUTH_REFUSED (15)
-
-#define CARD_ASSOC_COMPLETE (6)
-#define CARD_ASSOC_FAILED (16)
-
-/*** Values for authentication_state ***********************************/
-#define UNAUTHENTICATED (0)
-#define AWAITING_RESPONSE (1)
-#define AUTHENTICATED (2)
-#define NEED_TO_AUTH (3)
-
-/*** Values for authentication type ************************************/
-#define OPEN_AUTH_REQUEST (1)
-#define OPEN_AUTH_RESPONSE (2)
-#define BROADCAST_DEAUTH (0xc0)
-/*** Values for timer functions ****************************************/
-#define TODO_NOTHING (0)
-#define TODO_VERIFY_DL_START (-1)
-#define TODO_START_NET (-2)
-#define TODO_JOIN_NET (-3)
-#define TODO_AUTHENTICATE_TIMEOUT (-4)
-#define TODO_SEND_CCS (-5)
-/***********************************************************************/
-/* Parameter passing structure for update/report parameter CCS's */
-struct object_id {
- void *object_addr;
- unsigned char object_length;
-};
-
-#define OBJID_network_type 0
-#define OBJID_acting_as_ap_status 1
-#define OBJID_current_ess_id 2
-#define OBJID_scanning_mode 3
-#define OBJID_power_mgt_state 4
-#define OBJID_mac_address 5
-#define OBJID_frag_threshold 6
-#define OBJID_hop_time 7
-#define OBJID_beacon_period 8
-#define OBJID_dtim_period 9
-#define OBJID_retry_max 10
-#define OBJID_ack_timeout 11
-#define OBJID_sifs 12
-#define OBJID_difs 13
-#define OBJID_pifs 14
-#define OBJID_rts_threshold 15
-#define OBJID_scan_dwell_time 16
-#define OBJID_max_scan_dwell_time 17
-#define OBJID_assoc_resp_timeout 18
-#define OBJID_adhoc_scan_cycle_max 19
-#define OBJID_infra_scan_cycle_max 20
-#define OBJID_infra_super_cycle_max 21
-#define OBJID_promiscuous_mode 22
-#define OBJID_unique_word 23
-#define OBJID_slot_time 24
-#define OBJID_roaming_low_snr 25
-#define OBJID_low_snr_count_thresh 26
-#define OBJID_infra_missed_bcn 27
-#define OBJID_adhoc_missed_bcn 28
-#define OBJID_curr_country_code 29
-#define OBJID_hop_pattern 30
-#define OBJID_reserved 31
-#define OBJID_cw_max_msb 32
-#define OBJID_cw_min_msb 33
-#define OBJID_noise_filter_gain 34
-#define OBJID_noise_limit_offset 35
-#define OBJID_det_rssi_thresh_offset 36
-#define OBJID_med_busy_thresh_offset 37
-#define OBJID_det_sync_thresh 38
-#define OBJID_test_mode 39
-#define OBJID_test_min_chan_num 40
-#define OBJID_test_max_chan_num 41
-#define OBJID_allow_bcast_ID_prbrsp 42
-#define OBJID_privacy_must_start 43
-#define OBJID_privacy_can_join 44
-#define OBJID_basic_rate_set 45
-
-/**** Configuration/Status/Control Area ***************************/
-/* System Control Block (SCB) Area
- * Located at Shared RAM offset 0
- */
-struct scb {
- UCHAR ccs_index;
- UCHAR rcs_index;
-};
-
-/****** Status area at Shared RAM offset 0x0100 ******************************/
-struct status {
- UCHAR mrx_overflow_for_host; /* 0=ECF may write, 1=host may write*/
- UCHAR mrx_checksum_error_for_host; /* 0=ECF may write, 1=host may write*/
- UCHAR rx_hec_error_for_host; /* 0=ECF may write, 1=host may write*/
- UCHAR reserved1;
- short mrx_overflow; /* ECF increments on rx overflow */
- short mrx_checksum_error; /* ECF increments on rx CRC error */
- short rx_hec_error; /* ECF incs on mac header CRC error */
- UCHAR rxnoise; /* Average RSL measurement */
-};
-
-/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/
-struct host_to_ecf_area {
-
-};
-
-/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/
-struct startup_res_518 {
- UCHAR startup_word;
- UCHAR station_addr[ADDRLEN];
- UCHAR calc_prog_chksum;
- UCHAR calc_cis_chksum;
- UCHAR ecf_spare[7];
- UCHAR japan_call_sign[12];
-};
-
-struct startup_res_6 {
- UCHAR startup_word;
- UCHAR station_addr[ADDRLEN];
- UCHAR reserved;
- UCHAR supp_rates[8];
- UCHAR japan_call_sign[12];
- UCHAR calc_prog_chksum;
- UCHAR calc_cis_chksum;
- UCHAR firmware_version[3];
- UCHAR asic_version;
- UCHAR tib_length;
-};
-
-struct start_join_net_params {
- UCHAR net_type;
- UCHAR ssid[ESSID_SIZE];
- UCHAR reserved;
- UCHAR privacy_can_join;
-};
-
-/****** Command Control Structure area at Shared ram offset 0x0400 ***********/
-/* Structures for command specific parameters (ccs.var) */
-struct update_param_cmd {
- UCHAR object_id;
- UCHAR number_objects;
- UCHAR failure_cause;
-};
-struct report_param_cmd {
- UCHAR object_id;
- UCHAR number_objects;
- UCHAR failure_cause;
- UCHAR length;
-};
-struct start_network_cmd {
- UCHAR update_param;
- UCHAR bssid[ADDRLEN];
- UCHAR net_initiated;
- UCHAR net_default_tx_rate;
- UCHAR encryption;
-};
-struct join_network_cmd {
- UCHAR update_param;
- UCHAR bssid[ADDRLEN];
- UCHAR net_initiated;
- UCHAR net_default_tx_rate;
- UCHAR encryption;
-};
-struct tx_requested_cmd {
-
- UCHAR tx_data_ptr[2];
- UCHAR tx_data_length[2];
- UCHAR host_reserved[2];
- UCHAR reserved[3];
- UCHAR tx_rate;
- UCHAR pow_sav_mode;
- UCHAR retries;
- UCHAR antenna;
-};
-struct tx_requested_cmd_4 {
-
- UCHAR tx_data_ptr[2];
- UCHAR tx_data_length[2];
- UCHAR dest_addr[ADDRLEN];
- UCHAR pow_sav_mode;
- UCHAR retries;
- UCHAR station_id;
-};
-struct memory_dump_cmd {
- UCHAR memory_type;
- UCHAR memory_ptr[2];
- UCHAR length;
-};
-struct update_association_cmd {
- UCHAR status;
- UCHAR aid[2];
-};
-struct start_timer_cmd {
- UCHAR duration[2];
-};
-
-struct ccs {
- UCHAR buffer_status; /* 0 = buffer free, 1 = buffer busy */
- /* 2 = command complete, 3 = failed */
- UCHAR cmd; /* command to ECF */
- UCHAR link; /* link to next CCS, FF=end of list */
- /* command specific parameters */
- union {
- char reserved[13];
- struct update_param_cmd update_param;
- struct report_param_cmd report_param;
- UCHAR nummulticast;
- UCHAR mode;
- struct start_network_cmd start_network;
- struct join_network_cmd join_network;
- struct tx_requested_cmd tx_request;
- struct memory_dump_cmd memory_dump;
- struct update_association_cmd update_assoc;
- struct start_timer_cmd start_timer;
- } var;
-};
-
-/*****************************************************************************/
-/* Transmit buffer structures */
-struct tib_structure {
- UCHAR ccs_index;
- UCHAR psm;
- UCHAR pass_fail;
- UCHAR retry_count;
- UCHAR max_retries;
- UCHAR frags_remaining;
- UCHAR no_rb;
- UCHAR rts_reqd;
- UCHAR csma_tx_cntrl_2;
- UCHAR sifs_tx_cntrl_2;
- UCHAR tx_dma_addr_1[2];
- UCHAR tx_dma_addr_2[2];
- UCHAR var_dur_2mhz[2];
- UCHAR var_dur_1mhz[2];
- UCHAR max_dur_2mhz[2];
- UCHAR max_dur_1mhz[2];
- UCHAR hdr_len;
- UCHAR max_frag_len[2];
- UCHAR var_len[2];
- UCHAR phy_hdr_4;
- UCHAR mac_hdr_1;
- UCHAR mac_hdr_2;
- UCHAR sid[2];
-};
-
-struct phy_header {
- UCHAR sfd[2];
- UCHAR hdr_3;
- UCHAR hdr_4;
-};
-struct ray_rx_msg {
- struct mac_header mac;
- UCHAR var[];
-};
-
-struct tx_msg {
- struct tib_structure tib;
- struct phy_header phy;
- struct mac_header mac;
- UCHAR var[];
-};
-
-/****** ECF Receive Control Structure (RCS) Area at Shared RAM offset 0x0800 */
-/* Structures for command specific parameters (rcs.var) */
-struct rx_packet_cmd {
- UCHAR rx_data_ptr[2];
- UCHAR rx_data_length[2];
- UCHAR rx_sig_lev;
- UCHAR next_frag_rcs_index;
- UCHAR totalpacketlength[2];
-};
-struct rejoin_net_cmplt_cmd {
- UCHAR reserved;
- UCHAR bssid[ADDRLEN];
-};
-struct japan_call_sign_rxd {
- UCHAR rxd_call_sign[8];
- UCHAR reserved[5];
-};
-
-struct rcs {
- UCHAR buffer_status;
- UCHAR interrupt_id;
- UCHAR link_field;
- /* command specific parameters */
- union {
- UCHAR reserved[13];
- struct rx_packet_cmd rx_packet;
- struct rejoin_net_cmplt_cmd rejoin_net_complete;
- struct japan_call_sign_rxd japan_call_sign;
- } var;
-};
-
-/****** Startup parameter structures for both versions of firmware ***********/
-struct b4_startup_params {
- UCHAR a_network_type; /* C_ADHOC, C_INFRA */
- UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */
- UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */
- UCHAR a_scanning_mode; /* passive 0, active 1 */
- UCHAR a_power_mgt_state; /* CAM 0, */
- UCHAR a_mac_addr[ADDRLEN]; /* */
- UCHAR a_frag_threshold[2]; /* 512 */
- UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */
- UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */
- UCHAR a_dtim_period; /* in beacons */
- UCHAR a_retry_max; /* */
- UCHAR a_ack_timeout; /* */
- UCHAR a_sifs; /* */
- UCHAR a_difs; /* */
- UCHAR a_pifs; /* */
- UCHAR a_rts_threshold[2]; /* */
- UCHAR a_scan_dwell_time[2]; /* */
- UCHAR a_max_scan_dwell_time[2]; /* */
- UCHAR a_assoc_resp_timeout_thresh; /* */
- UCHAR a_adhoc_scan_cycle_max; /* */
- UCHAR a_infra_scan_cycle_max; /* */
- UCHAR a_infra_super_scan_cycle_max; /* */
- UCHAR a_promiscuous_mode; /* */
- UCHAR a_unique_word[2]; /* */
- UCHAR a_slot_time; /* */
- UCHAR a_roaming_low_snr_thresh; /* */
- UCHAR a_low_snr_count_thresh; /* */
- UCHAR a_infra_missed_bcn_thresh; /* */
- UCHAR a_adhoc_missed_bcn_thresh; /* */
- UCHAR a_curr_country_code; /* C_USA */
- UCHAR a_hop_pattern; /* */
- UCHAR a_hop_pattern_length; /* */
-/* b4 - b5 differences start here */
- UCHAR a_cw_max; /* */
- UCHAR a_cw_min; /* */
- UCHAR a_noise_filter_gain; /* */
- UCHAR a_noise_limit_offset; /* */
- UCHAR a_det_rssi_thresh_offset; /* */
- UCHAR a_med_busy_thresh_offset; /* */
- UCHAR a_det_sync_thresh; /* */
- UCHAR a_test_mode; /* */
- UCHAR a_test_min_chan_num; /* */
- UCHAR a_test_max_chan_num; /* */
- UCHAR a_rx_tx_delay; /* */
- UCHAR a_current_bss_id[ADDRLEN]; /* */
- UCHAR a_hop_set; /* */
-};
-struct b5_startup_params {
- UCHAR a_network_type; /* C_ADHOC, C_INFRA */
- UCHAR a_acting_as_ap_status; /* C_TYPE_STA, C_TYPE_AP */
- UCHAR a_current_ess_id[ESSID_SIZE]; /* Null terminated unless 32 long */
- UCHAR a_scanning_mode; /* passive 0, active 1 */
- UCHAR a_power_mgt_state; /* CAM 0, */
- UCHAR a_mac_addr[ADDRLEN]; /* */
- UCHAR a_frag_threshold[2]; /* 512 */
- UCHAR a_hop_time[2]; /* 16k * 2**n, n=0-4 in Kus */
- UCHAR a_beacon_period[2]; /* n * a_hop_time in Kus */
- UCHAR a_dtim_period; /* in beacons */
- UCHAR a_retry_max; /* 4 */
- UCHAR a_ack_timeout; /* */
- UCHAR a_sifs; /* */
- UCHAR a_difs; /* */
- UCHAR a_pifs; /* */
- UCHAR a_rts_threshold[2]; /* */
- UCHAR a_scan_dwell_time[2]; /* */
- UCHAR a_max_scan_dwell_time[2]; /* */
- UCHAR a_assoc_resp_timeout_thresh; /* */
- UCHAR a_adhoc_scan_cycle_max; /* */
- UCHAR a_infra_scan_cycle_max; /* */
- UCHAR a_infra_super_scan_cycle_max; /* */
- UCHAR a_promiscuous_mode; /* */
- UCHAR a_unique_word[2]; /* */
- UCHAR a_slot_time; /* */
- UCHAR a_roaming_low_snr_thresh; /* */
- UCHAR a_low_snr_count_thresh; /* */
- UCHAR a_infra_missed_bcn_thresh; /* */
- UCHAR a_adhoc_missed_bcn_thresh; /* */
- UCHAR a_curr_country_code; /* C_USA */
- UCHAR a_hop_pattern; /* */
- UCHAR a_hop_pattern_length; /* */
-/* b4 - b5 differences start here */
- UCHAR a_cw_max[2]; /* */
- UCHAR a_cw_min[2]; /* */
- UCHAR a_noise_filter_gain; /* */
- UCHAR a_noise_limit_offset; /* */
- UCHAR a_det_rssi_thresh_offset; /* */
- UCHAR a_med_busy_thresh_offset; /* */
- UCHAR a_det_sync_thresh; /* */
- UCHAR a_test_mode; /* */
- UCHAR a_test_min_chan_num; /* */
- UCHAR a_test_max_chan_num; /* */
- UCHAR a_allow_bcast_SSID_probe_rsp;
- UCHAR a_privacy_must_start;
- UCHAR a_privacy_can_join;
- UCHAR a_basic_rate_set[8];
-};
-
-/*****************************************************************************/
-#define RAY_IOCG_PARMS (SIOCDEVPRIVATE)
-#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1)
-#define RAY_DO_CMD (SIOCDEVPRIVATE + 2)
-
-/****** ethernet <-> 802.11 translation **************************************/
-typedef struct snaphdr_t
-{
- UCHAR dsap;
- UCHAR ssap;
- UCHAR ctrl;
- UCHAR org[3];
- UCHAR ethertype[2];
-} snaphdr_t;
-
-#define BRIDGE_ENCAP 0xf80000
-#define RFC1042_ENCAP 0
-#define SNAP_ID 0x0003aaaa
-#define RAY_IPX_TYPE 0x8137
-#define APPLEARP_TYPE 0x80f3
-/*****************************************************************************/
-#endif /* _RAYCTL_H_ */
--
2.39.2

2023-10-23 13:23:14

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 08/10] wifi: remove orphaned wl3501 driver

From: Arnd Bergmann <[email protected]>

Planet WL3501 is another PCMCIA driver for pre-802.11b interfaces
(2Mbit/s) with incomplete CFG80211 support.

This was marked as orphaned in 2017 but has been unmaintained
for a long time before that.

Signed-off-by: Arnd Bergmann <[email protected]>
---
MAINTAINERS | 5 -
drivers/net/wireless/legacy/Kconfig | 10 -
drivers/net/wireless/legacy/Makefile | 3 -
drivers/net/wireless/legacy/wl3501.h | 615 -------
drivers/net/wireless/legacy/wl3501_cs.c | 2036 -----------------------
5 files changed, 2669 deletions(-)
delete mode 100644 drivers/net/wireless/legacy/wl3501.h
delete mode 100644 drivers/net/wireless/legacy/wl3501_cs.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3123c955bb7f5..ee3c96de689c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23221,11 +23221,6 @@ M: Miloslav Trmac <[email protected]>
S: Maintained
F: drivers/input/misc/wistron_btns.c

-WL3501 WIRELESS PCMCIA CARD DRIVER
-L: [email protected]
-S: Orphan
-F: drivers/net/wireless/legacy/wl3501*
-
WMI BINARY MOF DRIVER
M: Armin Wolf <[email protected]>
R: Thomas Weißschuh <[email protected]>
diff --git a/drivers/net/wireless/legacy/Kconfig b/drivers/net/wireless/legacy/Kconfig
index 1d77d53d64409..b4e0e516f2faa 100644
--- a/drivers/net/wireless/legacy/Kconfig
+++ b/drivers/net/wireless/legacy/Kconfig
@@ -1,13 +1,3 @@
-config PCMCIA_WL3501
- tristate "Planet WL3501 PCMCIA cards"
- depends on CFG80211 && PCMCIA
- select WIRELESS_EXT
- select WEXT_SPY
- help
- A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet.
- It has basic support for Linux wireless extensions and initial
- micro support for ethtool.
-
config USB_NET_RNDIS_WLAN
tristate "Wireless RNDIS USB support"
depends on USB
diff --git a/drivers/net/wireless/legacy/Makefile b/drivers/net/wireless/legacy/Makefile
index d8705ccc5cf5d..1ed83f33ad20e 100644
--- a/drivers/net/wireless/legacy/Makefile
+++ b/drivers/net/wireless/legacy/Makefile
@@ -1,5 +1,2 @@
-# 16-bit wireless PCMCIA client drivers
-obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o
-
obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o

diff --git a/drivers/net/wireless/legacy/wl3501.h b/drivers/net/wireless/legacy/wl3501.h
deleted file mode 100644
index 91f276dd22a1b..0000000000000
--- a/drivers/net/wireless/legacy/wl3501.h
+++ /dev/null
@@ -1,615 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __WL3501_H__
-#define __WL3501_H__
-
-#include <linux/spinlock.h>
-#include <linux/ieee80211.h>
-
-/* define for WLA 2.0 */
-#define WL3501_BLKSZ 256
-/*
- * ID for input Signals of DRIVER block
- * bit[7-5] is block ID: 000
- * bit[4-0] is signal ID
-*/
-enum wl3501_signals {
- WL3501_SIG_ALARM,
- WL3501_SIG_MD_CONFIRM,
- WL3501_SIG_MD_IND,
- WL3501_SIG_ASSOC_CONFIRM,
- WL3501_SIG_ASSOC_IND,
- WL3501_SIG_AUTH_CONFIRM,
- WL3501_SIG_AUTH_IND,
- WL3501_SIG_DEAUTH_CONFIRM,
- WL3501_SIG_DEAUTH_IND,
- WL3501_SIG_DISASSOC_CONFIRM,
- WL3501_SIG_DISASSOC_IND,
- WL3501_SIG_GET_CONFIRM,
- WL3501_SIG_JOIN_CONFIRM,
- WL3501_SIG_PWR_MGMT_CONFIRM,
- WL3501_SIG_REASSOC_CONFIRM,
- WL3501_SIG_REASSOC_IND,
- WL3501_SIG_SCAN_CONFIRM,
- WL3501_SIG_SET_CONFIRM,
- WL3501_SIG_START_CONFIRM,
- WL3501_SIG_RESYNC_CONFIRM,
- WL3501_SIG_SITE_CONFIRM,
- WL3501_SIG_SAVE_CONFIRM,
- WL3501_SIG_RFTEST_CONFIRM,
-/*
- * ID for input Signals of MLME block
- * bit[7-5] is block ID: 010
- * bit[4-0] is signal ID
- */
- WL3501_SIG_ASSOC_REQ = 0x20,
- WL3501_SIG_AUTH_REQ,
- WL3501_SIG_DEAUTH_REQ,
- WL3501_SIG_DISASSOC_REQ,
- WL3501_SIG_GET_REQ,
- WL3501_SIG_JOIN_REQ,
- WL3501_SIG_PWR_MGMT_REQ,
- WL3501_SIG_REASSOC_REQ,
- WL3501_SIG_SCAN_REQ,
- WL3501_SIG_SET_REQ,
- WL3501_SIG_START_REQ,
- WL3501_SIG_MD_REQ,
- WL3501_SIG_RESYNC_REQ,
- WL3501_SIG_SITE_REQ,
- WL3501_SIG_SAVE_REQ,
- WL3501_SIG_RF_TEST_REQ,
- WL3501_SIG_MM_CONFIRM = 0x60,
- WL3501_SIG_MM_IND,
-};
-
-enum wl3501_mib_attribs {
- WL3501_MIB_ATTR_STATION_ID,
- WL3501_MIB_ATTR_AUTH_ALGORITHMS,
- WL3501_MIB_ATTR_AUTH_TYPE,
- WL3501_MIB_ATTR_MEDIUM_OCCUPANCY_LIMIT,
- WL3501_MIB_ATTR_CF_POLLABLE,
- WL3501_MIB_ATTR_CFP_PERIOD,
- WL3501_MIB_ATTR_CFPMAX_DURATION,
- WL3501_MIB_ATTR_AUTH_RESP_TMOUT,
- WL3501_MIB_ATTR_RX_DTIMS,
- WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,
- WL3501_MIB_ATTR_PRIV_INVOKED,
- WL3501_MIB_ATTR_WEP_DEFAULT_KEYS,
- WL3501_MIB_ATTR_WEP_DEFAULT_KEY_ID,
- WL3501_MIB_ATTR_WEP_KEY_MAPPINGS,
- WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN,
- WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED,
- WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT,
- WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT,
- WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT,
- WL3501_MIB_ATTR_MAC_ADDR,
- WL3501_MIB_ATTR_GROUP_ADDRS,
- WL3501_MIB_ATTR_RTS_THRESHOLD,
- WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
- WL3501_MIB_ATTR_LONG_RETRY_LIMIT,
- WL3501_MIB_ATTR_FRAG_THRESHOLD,
- WL3501_MIB_ATTR_MAX_TX_MSDU_LIFETIME,
- WL3501_MIB_ATTR_MAX_RX_LIFETIME,
- WL3501_MIB_ATTR_MANUFACTURER_ID,
- WL3501_MIB_ATTR_PRODUCT_ID,
- WL3501_MIB_ATTR_TX_FRAG_COUNT,
- WL3501_MIB_ATTR_MULTICAST_TX_FRAME_COUNT,
- WL3501_MIB_ATTR_FAILED_COUNT,
- WL3501_MIB_ATTR_RX_FRAG_COUNT,
- WL3501_MIB_ATTR_MULTICAST_RX_COUNT,
- WL3501_MIB_ATTR_FCS_ERROR_COUNT,
- WL3501_MIB_ATTR_RETRY_COUNT,
- WL3501_MIB_ATTR_MULTIPLE_RETRY_COUNT,
- WL3501_MIB_ATTR_RTS_SUCCESS_COUNT,
- WL3501_MIB_ATTR_RTS_FAILURE_COUNT,
- WL3501_MIB_ATTR_ACK_FAILURE_COUNT,
- WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT,
- WL3501_MIB_ATTR_PHY_TYPE,
- WL3501_MIB_ATTR_REG_DOMAINS_SUPPORT,
- WL3501_MIB_ATTR_CURRENT_REG_DOMAIN,
- WL3501_MIB_ATTR_SLOT_TIME,
- WL3501_MIB_ATTR_CCA_TIME,
- WL3501_MIB_ATTR_RX_TX_TURNAROUND_TIME,
- WL3501_MIB_ATTR_TX_PLCP_DELAY,
- WL3501_MIB_ATTR_RX_TX_SWITCH_TIME,
- WL3501_MIB_ATTR_TX_RAMP_ON_TIME,
- WL3501_MIB_ATTR_TX_RF_DELAY,
- WL3501_MIB_ATTR_SIFS_TIME,
- WL3501_MIB_ATTR_RX_RF_DELAY,
- WL3501_MIB_ATTR_RX_PLCP_DELAY,
- WL3501_MIB_ATTR_MAC_PROCESSING_DELAY,
- WL3501_MIB_ATTR_TX_RAMP_OFF_TIME,
- WL3501_MIB_ATTR_PREAMBLE_LEN,
- WL3501_MIB_ATTR_PLCP_HEADER_LEN,
- WL3501_MIB_ATTR_MPDU_DURATION_FACTOR,
- WL3501_MIB_ATTR_AIR_PROPAGATION_TIME,
- WL3501_MIB_ATTR_TEMP_TYPE,
- WL3501_MIB_ATTR_CW_MIN,
- WL3501_MIB_ATTR_CW_MAX,
- WL3501_MIB_ATTR_SUPPORT_DATA_RATES_TX,
- WL3501_MIB_ATTR_SUPPORT_DATA_RATES_RX,
- WL3501_MIB_ATTR_MPDU_MAX_LEN,
- WL3501_MIB_ATTR_SUPPORT_TX_ANTENNAS,
- WL3501_MIB_ATTR_CURRENT_TX_ANTENNA,
- WL3501_MIB_ATTR_SUPPORT_RX_ANTENNAS,
- WL3501_MIB_ATTR_DIVERSITY_SUPPORT,
- WL3501_MIB_ATTR_DIVERSITY_SELECTION_RS,
- WL3501_MIB_ATTR_NR_SUPPORTED_PWR_LEVELS,
- WL3501_MIB_ATTR_TX_PWR_LEVEL1,
- WL3501_MIB_ATTR_TX_PWR_LEVEL2,
- WL3501_MIB_ATTR_TX_PWR_LEVEL3,
- WL3501_MIB_ATTR_TX_PWR_LEVEL4,
- WL3501_MIB_ATTR_TX_PWR_LEVEL5,
- WL3501_MIB_ATTR_TX_PWR_LEVEL6,
- WL3501_MIB_ATTR_TX_PWR_LEVEL7,
- WL3501_MIB_ATTR_TX_PWR_LEVEL8,
- WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,
- WL3501_MIB_ATTR_CURRENT_CHAN,
- WL3501_MIB_ATTR_CCA_MODE_SUPPORTED,
- WL3501_MIB_ATTR_CURRENT_CCA_MODE,
- WL3501_MIB_ATTR_ED_THRESHOLD,
- WL3501_MIB_ATTR_SINTHESIZER_LOCKED,
- WL3501_MIB_ATTR_CURRENT_PWR_STATE,
- WL3501_MIB_ATTR_DOZE_TURNON_TIME,
- WL3501_MIB_ATTR_RCR33,
- WL3501_MIB_ATTR_DEFAULT_CHAN,
- WL3501_MIB_ATTR_SSID,
- WL3501_MIB_ATTR_PWR_MGMT_ENABLE,
- WL3501_MIB_ATTR_NET_CAPABILITY,
- WL3501_MIB_ATTR_ROUTING,
-};
-
-enum wl3501_net_type {
- WL3501_NET_TYPE_INFRA,
- WL3501_NET_TYPE_ADHOC,
- WL3501_NET_TYPE_ANY_BSS,
-};
-
-enum wl3501_scan_type {
- WL3501_SCAN_TYPE_ACTIVE,
- WL3501_SCAN_TYPE_PASSIVE,
-};
-
-enum wl3501_tx_result {
- WL3501_TX_RESULT_SUCCESS,
- WL3501_TX_RESULT_NO_BSS,
- WL3501_TX_RESULT_RETRY_LIMIT,
-};
-
-enum wl3501_sys_type {
- WL3501_SYS_TYPE_OPEN,
- WL3501_SYS_TYPE_SHARE_KEY,
-};
-
-enum wl3501_status {
- WL3501_STATUS_SUCCESS,
- WL3501_STATUS_INVALID,
- WL3501_STATUS_TIMEOUT,
- WL3501_STATUS_REFUSED,
- WL3501_STATUS_MANY_REQ,
- WL3501_STATUS_ALREADY_BSS,
-};
-
-#define WL3501_MGMT_CAPABILITY_ESS 0x0001 /* see 802.11 p.58 */
-#define WL3501_MGMT_CAPABILITY_IBSS 0x0002 /* - " - */
-#define WL3501_MGMT_CAPABILITY_CF_POLLABLE 0x0004 /* - " - */
-#define WL3501_MGMT_CAPABILITY_CF_POLL_REQUEST 0x0008 /* - " - */
-#define WL3501_MGMT_CAPABILITY_PRIVACY 0x0010 /* - " - */
-
-#define IW_REG_DOMAIN_FCC 0x10 /* Channel 1 to 11 USA */
-#define IW_REG_DOMAIN_DOC 0x20 /* Channel 1 to 11 Canada */
-#define IW_REG_DOMAIN_ETSI 0x30 /* Channel 1 to 13 Europe */
-#define IW_REG_DOMAIN_SPAIN 0x31 /* Channel 10 to 11 Spain */
-#define IW_REG_DOMAIN_FRANCE 0x32 /* Channel 10 to 13 France */
-#define IW_REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */
-#define IW_REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan */
-#define IW_REG_DOMAIN_ISRAEL 0x50 /* Channel 3 - 9 Israel */
-
-#define IW_MGMT_RATE_LABEL_MANDATORY 128 /* MSB */
-
-enum iw_mgmt_rate_labels {
- IW_MGMT_RATE_LABEL_1MBIT = 2,
- IW_MGMT_RATE_LABEL_2MBIT = 4,
- IW_MGMT_RATE_LABEL_5_5MBIT = 11,
- IW_MGMT_RATE_LABEL_11MBIT = 22,
-};
-
-enum iw_mgmt_info_element_ids {
- IW_MGMT_INFO_ELEMENT_SSID, /* Service Set Identity */
- IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES,
- IW_MGMT_INFO_ELEMENT_FH_PARAMETER_SET,
- IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
- IW_MGMT_INFO_ELEMENT_CS_PARAMETER_SET,
- IW_MGMT_INFO_ELEMENT_CS_TIM, /* Traffic Information Map */
- IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET,
- /* 7-15: Reserved, unused */
- IW_MGMT_INFO_ELEMENT_CHALLENGE_TEXT = 16,
- /* 17-31 Reserved for challenge text extension */
- /* 32-255 Reserved, unused */
-};
-
-struct iw_mgmt_info_element {
- u8 id; /* one of enum iw_mgmt_info_element_ids,
- but sizeof(enum) > sizeof(u8) :-( */
- u8 len;
- u8 data[];
-} __packed;
-
-struct iw_mgmt_essid_pset {
- struct iw_mgmt_info_element el;
- u8 essid[IW_ESSID_MAX_SIZE];
-} __packed;
-
-/*
- * According to 802.11 Wireless Networks, the definitive guide - O'Reilly
- * Pg 75
- */
-#define IW_DATA_RATE_MAX_LABELS 8
-
-struct iw_mgmt_data_rset {
- struct iw_mgmt_info_element el;
- u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS];
-} __packed;
-
-struct iw_mgmt_ds_pset {
- struct iw_mgmt_info_element el;
- u8 chan;
-} __packed;
-
-struct iw_mgmt_cf_pset {
- struct iw_mgmt_info_element el;
- u8 cfp_count;
- u8 cfp_period;
- u16 cfp_max_duration;
- u16 cfp_dur_remaining;
-} __packed;
-
-struct iw_mgmt_ibss_pset {
- struct iw_mgmt_info_element el;
- u16 atim_window;
-} __packed;
-
-struct wl3501_tx_hdr {
- u16 tx_cnt;
- u8 sync[16];
- u16 sfd;
- u8 signal;
- u8 service;
- u16 len;
- u16 crc16;
- u16 frame_ctrl;
- u16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- u16 seq_ctrl;
- u8 addr4[ETH_ALEN];
-};
-
-struct wl3501_rx_hdr {
- u16 rx_next_blk;
- u16 rc_next_frame_blk;
- u8 rx_blk_ctrl;
- u8 rx_next_frame;
- u8 rx_next_frame1;
- u8 rssi;
- char time[8];
- u8 signal;
- u8 service;
- u16 len;
- u16 crc16;
- u16 frame_ctrl;
- u16 duration;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- u16 seq;
- u8 addr4[ETH_ALEN];
-};
-
-struct wl3501_start_req {
- u16 next_blk;
- u8 sig_id;
- u8 bss_type;
- u16 beacon_period;
- u16 dtim_period;
- u16 probe_delay;
- u16 cap_info;
- struct iw_mgmt_essid_pset ssid;
- struct iw_mgmt_data_rset bss_basic_rset;
- struct iw_mgmt_data_rset operational_rset;
- struct iw_mgmt_cf_pset cf_pset;
- struct iw_mgmt_ds_pset ds_pset;
- struct iw_mgmt_ibss_pset ibss_pset;
-};
-
-struct wl3501_assoc_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 timeout;
- u16 cap_info;
- u16 listen_interval;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_assoc_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_assoc_ind {
- u16 next_blk;
- u8 sig_id;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_auth_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 type;
- u16 timeout;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_auth_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 type;
- u16 status;
- u8 mac_addr[ETH_ALEN];
-};
-
-struct wl3501_get_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 mib_attrib;
-};
-
-struct wl3501_get_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 mib_status;
- u16 mib_attrib;
- u8 mib_value[100];
-};
-
-struct wl3501_req {
- u16 beacon_period;
- u16 dtim_period;
- u16 cap_info;
- u8 bss_type;
- u8 bssid[ETH_ALEN];
- struct iw_mgmt_essid_pset ssid;
- struct iw_mgmt_ds_pset ds_pset;
- struct iw_mgmt_cf_pset cf_pset;
- struct iw_mgmt_ibss_pset ibss_pset;
- struct iw_mgmt_data_rset bss_basic_rset;
-};
-
-struct wl3501_join_req {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- struct iw_mgmt_data_rset operational_rset;
- u16 reserved2;
- u16 timeout;
- u16 probe_delay;
- u8 timestamp[8];
- u8 local_time[8];
- struct wl3501_req req;
-};
-
-struct wl3501_join_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_pwr_mgmt_req {
- u16 next_blk;
- u8 sig_id;
- u8 pwr_save;
- u8 wake_up;
- u8 receive_dtims;
-};
-
-struct wl3501_pwr_mgmt_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_scan_req {
- u16 next_blk;
- u8 sig_id;
- u8 bss_type;
- u16 probe_delay;
- u16 min_chan_time;
- u16 max_chan_time;
- u8 chan_list[14];
- u8 bssid[ETH_ALEN];
- struct iw_mgmt_essid_pset ssid;
- enum wl3501_scan_type scan_type;
-};
-
-struct wl3501_scan_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
- char timestamp[8];
- char localtime[8];
- struct wl3501_req req;
- u8 rssi;
-};
-
-struct wl3501_start_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 status;
-};
-
-struct wl3501_md_req {
- u16 next_blk;
- u8 sig_id;
- u8 routing;
- u16 data;
- u16 size;
- u8 pri;
- u8 service_class;
- struct {
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
- } addr;
-};
-
-struct wl3501_md_ind {
- u16 next_blk;
- u8 sig_id;
- u8 routing;
- u16 data;
- u16 size;
- u8 reception;
- u8 pri;
- u8 service_class;
- struct {
- u8 daddr[ETH_ALEN];
- u8 saddr[ETH_ALEN];
- } addr;
-};
-
-struct wl3501_md_confirm {
- u16 next_blk;
- u8 sig_id;
- u8 reserved;
- u16 data;
- u8 status;
- u8 pri;
- u8 service_class;
-};
-
-struct wl3501_resync_req {
- u16 next_blk;
- u8 sig_id;
-};
-
-/* Definitions for supporting clone adapters. */
-/* System Interface Registers (SIR space) */
-#define WL3501_NIC_GCR ((u8)0x00) /* SIR0 - General Conf Register */
-#define WL3501_NIC_BSS ((u8)0x01) /* SIR1 - Bank Switching Select Reg */
-#define WL3501_NIC_LMAL ((u8)0x02) /* SIR2 - Local Mem addr Reg [7:0] */
-#define WL3501_NIC_LMAH ((u8)0x03) /* SIR3 - Local Mem addr Reg [14:8] */
-#define WL3501_NIC_IODPA ((u8)0x04) /* SIR4 - I/O Data Port A */
-#define WL3501_NIC_IODPB ((u8)0x05) /* SIR5 - I/O Data Port B */
-#define WL3501_NIC_IODPC ((u8)0x06) /* SIR6 - I/O Data Port C */
-#define WL3501_NIC_IODPD ((u8)0x07) /* SIR7 - I/O Data Port D */
-
-/* Bits in GCR */
-#define WL3501_GCR_SWRESET ((u8)0x80)
-#define WL3501_GCR_CORESET ((u8)0x40)
-#define WL3501_GCR_DISPWDN ((u8)0x20)
-#define WL3501_GCR_ECWAIT ((u8)0x10)
-#define WL3501_GCR_ECINT ((u8)0x08)
-#define WL3501_GCR_INT2EC ((u8)0x04)
-#define WL3501_GCR_ENECINT ((u8)0x02)
-#define WL3501_GCR_DAM ((u8)0x01)
-
-/* Bits in BSS (Bank Switching Select Register) */
-#define WL3501_BSS_FPAGE0 ((u8)0x20) /* Flash memory page0 */
-#define WL3501_BSS_FPAGE1 ((u8)0x28)
-#define WL3501_BSS_FPAGE2 ((u8)0x30)
-#define WL3501_BSS_FPAGE3 ((u8)0x38)
-#define WL3501_BSS_SPAGE0 ((u8)0x00) /* SRAM page0 */
-#define WL3501_BSS_SPAGE1 ((u8)0x08)
-#define WL3501_BSS_SPAGE2 ((u8)0x10)
-#define WL3501_BSS_SPAGE3 ((u8)0x18)
-
-/* Define Driver Interface */
-/* Refer IEEE 802.11 */
-/* Tx packet header, include PLCP and MPDU */
-/* Tx PLCP Header */
-struct wl3501_80211_tx_plcp_hdr {
- u8 sync[16];
- u16 sfd;
- u8 signal;
- u8 service;
- u16 len;
- u16 crc16;
-} __packed;
-
-struct wl3501_80211_tx_hdr {
- struct wl3501_80211_tx_plcp_hdr pclp_hdr;
- struct ieee80211_hdr mac_hdr;
-} __packed __aligned(2);
-
-/*
- Reserve the beginning Tx space for descriptor use.
-
- TxBlockOffset --> *----*----*----*----* \
- (TxFreeDesc) | 0 | 1 | 2 | 3 | \
- | 4 | 5 | 6 | 7 | |
- | 8 | 9 | 10 | 11 | TX_DESC * 20
- | 12 | 13 | 14 | 15 | |
- | 16 | 17 | 18 | 19 | /
- TxBufferBegin --> *----*----*----*----* /
- (TxBufferHead) | |
- (TxBufferTail) | |
- | Send Buffer |
- | |
- | |
- *-------------------*
- TxBufferEnd -------------------------/
-
-*/
-
-struct wl3501_card {
- int base_addr;
- u8 mac_addr[ETH_ALEN];
- spinlock_t lock;
- wait_queue_head_t wait;
- struct wl3501_get_confirm sig_get_confirm;
- struct wl3501_pwr_mgmt_confirm sig_pwr_mgmt_confirm;
- u16 tx_buffer_size;
- u16 tx_buffer_head;
- u16 tx_buffer_tail;
- u16 tx_buffer_cnt;
- u16 esbq_req_start;
- u16 esbq_req_end;
- u16 esbq_req_head;
- u16 esbq_req_tail;
- u16 esbq_confirm_start;
- u16 esbq_confirm_end;
- u16 esbq_confirm;
- struct iw_mgmt_essid_pset essid;
- struct iw_mgmt_essid_pset keep_essid;
- u8 bssid[ETH_ALEN];
- int net_type;
- char nick[32];
- char card_name[32];
- char firmware_date[32];
- u8 chan;
- u8 cap_info;
- u16 start_seg;
- u16 bss_cnt;
- u16 join_sta_bss;
- u8 rssi;
- u8 adhoc_times;
- u8 reg_domain;
- u8 version[2];
- struct wl3501_scan_confirm bss_set[20];
-
- struct iw_statistics wstats;
- struct iw_spy_data spy_data;
- struct iw_public_data wireless_data;
- struct pcmcia_device *p_dev;
-};
-#endif
diff --git a/drivers/net/wireless/legacy/wl3501_cs.c b/drivers/net/wireless/legacy/wl3501_cs.c
deleted file mode 100644
index c45c4b7cbbaf1..0000000000000
--- a/drivers/net/wireless/legacy/wl3501_cs.c
+++ /dev/null
@@ -1,2036 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * WL3501 Wireless LAN PCMCIA Card Driver for Linux
- * Written originally for Linux 2.0.30 by Fox Chen, [email protected]
- * Ported to 2.2, 2.4 & 2.5 by Arnaldo Carvalho de Melo <[email protected]>
- * Wireless extensions in 2.4 by Gustavo Niemeyer <[email protected]>
- *
- * References used by Fox Chen while writing the original driver for 2.0.30:
- *
- * 1. WL24xx packet drivers (tooasm.asm)
- * 2. Access Point Firmware Interface Specification for IEEE 802.11 SUTRO
- * 3. IEEE 802.11
- * 4. Linux network driver (/usr/src/linux/drivers/net)
- * 5. ISA card driver - wl24.c
- * 6. Linux PCMCIA skeleton driver - skeleton.c
- * 7. Linux PCMCIA 3c589 network driver - 3c589_cs.c
- *
- * Tested with WL2400 firmware 1.2, Linux 2.0.30, and pcmcia-cs-2.9.12
- * 1. Performance: about 165 Kbytes/sec in TCP/IP with Ad-Hoc mode.
- * rsh 192.168.1.3 "dd if=/dev/zero bs=1k count=1000" > /dev/null
- * (Specification 2M bits/sec. is about 250 Kbytes/sec., but we must deduct
- * ETHER/IP/UDP/TCP header, and acknowledgement overhead)
- *
- * Tested with Planet AP in 2.4.17, 184 Kbytes/s in UDP in Infrastructure mode,
- * 173 Kbytes/s in TCP.
- *
- * Tested with Planet AP in 2.5.73-bk, 216 Kbytes/s in Infrastructure mode
- * with a SMP machine (dual pentium 100), using pktgen, 432 pps (pkt_size = 60)
- */
-
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fcntl.h>
-#include <linux/if_arp.h>
-#include <linux/ioport.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/wireless.h>
-#include <net/cfg80211.h>
-
-#include <net/iw_handler.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
-#include <asm/io.h>
-#include <linux/uaccess.h>
-
-#include "wl3501.h"
-
-#ifndef __i386__
-#define slow_down_io()
-#endif
-
-/* For rough constant delay */
-#define WL3501_NOPLOOP(n) { int x = 0; while (x++ < n) slow_down_io(); }
-
-
-
-#define wl3501_outb(a, b) { outb(a, b); slow_down_io(); }
-#define wl3501_outb_p(a, b) { outb_p(a, b); slow_down_io(); }
-#define wl3501_outsb(a, b, c) { outsb(a, b, c); slow_down_io(); }
-
-#define WL3501_RELEASE_TIMEOUT (25 * HZ)
-#define WL3501_MAX_ADHOC_TRIES 16
-
-#define WL3501_RESUME 0
-#define WL3501_SUSPEND 1
-
-static int wl3501_config(struct pcmcia_device *link);
-static void wl3501_release(struct pcmcia_device *link);
-
-static const struct {
- int reg_domain;
- int min, max, deflt;
-} iw_channel_table[] = {
- {
- .reg_domain = IW_REG_DOMAIN_FCC,
- .min = 1,
- .max = 11,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_DOC,
- .min = 1,
- .max = 11,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_ETSI,
- .min = 1,
- .max = 13,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_SPAIN,
- .min = 10,
- .max = 11,
- .deflt = 10,
- },
- {
- .reg_domain = IW_REG_DOMAIN_FRANCE,
- .min = 10,
- .max = 13,
- .deflt = 10,
- },
- {
- .reg_domain = IW_REG_DOMAIN_MKK,
- .min = 14,
- .max = 14,
- .deflt = 14,
- },
- {
- .reg_domain = IW_REG_DOMAIN_MKK1,
- .min = 1,
- .max = 14,
- .deflt = 1,
- },
- {
- .reg_domain = IW_REG_DOMAIN_ISRAEL,
- .min = 3,
- .max = 9,
- .deflt = 9,
- },
-};
-
-/**
- * iw_valid_channel - validate channel in regulatory domain
- * @reg_domain: regulatory domain
- * @channel: channel to validate
- *
- * Returns 0 if invalid in the specified regulatory domain, non-zero if valid.
- */
-static int iw_valid_channel(int reg_domain, int channel)
-{
- int i, rc = 0;
-
- for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++)
- if (reg_domain == iw_channel_table[i].reg_domain) {
- rc = channel >= iw_channel_table[i].min &&
- channel <= iw_channel_table[i].max;
- break;
- }
- return rc;
-}
-
-/**
- * iw_default_channel - get default channel for a regulatory domain
- * @reg_domain: regulatory domain
- *
- * Returns the default channel for a regulatory domain
- */
-static int iw_default_channel(int reg_domain)
-{
- int i, rc = 1;
-
- for (i = 0; i < ARRAY_SIZE(iw_channel_table); i++)
- if (reg_domain == iw_channel_table[i].reg_domain) {
- rc = iw_channel_table[i].deflt;
- break;
- }
- return rc;
-}
-
-static void iw_set_mgmt_info_element(enum iw_mgmt_info_element_ids id,
- struct iw_mgmt_info_element *el,
- void *value, int len)
-{
- el->id = id;
- el->len = len;
- memcpy(el->data, value, len);
-}
-
-static void iw_copy_mgmt_info_element(struct iw_mgmt_info_element *to,
- struct iw_mgmt_info_element *from)
-{
- iw_set_mgmt_info_element(from->id, to, from->data, from->len);
-}
-
-static inline void wl3501_switch_page(struct wl3501_card *this, u8 page)
-{
- wl3501_outb(page, this->base_addr + WL3501_NIC_BSS);
-}
-
-/*
- * Get Ethernet MAC address.
- *
- * WARNING: We switch to FPAGE0 and switc back again.
- * Making sure there is no other WL function beening called by ISR.
- */
-static int wl3501_get_flash_mac_addr(struct wl3501_card *this)
-{
- int base_addr = this->base_addr;
-
- /* get MAC addr */
- wl3501_outb(WL3501_BSS_FPAGE3, base_addr + WL3501_NIC_BSS); /* BSS */
- wl3501_outb(0x00, base_addr + WL3501_NIC_LMAL); /* LMAL */
- wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH); /* LMAH */
-
- /* wait for reading EEPROM */
- WL3501_NOPLOOP(100);
- this->mac_addr[0] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[1] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[2] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[3] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[4] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->mac_addr[5] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->reg_domain = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- wl3501_outb(WL3501_BSS_FPAGE0, base_addr + WL3501_NIC_BSS);
- wl3501_outb(0x04, base_addr + WL3501_NIC_LMAL);
- wl3501_outb(0x40, base_addr + WL3501_NIC_LMAH);
- WL3501_NOPLOOP(100);
- this->version[0] = inb(base_addr + WL3501_NIC_IODPA);
- WL3501_NOPLOOP(100);
- this->version[1] = inb(base_addr + WL3501_NIC_IODPA);
- /* switch to SRAM Page 0 (for safety) */
- wl3501_switch_page(this, WL3501_BSS_SPAGE0);
-
- /* The MAC addr should be 00:60:... */
- return this->mac_addr[0] == 0x00 && this->mac_addr[1] == 0x60;
-}
-
-/**
- * wl3501_set_to_wla - Move 'size' bytes from PC to card
- * @this: Card
- * @dest: Card addressing space
- * @src: PC addressing space
- * @size: Bytes to move
- *
- * Move 'size' bytes from PC to card. (Shouldn't be interrupted)
- */
-static void wl3501_set_to_wla(struct wl3501_card *this, u16 dest, void *src,
- int size)
-{
- /* switch to SRAM Page 0 */
- wl3501_switch_page(this, (dest & 0x8000) ? WL3501_BSS_SPAGE1 :
- WL3501_BSS_SPAGE0);
- /* set LMAL and LMAH */
- wl3501_outb(dest & 0xff, this->base_addr + WL3501_NIC_LMAL);
- wl3501_outb(((dest >> 8) & 0x7f), this->base_addr + WL3501_NIC_LMAH);
-
- /* rep out to Port A */
- wl3501_outsb(this->base_addr + WL3501_NIC_IODPA, src, size);
-}
-
-/**
- * wl3501_get_from_wla - Move 'size' bytes from card to PC
- * @this: Card
- * @src: Card addressing space
- * @dest: PC addressing space
- * @size: Bytes to move
- *
- * Move 'size' bytes from card to PC. (Shouldn't be interrupted)
- */
-static void wl3501_get_from_wla(struct wl3501_card *this, u16 src, void *dest,
- int size)
-{
- /* switch to SRAM Page 0 */
- wl3501_switch_page(this, (src & 0x8000) ? WL3501_BSS_SPAGE1 :
- WL3501_BSS_SPAGE0);
- /* set LMAL and LMAH */
- wl3501_outb(src & 0xff, this->base_addr + WL3501_NIC_LMAL);
- wl3501_outb((src >> 8) & 0x7f, this->base_addr + WL3501_NIC_LMAH);
-
- /* rep get from Port A */
- insb(this->base_addr + WL3501_NIC_IODPA, dest, size);
-}
-
-/*
- * Get/Allocate a free Tx Data Buffer
- *
- * *--------------*-----------------*----------------------------------*
- * | PLCP | MAC Header | DST SRC Data ... |
- * | (24 bytes) | (30 bytes) | (6) (6) (Ethernet Row Data) |
- * *--------------*-----------------*----------------------------------*
- * \ \- IEEE 802.11 -/ \-------------- len --------------/
- * \-struct wl3501_80211_tx_hdr--/ \-------- Ethernet Frame -------/
- *
- * Return = Position in Card
- */
-static u16 wl3501_get_tx_buffer(struct wl3501_card *this, u16 len)
-{
- u16 next, blk_cnt = 0, zero = 0;
- u16 full_len = sizeof(struct wl3501_80211_tx_hdr) + len;
- u16 ret = 0;
-
- if (full_len > this->tx_buffer_cnt * 254)
- goto out;
- ret = this->tx_buffer_head;
- while (full_len) {
- if (full_len < 254)
- full_len = 0;
- else
- full_len -= 254;
- wl3501_get_from_wla(this, this->tx_buffer_head, &next,
- sizeof(next));
- if (!full_len)
- wl3501_set_to_wla(this, this->tx_buffer_head, &zero,
- sizeof(zero));
- this->tx_buffer_head = next;
- blk_cnt++;
- /* if buffer is not enough */
- if (!next && full_len) {
- this->tx_buffer_head = ret;
- ret = 0;
- goto out;
- }
- }
- this->tx_buffer_cnt -= blk_cnt;
-out:
- return ret;
-}
-
-/*
- * Free an allocated Tx Buffer. ptr must be correct position.
- */
-static void wl3501_free_tx_buffer(struct wl3501_card *this, u16 ptr)
-{
- /* check if all space is not free */
- if (!this->tx_buffer_head)
- this->tx_buffer_head = ptr;
- else
- wl3501_set_to_wla(this, this->tx_buffer_tail,
- &ptr, sizeof(ptr));
- while (ptr) {
- u16 next;
-
- this->tx_buffer_cnt++;
- wl3501_get_from_wla(this, ptr, &next, sizeof(next));
- this->tx_buffer_tail = ptr;
- ptr = next;
- }
-}
-
-static int wl3501_esbq_req_test(struct wl3501_card *this)
-{
- u8 tmp = 0;
-
- wl3501_get_from_wla(this, this->esbq_req_head + 3, &tmp, sizeof(tmp));
- return tmp & 0x80;
-}
-
-static void wl3501_esbq_req(struct wl3501_card *this, u16 *ptr)
-{
- u16 tmp = 0;
-
- wl3501_set_to_wla(this, this->esbq_req_head, ptr, 2);
- wl3501_set_to_wla(this, this->esbq_req_head + 2, &tmp, sizeof(tmp));
- this->esbq_req_head += 4;
- if (this->esbq_req_head >= this->esbq_req_end)
- this->esbq_req_head = this->esbq_req_start;
-}
-
-static int wl3501_esbq_exec(struct wl3501_card *this, void *sig, int sig_size)
-{
- int rc = -EIO;
-
- if (wl3501_esbq_req_test(this)) {
- u16 ptr = wl3501_get_tx_buffer(this, sig_size);
- if (ptr) {
- wl3501_set_to_wla(this, ptr, sig, sig_size);
- wl3501_esbq_req(this, &ptr);
- rc = 0;
- }
- }
- return rc;
-}
-
-static int wl3501_request_mib(struct wl3501_card *this, u8 index, void *bf)
-{
- struct wl3501_get_req sig = {
- .sig_id = WL3501_SIG_GET_REQ,
- .mib_attrib = index,
- };
- unsigned long flags;
- int rc = -EIO;
-
- spin_lock_irqsave(&this->lock, flags);
- if (wl3501_esbq_req_test(this)) {
- u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig));
- if (ptr) {
- wl3501_set_to_wla(this, ptr, &sig, sizeof(sig));
- wl3501_esbq_req(this, &ptr);
- this->sig_get_confirm.mib_status = 255;
- rc = 0;
- }
- }
- spin_unlock_irqrestore(&this->lock, flags);
-
- return rc;
-}
-
-static int wl3501_get_mib_value(struct wl3501_card *this, u8 index,
- void *bf, int size)
-{
- int rc;
-
- rc = wl3501_request_mib(this, index, bf);
- if (rc)
- return rc;
-
- rc = wait_event_interruptible(this->wait,
- this->sig_get_confirm.mib_status != 255);
- if (rc)
- return rc;
-
- memcpy(bf, this->sig_get_confirm.mib_value, size);
- return 0;
-}
-
-static int wl3501_pwr_mgmt(struct wl3501_card *this, int suspend)
-{
- struct wl3501_pwr_mgmt_req sig = {
- .sig_id = WL3501_SIG_PWR_MGMT_REQ,
- .pwr_save = suspend,
- .wake_up = !suspend,
- .receive_dtims = 10,
- };
- unsigned long flags;
- int rc = -EIO;
-
- spin_lock_irqsave(&this->lock, flags);
- if (wl3501_esbq_req_test(this)) {
- u16 ptr = wl3501_get_tx_buffer(this, sizeof(sig));
- if (ptr) {
- wl3501_set_to_wla(this, ptr, &sig, sizeof(sig));
- wl3501_esbq_req(this, &ptr);
- this->sig_pwr_mgmt_confirm.status = 255;
- spin_unlock_irqrestore(&this->lock, flags);
- rc = wait_event_interruptible(this->wait,
- this->sig_pwr_mgmt_confirm.status != 255);
- printk(KERN_INFO "%s: %s status=%d\n", __func__,
- suspend ? "suspend" : "resume",
- this->sig_pwr_mgmt_confirm.status);
- goto out;
- }
- }
- spin_unlock_irqrestore(&this->lock, flags);
-out:
- return rc;
-}
-
-/**
- * wl3501_send_pkt - Send a packet.
- * @this: Card
- * @data: Ethernet raw frame. (e.g. data[0] - data[5] is Dest MAC Addr,
- * data[6] - data[11] is Src MAC Addr)
- * @len: Packet length
- * Ref: IEEE 802.11
- */
-static int wl3501_send_pkt(struct wl3501_card *this, u8 *data, u16 len)
-{
- u16 bf, sig_bf, next, tmplen, pktlen;
- struct wl3501_md_req sig = {
- .sig_id = WL3501_SIG_MD_REQ,
- };
- size_t sig_addr_len = sizeof(sig.addr);
- u8 *pdata = (char *)data;
- int rc = -EIO;
-
- if (wl3501_esbq_req_test(this)) {
- sig_bf = wl3501_get_tx_buffer(this, sizeof(sig));
- rc = -ENOMEM;
- if (!sig_bf) /* No free buffer available */
- goto out;
- bf = wl3501_get_tx_buffer(this, len + 26 + 24);
- if (!bf) {
- /* No free buffer available */
- wl3501_free_tx_buffer(this, sig_bf);
- goto out;
- }
- rc = 0;
- memcpy(&sig.addr, pdata, sig_addr_len);
- pktlen = len - sig_addr_len;
- pdata += sig_addr_len;
- sig.data = bf;
- if (((*pdata) * 256 + (*(pdata + 1))) > 1500) {
- u8 addr4[ETH_ALEN] = {
- [0] = 0xAA, [1] = 0xAA, [2] = 0x03, [4] = 0x00,
- };
-
- wl3501_set_to_wla(this, bf + 2 +
- offsetof(struct wl3501_tx_hdr, addr4),
- addr4, sizeof(addr4));
- sig.size = pktlen + 24 + 4 + 6;
- if (pktlen > (254 - sizeof(struct wl3501_tx_hdr))) {
- tmplen = 254 - sizeof(struct wl3501_tx_hdr);
- pktlen -= tmplen;
- } else {
- tmplen = pktlen;
- pktlen = 0;
- }
- wl3501_set_to_wla(this,
- bf + 2 + sizeof(struct wl3501_tx_hdr),
- pdata, tmplen);
- pdata += tmplen;
- wl3501_get_from_wla(this, bf, &next, sizeof(next));
- bf = next;
- } else {
- sig.size = pktlen + 24 + 4 - 2;
- pdata += 2;
- pktlen -= 2;
- if (pktlen > (254 - sizeof(struct wl3501_tx_hdr) + 6)) {
- tmplen = 254 - sizeof(struct wl3501_tx_hdr) + 6;
- pktlen -= tmplen;
- } else {
- tmplen = pktlen;
- pktlen = 0;
- }
- wl3501_set_to_wla(this, bf + 2 +
- offsetof(struct wl3501_tx_hdr, addr4),
- pdata, tmplen);
- pdata += tmplen;
- wl3501_get_from_wla(this, bf, &next, sizeof(next));
- bf = next;
- }
- while (pktlen > 0) {
- if (pktlen > 254) {
- tmplen = 254;
- pktlen -= 254;
- } else {
- tmplen = pktlen;
- pktlen = 0;
- }
- wl3501_set_to_wla(this, bf + 2, pdata, tmplen);
- pdata += tmplen;
- wl3501_get_from_wla(this, bf, &next, sizeof(next));
- bf = next;
- }
- wl3501_set_to_wla(this, sig_bf, &sig, sizeof(sig));
- wl3501_esbq_req(this, &sig_bf);
- }
-out:
- return rc;
-}
-
-static int wl3501_mgmt_resync(struct wl3501_card *this)
-{
- struct wl3501_resync_req sig = {
- .sig_id = WL3501_SIG_RESYNC_REQ,
- };
-
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static inline int wl3501_fw_bss_type(struct wl3501_card *this)
-{
- return this->net_type == IW_MODE_INFRA ? WL3501_NET_TYPE_INFRA :
- WL3501_NET_TYPE_ADHOC;
-}
-
-static inline int wl3501_fw_cap_info(struct wl3501_card *this)
-{
- return this->net_type == IW_MODE_INFRA ? WL3501_MGMT_CAPABILITY_ESS :
- WL3501_MGMT_CAPABILITY_IBSS;
-}
-
-static int wl3501_mgmt_scan(struct wl3501_card *this, u16 chan_time)
-{
- struct wl3501_scan_req sig = {
- .sig_id = WL3501_SIG_SCAN_REQ,
- .scan_type = WL3501_SCAN_TYPE_ACTIVE,
- .probe_delay = 0x10,
- .min_chan_time = chan_time,
- .max_chan_time = chan_time,
- .bss_type = wl3501_fw_bss_type(this),
- };
-
- this->bss_cnt = this->join_sta_bss = 0;
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static int wl3501_mgmt_join(struct wl3501_card *this, u16 stas)
-{
- struct wl3501_join_req sig = {
- .sig_id = WL3501_SIG_JOIN_REQ,
- .timeout = 10,
- .req.ds_pset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
- .len = 1,
- },
- .chan = this->chan,
- },
- };
-
- memcpy(&sig.req, &this->bss_set[stas].req, sizeof(sig.req));
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static int wl3501_mgmt_start(struct wl3501_card *this)
-{
- struct wl3501_start_req sig = {
- .sig_id = WL3501_SIG_START_REQ,
- .beacon_period = 400,
- .dtim_period = 1,
- .ds_pset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_DS_PARAMETER_SET,
- .len = 1,
- },
- .chan = this->chan,
- },
- .bss_basic_rset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES,
- .len = 2,
- },
- .data_rate_labels = {
- [0] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_1MBIT,
- [1] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_2MBIT,
- },
- },
- .operational_rset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_SUPPORTED_RATES,
- .len = 2,
- },
- .data_rate_labels = {
- [0] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_1MBIT,
- [1] = IW_MGMT_RATE_LABEL_MANDATORY |
- IW_MGMT_RATE_LABEL_2MBIT,
- },
- },
- .ibss_pset = {
- .el = {
- .id = IW_MGMT_INFO_ELEMENT_IBSS_PARAMETER_SET,
- .len = 2,
- },
- .atim_window = 10,
- },
- .bss_type = wl3501_fw_bss_type(this),
- .cap_info = wl3501_fw_cap_info(this),
- };
-
- iw_copy_mgmt_info_element(&sig.ssid.el, &this->essid.el);
- iw_copy_mgmt_info_element(&this->keep_essid.el, &this->essid.el);
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static void wl3501_mgmt_scan_confirm(struct wl3501_card *this, u16 addr)
-{
- u16 i = 0;
- int matchflag = 0;
- struct wl3501_scan_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- if (sig.status == WL3501_STATUS_SUCCESS) {
- pr_debug("success");
- if ((this->net_type == IW_MODE_INFRA &&
- (sig.req.cap_info & WL3501_MGMT_CAPABILITY_ESS)) ||
- (this->net_type == IW_MODE_ADHOC &&
- (sig.req.cap_info & WL3501_MGMT_CAPABILITY_IBSS)) ||
- this->net_type == IW_MODE_AUTO) {
- if (!this->essid.el.len)
- matchflag = 1;
- else if (this->essid.el.len == 3 &&
- !memcmp(this->essid.essid, "ANY", 3))
- matchflag = 1;
- else if (this->essid.el.len != sig.req.ssid.el.len)
- matchflag = 0;
- else if (memcmp(this->essid.essid, sig.req.ssid.essid,
- this->essid.el.len))
- matchflag = 0;
- else
- matchflag = 1;
- if (matchflag) {
- for (i = 0; i < this->bss_cnt; i++) {
- if (ether_addr_equal_unaligned(this->bss_set[i].req.bssid,
- sig.req.bssid)) {
- matchflag = 0;
- break;
- }
- }
- }
- if (matchflag && (i < 20)) {
- memcpy(&this->bss_set[i].req,
- &sig.req, sizeof(sig.req));
- this->bss_cnt++;
- this->rssi = sig.rssi;
- this->bss_set[i].rssi = sig.rssi;
- }
- }
- } else if (sig.status == WL3501_STATUS_TIMEOUT) {
- pr_debug("timeout");
- this->join_sta_bss = 0;
- for (i = this->join_sta_bss; i < this->bss_cnt; i++)
- if (!wl3501_mgmt_join(this, i))
- break;
- this->join_sta_bss = i;
- if (this->join_sta_bss == this->bss_cnt) {
- if (this->net_type == IW_MODE_INFRA)
- wl3501_mgmt_scan(this, 100);
- else {
- this->adhoc_times++;
- if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES)
- wl3501_mgmt_start(this);
- else
- wl3501_mgmt_scan(this, 100);
- }
- }
- }
-}
-
-/**
- * wl3501_block_interrupt - Mask interrupt from SUTRO
- * @this: Card
- *
- * Mask interrupt from SUTRO. (i.e. SUTRO cannot interrupt the HOST)
- * Return: 1 if interrupt is originally enabled
- */
-static int wl3501_block_interrupt(struct wl3501_card *this)
-{
- u8 old = inb(this->base_addr + WL3501_NIC_GCR);
- u8 new = old & (~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC |
- WL3501_GCR_ENECINT));
-
- wl3501_outb(new, this->base_addr + WL3501_NIC_GCR);
- return old & WL3501_GCR_ENECINT;
-}
-
-/**
- * wl3501_unblock_interrupt - Enable interrupt from SUTRO
- * @this: Card
- *
- * Enable interrupt from SUTRO. (i.e. SUTRO can interrupt the HOST)
- * Return: 1 if interrupt is originally enabled
- */
-static int wl3501_unblock_interrupt(struct wl3501_card *this)
-{
- u8 old = inb(this->base_addr + WL3501_NIC_GCR);
- u8 new = (old & ~(WL3501_GCR_ECINT | WL3501_GCR_INT2EC)) |
- WL3501_GCR_ENECINT;
-
- wl3501_outb(new, this->base_addr + WL3501_NIC_GCR);
- return old & WL3501_GCR_ENECINT;
-}
-
-/**
- * wl3501_receive - Receive data from Receive Queue.
- *
- * Receive data from Receive Queue.
- *
- * @this: card
- * @bf: address of host
- * @size: size of buffer.
- */
-static u16 wl3501_receive(struct wl3501_card *this, u8 *bf, u16 size)
-{
- u16 next_addr, next_addr1;
- u8 *data = bf + 12;
-
- size -= 12;
- wl3501_get_from_wla(this, this->start_seg + 2,
- &next_addr, sizeof(next_addr));
- if (size > WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr)) {
- wl3501_get_from_wla(this,
- this->start_seg +
- sizeof(struct wl3501_rx_hdr), data,
- WL3501_BLKSZ -
- sizeof(struct wl3501_rx_hdr));
- size -= WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr);
- data += WL3501_BLKSZ - sizeof(struct wl3501_rx_hdr);
- } else {
- wl3501_get_from_wla(this,
- this->start_seg +
- sizeof(struct wl3501_rx_hdr),
- data, size);
- size = 0;
- }
- while (size > 0) {
- if (size > WL3501_BLKSZ - 5) {
- wl3501_get_from_wla(this, next_addr + 5, data,
- WL3501_BLKSZ - 5);
- size -= WL3501_BLKSZ - 5;
- data += WL3501_BLKSZ - 5;
- wl3501_get_from_wla(this, next_addr + 2, &next_addr1,
- sizeof(next_addr1));
- next_addr = next_addr1;
- } else {
- wl3501_get_from_wla(this, next_addr + 5, data, size);
- size = 0;
- }
- }
- return 0;
-}
-
-static void wl3501_esbq_req_free(struct wl3501_card *this)
-{
- u8 tmp;
- u16 addr;
-
- if (this->esbq_req_head == this->esbq_req_tail)
- goto out;
- wl3501_get_from_wla(this, this->esbq_req_tail + 3, &tmp, sizeof(tmp));
- if (!(tmp & 0x80))
- goto out;
- wl3501_get_from_wla(this, this->esbq_req_tail, &addr, sizeof(addr));
- wl3501_free_tx_buffer(this, addr);
- this->esbq_req_tail += 4;
- if (this->esbq_req_tail >= this->esbq_req_end)
- this->esbq_req_tail = this->esbq_req_start;
-out:
- return;
-}
-
-static int wl3501_esbq_confirm(struct wl3501_card *this)
-{
- u8 tmp;
-
- wl3501_get_from_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp));
- return tmp & 0x80;
-}
-
-static void wl3501_online(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n",
- dev->name, this->bssid);
- netif_wake_queue(dev);
-}
-
-static void wl3501_esbq_confirm_done(struct wl3501_card *this)
-{
- u8 tmp = 0;
-
- wl3501_set_to_wla(this, this->esbq_confirm + 3, &tmp, sizeof(tmp));
- this->esbq_confirm += 4;
- if (this->esbq_confirm >= this->esbq_confirm_end)
- this->esbq_confirm = this->esbq_confirm_start;
-}
-
-static int wl3501_mgmt_auth(struct wl3501_card *this)
-{
- struct wl3501_auth_req sig = {
- .sig_id = WL3501_SIG_AUTH_REQ,
- .type = WL3501_SYS_TYPE_OPEN,
- .timeout = 1000,
- };
-
- pr_debug("entry");
- memcpy(sig.mac_addr, this->bssid, ETH_ALEN);
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static int wl3501_mgmt_association(struct wl3501_card *this)
-{
- struct wl3501_assoc_req sig = {
- .sig_id = WL3501_SIG_ASSOC_REQ,
- .timeout = 1000,
- .listen_interval = 5,
- .cap_info = this->cap_info,
- };
-
- pr_debug("entry");
- memcpy(sig.mac_addr, this->bssid, ETH_ALEN);
- return wl3501_esbq_exec(this, &sig, sizeof(sig));
-}
-
-static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
-{
- struct wl3501_card *this = netdev_priv(dev);
- struct wl3501_join_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- if (sig.status == WL3501_STATUS_SUCCESS) {
- if (this->net_type == IW_MODE_INFRA) {
- if (this->join_sta_bss < this->bss_cnt) {
- const int i = this->join_sta_bss;
- memcpy(this->bssid,
- this->bss_set[i].req.bssid, ETH_ALEN);
- this->chan = this->bss_set[i].req.ds_pset.chan;
- iw_copy_mgmt_info_element(&this->keep_essid.el,
- &this->bss_set[i].req.ssid.el);
- wl3501_mgmt_auth(this);
- }
- } else {
- const int i = this->join_sta_bss;
-
- memcpy(&this->bssid, &this->bss_set[i].req.bssid, ETH_ALEN);
- this->chan = this->bss_set[i].req.ds_pset.chan;
- iw_copy_mgmt_info_element(&this->keep_essid.el,
- &this->bss_set[i].req.ssid.el);
- wl3501_online(dev);
- }
- } else {
- int i;
- this->join_sta_bss++;
- for (i = this->join_sta_bss; i < this->bss_cnt; i++)
- if (!wl3501_mgmt_join(this, i))
- break;
- this->join_sta_bss = i;
- if (this->join_sta_bss == this->bss_cnt) {
- if (this->net_type == IW_MODE_INFRA)
- wl3501_mgmt_scan(this, 100);
- else {
- this->adhoc_times++;
- if (this->adhoc_times > WL3501_MAX_ADHOC_TRIES)
- wl3501_mgmt_start(this);
- else
- wl3501_mgmt_scan(this, 100);
- }
- }
- }
-}
-
-static inline void wl3501_alarm_interrupt(struct net_device *dev,
- struct wl3501_card *this)
-{
- if (this->net_type == IW_MODE_INFRA) {
- printk(KERN_INFO "Wireless LAN offline\n");
- netif_stop_queue(dev);
- wl3501_mgmt_resync(this);
- }
-}
-
-static inline void wl3501_md_confirm_interrupt(struct net_device *dev,
- struct wl3501_card *this,
- u16 addr)
-{
- struct wl3501_md_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- wl3501_free_tx_buffer(this, sig.data);
- if (netif_queue_stopped(dev))
- netif_wake_queue(dev);
-}
-
-static inline void wl3501_md_ind_interrupt(struct net_device *dev,
- struct wl3501_card *this, u16 addr)
-{
- struct wl3501_md_ind sig;
- struct sk_buff *skb;
- u8 rssi, addr4[ETH_ALEN];
- u16 pkt_len;
-
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- this->start_seg = sig.data;
- wl3501_get_from_wla(this,
- sig.data + offsetof(struct wl3501_rx_hdr, rssi),
- &rssi, sizeof(rssi));
- this->rssi = rssi <= 63 ? (rssi * 100) / 64 : 255;
-
- wl3501_get_from_wla(this,
- sig.data +
- offsetof(struct wl3501_rx_hdr, addr4),
- &addr4, sizeof(addr4));
- if (!(addr4[0] == 0xAA && addr4[1] == 0xAA &&
- addr4[2] == 0x03 && addr4[4] == 0x00)) {
- printk(KERN_INFO "Unsupported packet type!\n");
- return;
- }
- pkt_len = sig.size + 12 - 24 - 4 - 6;
-
- skb = dev_alloc_skb(pkt_len + 5);
-
- if (!skb) {
- printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n",
- dev->name, pkt_len);
- dev->stats.rx_dropped++;
- } else {
- skb->dev = dev;
- skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */
- skb_copy_to_linear_data(skb, (unsigned char *)&sig.addr,
- sizeof(sig.addr));
- wl3501_receive(this, skb->data, pkt_len);
- skb_put(skb, pkt_len);
- skb->protocol = eth_type_trans(skb, dev);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- netif_rx(skb);
- }
-}
-
-static inline void wl3501_get_confirm_interrupt(struct wl3501_card *this,
- u16 addr, void *sig, int size)
-{
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &this->sig_get_confirm,
- sizeof(this->sig_get_confirm));
- wake_up(&this->wait);
-}
-
-static inline void wl3501_start_confirm_interrupt(struct net_device *dev,
- struct wl3501_card *this,
- u16 addr)
-{
- struct wl3501_start_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
- if (sig.status == WL3501_STATUS_SUCCESS)
- netif_wake_queue(dev);
-}
-
-static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev,
- u16 addr)
-{
- struct wl3501_card *this = netdev_priv(dev);
- struct wl3501_assoc_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
-
- if (sig.status == WL3501_STATUS_SUCCESS)
- wl3501_online(dev);
-}
-
-static inline void wl3501_auth_confirm_interrupt(struct wl3501_card *this,
- u16 addr)
-{
- struct wl3501_auth_confirm sig;
-
- pr_debug("entry");
- wl3501_get_from_wla(this, addr, &sig, sizeof(sig));
-
- if (sig.status == WL3501_STATUS_SUCCESS)
- wl3501_mgmt_association(this);
- else
- wl3501_mgmt_resync(this);
-}
-
-static inline void wl3501_rx_interrupt(struct net_device *dev)
-{
- int morepkts;
- u16 addr;
- u8 sig_id;
- struct wl3501_card *this = netdev_priv(dev);
-
- pr_debug("entry");
-loop:
- morepkts = 0;
- if (!wl3501_esbq_confirm(this))
- goto free;
- wl3501_get_from_wla(this, this->esbq_confirm, &addr, sizeof(addr));
- wl3501_get_from_wla(this, addr + 2, &sig_id, sizeof(sig_id));
-
- switch (sig_id) {
- case WL3501_SIG_DEAUTH_IND:
- case WL3501_SIG_DISASSOC_IND:
- case WL3501_SIG_ALARM:
- wl3501_alarm_interrupt(dev, this);
- break;
- case WL3501_SIG_MD_CONFIRM:
- wl3501_md_confirm_interrupt(dev, this, addr);
- break;
- case WL3501_SIG_MD_IND:
- wl3501_md_ind_interrupt(dev, this, addr);
- break;
- case WL3501_SIG_GET_CONFIRM:
- wl3501_get_confirm_interrupt(this, addr,
- &this->sig_get_confirm,
- sizeof(this->sig_get_confirm));
- break;
- case WL3501_SIG_PWR_MGMT_CONFIRM:
- wl3501_get_confirm_interrupt(this, addr,
- &this->sig_pwr_mgmt_confirm,
- sizeof(this->sig_pwr_mgmt_confirm));
- break;
- case WL3501_SIG_START_CONFIRM:
- wl3501_start_confirm_interrupt(dev, this, addr);
- break;
- case WL3501_SIG_SCAN_CONFIRM:
- wl3501_mgmt_scan_confirm(this, addr);
- break;
- case WL3501_SIG_JOIN_CONFIRM:
- wl3501_mgmt_join_confirm(dev, addr);
- break;
- case WL3501_SIG_ASSOC_CONFIRM:
- wl3501_assoc_confirm_interrupt(dev, addr);
- break;
- case WL3501_SIG_AUTH_CONFIRM:
- wl3501_auth_confirm_interrupt(this, addr);
- break;
- case WL3501_SIG_RESYNC_CONFIRM:
- wl3501_mgmt_resync(this); /* FIXME: should be resync_confirm */
- break;
- }
- wl3501_esbq_confirm_done(this);
- morepkts = 1;
- /* free request if necessary */
-free:
- wl3501_esbq_req_free(this);
- if (morepkts)
- goto loop;
-}
-
-static inline void wl3501_ack_interrupt(struct wl3501_card *this)
-{
- wl3501_outb(WL3501_GCR_ECINT, this->base_addr + WL3501_NIC_GCR);
-}
-
-/**
- * wl3501_interrupt - Hardware interrupt from card.
- * @irq: Interrupt number
- * @dev_id: net_device
- *
- * We must acknowledge the interrupt as soon as possible, and block the
- * interrupt from the same card immediately to prevent re-entry.
- *
- * Before accessing the Control_Status_Block, we must lock SUTRO first.
- * On the other hand, to prevent SUTRO from malfunctioning, we must
- * unlock the SUTRO as soon as possible.
- */
-static irqreturn_t wl3501_interrupt(int irq, void *dev_id)
-{
- struct net_device *dev = dev_id;
- struct wl3501_card *this;
-
- this = netdev_priv(dev);
- spin_lock(&this->lock);
- wl3501_ack_interrupt(this);
- wl3501_block_interrupt(this);
- wl3501_rx_interrupt(dev);
- wl3501_unblock_interrupt(this);
- spin_unlock(&this->lock);
-
- return IRQ_HANDLED;
-}
-
-static int wl3501_reset_board(struct wl3501_card *this)
-{
- u8 tmp = 0;
- int i, rc = 0;
-
- /* Coreset */
- wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR);
- wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR);
- wl3501_outb_p(WL3501_GCR_CORESET, this->base_addr + WL3501_NIC_GCR);
-
- /* Reset SRAM 0x480 to zero */
- wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp));
-
- /* Start up */
- wl3501_outb_p(0, this->base_addr + WL3501_NIC_GCR);
-
- WL3501_NOPLOOP(1024 * 50);
-
- wl3501_unblock_interrupt(this); /* acme: was commented */
-
- /* Polling Self_Test_Status */
- for (i = 0; i < 10000; i++) {
- wl3501_get_from_wla(this, 0x480, &tmp, sizeof(tmp));
-
- if (tmp == 'W') {
- /* firmware complete all test successfully */
- tmp = 'A';
- wl3501_set_to_wla(this, 0x480, &tmp, sizeof(tmp));
- goto out;
- }
- WL3501_NOPLOOP(10);
- }
- printk(KERN_WARNING "%s: failed to reset the board!\n", __func__);
- rc = -ENODEV;
-out:
- return rc;
-}
-
-static int wl3501_init_firmware(struct wl3501_card *this)
-{
- u16 ptr, next;
- int rc = wl3501_reset_board(this);
-
- if (rc)
- goto fail;
- this->card_name[0] = '\0';
- wl3501_get_from_wla(this, 0x1a00,
- this->card_name, sizeof(this->card_name));
- this->card_name[sizeof(this->card_name) - 1] = '\0';
- this->firmware_date[0] = '\0';
- wl3501_get_from_wla(this, 0x1a40,
- this->firmware_date, sizeof(this->firmware_date));
- this->firmware_date[sizeof(this->firmware_date) - 1] = '\0';
- /* Switch to SRAM Page 0 */
- wl3501_switch_page(this, WL3501_BSS_SPAGE0);
- /* Read parameter from card */
- wl3501_get_from_wla(this, 0x482, &this->esbq_req_start, 2);
- wl3501_get_from_wla(this, 0x486, &this->esbq_req_end, 2);
- wl3501_get_from_wla(this, 0x488, &this->esbq_confirm_start, 2);
- wl3501_get_from_wla(this, 0x48c, &this->esbq_confirm_end, 2);
- wl3501_get_from_wla(this, 0x48e, &this->tx_buffer_head, 2);
- wl3501_get_from_wla(this, 0x492, &this->tx_buffer_size, 2);
- this->esbq_req_tail = this->esbq_req_head = this->esbq_req_start;
- this->esbq_req_end += this->esbq_req_start;
- this->esbq_confirm = this->esbq_confirm_start;
- this->esbq_confirm_end += this->esbq_confirm_start;
- /* Initial Tx Buffer */
- this->tx_buffer_cnt = 1;
- ptr = this->tx_buffer_head;
- next = ptr + WL3501_BLKSZ;
- while ((next - this->tx_buffer_head) < this->tx_buffer_size) {
- this->tx_buffer_cnt++;
- wl3501_set_to_wla(this, ptr, &next, sizeof(next));
- ptr = next;
- next = ptr + WL3501_BLKSZ;
- }
- rc = 0;
- next = 0;
- wl3501_set_to_wla(this, ptr, &next, sizeof(next));
- this->tx_buffer_tail = ptr;
-out:
- return rc;
-fail:
- printk(KERN_WARNING "%s: failed!\n", __func__);
- goto out;
-}
-
-static int wl3501_close(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
- struct pcmcia_device *link;
- link = this->p_dev;
-
- spin_lock_irqsave(&this->lock, flags);
- link->open--;
-
- /* Stop wl3501_hard_start_xmit() from now on */
- netif_stop_queue(dev);
- wl3501_ack_interrupt(this);
-
- /* Mask interrupts from the SUTRO */
- wl3501_block_interrupt(this);
-
- printk(KERN_INFO "%s: WL3501 closed\n", dev->name);
- spin_unlock_irqrestore(&this->lock, flags);
- return 0;
-}
-
-/**
- * wl3501_reset - Reset the SUTRO.
- * @dev: network device
- *
- * It is almost the same as wl3501_open(). In fact, we may just wl3501_close()
- * and wl3501_open() again, but I wouldn't like to free_irq() when the driver
- * is running. It seems to be dangerous.
- */
-static int wl3501_reset(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int rc = -ENODEV;
- unsigned long flags;
-
- spin_lock_irqsave(&this->lock, flags);
- wl3501_block_interrupt(this);
-
- if (wl3501_init_firmware(this)) {
- printk(KERN_WARNING "%s: Can't initialize Firmware!\n",
- dev->name);
- /* Free IRQ, and mark IRQ as unused */
- free_irq(dev->irq, dev);
- goto out;
- }
-
- /*
- * Queue has to be started only when the Card is Started
- */
- netif_stop_queue(dev);
- this->adhoc_times = 0;
- wl3501_ack_interrupt(this);
- wl3501_unblock_interrupt(this);
- wl3501_mgmt_scan(this, 100);
- pr_debug("%s: device reset", dev->name);
- rc = 0;
-out:
- spin_unlock_irqrestore(&this->lock, flags);
- return rc;
-}
-
-static void wl3501_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct net_device_stats *stats = &dev->stats;
- int rc;
-
- stats->tx_errors++;
- rc = wl3501_reset(dev);
- if (rc)
- printk(KERN_ERR "%s: Error %d resetting card on Tx timeout!\n",
- dev->name, rc);
- else {
- netif_trans_update(dev); /* prevent tx timeout */
- netif_wake_queue(dev);
- }
-}
-
-/*
- * Return : 0 - OK
- * 1 - Could not transmit (dev_queue_xmit will queue it)
- * and try to sent it later
- */
-static netdev_tx_t wl3501_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- int enabled, rc;
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&this->lock, flags);
- enabled = wl3501_block_interrupt(this);
- rc = wl3501_send_pkt(this, skb->data, skb->len);
- if (enabled)
- wl3501_unblock_interrupt(this);
- if (rc) {
- ++dev->stats.tx_dropped;
- netif_stop_queue(dev);
- } else {
- ++dev->stats.tx_packets;
- dev->stats.tx_bytes += skb->len;
- dev_kfree_skb_irq(skb);
-
- if (this->tx_buffer_cnt < 2)
- netif_stop_queue(dev);
- }
- spin_unlock_irqrestore(&this->lock, flags);
- return NETDEV_TX_OK;
-}
-
-static int wl3501_open(struct net_device *dev)
-{
- int rc = -ENODEV;
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
- struct pcmcia_device *link;
- link = this->p_dev;
-
- spin_lock_irqsave(&this->lock, flags);
- if (!pcmcia_dev_present(link))
- goto out;
- netif_device_attach(dev);
- link->open++;
-
- /* Initial WL3501 firmware */
- pr_debug("%s: Initialize WL3501 firmware...", dev->name);
- if (wl3501_init_firmware(this))
- goto fail;
- /* Initial device variables */
- this->adhoc_times = 0;
- /* Acknowledge Interrupt, for cleaning last state */
- wl3501_ack_interrupt(this);
-
- /* Enable interrupt from card after all */
- wl3501_unblock_interrupt(this);
- wl3501_mgmt_scan(this, 100);
- rc = 0;
- pr_debug("%s: WL3501 opened", dev->name);
- printk(KERN_INFO "%s: Card Name: %s\n"
- "%s: Firmware Date: %s\n",
- dev->name, this->card_name,
- dev->name, this->firmware_date);
-out:
- spin_unlock_irqrestore(&this->lock, flags);
- return rc;
-fail:
- printk(KERN_WARNING "%s: Can't initialize firmware!\n", dev->name);
- goto out;
-}
-
-static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
-{
- struct wl3501_card *this = netdev_priv(dev);
- struct iw_statistics *wstats = &this->wstats;
- u32 value; /* size checked: it is u32 */
-
- memset(wstats, 0, sizeof(*wstats));
- wstats->status = netif_running(dev);
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_ICV_ERROR_COUNT,
- &value, sizeof(value)))
- wstats->discard.code += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_UNDECRYPTABLE_COUNT,
- &value, sizeof(value)))
- wstats->discard.code += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_EXCLUDED_COUNT,
- &value, sizeof(value)))
- wstats->discard.code += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RETRY_COUNT,
- &value, sizeof(value)))
- wstats->discard.retries = value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FAILED_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_FAILURE_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_ACK_FAILURE_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- if (!wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAME_DUPLICATE_COUNT,
- &value, sizeof(value)))
- wstats->discard.misc += value;
- return wstats;
-}
-
-/**
- * wl3501_detach - deletes a driver "instance"
- * @link: FILL_IN
- *
- * This deletes a driver "instance". The device is de-registered with Card
- * Services. If it has been released, all local data structures are freed.
- * Otherwise, the structures will be freed when the device is released.
- */
-static void wl3501_detach(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- /* If the device is currently configured and active, we won't actually
- * delete it yet. Instead, it is marked so that when the release()
- * function is called, that will trigger a proper detach(). */
-
- while (link->open > 0)
- wl3501_close(dev);
-
- netif_device_detach(dev);
- wl3501_release(link);
-
- unregister_netdev(dev);
- free_netdev(dev);
-}
-
-static int wl3501_get_name(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- strscpy(wrqu->name, "IEEE 802.11-DS", sizeof(wrqu->name));
- return 0;
-}
-
-static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int channel = wrqu->freq.m;
- int rc = -EINVAL;
-
- if (iw_valid_channel(this->reg_domain, channel)) {
- this->chan = channel;
- rc = wl3501_reset(dev);
- }
- return rc;
-}
-
-static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->freq.m = 100000 *
- ieee80211_channel_to_frequency(this->chan, NL80211_BAND_2GHZ);
- wrqu->freq.e = 1;
- return 0;
-}
-
-static int wl3501_set_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- int rc = -EINVAL;
-
- if (wrqu->mode == IW_MODE_INFRA ||
- wrqu->mode == IW_MODE_ADHOC ||
- wrqu->mode == IW_MODE_AUTO) {
- struct wl3501_card *this = netdev_priv(dev);
-
- this->net_type = wrqu->mode;
- rc = wl3501_reset(dev);
- }
- return rc;
-}
-
-static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->mode = this->net_type;
- return 0;
-}
-
-static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->sens.value = this->rssi;
- wrqu->sens.disabled = !wrqu->sens.value;
- wrqu->sens.fixed = 1;
- return 0;
-}
-
-static int wl3501_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_range *range = (struct iw_range *)extra;
-
- /* Set the length (very important for backward compatibility) */
- wrqu->data.length = sizeof(*range);
-
- /* Set all the info we don't care or don't know about to zero */
- memset(range, 0, sizeof(*range));
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 1;
- range->throughput = 2 * 1000 * 1000; /* ~2 Mb/s */
- /* FIXME: study the code to fill in more fields... */
- return 0;
-}
-
-static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int rc = -EINVAL;
-
- /* FIXME: we support other ARPHRDs...*/
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- goto out;
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data)) {
- /* FIXME: rescan? */
- } else
- memcpy(this->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
- /* FIXME: rescan? deassoc & scan? */
- rc = 0;
-out:
- return rc;
-}
-
-static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN);
- return 0;
-}
-
-static int wl3501_set_scan(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * FIXME: trigger scanning with a reset, yes, I'm lazy
- */
- return wl3501_reset(dev);
-}
-
-static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- int i;
- char *current_ev = extra;
- struct iw_event iwe;
-
- for (i = 0; i < this->bss_cnt; ++i) {
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, this->bss_set[i].req.bssid, ETH_ALEN);
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_ADDR_LEN);
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- iwe.u.data.length = this->bss_set[i].req.ssid.el.len;
- current_ev = iwe_stream_add_point(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe,
- this->bss_set[i].req.ssid.essid);
- iwe.cmd = SIOCGIWMODE;
- iwe.u.mode = this->bss_set[i].req.bss_type;
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_UINT_LEN);
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = this->bss_set[i].req.ds_pset.chan;
- iwe.u.freq.e = 0;
- current_ev = iwe_stream_add_event(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, IW_EV_FREQ_LEN);
- iwe.cmd = SIOCGIWENCODE;
- if (this->bss_set[i].req.cap_info & WL3501_MGMT_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- current_ev = iwe_stream_add_point(info, current_ev,
- extra + IW_SCAN_MAX_DATA,
- &iwe, NULL);
- }
- /* Length of data */
- wrqu->data.length = (current_ev - extra);
- wrqu->data.flags = 0; /* FIXME: set properly these flags */
- return 0;
-}
-
-static int wl3501_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- if (wrqu->data.flags) {
- iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
- &this->essid.el,
- extra, wrqu->data.length);
- } else { /* We accept any ESSID */
- iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
- &this->essid.el, "ANY", 3);
- }
- return wl3501_reset(dev);
-}
-
-static int wl3501_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&this->lock, flags);
- wrqu->essid.flags = 1;
- wrqu->essid.length = this->essid.el.len;
- memcpy(extra, this->essid.essid, this->essid.el.len);
- spin_unlock_irqrestore(&this->lock, flags);
- return 0;
-}
-
-static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- if (wrqu->data.length > sizeof(this->nick))
- return -E2BIG;
- strscpy(this->nick, extra, wrqu->data.length);
- return 0;
-}
-
-static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct wl3501_card *this = netdev_priv(dev);
-
- strscpy(extra, this->nick, 32);
- wrqu->data.length = strlen(extra);
- return 0;
-}
-
-static int wl3501_get_rate(struct net_device *dev, struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * FIXME: have to see from where to get this info, perhaps this card
- * works at 1 Mbit/s too... for now leave at 2 Mbit/s that is the most
- * common with the Planet Access Points. -acme
- */
- wrqu->bitrate.value = 2000000;
- wrqu->bitrate.fixed = 1;
- return 0;
-}
-
-static int wl3501_get_rts_threshold(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD,
- &threshold, sizeof(threshold));
- if (!rc) {
- wrqu->rts.value = threshold;
- wrqu->rts.disabled = threshold >= 2347;
- wrqu->rts.fixed = 1;
- }
- return rc;
-}
-
-static int wl3501_get_frag_threshold(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u16 threshold; /* size checked: it is u16 */
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD,
- &threshold, sizeof(threshold));
- if (!rc) {
- wrqu->frag.value = threshold;
- wrqu->frag.disabled = threshold >= 2346;
- wrqu->frag.fixed = 1;
- }
- return rc;
-}
-
-static int wl3501_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u16 txpow;
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,
- &txpow, sizeof(txpow));
- if (!rc) {
- wrqu->txpower.value = txpow;
- wrqu->txpower.disabled = 0;
- /*
- * From the MIB values I think this can be configurable,
- * as it lists several tx power levels -acme
- */
- wrqu->txpower.fixed = 0;
- wrqu->txpower.flags = IW_TXPOW_MWATT;
- }
- return rc;
-}
-
-static int wl3501_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 retry; /* size checked: it is u8 */
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_LONG_RETRY_LIMIT,
- &retry, sizeof(retry));
- if (rc)
- goto out;
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- goto set_value;
- }
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
- &retry, sizeof(retry));
- if (rc)
- goto out;
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
-set_value:
- wrqu->retry.value = retry;
- wrqu->retry.disabled = 0;
-out:
- return rc;
-}
-
-static int wl3501_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 implemented, restricted, keys[100], len_keys, tocopy;
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,
- &implemented, sizeof(implemented));
- if (rc)
- goto out;
- if (!implemented) {
- wrqu->encoding.flags = IW_ENCODE_DISABLED;
- goto out;
- }
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_EXCLUDE_UNENCRYPTED,
- &restricted, sizeof(restricted));
- if (rc)
- goto out;
- wrqu->encoding.flags = restricted ? IW_ENCODE_RESTRICTED :
- IW_ENCODE_OPEN;
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS_LEN,
- &len_keys, sizeof(len_keys));
- if (rc)
- goto out;
- rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_WEP_KEY_MAPPINGS,
- keys, len_keys);
- if (rc)
- goto out;
- tocopy = min_t(u16, len_keys, wrqu->encoding.length);
- tocopy = min_t(u8, tocopy, 100);
- wrqu->encoding.length = tocopy;
- memcpy(extra, keys, tocopy);
-out:
- return rc;
-}
-
-static int wl3501_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- u8 pwr_state;
- struct wl3501_card *this = netdev_priv(dev);
- int rc = wl3501_get_mib_value(this,
- WL3501_MIB_ATTR_CURRENT_PWR_STATE,
- &pwr_state, sizeof(pwr_state));
- if (rc)
- goto out;
- wrqu->power.disabled = !pwr_state;
- wrqu->power.flags = IW_POWER_ON;
-out:
- return rc;
-}
-
-static const iw_handler wl3501_handler[] = {
- IW_HANDLER(SIOCGIWNAME, wl3501_get_name),
- IW_HANDLER(SIOCSIWFREQ, wl3501_set_freq),
- IW_HANDLER(SIOCGIWFREQ, wl3501_get_freq),
- IW_HANDLER(SIOCSIWMODE, wl3501_set_mode),
- IW_HANDLER(SIOCGIWMODE, wl3501_get_mode),
- IW_HANDLER(SIOCGIWSENS, wl3501_get_sens),
- IW_HANDLER(SIOCGIWRANGE, wl3501_get_range),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWAP, wl3501_set_wap),
- IW_HANDLER(SIOCGIWAP, wl3501_get_wap),
- IW_HANDLER(SIOCSIWSCAN, wl3501_set_scan),
- IW_HANDLER(SIOCGIWSCAN, wl3501_get_scan),
- IW_HANDLER(SIOCSIWESSID, wl3501_set_essid),
- IW_HANDLER(SIOCGIWESSID, wl3501_get_essid),
- IW_HANDLER(SIOCSIWNICKN, wl3501_set_nick),
- IW_HANDLER(SIOCGIWNICKN, wl3501_get_nick),
- IW_HANDLER(SIOCGIWRATE, wl3501_get_rate),
- IW_HANDLER(SIOCGIWRTS, wl3501_get_rts_threshold),
- IW_HANDLER(SIOCGIWFRAG, wl3501_get_frag_threshold),
- IW_HANDLER(SIOCGIWTXPOW, wl3501_get_txpow),
- IW_HANDLER(SIOCGIWRETRY, wl3501_get_retry),
- IW_HANDLER(SIOCGIWENCODE, wl3501_get_encode),
- IW_HANDLER(SIOCGIWPOWER, wl3501_get_power),
-};
-
-static const struct iw_handler_def wl3501_handler_def = {
- .num_standard = ARRAY_SIZE(wl3501_handler),
- .standard = (iw_handler *)wl3501_handler,
- .get_wireless_stats = wl3501_get_wireless_stats,
-};
-
-static const struct net_device_ops wl3501_netdev_ops = {
- .ndo_open = wl3501_open,
- .ndo_stop = wl3501_close,
- .ndo_start_xmit = wl3501_hard_start_xmit,
- .ndo_tx_timeout = wl3501_tx_timeout,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int wl3501_probe(struct pcmcia_device *p_dev)
-{
- struct net_device *dev;
- struct wl3501_card *this;
- int ret;
-
- /* The io structure describes IO port mapping */
- p_dev->resource[0]->end = 16;
- p_dev->resource[0]->flags = IO_DATA_PATH_WIDTH_8;
-
- /* General socket configuration */
- p_dev->config_flags = CONF_ENABLE_IRQ;
- p_dev->config_index = 1;
-
- dev = alloc_etherdev(sizeof(struct wl3501_card));
- if (!dev)
- return -ENOMEM;
-
- dev->netdev_ops = &wl3501_netdev_ops;
- dev->watchdog_timeo = 5 * HZ;
-
- this = netdev_priv(dev);
- this->wireless_data.spy_data = &this->spy_data;
- this->p_dev = p_dev;
- dev->wireless_data = &this->wireless_data;
- dev->wireless_handlers = &wl3501_handler_def;
- netif_stop_queue(dev);
- p_dev->priv = dev;
-
- ret = wl3501_config(p_dev);
- if (ret)
- goto out_free_etherdev;
-
- return 0;
-
-out_free_etherdev:
- free_netdev(dev);
- return ret;
-}
-
-static int wl3501_config(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
- int i = 0, j, ret;
- struct wl3501_card *this;
-
- /* Try allocating IO ports. This tries a few fixed addresses. If you
- * want, you can also read the card's config table to pick addresses --
- * see the serial driver for an example. */
- link->io_lines = 5;
-
- for (j = 0x280; j < 0x400; j += 0x20) {
- /* The '^0x300' is so that we probe 0x300-0x3ff first, then
- * 0x200-0x2ff, and so on, because this seems safer */
- link->resource[0]->start = j;
- link->resource[1]->start = link->resource[0]->start + 0x10;
- i = pcmcia_request_io(link);
- if (i == 0)
- break;
- }
- if (i != 0)
- goto failed;
-
- /* Now allocate an interrupt line. Note that this does not actually
- * assign a handler to the interrupt. */
-
- ret = pcmcia_request_irq(link, wl3501_interrupt);
- if (ret)
- goto failed;
-
- ret = pcmcia_enable_device(link);
- if (ret)
- goto failed;
-
- dev->irq = link->irq;
- dev->base_addr = link->resource[0]->start;
- SET_NETDEV_DEV(dev, &link->dev);
- if (register_netdev(dev)) {
- printk(KERN_NOTICE "wl3501_cs: register_netdev() failed\n");
- goto failed;
- }
-
- this = netdev_priv(dev);
-
- this->base_addr = dev->base_addr;
-
- if (!wl3501_get_flash_mac_addr(this)) {
- printk(KERN_WARNING "%s: Can't read MAC addr in flash ROM?\n",
- dev->name);
- unregister_netdev(dev);
- goto failed;
- }
-
- eth_hw_addr_set(dev, this->mac_addr);
-
- /* print probe information */
- printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, "
- "MAC addr in flash ROM:%pM\n",
- dev->name, this->base_addr, (int)dev->irq,
- dev->dev_addr);
- /*
- * Initialize card parameters - added by jss
- */
- this->net_type = IW_MODE_INFRA;
- this->bss_cnt = 0;
- this->join_sta_bss = 0;
- this->adhoc_times = 0;
- iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID, &this->essid.el,
- "ANY", 3);
- this->card_name[0] = '\0';
- this->firmware_date[0] = '\0';
- this->rssi = 255;
- this->chan = iw_default_channel(this->reg_domain);
- strscpy(this->nick, "Planet WL3501", sizeof(this->nick));
- spin_lock_init(&this->lock);
- init_waitqueue_head(&this->wait);
- netif_start_queue(dev);
- return 0;
-
-failed:
- wl3501_release(link);
- return -ENODEV;
-}
-
-static void wl3501_release(struct pcmcia_device *link)
-{
- pcmcia_disable_device(link);
-}
-
-static int wl3501_suspend(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND);
- if (link->open)
- netif_device_detach(dev);
-
- return 0;
-}
-
-static int wl3501_resume(struct pcmcia_device *link)
-{
- struct net_device *dev = link->priv;
-
- wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME);
- if (link->open) {
- wl3501_reset(dev);
- netif_device_attach(dev);
- }
-
- return 0;
-}
-
-
-static const struct pcmcia_device_id wl3501_ids[] = {
- PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
- PCMCIA_DEVICE_NULL
-};
-MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
-
-static struct pcmcia_driver wl3501_driver = {
- .owner = THIS_MODULE,
- .name = "wl3501_cs",
- .probe = wl3501_probe,
- .remove = wl3501_detach,
- .id_table = wl3501_ids,
- .suspend = wl3501_suspend,
- .resume = wl3501_resume,
-};
-module_pcmcia_driver(wl3501_driver);
-
-MODULE_AUTHOR("Fox Chen <[email protected]>, "
- "Arnaldo Carvalho de Melo <[email protected]>,"
- "Gustavo Niemeyer <[email protected]>");
-MODULE_DESCRIPTION("Planet wl3501 wireless driver");
-MODULE_LICENSE("GPL");
--
2.39.2

2023-10-23 13:23:39

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers

From: Arnd Bergmann <[email protected]>

These two drivers were used for the earliest "Centrino" branded Intel
laptops during the late 32-bit Pentium-M era, roughly 2003 to 2005, which
probably makes it the most modern platform that still uses the wireless
extension interface instead of cfg80211. Unlike the other drivers that
are suggested for removal, this one is still officially maintained.

According to Johannes Berg, there was an effort to finish the move away
from wext in the past, but the last evidence of this that I could find
is from commit a3caa99e6c68f ("libipw: initiate cfg80211 API conversion
(v2)") in 2009.

Link: https://lore.kernel.org/all/[email protected]/
Cc: Stanislav Yakovlev <[email protected]>
Cc: Linux Wireless <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
I'm not convinced this should be in the same set of drivers as the
rest, since this is clearly less obsolete than the other hardware
that I would remove support for.
---
.../networking/device_drivers/wifi/index.rst | 19 -
.../device_drivers/wifi/intel/ipw2100.rst | 323 -
.../device_drivers/wifi/intel/ipw2200.rst | 526 -
MAINTAINERS | 8 -
drivers/net/wireless/intel/Kconfig | 1 -
drivers/net/wireless/intel/Makefile | 3 -
drivers/net/wireless/intel/ipw2x00/Kconfig | 195 -
drivers/net/wireless/intel/ipw2x00/Makefile | 15 -
drivers/net/wireless/intel/ipw2x00/ipw.h | 20 -
drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8587 -----------
drivers/net/wireless/intel/ipw2x00/ipw2100.h | 1142 --
drivers/net/wireless/intel/ipw2x00/ipw2200.c | 11965 ----------------
drivers/net/wireless/intel/ipw2x00/ipw2200.h | 1984 ---
drivers/net/wireless/intel/ipw2x00/libipw.h | 1001 --
.../net/wireless/intel/ipw2x00/libipw_geo.c | 179 -
.../wireless/intel/ipw2x00/libipw_module.c | 297 -
.../net/wireless/intel/ipw2x00/libipw_rx.c | 1737 ---
.../net/wireless/intel/ipw2x00/libipw_tx.c | 519 -
.../net/wireless/intel/ipw2x00/libipw_wx.c | 726 -
19 files changed, 29247 deletions(-)
delete mode 100644 Documentation/networking/device_drivers/wifi/index.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Kconfig
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Makefile
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_geo.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_module.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_rx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_tx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_wx.c

diff --git a/Documentation/networking/device_drivers/wifi/index.rst b/Documentation/networking/device_drivers/wifi/index.rst
deleted file mode 100644
index fb394f5de4a94..0000000000000
--- a/Documentation/networking/device_drivers/wifi/index.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-
-Wi-Fi Device Drivers
-====================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- intel/ipw2100
- intel/ipw2200
-
-.. only:: subproject and html
-
- Indices
- =======
-
- * :ref:`genindex`
diff --git a/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst b/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
deleted file mode 100644
index 883e963557992..0000000000000
--- a/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
+++ /dev/null
@@ -1,323 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-===========================================
-Intel(R) PRO/Wireless 2100 Driver for Linux
-===========================================
-
-Support for:
-
-- Intel(R) PRO/Wireless 2100 Network Connection
-
-Copyright |copy| 2003-2006, Intel Corporation
-
-README.ipw2100
-
-:Version: git-1.1.5
-:Date: January 25, 2006
-
-.. Index
-
- 0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
- 1. Introduction
- 2. Release git-1.1.5 Current Features
- 3. Command Line Parameters
- 4. Sysfs Helper Files
- 5. Radio Kill Switch
- 6. Dynamic Firmware
- 7. Power Management
- 8. Support
- 9. License
-
-
-0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
-=================================================
-
-Important Notice FOR ALL USERS OR DISTRIBUTORS!!!!
-
-Intel wireless LAN adapters are engineered, manufactured, tested, and
-quality checked to ensure that they meet all necessary local and
-governmental regulatory agency requirements for the regions that they
-are designated and/or marked to ship into. Since wireless LANs are
-generally unlicensed devices that share spectrum with radars,
-satellites, and other licensed and unlicensed devices, it is sometimes
-necessary to dynamically detect, avoid, and limit usage to avoid
-interference with these devices. In many instances Intel is required to
-provide test data to prove regional and local compliance to regional and
-governmental regulations before certification or approval to use the
-product is granted. Intel's wireless LAN's EEPROM, firmware, and
-software driver are designed to carefully control parameters that affect
-radio operation and to ensure electromagnetic compliance (EMC). These
-parameters include, without limitation, RF power, spectrum usage,
-channel scanning, and human exposure.
-
-For these reasons Intel cannot permit any manipulation by third parties
-of the software provided in binary format with the wireless WLAN
-adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
-patches, utilities, or code with the Intel wireless LAN adapters that
-have been manipulated by an unauthorized party (i.e., patches,
-utilities, or code (including open source code modifications) which have
-not been validated by Intel), (i) you will be solely responsible for
-ensuring the regulatory compliance of the products, (ii) Intel will bear
-no liability, under any theory of liability for any issues associated
-with the modified products, including without limitation, claims under
-the warranty and/or issues arising from regulatory non-compliance, and
-(iii) Intel will not provide or be required to assist in providing
-support to any third parties for such modified products.
-
-Note: Many regulatory agencies consider Wireless LAN adapters to be
-modules, and accordingly, condition system-level regulatory approval
-upon receipt and review of test data documenting that the antennas and
-system configuration do not cause the EMC and radio operation to be
-non-compliant.
-
-The drivers available for download from SourceForge are provided as a
-part of a development project. Conformance to local regulatory
-requirements is the responsibility of the individual developer. As
-such, if you are interested in deploying or shipping a driver as part of
-solution intended to be used for purposes other than development, please
-obtain a tested driver from Intel Customer Support at:
-
-https://www.intel.com/support/wireless/sb/CS-006408.htm
-
-1. Introduction
-===============
-
-This document provides a brief overview of the features supported by the
-IPW2100 driver project. The main project website, where the latest
-development version of the driver can be found, is:
-
- http://ipw2100.sourceforge.net
-
-There you can find the not only the latest releases, but also information about
-potential fixes and patches, as well as links to the development mailing list
-for the driver project.
-
-
-2. Release git-1.1.5 Current Supported Features
-===============================================
-
-- Managed (BSS) and Ad-Hoc (IBSS)
-- WEP (shared key and open)
-- Wireless Tools support
-- 802.1x (tested with XSupplicant 1.0.1)
-
-Enabled (but not supported) features:
-- Monitor/RFMon mode
-- WPA/WPA2
-
-The distinction between officially supported and enabled is a reflection
-on the amount of validation and interoperability testing that has been
-performed on a given feature.
-
-
-3. Command Line Parameters
-==========================
-
-If the driver is built as a module, the following optional parameters are used
-by entering them on the command line with the modprobe command using this
-syntax::
-
- modprobe ipw2100 [<option>=<VAL1><,VAL2>...]
-
-For example, to disable the radio on driver loading, enter:
-
- modprobe ipw2100 disable=1
-
-The ipw2100 driver supports the following module parameters:
-
-========= ============== ============ ==============================
-Name Value Example Meaning
-========= ============== ============ ==============================
-debug 0x0-0xffffffff debug=1024 Debug level set to 1024
-mode 0,1,2 mode=1 AdHoc
-channel int channel=3 Only valid in AdHoc or Monitor
-associate boolean associate=0 Do NOT auto associate
-disable boolean disable=1 Do not power the HW
-========= ============== ============ ==============================
-
-
-4. Sysfs Helper Files
-=====================
-
-There are several ways to control the behavior of the driver. Many of the
-general capabilities are exposed through the Wireless Tools (iwconfig). There
-are a few capabilities that are exposed through entries in the Linux Sysfs.
-
-
-**Driver Level**
-
-For the driver level files, look in /sys/bus/pci/drivers/ipw2100/
-
- debug_level
- This controls the same global as the 'debug' module parameter. For
- information on the various debugging levels available, run the 'dvals'
- script found in the driver source directory.
-
- .. note::
-
- 'debug_level' is only enabled if CONFIG_IPW2100_DEBUG is turn on.
-
-**Device Level**
-
-For the device level files look in::
-
- /sys/bus/pci/drivers/ipw2100/{PCI-ID}/
-
-For example::
-
- /sys/bus/pci/drivers/ipw2100/0000:02:01.0
-
-For the device level files, see /sys/bus/pci/drivers/ipw2100:
-
- rf_kill
- read
-
- == =========================================
- 0 RF kill not enabled (radio on)
- 1 SW based RF kill active (radio off)
- 2 HW based RF kill active (radio off)
- 3 Both HW and SW RF kill active (radio off)
- == =========================================
-
- write
-
- == ==================================================
- 0 If SW based RF kill active, turn the radio back on
- 1 If radio is on, activate SW based RF kill
- == ==================================================
-
- .. note::
-
- If you enable the SW based RF kill and then toggle the HW
- based RF kill from ON -> OFF -> ON, the radio will NOT come back on
-
-
-5. Radio Kill Switch
-====================
-
-Most laptops provide the ability for the user to physically disable the radio.
-Some vendors have implemented this as a physical switch that requires no
-software to turn the radio off and on. On other laptops, however, the switch
-is controlled through a button being pressed and a software driver then making
-calls to turn the radio off and on. This is referred to as a "software based
-RF kill switch"
-
-See the Sysfs helper file 'rf_kill' for determining the state of the RF switch
-on your system.
-
-
-6. Dynamic Firmware
-===================
-
-As the firmware is licensed under a restricted use license, it can not be
-included within the kernel sources. To enable the IPW2100 you will need a
-firmware image to load into the wireless NIC's processors.
-
-You can obtain these images from <http://ipw2100.sf.net/firmware.php>.
-
-See INSTALL for instructions on installing the firmware.
-
-
-7. Power Management
-===================
-
-The IPW2100 supports the configuration of the Power Save Protocol
-through a private wireless extension interface. The IPW2100 supports
-the following different modes:
-
- === ===========================================================
- off No power management. Radio is always on.
- on Automatic power management
- 1-5 Different levels of power management. The higher the
- number the greater the power savings, but with an impact to
- packet latencies.
- === ===========================================================
-
-Power management works by powering down the radio after a certain
-interval of time has passed where no packets are passed through the
-radio. Once powered down, the radio remains in that state for a given
-period of time. For higher power savings, the interval between last
-packet processed to sleep is shorter and the sleep period is longer.
-
-When the radio is asleep, the access point sending data to the station
-must buffer packets at the AP until the station wakes up and requests
-any buffered packets. If you have an AP that does not correctly support
-the PSP protocol you may experience packet loss or very poor performance
-while power management is enabled. If this is the case, you will need
-to try and find a firmware update for your AP, or disable power
-management (via ``iwconfig eth1 power off``)
-
-To configure the power level on the IPW2100 you use a combination of
-iwconfig and iwpriv. iwconfig is used to turn power management on, off,
-and set it to auto.
-
- ========================= ====================================
- iwconfig eth1 power off Disables radio power down
- iwconfig eth1 power on Enables radio power management to
- last set level (defaults to AUTO)
- iwpriv eth1 set_power 0 Sets power level to AUTO and enables
- power management if not previously
- enabled.
- iwpriv eth1 set_power 1-5 Set the power level as specified,
- enabling power management if not
- previously enabled.
- ========================= ====================================
-
-You can view the current power level setting via::
-
- iwpriv eth1 get_power
-
-It will return the current period or timeout that is configured as a string
-in the form of xxxx/yyyy (z) where xxxx is the timeout interval (amount of
-time after packet processing), yyyy is the period to sleep (amount of time to
-wait before powering the radio and querying the access point for buffered
-packets), and z is the 'power level'. If power management is turned off the
-xxxx/yyyy will be replaced with 'off' -- the level reported will be the active
-level if `iwconfig eth1 power on` is invoked.
-
-
-8. Support
-==========
-
-For general development information and support,
-go to:
-
- http://ipw2100.sf.net/
-
-The ipw2100 1.1.0 driver and firmware can be downloaded from:
-
- http://support.intel.com
-
-For installation support on the ipw2100 1.1.0 driver on Linux kernels
-2.6.8 or greater, email support is available from:
-
- http://supportmail.intel.com
-
-9. License
-==========
-
- Copyright |copy| 2003 - 2006 Intel Corporation. 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.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- License Contact Information:
-
- James P. Ketrenos <[email protected]>
-
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
diff --git a/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst b/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
deleted file mode 100644
index 0cb42d2fd7e5f..0000000000000
--- a/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
+++ /dev/null
@@ -1,526 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-==============================================
-Intel(R) PRO/Wireless 2915ABG Driver for Linux
-==============================================
-
-
-Support for:
-
-- Intel(R) PRO/Wireless 2200BG Network Connection
-- Intel(R) PRO/Wireless 2915ABG Network Connection
-
-Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R)
-PRO/Wireless 2200BG Driver for Linux is a unified driver that works on
-both hardware adapters listed above. In this document the Intel(R)
-PRO/Wireless 2915ABG Driver for Linux will be used to reference the
-unified driver.
-
-Copyright |copy| 2004-2006, Intel Corporation
-
-README.ipw2200
-
-:Version: 1.1.2
-:Date: March 30, 2006
-
-
-.. Index
-
- 0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
- 1. Introduction
- 1.1. Overview of features
- 1.2. Module parameters
- 1.3. Wireless Extension Private Methods
- 1.4. Sysfs Helper Files
- 1.5. Supported channels
- 2. Ad-Hoc Networking
- 3. Interacting with Wireless Tools
- 3.1. iwconfig mode
- 3.2. iwconfig sens
- 4. About the Version Numbers
- 5. Firmware installation
- 6. Support
- 7. License
-
-
-0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
-=================================================
-
-Important Notice FOR ALL USERS OR DISTRIBUTORS!!!!
-
-Intel wireless LAN adapters are engineered, manufactured, tested, and
-quality checked to ensure that they meet all necessary local and
-governmental regulatory agency requirements for the regions that they
-are designated and/or marked to ship into. Since wireless LANs are
-generally unlicensed devices that share spectrum with radars,
-satellites, and other licensed and unlicensed devices, it is sometimes
-necessary to dynamically detect, avoid, and limit usage to avoid
-interference with these devices. In many instances Intel is required to
-provide test data to prove regional and local compliance to regional and
-governmental regulations before certification or approval to use the
-product is granted. Intel's wireless LAN's EEPROM, firmware, and
-software driver are designed to carefully control parameters that affect
-radio operation and to ensure electromagnetic compliance (EMC). These
-parameters include, without limitation, RF power, spectrum usage,
-channel scanning, and human exposure.
-
-For these reasons Intel cannot permit any manipulation by third parties
-of the software provided in binary format with the wireless WLAN
-adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
-patches, utilities, or code with the Intel wireless LAN adapters that
-have been manipulated by an unauthorized party (i.e., patches,
-utilities, or code (including open source code modifications) which have
-not been validated by Intel), (i) you will be solely responsible for
-ensuring the regulatory compliance of the products, (ii) Intel will bear
-no liability, under any theory of liability for any issues associated
-with the modified products, including without limitation, claims under
-the warranty and/or issues arising from regulatory non-compliance, and
-(iii) Intel will not provide or be required to assist in providing
-support to any third parties for such modified products.
-
-Note: Many regulatory agencies consider Wireless LAN adapters to be
-modules, and accordingly, condition system-level regulatory approval
-upon receipt and review of test data documenting that the antennas and
-system configuration do not cause the EMC and radio operation to be
-non-compliant.
-
-The drivers available for download from SourceForge are provided as a
-part of a development project. Conformance to local regulatory
-requirements is the responsibility of the individual developer. As
-such, if you are interested in deploying or shipping a driver as part of
-solution intended to be used for purposes other than development, please
-obtain a tested driver from Intel Customer Support at:
-
-http://support.intel.com
-
-
-1. Introduction
-===============
-
-The following sections attempt to provide a brief introduction to using
-the Intel(R) PRO/Wireless 2915ABG Driver for Linux.
-
-This document is not meant to be a comprehensive manual on
-understanding or using wireless technologies, but should be sufficient
-to get you moving without wires on Linux.
-
-For information on building and installing the driver, see the INSTALL
-file.
-
-
-1.1. Overview of Features
--------------------------
-The current release (1.1.2) supports the following features:
-
-+ BSS mode (Infrastructure, Managed)
-+ IBSS mode (Ad-Hoc)
-+ WEP (OPEN and SHARED KEY mode)
-+ 802.1x EAP via wpa_supplicant and xsupplicant
-+ Wireless Extension support
-+ Full B and G rate support (2200 and 2915)
-+ Full A rate support (2915 only)
-+ Transmit power control
-+ S state support (ACPI suspend/resume)
-
-The following features are currently enabled, but not officially
-supported:
-
-+ WPA
-+ long/short preamble support
-+ Monitor mode (aka RFMon)
-
-The distinction between officially supported and enabled is a reflection
-on the amount of validation and interoperability testing that has been
-performed on a given feature.
-
-
-
-1.2. Command Line Parameters
-----------------------------
-
-Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless
-2915ABG Driver for Linux allows configuration options to be provided
-as module parameters. The most common way to specify a module parameter
-is via the command line.
-
-The general form is::
-
- % modprobe ipw2200 parameter=value
-
-Where the supported parameter are:
-
- associate
- Set to 0 to disable the auto scan-and-associate functionality of the
- driver. If disabled, the driver will not attempt to scan
- for and associate to a network until it has been configured with
- one or more properties for the target network, for example configuring
- the network SSID. Default is 0 (do not auto-associate)
-
- Example: % modprobe ipw2200 associate=0
-
- auto_create
- Set to 0 to disable the auto creation of an Ad-Hoc network
- matching the channel and network name parameters provided.
- Default is 1.
-
- channel
- channel number for association. The normal method for setting
- the channel would be to use the standard wireless tools
- (i.e. `iwconfig eth1 channel 10`), but it is useful sometimes
- to set this while debugging. Channel 0 means 'ANY'
-
- debug
- If using a debug build, this is used to control the amount of debug
- info is logged. See the 'dvals' and 'load' script for more info on
- how to use this (the dvals and load scripts are provided as part
- of the ipw2200 development snapshot releases available from the
- SourceForge project at http://ipw2200.sf.net)
-
- led
- Can be used to turn on experimental LED code.
- 0 = Off, 1 = On. Default is 1.
-
- mode
- Can be used to set the default mode of the adapter.
- 0 = Managed, 1 = Ad-Hoc, 2 = Monitor
-
-
-1.3. Wireless Extension Private Methods
----------------------------------------
-
-As an interface designed to handle generic hardware, there are certain
-capabilities not exposed through the normal Wireless Tool interface. As
-such, a provision is provided for a driver to declare custom, or
-private, methods. The Intel(R) PRO/Wireless 2915ABG Driver for Linux
-defines several of these to configure various settings.
-
-The general form of using the private wireless methods is::
-
- % iwpriv $IFNAME method parameters
-
-Where $IFNAME is the interface name the device is registered with
-(typically eth1, customized via one of the various network interface
-name managers, such as ifrename)
-
-The supported private methods are:
-
- get_mode
- Can be used to report out which IEEE mode the driver is
- configured to support. Example:
-
- % iwpriv eth1 get_mode
- eth1 get_mode:802.11bg (6)
-
- set_mode
- Can be used to configure which IEEE mode the driver will
- support.
-
- Usage::
-
- % iwpriv eth1 set_mode {mode}
-
- Where {mode} is a number in the range 1-7:
-
- == =====================
- 1 802.11a (2915 only)
- 2 802.11b
- 3 802.11ab (2915 only)
- 4 802.11g
- 5 802.11ag (2915 only)
- 6 802.11bg
- 7 802.11abg (2915 only)
- == =====================
-
- get_preamble
- Can be used to report configuration of preamble length.
-
- set_preamble
- Can be used to set the configuration of preamble length:
-
- Usage::
-
- % iwpriv eth1 set_preamble {mode}
-
- Where {mode} is one of:
-
- == ========================================
- 1 Long preamble only
- 0 Auto (long or short based on connection)
- == ========================================
-
-
-1.4. Sysfs Helper Files
------------------------
-
-The Linux kernel provides a pseudo file system that can be used to
-access various components of the operating system. The Intel(R)
-PRO/Wireless 2915ABG Driver for Linux exposes several configuration
-parameters through this mechanism.
-
-An entry in the sysfs can support reading and/or writing. You can
-typically query the contents of a sysfs entry through the use of cat,
-and can set the contents via echo. For example::
-
- % cat /sys/bus/pci/drivers/ipw2200/debug_level
-
-Will report the current debug level of the driver's logging subsystem
-(only available if CONFIG_IPW2200_DEBUG was configured when the driver
-was built).
-
-You can set the debug level via::
-
- % echo $VALUE > /sys/bus/pci/drivers/ipw2200/debug_level
-
-Where $VALUE would be a number in the case of this sysfs entry. The
-input to sysfs files does not have to be a number. For example, the
-firmware loader used by hotplug utilizes sysfs entries for transferring
-the firmware image from user space into the driver.
-
-The Intel(R) PRO/Wireless 2915ABG Driver for Linux exposes sysfs entries
-at two levels -- driver level, which apply to all instances of the driver
-(in the event that there are more than one device installed) and device
-level, which applies only to the single specific instance.
-
-
-1.4.1 Driver Level Sysfs Helper Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-For the driver level files, look in /sys/bus/pci/drivers/ipw2200/
-
- debug_level
- This controls the same global as the 'debug' module parameter
-
-
-
-1.4.2 Device Level Sysfs Helper Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-For the device level files, look in::
-
- /sys/bus/pci/drivers/ipw2200/{PCI-ID}/
-
-For example:::
-
- /sys/bus/pci/drivers/ipw2200/0000:02:01.0
-
-For the device level files, see /sys/bus/pci/drivers/ipw2200:
-
- rf_kill
- read -
-
- == =========================================
- 0 RF kill not enabled (radio on)
- 1 SW based RF kill active (radio off)
- 2 HW based RF kill active (radio off)
- 3 Both HW and SW RF kill active (radio off)
- == =========================================
-
- write -
-
- == ==================================================
- 0 If SW based RF kill active, turn the radio back on
- 1 If radio is on, activate SW based RF kill
- == ==================================================
-
- .. note::
-
- If you enable the SW based RF kill and then toggle the HW
- based RF kill from ON -> OFF -> ON, the radio will NOT come back on
-
- ucode
- read-only access to the ucode version number
-
- led
- read -
-
- == =================
- 0 LED code disabled
- 1 LED code enabled
- == =================
-
- write -
-
- == ================
- 0 Disable LED code
- 1 Enable LED code
- == ================
-
-
- .. note::
-
- The LED code has been reported to hang some systems when
- running ifconfig and is therefore disabled by default.
-
-
-1.5. Supported channels
------------------------
-
-Upon loading the Intel(R) PRO/Wireless 2915ABG Driver for Linux, a
-message stating the detected geography code and the number of 802.11
-channels supported by the card will be displayed in the log.
-
-The geography code corresponds to a regulatory domain as shown in the
-table below.
-
- +------+----------------------------+--------------------+
- | | | Supported channels |
- | Code | Geography +----------+---------+
- | | | 802.11bg | 802.11a |
- +======+============================+==========+=========+
- | --- | Restricted | 11 | 0 |
- +------+----------------------------+----------+---------+
- | ZZF | Custom US/Canada | 11 | 8 |
- +------+----------------------------+----------+---------+
- | ZZD | Rest of World | 13 | 0 |
- +------+----------------------------+----------+---------+
- | ZZA | Custom USA & Europe & High | 11 | 13 |
- +------+----------------------------+----------+---------+
- | ZZB | Custom NA & Europe | 11 | 13 |
- +------+----------------------------+----------+---------+
- | ZZC | Custom Japan | 11 | 4 |
- +------+----------------------------+----------+---------+
- | ZZM | Custom | 11 | 0 |
- +------+----------------------------+----------+---------+
- | ZZE | Europe | 13 | 19 |
- +------+----------------------------+----------+---------+
- | ZZJ | Custom Japan | 14 | 4 |
- +------+----------------------------+----------+---------+
- | ZZR | Rest of World | 14 | 0 |
- +------+----------------------------+----------+---------+
- | ZZH | High Band | 13 | 4 |
- +------+----------------------------+----------+---------+
- | ZZG | Custom Europe | 13 | 4 |
- +------+----------------------------+----------+---------+
- | ZZK | Europe | 13 | 24 |
- +------+----------------------------+----------+---------+
- | ZZL | Europe | 11 | 13 |
- +------+----------------------------+----------+---------+
-
-2. Ad-Hoc Networking
-=====================
-
-When using a device in an Ad-Hoc network, it is useful to understand the
-sequence and requirements for the driver to be able to create, join, or
-merge networks.
-
-The following attempts to provide enough information so that you can
-have a consistent experience while using the driver as a member of an
-Ad-Hoc network.
-
-2.1. Joining an Ad-Hoc Network
-------------------------------
-
-The easiest way to get onto an Ad-Hoc network is to join one that
-already exists.
-
-2.2. Creating an Ad-Hoc Network
--------------------------------
-
-An Ad-Hoc networks is created using the syntax of the Wireless tool.
-
-For Example:
-iwconfig eth1 mode ad-hoc essid testing channel 2
-
-2.3. Merging Ad-Hoc Networks
-----------------------------
-
-
-3. Interaction with Wireless Tools
-==================================
-
-3.1 iwconfig mode
------------------
-
-When configuring the mode of the adapter, all run-time configured parameters
-are reset to the value used when the module was loaded. This includes
-channels, rates, ESSID, etc.
-
-3.2 iwconfig sens
------------------
-
-The 'iwconfig ethX sens XX' command will not set the signal sensitivity
-threshold, as described in iwconfig documentation, but rather the number
-of consecutive missed beacons that will trigger handover, i.e. roaming
-to another access point. At the same time, it will set the disassociation
-threshold to 3 times the given value.
-
-
-4. About the Version Numbers
-=============================
-
-Due to the nature of open source development projects, there are
-frequently changes being incorporated that have not gone through
-a complete validation process. These changes are incorporated into
-development snapshot releases.
-
-Releases are numbered with a three level scheme:
-
- major.minor.development
-
-Any version where the 'development' portion is 0 (for example
-1.0.0, 1.1.0, etc.) indicates a stable version that will be made
-available for kernel inclusion.
-
-Any version where the 'development' portion is not a 0 (for
-example 1.0.1, 1.1.5, etc.) indicates a development version that is
-being made available for testing and cutting edge users. The stability
-and functionality of the development releases are not know. We make
-efforts to try and keep all snapshots reasonably stable, but due to the
-frequency of their release, and the desire to get those releases
-available as quickly as possible, unknown anomalies should be expected.
-
-The major version number will be incremented when significant changes
-are made to the driver. Currently, there are no major changes planned.
-
-5. Firmware installation
-========================
-
-The driver requires a firmware image, download it and extract the
-files under /lib/firmware (or wherever your hotplug's firmware.agent
-will look for firmware files)
-
-The firmware can be downloaded from the following URL:
-
- http://ipw2200.sf.net/
-
-
-6. Support
-==========
-
-For direct support of the 1.0.0 version, you can contact
-http://supportmail.intel.com, or you can use the open source project
-support.
-
-For general information and support, go to:
-
- http://ipw2200.sf.net/
-
-
-7. License
-==========
-
- Copyright |copy| 2003 - 2006 Intel Corporation. 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.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- Contact Information:
-
- James P. Ketrenos <[email protected]>
-
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
diff --git a/MAINTAINERS b/MAINTAINERS
index 42117d5a1d4e4..73e843194739a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10823,14 +10823,6 @@ M: David E. Box <[email protected]>
S: Supported
F: drivers/platform/x86/intel/pmt/

-INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
-M: Stanislav Yakovlev <[email protected]>
-L: [email protected]
-S: Maintained
-F: Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
-F: Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
-F: drivers/net/wireless/intel/ipw2x00/
-
INTEL PSTATE DRIVER
M: Srinivas Pandruvada <[email protected]>
M: Len Brown <[email protected]>
diff --git a/drivers/net/wireless/intel/Kconfig b/drivers/net/wireless/intel/Kconfig
index 3d1d7d11a3961..12c380ddb0cb0 100644
--- a/drivers/net/wireless/intel/Kconfig
+++ b/drivers/net/wireless/intel/Kconfig
@@ -12,7 +12,6 @@ config WLAN_VENDOR_INTEL

if WLAN_VENDOR_INTEL

-source "drivers/net/wireless/intel/ipw2x00/Kconfig"
source "drivers/net/wireless/intel/iwlegacy/Kconfig"
source "drivers/net/wireless/intel/iwlwifi/Kconfig"

diff --git a/drivers/net/wireless/intel/Makefile b/drivers/net/wireless/intel/Makefile
index 208e73a160519..6d5762d96f739 100644
--- a/drivers/net/wireless/intel/Makefile
+++ b/drivers/net/wireless/intel/Makefile
@@ -1,7 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_IPW2100) += ipw2x00/
-obj-$(CONFIG_IPW2200) += ipw2x00/
-
obj-$(CONFIG_IWLEGACY) += iwlegacy/

obj-$(CONFIG_IWLWIFI) += iwlwifi/
diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig
deleted file mode 100644
index 1650d5865aa02..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/Kconfig
+++ /dev/null
@@ -1,195 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Intel Centrino wireless drivers
-#
-
-config IPW2100
- tristate "Intel PRO/Wireless 2100 Network Connection"
- depends on PCI && CFG80211
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select LIB80211
- select LIBIPW
- help
- A driver for the Intel PRO/Wireless 2100 Network
- Connection 802.11b wireless network adapter.
-
- See <file:Documentation/networking/device_drivers/wifi/intel/ipw2100.rst>
- for information on the capabilities currently enabled in this driver
- and for tips for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2100.sf.net/>. Once you have the firmware image, you
- will need to place it in /lib/firmware.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2100_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2100
- help
- Enables promiscuous/monitor mode support for the ipw2100 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2100_DEBUG
- bool "Enable full debugging output in IPW2100 module."
- depends on IPW2100
- help
- This option will enable debug tracing output for the IPW2100.
-
- This will result in the kernel module being ~60k larger. You can
- control which debug output is sent to the kernel log by setting the
- value in
-
- /sys/bus/pci/drivers/ipw2100/debug_level
-
- This entry will only exist if this option is enabled.
-
- If you are not trying to debug or develop the IPW2100 driver, you
- most likely want to say N here.
-
-config IPW2200
- tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
- depends on PCI && CFG80211
- select CFG80211_WEXT_EXPORT
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select LIB80211
- select LIBIPW
- help
- A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
- Connection adapters.
-
- See <file:Documentation/networking/device_drivers/wifi/intel/ipw2200.rst>
- for information on the capabilities currently enabled in this
- driver and for tips for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2200.sf.net/>. See the above referenced README.ipw2200
- for information on where to install the firmware images.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2200_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2200
- help
- Enables promiscuous/monitor mode support for the ipw2200 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2200_RADIOTAP
- bool "Enable radiotap format 802.11 raw packet support"
- depends on IPW2200_MONITOR
-
-config IPW2200_PROMISCUOUS
- bool "Enable creation of a RF radiotap promiscuous interface"
- depends on IPW2200_MONITOR
- select IPW2200_RADIOTAP
- help
- Enables the creation of a second interface prefixed 'rtap'.
- This second interface will provide every received in radiotap
- format.
-
- This is useful for performing wireless network analysis while
- maintaining an active association.
-
- Example usage:
-
- % modprobe ipw2200 rtap_iface=1
- % ifconfig rtap0 up
- % tethereal -i rtap0
-
- If you do not specify 'rtap_iface=1' as a module parameter then
- the rtap interface will not be created and you will need to turn
- it on via sysfs:
-
- % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
-
-config IPW2200_QOS
- bool "Enable QoS support"
- depends on IPW2200
-
-config IPW2200_DEBUG
- bool "Enable full debugging output in IPW2200 module."
- depends on IPW2200
- help
- This option will enable low level debug tracing output for IPW2200.
-
- Note, normal debug code is already compiled in. This low level
- debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
- will result in the kernel module being ~70 larger. Most users
- will typically not need this high verbosity debug information.
-
- If you are not sure, say N here.
-
-config LIBIPW
- tristate
- depends on PCI && CFG80211
- select WIRELESS_EXT
- select WEXT_SPY
- select CRYPTO
- select CRYPTO_MICHAEL_MIC
- select CRC32
- select LIB80211
- select LIB80211_CRYPT_WEP
- select LIB80211_CRYPT_TKIP
- select LIB80211_CRYPT_CCMP
- help
- This option enables the hardware independent IEEE 802.11
- networking stack. This component is deprecated in favor of the
- mac80211 component.
-
-config LIBIPW_DEBUG
- bool "Full debugging output for the LIBIPW component"
- depends on LIBIPW
- help
- This option will enable debug tracing output for the
- libipw component.
-
- This will result in the kernel module being ~70k larger. You
- can control which debug output is sent to the kernel log by
- setting the value in
-
- /proc/net/ieee80211/debug_level
-
- For example:
-
- % echo 0x00000FFO > /proc/net/ieee80211/debug_level
-
- For a list of values you can assign to debug_level, you
- can look at the bit mask values in ieee80211.h
-
- If you are not trying to debug or develop the libipw
- component, you most likely want to say N here.
diff --git a/drivers/net/wireless/intel/ipw2x00/Makefile b/drivers/net/wireless/intel/ipw2x00/Makefile
deleted file mode 100644
index e1ec50359dffc..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the Intel Centrino wireless drivers
-#
-
-obj-$(CONFIG_IPW2100) += ipw2100.o
-obj-$(CONFIG_IPW2200) += ipw2200.o
-
-obj-$(CONFIG_LIBIPW) += libipw.o
-libipw-objs := \
- libipw_module.o \
- libipw_tx.o \
- libipw_rx.o \
- libipw_wx.o \
- libipw_geo.o
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw.h b/drivers/net/wireless/intel/ipw2x00/ipw.h
deleted file mode 100644
index 7b230a132daa7..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver
- *
- * Copyright 2012 Stanislav Yakovlev <[email protected]>
- */
-
-#ifndef __IPW_H__
-#define __IPW_H__
-
-#include <linux/ieee80211.h>
-
-static const u32 ipw_cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
-};
-
-#endif
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
deleted file mode 100644
index 0812db8936f13..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ /dev/null
@@ -1,8587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
- Portions of this file are based on the sample_* files provided by Wireless
- Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes
- <[email protected]>
-
- Portions of this file are based on the Host AP project,
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <[email protected]>
- Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
-
- Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
- ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
- available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox
-
-******************************************************************************/
-/*
-
- Initial driver on which this is based was developed by Janusz Gorycki,
- Maciej Urbaniak, and Maciej Sosnowski.
-
- Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak.
-
-Theory of Operation
-
-Tx - Commands and Data
-
-Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs)
-Each TBD contains a pointer to the physical (dma_addr_t) address of data being
-sent to the firmware as well as the length of the data.
-
-The host writes to the TBD queue at the WRITE index. The WRITE index points
-to the _next_ packet to be written and is advanced when after the TBD has been
-filled.
-
-The firmware pulls from the TBD queue at the READ index. The READ index points
-to the currently being read entry, and is advanced once the firmware is
-done with a packet.
-
-When data is sent to the firmware, the first TBD is used to indicate to the
-firmware if a Command or Data is being sent. If it is Command, all of the
-command information is contained within the physical address referred to by the
-TBD. If it is Data, the first TBD indicates the type of data packet, number
-of fragments, etc. The next TBD then refers to the actual packet location.
-
-The Tx flow cycle is as follows:
-
-1) ipw2100_tx() is called by kernel with SKB to transmit
-2) Packet is move from the tx_free_list and appended to the transmit pending
- list (tx_pend_list)
-3) work is scheduled to move pending packets into the shared circular queue.
-4) when placing packet in the circular queue, the incoming SKB is DMA mapped
- to a physical address. That address is entered into a TBD. Two TBDs are
- filled out. The first indicating a data packet, the second referring to the
- actual payload data.
-5) the packet is removed from tx_pend_list and placed on the end of the
- firmware pending list (fw_pend_list)
-6) firmware is notified that the WRITE index has
-7) Once the firmware has processed the TBD, INTA is triggered.
-8) For each Tx interrupt received from the firmware, the READ index is checked
- to see which TBDs are done being processed.
-9) For each TBD that has been processed, the ISR pulls the oldest packet
- from the fw_pend_list.
-10)The packet structure contained in the fw_pend_list is then used
- to unmap the DMA address and to free the SKB originally passed to the driver
- from the kernel.
-11)The packet structure is placed onto the tx_free_list
-
-The above steps are the same for commands, only the msg_free_list/msg_pend_list
-are used instead of tx_free_list/tx_pend_list
-
-...
-
-Critical Sections / Locking :
-
-There are two locks utilized. The first is the low level lock (priv->low_lock)
-that protects the following:
-
-- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows:
-
- tx_free_list : Holds pre-allocated Tx buffers.
- TAIL modified in __ipw2100_tx_process()
- HEAD modified in ipw2100_tx()
-
- tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring
- TAIL modified ipw2100_tx()
- HEAD modified by ipw2100_tx_send_data()
-
- msg_free_list : Holds pre-allocated Msg (Command) buffers
- TAIL modified in __ipw2100_tx_process()
- HEAD modified in ipw2100_hw_send_command()
-
- msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring
- TAIL modified in ipw2100_hw_send_command()
- HEAD modified in ipw2100_tx_send_commands()
-
- The flow of data on the TX side is as follows:
-
- MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST
- TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST
-
- The methods that work on the TBD ring are protected via priv->low_lock.
-
-- The internal data state of the device itself
-- Access to the firmware read/write indexes for the BD queues
- and associated logic
-
-All external entry functions are locked with the priv->action_lock to ensure
-that only one external action is invoked at a time.
-
-
-*/
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/stringify.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/firmware.h>
-#include <linux/acpi.h>
-#include <linux/ctype.h>
-#include <linux/pm_qos.h>
-
-#include <net/lib80211.h>
-
-#include "ipw2100.h"
-#include "ipw.h"
-
-#define IPW2100_VERSION "git-1.2.2"
-
-#define DRV_NAME "ipw2100"
-#define DRV_VERSION IPW2100_VERSION
-#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-
-static struct pm_qos_request ipw2100_pm_qos_req;
-
-/* Debugging stuff */
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW2100_RX_DEBUG /* Reception debugging */
-#endif
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-
-static int debug = 0;
-static int network_mode = 0;
-static int channel = 0;
-static int associate = 0;
-static int disable = 0;
-#ifdef CONFIG_PM
-static struct ipw2100_fw ipw2100_firmware;
-#endif
-
-#include <linux/moduleparam.h>
-module_param(debug, int, 0444);
-module_param_named(mode, network_mode, int, 0444);
-module_param(channel, int, 0444);
-module_param(associate, int, 0444);
-module_param(disable, int, 0444);
-
-MODULE_PARM_DESC(debug, "debug level");
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
-MODULE_PARM_DESC(channel, "channel");
-MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-
-static u32 ipw2100_debug_level = IPW_DL_NONE;
-
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW_DEBUG(level, message...) \
-do { \
- if (ipw2100_debug_level & (level)) { \
- printk(KERN_DEBUG "ipw2100: %s ", __func__); \
- printk(message); \
- } \
-} while (0)
-#else
-#define IPW_DEBUG(level, message...) do {} while (0)
-#endif /* CONFIG_IPW2100_DEBUG */
-
-#ifdef CONFIG_IPW2100_DEBUG
-static const char *command_types[] = {
- "undefined",
- "unused", /* HOST_ATTENTION */
- "HOST_COMPLETE",
- "unused", /* SLEEP */
- "unused", /* HOST_POWER_DOWN */
- "unused",
- "SYSTEM_CONFIG",
- "unused", /* SET_IMR */
- "SSID",
- "MANDATORY_BSSID",
- "AUTHENTICATION_TYPE",
- "ADAPTER_ADDRESS",
- "PORT_TYPE",
- "INTERNATIONAL_MODE",
- "CHANNEL",
- "RTS_THRESHOLD",
- "FRAG_THRESHOLD",
- "POWER_MODE",
- "TX_RATES",
- "BASIC_TX_RATES",
- "WEP_KEY_INFO",
- "unused",
- "unused",
- "unused",
- "unused",
- "WEP_KEY_INDEX",
- "WEP_FLAGS",
- "ADD_MULTICAST",
- "CLEAR_ALL_MULTICAST",
- "BEACON_INTERVAL",
- "ATIM_WINDOW",
- "CLEAR_STATISTICS",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "TX_POWER_INDEX",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "BROADCAST_SCAN",
- "CARD_DISABLE",
- "PREFERRED_BSSID",
- "SET_SCAN_OPTIONS",
- "SCAN_DWELL_TIME",
- "SWEEP_TABLE",
- "AP_OR_STATION_TABLE",
- "GROUP_ORDINALS",
- "SHORT_RETRY_LIMIT",
- "LONG_RETRY_LIMIT",
- "unused", /* SAVE_CALIBRATION */
- "unused", /* RESTORE_CALIBRATION */
- "undefined",
- "undefined",
- "undefined",
- "HOST_PRE_POWER_DOWN",
- "unused", /* HOST_INTERRUPT_COALESCING */
- "undefined",
- "CARD_DISABLE_PHY_OFF",
- "MSDU_TX_RATES",
- "undefined",
- "SET_STATION_STAT_BITS",
- "CLEAR_STATIONS_STAT_BITS",
- "LEAP_ROGUE_MODE",
- "SET_SECURITY_INFORMATION",
- "DISASSOCIATION_BSSID",
- "SET_WPA_ASS_IE"
-};
-#endif
-
-static const long ipw2100_frequencies[] = {
- 2412, 2417, 2422, 2427,
- 2432, 2437, 2442, 2447,
- 2452, 2457, 2462, 2467,
- 2472, 2484
-};
-
-#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
-
-static struct ieee80211_rate ipw2100_bg_rates[] = {
- { .bitrate = 10 },
- { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-};
-
-#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
-
-/* Pre-decl until we get the code solid and then we can clean it up */
-static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
-static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
-static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
-
-static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
-static void ipw2100_queues_free(struct ipw2100_priv *priv);
-static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
-
-static int ipw2100_fw_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_get_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
- size_t max);
-static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
- size_t max);
-static void ipw2100_release_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_ucode_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static void ipw2100_wx_event_work(struct work_struct *work);
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
-static const struct iw_handler_def ipw2100_wx_handler_def;
-
-static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread32(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
-}
-
-static inline void write_register(struct net_device *dev, u32 reg, u32 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite32(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
-}
-
-static inline void read_register_word(struct net_device *dev, u32 reg,
- u16 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread16(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
-}
-
-static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread8(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
-}
-
-static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite16(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
-}
-
-static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite8(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
-}
-
-static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
- const u8 * buf)
-{
- u32 aligned_addr;
- u32 aligned_len;
- u32 dif_len;
- u32 i;
-
- /* read first nibble byte by byte */
- aligned_addr = addr & (~0x3);
- dif_len = addr - aligned_addr;
- if (dif_len) {
- /* Start reading at aligned_addr + dif_len */
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- write_register_byte(dev,
- IPW_REG_INDIRECT_ACCESS_DATA + i,
- *buf);
-
- len -= dif_len;
- aligned_addr += 4;
- }
-
- /* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
- aligned_len = len & (~0x3);
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
-
- /* copy the last nibble */
- dif_len = len - aligned_len;
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
- *buf);
-}
-
-static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
- u8 * buf)
-{
- u32 aligned_addr;
- u32 aligned_len;
- u32 dif_len;
- u32 i;
-
- /* read first nibble byte by byte */
- aligned_addr = addr & (~0x3);
- dif_len = addr - aligned_addr;
- if (dif_len) {
- /* Start reading at aligned_addr + dif_len */
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- read_register_byte(dev,
- IPW_REG_INDIRECT_ACCESS_DATA + i,
- buf);
-
- len -= dif_len;
- aligned_addr += 4;
- }
-
- /* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
- aligned_len = len & (~0x3);
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
-
- /* copy the last nibble */
- dif_len = len - aligned_len;
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
-}
-
-static bool ipw2100_hw_is_adapter_in_system(struct net_device *dev)
-{
- u32 dbg;
-
- read_register(dev, IPW_REG_DOA_DEBUG_AREA_START, &dbg);
-
- return dbg == IPW_DATA_DOA_DEBUG_VALUE;
-}
-
-static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
- void *val, u32 * len)
-{
- struct ipw2100_ordinals *ordinals = &priv->ordinals;
- u32 addr;
- u32 field_info;
- u16 field_len;
- u16 field_count;
- u32 total_length;
-
- if (ordinals->table1_addr == 0) {
- printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
- "before they have been loaded.\n");
- return -EINVAL;
- }
-
- if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
- if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- printk(KERN_WARNING DRV_NAME
- ": ordinal buffer length too small, need %zd\n",
- IPW_ORD_TAB_1_ENTRY_SIZE);
-
- return -EINVAL;
- }
-
- read_nic_dword(priv->net_dev,
- ordinals->table1_addr + (ord << 2), &addr);
- read_nic_dword(priv->net_dev, addr, val);
-
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- return 0;
- }
-
- if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
-
- ord -= IPW_START_ORD_TAB_2;
-
- /* get the address of statistic */
- read_nic_dword(priv->net_dev,
- ordinals->table2_addr + (ord << 3), &addr);
-
- /* get the second DW of statistics ;
- * two 16-bit words - first is length, second is count */
- read_nic_dword(priv->net_dev,
- ordinals->table2_addr + (ord << 3) + sizeof(u32),
- &field_info);
-
- /* get each entry length */
- field_len = *((u16 *) & field_info);
-
- /* get number of entries */
- field_count = *(((u16 *) & field_info) + 1);
-
- /* abort if no enough memory */
- total_length = field_len * field_count;
- if (total_length > *len) {
- *len = total_length;
- return -EINVAL;
- }
-
- *len = total_length;
- if (!total_length)
- return 0;
-
- /* read the ordinal data from the SRAM */
- read_nic_memory(priv->net_dev, addr, total_length, val);
-
- return 0;
- }
-
- printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
- "in table 2\n", ord);
-
- return -EINVAL;
-}
-
-static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
- u32 * len)
-{
- struct ipw2100_ordinals *ordinals = &priv->ordinals;
- u32 addr;
-
- if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
- if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
- IPW_DEBUG_INFO("wrong size\n");
- return -EINVAL;
- }
-
- read_nic_dword(priv->net_dev,
- ordinals->table1_addr + (ord << 2), &addr);
-
- write_nic_dword(priv->net_dev, addr, *val);
-
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- return 0;
- }
-
- IPW_DEBUG_INFO("wrong table\n");
- if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
- return -EINVAL;
-
- return -EINVAL;
-}
-
-static char *snprint_line(char *buf, size_t count,
- const u8 * data, u32 len, u32 ofs)
-{
- int out, i, j, l;
- char c;
-
- out = scnprintf(buf, count, "%08X", ofs);
-
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++)
- out += scnprintf(buf + out, count - out, "%02X ",
- data[(i * 8 + j)]);
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- out += scnprintf(buf + out, count - out, " ");
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++) {
- c = data[(i * 8 + j)];
- if (!isascii(c) || !isprint(c))
- c = '.';
-
- out += scnprintf(buf + out, count - out, "%c", c);
- }
-
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- return buf;
-}
-
-static void printk_buf(int level, const u8 * data, u32 len)
-{
- char line[81];
- u32 ofs = 0;
- if (!(ipw2100_debug_level & level))
- return;
-
- while (len) {
- printk(KERN_DEBUG "%s\n",
- snprint_line(line, sizeof(line), &data[ofs],
- min(len, 16U), ofs));
- ofs += 16;
- len -= min(len, 16U);
- }
-}
-
-#define MAX_RESET_BACKOFF 10
-
-static void schedule_reset(struct ipw2100_priv *priv)
-{
- time64_t now = ktime_get_boottime_seconds();
-
- /* If we haven't received a reset request within the backoff period,
- * then we can reset the backoff interval so this reset occurs
- * immediately */
- if (priv->reset_backoff &&
- (now - priv->last_reset > priv->reset_backoff))
- priv->reset_backoff = 0;
-
- priv->last_reset = now;
-
- if (!(priv->status & STATUS_RESET_PENDING)) {
- IPW_DEBUG_INFO("%s: Scheduling firmware restart (%llds).\n",
- priv->net_dev->name, priv->reset_backoff);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
- priv->status |= STATUS_RESET_PENDING;
- if (priv->reset_backoff)
- schedule_delayed_work(&priv->reset_work,
- priv->reset_backoff * HZ);
- else
- schedule_delayed_work(&priv->reset_work, 0);
-
- if (priv->reset_backoff < MAX_RESET_BACKOFF)
- priv->reset_backoff++;
-
- wake_up_interruptible(&priv->wait_command_queue);
- } else
- IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
- priv->net_dev->name);
-
-}
-
-#define HOST_COMPLETE_TIMEOUT (2 * HZ)
-static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
- struct host_command *cmd)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- unsigned long flags;
- int err = 0;
-
- IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
- command_types[cmd->host_command], cmd->host_command,
- cmd->host_command_length);
- printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
- cmd->host_command_length);
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->fatal_error) {
- IPW_DEBUG_INFO
- ("Attempt to send command while hardware in fatal error condition.\n");
- err = -EIO;
- goto fail_unlock;
- }
-
- if (!(priv->status & STATUS_RUNNING)) {
- IPW_DEBUG_INFO
- ("Attempt to send command while hardware is not running.\n");
- err = -EIO;
- goto fail_unlock;
- }
-
- if (priv->status & STATUS_CMD_ACTIVE) {
- IPW_DEBUG_INFO
- ("Attempt to send command while another command is pending.\n");
- err = -EBUSY;
- goto fail_unlock;
- }
-
- if (list_empty(&priv->msg_free_list)) {
- IPW_DEBUG_INFO("no available msg buffers\n");
- goto fail_unlock;
- }
-
- priv->status |= STATUS_CMD_ACTIVE;
- priv->messages_sent++;
-
- element = priv->msg_free_list.next;
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
- packet->jiffy_start = jiffies;
-
- /* initialize the firmware command packet */
- packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
- packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
- packet->info.c_struct.cmd->host_command_len_reg =
- cmd->host_command_length;
- packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
-
- memcpy(packet->info.c_struct.cmd->host_command_params_reg,
- cmd->host_command_parameters,
- sizeof(packet->info.c_struct.cmd->host_command_params_reg));
-
- list_del(element);
- DEC_STAT(&priv->msg_free_stat);
-
- list_add_tail(element, &priv->msg_pend_list);
- INC_STAT(&priv->msg_pend_stat);
-
- ipw2100_tx_send_commands(priv);
- ipw2100_tx_send_data(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- /*
- * We must wait for this command to complete before another
- * command can be sent... but if we wait more than 3 seconds
- * then there is a problem.
- */
-
- err =
- wait_event_interruptible_timeout(priv->wait_command_queue,
- !(priv->
- status & STATUS_CMD_ACTIVE),
- HOST_COMPLETE_TIMEOUT);
-
- if (err == 0) {
- IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
- 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
- priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
- priv->status &= ~STATUS_CMD_ACTIVE;
- schedule_reset(priv);
- return -EIO;
- }
-
- if (priv->fatal_error) {
- printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* !!!!! HACK TEST !!!!!
- * When lots of debug trace statements are enabled, the driver
- * doesn't seem to have as many firmware restart cycles...
- *
- * As a test, we're sticking in a 1/100s delay here */
- schedule_timeout_uninterruptible(msecs_to_jiffies(10));
-
- return 0;
-
- fail_unlock:
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- return err;
-}
-
-/*
- * Verify the values and data access of the hardware
- * No locks needed or used. No functions called.
- */
-static int ipw2100_verify(struct ipw2100_priv *priv)
-{
- u32 data1, data2;
- u32 address;
-
- u32 val1 = 0x76543210;
- u32 val2 = 0xFEDCBA98;
-
- /* Domain 0 check - all values should be DOA_DEBUG */
- for (address = IPW_REG_DOA_DEBUG_AREA_START;
- address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
- read_register(priv->net_dev, address, &data1);
- if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
- return -EIO;
- }
-
- /* Domain 1 check - use arbitrary read/write compare */
- for (address = 0; address < 5; address++) {
- /* The memory area is not used now */
- write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
- val1);
- write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
- val2);
- read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
- &data1);
- read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
- &data2);
- if (val1 == data1 && val2 == data2)
- return 0;
- }
-
- return -EIO;
-}
-
-/*
- *
- * Loop until the CARD_DISABLED bit is the same value as the
- * supplied parameter
- *
- * TODO: See if it would be more efficient to do a wait/wake
- * cycle and have the completion event trigger the wakeup
- *
- */
-#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
-static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
-{
- int i;
- u32 card_state;
- u32 len = sizeof(card_state);
- int err;
-
- for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
- err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
- &card_state, &len);
- if (err) {
- IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
- "failed.\n");
- return 0;
- }
-
- /* We'll break out if either the HW state says it is
- * in the state we want, or if HOST_COMPLETE command
- * finishes */
- if ((card_state == state) ||
- ((priv->status & STATUS_ENABLED) ?
- IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
- if (state == IPW_HW_STATE_ENABLED)
- priv->status |= STATUS_ENABLED;
- else
- priv->status &= ~STATUS_ENABLED;
-
- return 0;
- }
-
- udelay(50);
- }
-
- IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
- state ? "DISABLED" : "ENABLED");
- return -EIO;
-}
-
-/*********************************************************************
- Procedure : sw_reset_and_clock
- Purpose : Asserts s/w reset, asserts clock initialization
- and waits for clock stabilization
- ********************************************************************/
-static int sw_reset_and_clock(struct ipw2100_priv *priv)
-{
- int i;
- u32 r;
-
- // assert s/w reset
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- // wait for clock stabilization
- for (i = 0; i < 1000; i++) {
- udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
-
- // check clock ready bit
- read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
- if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
- break;
- }
-
- if (i == 1000)
- return -EIO; // TODO: better error value
-
- /* set "initialization complete" bit to move adapter to
- * D0 state */
- write_register(priv->net_dev, IPW_REG_GP_CNTRL,
- IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
-
- /* wait for clock stabilization */
- for (i = 0; i < 10000; i++) {
- udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
-
- /* check clock ready bit */
- read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
- if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
- break;
- }
-
- if (i == 10000)
- return -EIO; /* TODO: better error value */
-
- /* set D0 standby bit */
- read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
- write_register(priv->net_dev, IPW_REG_GP_CNTRL,
- r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
-
- return 0;
-}
-
-/*********************************************************************
- Procedure : ipw2100_download_firmware
- Purpose : Initiaze adapter after power on.
- The sequence is:
- 1. assert s/w reset first!
- 2. awake clocks & wait for clock stabilization
- 3. hold ARC (don't ask me why...)
- 4. load Dino ucode and reset/clock init again
- 5. zero-out shared mem
- 6. download f/w
- *******************************************************************/
-static int ipw2100_download_firmware(struct ipw2100_priv *priv)
-{
- u32 address;
- int err;
-
-#ifndef CONFIG_PM
- /* Fetch the firmware and microcode */
- struct ipw2100_fw ipw2100_firmware;
-#endif
-
- if (priv->fatal_error) {
- IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
- "fatal error %d. Interface must be brought down.\n",
- priv->net_dev->name, priv->fatal_error);
- return -EINVAL;
- }
-#ifdef CONFIG_PM
- if (!ipw2100_firmware.version) {
- err = ipw2100_get_firmware(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
- priv->fatal_error = IPW2100_ERR_FW_LOAD;
- goto fail;
- }
- }
-#else
- err = ipw2100_get_firmware(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
- priv->fatal_error = IPW2100_ERR_FW_LOAD;
- goto fail;
- }
-#endif
- priv->firmware_version = ipw2100_firmware.version;
-
- /* s/w reset and clock stabilization */
- err = sw_reset_and_clock(priv);
- if (err) {
- IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- err = ipw2100_verify(priv);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* Hold ARC */
- write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
-
- /* allow ARC to run */
- write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
-
- /* load microcode */
- err = ipw2100_ucode_download(priv, &ipw2100_firmware);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* release ARC */
- write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
-
- /* s/w reset and clock stabilization (again!!!) */
- err = sw_reset_and_clock(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: sw_reset_and_clock failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* load f/w */
- err = ipw2100_fw_download(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-#ifndef CONFIG_PM
- /*
- * When the .resume method of the driver is called, the other
- * part of the system, i.e. the ide driver could still stay in
- * the suspend stage. This prevents us from loading the firmware
- * from the disk. --YZ
- */
-
- /* free any storage allocated for firmware image */
- ipw2100_release_firmware(priv, &ipw2100_firmware);
-#endif
-
- /* zero out Domain 1 area indirectly (Si requirement) */
- for (address = IPW_HOST_FW_SHARED_AREA0;
- address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA1;
- address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA2;
- address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA3;
- address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_INTERRUPT_AREA;
- address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
-
- return 0;
-
- fail:
- ipw2100_release_firmware(priv, &ipw2100_firmware);
- return err;
-}
-
-static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
-{
- if (priv->status & STATUS_INT_ENABLED)
- return;
- priv->status |= STATUS_INT_ENABLED;
- write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
-}
-
-static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
-{
- if (!(priv->status & STATUS_INT_ENABLED))
- return;
- priv->status &= ~STATUS_INT_ENABLED;
- write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
-}
-
-static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
-{
- struct ipw2100_ordinals *ord = &priv->ordinals;
-
- IPW_DEBUG_INFO("enter\n");
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
- &ord->table1_addr);
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
- &ord->table2_addr);
-
- read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
- read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
-
- ord->table2_size &= 0x0000FFFF;
-
- IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
- IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
- IPW_DEBUG_INFO("exit\n");
-}
-
-static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
-{
- u32 reg = 0;
- /*
- * Set GPIO 3 writable by FW; GPIO 1 writable
- * by driver and enable clock
- */
- reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
- IPW_BIT_GPIO_LED_OFF);
- write_register(priv->net_dev, IPW_REG_GPIO, reg);
-}
-
-static int rf_kill_active(struct ipw2100_priv *priv)
-{
-#define MAX_RF_KILL_CHECKS 5
-#define RF_KILL_CHECK_DELAY 40
-
- unsigned short value = 0;
- u32 reg = 0;
- int i;
-
- if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- priv->status &= ~STATUS_RF_KILL_HW;
- return 0;
- }
-
- for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
- udelay(RF_KILL_CHECK_DELAY);
- read_register(priv->net_dev, IPW_REG_GPIO, &reg);
- value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
- }
-
- if (value == 0) {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- priv->status |= STATUS_RF_KILL_HW;
- } else {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- priv->status &= ~STATUS_RF_KILL_HW;
- }
-
- return (value == 0);
-}
-
-static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
-{
- u32 addr, len;
- u32 val;
-
- /*
- * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
- */
- len = sizeof(addr);
- if (ipw2100_get_ordinal
- (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return -EIO;
- }
-
- IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
-
- /*
- * EEPROM version is the byte at offset 0xfd in firmware
- * We read 4 bytes, then shift out the byte we actually want */
- read_nic_dword(priv->net_dev, addr + 0xFC, &val);
- priv->eeprom_version = (val >> 24) & 0xFF;
- IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
-
- /*
- * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
- *
- * notice that the EEPROM bit is reverse polarity, i.e.
- * bit = 0 signifies HW RF kill switch is supported
- * bit = 1 signifies HW RF kill switch is NOT supported
- */
- read_nic_dword(priv->net_dev, addr + 0x20, &val);
- if (!((val >> 24) & 0x01))
- priv->hw_features |= HW_FEATURE_RFKILL;
-
- IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
- (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
-
- return 0;
-}
-
-/*
- * Start firmware execution after power on and initialization
- * The sequence is:
- * 1. Release ARC
- * 2. Wait for f/w initialization completes;
- */
-static int ipw2100_start_adapter(struct ipw2100_priv *priv)
-{
- int i;
- u32 inta, inta_mask, gpio;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->status & STATUS_RUNNING)
- return 0;
-
- /*
- * Initialize the hw - drive adapter to DO state by setting
- * init_done bit. Wait for clk_ready bit and Download
- * fw & dino ucode
- */
- if (ipw2100_download_firmware(priv)) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to power on the adapter.\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* Clear the Tx, Rx and Msg queues and the r/w indexes
- * in the firmware RBD and TBD ring queue */
- ipw2100_queues_initialize(priv);
-
- ipw2100_hw_set_gpio(priv);
-
- /* TODO -- Look at disabling interrupts here to make sure none
- * get fired during FW initialization */
-
- /* Release ARC - clear reset bit */
- write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
-
- /* wait for f/w initialization complete */
- IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
- i = 5000;
- do {
- schedule_timeout_uninterruptible(msecs_to_jiffies(40));
- /* Todo... wait for sync command ... */
-
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
-
- /* check "init done" bit */
- if (inta & IPW2100_INTA_FW_INIT_DONE) {
- /* reset "init done" bit */
- write_register(priv->net_dev, IPW_REG_INTA,
- IPW2100_INTA_FW_INIT_DONE);
- break;
- }
-
- /* check error conditions : we check these after the firmware
- * check so that if there is an error, the interrupt handler
- * will see it and the adapter will be reset */
- if (inta &
- (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
- /* clear error conditions */
- write_register(priv->net_dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR);
- }
- } while (--i);
-
- /* Clear out any pending INTAs since we aren't supposed to have
- * interrupts enabled at this point... */
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
- read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
- inta &= IPW_INTERRUPT_MASK;
- /* Clear out any pending interrupts */
- if (inta & inta_mask)
- write_register(priv->net_dev, IPW_REG_INTA, inta);
-
- IPW_DEBUG_FW("f/w initialization complete: %s\n",
- i ? "SUCCESS" : "FAILED");
-
- if (!i) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Firmware did not initialize.\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* allow firmware to write to GPIO1 & GPIO3 */
- read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
-
- gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
-
- write_register(priv->net_dev, IPW_REG_GPIO, gpio);
-
- /* Ready to receive commands */
- priv->status |= STATUS_RUNNING;
-
- /* The adapter has been reset; we are not associated */
- priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
-{
- if (!priv->fatal_error)
- return;
-
- priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
- priv->fatal_index %= IPW2100_ERROR_QUEUE;
- priv->fatal_error = 0;
-}
-
-/* NOTE: Our interrupt is disabled when this method is called */
-static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
-{
- u32 reg;
- int i;
-
- IPW_DEBUG_INFO("Power cycling the hardware.\n");
-
- ipw2100_hw_set_gpio(priv);
-
- /* Step 1. Stop Master Assert */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
-
- /* Step 2. Wait for stop Master Assert
- * (not more than 50us, otherwise ret error */
- i = 5;
- do {
- udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
- read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- } while (--i);
-
- priv->status &= ~STATUS_RESET_PENDING;
-
- if (!i) {
- IPW_DEBUG_INFO
- ("exit - waited too long for master assert stop\n");
- return -EIO;
- }
-
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- /* Reset any fatal_error conditions */
- ipw2100_reset_fatalerror(priv);
-
- /* At this point, the adapter is now stopped and disabled */
- priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
- STATUS_ASSOCIATED | STATUS_ENABLED);
-
- return 0;
-}
-
-/*
- * Send the CARD_DISABLE_PHY_OFF command to the card to disable it
- *
- * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
- *
- * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
- * if STATUS_ASSN_LOST is sent.
- */
-static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
-{
-
-#define HW_PHY_OFF_LOOP_DELAY (msecs_to_jiffies(50))
-
- struct host_command cmd = {
- .host_command = CARD_DISABLE_PHY_OFF,
- .host_command_sequence = 0,
- .host_command_length = 0,
- };
- int err, i;
- u32 val1, val2;
-
- IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
-
- /* Turn off the radio */
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- for (i = 0; i < 2500; i++) {
- read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
- read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
-
- if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
- (val2 & IPW2100_COMMAND_PHY_OFF))
- return 0;
-
- schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
- }
-
- return -EIO;
-}
-
-static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = HOST_COMPLETE,
- .host_command_sequence = 0,
- .host_command_length = 0
- };
- int err = 0;
-
- IPW_DEBUG_HC("HOST_COMPLETE\n");
-
- if (priv->status & STATUS_ENABLED)
- return 0;
-
- mutex_lock(&priv->adapter_mutex);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
- goto fail_up;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
- goto fail_up;
- }
-
- err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
- if (err) {
- IPW_DEBUG_INFO("%s: card not responding to init command.\n",
- priv->net_dev->name);
- goto fail_up;
- }
-
- if (priv->stop_hang_check) {
- priv->stop_hang_check = 0;
- schedule_delayed_work(&priv->hang_check, HZ / 2);
- }
-
- fail_up:
- mutex_unlock(&priv->adapter_mutex);
- return err;
-}
-
-static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
-{
-#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
-
- struct host_command cmd = {
- .host_command = HOST_PRE_POWER_DOWN,
- .host_command_sequence = 0,
- .host_command_length = 0,
- };
- int err, i;
- u32 reg;
-
- if (!(priv->status & STATUS_RUNNING))
- return 0;
-
- priv->status |= STATUS_STOPPING;
-
- /* We can only shut down the card if the firmware is operational. So,
- * if we haven't reset since a fatal_error, then we can not send the
- * shutdown commands. */
- if (!priv->fatal_error) {
- /* First, make sure the adapter is enabled so that the PHY_OFF
- * command can shut it down */
- ipw2100_enable_adapter(priv);
-
- err = ipw2100_hw_phy_off(priv);
- if (err)
- printk(KERN_WARNING DRV_NAME
- ": Error disabling radio %d\n", err);
-
- /*
- * If in D0-standby mode going directly to D3 may cause a
- * PCI bus violation. Therefore we must change out of the D0
- * state.
- *
- * Sending the PREPARE_FOR_POWER_DOWN will restrict the
- * hardware from going into standby mode and will transition
- * out of D0-standby if it is already in that state.
- *
- * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
- * driver upon completion. Once received, the driver can
- * proceed to the D3 state.
- *
- * Prepare for power down command to fw. This command would
- * take HW out of D0-standby and prepare it for D3 state.
- *
- * Currently FW does not support event notification for this
- * event. Therefore, skip waiting for it. Just wait a fixed
- * 100ms
- */
- IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Power down command failed: Error %d\n",
- priv->net_dev->name, err);
- else
- schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
- }
-
- priv->status &= ~STATUS_ENABLED;
-
- /*
- * Set GPIO 3 writable by FW; GPIO 1 writable
- * by driver and enable clock
- */
- ipw2100_hw_set_gpio(priv);
-
- /*
- * Power down adapter. Sequence:
- * 1. Stop master assert (RESET_REG[9]=1)
- * 2. Wait for stop master (RESET_REG[8]==1)
- * 3. S/w reset assert (RESET_REG[7] = 1)
- */
-
- /* Stop master assert */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
-
- /* wait stop master not more than 50 usec.
- * Otherwise return error. */
- for (i = 5; i > 0; i--) {
- udelay(10);
-
- /* Check master stop bit */
- read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- }
-
- if (i == 0)
- printk(KERN_WARNING DRV_NAME
- ": %s: Could now power down adapter.\n",
- priv->net_dev->name);
-
- /* assert s/w reset */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
-
- return 0;
-}
-
-static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = CARD_DISABLE,
- .host_command_sequence = 0,
- .host_command_length = 0
- };
- int err = 0;
-
- IPW_DEBUG_HC("CARD_DISABLE\n");
-
- if (!(priv->status & STATUS_ENABLED))
- return 0;
-
- /* Make sure we clear the associated state */
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
-
- if (!priv->stop_hang_check) {
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
- }
-
- mutex_lock(&priv->adapter_mutex);
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": exit - failed to send CARD_DISABLE command\n");
- goto fail_up;
- }
-
- err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": exit - card failed to change to DISABLED\n");
- goto fail_up;
- }
-
- IPW_DEBUG_INFO("TODO: implement scan state machine\n");
-
- fail_up:
- mutex_unlock(&priv->adapter_mutex);
- return err;
-}
-
-static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = SET_SCAN_OPTIONS,
- .host_command_sequence = 0,
- .host_command_length = 8
- };
- int err;
-
- IPW_DEBUG_INFO("enter\n");
-
- IPW_DEBUG_SCAN("setting scan options\n");
-
- cmd.host_command_parameters[0] = 0;
-
- if (!(priv->config & CFG_ASSOCIATE))
- cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
- if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
- cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
- if (priv->config & CFG_PASSIVE_SCAN)
- cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
-
- cmd.host_command_parameters[1] = priv->channel_mask;
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
- cmd.host_command_parameters[0]);
-
- return err;
-}
-
-static int ipw2100_start_scan(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = BROADCAST_SCAN,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- IPW_DEBUG_HC("START_SCAN\n");
-
- cmd.host_command_parameters[0] = 0;
-
- /* No scanning if in monitor mode */
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- return 1;
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
- return 0;
- }
-
- IPW_DEBUG_INFO("enter\n");
-
- /* Not clearing here; doing so makes iwlist always return nothing...
- *
- * We should modify the table logic to use aging tables vs. clearing
- * the table on each scan start.
- */
- IPW_DEBUG_SCAN("starting scan\n");
-
- priv->status |= STATUS_SCANNING;
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- priv->status &= ~STATUS_SCANNING;
-
- IPW_DEBUG_INFO("exit\n");
-
- return err;
-}
-
-static const struct libipw_geo ipw_geos[] = {
- { /* Restricted */
- "---",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14}},
- },
-};
-
-static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
-{
- unsigned long flags;
- int err = 0;
- u32 lock;
- u32 ord_len = sizeof(lock);
-
- /* Age scan list entries found before suspend */
- if (priv->suspend_time) {
- libipw_networks_age(priv->ieee, priv->suspend_time);
- priv->suspend_time = 0;
- }
-
- /* Quiet if manually disabled. */
- if (priv->status & STATUS_RF_KILL_SW) {
- IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
- "switch\n", priv->net_dev->name);
- return 0;
- }
-
- /* the ipw2100 hardware really doesn't want power management delays
- * longer than 175usec
- */
- cpu_latency_qos_update_request(&ipw2100_pm_qos_req, 175);
-
- /* If the interrupt is enabled, turn it off... */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
-
- /* Reset any fatal_error conditions */
- ipw2100_reset_fatalerror(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- if (priv->status & STATUS_POWERED ||
- (priv->status & STATUS_RESET_PENDING)) {
- /* Power cycle the card ... */
- err = ipw2100_power_cycle_adapter(priv);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Could not cycle adapter.\n",
- priv->net_dev->name);
- goto exit;
- }
- } else
- priv->status |= STATUS_POWERED;
-
- /* Load the firmware, start the clocks, etc. */
- err = ipw2100_start_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to start the firmware.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- ipw2100_initialize_ordinals(priv);
-
- /* Determine capabilities of this particular HW configuration */
- err = ipw2100_get_hw_features(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to determine HW features.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- /* Initialize the geo */
- libipw_set_geo(priv->ieee, &ipw_geos[0]);
- priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
-
- lock = LOCK_NONE;
- err = ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to clear ordinal lock.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- priv->status &= ~STATUS_SCANNING;
-
- if (rf_kill_active(priv)) {
- printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
- priv->net_dev->name);
-
- if (priv->stop_rf_kill) {
- priv->stop_rf_kill = 0;
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(HZ));
- }
-
- deferred = 1;
- }
-
- /* Turn on the interrupt so that commands can be processed */
- ipw2100_enable_interrupts(priv);
-
- /* Send all of the commands that must be sent prior to
- * HOST_COMPLETE */
- err = ipw2100_adapter_setup(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- if (!deferred) {
- /* Enable the adapter - sends HOST_COMPLETE */
- err = ipw2100_enable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: failed in call to enable adapter.\n",
- priv->net_dev->name);
- ipw2100_hw_stop_adapter(priv);
- goto exit;
- }
-
- /* Start a scan . . . */
- ipw2100_set_scan_options(priv);
- ipw2100_start_scan(priv);
- }
-
- exit:
- return err;
-}
-
-static void ipw2100_down(struct ipw2100_priv *priv)
-{
- unsigned long flags;
- union iwreq_data wrqu = {
- .ap_addr = {
- .sa_family = ARPHRD_ETHER}
- };
- int associated = priv->status & STATUS_ASSOCIATED;
-
- /* Kill the RF switch timer */
- if (!priv->stop_rf_kill) {
- priv->stop_rf_kill = 1;
- cancel_delayed_work(&priv->rf_kill);
- }
-
- /* Kill the firmware hang check timer */
- if (!priv->stop_hang_check) {
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
- }
-
- /* Kill any pending resets */
- if (priv->status & STATUS_RESET_PENDING)
- cancel_delayed_work(&priv->reset_work);
-
- /* Make sure the interrupt is on so that FW commands will be
- * processed correctly */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- if (ipw2100_hw_stop_adapter(priv))
- printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
- priv->net_dev->name);
-
- /* Do not disable the interrupt until _after_ we disable
- * the adaptor. Otherwise the CARD_DISABLE command will never
- * be ack'd by the firmware */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- cpu_latency_qos_update_request(&ipw2100_pm_qos_req,
- PM_QOS_DEFAULT_VALUE);
-
- /* We have to signal any supplicant if we are disassociating */
- if (associated)
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
-}
-
-static int ipw2100_wdev_init(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct wireless_dev *wdev = &priv->ieee->wdev;
- int i;
-
- memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
-
- /* fill-out priv->ieee->bg_band */
- if (geo->bg_channels) {
- struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
-
- bg_band->band = NL80211_BAND_2GHZ;
- bg_band->n_channels = geo->bg_channels;
- bg_band->channels = kcalloc(geo->bg_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!bg_band->channels) {
- ipw2100_down(priv);
- return -ENOMEM;
- }
- /* translate geo->bg to bg_band.channels */
- for (i = 0; i < geo->bg_channels; i++) {
- bg_band->channels[i].band = NL80211_BAND_2GHZ;
- bg_band->channels[i].center_freq = geo->bg[i].freq;
- bg_band->channels[i].hw_value = geo->bg[i].channel;
- bg_band->channels[i].max_power = geo->bg[i].max_power;
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- bg_band->bitrates = ipw2100_bg_rates;
- bg_band->n_bitrates = RATE_COUNT;
-
- wdev->wiphy->bands[NL80211_BAND_2GHZ] = bg_band;
- }
-
- wdev->wiphy->cipher_suites = ipw_cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
-
- set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
- if (wiphy_register(wdev->wiphy))
- return -EIO;
- return 0;
-}
-
-static void ipw2100_reset_adapter(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, reset_work.work);
- unsigned long flags;
- union iwreq_data wrqu = {
- .ap_addr = {
- .sa_family = ARPHRD_ETHER}
- };
- int associated = priv->status & STATUS_ASSOCIATED;
-
- spin_lock_irqsave(&priv->low_lock, flags);
- IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
- priv->resets++;
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- priv->status |= STATUS_SECURITY_UPDATED;
-
- /* Force a power cycle even if interface hasn't been opened
- * yet */
- cancel_delayed_work(&priv->reset_work);
- priv->status |= STATUS_RESET_PENDING;
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- mutex_lock(&priv->action_mutex);
- /* stop timed checks so that they don't interfere with reset */
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
-
- /* We have to signal any supplicant if we are disassociating */
- if (associated)
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-
- ipw2100_up(priv, 0);
- mutex_unlock(&priv->action_mutex);
-
-}
-
-static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
-{
-
-#define MAC_ASSOCIATION_READ_DELAY (HZ)
- int ret;
- unsigned int len, essid_len;
- char essid[IW_ESSID_MAX_SIZE];
- u32 txrate;
- u32 chan;
- char *txratename;
- u8 bssid[ETH_ALEN];
-
- /*
- * TBD: BSSID is usually 00:00:00:00:00:00 here and not
- * an actual MAC of the AP. Seems like FW sets this
- * address too late. Read it later and expose through
- * /proc or schedule a later task to query and update
- */
-
- essid_len = IW_ESSID_MAX_SIZE;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
- essid, &essid_len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
-
- len = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
-
- len = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
- len = ETH_ALEN;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid,
- &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
- memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
-
- switch (txrate) {
- case TX_RATE_1_MBIT:
- txratename = "1Mbps";
- break;
- case TX_RATE_2_MBIT:
- txratename = "2Mbsp";
- break;
- case TX_RATE_5_5_MBIT:
- txratename = "5.5Mbps";
- break;
- case TX_RATE_11_MBIT:
- txratename = "11Mbps";
- break;
- default:
- IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
- txratename = "unknown rate";
- break;
- }
-
- IPW_DEBUG_INFO("%s: Associated with '%*pE' at %s, channel %d (BSSID=%pM)\n",
- priv->net_dev->name, essid_len, essid,
- txratename, chan, bssid);
-
- /* now we copy read ssid into dev */
- if (!(priv->config & CFG_STATIC_ESSID)) {
- priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
- memcpy(priv->essid, essid, priv->essid_len);
- }
- priv->channel = chan;
- memcpy(priv->bssid, bssid, ETH_ALEN);
-
- priv->status |= STATUS_ASSOCIATING;
- priv->connect_start = ktime_get_boottime_seconds();
-
- schedule_delayed_work(&priv->wx_event_work, HZ / 10);
-}
-
-static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
- int length, int batch_mode)
-{
- int ssid_len = min(length, IW_ESSID_MAX_SIZE);
- struct host_command cmd = {
- .host_command = SSID,
- .host_command_sequence = 0,
- .host_command_length = ssid_len
- };
- int err;
-
- IPW_DEBUG_HC("SSID: '%*pE'\n", ssid_len, essid);
-
- if (ssid_len)
- memcpy(cmd.host_command_parameters, essid, ssid_len);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
- * disable auto association -- so we cheat by setting a bogus SSID */
- if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
- int i;
- u8 *bogus = (u8 *) cmd.host_command_parameters;
- for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
- bogus[i] = 0x18 + i;
- cmd.host_command_length = IW_ESSID_MAX_SIZE;
- }
-
- /* NOTE: We always send the SSID command even if the provided ESSID is
- * the same as what we currently think is set. */
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (!err) {
- memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
- memcpy(priv->essid, essid, ssid_len);
- priv->essid_len = ssid_len;
- }
-
- if (!batch_mode) {
- if (ipw2100_enable_adapter(priv))
- err = -EIO;
- }
-
- return err;
-}
-
-static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
- "disassociated: '%*pE' %pM\n", priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
-
- if (priv->status & STATUS_STOPPING) {
- IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
- return;
- }
-
- eth_zero_addr(priv->bssid);
- eth_zero_addr(priv->ieee->bssid);
-
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
-
- if (!(priv->status & STATUS_RUNNING))
- return;
-
- if (priv->status & STATUS_SECURITY_UPDATED)
- schedule_delayed_work(&priv->security_work, 0);
-
- schedule_delayed_work(&priv->wx_event_work, 0);
-}
-
-static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
- priv->net_dev->name);
-
- /* RF_KILL is now enabled (else we wouldn't be here) */
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- priv->status |= STATUS_RF_KILL_HW;
-
- /* Make sure the RF Kill check timer is running */
- priv->stop_rf_kill = 0;
- mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
-}
-
-static void ipw2100_scan_event(struct work_struct *work)
-{
- struct ipw2100_priv *priv = container_of(work, struct ipw2100_priv,
- scan_event.work);
- union iwreq_data wrqu;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_SCAN("scan complete\n");
- /* Age the scan results... */
- priv->ieee->scans++;
- priv->status &= ~STATUS_SCANNING;
-
- /* Only userspace-requested scan completion events go out immediately */
- if (!priv->user_requested_scan) {
- schedule_delayed_work(&priv->scan_event,
- round_jiffies_relative(msecs_to_jiffies(4000)));
- } else {
- priv->user_requested_scan = 0;
- mod_delayed_work(system_wq, &priv->scan_event, 0);
- }
-}
-
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW2100_HANDLER(v, f) { v, f, # v }
-struct ipw2100_status_indicator {
- int status;
- void (*cb) (struct ipw2100_priv * priv, u32 status);
- char *name;
-};
-#else
-#define IPW2100_HANDLER(v, f) { v, f }
-struct ipw2100_status_indicator {
- int status;
- void (*cb) (struct ipw2100_priv * priv, u32 status);
-};
-#endif /* CONFIG_IPW2100_DEBUG */
-
-static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_SCAN("Scanning...\n");
- priv->status |= STATUS_SCANNING;
-}
-
-static const struct ipw2100_status_indicator status_handlers[] = {
- IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
- IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
- IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
- IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
- IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
- IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
- IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
- IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
- IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
- IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
- IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
- IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
- IPW2100_HANDLER(-1, NULL)
-};
-
-static void isr_status_change(struct ipw2100_priv *priv, int status)
-{
- int i;
-
- if (status == IPW_STATE_SCANNING &&
- priv->status & STATUS_ASSOCIATED &&
- !(priv->status & STATUS_SCANNING)) {
- IPW_DEBUG_INFO("Scan detected while associated, with "
- "no scan request. Restarting firmware.\n");
-
- /* Wake up any sleeping jobs */
- schedule_reset(priv);
- }
-
- for (i = 0; status_handlers[i].status != -1; i++) {
- if (status == status_handlers[i].status) {
- IPW_DEBUG_NOTIF("Status change: %s\n",
- status_handlers[i].name);
- if (status_handlers[i].cb)
- status_handlers[i].cb(priv, status);
- priv->wstats.status = status;
- return;
- }
- }
-
- IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
-}
-
-static void isr_rx_complete_command(struct ipw2100_priv *priv,
- struct ipw2100_cmd_header *cmd)
-{
-#ifdef CONFIG_IPW2100_DEBUG
- if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
- IPW_DEBUG_HC("Command completed '%s (%d)'\n",
- command_types[cmd->host_command_reg],
- cmd->host_command_reg);
- }
-#endif
- if (cmd->host_command_reg == HOST_COMPLETE)
- priv->status |= STATUS_ENABLED;
-
- if (cmd->host_command_reg == CARD_DISABLE)
- priv->status &= ~STATUS_ENABLED;
-
- priv->status &= ~STATUS_CMD_ACTIVE;
-
- wake_up_interruptible(&priv->wait_command_queue);
-}
-
-#ifdef CONFIG_IPW2100_DEBUG
-static const char *frame_types[] = {
- "COMMAND_STATUS_VAL",
- "STATUS_CHANGE_VAL",
- "P80211_DATA_VAL",
- "P8023_DATA_VAL",
- "HOST_NOTIFICATION_VAL"
-};
-#endif
-
-static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
- struct ipw2100_rx_packet *packet)
-{
- packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
- if (!packet->skb)
- return -ENOMEM;
-
- packet->rxp = (struct ipw2100_rx *)packet->skb->data;
- packet->dma_addr = dma_map_single(&priv->pci_dev->dev,
- packet->skb->data,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&priv->pci_dev->dev, packet->dma_addr)) {
- dev_kfree_skb(packet->skb);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-#define SEARCH_ERROR 0xffffffff
-#define SEARCH_FAIL 0xfffffffe
-#define SEARCH_SUCCESS 0xfffffff0
-#define SEARCH_DISCARD 0
-#define SEARCH_SNAPSHOT 1
-
-#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
-static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
-{
- int i;
- if (!priv->snapshot[0])
- return;
- for (i = 0; i < 0x30; i++)
- kfree(priv->snapshot[i]);
- priv->snapshot[0] = NULL;
-}
-
-#ifdef IPW2100_DEBUG_C3
-static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
-{
- int i;
- if (priv->snapshot[0])
- return 1;
- for (i = 0; i < 0x30; i++) {
- priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
- if (!priv->snapshot[i]) {
- IPW_DEBUG_INFO("%s: Error allocating snapshot "
- "buffer %d\n", priv->net_dev->name, i);
- while (i > 0)
- kfree(priv->snapshot[--i]);
- priv->snapshot[0] = NULL;
- return 0;
- }
- }
-
- return 1;
-}
-
-static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
- size_t len, int mode)
-{
- u32 i, j;
- u32 tmp;
- u8 *s, *d;
- u32 ret;
-
- s = in_buf;
- if (mode == SEARCH_SNAPSHOT) {
- if (!ipw2100_snapshot_alloc(priv))
- mode = SEARCH_DISCARD;
- }
-
- for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
- read_nic_dword(priv->net_dev, i, &tmp);
- if (mode == SEARCH_SNAPSHOT)
- *(u32 *) SNAPSHOT_ADDR(i) = tmp;
- if (ret == SEARCH_FAIL) {
- d = (u8 *) & tmp;
- for (j = 0; j < 4; j++) {
- if (*s != *d) {
- s = in_buf;
- continue;
- }
-
- s++;
- d++;
-
- if ((s - in_buf) == len)
- ret = (i + j) - len + 1;
- }
- } else if (mode == SEARCH_DISCARD)
- return ret;
- }
-
- return ret;
-}
-#endif
-
-/*
- *
- * 0) Disconnect the SKB from the firmware (just unmap)
- * 1) Pack the ETH header into the SKB
- * 2) Pass the SKB to the network stack
- *
- * When packet is provided by the firmware, it contains the following:
- *
- * . libipw_hdr
- * . libipw_snap_hdr
- *
- * The size of the constructed ethernet
- *
- */
-#ifdef IPW2100_RX_DEBUG
-static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
-#endif
-
-static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
-{
-#ifdef IPW2100_DEBUG_C3
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- u32 match, reg;
- int j;
-#endif
-
- IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
- i * sizeof(struct ipw2100_status));
-
-#ifdef IPW2100_DEBUG_C3
- /* Halt the firmware so we can get a good image */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
- j = 5;
- do {
- udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
- read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- } while (j--);
-
- match = ipw2100_match_buf(priv, (u8 *) status,
- sizeof(struct ipw2100_status),
- SEARCH_SNAPSHOT);
- if (match < SEARCH_SUCCESS)
- IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
- "offset 0x%06X, length %d:\n",
- priv->net_dev->name, match,
- sizeof(struct ipw2100_status));
- else
- IPW_DEBUG_INFO("%s: No DMA status match in "
- "Firmware.\n", priv->net_dev->name);
-
- printk_buf((u8 *) priv->status_queue.drv,
- sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
-#endif
-
- priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
- priv->net_dev->stats.rx_errors++;
- schedule_reset(priv);
-}
-
-static void isr_rx(struct ipw2100_priv *priv, int i,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- IPW_DEBUG_RX("Handler...\n");
-
- if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
- IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
- " Dropping.\n",
- dev->name,
- status->frame_size, skb_tailroom(packet->skb));
- dev->stats.rx_errors++;
- return;
- }
-
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
- !(priv->status & STATUS_ASSOCIATED))) {
- IPW_DEBUG_DROP("Dropping packet while not associated.\n");
- priv->wstats.discard.misc++;
- return;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
-
- skb_put(packet->skb, status->frame_size);
-
-#ifdef IPW2100_RX_DEBUG
- /* Make a copy of the frame so we can dump it to the logs if
- * libipw_rx fails */
- skb_copy_from_linear_data(packet->skb, packet_data,
- min_t(u32, status->frame_size,
- IPW_RX_NIC_BUFFER_LENGTH));
-#endif
-
- if (!libipw_rx(priv->ieee, packet->skb, stats)) {
-#ifdef IPW2100_RX_DEBUG
- IPW_DEBUG_DROP("%s: Non consumed packet:\n",
- dev->name);
- printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
-#endif
- dev->stats.rx_errors++;
-
- /* libipw_rx failed, so it didn't free the SKB */
- dev_kfree_skb_any(packet->skb);
- packet->skb = NULL;
- }
-
- /* We need to allocate a new SKB and attach it to the RDB. */
- if (unlikely(ipw2100_alloc_skb(priv, packet))) {
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Unable to allocate SKB onto RBD ring - disabling "
- "adapter.\n", dev->name);
- /* TODO: schedule adapter shutdown */
- IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
- }
-
- /* Update the RDB entry */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
-}
-
-#ifdef CONFIG_IPW2100_MONITOR
-
-static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- /* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE */
- struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
- s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
- } *ipw_rt;
-
- IPW_DEBUG_RX("Handler...\n");
-
- if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
- sizeof(struct ipw_rt_hdr))) {
- IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
- " Dropping.\n",
- dev->name,
- status->frame_size,
- skb_tailroom(packet->skb));
- dev->stats.rx_errors++;
- return;
- }
-
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- if (unlikely(priv->config & CFG_CRC_CHECK &&
- status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
- IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
- dev->stats.rx_errors++;
- return;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
- memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
- packet->skb->data, status->frame_size);
-
- ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
-
- ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
-
- ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
-
- skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
-
- if (!libipw_rx(priv->ieee, packet->skb, stats)) {
- dev->stats.rx_errors++;
-
- /* libipw_rx failed, so it didn't free the SKB */
- dev_kfree_skb_any(packet->skb);
- packet->skb = NULL;
- }
-
- /* We need to allocate a new SKB and attach it to the RDB. */
- if (unlikely(ipw2100_alloc_skb(priv, packet))) {
- IPW_DEBUG_WARNING(
- "%s: Unable to allocate SKB onto RBD ring - disabling "
- "adapter.\n", dev->name);
- /* TODO: schedule adapter shutdown */
- IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
- }
-
- /* Update the RDB entry */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
-}
-
-#endif
-
-static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
-{
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
- u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
-
- switch (frame_type) {
- case COMMAND_STATUS_VAL:
- return (status->frame_size != sizeof(u->rx_data.command));
- case STATUS_CHANGE_VAL:
- return (status->frame_size != sizeof(u->rx_data.status));
- case HOST_NOTIFICATION_VAL:
- return (status->frame_size < sizeof(u->rx_data.notification));
- case P80211_DATA_VAL:
- case P8023_DATA_VAL:
-#ifdef CONFIG_IPW2100_MONITOR
- return 0;
-#else
- switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
- case IEEE80211_FTYPE_MGMT:
- case IEEE80211_FTYPE_CTL:
- return 0;
- case IEEE80211_FTYPE_DATA:
- return (status->frame_size >
- IPW_MAX_802_11_PAYLOAD_LENGTH);
- }
-#endif
- }
-
- return 1;
-}
-
-/*
- * ipw2100 interrupts are disabled at this point, and the ISR
- * is the only code that calls this method. So, we do not need
- * to play with any locks.
- *
- * RX Queue works as follows:
- *
- * Read index - firmware places packet in entry identified by the
- * Read index and advances Read index. In this manner,
- * Read index will always point to the next packet to
- * be filled--but not yet valid.
- *
- * Write index - driver fills this entry with an unused RBD entry.
- * This entry has not filled by the firmware yet.
- *
- * In between the W and R indexes are the RBDs that have been received
- * but not yet processed.
- *
- * The process of handling packets will start at WRITE + 1 and advance
- * until it reaches the READ index.
- *
- * The WRITE index is cached in the variable 'priv->rx_queue.next'.
- *
- */
-static void __ipw2100_rx_process(struct ipw2100_priv *priv)
-{
- struct ipw2100_bd_queue *rxq = &priv->rx_queue;
- struct ipw2100_status_queue *sq = &priv->status_queue;
- struct ipw2100_rx_packet *packet;
- u16 frame_type;
- u32 r, w, i, s;
- struct ipw2100_rx *u;
- struct libipw_rx_stats stats = {
- .mac_time = jiffies,
- };
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
-
- if (r >= rxq->entries) {
- IPW_DEBUG_RX("exit - bad read index\n");
- return;
- }
-
- i = (rxq->next + 1) % rxq->entries;
- s = i;
- while (i != r) {
- /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
- r, rxq->next, i); */
-
- packet = &priv->rx_buffers[i];
-
- /* Sync the DMA for the RX buffer so CPU is sure to get
- * the correct values */
- dma_sync_single_for_cpu(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
-
- if (unlikely(ipw2100_corruption_check(priv, i))) {
- ipw2100_corruption_detected(priv, i);
- goto increment;
- }
-
- u = packet->rxp;
- frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
- stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
- stats.len = sq->drv[i].frame_size;
-
- stats.mask = 0;
- if (stats.rssi != 0)
- stats.mask |= LIBIPW_STATMASK_RSSI;
- stats.freq = LIBIPW_24GHZ_BAND;
-
- IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
- priv->net_dev->name, frame_types[frame_type],
- stats.len);
-
- switch (frame_type) {
- case COMMAND_STATUS_VAL:
- /* Reset Rx watchdog */
- isr_rx_complete_command(priv, &u->rx_data.command);
- break;
-
- case STATUS_CHANGE_VAL:
- isr_status_change(priv, u->rx_data.status);
- break;
-
- case P80211_DATA_VAL:
- case P8023_DATA_VAL:
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- isr_rx_monitor(priv, i, &stats);
- break;
- }
-#endif
- if (stats.len < sizeof(struct libipw_hdr_3addr))
- break;
- switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
- case IEEE80211_FTYPE_MGMT:
- libipw_rx_mgt(priv->ieee,
- &u->rx_data.header, &stats);
- break;
-
- case IEEE80211_FTYPE_CTL:
- break;
-
- case IEEE80211_FTYPE_DATA:
- isr_rx(priv, i, &stats);
- break;
-
- }
- break;
- }
-
- increment:
- /* clear status field associated with this RBD */
- rxq->drv[i].status.info.field = 0;
-
- i = (i + 1) % rxq->entries;
- }
-
- if (i != s) {
- /* backtrack one entry, wrapping to end if at 0 */
- rxq->next = (i ? i : rxq->entries) - 1;
-
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
- }
-}
-
-/*
- * __ipw2100_tx_process
- *
- * This routine will determine whether the next packet on
- * the fw_pend_list has been processed by the firmware yet.
- *
- * If not, then it does nothing and returns.
- *
- * If so, then it removes the item from the fw_pend_list, frees
- * any associated storage, and places the item back on the
- * free list of its source (either msg_free_list or tx_free_list)
- *
- * TX Queue works as follows:
- *
- * Read index - points to the next TBD that the firmware will
- * process. The firmware will read the data, and once
- * done processing, it will advance the Read index.
- *
- * Write index - driver fills this entry with an constructed TBD
- * entry. The Write index is not advanced until the
- * packet has been configured.
- *
- * In between the W and R indexes are the TBDs that have NOT been
- * processed. Lagging behind the R index are packets that have
- * been processed but have not been freed by the driver.
- *
- * In order to free old storage, an internal index will be maintained
- * that points to the next packet to be freed. When all used
- * packets have been freed, the oldest index will be the same as the
- * firmware's read index.
- *
- * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
- *
- * Because the TBD structure can not contain arbitrary data, the
- * driver must keep an internal queue of cached allocations such that
- * it can put that data back into the tx_free_list and msg_free_list
- * for use by future command and data packets.
- *
- */
-static int __ipw2100_tx_process(struct ipw2100_priv *priv)
-{
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- int descriptors_used;
- int e, i;
- u32 r, w, frag_num = 0;
-
- if (list_empty(&priv->fw_pend_list))
- return 0;
-
- element = priv->fw_pend_list.next;
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
- tbd = &txq->drv[packet->index];
-
- /* Determine how many TBD entries must be finished... */
- switch (packet->type) {
- case COMMAND:
- /* COMMAND uses only one slot; don't advance */
- descriptors_used = 1;
- e = txq->oldest;
- break;
-
- case DATA:
- /* DATA uses two slots; advance and loop position. */
- descriptors_used = tbd->num_fragments;
- frag_num = tbd->num_fragments - 1;
- e = txq->oldest + frag_num;
- e %= txq->entries;
- break;
-
- default:
- printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
- priv->net_dev->name);
- return 0;
- }
-
- /* if the last TBD is not done by NIC yet, then packet is
- * not ready to be released.
- *
- */
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
- &r);
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- &w);
- if (w != txq->next)
- printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
- priv->net_dev->name);
-
- /*
- * txq->next is the index of the last packet written txq->oldest is
- * the index of the r is the index of the next packet to be read by
- * firmware
- */
-
- /*
- * Quick graphic to help you visualize the following
- * if / else statement
- *
- * ===>| s---->|===============
- * e>|
- * | a | b | c | d | e | f | g | h | i | j | k | l
- * r---->|
- * w
- *
- * w - updated by driver
- * r - updated by firmware
- * s - start of oldest BD entry (txq->oldest)
- * e - end of oldest BD entry
- *
- */
- if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
- IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
- return 0;
- }
-
- list_del(element);
- DEC_STAT(&priv->fw_pend_stat);
-
-#ifdef CONFIG_IPW2100_DEBUG
- {
- i = txq->oldest;
- IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
- txq->drv[i].host_addr, txq->drv[i].buf_length);
-
- if (packet->type == DATA) {
- i = (i + 1) % txq->entries;
-
- IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32) (txq->nic + i *
- sizeof(struct ipw2100_bd)),
- (u32) txq->drv[i].host_addr,
- txq->drv[i].buf_length);
- }
- }
-#endif
-
- switch (packet->type) {
- case DATA:
- if (txq->drv[txq->oldest].status.info.fields.txType != 0)
- printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
- "Expecting DATA TBD but pulled "
- "something else: ids %d=%d.\n",
- priv->net_dev->name, txq->oldest, packet->index);
-
- /* DATA packet; we have to unmap and free the SKB */
- for (i = 0; i < frag_num; i++) {
- tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
-
- IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
- (packet->index + 1 + i) % txq->entries,
- tbd->host_addr, tbd->buf_length);
-
- dma_unmap_single(&priv->pci_dev->dev, tbd->host_addr,
- tbd->buf_length, DMA_TO_DEVICE);
- }
-
- libipw_txb_free(packet->info.d_struct.txb);
- packet->info.d_struct.txb = NULL;
-
- list_add_tail(element, &priv->tx_free_list);
- INC_STAT(&priv->tx_free_stat);
-
- /* We have a free slot in the Tx queue, so wake up the
- * transmit layer if it is stopped. */
- if (priv->status & STATUS_ASSOCIATED)
- netif_wake_queue(priv->net_dev);
-
- /* A packet was processed by the hardware, so update the
- * watchdog */
- netif_trans_update(priv->net_dev);
-
- break;
-
- case COMMAND:
- if (txq->drv[txq->oldest].status.info.fields.txType != 1)
- printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
- "Expecting COMMAND TBD but pulled "
- "something else: ids %d=%d.\n",
- priv->net_dev->name, txq->oldest, packet->index);
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (packet->info.c_struct.cmd->host_command_reg <
- ARRAY_SIZE(command_types))
- IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
- command_types[packet->info.c_struct.cmd->
- host_command_reg],
- packet->info.c_struct.cmd->
- host_command_reg,
- packet->info.c_struct.cmd->cmd_status_reg);
-#endif
-
- list_add_tail(element, &priv->msg_free_list);
- INC_STAT(&priv->msg_free_stat);
- break;
- }
-
- /* advance oldest used TBD pointer to start of next entry */
- txq->oldest = (e + 1) % txq->entries;
- /* increase available TBDs number */
- txq->available += descriptors_used;
- SET_STAT(&priv->txq_stat, txq->available);
-
- IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
- jiffies - packet->jiffy_start);
-
- return (!list_empty(&priv->fw_pend_list));
-}
-
-static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
-{
- int i = 0;
-
- while (__ipw2100_tx_process(priv) && i < 200)
- i++;
-
- if (i == 200) {
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Driver is running slow (%d iters).\n",
- priv->net_dev->name, i);
- }
-}
-
-static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- int next = txq->next;
-
- while (!list_empty(&priv->msg_pend_list)) {
- /* if there isn't enough space in TBD queue, then
- * don't stuff a new one in.
- * NOTE: 3 are needed as a command will take one,
- * and there is a minimum of 2 that must be
- * maintained between the r and w indexes
- */
- if (txq->available <= 3) {
- IPW_DEBUG_TX("no room in tx_queue\n");
- break;
- }
-
- element = priv->msg_pend_list.next;
- list_del(element);
- DEC_STAT(&priv->msg_pend_stat);
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
- &txq->drv[txq->next],
- (u32) (txq->nic + txq->next *
- sizeof(struct ipw2100_bd)));
-
- packet->index = txq->next;
-
- tbd = &txq->drv[txq->next];
-
- /* initialize TBD */
- tbd->host_addr = packet->info.c_struct.cmd_phys;
- tbd->buf_length = sizeof(struct ipw2100_cmd_header);
- /* not marking number of fragments causes problems
- * with f/w debug version */
- tbd->num_fragments = 1;
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_COMMAND |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
-
- /* update TBD queue counters */
- txq->next++;
- txq->next %= txq->entries;
- txq->available--;
- DEC_STAT(&priv->txq_stat);
-
- list_add_tail(element, &priv->fw_pend_list);
- INC_STAT(&priv->fw_pend_stat);
- }
-
- if (txq->next != next) {
- /* kick off the DMA by notifying firmware the
- * write index has moved; make sure TBD stores are sync'd */
- wmb();
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- txq->next);
- }
-}
-
-/*
- * ipw2100_tx_send_data
- *
- */
-static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- int next = txq->next;
- int i = 0;
- struct ipw2100_data_header *ipw_hdr;
- struct libipw_hdr_3addr *hdr;
-
- while (!list_empty(&priv->tx_pend_list)) {
- /* if there isn't enough space in TBD queue, then
- * don't stuff a new one in.
- * NOTE: 4 are needed as a data will take two,
- * and there is a minimum of 2 that must be
- * maintained between the r and w indexes
- */
- element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
- IPW_MAX_BDS)) {
- /* TODO: Support merging buffers if more than
- * IPW_MAX_BDS are used */
- IPW_DEBUG_INFO("%s: Maximum BD threshold exceeded. "
- "Increase fragmentation level.\n",
- priv->net_dev->name);
- }
-
- if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
- IPW_DEBUG_TX("no room in tx_queue\n");
- break;
- }
-
- list_del(element);
- DEC_STAT(&priv->tx_pend_stat);
-
- tbd = &txq->drv[txq->next];
-
- packet->index = txq->next;
-
- ipw_hdr = packet->info.d_struct.data;
- hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
- fragments[0]->data;
-
- if (priv->ieee->iw_mode == IW_MODE_INFRA) {
- /* To DS: Addr1 = BSSID, Addr2 = SA,
- Addr3 = DA */
- memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
- } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA,
- Addr3 = BSSID */
- memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
- }
-
- ipw_hdr->host_command_reg = SEND;
- ipw_hdr->host_command_reg1 = 0;
-
- /* For now we only support host based encryption */
- ipw_hdr->needs_encryption = 0;
- ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
- if (packet->info.d_struct.txb->nr_frags > 1)
- ipw_hdr->fragment_size =
- packet->info.d_struct.txb->frag_size -
- LIBIPW_3ADDR_LEN;
- else
- ipw_hdr->fragment_size = 0;
-
- tbd->host_addr = packet->info.d_struct.data_phys;
- tbd->buf_length = sizeof(struct ipw2100_data_header);
- tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
- txq->next++;
- txq->next %= txq->entries;
-
- IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
- packet->index, tbd->host_addr, tbd->buf_length);
-#ifdef CONFIG_IPW2100_DEBUG
- if (packet->info.d_struct.txb->nr_frags > 1)
- IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
- packet->info.d_struct.txb->nr_frags);
-#endif
-
- for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
- tbd = &txq->drv[txq->next];
- if (i == packet->info.d_struct.txb->nr_frags - 1)
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
- else
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
-
- tbd->buf_length = packet->info.d_struct.txb->
- fragments[i]->len - LIBIPW_3ADDR_LEN;
-
- tbd->host_addr = dma_map_single(&priv->pci_dev->dev,
- packet->info.d_struct.
- txb->fragments[i]->data +
- LIBIPW_3ADDR_LEN,
- tbd->buf_length,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&priv->pci_dev->dev, tbd->host_addr)) {
- IPW_DEBUG_TX("dma mapping error\n");
- break;
- }
-
- IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
- txq->next, tbd->host_addr,
- tbd->buf_length);
-
- dma_sync_single_for_device(&priv->pci_dev->dev,
- tbd->host_addr,
- tbd->buf_length,
- DMA_TO_DEVICE);
-
- txq->next++;
- txq->next %= txq->entries;
- }
-
- txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
- SET_STAT(&priv->txq_stat, txq->available);
-
- list_add_tail(element, &priv->fw_pend_list);
- INC_STAT(&priv->fw_pend_stat);
- }
-
- if (txq->next != next) {
- /* kick off the DMA by notifying firmware the
- * write index has moved; make sure TBD stores are sync'd */
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- txq->next);
- }
-}
-
-static void ipw2100_irq_tasklet(struct tasklet_struct *t)
-{
- struct ipw2100_priv *priv = from_tasklet(priv, t, irq_tasklet);
- struct net_device *dev = priv->net_dev;
- unsigned long flags;
- u32 inta, tmp;
-
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
-
- read_register(dev, IPW_REG_INTA, &inta);
-
- IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
- (unsigned long)inta & IPW_INTERRUPT_MASK);
-
- priv->in_isr++;
- priv->interrupts++;
-
- /* We do not loop and keep polling for more interrupts as this
- * is frowned upon and doesn't play nicely with other potentially
- * chained IRQs */
- IPW_DEBUG_ISR("INTA: 0x%08lX\n",
- (unsigned long)inta & IPW_INTERRUPT_MASK);
-
- if (inta & IPW2100_INTA_FATAL_ERROR) {
- printk(KERN_WARNING DRV_NAME
- ": Fatal interrupt. Scheduling firmware restart.\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
-
- read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
- IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
- priv->net_dev->name, priv->fatal_error);
-
- read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
- IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
- priv->net_dev->name, tmp);
-
- /* Wake up any sleeping jobs */
- schedule_reset(priv);
- }
-
- if (inta & IPW2100_INTA_PARITY_ERROR) {
- printk(KERN_ERR DRV_NAME
- ": ***** PARITY ERROR INTERRUPT !!!!\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
- }
-
- if (inta & IPW2100_INTA_RX_TRANSFER) {
- IPW_DEBUG_ISR("RX interrupt\n");
-
- priv->rx_interrupts++;
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
-
- __ipw2100_rx_process(priv);
- __ipw2100_tx_complete(priv);
- }
-
- if (inta & IPW2100_INTA_TX_TRANSFER) {
- IPW_DEBUG_ISR("TX interrupt\n");
-
- priv->tx_interrupts++;
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
-
- __ipw2100_tx_complete(priv);
- ipw2100_tx_send_commands(priv);
- ipw2100_tx_send_data(priv);
- }
-
- if (inta & IPW2100_INTA_TX_COMPLETE) {
- IPW_DEBUG_ISR("TX complete\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
-
- __ipw2100_tx_complete(priv);
- }
-
- if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
- /* ipw2100_handle_event(dev); */
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
- }
-
- if (inta & IPW2100_INTA_FW_INIT_DONE) {
- IPW_DEBUG_ISR("FW init done interrupt\n");
- priv->inta_other++;
-
- read_register(dev, IPW_REG_INTA, &tmp);
- if (tmp & (IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR)) {
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR);
- }
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
- }
-
- if (inta & IPW2100_INTA_STATUS_CHANGE) {
- IPW_DEBUG_ISR("Status change interrupt\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
- }
-
- if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
- IPW_DEBUG_ISR("slave host mode interrupt\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
- }
-
- priv->in_isr--;
- ipw2100_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- IPW_DEBUG_ISR("exit\n");
-}
-
-static irqreturn_t ipw2100_interrupt(int irq, void *data)
-{
- struct ipw2100_priv *priv = data;
- u32 inta, inta_mask;
-
- if (!data)
- return IRQ_NONE;
-
- spin_lock(&priv->low_lock);
-
- /* We check to see if we should be ignoring interrupts before
- * we touch the hardware. During ucode load if we try and handle
- * an interrupt we can cause keyboard problems as well as cause
- * the ucode to fail to initialize */
- if (!(priv->status & STATUS_INT_ENABLED)) {
- /* Shared IRQ */
- goto none;
- }
-
- read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
- goto none;
- }
-
- inta &= IPW_INTERRUPT_MASK;
-
- if (!(inta & inta_mask)) {
- /* Shared interrupt */
- goto none;
- }
-
- /* We disable the hardware interrupt here just to prevent unneeded
- * calls to be made. We disable this again within the actual
- * work tasklet, so if another part of the code re-enables the
- * interrupt, that is fine */
- ipw2100_disable_interrupts(priv);
-
- tasklet_schedule(&priv->irq_tasklet);
- spin_unlock(&priv->low_lock);
-
- return IRQ_HANDLED;
- none:
- spin_unlock(&priv->low_lock);
- return IRQ_NONE;
-}
-
-static netdev_tx_t ipw2100_tx(struct libipw_txb *txb,
- struct net_device *dev, int pri)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_INFO("Can not transmit when not connected.\n");
- priv->net_dev->stats.tx_carrier_errors++;
- netif_stop_queue(dev);
- goto fail_unlock;
- }
-
- if (list_empty(&priv->tx_free_list))
- goto fail_unlock;
-
- element = priv->tx_free_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- packet->info.d_struct.txb = txb;
-
- IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
- printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
-
- packet->jiffy_start = jiffies;
-
- list_del(element);
- DEC_STAT(&priv->tx_free_stat);
-
- list_add_tail(element, &priv->tx_pend_list);
- INC_STAT(&priv->tx_pend_stat);
-
- ipw2100_tx_send_data(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
- return NETDEV_TX_OK;
-
-fail_unlock:
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&priv->low_lock, flags);
- return NETDEV_TX_BUSY;
-}
-
-static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err = -EINVAL;
- void *v;
- dma_addr_t p;
-
- priv->msg_buffers =
- kmalloc_array(IPW_COMMAND_POOL_SIZE,
- sizeof(struct ipw2100_tx_packet),
- GFP_KERNEL);
- if (!priv->msg_buffers)
- return -ENOMEM;
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
- v = dma_alloc_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header), &p,
- GFP_KERNEL);
- if (!v) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: PCI alloc failed for msg "
- "buffers.\n", priv->net_dev->name);
- err = -ENOMEM;
- break;
- }
-
- priv->msg_buffers[i].type = COMMAND;
- priv->msg_buffers[i].info.c_struct.cmd =
- (struct ipw2100_cmd_header *)v;
- priv->msg_buffers[i].info.c_struct.cmd_phys = p;
- }
-
- if (i == IPW_COMMAND_POOL_SIZE)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header),
- priv->msg_buffers[j].info.c_struct.cmd,
- priv->msg_buffers[j].info.c_struct.cmd_phys);
- }
-
- kfree(priv->msg_buffers);
- priv->msg_buffers = NULL;
-
- return err;
-}
-
-static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
-{
- int i;
-
- INIT_LIST_HEAD(&priv->msg_free_list);
- INIT_LIST_HEAD(&priv->msg_pend_list);
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
- list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
- SET_STAT(&priv->msg_free_stat, i);
-
- return 0;
-}
-
-static void ipw2100_msg_free(struct ipw2100_priv *priv)
-{
- int i;
-
- if (!priv->msg_buffers)
- return;
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header),
- priv->msg_buffers[i].info.c_struct.cmd,
- priv->msg_buffers[i].info.c_struct.cmd_phys);
- }
-
- kfree(priv->msg_buffers);
- priv->msg_buffers = NULL;
-}
-
-static ssize_t pci_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct pci_dev *pci_dev = to_pci_dev(d);
- char *out = buf;
- int i, j;
- u32 val;
-
- for (i = 0; i < 16; i++) {
- out += sprintf(out, "[%08X] ", i * 16);
- for (j = 0; j < 16; j += 4) {
- pci_read_config_dword(pci_dev, i * 16 + j, &val);
- out += sprintf(out, "%08X ", val);
- }
- out += sprintf(out, "\n");
- }
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(pci);
-
-static ssize_t cfg_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->config);
-}
-
-static DEVICE_ATTR_RO(cfg);
-
-static ssize_t status_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->status);
-}
-
-static DEVICE_ATTR_RO(status);
-
-static ssize_t capability_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->capability);
-}
-
-static DEVICE_ATTR_RO(capability);
-
-#define IPW2100_REG(x) { IPW_ ##x, #x }
-static const struct {
- u32 addr;
- const char *name;
-} hw_data[] = {
-IPW2100_REG(REG_GP_CNTRL),
- IPW2100_REG(REG_GPIO),
- IPW2100_REG(REG_INTA),
- IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
-#define IPW2100_NIC(x, s) { x, #x, s }
-static const struct {
- u32 addr;
- const char *name;
- size_t size;
-} nic_data[] = {
-IPW2100_NIC(IPW2100_CONTROL_REG, 2),
- IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
-#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
-static const struct {
- u8 index;
- const char *name;
- const char *desc;
-} ord_data[] = {
-IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_HOST_COMPLETE,
- "successful Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA,
- "successful Directed Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA1,
- "successful Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA2,
- "successful Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA5_5,
- "successful Directed Tx's (MSDU) @ 5_5MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA11,
- "successful Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA1,
- "successful Non_Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA2,
- "successful Non_Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
- "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA11,
- "successful Non_Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
- IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
- IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
- IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
- IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
- IPW2100_ORD(STAT_TX_ASSN_RESP,
- "successful Association response Tx's"),
- IPW2100_ORD(STAT_TX_REASSN,
- "successful Reassociation Tx's"),
- IPW2100_ORD(STAT_TX_REASSN_RESP,
- "successful Reassociation response Tx's"),
- IPW2100_ORD(STAT_TX_PROBE,
- "probes successfully transmitted"),
- IPW2100_ORD(STAT_TX_PROBE_RESP,
- "probe responses successfully transmitted"),
- IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
- IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
- IPW2100_ORD(STAT_TX_DISASSN,
- "successful Disassociation TX"),
- IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
- IPW2100_ORD(STAT_TX_DEAUTH,
- "successful Deauthentication TX"),
- IPW2100_ORD(STAT_TX_TOTAL_BYTES,
- "Total successful Tx data bytes"),
- IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
- IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
- IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
- IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
- IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
- IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
- IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
- "times max tries in a hop failed"),
- IPW2100_ORD(STAT_TX_DISASSN_FAIL,
- "times disassociation failed"),
- IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
- IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
- IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
- IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
- IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA5_5,
- "directed packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
- IPW2100_ORD(STAT_RX_NODIR_DATA1,
- "nondirected packets at 1MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA2,
- "nondirected packets at 2MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
- "nondirected packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA11,
- "nondirected packets at 11MB"),
- IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
- IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
- "Rx CTS"),
- IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
- IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
- IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
- IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
- IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
- IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
- IPW2100_ORD(STAT_RX_REASSN_RESP,
- "Reassociation response Rx's"),
- IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
- IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
- IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
- IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
- IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
- IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
- IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
- IPW2100_ORD(STAT_RX_TOTAL_BYTES,
- "Total rx data bytes received"),
- IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
- IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE1,
- "duplicate rx packets at 1MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE2,
- "duplicate rx packets at 2MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE5_5,
- "duplicate rx packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE11,
- "duplicate rx packets at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
- IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
- IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
- IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
- IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
- "rx frames with invalid protocol"),
- IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
- IPW2100_ORD(STAT_RX_NO_BUFFER,
- "rx frames rejected due to no buffer"),
- IPW2100_ORD(STAT_RX_MISSING_FRAG,
- "rx frames dropped due to missing fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
- "rx frames dropped due to non-sequential fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
- "rx frames dropped due to unmatched 1st frame"),
- IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
- "rx frames dropped due to uncompleted frame"),
- IPW2100_ORD(STAT_RX_ICV_ERRORS,
- "ICV errors during decryption"),
- IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
- IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
- IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
- "poll response timeouts"),
- IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
- "timeouts waiting for last {broad,multi}cast pkt"),
- IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
- IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
- IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
- IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
- IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
- "current calculation of % missed beacons"),
- IPW2100_ORD(STAT_PERCENT_RETRIES,
- "current calculation of % missed tx retries"),
- IPW2100_ORD(ASSOCIATED_AP_PTR,
- "0 if not associated, else pointer to AP table entry"),
- IPW2100_ORD(AVAILABLE_AP_CNT,
- "AP's described in the AP table"),
- IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
- IPW2100_ORD(STAT_AP_ASSNS, "associations"),
- IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
- IPW2100_ORD(STAT_ASSN_RESP_FAIL,
- "failures due to response fail"),
- IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
- IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
- IPW2100_ORD(STAT_ROAM_INHIBIT,
- "times roaming was inhibited due to activity"),
- IPW2100_ORD(RSSI_AT_ASSN,
- "RSSI of associated AP at time of association"),
- IPW2100_ORD(STAT_ASSN_CAUSE1,
- "reassociation: no probe response or TX on hop"),
- IPW2100_ORD(STAT_ASSN_CAUSE2,
- "reassociation: poor tx/rx quality"),
- IPW2100_ORD(STAT_ASSN_CAUSE3,
- "reassociation: tx/rx quality (excessive AP load"),
- IPW2100_ORD(STAT_ASSN_CAUSE4,
- "reassociation: AP RSSI level"),
- IPW2100_ORD(STAT_ASSN_CAUSE5,
- "reassociations due to load leveling"),
- IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
- IPW2100_ORD(STAT_AUTH_RESP_FAIL,
- "times authentication response failed"),
- IPW2100_ORD(STATION_TABLE_CNT,
- "entries in association table"),
- IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
- IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
- IPW2100_ORD(COUNTRY_CODE,
- "IEEE country code as recv'd from beacon"),
- IPW2100_ORD(COUNTRY_CHANNELS,
- "channels supported by country"),
- IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
- IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
- IPW2100_ORD(ANTENNA_DIVERSITY,
- "TRUE if antenna diversity is disabled"),
- IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
- IPW2100_ORD(OUR_FREQ,
- "current radio freq lower digits - channel ID"),
- IPW2100_ORD(RTC_TIME, "current RTC time"),
- IPW2100_ORD(PORT_TYPE, "operating mode"),
- IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
- IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
- IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
- IPW2100_ORD(BASIC_RATES, "basic tx rates"),
- IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
- IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
- IPW2100_ORD(CAPABILITIES,
- "Management frame capability field"),
- IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
- IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
- IPW2100_ORD(RTS_THRESHOLD,
- "Min packet length for RTS handshaking"),
- IPW2100_ORD(INT_MODE, "International mode"),
- IPW2100_ORD(FRAGMENTATION_THRESHOLD,
- "protocol frag threshold"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
- "EEPROM offset in SRAM"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
- "EEPROM size in SRAM"),
- IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
- IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
- "EEPROM IBSS 11b channel set"),
- IPW2100_ORD(MAC_VERSION, "MAC Version"),
- IPW2100_ORD(MAC_REVISION, "MAC Revision"),
- IPW2100_ORD(RADIO_VERSION, "Radio Version"),
- IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
- IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
-
-static ssize_t registers_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- int i;
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- char *out = buf;
- u32 val = 0;
-
- out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
-
- for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
- read_register(dev, hw_data[i].addr, &val);
- out += sprintf(out, "%30s [%08X] : %08X\n",
- hw_data[i].name, hw_data[i].addr, val);
- }
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(registers);
-
-static ssize_t hardware_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- char *out = buf;
- int i;
-
- out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
-
- for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
- u8 tmp8;
- u16 tmp16;
- u32 tmp32;
-
- switch (nic_data[i].size) {
- case 1:
- read_nic_byte(dev, nic_data[i].addr, &tmp8);
- out += sprintf(out, "%30s [%08X] : %02X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp8);
- break;
- case 2:
- read_nic_word(dev, nic_data[i].addr, &tmp16);
- out += sprintf(out, "%30s [%08X] : %04X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp16);
- break;
- case 4:
- read_nic_dword(dev, nic_data[i].addr, &tmp32);
- out += sprintf(out, "%30s [%08X] : %08X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp32);
- break;
- }
- }
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(hardware);
-
-static ssize_t memory_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- static unsigned long loop = 0;
- int len = 0;
- u32 buffer[4];
- int i;
- char line[81];
-
- if (loop >= 0x30000)
- loop = 0;
-
- /* sysfs provides us PAGE_SIZE buffer */
- while (len < PAGE_SIZE - 128 && loop < 0x30000) {
-
- if (priv->snapshot[0])
- for (i = 0; i < 4; i++)
- buffer[i] =
- *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
- else
- for (i = 0; i < 4; i++)
- read_nic_dword(dev, loop + i * 4, &buffer[i]);
-
- if (priv->dump_raw)
- len += sprintf(buf + len,
- "%c%c%c%c"
- "%c%c%c%c"
- "%c%c%c%c"
- "%c%c%c%c",
- ((u8 *) buffer)[0x0],
- ((u8 *) buffer)[0x1],
- ((u8 *) buffer)[0x2],
- ((u8 *) buffer)[0x3],
- ((u8 *) buffer)[0x4],
- ((u8 *) buffer)[0x5],
- ((u8 *) buffer)[0x6],
- ((u8 *) buffer)[0x7],
- ((u8 *) buffer)[0x8],
- ((u8 *) buffer)[0x9],
- ((u8 *) buffer)[0xa],
- ((u8 *) buffer)[0xb],
- ((u8 *) buffer)[0xc],
- ((u8 *) buffer)[0xd],
- ((u8 *) buffer)[0xe],
- ((u8 *) buffer)[0xf]);
- else
- len += sprintf(buf + len, "%s\n",
- snprint_line(line, sizeof(line),
- (u8 *) buffer, 16, loop));
- loop += 16;
- }
-
- return len;
-}
-
-static ssize_t memory_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- const char *p = buf;
-
- (void)dev; /* kill unused-var warning for debug-only code */
-
- if (count < 1)
- return count;
-
- if (p[0] == '1' ||
- (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
- IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
- dev->name);
- priv->dump_raw = 1;
-
- } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
- tolower(p[1]) == 'f')) {
- IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
- dev->name);
- priv->dump_raw = 0;
-
- } else if (tolower(p[0]) == 'r') {
- IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
- ipw2100_snapshot_free(priv);
-
- } else
- IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
- "reset = clear memory snapshot\n", dev->name);
-
- return count;
-}
-
-static DEVICE_ATTR_RW(memory);
-
-static ssize_t ordinals_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- u32 val = 0;
- int len = 0;
- u32 val_len;
- static int loop = 0;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return 0;
-
- if (loop >= ARRAY_SIZE(ord_data))
- loop = 0;
-
- /* sysfs provides us PAGE_SIZE buffer */
- while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
- val_len = sizeof(u32);
-
- if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
- &val_len))
- len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
- ord_data[loop].index,
- ord_data[loop].desc);
- else
- len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
- ord_data[loop].index, val,
- ord_data[loop].desc);
- loop++;
- }
-
- return len;
-}
-
-static DEVICE_ATTR_RO(ordinals);
-
-static ssize_t stats_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char *out = buf;
-
- out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
- priv->interrupts, priv->tx_interrupts,
- priv->rx_interrupts, priv->inta_other);
- out += sprintf(out, "firmware resets: %d\n", priv->resets);
- out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
-#ifdef CONFIG_IPW2100_DEBUG
- out += sprintf(out, "packet mismatch image: %s\n",
- priv->snapshot[0] ? "YES" : "NO");
-#endif
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(stats);
-
-static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
-{
- int err;
-
- if (mode == priv->ieee->iw_mode)
- return 0;
-
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
-
- switch (mode) {
- case IW_MODE_INFRA:
- priv->net_dev->type = ARPHRD_ETHER;
- break;
- case IW_MODE_ADHOC:
- priv->net_dev->type = ARPHRD_ETHER;
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- priv->last_mode = priv->ieee->iw_mode;
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- break;
-#endif /* CONFIG_IPW2100_MONITOR */
- }
-
- priv->ieee->iw_mode = mode;
-
-#ifdef CONFIG_PM
- /* Indicate ipw2100_download_firmware download firmware
- * from disk instead of memory. */
- ipw2100_firmware.version = 0;
-#endif
-
- printk(KERN_INFO "%s: Resetting on mode change.\n", priv->net_dev->name);
- priv->reset_backoff = 0;
- schedule_reset(priv);
-
- return 0;
-}
-
-static ssize_t internals_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- int len = 0;
-
-#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
-
- if (priv->status & STATUS_ASSOCIATED)
- len += sprintf(buf + len, "connected: %llu\n",
- ktime_get_boottime_seconds() - priv->connect_start);
- else
- len += sprintf(buf + len, "not connected\n");
-
- DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
- DUMP_VAR(status, "08lx");
- DUMP_VAR(config, "08lx");
- DUMP_VAR(capability, "08lx");
-
- len +=
- sprintf(buf + len, "last_rtc: %lu\n",
- (unsigned long)priv->last_rtc);
-
- DUMP_VAR(fatal_error, "d");
- DUMP_VAR(stop_hang_check, "d");
- DUMP_VAR(stop_rf_kill, "d");
- DUMP_VAR(messages_sent, "d");
-
- DUMP_VAR(tx_pend_stat.value, "d");
- DUMP_VAR(tx_pend_stat.hi, "d");
-
- DUMP_VAR(tx_free_stat.value, "d");
- DUMP_VAR(tx_free_stat.lo, "d");
-
- DUMP_VAR(msg_free_stat.value, "d");
- DUMP_VAR(msg_free_stat.lo, "d");
-
- DUMP_VAR(msg_pend_stat.value, "d");
- DUMP_VAR(msg_pend_stat.hi, "d");
-
- DUMP_VAR(fw_pend_stat.value, "d");
- DUMP_VAR(fw_pend_stat.hi, "d");
-
- DUMP_VAR(txq_stat.value, "d");
- DUMP_VAR(txq_stat.lo, "d");
-
- DUMP_VAR(ieee->scans, "d");
- DUMP_VAR(reset_backoff, "lld");
-
- return len;
-}
-
-static DEVICE_ATTR_RO(internals);
-
-static ssize_t bssinfo_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char essid[IW_ESSID_MAX_SIZE + 1];
- u8 bssid[ETH_ALEN];
- u32 chan = 0;
- char *out = buf;
- unsigned int length;
- int ret;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return 0;
-
- memset(essid, 0, sizeof(essid));
- memset(bssid, 0, sizeof(bssid));
-
- length = IW_ESSID_MAX_SIZE;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- length = sizeof(bssid);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
- bssid, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- length = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- out += sprintf(out, "ESSID: %s\n", essid);
- out += sprintf(out, "BSSID: %pM\n", bssid);
- out += sprintf(out, "Channel: %d\n", chan);
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(bssinfo);
-
-#ifdef CONFIG_IPW2100_DEBUG
-static ssize_t debug_level_show(struct device_driver *d, char *buf)
-{
- return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
-}
-
-static ssize_t debug_level_store(struct device_driver *d,
- const char *buf, size_t count)
-{
- u32 val;
- int ret;
-
- ret = kstrtou32(buf, 0, &val);
- if (ret)
- IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
- else
- ipw2100_debug_level = val;
-
- return strnlen(buf, count);
-}
-static DRIVER_ATTR_RW(debug_level);
-#endif /* CONFIG_IPW2100_DEBUG */
-
-static ssize_t fatal_error_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char *out = buf;
- int i;
-
- if (priv->fatal_error)
- out += sprintf(out, "0x%08X\n", priv->fatal_error);
- else
- out += sprintf(out, "0\n");
-
- for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
- if (!priv->fatal_errors[(priv->fatal_index - i) %
- IPW2100_ERROR_QUEUE])
- continue;
-
- out += sprintf(out, "%d. 0x%08X\n", i,
- priv->fatal_errors[(priv->fatal_index - i) %
- IPW2100_ERROR_QUEUE]);
- }
-
- return out - buf;
-}
-
-static ssize_t fatal_error_store(struct device *d,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- schedule_reset(priv);
- return count;
-}
-
-static DEVICE_ATTR_RW(fatal_error);
-
-static ssize_t scan_age_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", priv->ieee->scan_age);
-}
-
-static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- unsigned long val;
- int ret;
-
- (void)dev; /* kill unused-var warning for debug-only code */
-
- IPW_DEBUG_INFO("enter\n");
-
- ret = kstrtoul(buf, 0, &val);
- if (ret) {
- IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
- } else {
- priv->ieee->scan_age = val;
- IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(scan_age);
-
-static ssize_t rf_kill_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- /* 0 - RF kill not enabled
- 1 - SW based RF kill active (sysfs)
- 2 - HW based RF kill active
- 3 - Both HW and SW baed RF kill active */
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
- (rf_kill_active(priv) ? 0x2 : 0x0);
- return sprintf(buf, "%i\n", val);
-}
-
-static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
-{
- if ((disable_radio ? 1 : 0) ==
- (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
- return 0;
-
- IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
- disable_radio ? "OFF" : "ON");
-
- mutex_lock(&priv->action_mutex);
-
- if (disable_radio) {
- priv->status |= STATUS_RF_KILL_SW;
- ipw2100_down(priv);
- } else {
- priv->status &= ~STATUS_RF_KILL_SW;
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("Can not turn radio back on - "
- "disabled by HW switch\n");
- /* Make sure the RF_KILL check timer is running */
- priv->stop_rf_kill = 0;
- mod_delayed_work(system_wq, &priv->rf_kill,
- round_jiffies_relative(HZ));
- } else
- schedule_reset(priv);
- }
-
- mutex_unlock(&priv->action_mutex);
- return 1;
-}
-
-static ssize_t rf_kill_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- ipw_radio_kill_sw(priv, buf[0] == '1');
- return count;
-}
-
-static DEVICE_ATTR_RW(rf_kill);
-
-static struct attribute *ipw2100_sysfs_entries[] = {
- &dev_attr_hardware.attr,
- &dev_attr_registers.attr,
- &dev_attr_ordinals.attr,
- &dev_attr_pci.attr,
- &dev_attr_stats.attr,
- &dev_attr_internals.attr,
- &dev_attr_bssinfo.attr,
- &dev_attr_memory.attr,
- &dev_attr_scan_age.attr,
- &dev_attr_fatal_error.attr,
- &dev_attr_rf_kill.attr,
- &dev_attr_cfg.attr,
- &dev_attr_status.attr,
- &dev_attr_capability.attr,
- NULL,
-};
-
-static const struct attribute_group ipw2100_attribute_group = {
- .attrs = ipw2100_sysfs_entries,
-};
-
-static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
-{
- struct ipw2100_status_queue *q = &priv->status_queue;
-
- IPW_DEBUG_INFO("enter\n");
-
- q->size = entries * sizeof(struct ipw2100_status);
- q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
- GFP_KERNEL);
- if (!q->drv) {
- IPW_DEBUG_WARNING("Can not allocate status queue.\n");
- return -ENOMEM;
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void status_queue_free(struct ipw2100_priv *priv)
-{
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->status_queue.drv) {
- dma_free_coherent(&priv->pci_dev->dev,
- priv->status_queue.size,
- priv->status_queue.drv,
- priv->status_queue.nic);
- priv->status_queue.drv = NULL;
- }
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int bd_queue_allocate(struct ipw2100_priv *priv,
- struct ipw2100_bd_queue *q, int entries)
-{
- IPW_DEBUG_INFO("enter\n");
-
- memset(q, 0, sizeof(struct ipw2100_bd_queue));
-
- q->entries = entries;
- q->size = entries * sizeof(struct ipw2100_bd);
- q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
- GFP_KERNEL);
- if (!q->drv) {
- IPW_DEBUG_INFO
- ("can't allocate shared memory for buffer descriptors\n");
- return -ENOMEM;
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
-{
- IPW_DEBUG_INFO("enter\n");
-
- if (!q)
- return;
-
- if (q->drv) {
- dma_free_coherent(&priv->pci_dev->dev, q->size, q->drv,
- q->nic);
- q->drv = NULL;
- }
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void bd_queue_initialize(struct ipw2100_priv *priv,
- struct ipw2100_bd_queue *q, u32 base, u32 size,
- u32 r, u32 w)
-{
- IPW_DEBUG_INFO("enter\n");
-
- IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
- (u32) q->nic);
-
- write_register(priv->net_dev, base, q->nic);
- write_register(priv->net_dev, size, q->entries);
- write_register(priv->net_dev, r, q->oldest);
- write_register(priv->net_dev, w, q->next);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void ipw2100_kill_works(struct ipw2100_priv *priv)
-{
- priv->stop_rf_kill = 1;
- priv->stop_hang_check = 1;
- cancel_delayed_work_sync(&priv->reset_work);
- cancel_delayed_work_sync(&priv->security_work);
- cancel_delayed_work_sync(&priv->wx_event_work);
- cancel_delayed_work_sync(&priv->hang_check);
- cancel_delayed_work_sync(&priv->rf_kill);
- cancel_delayed_work_sync(&priv->scan_event);
-}
-
-static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err;
- void *v;
- dma_addr_t p;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
- priv->net_dev->name);
- return err;
- }
-
- priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH,
- sizeof(struct ipw2100_tx_packet),
- GFP_KERNEL);
- if (!priv->tx_buffers) {
- bd_queue_free(priv, &priv->tx_queue);
- return -ENOMEM;
- }
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- v = dma_alloc_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header), &p,
- GFP_KERNEL);
- if (!v) {
- printk(KERN_ERR DRV_NAME
- ": %s: PCI alloc failed for tx " "buffers.\n",
- priv->net_dev->name);
- err = -ENOMEM;
- break;
- }
-
- priv->tx_buffers[i].type = DATA;
- priv->tx_buffers[i].info.d_struct.data =
- (struct ipw2100_data_header *)v;
- priv->tx_buffers[i].info.d_struct.data_phys = p;
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
-
- if (i == TX_PENDED_QUEUE_LENGTH)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[j].info.d_struct.data,
- priv->tx_buffers[j].info.d_struct.data_phys);
- }
-
- kfree(priv->tx_buffers);
- priv->tx_buffers = NULL;
-
- return err;
-}
-
-static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- /*
- * reinitialize packet info lists
- */
- INIT_LIST_HEAD(&priv->fw_pend_list);
- INIT_STAT(&priv->fw_pend_stat);
-
- /*
- * reinitialize lists
- */
- INIT_LIST_HEAD(&priv->tx_pend_list);
- INIT_LIST_HEAD(&priv->tx_free_list);
- INIT_STAT(&priv->tx_pend_stat);
- INIT_STAT(&priv->tx_free_stat);
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- /* We simply drop any SKBs that have been queued for
- * transmit */
- if (priv->tx_buffers[i].info.d_struct.txb) {
- libipw_txb_free(priv->tx_buffers[i].info.d_struct.
- txb);
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
-
- list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
- }
-
- SET_STAT(&priv->tx_free_stat, i);
-
- priv->tx_queue.oldest = 0;
- priv->tx_queue.available = priv->tx_queue.entries;
- priv->tx_queue.next = 0;
- INIT_STAT(&priv->txq_stat);
- SET_STAT(&priv->txq_stat, priv->tx_queue.available);
-
- bd_queue_initialize(priv, &priv->tx_queue,
- IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
- IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
- IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
-
- IPW_DEBUG_INFO("exit\n");
-
-}
-
-static void ipw2100_tx_free(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- bd_queue_free(priv, &priv->tx_queue);
-
- if (!priv->tx_buffers)
- return;
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- if (priv->tx_buffers[i].info.d_struct.txb) {
- libipw_txb_free(priv->tx_buffers[i].info.d_struct.
- txb);
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
- if (priv->tx_buffers[i].info.d_struct.data)
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[i].info.d_struct.data,
- priv->tx_buffers[i].info.d_struct.data_phys);
- }
-
- kfree(priv->tx_buffers);
- priv->tx_buffers = NULL;
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err = -EINVAL;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_INFO("failed bd_queue_allocate\n");
- return err;
- }
-
- err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_INFO("failed status_queue_allocate\n");
- bd_queue_free(priv, &priv->rx_queue);
- return err;
- }
-
- /*
- * allocate packets
- */
- priv->rx_buffers = kmalloc_array(RX_QUEUE_LENGTH,
- sizeof(struct ipw2100_rx_packet),
- GFP_KERNEL);
- if (!priv->rx_buffers) {
- IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
-
- bd_queue_free(priv, &priv->rx_queue);
-
- status_queue_free(priv);
-
- return -ENOMEM;
- }
-
- for (i = 0; i < RX_QUEUE_LENGTH; i++) {
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- err = ipw2100_alloc_skb(priv, packet);
- if (unlikely(err)) {
- err = -ENOMEM;
- break;
- }
-
- /* The BD holds the cache aligned address */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
- priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
- priv->status_queue.drv[i].status_fields = 0;
- }
-
- if (i == RX_QUEUE_LENGTH)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_unmap_single(&priv->pci_dev->dev,
- priv->rx_buffers[j].dma_addr,
- sizeof(struct ipw2100_rx_packet),
- DMA_FROM_DEVICE);
- dev_kfree_skb(priv->rx_buffers[j].skb);
- }
-
- kfree(priv->rx_buffers);
- priv->rx_buffers = NULL;
-
- bd_queue_free(priv, &priv->rx_queue);
-
- status_queue_free(priv);
-
- return err;
-}
-
-static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
-{
- IPW_DEBUG_INFO("enter\n");
-
- priv->rx_queue.oldest = 0;
- priv->rx_queue.available = priv->rx_queue.entries - 1;
- priv->rx_queue.next = priv->rx_queue.entries - 1;
-
- INIT_STAT(&priv->rxq_stat);
- SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
-
- bd_queue_initialize(priv, &priv->rx_queue,
- IPW_MEM_HOST_SHARED_RX_BD_BASE,
- IPW_MEM_HOST_SHARED_RX_BD_SIZE,
- IPW_MEM_HOST_SHARED_RX_READ_INDEX,
- IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
-
- /* set up the status queue */
- write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
- priv->status_queue.nic);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void ipw2100_rx_free(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- bd_queue_free(priv, &priv->rx_queue);
- status_queue_free(priv);
-
- if (!priv->rx_buffers)
- return;
-
- for (i = 0; i < RX_QUEUE_LENGTH; i++) {
- if (priv->rx_buffers[i].rxp) {
- dma_unmap_single(&priv->pci_dev->dev,
- priv->rx_buffers[i].dma_addr,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
- dev_kfree_skb(priv->rx_buffers[i].skb);
- }
- }
-
- kfree(priv->rx_buffers);
- priv->rx_buffers = NULL;
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
-{
- u32 length = ETH_ALEN;
- u8 addr[ETH_ALEN];
-
- int err;
-
- err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
- if (err) {
- IPW_DEBUG_INFO("MAC address read failed\n");
- return -EIO;
- }
-
- eth_hw_addr_set(priv->net_dev, addr);
- IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
-
- return 0;
-}
-
-/********************************************************************
- *
- * Firmware Commands
- *
- ********************************************************************/
-
-static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = ADAPTER_ADDRESS,
- .host_command_sequence = 0,
- .host_command_length = ETH_ALEN
- };
- int err;
-
- IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->config & CFG_CUSTOM_MAC) {
- memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
- eth_hw_addr_set(priv->net_dev, priv->mac_addr);
- } else
- memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
- ETH_ALEN);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- IPW_DEBUG_INFO("exit\n");
- return err;
-}
-
-static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = PORT_TYPE,
- .host_command_sequence = 0,
- .host_command_length = sizeof(u32)
- };
- int err;
-
- switch (port_type) {
- case IW_MODE_INFRA:
- cmd.host_command_parameters[0] = IPW_BSS;
- break;
- case IW_MODE_ADHOC:
- cmd.host_command_parameters[0] = IPW_IBSS;
- break;
- }
-
- IPW_DEBUG_HC("PORT_TYPE: %s\n",
- port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = CHANNEL,
- .host_command_sequence = 0,
- .host_command_length = sizeof(u32)
- };
- int err;
-
- cmd.host_command_parameters[0] = channel;
-
- IPW_DEBUG_HC("CHANNEL: %d\n", channel);
-
- /* If BSS then we don't support channel selection */
- if (priv->ieee->iw_mode == IW_MODE_INFRA)
- return 0;
-
- if ((channel != 0) &&
- ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
- return -EINVAL;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- IPW_DEBUG_INFO("Failed to set channel to %d", channel);
- return err;
- }
-
- if (channel)
- priv->config |= CFG_STATIC_CHANNEL;
- else
- priv->config &= ~CFG_STATIC_CHANNEL;
-
- priv->channel = channel;
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SYSTEM_CONFIG,
- .host_command_sequence = 0,
- .host_command_length = 12,
- };
- u32 ibss_mask, len = sizeof(u32);
- int err;
-
- /* Set system configuration */
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
-
- cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
- IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
-
- if (!(priv->config & CFG_LONG_PREAMBLE))
- cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
-
- err = ipw2100_get_ordinal(priv,
- IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
- &ibss_mask, &len);
- if (err)
- ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
-
- cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
- cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
-
- /* 11b only */
- /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
-/* If IPv6 is configured in the kernel then we don't want to filter out all
- * of the multicast packets as IPv6 needs some. */
-#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
- cmd.host_command = ADD_MULTICAST;
- cmd.host_command_sequence = 0;
- cmd.host_command_length = 0;
-
- ipw2100_hw_send_command(priv, &cmd);
-#endif
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = BASIC_TX_RATES,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- /* Set BASIC TX Rate first */
- ipw2100_hw_send_command(priv, &cmd);
-
- /* Set TX Rate */
- cmd.host_command = TX_RATES;
- ipw2100_hw_send_command(priv, &cmd);
-
- /* Set MSDU TX Rate */
- cmd.host_command = MSDU_TX_RATES;
- ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- priv->tx_rates = rate;
-
- return 0;
-}
-
-static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
-{
- struct host_command cmd = {
- .host_command = POWER_MODE,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = power_level;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- if (power_level == IPW_POWER_MODE_CAM)
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- else
- priv->power_mode = IPW_POWER_ENABLED | power_level;
-
-#ifdef IPW2100_TX_POWER
- if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
- /* Set beacon interval */
- cmd.host_command = TX_POWER_INDEX;
- cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
- }
-#endif
-
- return 0;
-}
-
-static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
-{
- struct host_command cmd = {
- .host_command = RTS_THRESHOLD,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- if (threshold & RTS_DISABLED)
- cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
- else
- cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->rts_threshold = threshold;
-
- return 0;
-}
-
-#if 0
-int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
- u32 threshold, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = FRAG_THRESHOLD,
- .host_command_sequence = 0,
- .host_command_length = 4,
- .host_command_parameters[0] = 0,
- };
- int err;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (threshold == 0)
- threshold = DEFAULT_FRAG_THRESHOLD;
- else {
- threshold = max(threshold, MIN_FRAG_THRESHOLD);
- threshold = min(threshold, MAX_FRAG_THRESHOLD);
- }
-
- cmd.host_command_parameters[0] = threshold;
-
- IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- if (!err)
- priv->frag_threshold = threshold;
-
- return err;
-}
-#endif
-
-static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
-{
- struct host_command cmd = {
- .host_command = SHORT_RETRY_LIMIT,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = retry;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->short_retry_limit = retry;
-
- return 0;
-}
-
-static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
-{
- struct host_command cmd = {
- .host_command = LONG_RETRY_LIMIT,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = retry;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->long_retry_limit = retry;
-
- return 0;
-}
-
-static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = MANDATORY_BSSID,
- .host_command_sequence = 0,
- .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
- };
- int err;
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (bssid != NULL)
- IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
- else
- IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
-#endif
- /* if BSSID is empty then we disable mandatory bssid mode */
- if (bssid != NULL)
- memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = DISASSOCIATION_BSSID,
- .host_command_sequence = 0,
- .host_command_length = ETH_ALEN
- };
- int err;
-
- IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
-
- /* The Firmware currently ignores the BSSID and just disassociates from
- * the currently associated AP -- but in the off chance that a future
- * firmware does use the BSSID provided here, we go ahead and try and
- * set it to the currently associated AP's BSSID */
- memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- return err;
-}
-
-static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
- struct ipw2100_wpa_assoc_frame *, int)
- __attribute__ ((unused));
-
-static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
- struct ipw2100_wpa_assoc_frame *wpa_frame,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SET_WPA_IE,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
- };
- int err;
-
- IPW_DEBUG_HC("SET_WPA_IE\n");
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- memcpy(cmd.host_command_parameters, wpa_frame,
- sizeof(struct ipw2100_wpa_assoc_frame));
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- if (ipw2100_enable_adapter(priv))
- err = -EIO;
- }
-
- return err;
-}
-
-struct security_info_params {
- u32 allowed_ciphers;
- u16 version;
- u8 auth_mode;
- u8 replay_counters_number;
- u8 unicast_using_group;
-} __packed;
-
-static int ipw2100_set_security_information(struct ipw2100_priv *priv,
- int auth_mode,
- int security_level,
- int unicast_using_group,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SET_SECURITY_INFORMATION,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct security_info_params)
- };
- struct security_info_params *security =
- (struct security_info_params *)&cmd.host_command_parameters;
- int err;
- memset(security, 0, sizeof(*security));
-
- /* If shared key AP authentication is turned on, then we need to
- * configure the firmware to try and use it.
- *
- * Actual data encryption/decryption is handled by the host. */
- security->auth_mode = auth_mode;
- security->unicast_using_group = unicast_using_group;
-
- switch (security_level) {
- default:
- case SEC_LEVEL_0:
- security->allowed_ciphers = IPW_NONE_CIPHER;
- break;
- case SEC_LEVEL_1:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER;
- break;
- case SEC_LEVEL_2:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
- break;
- case SEC_LEVEL_2_CKIP:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
- break;
- case SEC_LEVEL_3:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
- break;
- }
-
- IPW_DEBUG_HC
- ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
- security->auth_mode, security->allowed_ciphers, security_level);
-
- security->replay_counters_number = 0;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
-{
- struct host_command cmd = {
- .host_command = TX_POWER_INDEX,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err = 0;
- u32 tmp = tx_power;
-
- if (tx_power != IPW_TX_POWER_DEFAULT)
- tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
- (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
-
- cmd.host_command_parameters[0] = tmp;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- err = ipw2100_hw_send_command(priv, &cmd);
- if (!err)
- priv->tx_power = tx_power;
-
- return 0;
-}
-
-static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
- u32 interval, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = BEACON_INTERVAL,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = interval;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
-{
- ipw2100_tx_initialize(priv);
- ipw2100_rx_initialize(priv);
- ipw2100_msg_initialize(priv);
-}
-
-static void ipw2100_queues_free(struct ipw2100_priv *priv)
-{
- ipw2100_tx_free(priv);
- ipw2100_rx_free(priv);
- ipw2100_msg_free(priv);
-}
-
-static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
-{
- if (ipw2100_tx_allocate(priv) ||
- ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
- goto fail;
-
- return 0;
-
- fail:
- ipw2100_tx_free(priv);
- ipw2100_rx_free(priv);
- ipw2100_msg_free(priv);
- return -ENOMEM;
-}
-
-#define IPW_PRIVACY_CAPABLE 0x0008
-
-static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = WEP_FLAGS,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = flags;
-
- IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-struct ipw2100_wep_key {
- u8 idx;
- u8 len;
- u8 key[13];
-};
-
-/* Macros to ease up priting WEP keys */
-#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
-#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
-#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
-#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
-
-/**
- * ipw2100_set_key() - Set a the wep key
- *
- * @priv: struct to work on
- * @idx: index of the key we want to set
- * @key: ptr to the key data to set
- * @len: length of the buffer at @key
- * @batch_mode: FIXME perform the operation in batch mode, not
- * disabling the device.
- *
- * @returns 0 if OK, < 0 errno code on error.
- *
- * Fill out a command structure with the new wep key, length an
- * index and send it down the wire.
- */
-static int ipw2100_set_key(struct ipw2100_priv *priv,
- int idx, char *key, int len, int batch_mode)
-{
- int keylen = len ? (len <= 5 ? 5 : 13) : 0;
- struct host_command cmd = {
- .host_command = WEP_KEY_INFO,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct ipw2100_wep_key),
- };
- struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
- int err;
-
- IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
- idx, keylen, len);
-
- /* NOTE: We don't check cached values in case the firmware was reset
- * or some other problem is occurring. If the user is setting the key,
- * then we push the change */
-
- wep_key->idx = idx;
- wep_key->len = keylen;
-
- if (keylen) {
- memcpy(wep_key->key, key, len);
- memset(wep_key->key + len, 0, keylen - len);
- }
-
- /* Will be optimized out on debug not being configured in */
- if (keylen == 0)
- IPW_DEBUG_WEP("%s: Clearing key %d\n",
- priv->net_dev->name, wep_key->idx);
- else if (keylen == 5)
- IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_64(wep_key->key));
- else
- IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
- "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_128(wep_key->key));
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- int err2 = ipw2100_enable_adapter(priv);
- if (err == 0)
- err = err2;
- }
- return err;
-}
-
-static int ipw2100_set_key_index(struct ipw2100_priv *priv,
- int idx, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = WEP_KEY_INDEX,
- .host_command_sequence = 0,
- .host_command_length = 4,
- .host_command_parameters = {idx},
- };
- int err;
-
- IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
-
- if (idx < 0 || idx > 3)
- return -EINVAL;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
-{
- int i, err, auth_mode, sec_level, use_group;
-
- if (!(priv->status & STATUS_RUNNING))
- return 0;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (!priv->ieee->sec.enabled) {
- err =
- ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
- SEC_LEVEL_0, 0, 1);
- } else {
- auth_mode = IPW_AUTH_OPEN;
- if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
- if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
- auth_mode = IPW_AUTH_SHARED;
- else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
- auth_mode = IPW_AUTH_LEAP_CISCO_ID;
- }
-
- sec_level = SEC_LEVEL_0;
- if (priv->ieee->sec.flags & SEC_LEVEL)
- sec_level = priv->ieee->sec.level;
-
- use_group = 0;
- if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
- use_group = priv->ieee->sec.unicast_uses_group;
-
- err =
- ipw2100_set_security_information(priv, auth_mode, sec_level,
- use_group, 1);
- }
-
- if (err)
- goto exit;
-
- if (priv->ieee->sec.enabled) {
- for (i = 0; i < 4; i++) {
- if (!(priv->ieee->sec.flags & (1 << i))) {
- memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
- priv->ieee->sec.key_sizes[i] = 0;
- } else {
- err = ipw2100_set_key(priv, i,
- priv->ieee->sec.keys[i],
- priv->ieee->sec.
- key_sizes[i], 1);
- if (err)
- goto exit;
- }
- }
-
- ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
- }
-
- /* Always enable privacy so the Host can filter WEP packets if
- * encrypted data is sent up */
- err =
- ipw2100_set_wep_flags(priv,
- priv->ieee->sec.
- enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
- if (err)
- goto exit;
-
- priv->status &= ~STATUS_SECURITY_UPDATED;
-
- exit:
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static void ipw2100_security_work(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, security_work.work);
-
- /* If we happen to have reconnected before we get a chance to
- * process this, then update the security settings--which causes
- * a disassociation to occur */
- if (!(priv->status & STATUS_ASSOCIATED) &&
- priv->status & STATUS_SECURITY_UPDATED)
- ipw2100_configure_security(priv, 0);
-}
-
-static void shim__set_security(struct net_device *dev,
- struct libipw_security *sec)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int i;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED))
- goto done;
-
- for (i = 0; i < 4; i++) {
- if (sec->flags & (1 << i)) {
- priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
- if (sec->key_sizes[i] == 0)
- priv->ieee->sec.flags &= ~(1 << i);
- else
- memcpy(priv->ieee->sec.keys[i], sec->keys[i],
- sec->key_sizes[i]);
- if (sec->level == SEC_LEVEL_1) {
- priv->ieee->sec.flags |= (1 << i);
- priv->status |= STATUS_SECURITY_UPDATED;
- } else
- priv->ieee->sec.flags &= ~(1 << i);
- }
- }
-
- if ((sec->flags & SEC_ACTIVE_KEY) &&
- priv->ieee->sec.active_key != sec->active_key) {
- priv->ieee->sec.active_key = sec->active_key;
- priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->ieee->sec.auth_mode != sec->auth_mode)) {
- priv->ieee->sec.auth_mode = sec->auth_mode;
- priv->ieee->sec.flags |= SEC_AUTH_MODE;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
- priv->ieee->sec.flags |= SEC_ENABLED;
- priv->ieee->sec.enabled = sec->enabled;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENCRYPT)
- priv->ieee->sec.encrypt = sec->encrypt;
-
- if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
- priv->ieee->sec.level = sec->level;
- priv->ieee->sec.flags |= SEC_LEVEL;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
- priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
-
-/* As a temporary work around to enable WPA until we figure out why
- * wpa_supplicant toggles the security capability of the driver, which
- * forces a disassociation with force_update...
- *
- * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
- ipw2100_configure_security(priv, 0);
- done:
- mutex_unlock(&priv->action_mutex);
-}
-
-static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
-{
- int err;
- int batch_mode = 1;
- u8 *bssid;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- err = ipw2100_set_channel(priv, priv->channel, batch_mode);
- if (err)
- return err;
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
- }
-#endif /* CONFIG_IPW2100_MONITOR */
-
- err = ipw2100_read_mac_address(priv);
- if (err)
- return -EIO;
-
- err = ipw2100_set_mac_address(priv, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
- if (err)
- return err;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- err = ipw2100_set_channel(priv, priv->channel, batch_mode);
- if (err)
- return err;
- }
-
- err = ipw2100_system_config(priv, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
- if (err)
- return err;
-
- /* Default to power mode OFF */
- err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
- if (err)
- return err;
-
- err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
- if (err)
- return err;
-
- if (priv->config & CFG_STATIC_BSSID)
- bssid = priv->bssid;
- else
- bssid = NULL;
- err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
- if (err)
- return err;
-
- if (priv->config & CFG_STATIC_ESSID)
- err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
- batch_mode);
- else
- err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_configure_security(priv, batch_mode);
- if (err)
- return err;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- err =
- ipw2100_set_ibss_beacon_interval(priv,
- priv->beacon_interval,
- batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_tx_power(priv, priv->tx_power);
- if (err)
- return err;
- }
-
- /*
- err = ipw2100_set_fragmentation_threshold(
- priv, priv->frag_threshold, batch_mode);
- if (err)
- return err;
- */
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-/*************************************************************************
- *
- * EXTERNALLY CALLED METHODS
- *
- *************************************************************************/
-
-/* This method is called by the network layer -- not to be confused with
- * ipw2100_set_mac_address() declared above called by this driver (and this
- * method as well) to talk to the firmware */
-static int ipw2100_set_address(struct net_device *dev, void *p)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct sockaddr *addr = p;
- int err = 0;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
-
- mutex_lock(&priv->action_mutex);
-
- priv->config |= CFG_CUSTOM_MAC;
- memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
-
- err = ipw2100_set_mac_address(priv, 0);
- if (err)
- goto done;
-
- priv->reset_backoff = 0;
- mutex_unlock(&priv->action_mutex);
- ipw2100_reset_adapter(&priv->reset_work.work);
- return 0;
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_open(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- unsigned long flags;
- IPW_DEBUG_INFO("dev->open\n");
-
- spin_lock_irqsave(&priv->low_lock, flags);
- if (priv->status & STATUS_ASSOCIATED) {
- netif_carrier_on(dev);
- netif_start_queue(dev);
- }
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- return 0;
-}
-
-static int ipw2100_close(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- unsigned long flags;
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
-
- IPW_DEBUG_INFO("enter\n");
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->status & STATUS_ASSOCIATED)
- netif_carrier_off(dev);
- netif_stop_queue(dev);
-
- /* Flush the TX queue ... */
- while (!list_empty(&priv->tx_pend_list)) {
- element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- list_del(element);
- DEC_STAT(&priv->tx_pend_stat);
-
- libipw_txb_free(packet->info.d_struct.txb);
- packet->info.d_struct.txb = NULL;
-
- list_add_tail(element, &priv->tx_free_list);
- INC_STAT(&priv->tx_free_stat);
- }
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-/*
- * TODO: Fix this function... its just wrong
- */
-static void ipw2100_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- dev->stats.tx_errors++;
-
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- return;
-#endif
-
- IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
- dev->name);
- schedule_reset(priv);
-}
-
-static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
-{
- /* This is called when wpa_supplicant loads and closes the driver
- * interface. */
- priv->ieee->wpa_enabled = value;
- return 0;
-}
-
-static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
-{
-
- struct libipw_device *ieee = priv->ieee;
- struct libipw_security sec = {
- .flags = SEC_AUTH_MODE,
- };
- int ret = 0;
-
- if (value & IW_AUTH_ALG_SHARED_KEY) {
- sec.auth_mode = WLAN_AUTH_SHARED_KEY;
- ieee->open_wep = 0;
- } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
- sec.auth_mode = WLAN_AUTH_OPEN;
- ieee->open_wep = 1;
- } else if (value & IW_AUTH_ALG_LEAP) {
- sec.auth_mode = WLAN_AUTH_LEAP;
- ieee->open_wep = 1;
- } else
- return -EINVAL;
-
- if (ieee->set_security)
- ieee->set_security(ieee->dev, &sec);
- else
- ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
- char *wpa_ie, int wpa_ie_len)
-{
-
- struct ipw2100_wpa_assoc_frame frame;
-
- frame.fixed_ie_mask = 0;
-
- /* copy WPA IE */
- memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
- frame.var_ie_len = wpa_ie_len;
-
- /* make sure WPA is enabled */
- ipw2100_wpa_enable(priv, 1);
- ipw2100_set_wpa_ie(priv, &frame, 0);
-}
-
-static void ipw_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- char fw_ver[64], ucode_ver[64];
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
-
- ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
- ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
-
- snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
- fw_ver, priv->eeprom_version, ucode_ver);
-
- strscpy(info->bus_info, pci_name(priv->pci_dev),
- sizeof(info->bus_info));
-}
-
-static u32 ipw2100_ethtool_get_link(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
-}
-
-static const struct ethtool_ops ipw2100_ethtool_ops = {
- .get_link = ipw2100_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
-};
-
-static void ipw2100_hang_check(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, hang_check.work);
- unsigned long flags;
- u32 rtc = 0xa5a5a5a5;
- u32 len = sizeof(rtc);
- int restart = 0;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->fatal_error != 0) {
- /* If fatal_error is set then we need to restart */
- IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
- priv->net_dev->name);
-
- restart = 1;
- } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
- (rtc == priv->last_rtc)) {
- /* Check if firmware is hung */
- IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
- priv->net_dev->name);
-
- restart = 1;
- }
-
- if (restart) {
- /* Kill timer */
- priv->stop_hang_check = 1;
- priv->hangs++;
-
- /* Restart the NIC */
- schedule_reset(priv);
- }
-
- priv->last_rtc = rtc;
-
- if (!priv->stop_hang_check)
- schedule_delayed_work(&priv->hang_check, HZ / 2);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-}
-
-static void ipw2100_rf_kill(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, rf_kill.work);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
- if (!priv->stop_rf_kill)
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(HZ));
- goto exit_unlock;
- }
-
- /* RF Kill is now disabled, so bring the device back up */
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
- "device\n");
- schedule_reset(priv);
- } else
- IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
- "enabled\n");
-
- exit_unlock:
- spin_unlock_irqrestore(&priv->low_lock, flags);
-}
-
-static void ipw2100_irq_tasklet(struct tasklet_struct *t);
-
-static const struct net_device_ops ipw2100_netdev_ops = {
- .ndo_open = ipw2100_open,
- .ndo_stop = ipw2100_close,
- .ndo_start_xmit = libipw_xmit,
- .ndo_tx_timeout = ipw2100_tx_timeout,
- .ndo_set_mac_address = ipw2100_set_address,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* Look into using netdev destructor to shutdown libipw? */
-
-static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
- void __iomem * ioaddr)
-{
- struct ipw2100_priv *priv;
- struct net_device *dev;
-
- dev = alloc_libipw(sizeof(struct ipw2100_priv), 0);
- if (!dev)
- return NULL;
- priv = libipw_priv(dev);
- priv->ieee = netdev_priv(dev);
- priv->pci_dev = pci_dev;
- priv->net_dev = dev;
- priv->ioaddr = ioaddr;
-
- priv->ieee->hard_start_xmit = ipw2100_tx;
- priv->ieee->set_security = shim__set_security;
-
- priv->ieee->perfect_rssi = -20;
- priv->ieee->worst_rssi = -85;
-
- dev->netdev_ops = &ipw2100_netdev_ops;
- dev->ethtool_ops = &ipw2100_ethtool_ops;
- dev->wireless_handlers = &ipw2100_wx_handler_def;
- priv->wireless_data.libipw = priv->ieee;
- dev->wireless_data = &priv->wireless_data;
- dev->watchdog_timeo = 3 * HZ;
- dev->irq = 0;
- dev->min_mtu = 68;
- dev->max_mtu = LIBIPW_DATA_LEN;
-
- /* NOTE: We don't use the wireless_handlers hook
- * in dev as the system will start throwing WX requests
- * to us before we're actually initialized and it just
- * ends up causing problems. So, we just handle
- * the WX extensions through the ipw2100_ioctl interface */
-
- /* memset() puts everything to 0, so we only have explicitly set
- * those values that need to be something else */
-
- /* If power management is turned on, default to AUTO mode */
- priv->power_mode = IPW_POWER_AUTO;
-
-#ifdef CONFIG_IPW2100_MONITOR
- priv->config |= CFG_CRC_CHECK;
-#endif
- priv->ieee->wpa_enabled = 0;
- priv->ieee->drop_unencrypted = 0;
- priv->ieee->privacy_invoked = 0;
- priv->ieee->ieee802_1x = 1;
-
- /* Set module parameters */
- switch (network_mode) {
- case 1:
- priv->ieee->iw_mode = IW_MODE_ADHOC;
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case 2:
- priv->ieee->iw_mode = IW_MODE_MONITOR;
- break;
-#endif
- default:
- case 0:
- priv->ieee->iw_mode = IW_MODE_INFRA;
- break;
- }
-
- if (disable == 1)
- priv->status |= STATUS_RF_KILL_SW;
-
- if (channel != 0 &&
- ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
- priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = channel;
- }
-
- if (associate)
- priv->config |= CFG_ASSOCIATE;
-
- priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
- priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
- priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
- priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
- priv->tx_power = IPW_TX_POWER_DEFAULT;
- priv->tx_rates = DEFAULT_TX_RATES;
-
- strcpy(priv->nick, "ipw2100");
-
- spin_lock_init(&priv->low_lock);
- mutex_init(&priv->action_mutex);
- mutex_init(&priv->adapter_mutex);
-
- init_waitqueue_head(&priv->wait_command_queue);
-
- netif_carrier_off(dev);
-
- INIT_LIST_HEAD(&priv->msg_free_list);
- INIT_LIST_HEAD(&priv->msg_pend_list);
- INIT_STAT(&priv->msg_free_stat);
- INIT_STAT(&priv->msg_pend_stat);
-
- INIT_LIST_HEAD(&priv->tx_free_list);
- INIT_LIST_HEAD(&priv->tx_pend_list);
- INIT_STAT(&priv->tx_free_stat);
- INIT_STAT(&priv->tx_pend_stat);
-
- INIT_LIST_HEAD(&priv->fw_pend_list);
- INIT_STAT(&priv->fw_pend_stat);
-
- INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
- INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
- INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
- INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
- INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
- INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event);
-
- tasklet_setup(&priv->irq_tasklet, ipw2100_irq_tasklet);
-
- /* NOTE: We do not start the deferred work for status checks yet */
- priv->stop_rf_kill = 1;
- priv->stop_hang_check = 1;
-
- return dev;
-}
-
-static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
- const struct pci_device_id *ent)
-{
- void __iomem *ioaddr;
- struct net_device *dev = NULL;
- struct ipw2100_priv *priv = NULL;
- int err = 0;
- int registered = 0;
- u32 val;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (!(pci_resource_flags(pci_dev, 0) & IORESOURCE_MEM)) {
- IPW_DEBUG_INFO("weird - resource type is not memory\n");
- err = -ENODEV;
- goto out;
- }
-
- ioaddr = pci_iomap(pci_dev, 0, 0);
- if (!ioaddr) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ioremap.\n");
- err = -EIO;
- goto fail;
- }
-
- /* allocate and initialize our net_device */
- dev = ipw2100_alloc_device(pci_dev, ioaddr);
- if (!dev) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ipw2100_alloc_device.\n");
- err = -ENOMEM;
- goto fail;
- }
-
- /* set up PCI mappings for device */
- err = pci_enable_device(pci_dev);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_enable_device.\n");
- return err;
- }
-
- priv = libipw_priv(dev);
-
- pci_set_master(pci_dev);
- pci_set_drvdata(pci_dev, priv);
-
- err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_set_dma_mask.\n");
- pci_disable_device(pci_dev);
- return err;
- }
-
- err = pci_request_regions(pci_dev, DRV_NAME);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_request_regions.\n");
- pci_disable_device(pci_dev);
- return err;
- }
-
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_read_config_dword(pci_dev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
-
- if (!ipw2100_hw_is_adapter_in_system(dev)) {
- printk(KERN_WARNING DRV_NAME
- "Device not found via register read.\n");
- err = -ENODEV;
- goto fail;
- }
-
- SET_NETDEV_DEV(dev, &pci_dev->dev);
-
- /* Force interrupts to be shut off on the device */
- priv->status |= STATUS_INT_ENABLED;
- ipw2100_disable_interrupts(priv);
-
- /* Allocate and initialize the Tx/Rx queues and lists */
- if (ipw2100_queues_allocate(priv)) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ipw2100_queues_allocate.\n");
- err = -ENOMEM;
- goto fail;
- }
- ipw2100_queues_initialize(priv);
-
- err = request_irq(pci_dev->irq,
- ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling request_irq: %d.\n", pci_dev->irq);
- goto fail;
- }
- dev->irq = pci_dev->irq;
-
- IPW_DEBUG_INFO("Attempting to register device...\n");
-
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2100 Network Connection\n");
-
- err = ipw2100_up(priv, 1);
- if (err)
- goto fail;
-
- err = ipw2100_wdev_init(dev);
- if (err)
- goto fail;
- registered = 1;
-
- /* Bring up the interface. Pre 0.46, after we registered the
- * network device we would call ipw2100_up. This introduced a race
- * condition with newer hotplug configurations (network was coming
- * up and making calls before the device was initialized).
- */
- err = register_netdev(dev);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling register_netdev.\n");
- goto fail;
- }
- registered = 2;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
-
- /* perform this after register_netdev so that dev->name is set */
- err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
- if (err)
- goto fail_unlock;
-
- /* If the RF Kill switch is disabled, go ahead and complete the
- * startup sequence */
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- /* Enable the adapter - sends HOST_COMPLETE */
- if (ipw2100_enable_adapter(priv)) {
- printk(KERN_WARNING DRV_NAME
- ": %s: failed in call to enable adapter.\n",
- priv->net_dev->name);
- ipw2100_hw_stop_adapter(priv);
- err = -EIO;
- goto fail_unlock;
- }
-
- /* Start a scan . . . */
- ipw2100_set_scan_options(priv);
- ipw2100_start_scan(priv);
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- priv->status |= STATUS_INITIALIZED;
-
- mutex_unlock(&priv->action_mutex);
-out:
- return err;
-
- fail_unlock:
- mutex_unlock(&priv->action_mutex);
- fail:
- if (dev) {
- if (registered >= 2)
- unregister_netdev(dev);
-
- if (registered) {
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->bg_band.channels);
- }
-
- ipw2100_hw_stop_adapter(priv);
-
- ipw2100_disable_interrupts(priv);
-
- if (dev->irq)
- free_irq(dev->irq, priv);
-
- ipw2100_kill_works(priv);
-
- /* These are safe to call even if they weren't allocated */
- ipw2100_queues_free(priv);
- sysfs_remove_group(&pci_dev->dev.kobj,
- &ipw2100_attribute_group);
-
- free_libipw(dev, 0);
- }
-
- pci_iounmap(pci_dev, ioaddr);
-
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
- goto out;
-}
-
-static void ipw2100_pci_remove_one(struct pci_dev *pci_dev)
-{
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
- struct net_device *dev = priv->net_dev;
-
- mutex_lock(&priv->action_mutex);
-
- priv->status &= ~STATUS_INITIALIZED;
-
- sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
-
-#ifdef CONFIG_PM
- if (ipw2100_firmware.version)
- ipw2100_release_firmware(priv, &ipw2100_firmware);
-#endif
- /* Take down the hardware */
- ipw2100_down(priv);
-
- /* Release the mutex so that the network subsystem can
- * complete any needed calls into the driver... */
- mutex_unlock(&priv->action_mutex);
-
- /* Unregister the device first - this results in close()
- * being called if the device is open. If we free storage
- * first, then close() will crash.
- * FIXME: remove the comment above. */
- unregister_netdev(dev);
-
- ipw2100_kill_works(priv);
-
- ipw2100_queues_free(priv);
-
- /* Free potential debugging firmware snapshot */
- ipw2100_snapshot_free(priv);
-
- free_irq(dev->irq, priv);
-
- pci_iounmap(pci_dev, priv->ioaddr);
-
- /* wiphy_unregister needs to be here, before free_libipw */
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->bg_band.channels);
- free_libipw(dev, 0);
-
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int __maybe_unused ipw2100_suspend(struct device *dev_d)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(dev_d);
- struct net_device *dev = priv->net_dev;
-
- IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
-
- mutex_lock(&priv->action_mutex);
- if (priv->status & STATUS_INITIALIZED) {
- /* Take down the device; powers it off, etc. */
- ipw2100_down(priv);
- }
-
- /* Remove the PRESENT state of the device */
- netif_device_detach(dev);
-
- priv->suspend_at = ktime_get_boottime_seconds();
-
- mutex_unlock(&priv->action_mutex);
-
- return 0;
-}
-
-static int __maybe_unused ipw2100_resume(struct device *dev_d)
-{
- struct pci_dev *pci_dev = to_pci_dev(dev_d);
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
- struct net_device *dev = priv->net_dev;
- u32 val;
-
- if (IPW2100_PM_DISABLED)
- return 0;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
-
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
- * from interfering with C3 CPU state. pci_restore_state won't help
- * here since it only restores the first 64 bytes pci config header.
- */
- pci_read_config_dword(pci_dev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
-
- /* Set the device back into the PRESENT state; this will also wake
- * the queue of needed */
- netif_device_attach(dev);
-
- priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at;
-
- /* Bring the device back up */
- if (!(priv->status & STATUS_RF_KILL_SW))
- ipw2100_up(priv, 0);
-
- mutex_unlock(&priv->action_mutex);
-
- return 0;
-}
-
-static void ipw2100_shutdown(struct pci_dev *pci_dev)
-{
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
-
- /* Take down the device; powers it off, etc. */
- ipw2100_down(priv);
-
- pci_disable_device(pci_dev);
-}
-
-#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
-
-static const struct pci_device_id ipw2100_pci_id_table[] = {
- IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
- IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
-
-static SIMPLE_DEV_PM_OPS(ipw2100_pm_ops, ipw2100_suspend, ipw2100_resume);
-
-static struct pci_driver ipw2100_pci_driver = {
- .name = DRV_NAME,
- .id_table = ipw2100_pci_id_table,
- .probe = ipw2100_pci_init_one,
- .remove = ipw2100_pci_remove_one,
- .driver.pm = &ipw2100_pm_ops,
- .shutdown = ipw2100_shutdown,
-};
-
-/*
- * Initialize the ipw2100 driver/module
- *
- * @returns 0 if ok, < 0 errno node con error.
- *
- * Note: we cannot init the /proc stuff until the PCI driver is there,
- * or we risk an unlikely race condition on someone accessing
- * uninitialized data in the PCI dev struct through /proc.
- */
-static int __init ipw2100_init(void)
-{
- int ret;
-
- printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
- printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
-
- cpu_latency_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
-
- ret = pci_register_driver(&ipw2100_pci_driver);
- if (ret)
- goto out;
-
-#ifdef CONFIG_IPW2100_DEBUG
- ipw2100_debug_level = debug;
- ret = driver_create_file(&ipw2100_pci_driver.driver,
- &driver_attr_debug_level);
-#endif
-
-out:
- return ret;
-}
-
-/*
- * Cleanup ipw2100 driver registration
- */
-static void __exit ipw2100_exit(void)
-{
- /* FIXME: IPG: check that we have no instances of the devices open */
-#ifdef CONFIG_IPW2100_DEBUG
- driver_remove_file(&ipw2100_pci_driver.driver,
- &driver_attr_debug_level);
-#endif
- pci_unregister_driver(&ipw2100_pci_driver);
- cpu_latency_qos_remove_request(&ipw2100_pm_qos_req);
-}
-
-module_init(ipw2100_init);
-module_exit(ipw2100_exit);
-
-static int ipw2100_wx_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- if (!(priv->status & STATUS_ASSOCIATED))
- strcpy(wrqu->name, "unassociated");
- else
- snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
-
- IPW_DEBUG_WX("Name: %s\n", wrqu->name);
- return 0;
-}
-
-static int ipw2100_wx_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_freq *fwrq = &wrqu->freq;
- int err = 0;
-
- if (priv->ieee->iw_mode == IW_MODE_INFRA)
- return -EOPNOTSUPP;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- /* if setting by freq convert to channel */
- if (fwrq->e == 1) {
- if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
- int f = fwrq->m / 100000;
- int c = 0;
-
- while ((c < REG_MAX_CHANNEL) &&
- (f != ipw2100_frequencies[c]))
- c++;
-
- /* hack to fall through */
- fwrq->e = 0;
- fwrq->m = c + 1;
- }
- }
-
- if (fwrq->e > 0 || fwrq->m > 1000) {
- err = -EOPNOTSUPP;
- goto done;
- } else { /* Set the channel */
- IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
- err = ipw2100_set_channel(priv, fwrq->m, 0);
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->freq.e = 0;
-
- /* If we are associated, trying to associate, or have a statically
- * configured CHANNEL then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_CHANNEL ||
- priv->status & STATUS_ASSOCIATED)
- wrqu->freq.m = priv->channel;
- else
- wrqu->freq.m = 0;
-
- IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
- return 0;
-
-}
-
-static int ipw2100_wx_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
-
- if (wrqu->mode == priv->ieee->iw_mode)
- return 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- switch (wrqu->mode) {
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
- break;
-#endif /* CONFIG_IPW2100_MONITOR */
- case IW_MODE_ADHOC:
- err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
- break;
- case IW_MODE_INFRA:
- case IW_MODE_AUTO:
- default:
- err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
- break;
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->mode = priv->ieee->iw_mode;
- IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
-
- return 0;
-}
-
-#define POWER_MODES 5
-
-/* Values are in microsecond */
-static const s32 timeout_duration[POWER_MODES] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-
-static const s32 period_duration[POWER_MODES] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
-static int ipw2100_wx_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_range *range = (struct iw_range *)extra;
- u16 val;
- int i, level;
-
- wrqu->data.length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- /* Let's try to keep this struct in the same order as in
- * linux/include/wireless.h
- */
-
- /* TODO: See what values we can set, and remove the ones we can't
- * set, or fill them with some default data.
- */
-
- /* ~5 Mb/s real (802.11b) */
- range->throughput = 5 * 1000 * 1000;
-
-// range->sensitivity; /* signal level threshold range */
-
- range->max_qual.qual = 100;
- /* TODO: Find real max RSSI and stick here */
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
-
- range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
- range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
-
- range->num_bitrates = RATE_COUNT;
-
- for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
- range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
- }
-
- range->min_rts = MIN_RTS_THRESHOLD;
- range->max_rts = MAX_RTS_THRESHOLD;
- range->min_frag = MIN_FRAG_THRESHOLD;
- range->max_frag = MAX_FRAG_THRESHOLD;
-
- range->min_pmp = period_duration[0]; /* Minimal PM period */
- range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
- range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
- range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
-
- /* How to decode max/min PM period */
- range->pmp_flags = IW_POWER_PERIOD;
- /* How to decode max/min PM period */
- range->pmt_flags = IW_POWER_TIMEOUT;
- /* What PM options are supported */
- range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13; /* Different token sizes */
- range->num_encoding_sizes = 2; /* Number of entry in the list */
- range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
-// range->encoding_login_index; /* token index for login token */
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- range->txpower_capa = IW_TXPOW_DBM;
- range->num_txpower = IW_MAX_TXPOWER;
- for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
- i < IW_MAX_TXPOWER;
- i++, level -=
- ((IPW_TX_POWER_MAX_DBM -
- IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
- range->txpower[i] = level / 16;
- } else {
- range->txpower_capa = 0;
- range->num_txpower = 0;
- }
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
-// range->retry_capa; /* What retry options are supported */
-// range->retry_flags; /* How to decode max/min retry limit */
-// range->r_time_flags; /* How to decode max/min retry life */
-// range->min_retry; /* Minimal number of retries */
-// range->max_retry; /* Maximal number of retries */
-// range->min_r_time; /* Minimal retry lifetime */
-// range->max_r_time; /* Maximal retry lifetime */
-
- range->num_channels = FREQ_COUNT;
-
- val = 0;
- for (i = 0; i < FREQ_COUNT; i++) {
- // TODO: Include only legal frequencies for some countries
-// if (local->channel_mask & (1 << i)) {
- range->freq[val].i = i + 1;
- range->freq[val].m = ipw2100_frequencies[i] * 100000;
- range->freq[val].e = 1;
- val++;
-// }
- if (val == IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = val;
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWAP));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- IPW_DEBUG_WX("GET Range\n");
-
- return 0;
-}
-
-static int ipw2100_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- // sanity checks
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- return -EINVAL;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
- is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
- /* we disable mandatory BSSID association */
- IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
- priv->config &= ~CFG_STATIC_BSSID;
- err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
- goto done;
- }
-
- priv->config |= CFG_STATIC_BSSID;
- memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
-
- err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
-
- IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured BSSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
- } else
- eth_zero_addr(wrqu->ap_addr.sa_data);
-
- IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
- return 0;
-}
-
-static int ipw2100_wx_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- char *essid = ""; /* ANY */
- int length = 0;
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->essid.flags && wrqu->essid.length) {
- length = wrqu->essid.length;
- essid = extra;
- }
-
- if (length == 0) {
- IPW_DEBUG_WX("Setting ESSID to ANY\n");
- priv->config &= ~CFG_STATIC_ESSID;
- err = ipw2100_set_essid(priv, NULL, 0, 0);
- goto done;
- }
-
- length = min(length, IW_ESSID_MAX_SIZE);
-
- priv->config |= CFG_STATIC_ESSID;
-
- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
- IPW_DEBUG_WX("ESSID set to current ESSID.\n");
- err = 0;
- goto done;
- }
-
- IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, essid, length);
-
- priv->essid_len = length;
- memcpy(priv->essid, essid, priv->essid_len);
-
- err = ipw2100_set_essid(priv, essid, length, 0);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured ESSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
- IPW_DEBUG_WX("Getting essid: '%*pE'\n",
- priv->essid_len, priv->essid);
- memcpy(extra, priv->essid, priv->essid_len);
- wrqu->essid.length = priv->essid_len;
- wrqu->essid.flags = 1; /* active */
- } else {
- IPW_DEBUG_WX("Getting essid: ANY\n");
- wrqu->essid.length = 0;
- wrqu->essid.flags = 0; /* active */
- }
-
- return 0;
-}
-
-static int ipw2100_wx_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (wrqu->data.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
-
- IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
-
- return 0;
-}
-
-static int ipw2100_wx_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->data.length = strlen(priv->nick);
- memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
-
- IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
-
- return 0;
-}
-
-static int ipw2100_wx_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- u32 target_rate = wrqu->bitrate.value;
- u32 rate;
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- rate = 0;
-
- if (target_rate == 1000000 ||
- (!wrqu->bitrate.fixed && target_rate > 1000000))
- rate |= TX_RATE_1_MBIT;
- if (target_rate == 2000000 ||
- (!wrqu->bitrate.fixed && target_rate > 2000000))
- rate |= TX_RATE_2_MBIT;
- if (target_rate == 5500000 ||
- (!wrqu->bitrate.fixed && target_rate > 5500000))
- rate |= TX_RATE_5_5_MBIT;
- if (target_rate == 11000000 ||
- (!wrqu->bitrate.fixed && target_rate > 11000000))
- rate |= TX_RATE_11_MBIT;
- if (rate == 0)
- rate = DEFAULT_TX_RATES;
-
- err = ipw2100_set_tx_rates(priv, rate, 0);
-
- IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int val;
- unsigned int len = sizeof(val);
- int err = 0;
-
- if (!(priv->status & STATUS_ENABLED) ||
- priv->status & STATUS_RF_KILL_MASK ||
- !(priv->status & STATUS_ASSOCIATED)) {
- wrqu->bitrate.value = 0;
- return 0;
- }
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
- if (err) {
- IPW_DEBUG_WX("failed querying ordinals.\n");
- goto done;
- }
-
- switch (val & TX_RATE_MASK) {
- case TX_RATE_1_MBIT:
- wrqu->bitrate.value = 1000000;
- break;
- case TX_RATE_2_MBIT:
- wrqu->bitrate.value = 2000000;
- break;
- case TX_RATE_5_5_MBIT:
- wrqu->bitrate.value = 5500000;
- break;
- case TX_RATE_11_MBIT:
- wrqu->bitrate.value = 11000000;
- break;
- default:
- wrqu->bitrate.value = 0;
- }
-
- IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int value, err;
-
- /* Auto RTS not yet supported */
- if (wrqu->rts.fixed == 0)
- return -EINVAL;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->rts.disabled)
- value = priv->rts_threshold | RTS_DISABLED;
- else {
- if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
- err = -EINVAL;
- goto done;
- }
- value = wrqu->rts.value;
- }
-
- err = ipw2100_set_rts_threshold(priv, value);
-
- IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
- wrqu->rts.fixed = 1; /* no auto select */
-
- /* If RTS is set to the default value, then it is disabled */
- wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
-
- IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0, value;
-
- if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
- return -EINPROGRESS;
-
- if (priv->ieee->iw_mode != IW_MODE_ADHOC)
- return 0;
-
- if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
- return -EINVAL;
-
- if (wrqu->txpower.fixed == 0)
- value = IPW_TX_POWER_DEFAULT;
- else {
- if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
- wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
- return -EINVAL;
-
- value = wrqu->txpower.value;
- }
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- err = ipw2100_set_tx_power(priv, value);
-
- IPW_DEBUG_WX("SET TX Power -> %d\n", value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
-
- if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
- wrqu->txpower.fixed = 0;
- wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
- } else {
- wrqu->txpower.fixed = 1;
- wrqu->txpower.value = priv->tx_power;
- }
-
- wrqu->txpower.flags = IW_TXPOW_DBM;
-
- IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (!wrqu->frag.fixed)
- return -EINVAL;
-
- if (wrqu->frag.disabled) {
- priv->frag_threshold |= FRAG_DISABLED;
- priv->ieee->fts = DEFAULT_FTS;
- } else {
- if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD)
- return -EINVAL;
-
- priv->ieee->fts = wrqu->frag.value & ~0x1;
- priv->frag_threshold = priv->ieee->fts;
- }
-
- IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
-
- return 0;
-}
-
-static int ipw2100_wx_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
- wrqu->frag.fixed = 0; /* no auto select */
- wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
-
- IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
- return -EINVAL;
-
- if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
- return 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->retry.flags & IW_RETRY_SHORT) {
- err = ipw2100_set_short_retry(priv, wrqu->retry.value);
- IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
- wrqu->retry.value);
- goto done;
- }
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- err = ipw2100_set_long_retry(priv, wrqu->retry.value);
- IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
- wrqu->retry.value);
- goto done;
- }
-
- err = ipw2100_set_short_retry(priv, wrqu->retry.value);
- if (!err)
- err = ipw2100_set_long_retry(priv, wrqu->retry.value);
-
- IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->retry.disabled = 0; /* can't be disabled */
-
- if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
- return -EINVAL;
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- wrqu->retry.value = priv->long_retry_limit;
- } else {
- wrqu->retry.flags =
- (priv->short_retry_limit !=
- priv->long_retry_limit) ?
- IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
-
- wrqu->retry.value = priv->short_retry_limit;
- }
-
- IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- IPW_DEBUG_WX("Initiating scan...\n");
-
- priv->user_requested_scan = 1;
- if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
- IPW_DEBUG_WX("Start scan failed.\n");
-
- /* TODO: Mark a scan as pending so when hardware initialized
- * a scan starts */
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
-}
-
-/*
- * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
- */
-static int ipw2100_wx_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- /*
- * No check of STATUS_INITIALIZED required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw2100_wx_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw2100_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->power.disabled) {
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
- IPW_DEBUG_WX("SET Power Management Mode -> off\n");
- goto done;
- }
-
- switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitly state all */
- break;
- default: /* Otherwise we don't support it */
- IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
- wrqu->power.flags);
- err = -EOPNOTSUPP;
- goto done;
- }
-
- /* If the user hasn't specified a power management mode yet, default
- * to BATTERY */
- priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
- err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
-
- IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-
-}
-
-static int ipw2100_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- wrqu->power.disabled = 1;
- else {
- wrqu->power.disabled = 0;
- wrqu->power.flags = 0;
- }
-
- IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
-
- return 0;
-}
-
-/*
- * WE-18 WPA support
- */
-
-/* SIOCSIWGENIE */
-static int ipw2100_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- u8 *buf;
-
- if (!ieee->wpa_enabled)
- return -EOPNOTSUPP;
-
- if (wrqu->data.length > MAX_WPA_IE_LEN ||
- (wrqu->data.length && extra == NULL))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = buf;
- ieee->wpa_ie_len = wrqu->data.length;
- } else {
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = NULL;
- ieee->wpa_ie_len = 0;
- }
-
- ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
-
- return 0;
-}
-
-/* SIOCGIWGENIE */
-static int ipw2100_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
-
- if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
- wrqu->data.length = 0;
- return 0;
- }
-
- if (wrqu->data.length < ieee->wpa_ie_len)
- return -E2BIG;
-
- wrqu->data.length = ieee->wpa_ie_len;
- memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
-
- return 0;
-}
-
-/* SIOCSIWAUTH */
-static int ipw2100_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
- unsigned long flags;
- int ret = 0;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * ipw2200 does not use these parameters
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
- break;
-
- flags = crypt->ops->get_flags(crypt->priv);
-
- if (param->value)
- flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
- else
- flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
-
- crypt->ops->set_flags(flags, crypt->priv);
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:{
- /* HACK:
- *
- * wpa_supplicant calls set_wpa_enabled when the driver
- * is loaded and unloaded, regardless of if WPA is being
- * used. No other calls are made which can be used to
- * determine if encryption will be used or not prior to
- * association being expected. If encryption is not being
- * used, drop_unencrypted is set to false, else true -- we
- * can use this to determine if the CAP_PRIVACY_ON bit should
- * be set.
- */
- struct libipw_security sec = {
- .flags = SEC_ENABLED,
- .enabled = param->value,
- };
- priv->ieee->drop_unencrypted = param->value;
- /* We only change SEC_LEVEL for open mode. Others
- * are set by ipw_wpa_set_encryption.
- */
- if (!param->value) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_0;
- } else {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- }
- if (priv->ieee->set_security)
- priv->ieee->set_security(priv->ieee->dev, &sec);
- break;
- }
-
- case IW_AUTH_80211_AUTH_ALG:
- ret = ipw2100_wpa_set_auth_algs(priv, param->value);
- break;
-
- case IW_AUTH_WPA_ENABLED:
- ret = ipw2100_wpa_enable(priv, param->value);
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = param->value;
- break;
-
- //case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = param->value;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return ret;
-}
-
-/* SIOCGIWAUTH */
-static int ipw2100_wx_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * wpa_supplicant will control these internally
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->get_flags) {
- IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
- "crypt not set!\n");
- break;
- }
-
- param->value = (crypt->ops->get_flags(crypt->priv) &
- IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value = ieee->drop_unencrypted;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- param->value = priv->ieee->sec.auth_mode;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = ieee->wpa_enabled;
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- param->value = ieee->ieee802_1x;
- break;
-
- case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- param->value = ieee->privacy_invoked;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/* SIOCSIWENCODEEXT */
-static int ipw2100_wx_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCGIWENCODEEXT */
-static int ipw2100_wx_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCSIWMLME */
-static int ipw2100_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- // silently ignore
- break;
-
- case IW_MLME_DISASSOC:
- ipw2100_disassociate_bssid(priv);
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/*
- *
- * IWPRIV handlers
- *
- */
-#ifdef CONFIG_IPW2100_MONITOR
-static int ipw2100_wx_set_promisc(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int *parms = (int *)extra;
- int enable = (parms[0] > 0);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (enable) {
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- err = ipw2100_set_channel(priv, parms[1], 0);
- goto done;
- }
- priv->channel = parms[1];
- err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
- } else {
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- err = ipw2100_switch_mode(priv, priv->last_mode);
- }
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- if (priv->status & STATUS_INITIALIZED)
- schedule_reset(priv);
- return 0;
-}
-
-#endif
-
-static int ipw2100_wx_set_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if ((mode < 0) || (mode > POWER_MODES))
- mode = IPW_POWER_AUTO;
-
- if (IPW_POWER_LEVEL(priv->power_mode) != mode)
- err = ipw2100_set_power_mode(priv, mode);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-#define MAX_POWER_STRING 80
-static int ipw2100_wx_get_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- int level = IPW_POWER_LEVEL(priv->power_mode);
- s32 timeout, period;
-
- if (!(priv->power_mode & IPW_POWER_ENABLED)) {
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Off)", level);
- } else {
- switch (level) {
- case IPW_POWER_MODE_CAM:
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (None)", level);
- break;
- case IPW_POWER_AUTO:
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Auto)", level);
- break;
- default:
- timeout = timeout_duration[level - 1] / 1000;
- period = period_duration[level - 1] / 1000;
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d "
- "(Timeout %dms, Period %dms)",
- level, timeout, period);
- }
- }
-
- wrqu->data.length = strlen(extra) + 1;
-
- return 0;
-}
-
-static int ipw2100_wx_set_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (mode == 1)
- priv->config |= CFG_LONG_PREAMBLE;
- else if (mode == 0)
- priv->config &= ~CFG_LONG_PREAMBLE;
- else {
- err = -EINVAL;
- goto done;
- }
-
- err = ipw2100_system_config(priv, 0);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (priv->config & CFG_LONG_PREAMBLE)
- snprintf(wrqu->name, IFNAMSIZ, "long (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
-
- return 0;
-}
-
-#ifdef CONFIG_IPW2100_MONITOR
-static int ipw2100_wx_set_crc_check(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (mode == 1)
- priv->config |= CFG_CRC_CHECK;
- else if (mode == 0)
- priv->config &= ~CFG_CRC_CHECK;
- else {
- err = -EINVAL;
- goto done;
- }
- err = 0;
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_crc_check(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (priv->config & CFG_CRC_CHECK)
- snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
-
- return 0;
-}
-#endif /* CONFIG_IPW2100_MONITOR */
-
-static iw_handler ipw2100_wx_handlers[] = {
- IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
- IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
- IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
- IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
- IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
- IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
- IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
- IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
- IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
- IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
- IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
- IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
- IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
- IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
- IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
- IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
- IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
- IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
- IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
- IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
- IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
- IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
- IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
- IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
- IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
- IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
- IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
-};
-
-#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
-#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
-#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
-#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
-#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
-#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
-#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
-#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
-
-static const struct iw_priv_args ipw2100_private_args[] = {
-
-#ifdef CONFIG_IPW2100_MONITOR
- {
- IPW2100_PRIV_SET_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
- {
- IPW2100_PRIV_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
-#endif /* CONFIG_IPW2100_MONITOR */
-
- {
- IPW2100_PRIV_SET_POWER,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
- {
- IPW2100_PRIV_GET_POWER,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
- "get_power"},
- {
- IPW2100_PRIV_SET_LONGPREAMBLE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
- {
- IPW2100_PRIV_GET_LONGPREAMBLE,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
-#ifdef CONFIG_IPW2100_MONITOR
- {
- IPW2100_PRIV_SET_CRC_CHECK,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
- {
- IPW2100_PRIV_GET_CRC_CHECK,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
-#endif /* CONFIG_IPW2100_MONITOR */
-};
-
-static iw_handler ipw2100_private_handler[] = {
-#ifdef CONFIG_IPW2100_MONITOR
- ipw2100_wx_set_promisc,
- ipw2100_wx_reset,
-#else /* CONFIG_IPW2100_MONITOR */
- NULL,
- NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
- ipw2100_wx_set_powermode,
- ipw2100_wx_get_powermode,
- ipw2100_wx_set_preamble,
- ipw2100_wx_get_preamble,
-#ifdef CONFIG_IPW2100_MONITOR
- ipw2100_wx_set_crc_check,
- ipw2100_wx_get_crc_check,
-#else /* CONFIG_IPW2100_MONITOR */
- NULL,
- NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
-};
-
-/*
- * Get wireless statistics.
- * Called by /proc/net/wireless
- * Also called by SIOCGIWSTATS
- */
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
-{
- enum {
- POOR = 30,
- FAIR = 60,
- GOOD = 80,
- VERY_GOOD = 90,
- EXCELLENT = 95,
- PERFECT = 100
- };
- int rssi_qual;
- int tx_qual;
- int beacon_qual;
- int quality;
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_statistics *wstats;
- u32 rssi, tx_retries, missed_beacons, tx_failures;
- u32 ord_len = sizeof(u32);
-
- if (!priv)
- return (struct iw_statistics *)NULL;
-
- wstats = &priv->wstats;
-
- /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
- * ipw2100_wx_wireless_stats seems to be called before fw is
- * initialized. STATUS_ASSOCIATED will only be set if the hw is up
- * and associated; if not associcated, the values are all meaningless
- * anyway, so set them all to NULL and INVALID */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->miss.beacon = 0;
- wstats->discard.retries = 0;
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
- return wstats;
- }
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
- &missed_beacons, &ord_len))
- goto fail_get_ordinal;
-
- /* If we don't have a connection the quality and level is 0 */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- } else {
- if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
- &rssi, &ord_len))
- goto fail_get_ordinal;
- wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
- if (rssi < 10)
- rssi_qual = rssi * POOR / 10;
- else if (rssi < 15)
- rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
- else if (rssi < 20)
- rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
- else if (rssi < 30)
- rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
- 10 + GOOD;
- else
- rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
- 10 + VERY_GOOD;
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
- &tx_retries, &ord_len))
- goto fail_get_ordinal;
-
- if (tx_retries > 75)
- tx_qual = (90 - tx_retries) * POOR / 15;
- else if (tx_retries > 70)
- tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
- else if (tx_retries > 65)
- tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
- else if (tx_retries > 50)
- tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
- 15 + GOOD;
- else
- tx_qual = (50 - tx_retries) *
- (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
-
- if (missed_beacons > 50)
- beacon_qual = (60 - missed_beacons) * POOR / 10;
- else if (missed_beacons > 40)
- beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
- 10 + POOR;
- else if (missed_beacons > 32)
- beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
- 18 + FAIR;
- else if (missed_beacons > 20)
- beacon_qual = (32 - missed_beacons) *
- (VERY_GOOD - GOOD) / 20 + GOOD;
- else
- beacon_qual = (20 - missed_beacons) *
- (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
-
- quality = min(tx_qual, rssi_qual);
- quality = min(beacon_qual, quality);
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (beacon_qual == quality)
- IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
- else if (tx_qual == quality)
- IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
- else if (quality != 100)
- IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
- else
- IPW_DEBUG_WX("Quality not clamped.\n");
-#endif
-
- wstats->qual.qual = quality;
- wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
- }
-
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
-
- /* FIXME: this is percent and not a # */
- wstats->miss.beacon = missed_beacons;
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
- &tx_failures, &ord_len))
- goto fail_get_ordinal;
- wstats->discard.retries = tx_failures;
-
- return wstats;
-
- fail_get_ordinal:
- IPW_DEBUG_WX("failed querying ordinals.\n");
-
- return (struct iw_statistics *)NULL;
-}
-
-static const struct iw_handler_def ipw2100_wx_handler_def = {
- .standard = ipw2100_wx_handlers,
- .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
- .num_private = ARRAY_SIZE(ipw2100_private_handler),
- .num_private_args = ARRAY_SIZE(ipw2100_private_args),
- .private = (iw_handler *) ipw2100_private_handler,
- .private_args = (struct iw_priv_args *)ipw2100_private_args,
- .get_wireless_stats = ipw2100_wx_wireless_stats,
-};
-
-static void ipw2100_wx_event_work(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, wx_event_work.work);
- union iwreq_data wrqu;
- unsigned int len = ETH_ALEN;
-
- if (priv->status & STATUS_STOPPING)
- return;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_WX("enter\n");
-
- mutex_unlock(&priv->action_mutex);
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /* Fetch BSSID from the hardware */
- if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
- priv->status & STATUS_RF_KILL_MASK ||
- ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
- &priv->bssid, &len)) {
- eth_zero_addr(wrqu.ap_addr.sa_data);
- } else {
- /* We now have the BSSID, so can finish setting to the full
- * associated state */
- memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
- priv->status &= ~STATUS_ASSOCIATING;
- priv->status |= STATUS_ASSOCIATED;
- netif_carrier_on(priv->net_dev);
- netif_wake_queue(priv->net_dev);
- }
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_WX("Configuring ESSID\n");
- mutex_lock(&priv->action_mutex);
- /* This is a disassociation event, so kick the firmware to
- * look for another AP */
- if (priv->config & CFG_STATIC_ESSID)
- ipw2100_set_essid(priv, priv->essid, priv->essid_len,
- 0);
- else
- ipw2100_set_essid(priv, NULL, 0, 0);
- mutex_unlock(&priv->action_mutex);
- }
-
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-#define IPW2100_FW_MAJOR_VERSION 1
-#define IPW2100_FW_MINOR_VERSION 3
-
-#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
-#define IPW2100_FW_MAJOR(x) (x & 0xff)
-
-#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
- IPW2100_FW_MAJOR_VERSION)
-
-#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
-"." __stringify(IPW2100_FW_MINOR_VERSION)
-
-#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
-
-/*
-
-BINARY FIRMWARE HEADER FORMAT
-
-offset length desc
-0 2 version
-2 2 mode == 0:BSS,1:IBSS,2:MONITOR
-4 4 fw_len
-8 4 uc_len
-C fw_len firmware data
-12 + fw_len uc_len microcode data
-
-*/
-
-struct ipw2100_fw_header {
- short version;
- short mode;
- unsigned int fw_size;
- unsigned int uc_size;
-} __packed;
-
-static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
-{
- struct ipw2100_fw_header *h =
- (struct ipw2100_fw_header *)fw->fw_entry->data;
-
- if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
- printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
- "(detected version id of %u). "
- "See Documentation/networking/device_drivers/wifi/intel/ipw2100.rst\n",
- h->version);
- return 1;
- }
-
- fw->version = h->version;
- fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
- fw->fw.size = h->fw_size;
- fw->uc.data = fw->fw.data + h->fw_size;
- fw->uc.size = h->uc_size;
-
- return 0;
-}
-
-static int ipw2100_get_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- char *fw_name;
- int rc;
-
- IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
- priv->net_dev->name);
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- fw_name = IPW2100_FW_NAME("-i");
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- fw_name = IPW2100_FW_NAME("-p");
- break;
-#endif
- case IW_MODE_INFRA:
- default:
- fw_name = IPW2100_FW_NAME("");
- break;
- }
-
- rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
-
- if (rc < 0) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: Firmware '%s' not available or load failed.\n",
- priv->net_dev->name, fw_name);
- return rc;
- }
- IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
- fw->fw_entry->size);
-
- ipw2100_mod_firmware_load(fw);
-
- return 0;
-}
-
-MODULE_FIRMWARE(IPW2100_FW_NAME("-i"));
-#ifdef CONFIG_IPW2100_MONITOR
-MODULE_FIRMWARE(IPW2100_FW_NAME("-p"));
-#endif
-MODULE_FIRMWARE(IPW2100_FW_NAME(""));
-
-static void ipw2100_release_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- fw->version = 0;
- release_firmware(fw->fw_entry);
- fw->fw_entry = NULL;
-}
-
-static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
- size_t max)
-{
- char ver[MAX_FW_VERSION_LEN];
- u32 len = MAX_FW_VERSION_LEN;
- u32 tmp;
- int i;
- /* firmware version is an ascii string (max len of 14) */
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
- return -EIO;
- tmp = max;
- if (len >= max)
- len = max - 1;
- for (i = 0; i < len; i++)
- buf[i] = ver[i];
- buf[i] = '\0';
- return tmp;
-}
-
-static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
- size_t max)
-{
- u32 ver;
- u32 len = sizeof(ver);
- /* microcode version is a 32 bit integer */
- if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
- return -EIO;
- return snprintf(buf, max, "%08X", ver);
-}
-
-/*
- * On exit, the firmware will have been freed from the fw list
- */
-static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
-{
- /* firmware is constructed of N contiguous entries, each entry is
- * structured as:
- *
- * offset sie desc
- * 0 4 address to write to
- * 4 2 length of data run
- * 6 length data
- */
- unsigned int addr;
- unsigned short len;
-
- const unsigned char *firmware_data = fw->fw.data;
- unsigned int firmware_data_left = fw->fw.size;
-
- while (firmware_data_left > 0) {
- addr = *(u32 *) (firmware_data);
- firmware_data += 4;
- firmware_data_left -= 4;
-
- len = *(u16 *) (firmware_data);
- firmware_data += 2;
- firmware_data_left -= 2;
-
- if (len > 32) {
- printk(KERN_ERR DRV_NAME ": "
- "Invalid firmware run-length of %d bytes\n",
- len);
- return -EINVAL;
- }
-
- write_nic_memory(priv->net_dev, addr, len, firmware_data);
- firmware_data += len;
- firmware_data_left -= len;
- }
-
- return 0;
-}
-
-struct symbol_alive_response {
- u8 cmd_id;
- u8 seq_num;
- u8 ucode_rev;
- u8 eeprom_valid;
- u16 valid_flags;
- u8 IEEE_addr[6];
- u16 flags;
- u16 pcb_rev;
- u16 clock_settle_time; // 1us LSB
- u16 powerup_settle_time; // 1us LSB
- u16 hop_settle_time; // 1us LSB
- u8 date[3]; // month, day, year
- u8 time[2]; // hours, minutes
- u8 ucode_valid;
-};
-
-static int ipw2100_ucode_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- struct net_device *dev = priv->net_dev;
- const unsigned char *microcode_data = fw->uc.data;
- unsigned int microcode_data_left = fw->uc.size;
- void __iomem *reg = priv->ioaddr;
-
- struct symbol_alive_response response;
- int i, j;
- u8 data;
-
- /* Symbol control */
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
- readl(reg);
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
- readl(reg);
-
- /* HW config */
- write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
- readl(reg);
- write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
- readl(reg);
-
- /* EN_CS_ACCESS bit to reset control store pointer */
- write_nic_byte(dev, 0x210000, 0x40);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x40);
- readl(reg);
-
- /* copy microcode from buffer into Symbol */
-
- while (microcode_data_left > 0) {
- write_nic_byte(dev, 0x210010, *microcode_data++);
- write_nic_byte(dev, 0x210010, *microcode_data++);
- microcode_data_left -= 2;
- }
-
- /* EN_CS_ACCESS bit to reset the control store pointer */
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
-
- /* Enable System (Reg 0)
- * first enable causes garbage in RX FIFO */
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x80);
- readl(reg);
-
- /* Reset External Baseband Reg */
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
- readl(reg);
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
- readl(reg);
-
- /* HW Config (Reg 5) */
- write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
- readl(reg);
- write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
- readl(reg);
-
- /* Enable System (Reg 0)
- * second enable should be OK */
- write_nic_byte(dev, 0x210000, 0x00); // clear enable system
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x80); // set enable system
-
- /* check Symbol is enabled - upped this from 5 as it wasn't always
- * catching the update */
- for (i = 0; i < 10; i++) {
- udelay(10);
-
- /* check Dino is enabled bit */
- read_nic_byte(dev, 0x210000, &data);
- if (data & 0x1)
- break;
- }
-
- if (i == 10) {
- printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
- dev->name);
- return -EIO;
- }
-
- /* Get Symbol alive response */
- for (i = 0; i < 30; i++) {
- /* Read alive response structure */
- for (j = 0;
- j < (sizeof(struct symbol_alive_response) >> 1); j++)
- read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
-
- if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
- break;
- udelay(10);
- }
-
- if (i == 30) {
- printk(KERN_ERR DRV_NAME
- ": %s: No response from Symbol - hw not alive\n",
- dev->name);
- printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
- return -EIO;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h
deleted file mode 100644
index b34085ade3aa1..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h
+++ /dev/null
@@ -1,1142 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#ifndef _IPW2100_H
-#define _IPW2100_H
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <asm/io.h>
-#include <linux/socket.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h> // new driver API
-
-#ifdef CONFIG_IPW2100_MONITOR
-#include <net/ieee80211_radiotap.h>
-#endif
-
-#include <linux/workqueue.h>
-#include <linux/mutex.h>
-
-#include "libipw.h"
-
-struct ipw2100_priv;
-struct ipw2100_tx_packet;
-struct ipw2100_rx_packet;
-
-#define IPW_DL_UNINIT 0x80000000
-#define IPW_DL_NONE 0x00000000
-#define IPW_DL_ALL 0x7FFFFFFF
-
-/*
- * To use the debug system;
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define IPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your
- * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ipw2100/debug_level
- *
- * you simply need to add your entry to the ipw2100_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/ipw2100 then you do not have
- * CONFIG_IPW2100_DEBUG defined in your kernel configuration
- *
- */
-
-#define IPW_DL_ERROR (1<<0)
-#define IPW_DL_WARNING (1<<1)
-#define IPW_DL_INFO (1<<2)
-#define IPW_DL_WX (1<<3)
-#define IPW_DL_HC (1<<5)
-#define IPW_DL_STATE (1<<6)
-
-#define IPW_DL_NOTIF (1<<10)
-#define IPW_DL_SCAN (1<<11)
-#define IPW_DL_ASSOC (1<<12)
-#define IPW_DL_DROP (1<<13)
-
-#define IPW_DL_IOCTL (1<<14)
-#define IPW_DL_RF_KILL (1<<17)
-
-#define IPW_DL_MANAGE (1<<15)
-#define IPW_DL_FW (1<<16)
-
-#define IPW_DL_FRAG (1<<21)
-#define IPW_DL_WEP (1<<22)
-#define IPW_DL_TX (1<<23)
-#define IPW_DL_RX (1<<24)
-#define IPW_DL_ISR (1<<25)
-#define IPW_DL_IO (1<<26)
-#define IPW_DL_TRACE (1<<28)
-
-#define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_INFO(f...) IPW_DEBUG(IPW_DL_INFO, ## f)
-#define IPW_DEBUG_WX(f...) IPW_DEBUG(IPW_DL_WX, ## f)
-#define IPW_DEBUG_SCAN(f...) IPW_DEBUG(IPW_DL_SCAN, ## f)
-#define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f)
-#define IPW_DEBUG_TRACE(f...) IPW_DEBUG(IPW_DL_TRACE, ## f)
-#define IPW_DEBUG_RX(f...) IPW_DEBUG(IPW_DL_RX, ## f)
-#define IPW_DEBUG_TX(f...) IPW_DEBUG(IPW_DL_TX, ## f)
-#define IPW_DEBUG_ISR(f...) IPW_DEBUG(IPW_DL_ISR, ## f)
-#define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f)
-#define IPW_DEBUG_WEP(f...) IPW_DEBUG(IPW_DL_WEP, ## f)
-#define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f)
-#define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f)
-#define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f)
-#define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f)
-#define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f)
-#define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f)
-#define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f)
-#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-
-enum {
- IPW_HW_STATE_DISABLED = 1,
- IPW_HW_STATE_ENABLED = 0
-};
-
-extern const char *port_type_str[];
-extern const char *band_str[];
-
-#define NUMBER_OF_BD_PER_COMMAND_PACKET 1
-#define NUMBER_OF_BD_PER_DATA_PACKET 2
-
-#define IPW_MAX_BDS 6
-#define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR 2
-#define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS 1
-
-#define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \
- (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET)
-
-struct bd_status {
- union {
- struct {
- u8 nlf:1, txType:2, intEnabled:1, reserved:4;
- } fields;
- u8 field;
- } info;
-} __packed;
-
-struct ipw2100_bd {
- u32 host_addr;
- u32 buf_length;
- struct bd_status status;
- /* number of fragments for frame (should be set only for
- * 1st TBD) */
- u8 num_fragments;
- u8 reserved[6];
-} __packed;
-
-#define IPW_BD_QUEUE_LENGTH(n) (1<<n)
-#define IPW_BD_ALIGNMENT(L) (L*sizeof(struct ipw2100_bd))
-
-#define IPW_BD_STATUS_TX_FRAME_802_3 0x00
-#define IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT 0x01
-#define IPW_BD_STATUS_TX_FRAME_COMMAND 0x02
-#define IPW_BD_STATUS_TX_FRAME_802_11 0x04
-#define IPW_BD_STATUS_TX_INTERRUPT_ENABLE 0x08
-
-struct ipw2100_bd_queue {
- /* driver (virtual) pointer to queue */
- struct ipw2100_bd *drv;
-
- /* firmware (physical) pointer to queue */
- dma_addr_t nic;
-
- /* Length of phy memory allocated for BDs */
- u32 size;
-
- /* Number of BDs in queue (and in array) */
- u32 entries;
-
- /* Number of available BDs (invalid for NIC BDs) */
- u32 available;
-
- /* Offset of oldest used BD in array (next one to
- * check for completion) */
- u32 oldest;
-
- /* Offset of next available (unused) BD */
- u32 next;
-};
-
-#define RX_QUEUE_LENGTH 256
-#define TX_QUEUE_LENGTH 256
-#define HW_QUEUE_LENGTH 256
-
-#define TX_PENDED_QUEUE_LENGTH (TX_QUEUE_LENGTH / NUMBER_OF_BD_PER_DATA_PACKET)
-
-#define STATUS_TYPE_MASK 0x0000000f
-#define COMMAND_STATUS_VAL 0
-#define STATUS_CHANGE_VAL 1
-#define P80211_DATA_VAL 2
-#define P8023_DATA_VAL 3
-#define HOST_NOTIFICATION_VAL 4
-
-#define IPW2100_RSSI_TO_DBM (-98)
-
-struct ipw2100_status {
- u32 frame_size;
- u16 status_fields;
- u8 flags;
-#define IPW_STATUS_FLAG_DECRYPTED (1<<0)
-#define IPW_STATUS_FLAG_WEP_ENCRYPTED (1<<1)
-#define IPW_STATUS_FLAG_CRC_ERROR (1<<2)
- u8 rssi;
-} __packed;
-
-struct ipw2100_status_queue {
- /* driver (virtual) pointer to queue */
- struct ipw2100_status *drv;
-
- /* firmware (physical) pointer to queue */
- dma_addr_t nic;
-
- /* Length of phy memory allocated for BDs */
- u32 size;
-};
-
-#define HOST_COMMAND_PARAMS_REG_LEN 100
-#define CMD_STATUS_PARAMS_REG_LEN 3
-
-#define IPW_WPA_CAPABILITIES 0x1
-#define IPW_WPA_LISTENINTERVAL 0x2
-#define IPW_WPA_AP_ADDRESS 0x4
-
-#define IPW_MAX_VAR_IE_LEN ((HOST_COMMAND_PARAMS_REG_LEN - 4) * sizeof(u32))
-
-struct ipw2100_wpa_assoc_frame {
- u16 fixed_ie_mask;
- struct {
- u16 capab_info;
- u16 listen_interval;
- u8 current_ap[ETH_ALEN];
- } fixed_ies;
- u32 var_ie_len;
- u8 var_ie[IPW_MAX_VAR_IE_LEN];
-};
-
-#define IPW_BSS 1
-#define IPW_MONITOR 2
-#define IPW_IBSS 3
-
-/**
- * @struct _tx_cmd - HWCommand
- * @brief H/W command structure.
- */
-struct ipw2100_cmd_header {
- u32 host_command_reg;
- u32 host_command_reg1;
- u32 sequence;
- u32 host_command_len_reg;
- u32 host_command_params_reg[HOST_COMMAND_PARAMS_REG_LEN];
- u32 cmd_status_reg;
- u32 cmd_status_params_reg[CMD_STATUS_PARAMS_REG_LEN];
- u32 rxq_base_ptr;
- u32 rxq_next_ptr;
- u32 rxq_host_ptr;
- u32 txq_base_ptr;
- u32 txq_next_ptr;
- u32 txq_host_ptr;
- u32 tx_status_reg;
- u32 reserved;
- u32 status_change_reg;
- u32 reserved1[3];
- u32 *ordinal1_ptr;
- u32 *ordinal2_ptr;
-} __packed;
-
-struct ipw2100_data_header {
- u32 host_command_reg;
- u32 host_command_reg1;
- u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver
- u8 needs_encryption; // BOOLEAN in win! TRUE if frma need to be enc in NIC
- u8 wep_index; // 0 no key, 1-4 key index, 0xff immediate key
- u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
- u8 key[16];
- u8 reserved[10]; // f/w reserved
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
- u16 fragment_size;
-} __packed;
-
-/* Host command data structure */
-struct host_command {
- u32 host_command; // COMMAND ID
- u32 host_command1; // COMMAND ID
- u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID)
- u32 host_command_length; // LENGTH
- u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS
-} __packed;
-
-typedef enum {
- POWER_ON_RESET,
- EXIT_POWER_DOWN_RESET,
- SW_RESET,
- EEPROM_RW,
- SW_RE_INIT
-} ipw2100_reset_event;
-
-enum {
- COMMAND = 0xCAFE,
- DATA,
- RX
-};
-
-struct ipw2100_tx_packet {
- int type;
- int index;
- union {
- struct { /* COMMAND */
- struct ipw2100_cmd_header *cmd;
- dma_addr_t cmd_phys;
- } c_struct;
- struct { /* DATA */
- struct ipw2100_data_header *data;
- dma_addr_t data_phys;
- struct libipw_txb *txb;
- } d_struct;
- } info;
- int jiffy_start;
-
- struct list_head list;
-};
-
-struct ipw2100_rx_packet {
- struct ipw2100_rx *rxp;
- dma_addr_t dma_addr;
- int jiffy_start;
- struct sk_buff *skb;
- struct list_head list;
-};
-
-#define FRAG_DISABLED (1<<31)
-#define RTS_DISABLED (1<<31)
-#define MAX_RTS_THRESHOLD 2304U
-#define MIN_RTS_THRESHOLD 1U
-#define DEFAULT_RTS_THRESHOLD 1000U
-
-#define DEFAULT_BEACON_INTERVAL 100U
-#define DEFAULT_SHORT_RETRY_LIMIT 7U
-#define DEFAULT_LONG_RETRY_LIMIT 4U
-
-struct ipw2100_ordinals {
- u32 table1_addr;
- u32 table2_addr;
- u32 table1_size;
- u32 table2_size;
-};
-
-/* Host Notification header */
-struct ipw2100_notification {
- u32 hnhdr_subtype; /* type of host notification */
- u32 hnhdr_size; /* size in bytes of data
- or number of entries, if table.
- Does NOT include header */
-} __packed;
-
-#define MAX_KEY_SIZE 16
-#define MAX_KEYS 8
-
-#define IPW2100_WEP_ENABLE (1<<1)
-#define IPW2100_WEP_DROP_CLEAR (1<<2)
-
-#define IPW_NONE_CIPHER (1<<0)
-#define IPW_WEP40_CIPHER (1<<1)
-#define IPW_TKIP_CIPHER (1<<2)
-#define IPW_CCMP_CIPHER (1<<4)
-#define IPW_WEP104_CIPHER (1<<5)
-#define IPW_CKIP_CIPHER (1<<6)
-
-#define IPW_AUTH_OPEN 0
-#define IPW_AUTH_SHARED 1
-#define IPW_AUTH_LEAP 2
-#define IPW_AUTH_LEAP_CISCO_ID 0x80
-
-struct statistic {
- int value;
- int hi;
- int lo;
-};
-
-#define INIT_STAT(x) do { \
- (x)->value = (x)->hi = 0; \
- (x)->lo = 0x7fffffff; \
-} while (0)
-#define SET_STAT(x,y) do { \
- (x)->value = y; \
- if ((x)->value > (x)->hi) (x)->hi = (x)->value; \
- if ((x)->value < (x)->lo) (x)->lo = (x)->value; \
-} while (0)
-#define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \
-while (0)
-#define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \
-while (0)
-
-#define IPW2100_ERROR_QUEUE 5
-
-/* Power management code: enable or disable? */
-enum {
-#ifdef CONFIG_PM
- IPW2100_PM_DISABLED = 0,
- PM_STATE_SIZE = 16,
-#else
- IPW2100_PM_DISABLED = 1,
- PM_STATE_SIZE = 0,
-#endif
-};
-
-#define STATUS_POWERED (1<<0)
-#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */
-#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */
-#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */
-#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */
-#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */
-#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */
-#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */
-#define STATUS_INT_ENABLED (1<<11)
-#define STATUS_RF_KILL_HW (1<<12)
-#define STATUS_RF_KILL_SW (1<<13)
-#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
-#define STATUS_EXIT_PENDING (1<<14)
-
-#define STATUS_SCAN_PENDING (1<<23)
-#define STATUS_SCANNING (1<<24)
-#define STATUS_SCAN_ABORTING (1<<25)
-#define STATUS_SCAN_COMPLETE (1<<26)
-#define STATUS_WX_EVENT_PENDING (1<<27)
-#define STATUS_RESET_PENDING (1<<29)
-#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
-
-/* Internal NIC states */
-#define IPW_STATE_INITIALIZED (1<<0)
-#define IPW_STATE_COUNTRY_FOUND (1<<1)
-#define IPW_STATE_ASSOCIATED (1<<2)
-#define IPW_STATE_ASSN_LOST (1<<3)
-#define IPW_STATE_ASSN_CHANGED (1<<4)
-#define IPW_STATE_SCAN_COMPLETE (1<<5)
-#define IPW_STATE_ENTERED_PSP (1<<6)
-#define IPW_STATE_LEFT_PSP (1<<7)
-#define IPW_STATE_RF_KILL (1<<8)
-#define IPW_STATE_DISABLED (1<<9)
-#define IPW_STATE_POWER_DOWN (1<<10)
-#define IPW_STATE_SCANNING (1<<11)
-
-#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
-#define CFG_CUSTOM_MAC (1<<3)
-#define CFG_LONG_PREAMBLE (1<<4)
-#define CFG_ASSOCIATE (1<<6)
-#define CFG_FIXED_RATE (1<<7)
-#define CFG_ADHOC_CREATE (1<<8)
-#define CFG_PASSIVE_SCAN (1<<10)
-#ifdef CONFIG_IPW2100_MONITOR
-#define CFG_CRC_CHECK (1<<11)
-#endif
-
-#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
-
-struct ipw2100_priv {
- void __iomem *ioaddr;
-
- int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
- int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
-
- struct libipw_device *ieee;
- unsigned long status;
- unsigned long config;
- unsigned long capability;
-
- /* Statistics */
- int resets;
- time64_t reset_backoff;
-
- /* Context */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
- u8 bssid[ETH_ALEN];
- u8 channel;
- int last_mode;
-
- time64_t connect_start;
- time64_t last_reset;
-
- u32 channel_mask;
- u32 fatal_error;
- u32 fatal_errors[IPW2100_ERROR_QUEUE];
- u32 fatal_index;
- int eeprom_version;
- int firmware_version;
- unsigned long hw_features;
- int hangs;
- u32 last_rtc;
- int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
- u8 *snapshot[0x30];
-
- u8 mandatory_bssid_mac[ETH_ALEN];
- u8 mac_addr[ETH_ALEN];
-
- int power_mode;
-
- int messages_sent;
-
- int short_retry_limit;
- int long_retry_limit;
-
- u32 rts_threshold;
- u32 frag_threshold;
-
- int in_isr;
-
- u32 tx_rates;
- int tx_power;
- u32 beacon_interval;
-
- char nick[IW_ESSID_MAX_SIZE + 1];
-
- struct ipw2100_status_queue status_queue;
-
- struct statistic txq_stat;
- struct statistic rxq_stat;
- struct ipw2100_bd_queue rx_queue;
- struct ipw2100_bd_queue tx_queue;
- struct ipw2100_rx_packet *rx_buffers;
-
- struct statistic fw_pend_stat;
- struct list_head fw_pend_list;
-
- struct statistic msg_free_stat;
- struct statistic msg_pend_stat;
- struct list_head msg_free_list;
- struct list_head msg_pend_list;
- struct ipw2100_tx_packet *msg_buffers;
-
- struct statistic tx_free_stat;
- struct statistic tx_pend_stat;
- struct list_head tx_free_list;
- struct list_head tx_pend_list;
- struct ipw2100_tx_packet *tx_buffers;
-
- struct ipw2100_ordinals ordinals;
-
- struct pci_dev *pci_dev;
-
- struct proc_dir_entry *dir_dev;
-
- struct net_device *net_dev;
- struct iw_statistics wstats;
-
- struct iw_public_data wireless_data;
-
- struct tasklet_struct irq_tasklet;
-
- struct delayed_work reset_work;
- struct delayed_work security_work;
- struct delayed_work wx_event_work;
- struct delayed_work hang_check;
- struct delayed_work rf_kill;
- struct delayed_work scan_event;
-
- int user_requested_scan;
-
- /* Track time in suspend, using CLOCK_BOOTTIME */
- time64_t suspend_at;
- time64_t suspend_time;
-
- u32 interrupts;
- int tx_interrupts;
- int rx_interrupts;
- int inta_other;
-
- spinlock_t low_lock;
- struct mutex action_mutex;
- struct mutex adapter_mutex;
-
- wait_queue_head_t wait_command_queue;
-};
-
-/*********************************************************
- * Host Command -> From Driver to FW
- *********************************************************/
-
-/**
- * Host command identifiers
- */
-#define HOST_COMPLETE 2
-#define SYSTEM_CONFIG 6
-#define SSID 8
-#define MANDATORY_BSSID 9
-#define AUTHENTICATION_TYPE 10
-#define ADAPTER_ADDRESS 11
-#define PORT_TYPE 12
-#define INTERNATIONAL_MODE 13
-#define CHANNEL 14
-#define RTS_THRESHOLD 15
-#define FRAG_THRESHOLD 16
-#define POWER_MODE 17
-#define TX_RATES 18
-#define BASIC_TX_RATES 19
-#define WEP_KEY_INFO 20
-#define WEP_KEY_INDEX 25
-#define WEP_FLAGS 26
-#define ADD_MULTICAST 27
-#define CLEAR_ALL_MULTICAST 28
-#define BEACON_INTERVAL 29
-#define ATIM_WINDOW 30
-#define CLEAR_STATISTICS 31
-#define SEND 33
-#define TX_POWER_INDEX 36
-#define BROADCAST_SCAN 43
-#define CARD_DISABLE 44
-#define PREFERRED_BSSID 45
-#define SET_SCAN_OPTIONS 46
-#define SCAN_DWELL_TIME 47
-#define SWEEP_TABLE 48
-#define AP_OR_STATION_TABLE 49
-#define GROUP_ORDINALS 50
-#define SHORT_RETRY_LIMIT 51
-#define LONG_RETRY_LIMIT 52
-
-#define HOST_PRE_POWER_DOWN 58
-#define CARD_DISABLE_PHY_OFF 61
-#define MSDU_TX_RATES 62
-
-/* Rogue AP Detection */
-#define SET_STATION_STAT_BITS 64
-#define CLEAR_STATIONS_STAT_BITS 65
-#define LEAP_ROGUE_MODE 66 //TODO tbw replaced by CFG_LEAP_ROGUE_AP
-#define SET_SECURITY_INFORMATION 67
-#define DISASSOCIATION_BSSID 68
-#define SET_WPA_IE 69
-
-/* system configuration bit mask: */
-#define IPW_CFG_MONITOR 0x00004
-#define IPW_CFG_PREAMBLE_AUTO 0x00010
-#define IPW_CFG_IBSS_AUTO_START 0x00020
-#define IPW_CFG_LOOPBACK 0x00100
-#define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800
-#define IPW_CFG_BT_SIDEBAND_SIGNAL 0x02000
-#define IPW_CFG_802_1x_ENABLE 0x04000
-#define IPW_CFG_BSS_MASK 0x08000
-#define IPW_CFG_IBSS_MASK 0x10000
-
-#define IPW_SCAN_NOASSOCIATE (1<<0)
-#define IPW_SCAN_MIXED_CELL (1<<1)
-/* RESERVED (1<<2) */
-#define IPW_SCAN_PASSIVE (1<<3)
-
-#define IPW_NIC_FATAL_ERROR 0x2A7F0
-#define IPW_ERROR_ADDR(x) (x & 0x3FFFF)
-#define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24)
-#define IPW2100_ERR_C3_CORRUPTION (0x10 << 24)
-#define IPW2100_ERR_MSG_TIMEOUT (0x11 << 24)
-#define IPW2100_ERR_FW_LOAD (0x12 << 24)
-
-#define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND 0x200
-#define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80
-
-#define IPW_MEM_HOST_SHARED_RX_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40)
-#define IPW_MEM_HOST_SHARED_RX_STATUS_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44)
-#define IPW_MEM_HOST_SHARED_RX_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48)
-#define IPW_MEM_HOST_SHARED_RX_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0)
-
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00)
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04)
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80)
-
-#define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \
- (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20)
-
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \
- (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND)
-
-#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180)
-#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184)
-
-#define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB)
-#define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1
-#define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2
-#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3
-#define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4
-#define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5
-#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16
-#define IPW2100_INTA_FW_INIT_DONE (0x01000000) // Bit 24
-#define IPW2100_INTA_FW_CALIBRATION_CALC (0x02000000) // Bit 25
-#define IPW2100_INTA_FATAL_ERROR (0x40000000) // Bit 30
-#define IPW2100_INTA_PARITY_ERROR (0x80000000) // Bit 31 (MSB)
-
-#define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET (0x00000001)
-#define IPW_AUX_HOST_RESET_REG_FORCE_NMI (0x00000002)
-#define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI (0x00000004)
-#define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI (0x00000008)
-#define IPW_AUX_HOST_RESET_REG_SW_RESET (0x00000080)
-#define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED (0x00000100)
-#define IPW_AUX_HOST_RESET_REG_STOP_MASTER (0x00000200)
-
-#define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY (0x00000001) // Bit 0 (LSB)
-#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY (0x00000002) // Bit 1
-#define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE (0x00000004) // Bit 2
-#define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG (0x000007c0) // Bits 6-10
-#define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE (0x00000200) // Bit 9
-#define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE (0x00000400) // Bit 10
-#define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE (0x20000000) // Bit 29
-#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK (0x40000000) // Bit 30
-#define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK (0x80000000) // Bit 31 (MSB)
-
-#define IPW_BIT_GPIO_GPIO1_MASK 0x0000000C
-#define IPW_BIT_GPIO_GPIO3_MASK 0x000000C0
-#define IPW_BIT_GPIO_GPIO1_ENABLE 0x00000008
-#define IPW_BIT_GPIO_RF_KILL 0x00010000
-
-#define IPW_BIT_GPIO_LED_OFF 0x00002000 // Bit 13 = 1
-
-#define IPW_REG_DOMAIN_0_OFFSET 0x0000
-#define IPW_REG_DOMAIN_1_OFFSET IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND
-
-#define IPW_REG_INTA IPW_REG_DOMAIN_0_OFFSET + 0x0008
-#define IPW_REG_INTA_MASK IPW_REG_DOMAIN_0_OFFSET + 0x000C
-#define IPW_REG_INDIRECT_ACCESS_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0010
-#define IPW_REG_INDIRECT_ACCESS_DATA IPW_REG_DOMAIN_0_OFFSET + 0x0014
-#define IPW_REG_AUTOINCREMENT_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0018
-#define IPW_REG_AUTOINCREMENT_DATA IPW_REG_DOMAIN_0_OFFSET + 0x001C
-#define IPW_REG_RESET_REG IPW_REG_DOMAIN_0_OFFSET + 0x0020
-#define IPW_REG_GP_CNTRL IPW_REG_DOMAIN_0_OFFSET + 0x0024
-#define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030
-#define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188
-#define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C
-#define IPW_REG_FW_COMPATIBILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190
-
-#define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC
-
-#define IPW_INTERRUPT_MASK 0xC1010013
-
-#define IPW2100_CONTROL_REG 0x220000
-#define IPW2100_CONTROL_PHY_OFF 0x8
-
-#define IPW2100_COMMAND 0x00300004
-#define IPW2100_COMMAND_PHY_ON 0x0
-#define IPW2100_COMMAND_PHY_OFF 0x1
-
-/* in DEBUG_AREA, values of memory always 0xd55555d5 */
-#define IPW_REG_DOA_DEBUG_AREA_START IPW_REG_DOMAIN_0_OFFSET + 0x0090
-#define IPW_REG_DOA_DEBUG_AREA_END IPW_REG_DOMAIN_0_OFFSET + 0x00FF
-#define IPW_DATA_DOA_DEBUG_VALUE 0xd55555d5
-
-#define IPW_INTERNAL_REGISTER_HALT_AND_RESET 0x003000e0
-
-#define IPW_WAIT_CLOCK_STABILIZATION_DELAY 50 // micro seconds
-#define IPW_WAIT_RESET_ARC_COMPLETE_DELAY 10 // micro seconds
-#define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds
-
-// BD ring queue read/write difference
-#define IPW_BD_QUEUE_W_R_MIN_SPARE 2
-
-#define IPW_CACHE_LINE_LENGTH_DEFAULT 0x80
-
-#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli
-#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli
-
-#define IPW_HEADER_802_11_SIZE sizeof(struct libipw_hdr_3addr)
-#define IPW_MAX_80211_PAYLOAD_SIZE 2304U
-#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312
-#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536
-#define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH 60
-#define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \
- (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \
- sizeof(struct ethhdr))
-
-#define IPW_802_11_FCS_LENGTH 4
-#define IPW_RX_NIC_BUFFER_LENGTH \
- (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \
- IPW_802_11_FCS_LENGTH)
-
-#define IPW_802_11_PAYLOAD_OFFSET \
- (sizeof(struct libipw_hdr_3addr) + \
- sizeof(struct libipw_snap_hdr))
-
-struct ipw2100_rx {
- union {
- unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
- struct libipw_hdr_4addr header;
- u32 status;
- struct ipw2100_notification notification;
- struct ipw2100_cmd_header command;
- } rx_data;
-} __packed;
-
-/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */
-#define TX_RATE_1_MBIT 0x0001
-#define TX_RATE_2_MBIT 0x0002
-#define TX_RATE_5_5_MBIT 0x0004
-#define TX_RATE_11_MBIT 0x0008
-#define TX_RATE_MASK 0x000F
-#define DEFAULT_TX_RATES 0x000F
-
-#define IPW_POWER_MODE_CAM 0x00 //(always on)
-#define IPW_POWER_INDEX_1 0x01
-#define IPW_POWER_INDEX_2 0x02
-#define IPW_POWER_INDEX_3 0x03
-#define IPW_POWER_INDEX_4 0x04
-#define IPW_POWER_INDEX_5 0x05
-#define IPW_POWER_AUTO 0x06
-#define IPW_POWER_MASK 0x0F
-#define IPW_POWER_ENABLED 0x10
-#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
-
-#define IPW_TX_POWER_AUTO 0
-#define IPW_TX_POWER_ENHANCED 1
-
-#define IPW_TX_POWER_DEFAULT 32
-#define IPW_TX_POWER_MIN 0
-#define IPW_TX_POWER_MAX 16
-#define IPW_TX_POWER_MIN_DBM (-12)
-#define IPW_TX_POWER_MAX_DBM 16
-
-#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan
-#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan
-
-#define REG_MIN_CHANNEL 0
-#define REG_MAX_CHANNEL 14
-
-#define REG_CHANNEL_MASK 0x00003FFF
-#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff
-
-#define DIVERSITY_EITHER 0 // Use both antennas
-#define DIVERSITY_ANTENNA_A 1 // Use antenna A
-#define DIVERSITY_ANTENNA_B 2 // Use antenna B
-
-#define HOST_COMMAND_WAIT 0
-#define HOST_COMMAND_NO_WAIT 1
-
-#define LOCK_NONE 0
-#define LOCK_DRIVER 1
-#define LOCK_FW 2
-
-#define TYPE_SWEEP_ORD 0x000D
-#define TYPE_IBSS_STTN_ORD 0x000E
-#define TYPE_BSS_AP_ORD 0x000F
-#define TYPE_RAW_BEACON_ENTRY 0x0010
-#define TYPE_CALIBRATION_DATA 0x0011
-#define TYPE_ROGUE_AP_DATA 0x0012
-#define TYPE_ASSOCIATION_REQUEST 0x0013
-#define TYPE_REASSOCIATION_REQUEST 0x0014
-
-#define HW_FEATURE_RFKILL 0x0001
-#define RF_KILLSWITCH_OFF 1
-#define RF_KILLSWITCH_ON 0
-
-#define IPW_COMMAND_POOL_SIZE 40
-
-#define IPW_START_ORD_TAB_1 1
-#define IPW_START_ORD_TAB_2 1000
-
-#define IPW_ORD_TAB_1_ENTRY_SIZE sizeof(u32)
-
-#define IS_ORDINAL_TABLE_ONE(mgr,id) \
- ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size))
-#define IS_ORDINAL_TABLE_TWO(mgr,id) \
- ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2)))
-
-#define BSS_ID_LENGTH 6
-
-// Fixed size data: Ordinal Table 1
-typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
-// Transmit statistics
- IPW_ORD_STAT_TX_HOST_REQUESTS = 1, // # of requested Host Tx's (MSDU)
- IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU)
- IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU)
-
- IPW_ORD_STAT_TX_DIR_DATA1 = 4, // # of successful Directed Tx's (MSDU) @ 1MB
- IPW_ORD_STAT_TX_DIR_DATA2, // # of successful Directed Tx's (MSDU) @ 2MB
- IPW_ORD_STAT_TX_DIR_DATA5_5, // # of successful Directed Tx's (MSDU) @ 5_5MB
- IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB
- IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB
-
- IPW_ORD_STAT_TX_NODIR_DATA1 = 13, // # of successful Non_Directed Tx's (MSDU) @ 1MB
- IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB
- IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB
- IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB
-
- IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's
- IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS
- IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS
- IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK
- IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's
- IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's
- IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's
- IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's
- IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted
- IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted
- IPW_ORD_STAT_TX_BEACON, // # of tx beacon
- IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM
- IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX
- IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx
- IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX
-
- IPW_ORD_STAT_TX_TOTAL_BYTES = 41, // Total successful Tx data bytes
- IPW_ORD_STAT_TX_RETRIES, // # of Tx retries
- IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS
- IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS
- IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS
- IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS
-
- IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures
- IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time
- IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP, // # of times max tries in a hop failed
- IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup
- IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted
- IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed
- IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames
- IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent
- IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks
-
- // Receive statistics
- IPW_ORD_STAT_RX_HOST = 61, // # of packets passed to host
- IPW_ORD_STAT_RX_DIR_DATA, // # of directed packets
- IPW_ORD_STAT_RX_DIR_DATA1, // # of directed packets at 1MB
- IPW_ORD_STAT_RX_DIR_DATA2, // # of directed packets at 2MB
- IPW_ORD_STAT_RX_DIR_DATA5_5, // # of directed packets at 5.5MB
- IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB
- IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB
-
- IPW_ORD_STAT_RX_NODIR_DATA = 71, // # of nondirected packets
- IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB
- IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB
- IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB
- IPW_ORD_STAT_RX_NODIR_DATA11, // # of nondirected packets at 11MB
-
- IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's
- IPW_ORD_STAT_RX_POLL, //NS // # of poll rx
- IPW_ORD_STAT_RX_RTS, // # of Rx RTS
- IPW_ORD_STAT_RX_CTS, // # of Rx CTS
- IPW_ORD_STAT_RX_ACK, // # of Rx ACK
- IPW_ORD_STAT_RX_CFEND, // # of Rx CF End
- IPW_ORD_STAT_RX_CFEND_ACK, // # of Rx CF End + CF Ack
- IPW_ORD_STAT_RX_ASSN, // # of Association Rx's
- IPW_ORD_STAT_RX_ASSN_RESP, // # of Association response Rx's
- IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's
- IPW_ORD_STAT_RX_REASSN_RESP, // # of Reassociation response Rx's
- IPW_ORD_STAT_RX_PROBE, // # of probe Rx's
- IPW_ORD_STAT_RX_PROBE_RESP, // # of probe response Rx's
- IPW_ORD_STAT_RX_BEACON, // # of Rx beacon
- IPW_ORD_STAT_RX_ATIM, // # of Rx ATIM
- IPW_ORD_STAT_RX_DISASSN, // # of disassociation Rx
- IPW_ORD_STAT_RX_AUTH, // # of authentication Rx
- IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx
-
- IPW_ORD_STAT_RX_TOTAL_BYTES = 101, // Total rx data bytes received
- IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error
- IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB
- IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB
- IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB
- IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB
-
- IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
- IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB
- IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB
- IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB
- IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
-
- IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db
- IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db
- IPW_ORD_PERS_DB_ADDR, // # address of fw permanent db
- IPW_ORD_STAT_RX_INVALID_PROTOCOL, // # of rx frames with invalid protocol
- IPW_ORD_SYS_BOOT_TIME, // # Boot time
- IPW_ORD_STAT_RX_NO_BUFFER, // # of rx frames rejected due to no buffer
- IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late
- IPW_ORD_STAT_RX_ABORT_AT_HOP, //NS // # of rx frames aborted due to hop
- IPW_ORD_STAT_RX_MISSING_FRAG, // # of rx frames dropped due to missing fragment
- IPW_ORD_STAT_RX_ORPHAN_FRAG, // # of rx frames dropped due to non-sequential fragment
- IPW_ORD_STAT_RX_ORPHAN_FRAME, // # of rx frames dropped due to unmatched 1st frame
- IPW_ORD_STAT_RX_FRAG_AGEOUT, // # of rx frames dropped due to uncompleted frame
- IPW_ORD_STAT_RX_BAD_SSID, //NS // Bad SSID (unused)
- IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption
-
-// PSP Statistics
- IPW_ORD_STAT_PSP_SUSPENSION = 137, // # of times adapter suspended
- IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout
- IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts
- IPW_ORD_STAT_PSP_NONDIR_TIMEOUT, // # of timeouts waiting for last broadcast/muticast pkt
- IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received
- IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received
- IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID
-
-// Association and roaming
- IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association
- IPW_ORD_STAT_PERCENT_MISSED_BCNS, // current calculation of % missed beacons
- IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries
- IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated
- // AP table entry. set to 0 if not associated
- IPW_ORD_AVAILABLE_AP_CNT, // # of AP's described in the AP table
- IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs
- IPW_ORD_STAT_AP_ASSNS, // # of associations
- IPW_ORD_STAT_ASSN_FAIL, // # of association failures
- IPW_ORD_STAT_ASSN_RESP_FAIL, // # of failuresdue to response fail
- IPW_ORD_STAT_FULL_SCANS, // # of full scans
-
- IPW_ORD_CARD_DISABLED, // # Card Disabled
- IPW_ORD_STAT_ROAM_INHIBIT, // # of times roaming was inhibited due to ongoing activity
- IPW_FILLER_40,
- IPW_ORD_RSSI_AT_ASSN = 160, // RSSI of associated AP at time of association
- IPW_ORD_STAT_ASSN_CAUSE1, // # of reassociations due to no tx from AP in last N
- // hops or no prob_ responses in last 3 minutes
- IPW_ORD_STAT_ASSN_CAUSE2, // # of reassociations due to poor tx/rx quality
- IPW_ORD_STAT_ASSN_CAUSE3, // # of reassociations due to tx/rx quality with excessive
- // load at the AP
- IPW_ORD_STAT_ASSN_CAUSE4, // # of reassociations due to AP RSSI level fell below
- // eligible group
- IPW_ORD_STAT_ASSN_CAUSE5, // # of reassociations due to load leveling
- IPW_ORD_STAT_ASSN_CAUSE6, //NS // # of reassociations due to dropped by Ap
- IPW_FILLER_41,
- IPW_FILLER_42,
- IPW_FILLER_43,
- IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed
- IPW_ORD_STAT_AUTH_RESP_FAIL, // # of times authentication response failed
- IPW_ORD_STATION_TABLE_CNT, // # of entries in association table
-
-// Other statistics
- IPW_ORD_RSSI_AVG_CURR = 173, // Current avg RSSI
- IPW_ORD_STEST_RESULTS_CURR, //NS // Current self test results word
- IPW_ORD_STEST_RESULTS_CUM, //NS // Cummulative self test results word
- IPW_ORD_SELF_TEST_STATUS, //NS //
- IPW_ORD_POWER_MGMT_MODE, // Power mode - 0=CAM, 1=PSP
- IPW_ORD_POWER_MGMT_INDEX, //NS //
- IPW_ORD_COUNTRY_CODE, // IEEE country code as recv'd from beacon
- IPW_ORD_COUNTRY_CHANNELS, // channels supported by country
-// IPW_ORD_COUNTRY_CHANNELS:
-// For 11b the lower 2-byte are used for channels from 1-14
-// and the higher 2-byte are not used.
- IPW_ORD_RESET_CNT, // # of adapter resets (warm)
- IPW_ORD_BEACON_INTERVAL, // Beacon interval
-
- IPW_ORD_PRINCETON_VERSION = 184, //NS // Princeton Version
- IPW_ORD_ANTENNA_DIVERSITY, // TRUE if antenna diversity is disabled
- IPW_ORD_CCA_RSSI, //NS // CCA RSSI value (factory programmed)
- IPW_ORD_STAT_EEPROM_UPDATE, //NS // # of times config EEPROM updated
- IPW_ORD_DTIM_PERIOD, // # of beacon intervals between DTIMs
- IPW_ORD_OUR_FREQ, // current radio freq lower digits - channel ID
-
- IPW_ORD_RTC_TIME = 190, // current RTC time
- IPW_ORD_PORT_TYPE, // operating mode
- IPW_ORD_CURRENT_TX_RATE, // current tx rate
- IPW_ORD_SUPPORTED_RATES, // Bitmap of supported tx rates
- IPW_ORD_ATIM_WINDOW, // current ATIM Window
- IPW_ORD_BASIC_RATES, // bitmap of basic tx rates
- IPW_ORD_NIC_HIGHEST_RATE, // bitmap of basic tx rates
- IPW_ORD_AP_HIGHEST_RATE, // bitmap of basic tx rates
- IPW_ORD_CAPABILITIES, // Management frame capability field
- IPW_ORD_AUTH_TYPE, // Type of authentication
- IPW_ORD_RADIO_TYPE, // Adapter card platform type
- IPW_ORD_RTS_THRESHOLD = 201, // Min length of packet after which RTS handshaking is used
- IPW_ORD_INT_MODE, // International mode
- IPW_ORD_FRAGMENTATION_THRESHOLD, // protocol frag threshold
- IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, // EEPROM offset in SRAM
- IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE, // EEPROM size in SRAM
- IPW_ORD_EEPROM_SKU_CAPABILITY, // EEPROM SKU Capability 206 =
- IPW_ORD_EEPROM_IBSS_11B_CHANNELS, // EEPROM IBSS 11b channel set
-
- IPW_ORD_MAC_VERSION = 209, // MAC Version
- IPW_ORD_MAC_REVISION, // MAC Revision
- IPW_ORD_RADIO_VERSION, // Radio Version
- IPW_ORD_NIC_MANF_DATE_TIME, // MANF Date/Time STAMP
- IPW_ORD_UCODE_VERSION, // Ucode Version
- IPW_ORD_HW_RF_SWITCH_STATE = 214, // HW RF Kill Switch State
-} ORDINALTABLE1;
-
-// ordinal table 2
-// Variable length data:
-#define IPW_FIRST_VARIABLE_LENGTH_ORDINAL 1001
-
-typedef enum _ORDINAL_TABLE_2 { // NS - means Not Supported by FW
- IPW_ORD_STAT_BASE = 1000, // contains number of variable ORDs
- IPW_ORD_STAT_ADAPTER_MAC = 1001, // 6 bytes: our adapter MAC address
- IPW_ORD_STAT_PREFERRED_BSSID = 1002, // 6 bytes: BSSID of the preferred AP
- IPW_ORD_STAT_MANDATORY_BSSID = 1003, // 6 bytes: BSSID of the mandatory AP
- IPW_FILL_1, //NS //
- IPW_ORD_STAT_COUNTRY_TEXT = 1005, // 36 bytes: Country name text, First two bytes are Country code
- IPW_ORD_STAT_ASSN_SSID = 1006, // 32 bytes: ESSID String
- IPW_ORD_STATION_TABLE = 1007, // ? bytes: Station/AP table (via Direct SSID Scans)
- IPW_ORD_STAT_SWEEP_TABLE = 1008, // ? bytes: Sweep/Host Table table (via Broadcast Scans)
- IPW_ORD_STAT_ROAM_LOG = 1009, // ? bytes: Roaming log
- IPW_ORD_STAT_RATE_LOG = 1010, //NS // 0 bytes: Rate log
- IPW_ORD_STAT_FIFO = 1011, //NS // 0 bytes: Fifo buffer data structures
- IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011")
- IPW_ORD_STAT_FW_DATE = 1013, // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002")
- IPW_ORD_STAT_ASSN_AP_BSSID = 1014, // 6 bytes: MAC address of associated AP
- IPW_ORD_STAT_DEBUG = 1015, //NS // ? bytes:
- IPW_ORD_STAT_NIC_BPA_NUM = 1016, // 11 bytes: NIC BPA number in ASCII
- IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date
- IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018,
-} ORDINALTABLE2; // NS - means Not Supported by FW
-
-#define IPW_LAST_VARIABLE_LENGTH_ORDINAL 1018
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY // enable iwspy support
-#endif
-
-#define IPW_HOST_FW_SHARED_AREA0 0x0002f200
-#define IPW_HOST_FW_SHARED_AREA0_END 0x0002f510 // 0x310 bytes
-
-#define IPW_HOST_FW_SHARED_AREA1 0x0002f610
-#define IPW_HOST_FW_SHARED_AREA1_END 0x0002f630 // 0x20 bytes
-
-#define IPW_HOST_FW_SHARED_AREA2 0x0002fa00
-#define IPW_HOST_FW_SHARED_AREA2_END 0x0002fa20 // 0x20 bytes
-
-#define IPW_HOST_FW_SHARED_AREA3 0x0002fc00
-#define IPW_HOST_FW_SHARED_AREA3_END 0x0002fc10 // 0x10 bytes
-
-#define IPW_HOST_FW_INTERRUPT_AREA 0x0002ff80
-#define IPW_HOST_FW_INTERRUPT_AREA_END 0x00030000 // 0x80 bytes
-
-struct ipw2100_fw_chunk {
- unsigned char *buf;
- long len;
- long pos;
- struct list_head list;
-};
-
-struct ipw2100_fw_chunk_set {
- const void *data;
- unsigned long size;
-};
-
-struct ipw2100_fw {
- int version;
- struct ipw2100_fw_chunk_set fw;
- struct ipw2100_fw_chunk_set uc;
- const struct firmware *fw_entry;
-};
-
-#define MAX_FW_VERSION_LEN 14
-
-#endif /* _IPW2100_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
deleted file mode 100644
index 820100cac4915..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ /dev/null
@@ -1,11965 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
- 802.11 status code portion of this file from ethereal-0.10.6:
- Copyright 2000, Axis Communications AB
- Ethereal - Network traffic analyzer
- By Gerald Combs <[email protected]>
- Copyright 1998 Gerald Combs
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <net/cfg80211-wext.h>
-#include "ipw2200.h"
-#include "ipw.h"
-
-
-#ifndef KBUILD_EXTMOD
-#define VK "k"
-#else
-#define VK
-#endif
-
-#ifdef CONFIG_IPW2200_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#ifdef CONFIG_IPW2200_MONITOR
-#define VM "m"
-#else
-#define VM
-#endif
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-#define VP "p"
-#else
-#define VP
-#endif
-
-#ifdef CONFIG_IPW2200_RADIOTAP
-#define VR "r"
-#else
-#define VR
-#endif
-
-#ifdef CONFIG_IPW2200_QOS
-#define VQ "q"
-#else
-#define VQ
-#endif
-
-#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ
-#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-#define DRV_VERSION IPW2200_VERSION
-
-#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1)
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("ipw2200-ibss.fw");
-#ifdef CONFIG_IPW2200_MONITOR
-MODULE_FIRMWARE("ipw2200-sniffer.fw");
-#endif
-MODULE_FIRMWARE("ipw2200-bss.fw");
-
-static int cmdlog = 0;
-static int debug = 0;
-static int default_channel = 0;
-static int network_mode = 0;
-
-static u32 ipw_debug_level;
-static int associate;
-static int auto_create = 1;
-static int led_support = 1;
-static int disable = 0;
-static int bt_coexist = 0;
-static int hwcrypto = 0;
-static int roaming = 1;
-static const char ipw_modes[] = {
- 'a', 'b', 'g', '?'
-};
-static int antenna = CFG_SYS_ANTENNA_BOTH;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */
-#endif
-
-static struct ieee80211_rate ipw2200_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 }
-};
-
-#define ipw2200_a_rates (ipw2200_rates + 4)
-#define ipw2200_num_a_rates 8
-#define ipw2200_bg_rates (ipw2200_rates + 0)
-#define ipw2200_num_bg_rates 12
-
-/* Ugly macro to convert literal channel numbers into their mhz equivalents
- * There are certianly some conditions that will break this (like feeding it '30')
- * but they shouldn't arise since nothing talks on channel 30. */
-#define ieee80211chan2mhz(x) \
- (((x) <= 14) ? \
- (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
- ((x) + 1000) * 5)
-
-#ifdef CONFIG_IPW2200_QOS
-static int qos_enable = 0;
-static int qos_burst_enable = 0;
-static int qos_no_ack_mask = 0;
-static int burst_duration_CCK = 0;
-static int burst_duration_OFDM = 0;
-
-static struct libipw_qos_parameters def_qos_parameters_OFDM = {
- {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM,
- QOS_TX3_CW_MIN_OFDM},
- {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM,
- QOS_TX3_CW_MAX_OFDM},
- {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
- {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
- {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM,
- QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM}
-};
-
-static struct libipw_qos_parameters def_qos_parameters_CCK = {
- {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK,
- QOS_TX3_CW_MIN_CCK},
- {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK,
- QOS_TX3_CW_MAX_CCK},
- {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
- {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
- {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK,
- QOS_TX3_TXOP_LIMIT_CCK}
-};
-
-static struct libipw_qos_parameters def_parameters_OFDM = {
- {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM,
- DEF_TX3_CW_MIN_OFDM},
- {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM,
- DEF_TX3_CW_MAX_OFDM},
- {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
- {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
- {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM,
- DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM}
-};
-
-static struct libipw_qos_parameters def_parameters_CCK = {
- {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK,
- DEF_TX3_CW_MIN_CCK},
- {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK,
- DEF_TX3_CW_MAX_CCK},
- {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
- {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
- {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK,
- DEF_TX3_TXOP_LIMIT_CCK}
-};
-
-static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
-
-static int from_priority_to_tx_queue[] = {
- IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1,
- IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4
-};
-
-static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv);
-
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
- *qos_param);
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
- *qos_param);
-#endif /* CONFIG_IPW2200_QOS */
-
-static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev);
-static void ipw_remove_current_network(struct ipw_priv *priv);
-static void ipw_rx(struct ipw_priv *priv);
-static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
- struct clx2_tx_queue *txq, int qindex);
-static int ipw_queue_reset(struct ipw_priv *priv);
-
-static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, const void *buf,
- int len, int sync);
-
-static void ipw_tx_queue_free(struct ipw_priv *);
-
-static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);
-static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
-static void ipw_rx_queue_replenish(void *);
-static int ipw_up(struct ipw_priv *);
-static void ipw_bg_up(struct work_struct *work);
-static void ipw_down(struct ipw_priv *);
-static void ipw_bg_down(struct work_struct *work);
-static int ipw_config(struct ipw_priv *);
-static int init_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *prates);
-static void ipw_set_hwcrypto_keys(struct ipw_priv *);
-static void ipw_send_wep_keys(struct ipw_priv *, int);
-
-static int snprint_line(char *buf, size_t count,
- const u8 * data, u32 len, u32 ofs)
-{
- int out, i, j, l;
- char c;
-
- out = scnprintf(buf, count, "%08X", ofs);
-
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++)
- out += scnprintf(buf + out, count - out, "%02X ",
- data[(i * 8 + j)]);
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- out += scnprintf(buf + out, count - out, " ");
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++) {
- c = data[(i * 8 + j)];
- if (!isascii(c) || !isprint(c))
- c = '.';
-
- out += scnprintf(buf + out, count - out, "%c", c);
- }
-
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- return out;
-}
-
-static void printk_buf(int level, const u8 * data, u32 len)
-{
- char line[81];
- u32 ofs = 0;
- if (!(ipw_debug_level & level))
- return;
-
- while (len) {
- snprint_line(line, sizeof(line), &data[ofs],
- min(len, 16U), ofs);
- printk(KERN_DEBUG "%s\n", line);
- ofs += 16;
- len -= min(len, 16U);
- }
-}
-
-static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len)
-{
- size_t out = size;
- u32 ofs = 0;
- int total = 0;
-
- while (size && len) {
- out = snprint_line(output, size, &data[ofs],
- min_t(size_t, len, 16U), ofs);
-
- ofs += 16;
- output += out;
- size -= out;
- len -= min_t(size_t, len, 16U);
- total += out;
- }
- return total;
-}
-
-/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
-static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
-#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
-
-/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
-static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg);
-#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b)
-
-/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value);
-static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg8(a, b, c);
-}
-
-/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value);
-static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg16(a, b, c);
-}
-
-/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value);
-static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg32(a, b, c);
-}
-
-/* 8-bit direct write (low 4K) */
-static inline void _ipw_write8(struct ipw_priv *ipw, unsigned long ofs,
- u8 val)
-{
- writeb(val, ipw->hw_base + ofs);
-}
-
-/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write8(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write8(ipw, ofs, val); \
-} while (0)
-
-/* 16-bit direct write (low 4K) */
-static inline void _ipw_write16(struct ipw_priv *ipw, unsigned long ofs,
- u16 val)
-{
- writew(val, ipw->hw_base + ofs);
-}
-
-/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write16(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write16(ipw, ofs, val); \
-} while (0)
-
-/* 32-bit direct write (low 4K) */
-static inline void _ipw_write32(struct ipw_priv *ipw, unsigned long ofs,
- u32 val)
-{
- writel(val, ipw->hw_base + ofs);
-}
-
-/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write32(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write32(ipw, ofs, val); \
-} while (0)
-
-/* 8-bit direct read (low 4K) */
-static inline u8 _ipw_read8(struct ipw_priv *ipw, unsigned long ofs)
-{
- return readb(ipw->hw_base + ofs);
-}
-
-/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read8(ipw, ofs) ({ \
- IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", __FILE__, __LINE__, \
- (u32)(ofs)); \
- _ipw_read8(ipw, ofs); \
-})
-
-/* 32-bit direct read (low 4K) */
-static inline u32 _ipw_read32(struct ipw_priv *ipw, unsigned long ofs)
-{
- return readl(ipw->hw_base + ofs);
-}
-
-/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read32(ipw, ofs) ({ \
- IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", __FILE__, __LINE__, \
- (u32)(ofs)); \
- _ipw_read32(ipw, ofs); \
-})
-
-static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
-/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
-#define ipw_read_indirect(a, b, c, d) ({ \
- IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %u bytes\n", __FILE__, \
- __LINE__, (u32)(b), (u32)(d)); \
- _ipw_read_indirect(a, b, c, d); \
-})
-
-/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
-static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
- int num);
-#define ipw_write_indirect(a, b, c, d) do { \
- IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %u bytes\n", __FILE__, \
- __LINE__, (u32)(b), (u32)(d)); \
- _ipw_write_indirect(a, b, c, d); \
-} while (0)
-
-/* 32-bit indirect write (above 4K) */
-static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
-{
- IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
- _ipw_write32(priv, IPW_INDIRECT_DATA, value);
-}
-
-/* 8-bit indirect write (above 4K) */
-static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
-{
- u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = reg - aligned_addr;
-
- IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value);
-}
-
-/* 16-bit indirect write (above 4K) */
-static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
-{
- u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = (reg - aligned_addr) & (~0x1ul);
-
- IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value);
-}
-
-/* 8-bit indirect read (above 4K) */
-static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
-{
- u32 word;
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
- IPW_DEBUG_IO(" reg = 0x%8X :\n", reg);
- word = _ipw_read32(priv, IPW_INDIRECT_DATA);
- return (word >> ((reg & 0x3) * 8)) & 0xff;
-}
-
-/* 32-bit indirect read (above 4K) */
-static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
-{
- u32 value;
-
- IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg);
-
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
- value = _ipw_read32(priv, IPW_INDIRECT_DATA);
- IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x\n", reg, value);
- return value;
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) read, */
-/* for area above 1st 4K of SRAM/reg space */
-static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
- int num)
-{
- u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = addr - aligned_addr;
- u32 i;
-
- IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
-
- if (num <= 0) {
- return;
- }
-
- /* Read the first dword (or portion) byte by byte */
- if (unlikely(dif_len)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- /* Start reading at aligned_addr + dif_len */
- for (i = dif_len; ((i < 4) && (num > 0)); i++, num--)
- *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i);
- aligned_addr += 4;
- }
-
- /* Read all of the middle dwords as dwords, with auto-increment */
- _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
- for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
- *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA);
-
- /* Read the last dword (or portion) byte by byte */
- if (unlikely(num)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- for (i = 0; num > 0; i++, num--)
- *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i);
- }
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) write, */
-/* for area above 1st 4K of SRAM/reg space */
-static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
- int num)
-{
- u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = addr - aligned_addr;
- u32 i;
-
- IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
-
- if (num <= 0) {
- return;
- }
-
- /* Write the first dword (or portion) byte by byte */
- if (unlikely(dif_len)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- /* Start writing at aligned_addr + dif_len */
- for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++)
- _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
- aligned_addr += 4;
- }
-
- /* Write all of the middle dwords as dwords, with auto-increment */
- _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
- for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
- _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf);
-
- /* Write the last dword (or portion) byte by byte */
- if (unlikely(num)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- for (i = 0; num > 0; i++, num--, buf++)
- _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
- }
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) write, */
-/* for 1st 4K of SRAM/regs space */
-static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
- int num)
-{
- memcpy_toio((priv->hw_base + addr), buf, num);
-}
-
-/* Set bit(s) in low 4K of SRAM/regs */
-static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask)
-{
- ipw_write32(priv, reg, ipw_read32(priv, reg) | mask);
-}
-
-/* Clear bit(s) in low 4K of SRAM/regs */
-static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
-{
- ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
-}
-
-static inline void __ipw_enable_interrupts(struct ipw_priv *priv)
-{
- if (priv->status & STATUS_INT_ENABLED)
- return;
- priv->status |= STATUS_INT_ENABLED;
- ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
-}
-
-static inline void __ipw_disable_interrupts(struct ipw_priv *priv)
-{
- if (!(priv->status & STATUS_INT_ENABLED))
- return;
- priv->status &= ~STATUS_INT_ENABLED;
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
-}
-
-static inline void ipw_enable_interrupts(struct ipw_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- __ipw_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void ipw_disable_interrupts(struct ipw_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- __ipw_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static char *ipw_error_desc(u32 val)
-{
- switch (val) {
- case IPW_FW_ERROR_OK:
- return "ERROR_OK";
- case IPW_FW_ERROR_FAIL:
- return "ERROR_FAIL";
- case IPW_FW_ERROR_MEMORY_UNDERFLOW:
- return "MEMORY_UNDERFLOW";
- case IPW_FW_ERROR_MEMORY_OVERFLOW:
- return "MEMORY_OVERFLOW";
- case IPW_FW_ERROR_BAD_PARAM:
- return "BAD_PARAM";
- case IPW_FW_ERROR_BAD_CHECKSUM:
- return "BAD_CHECKSUM";
- case IPW_FW_ERROR_NMI_INTERRUPT:
- return "NMI_INTERRUPT";
- case IPW_FW_ERROR_BAD_DATABASE:
- return "BAD_DATABASE";
- case IPW_FW_ERROR_ALLOC_FAIL:
- return "ALLOC_FAIL";
- case IPW_FW_ERROR_DMA_UNDERRUN:
- return "DMA_UNDERRUN";
- case IPW_FW_ERROR_DMA_STATUS:
- return "DMA_STATUS";
- case IPW_FW_ERROR_DINO_ERROR:
- return "DINO_ERROR";
- case IPW_FW_ERROR_EEPROM_ERROR:
- return "EEPROM_ERROR";
- case IPW_FW_ERROR_SYSASSERT:
- return "SYSASSERT";
- case IPW_FW_ERROR_FATAL_ERROR:
- return "FATAL_ERROR";
- default:
- return "UNKNOWN_ERROR";
- }
-}
-
-static void ipw_dump_error_log(struct ipw_priv *priv,
- struct ipw_fw_error *error)
-{
- u32 i;
-
- if (!error) {
- IPW_ERROR("Error allocating and capturing error log. "
- "Nothing to dump.\n");
- return;
- }
-
- IPW_ERROR("Start IPW Error Log Dump:\n");
- IPW_ERROR("Status: 0x%08X, Config: %08X\n",
- error->status, error->config);
-
- for (i = 0; i < error->elem_len; i++)
- IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
- ipw_error_desc(error->elem[i].desc),
- error->elem[i].time,
- error->elem[i].blink1,
- error->elem[i].blink2,
- error->elem[i].link1,
- error->elem[i].link2, error->elem[i].data);
- for (i = 0; i < error->log_len; i++)
- IPW_ERROR("%i\t0x%08x\t%i\n",
- error->log[i].time,
- error->log[i].data, error->log[i].event);
-}
-
-static inline int ipw_is_init(struct ipw_priv *priv)
-{
- return (priv->status & STATUS_INIT) ? 1 : 0;
-}
-
-static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
-{
- u32 addr, field_info, field_len, field_count, total_len;
-
- IPW_DEBUG_ORD("ordinal = %i\n", ord);
-
- if (!priv || !val || !len) {
- IPW_DEBUG_ORD("Invalid argument\n");
- return -EINVAL;
- }
-
- /* verify device ordinal tables have been initialized */
- if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) {
- IPW_DEBUG_ORD("Access ordinals before initialization\n");
- return -EINVAL;
- }
-
- switch (IPW_ORD_TABLE_ID_MASK & ord) {
- case IPW_ORD_TABLE_0_MASK:
- /*
- * TABLE 0: Direct access to a table of 32 bit values
- *
- * This is a very simple table with the data directly
- * read from the table
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table0_len) {
- IPW_DEBUG_ORD("ordinal value (%i) longer then "
- "max (%i)\n", ord, priv->table0_len);
- return -EINVAL;
- }
-
- /* verify we have enough room to store the value */
- if (*len < sizeof(u32)) {
- IPW_DEBUG_ORD("ordinal buffer length too small, "
- "need %zd\n", sizeof(u32));
- return -EINVAL;
- }
-
- IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n",
- ord, priv->table0_addr + (ord << 2));
-
- *len = sizeof(u32);
- ord <<= 2;
- *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord);
- break;
-
- case IPW_ORD_TABLE_1_MASK:
- /*
- * TABLE 1: Indirect access to a table of 32 bit values
- *
- * This is a fairly large table of u32 values each
- * representing starting addr for the data (which is
- * also a u32)
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table1_len) {
- IPW_DEBUG_ORD("ordinal value too long\n");
- return -EINVAL;
- }
-
- /* verify we have enough room to store the value */
- if (*len < sizeof(u32)) {
- IPW_DEBUG_ORD("ordinal buffer length too small, "
- "need %zd\n", sizeof(u32));
- return -EINVAL;
- }
-
- *((u32 *) val) =
- ipw_read_reg32(priv, (priv->table1_addr + (ord << 2)));
- *len = sizeof(u32);
- break;
-
- case IPW_ORD_TABLE_2_MASK:
- /*
- * TABLE 2: Indirect access to a table of variable sized values
- *
- * This table consist of six values, each containing
- * - dword containing the starting offset of the data
- * - dword containing the lengh in the first 16bits
- * and the count in the second 16bits
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table2_len) {
- IPW_DEBUG_ORD("ordinal value too long\n");
- return -EINVAL;
- }
-
- /* get the address of statistic */
- addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3));
-
- /* get the second DW of statistics ;
- * two 16-bit words - first is length, second is count */
- field_info =
- ipw_read_reg32(priv,
- priv->table2_addr + (ord << 3) +
- sizeof(u32));
-
- /* get each entry length */
- field_len = *((u16 *) & field_info);
-
- /* get number of entries */
- field_count = *(((u16 *) & field_info) + 1);
-
- /* abort if not enough memory */
- total_len = field_len * field_count;
- if (total_len > *len) {
- *len = total_len;
- return -EINVAL;
- }
-
- *len = total_len;
- if (!total_len)
- return 0;
-
- IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, "
- "field_info = 0x%08x\n",
- addr, total_len, field_info);
- ipw_read_indirect(priv, addr, val, total_len);
- break;
-
- default:
- IPW_DEBUG_ORD("Invalid ordinal!\n");
- return -EINVAL;
-
- }
-
- return 0;
-}
-
-static void ipw_init_ordinals(struct ipw_priv *priv)
-{
- priv->table0_addr = IPW_ORDINALS_TABLE_LOWER;
- priv->table0_len = ipw_read32(priv, priv->table0_addr);
-
- IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n",
- priv->table0_addr, priv->table0_len);
-
- priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1);
- priv->table1_len = ipw_read_reg32(priv, priv->table1_addr);
-
- IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n",
- priv->table1_addr, priv->table1_len);
-
- priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2);
- priv->table2_len = ipw_read_reg32(priv, priv->table2_addr);
- priv->table2_len &= 0x0000ffff; /* use first two bytes */
-
- IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n",
- priv->table2_addr, priv->table2_len);
-
-}
-
-static u32 ipw_register_toggle(u32 reg)
-{
- reg &= ~IPW_START_STANDBY;
- if (reg & IPW_GATE_ODMA)
- reg &= ~IPW_GATE_ODMA;
- if (reg & IPW_GATE_IDMA)
- reg &= ~IPW_GATE_IDMA;
- if (reg & IPW_GATE_ADMA)
- reg &= ~IPW_GATE_ADMA;
- return reg;
-}
-
-/*
- * LED behavior:
- * - On radio ON, turn on any LEDs that require to be on during start
- * - On initialization, start unassociated blink
- * - On association, disable unassociated blink
- * - On disassociation, start unassociated blink
- * - On radio OFF, turn off any LEDs started during radio on
- *
- */
-#define LD_TIME_LINK_ON msecs_to_jiffies(300)
-#define LD_TIME_LINK_OFF msecs_to_jiffies(2700)
-#define LD_TIME_ACT_ON msecs_to_jiffies(250)
-
-static void ipw_led_link_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* If configured to not use LEDs, or nic_type is 1,
- * then we don't toggle a LINK led */
- if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (!(priv->status & STATUS_RF_KILL_MASK) &&
- !(priv->status & STATUS_LED_LINK_ON)) {
- IPW_DEBUG_LED("Link LED On\n");
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led |= priv->led_association_on;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- priv->status |= STATUS_LED_LINK_ON;
-
- /* If we aren't associated, schedule turning the LED off */
- if (!(priv->status & STATUS_ASSOCIATED))
- schedule_delayed_work(&priv->led_link_off,
- LD_TIME_LINK_ON);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_link_on(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_link_on.work);
- mutex_lock(&priv->mutex);
- ipw_led_link_on(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_led_link_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* If configured not to use LEDs, or nic type is 1,
- * then we don't goggle the LINK led. */
- if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->status & STATUS_LED_LINK_ON) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_association_off;
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Link LED Off\n");
-
- priv->status &= ~STATUS_LED_LINK_ON;
-
- /* If we aren't associated and the radio is on, schedule
- * turning the LED on (blink while unassociated) */
- if (!(priv->status & STATUS_RF_KILL_MASK) &&
- !(priv->status & STATUS_ASSOCIATED))
- schedule_delayed_work(&priv->led_link_on,
- LD_TIME_LINK_OFF);
-
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_link_off(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_link_off.work);
- mutex_lock(&priv->mutex);
- ipw_led_link_off(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void __ipw_led_activity_on(struct ipw_priv *priv)
-{
- u32 led;
-
- if (priv->config & CFG_NO_LED)
- return;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return;
-
- if (!(priv->status & STATUS_LED_ACT_ON)) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led |= priv->led_activity_on;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Activity LED On\n");
-
- priv->status |= STATUS_LED_ACT_ON;
-
- cancel_delayed_work(&priv->led_act_off);
- schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
- } else {
- /* Reschedule LED off for full time period */
- cancel_delayed_work(&priv->led_act_off);
- schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
- }
-}
-
-#if 0
-void ipw_led_activity_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- __ipw_led_activity_on(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-#endif /* 0 */
-
-static void ipw_led_activity_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- if (priv->config & CFG_NO_LED)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->status & STATUS_LED_ACT_ON) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_activity_off;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Activity LED Off\n");
-
- priv->status &= ~STATUS_LED_ACT_ON;
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_activity_off(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_act_off.work);
- mutex_lock(&priv->mutex);
- ipw_led_activity_off(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_led_band_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* Only nic type 1 supports mode LEDs */
- if (priv->config & CFG_NO_LED ||
- priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- if (priv->assoc_network->mode == IEEE_A) {
- led |= priv->led_ofdm_on;
- led &= priv->led_association_off;
- IPW_DEBUG_LED("Mode LED On: 802.11a\n");
- } else if (priv->assoc_network->mode == IEEE_G) {
- led |= priv->led_ofdm_on;
- led |= priv->led_association_on;
- IPW_DEBUG_LED("Mode LED On: 802.11g\n");
- } else {
- led &= priv->led_ofdm_off;
- led |= priv->led_association_on;
- IPW_DEBUG_LED("Mode LED On: 802.11b\n");
- }
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_led_band_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* Only nic type 1 supports mode LEDs */
- if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_ofdm_off;
- led &= priv->led_association_off;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_led_radio_on(struct ipw_priv *priv)
-{
- ipw_led_link_on(priv);
-}
-
-static void ipw_led_radio_off(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
-}
-
-static void ipw_led_link_up(struct ipw_priv *priv)
-{
- /* Set the Link Led on for all nic types */
- ipw_led_link_on(priv);
-}
-
-static void ipw_led_link_down(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
-
- if (priv->status & STATUS_RF_KILL_MASK)
- ipw_led_radio_off(priv);
-}
-
-static void ipw_led_init(struct ipw_priv *priv)
-{
- priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE];
-
- /* Set the default PINs for the link and activity leds */
- priv->led_activity_on = IPW_ACTIVITY_LED;
- priv->led_activity_off = ~(IPW_ACTIVITY_LED);
-
- priv->led_association_on = IPW_ASSOCIATED_LED;
- priv->led_association_off = ~(IPW_ASSOCIATED_LED);
-
- /* Set the default PINs for the OFDM leds */
- priv->led_ofdm_on = IPW_OFDM_LED;
- priv->led_ofdm_off = ~(IPW_OFDM_LED);
-
- switch (priv->nic_type) {
- case EEPROM_NIC_TYPE_1:
- /* In this NIC type, the LEDs are reversed.... */
- priv->led_activity_on = IPW_ASSOCIATED_LED;
- priv->led_activity_off = ~(IPW_ASSOCIATED_LED);
- priv->led_association_on = IPW_ACTIVITY_LED;
- priv->led_association_off = ~(IPW_ACTIVITY_LED);
-
- if (!(priv->config & CFG_NO_LED))
- ipw_led_band_on(priv);
-
- /* And we don't blink link LEDs for this nic, so
- * just return here */
- return;
-
- case EEPROM_NIC_TYPE_3:
- case EEPROM_NIC_TYPE_2:
- case EEPROM_NIC_TYPE_4:
- case EEPROM_NIC_TYPE_0:
- break;
-
- default:
- IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n",
- priv->nic_type);
- priv->nic_type = EEPROM_NIC_TYPE_0;
- break;
- }
-
- if (!(priv->config & CFG_NO_LED)) {
- if (priv->status & STATUS_ASSOCIATED)
- ipw_led_link_on(priv);
- else
- ipw_led_link_off(priv);
- }
-}
-
-static void ipw_led_shutdown(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
- ipw_led_band_off(priv);
- cancel_delayed_work(&priv->led_link_on);
- cancel_delayed_work(&priv->led_link_off);
- cancel_delayed_work(&priv->led_act_off);
-}
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
- * used for controlling the debug level.
- *
- * See the level definitions in ipw for details.
- */
-static ssize_t debug_level_show(struct device_driver *d, char *buf)
-{
- return sprintf(buf, "0x%08X\n", ipw_debug_level);
-}
-
-static ssize_t debug_level_store(struct device_driver *d, const char *buf,
- size_t count)
-{
- unsigned long val;
-
- int result = kstrtoul(buf, 0, &val);
-
- if (result == -EINVAL)
- printk(KERN_INFO DRV_NAME
- ": %s is not in hex or decimal form.\n", buf);
- else if (result == -ERANGE)
- printk(KERN_INFO DRV_NAME
- ": %s has overflowed.\n", buf);
- else
- ipw_debug_level = val;
-
- return count;
-}
-static DRIVER_ATTR_RW(debug_level);
-
-static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
-{
- /* length = 1st dword in log */
- return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG));
-}
-
-static void ipw_capture_event_log(struct ipw_priv *priv,
- u32 log_len, struct ipw_event *log)
-{
- u32 base;
-
- if (log_len) {
- base = ipw_read32(priv, IPW_EVENT_LOG);
- ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32),
- (u8 *) log, sizeof(*log) * log_len);
- }
-}
-
-static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
-{
- struct ipw_fw_error *error;
- u32 log_len = ipw_get_event_log_len(priv);
- u32 base = ipw_read32(priv, IPW_ERROR_LOG);
- u32 elem_len = ipw_read_reg32(priv, base);
-
- error = kmalloc(size_add(struct_size(error, elem, elem_len),
- array_size(sizeof(*error->log), log_len)),
- GFP_ATOMIC);
- if (!error) {
- IPW_ERROR("Memory allocation for firmware error log "
- "failed.\n");
- return NULL;
- }
- error->jiffies = jiffies;
- error->status = priv->status;
- error->config = priv->config;
- error->elem_len = elem_len;
- error->log_len = log_len;
- error->log = (struct ipw_event *)(error->elem + elem_len);
-
- ipw_capture_event_log(priv, log_len, error->log);
-
- if (elem_len)
- ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem,
- sizeof(*error->elem) * elem_len);
-
- return error;
-}
-
-static ssize_t event_log_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 log_len = ipw_get_event_log_len(priv);
- u32 log_size;
- struct ipw_event *log;
- u32 len = 0, i;
-
- /* not using min() because of its strict type checking */
- log_size = PAGE_SIZE / sizeof(*log) > log_len ?
- sizeof(*log) * log_len : PAGE_SIZE;
- log = kzalloc(log_size, GFP_KERNEL);
- if (!log) {
- IPW_ERROR("Unable to allocate memory for log\n");
- return 0;
- }
- log_len = log_size / sizeof(*log);
- ipw_capture_event_log(priv, log_len, log);
-
- len += scnprintf(buf + len, PAGE_SIZE - len, "%08X", log_len);
- for (i = 0; i < log_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X",
- log[i].time, log[i].event, log[i].data);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- kfree(log);
- return len;
-}
-
-static DEVICE_ATTR_RO(event_log);
-
-static ssize_t error_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 len = 0, i;
- if (!priv->error)
- return 0;
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "%08lX%08X%08X%08X",
- priv->error->jiffies,
- priv->error->status,
- priv->error->config, priv->error->elem_len);
- for (i = 0; i < priv->error->elem_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X%08X%08X%08X%08X",
- priv->error->elem[i].time,
- priv->error->elem[i].desc,
- priv->error->elem[i].blink1,
- priv->error->elem[i].blink2,
- priv->error->elem[i].link1,
- priv->error->elem[i].link2,
- priv->error->elem[i].data);
-
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X", priv->error->log_len);
- for (i = 0; i < priv->error->log_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X",
- priv->error->log[i].time,
- priv->error->log[i].event,
- priv->error->log[i].data);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- return len;
-}
-
-static ssize_t error_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- kfree(priv->error);
- priv->error = NULL;
- return count;
-}
-
-static DEVICE_ATTR_RW(error);
-
-static ssize_t cmd_log_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 len = 0, i;
- if (!priv->cmdlog)
- return 0;
- for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
- (i != priv->cmdlog_pos) && (len < PAGE_SIZE);
- i = (i + 1) % priv->cmdlog_len) {
- len +=
- scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies,
- priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd,
- priv->cmdlog[i].cmd.len);
- len +=
- snprintk_buf(buf + len, PAGE_SIZE - len,
- (u8 *) priv->cmdlog[i].cmd.param,
- priv->cmdlog[i].cmd.len);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- }
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- return len;
-}
-
-static DEVICE_ATTR_RO(cmd_log);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static void ipw_prom_free(struct ipw_priv *priv);
-static int ipw_prom_alloc(struct ipw_priv *priv);
-static ssize_t rtap_iface_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int rc = 0;
-
- if (count < 1)
- return -EINVAL;
-
- switch (buf[0]) {
- case '0':
- if (!rtap_iface)
- return count;
-
- if (netif_running(priv->prom_net_dev)) {
- IPW_WARNING("Interface is up. Cannot unregister.\n");
- return count;
- }
-
- ipw_prom_free(priv);
- rtap_iface = 0;
- break;
-
- case '1':
- if (rtap_iface)
- return count;
-
- rc = ipw_prom_alloc(priv);
- if (!rc)
- rtap_iface = 1;
- break;
-
- default:
- return -EINVAL;
- }
-
- if (rc) {
- IPW_ERROR("Failed to register promiscuous network "
- "device (error %d).\n", rc);
- }
-
- return count;
-}
-
-static ssize_t rtap_iface_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- if (rtap_iface)
- return sprintf(buf, "%s", priv->prom_net_dev->name);
- else {
- buf[0] = '-';
- buf[1] = '1';
- buf[2] = '\0';
- return 3;
- }
-}
-
-static DEVICE_ATTR_ADMIN_RW(rtap_iface);
-
-static ssize_t rtap_filter_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (!priv->prom_priv) {
- IPW_ERROR("Attempting to set filter without "
- "rtap_iface enabled.\n");
- return -EPERM;
- }
-
- priv->prom_priv->filter = simple_strtol(buf, NULL, 0);
-
- IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n",
- BIT_ARG16(priv->prom_priv->filter));
-
- return count;
-}
-
-static ssize_t rtap_filter_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "0x%04X",
- priv->prom_priv ? priv->prom_priv->filter : 0);
-}
-
-static DEVICE_ATTR_ADMIN_RW(rtap_filter);
-#endif
-
-static ssize_t scan_age_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", priv->ieee->scan_age);
-}
-
-static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
-
- IPW_DEBUG_INFO("enter\n");
-
- unsigned long val;
- int result = kstrtoul(buf, 0, &val);
-
- if (result == -EINVAL || result == -ERANGE) {
- IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
- } else {
- priv->ieee->scan_age = val;
- IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return count;
-}
-
-static DEVICE_ATTR_RW(scan_age);
-
-static ssize_t led_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1);
-}
-
-static ssize_t led_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- IPW_DEBUG_INFO("enter\n");
-
- if (count == 0)
- return 0;
-
- if (*buf == 0) {
- IPW_DEBUG_LED("Disabling LED control.\n");
- priv->config |= CFG_NO_LED;
- ipw_led_shutdown(priv);
- } else {
- IPW_DEBUG_LED("Enabling LED control.\n");
- priv->config &= ~CFG_NO_LED;
- ipw_led_init(priv);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return count;
-}
-
-static DEVICE_ATTR_RW(led);
-
-static ssize_t status_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->status);
-}
-
-static DEVICE_ATTR_RO(status);
-
-static ssize_t cfg_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->config);
-}
-
-static DEVICE_ATTR_RO(cfg);
-
-static ssize_t nic_type_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "TYPE: %d\n", priv->nic_type);
-}
-
-static DEVICE_ATTR_RO(nic_type);
-
-static ssize_t ucode_version_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 len = sizeof(u32), tmp = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len))
- return 0;
-
- return sprintf(buf, "0x%08x\n", tmp);
-}
-
-static DEVICE_ATTR_RO(ucode_version);
-
-static ssize_t rtc_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- u32 len = sizeof(u32), tmp = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len))
- return 0;
-
- return sprintf(buf, "0x%08x\n", tmp);
-}
-
-static DEVICE_ATTR_RO(rtc);
-
-/*
- * Add a device attribute to view/control the delay between eeprom
- * operations.
- */
-static ssize_t eeprom_delay_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- int n = p->eeprom_delay;
- return sprintf(buf, "%i\n", n);
-}
-static ssize_t eeprom_delay_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- sscanf(buf, "%i", &p->eeprom_delay);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(eeprom_delay);
-
-static ssize_t command_event_reg_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT);
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t command_event_reg_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- u32 reg;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &reg);
- ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(command_event_reg);
-
-static ssize_t mem_gpio_reg_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- reg = ipw_read_reg32(p, 0x301100);
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t mem_gpio_reg_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- u32 reg;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &reg);
- ipw_write_reg32(p, 0x301100, reg);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(mem_gpio_reg);
-
-static ssize_t indirect_dword_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_INDIRECT_DWORD)
- reg = ipw_read_reg32(priv, priv->indirect_dword);
- else
- reg = 0;
-
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t indirect_dword_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->indirect_dword);
- priv->status |= STATUS_INDIRECT_DWORD;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(indirect_dword);
-
-static ssize_t indirect_byte_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u8 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_INDIRECT_BYTE)
- reg = ipw_read_reg8(priv, priv->indirect_byte);
- else
- reg = 0;
-
- return sprintf(buf, "0x%02x\n", reg);
-}
-static ssize_t indirect_byte_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->indirect_byte);
- priv->status |= STATUS_INDIRECT_BYTE;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(indirect_byte);
-
-static ssize_t direct_dword_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_DIRECT_DWORD)
- reg = ipw_read32(priv, priv->direct_dword);
- else
- reg = 0;
-
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t direct_dword_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->direct_dword);
- priv->status |= STATUS_DIRECT_DWORD;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(direct_dword);
-
-static int rf_kill_active(struct ipw_priv *priv)
-{
- if (0 == (ipw_read32(priv, 0x30) & 0x10000)) {
- priv->status |= STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- } else {
- priv->status &= ~STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- }
-
- return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;
-}
-
-static ssize_t rf_kill_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- /* 0 - RF kill not enabled
- 1 - SW based RF kill active (sysfs)
- 2 - HW based RF kill active
- 3 - Both HW and SW baed RF kill active */
- struct ipw_priv *priv = dev_get_drvdata(d);
- int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
- (rf_kill_active(priv) ? 0x2 : 0x0);
- return sprintf(buf, "%i\n", val);
-}
-
-static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
-{
- if ((disable_radio ? 1 : 0) ==
- ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0))
- return 0;
-
- IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
- disable_radio ? "OFF" : "ON");
-
- if (disable_radio) {
- priv->status |= STATUS_RF_KILL_SW;
-
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- schedule_work(&priv->down);
- } else {
- priv->status &= ~STATUS_RF_KILL_SW;
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("Can not turn radio back on - "
- "disabled by HW switch\n");
- /* Make sure the RF_KILL check timer is running */
- cancel_delayed_work(&priv->rf_kill);
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(2 * HZ));
- } else
- schedule_work(&priv->up);
- }
-
- return 1;
-}
-
-static ssize_t rf_kill_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- ipw_radio_kill_sw(priv, buf[0] == '1');
-
- return count;
-}
-
-static DEVICE_ATTR_RW(rf_kill);
-
-static ssize_t speed_scan_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int pos = 0, len = 0;
- if (priv->config & CFG_SPEED_SCAN) {
- while (priv->speed_scan[pos] != 0)
- len += sprintf(&buf[len], "%d ",
- priv->speed_scan[pos++]);
- return len + sprintf(&buf[len], "\n");
- }
-
- return sprintf(buf, "0\n");
-}
-
-static ssize_t speed_scan_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int channel, pos = 0;
- const char *p = buf;
-
- /* list of space separated channels to scan, optionally ending with 0 */
- while ((channel = simple_strtol(p, NULL, 0))) {
- if (pos == MAX_SPEED_SCAN - 1) {
- priv->speed_scan[pos] = 0;
- break;
- }
-
- if (libipw_is_valid_channel(priv->ieee, channel))
- priv->speed_scan[pos++] = channel;
- else
- IPW_WARNING("Skipping invalid channel request: %d\n",
- channel);
- p = strchr(p, ' ');
- if (!p)
- break;
- while (*p == ' ' || *p == '\t')
- p++;
- }
-
- if (pos == 0)
- priv->config &= ~CFG_SPEED_SCAN;
- else {
- priv->speed_scan_pos = 0;
- priv->config |= CFG_SPEED_SCAN;
- }
-
- return count;
-}
-
-static DEVICE_ATTR_RW(speed_scan);
-
-static ssize_t net_stats_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0');
-}
-
-static ssize_t net_stats_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- if (buf[0] == '1')
- priv->config |= CFG_NET_STATS;
- else
- priv->config &= ~CFG_NET_STATS;
-
- return count;
-}
-
-static DEVICE_ATTR_RW(net_stats);
-
-static ssize_t channels_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int len = 0, i;
-
- len = sprintf(&buf[len],
- "Displaying %d channels in 2.4Ghz band "
- "(802.11bg):\n", geo->bg_channels);
-
- for (i = 0; i < geo->bg_channels; i++) {
- len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
- geo->bg[i].channel,
- geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT ?
- " (radar spectrum)" : "",
- ((geo->bg[i].flags & LIBIPW_CH_NO_IBSS) ||
- (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT))
- ? "" : ", IBSS",
- geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
- "passive only" : "active/passive",
- geo->bg[i].flags & LIBIPW_CH_B_ONLY ?
- "B" : "B/G");
- }
-
- len += sprintf(&buf[len],
- "Displaying %d channels in 5.2Ghz band "
- "(802.11a):\n", geo->a_channels);
- for (i = 0; i < geo->a_channels; i++) {
- len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
- geo->a[i].channel,
- geo->a[i].flags & LIBIPW_CH_RADAR_DETECT ?
- " (radar spectrum)" : "",
- ((geo->a[i].flags & LIBIPW_CH_NO_IBSS) ||
- (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT))
- ? "" : ", IBSS",
- geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
- "passive only" : "active/passive");
- }
-
- return len;
-}
-
-static DEVICE_ATTR_ADMIN_RO(channels);
-
-static void notify_wx_assoc_event(struct ipw_priv *priv)
-{
- union iwreq_data wrqu;
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- if (priv->status & STATUS_ASSOCIATED)
- memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- else
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void ipw_irq_tasklet(struct tasklet_struct *t)
-{
- struct ipw_priv *priv = from_tasklet(priv, t, irq_tasklet);
- u32 inta, inta_mask, handled = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
-
- inta = ipw_read32(priv, IPW_INTA_RW);
- inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- IPW_WARNING("TASKLET INTA == 0xFFFFFFFF\n");
- /* Only handle the cached INTA values */
- inta = 0;
- }
- inta &= (IPW_INTA_MASK_ALL & inta_mask);
-
- /* Add any cached INTA values that need to be handled */
- inta |= priv->isr_inta;
-
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* handle all the justifications for the interrupt */
- if (inta & IPW_INTA_BIT_RX_TRANSFER) {
- ipw_rx(priv);
- handled |= IPW_INTA_BIT_RX_TRANSFER;
- }
-
- if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) {
- IPW_DEBUG_HC("Command completed.\n");
- ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1);
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
- handled |= IPW_INTA_BIT_TX_CMD_QUEUE;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_1) {
- IPW_DEBUG_TX("TX_QUEUE_1\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[0], 0);
- handled |= IPW_INTA_BIT_TX_QUEUE_1;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_2) {
- IPW_DEBUG_TX("TX_QUEUE_2\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[1], 1);
- handled |= IPW_INTA_BIT_TX_QUEUE_2;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_3) {
- IPW_DEBUG_TX("TX_QUEUE_3\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[2], 2);
- handled |= IPW_INTA_BIT_TX_QUEUE_3;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_4) {
- IPW_DEBUG_TX("TX_QUEUE_4\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[3], 3);
- handled |= IPW_INTA_BIT_TX_QUEUE_4;
- }
-
- if (inta & IPW_INTA_BIT_STATUS_CHANGE) {
- IPW_WARNING("STATUS_CHANGE\n");
- handled |= IPW_INTA_BIT_STATUS_CHANGE;
- }
-
- if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) {
- IPW_WARNING("TX_PERIOD_EXPIRED\n");
- handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED;
- }
-
- if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
- IPW_WARNING("HOST_CMD_DONE\n");
- handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) {
- IPW_WARNING("FW_INITIALIZATION_DONE\n");
- handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
- IPW_WARNING("PHY_OFF_DONE\n");
- handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
- }
-
- if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
- IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
- priv->status |= STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- wake_up_interruptible(&priv->wait_command_queue);
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- schedule_work(&priv->link_down);
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- handled |= IPW_INTA_BIT_RF_KILL_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FATAL_ERROR) {
- IPW_WARNING("Firmware error detected. Restarting.\n");
- if (priv->error) {
- IPW_DEBUG_FW("Sysfs 'error' log already exists.\n");
- if (ipw_debug_level & IPW_DL_FW_ERRORS) {
- struct ipw_fw_error *error =
- ipw_alloc_error_log(priv);
- ipw_dump_error_log(priv, error);
- kfree(error);
- }
- } else {
- priv->error = ipw_alloc_error_log(priv);
- if (priv->error)
- IPW_DEBUG_FW("Sysfs 'error' log captured.\n");
- else
- IPW_DEBUG_FW("Error allocating sysfs 'error' "
- "log.\n");
- if (ipw_debug_level & IPW_DL_FW_ERRORS)
- ipw_dump_error_log(priv, priv->error);
- }
-
- /* XXX: If hardware encryption is for WPA/WPA2,
- * we have to notify the supplicant. */
- if (priv->ieee->sec.encrypt) {
- priv->status &= ~STATUS_ASSOCIATED;
- notify_wx_assoc_event(priv);
- }
-
- /* Keep the restart process from trying to send host
- * commands by clearing the INIT status bit */
- priv->status &= ~STATUS_INIT;
-
- /* Cancel currently queued command. */
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
-
- schedule_work(&priv->adapter_restart);
- handled |= IPW_INTA_BIT_FATAL_ERROR;
- }
-
- if (inta & IPW_INTA_BIT_PARITY_ERROR) {
- IPW_ERROR("Parity error\n");
- handled |= IPW_INTA_BIT_PARITY_ERROR;
- }
-
- if (handled != inta) {
- IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* enable all interrupts */
- ipw_enable_interrupts(priv);
-}
-
-#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
-static char *get_cmd_string(u8 cmd)
-{
- switch (cmd) {
- IPW_CMD(HOST_COMPLETE);
- IPW_CMD(POWER_DOWN);
- IPW_CMD(SYSTEM_CONFIG);
- IPW_CMD(MULTICAST_ADDRESS);
- IPW_CMD(SSID);
- IPW_CMD(ADAPTER_ADDRESS);
- IPW_CMD(PORT_TYPE);
- IPW_CMD(RTS_THRESHOLD);
- IPW_CMD(FRAG_THRESHOLD);
- IPW_CMD(POWER_MODE);
- IPW_CMD(WEP_KEY);
- IPW_CMD(TGI_TX_KEY);
- IPW_CMD(SCAN_REQUEST);
- IPW_CMD(SCAN_REQUEST_EXT);
- IPW_CMD(ASSOCIATE);
- IPW_CMD(SUPPORTED_RATES);
- IPW_CMD(SCAN_ABORT);
- IPW_CMD(TX_FLUSH);
- IPW_CMD(QOS_PARAMETERS);
- IPW_CMD(DINO_CONFIG);
- IPW_CMD(RSN_CAPABILITIES);
- IPW_CMD(RX_KEY);
- IPW_CMD(CARD_DISABLE);
- IPW_CMD(SEED_NUMBER);
- IPW_CMD(TX_POWER);
- IPW_CMD(COUNTRY_INFO);
- IPW_CMD(AIRONET_INFO);
- IPW_CMD(AP_TX_POWER);
- IPW_CMD(CCKM_INFO);
- IPW_CMD(CCX_VER_INFO);
- IPW_CMD(SET_CALIBRATION);
- IPW_CMD(SENSITIVITY_CALIB);
- IPW_CMD(RETRY_LIMIT);
- IPW_CMD(IPW_PRE_POWER_DOWN);
- IPW_CMD(VAP_BEACON_TEMPLATE);
- IPW_CMD(VAP_DTIM_PERIOD);
- IPW_CMD(EXT_SUPPORTED_RATES);
- IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT);
- IPW_CMD(VAP_QUIET_INTERVALS);
- IPW_CMD(VAP_CHANNEL_SWITCH);
- IPW_CMD(VAP_MANDATORY_CHANNELS);
- IPW_CMD(VAP_CELL_PWR_LIMIT);
- IPW_CMD(VAP_CF_PARAM_SET);
- IPW_CMD(VAP_SET_BEACONING_STATE);
- IPW_CMD(MEASUREMENT);
- IPW_CMD(POWER_CAPABILITY);
- IPW_CMD(SUPPORTED_CHANNELS);
- IPW_CMD(TPC_REPORT);
- IPW_CMD(WME_INFO);
- IPW_CMD(PRODUCTION_COMMAND);
- default:
- return "UNKNOWN";
- }
-}
-
-#define HOST_COMPLETE_TIMEOUT HZ
-
-static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
-{
- int rc = 0;
- unsigned long flags;
- unsigned long now, end;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->status & STATUS_HCMD_ACTIVE) {
- IPW_ERROR("Failed to send %s: Already sending a command.\n",
- get_cmd_string(cmd->cmd));
- spin_unlock_irqrestore(&priv->lock, flags);
- return -EAGAIN;
- }
-
- priv->status |= STATUS_HCMD_ACTIVE;
-
- if (priv->cmdlog) {
- priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies;
- priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd;
- priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len;
- memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param,
- cmd->len);
- priv->cmdlog[priv->cmdlog_pos].retcode = -1;
- }
-
- IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n",
- get_cmd_string(cmd->cmd), cmd->cmd, cmd->len,
- priv->status);
-
-#ifndef DEBUG_CMD_WEP_KEY
- if (cmd->cmd == IPW_CMD_WEP_KEY)
- IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n");
- else
-#endif
- printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
-
- rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0);
- if (rc) {
- priv->status &= ~STATUS_HCMD_ACTIVE;
- IPW_ERROR("Failed to send %s: Reason %d\n",
- get_cmd_string(cmd->cmd), rc);
- spin_unlock_irqrestore(&priv->lock, flags);
- goto exit;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- now = jiffies;
- end = now + HOST_COMPLETE_TIMEOUT;
-again:
- rc = wait_event_interruptible_timeout(priv->wait_command_queue,
- !(priv->
- status & STATUS_HCMD_ACTIVE),
- end - now);
- if (rc < 0) {
- now = jiffies;
- if (time_before(now, end))
- goto again;
- rc = 0;
- }
-
- if (rc == 0) {
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->status & STATUS_HCMD_ACTIVE) {
- IPW_ERROR("Failed to send %s: Command timed out.\n",
- get_cmd_string(cmd->cmd));
- priv->status &= ~STATUS_HCMD_ACTIVE;
- spin_unlock_irqrestore(&priv->lock, flags);
- rc = -EIO;
- goto exit;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- } else
- rc = 0;
-
- if (priv->status & STATUS_RF_KILL_HW) {
- IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n",
- get_cmd_string(cmd->cmd));
- rc = -EIO;
- goto exit;
- }
-
- exit:
- if (priv->cmdlog) {
- priv->cmdlog[priv->cmdlog_pos++].retcode = rc;
- priv->cmdlog_pos %= priv->cmdlog_len;
- }
- return rc;
-}
-
-static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command)
-{
- struct host_cmd cmd = {
- .cmd = command,
- };
-
- return __ipw_send_cmd(priv, &cmd);
-}
-
-static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len,
- const void *data)
-{
- struct host_cmd cmd = {
- .cmd = command,
- .len = len,
- .param = data,
- };
-
- return __ipw_send_cmd(priv, &cmd);
-}
-
-static int ipw_send_host_complete(struct ipw_priv *priv)
-{
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE);
-}
-
-static int ipw_send_system_config(struct ipw_priv *priv)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG,
- sizeof(priv->sys_config),
- &priv->sys_config);
-}
-
-static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
-{
- if (!priv || !ssid) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE),
- ssid);
-}
-
-static int ipw_send_adapter_address(struct ipw_priv *priv, const u8 * mac)
-{
- if (!priv || !mac) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- IPW_DEBUG_INFO("%s: Setting MAC to %pM\n",
- priv->net_dev->name, mac);
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
-}
-
-static void ipw_adapter_restart(void *adapter)
-{
- struct ipw_priv *priv = adapter;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return;
-
- ipw_down(priv);
-
- if (priv->assoc_network &&
- (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS))
- ipw_remove_current_network(priv);
-
- if (ipw_up(priv)) {
- IPW_ERROR("Failed to up device\n");
- return;
- }
-}
-
-static void ipw_bg_adapter_restart(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, adapter_restart);
- mutex_lock(&priv->mutex);
- ipw_adapter_restart(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_abort_scan(struct ipw_priv *priv);
-
-#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
-
-static void ipw_scan_check(void *data)
-{
- struct ipw_priv *priv = data;
-
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_SCAN("Scan completion watchdog resetting "
- "adapter after (%dms).\n",
- jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
- schedule_work(&priv->adapter_restart);
- } else if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan completion watchdog aborting scan "
- "after (%dms).\n",
- jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
- ipw_abort_scan(priv);
- schedule_delayed_work(&priv->scan_check, HZ);
- }
-}
-
-static void ipw_bg_scan_check(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, scan_check.work);
- mutex_lock(&priv->mutex);
- ipw_scan_check(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_send_scan_request_ext(struct ipw_priv *priv,
- struct ipw_scan_request_ext *request)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT,
- sizeof(*request), request);
-}
-
-static int ipw_send_scan_abort(struct ipw_priv *priv)
-{
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT);
-}
-
-static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
-{
- struct ipw_sensitivity_calib calib = {
- .beacon_rssi_raw = cpu_to_le16(sens),
- };
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib),
- &calib);
-}
-
-static int ipw_send_associate(struct ipw_priv *priv,
- struct ipw_associate *associate)
-{
- if (!priv || !associate) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(*associate),
- associate);
-}
-
-static int ipw_send_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *rates)
-{
- if (!priv || !rates) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates),
- rates);
-}
-
-static int ipw_set_random_seed(struct ipw_priv *priv)
-{
- u32 val;
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- get_random_bytes(&val, sizeof(val));
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val);
-}
-
-static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
-{
- __le32 v = cpu_to_le32(phy_off);
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(v), &v);
-}
-
-static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
-{
- if (!priv || !power) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power);
-}
-
-static int ipw_set_tx_power(struct ipw_priv *priv)
-{
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct ipw_tx_power tx_power;
- s8 max_power;
- int i;
-
- memset(&tx_power, 0, sizeof(tx_power));
-
- /* configure device for 'G' band */
- tx_power.ieee_mode = IPW_G_MODE;
- tx_power.num_channels = geo->bg_channels;
- for (i = 0; i < geo->bg_channels; i++) {
- max_power = geo->bg[i].max_power;
- tx_power.channels_tx_power[i].channel_number =
- geo->bg[i].channel;
- tx_power.channels_tx_power[i].tx_power = max_power ?
- min(max_power, priv->tx_power) : priv->tx_power;
- }
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
-
- /* configure device to also handle 'B' band */
- tx_power.ieee_mode = IPW_B_MODE;
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
-
- /* configure device to also handle 'A' band */
- if (priv->ieee->abg_true) {
- tx_power.ieee_mode = IPW_A_MODE;
- tx_power.num_channels = geo->a_channels;
- for (i = 0; i < tx_power.num_channels; i++) {
- max_power = geo->a[i].max_power;
- tx_power.channels_tx_power[i].channel_number =
- geo->a[i].channel;
- tx_power.channels_tx_power[i].tx_power = max_power ?
- min(max_power, priv->tx_power) : priv->tx_power;
- }
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
- }
- return 0;
-}
-
-static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
-{
- struct ipw_rts_threshold rts_threshold = {
- .rts_threshold = cpu_to_le16(rts),
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD,
- sizeof(rts_threshold), &rts_threshold);
-}
-
-static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
-{
- struct ipw_frag_threshold frag_threshold = {
- .frag_threshold = cpu_to_le16(frag),
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD,
- sizeof(frag_threshold), &frag_threshold);
-}
-
-static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
-{
- __le32 param;
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- /* If on battery, set to 3, if AC set to CAM, else user
- * level */
- switch (mode) {
- case IPW_POWER_BATTERY:
- param = cpu_to_le32(IPW_POWER_INDEX_3);
- break;
- case IPW_POWER_AC:
- param = cpu_to_le32(IPW_POWER_MODE_CAM);
- break;
- default:
- param = cpu_to_le32(mode);
- break;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
- &param);
-}
-
-static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit)
-{
- struct ipw_retry_limit retry_limit = {
- .short_retry_limit = slimit,
- .long_retry_limit = llimit
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit),
- &retry_limit);
-}
-
-/*
- * The IPW device contains a Microwire compatible EEPROM that stores
- * various data like the MAC address. Usually the firmware has exclusive
- * access to the eeprom, but during device initialization (before the
- * device driver has sent the HostComplete command to the firmware) the
- * device driver has read access to the EEPROM by way of indirect addressing
- * through a couple of memory mapped registers.
- *
- * The following is a simplified implementation for pulling data out of the
- * eeprom, along with some helper functions to find information in
- * the per device private data's copy of the eeprom.
- *
- * NOTE: To better understand how these functions work (i.e what is a chip
- * select and why do have to keep driving the eeprom clock?), read
- * just about any data sheet for a Microwire compatible EEPROM.
- */
-
-/* write a 32 bit value into the indirect accessor register */
-static inline void eeprom_write_reg(struct ipw_priv *p, u32 data)
-{
- ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data);
-
- /* the eeprom requires some time to complete the operation */
- udelay(p->eeprom_delay);
-}
-
-/* perform a chip select operation */
-static void eeprom_cs(struct ipw_priv *priv)
-{
- eeprom_write_reg(priv, 0);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
-}
-
-/* perform a chip select operation */
-static void eeprom_disable_cs(struct ipw_priv *priv)
-{
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- eeprom_write_reg(priv, 0);
- eeprom_write_reg(priv, EEPROM_BIT_SK);
-}
-
-/* push a single bit down to the eeprom */
-static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit)
-{
- int d = (bit ? EEPROM_BIT_DI : 0);
- eeprom_write_reg(p, EEPROM_BIT_CS | d);
- eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK);
-}
-
-/* push an opcode followed by an address down to the eeprom */
-static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr)
-{
- int i;
-
- eeprom_cs(priv);
- eeprom_write_bit(priv, 1);
- eeprom_write_bit(priv, op & 2);
- eeprom_write_bit(priv, op & 1);
- for (i = 7; i >= 0; i--) {
- eeprom_write_bit(priv, addr & (1 << i));
- }
-}
-
-/* pull 16 bits off the eeprom, one bit at a time */
-static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr)
-{
- int i;
- u16 r = 0;
-
- /* Send READ Opcode */
- eeprom_op(priv, EEPROM_CMD_READ, addr);
-
- /* Send dummy bit */
- eeprom_write_reg(priv, EEPROM_BIT_CS);
-
- /* Read the byte off the eeprom one bit at a time */
- for (i = 0; i < 16; i++) {
- u32 data = 0;
- eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS);
- r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0);
- }
-
- /* Send another dummy bit */
- eeprom_write_reg(priv, 0);
- eeprom_disable_cs(priv);
-
- return r;
-}
-
-/* helper function for pulling the mac address out of the private */
-/* data's copy of the eeprom data */
-static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
-{
- memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], ETH_ALEN);
-}
-
-static void ipw_read_eeprom(struct ipw_priv *priv)
-{
- int i;
- __le16 *eeprom = (__le16 *) priv->eeprom;
-
- IPW_DEBUG_TRACE(">>\n");
-
- /* read entire contents of eeprom into private buffer */
- for (i = 0; i < 128; i++)
- eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-/*
- * Either the device driver (i.e. the host) or the firmware can
- * load eeprom data into the designated region in SRAM. If neither
- * happens then the FW will shutdown with a fatal error.
- *
- * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE
- * bit needs region of shared SRAM needs to be non-zero.
- */
-static void ipw_eeprom_init_sram(struct ipw_priv *priv)
-{
- int i;
-
- IPW_DEBUG_TRACE(">>\n");
-
- /*
- If the data looks correct, then copy it to our private
- copy. Otherwise let the firmware know to perform the operation
- on its own.
- */
- if (priv->eeprom[EEPROM_VERSION] != 0) {
- IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
-
- /* write the eeprom data to sram */
- for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
- ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]);
-
- /* Do not load eeprom data on fatal error or suspend */
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
- } else {
- IPW_DEBUG_INFO("Enabling FW initialization of SRAM\n");
-
- /* Load eeprom data on fatal error or suspend */
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1);
- }
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-static void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
-{
- count >>= 2;
- if (!count)
- return;
- _ipw_write32(priv, IPW_AUTOINC_ADDR, start);
- while (count--)
- _ipw_write32(priv, IPW_AUTOINC_DATA, 0);
-}
-
-static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
-{
- ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL,
- CB_NUMBER_OF_ELEMENTS_SMALL *
- sizeof(struct command_block));
-}
-
-static int ipw_fw_dma_enable(struct ipw_priv *priv)
-{ /* start dma engine but no transfers yet */
-
- IPW_DEBUG_FW(">> :\n");
-
- /* Start the dma */
- ipw_fw_dma_reset_command_blocks(priv);
-
- /* Write CB base address */
- ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL);
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-}
-
-static void ipw_fw_dma_abort(struct ipw_priv *priv)
-{
- u32 control = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- /* set the Stop and Abort bit */
- control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
- ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
- priv->sram_desc.last_cb_index = 0;
-
- IPW_DEBUG_FW("<<\n");
-}
-
-static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
- struct command_block *cb)
-{
- u32 address =
- IPW_SHARED_SRAM_DMA_CONTROL +
- (sizeof(struct command_block) * index);
- IPW_DEBUG_FW(">> :\n");
-
- ipw_write_indirect(priv, address, (u8 *) cb,
- (int)sizeof(struct command_block));
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-
-}
-
-static int ipw_fw_dma_kick(struct ipw_priv *priv)
-{
- u32 control = 0;
- u32 index = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- for (index = 0; index < priv->sram_desc.last_cb_index; index++)
- ipw_fw_dma_write_command_block(priv, index,
- &priv->sram_desc.cb_list[index]);
-
- /* Enable the DMA in the CSR register */
- ipw_clear_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED |
- IPW_RESET_REG_STOP_MASTER);
-
- /* Set the Start bit. */
- control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START;
- ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-}
-
-static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
-{
- u32 address;
- u32 register_value = 0;
- u32 cb_fields_address = 0;
-
- IPW_DEBUG_FW(">> :\n");
- address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
- IPW_DEBUG_FW_INFO("Current CB is 0x%x\n", address);
-
- /* Read the DMA Controlor register */
- register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL);
- IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x\n", register_value);
-
- /* Print the CB values */
- cb_fields_address = address;
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Control Field is 0x%x\n", register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x\n", register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x\n",
- register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x\n", register_value);
-
- IPW_DEBUG_FW(">> :\n");
-}
-
-static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
-{
- u32 current_cb_address = 0;
- u32 current_cb_index = 0;
-
- IPW_DEBUG_FW("<< :\n");
- current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
-
- current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) /
- sizeof(struct command_block);
-
- IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X\n",
- current_cb_index, current_cb_address);
-
- IPW_DEBUG_FW(">> :\n");
- return current_cb_index;
-
-}
-
-static int ipw_fw_dma_add_command_block(struct ipw_priv *priv,
- u32 src_address,
- u32 dest_address,
- u32 length,
- int interrupt_enabled, int is_last)
-{
-
- u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC |
- CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG |
- CB_DEST_SIZE_LONG;
- struct command_block *cb;
- u32 last_cb_element = 0;
-
- IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n",
- src_address, dest_address, length);
-
- if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL)
- return -1;
-
- last_cb_element = priv->sram_desc.last_cb_index;
- cb = &priv->sram_desc.cb_list[last_cb_element];
- priv->sram_desc.last_cb_index++;
-
- /* Calculate the new CB control word */
- if (interrupt_enabled)
- control |= CB_INT_ENABLED;
-
- if (is_last)
- control |= CB_LAST_VALID;
-
- control |= length;
-
- /* Calculate the CB Element's checksum value */
- cb->status = control ^ src_address ^ dest_address;
-
- /* Copy the Source and Destination addresses */
- cb->dest_addr = dest_address;
- cb->source_addr = src_address;
-
- /* Copy the Control Word last */
- cb->control = control;
-
- return 0;
-}
-
-static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address,
- int nr, u32 dest_address, u32 len)
-{
- int ret, i;
- u32 size;
-
- IPW_DEBUG_FW(">>\n");
- IPW_DEBUG_FW_INFO("nr=%d dest_address=0x%x len=0x%x\n",
- nr, dest_address, len);
-
- for (i = 0; i < nr; i++) {
- size = min_t(u32, len - i * CB_MAX_LENGTH, CB_MAX_LENGTH);
- ret = ipw_fw_dma_add_command_block(priv, src_address[i],
- dest_address +
- i * CB_MAX_LENGTH, size,
- 0, 0);
- if (ret) {
- IPW_DEBUG_FW_INFO(": Failed\n");
- return -1;
- } else
- IPW_DEBUG_FW_INFO(": Added new cb\n");
- }
-
- IPW_DEBUG_FW("<<\n");
- return 0;
-}
-
-static int ipw_fw_dma_wait(struct ipw_priv *priv)
-{
- u32 current_index = 0, previous_index;
- u32 watchdog = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- current_index = ipw_fw_dma_command_block_index(priv);
- IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n",
- (int)priv->sram_desc.last_cb_index);
-
- while (current_index < priv->sram_desc.last_cb_index) {
- udelay(50);
- previous_index = current_index;
- current_index = ipw_fw_dma_command_block_index(priv);
-
- if (previous_index < current_index) {
- watchdog = 0;
- continue;
- }
- if (++watchdog > 400) {
- IPW_DEBUG_FW_INFO("Timeout\n");
- ipw_fw_dma_dump_command_block(priv);
- ipw_fw_dma_abort(priv);
- return -1;
- }
- }
-
- ipw_fw_dma_abort(priv);
-
- /*Disable the DMA in the CSR register */
- ipw_set_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER);
-
- IPW_DEBUG_FW("<< dmaWaitSync\n");
- return 0;
-}
-
-static void ipw_remove_current_network(struct ipw_priv *priv)
-{
- struct list_head *element, *safe;
- struct libipw_network *network = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_safe(element, safe, &priv->ieee->network_list) {
- network = list_entry(element, struct libipw_network, list);
- if (ether_addr_equal(network->bssid, priv->bssid)) {
- list_del(element);
- list_add_tail(&network->list,
- &priv->ieee->network_free_list);
- }
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-}
-
-/* timeout in msec, attempted in 10-msec quanta */
-static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
- int timeout)
-{
- int i = 0;
-
- do {
- if ((ipw_read32(priv, addr) & mask) == mask)
- return i;
- mdelay(10);
- i += 10;
- } while (i < timeout);
-
- return -ETIME;
-}
-
-/* These functions load the firmware and micro code for the operation of
- * the ipw hardware. It assumes the buffer has all the bits for the
- * image and the caller is handling the memory allocation and clean up.
- */
-
-static int ipw_stop_master(struct ipw_priv *priv)
-{
- int rc;
-
- IPW_DEBUG_TRACE(">>\n");
- /* stop master. typical delay - 0 */
- ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
-
- /* timeout is in msec, polled in 10-msec quanta */
- rc = ipw_poll_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED, 100);
- if (rc < 0) {
- IPW_ERROR("wait for stop master failed after 100ms\n");
- return -1;
- }
-
- IPW_DEBUG_INFO("stop master %dms\n", rc);
-
- return rc;
-}
-
-static void ipw_arc_release(struct ipw_priv *priv)
-{
- IPW_DEBUG_TRACE(">>\n");
- mdelay(5);
-
- ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
-
- /* no one knows timing, for safety add some delay */
- mdelay(5);
-}
-
-struct fw_chunk {
- __le32 address;
- __le32 length;
-};
-
-static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
-{
- int rc = 0, i, addr;
- u8 cr = 0;
- __le16 *image;
-
- image = (__le16 *) data;
-
- IPW_DEBUG_TRACE(">>\n");
-
- rc = ipw_stop_master(priv);
-
- if (rc < 0)
- return rc;
-
- for (addr = IPW_SHARED_LOWER_BOUND;
- addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
- ipw_write32(priv, addr, 0);
- }
-
- /* no ucode (yet) */
- memset(&priv->dino_alive, 0, sizeof(priv->dino_alive));
- /* destroy DMA queues */
- /* reset sequence */
-
- ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON);
- ipw_arc_release(priv);
- ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF);
- mdelay(1);
-
- /* reset PHY */
- ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN);
- mdelay(1);
-
- ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0);
- mdelay(1);
-
- /* enable ucode store */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0);
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS);
- mdelay(1);
-
- /* write ucode */
- /*
- * @bug
- * Do NOT set indirect address register once and then
- * store data to indirect data register in the loop.
- * It seems very reasonable, but in this case DINO do not
- * accept ucode. It is essential to set address each time.
- */
- /* load new ipw uCode */
- for (i = 0; i < len / 2; i++)
- ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE,
- le16_to_cpu(image[i]));
-
- /* enable DINO */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
-
- /* this is where the igx / win driver deveates from the VAP driver. */
-
- /* wait for alive response */
- for (i = 0; i < 100; i++) {
- /* poll for incoming data */
- cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS);
- if (cr & DINO_RXFIFO_DATA)
- break;
- mdelay(1);
- }
-
- if (cr & DINO_RXFIFO_DATA) {
- /* alive_command_responce size is NOT multiple of 4 */
- __le32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4];
-
- for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
- response_buffer[i] =
- cpu_to_le32(ipw_read_reg32(priv,
- IPW_BASEBAND_RX_FIFO_READ));
- memcpy(&priv->dino_alive, response_buffer,
- sizeof(priv->dino_alive));
- if (priv->dino_alive.alive_command == 1
- && priv->dino_alive.ucode_valid == 1) {
- rc = 0;
- IPW_DEBUG_INFO
- ("Microcode OK, rev. %d (0x%x) dev. %d (0x%x) "
- "of %02d/%02d/%02d %02d:%02d\n",
- priv->dino_alive.software_revision,
- priv->dino_alive.software_revision,
- priv->dino_alive.device_identifier,
- priv->dino_alive.device_identifier,
- priv->dino_alive.time_stamp[0],
- priv->dino_alive.time_stamp[1],
- priv->dino_alive.time_stamp[2],
- priv->dino_alive.time_stamp[3],
- priv->dino_alive.time_stamp[4]);
- } else {
- IPW_DEBUG_INFO("Microcode is not alive\n");
- rc = -EINVAL;
- }
- } else {
- IPW_DEBUG_INFO("No alive response from DINO\n");
- rc = -ETIME;
- }
-
- /* disable DINO, otherwise for some reason
- firmware have problem getting alive resp. */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
-
- return rc;
-}
-
-static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
-{
- int ret = -1;
- int offset = 0;
- struct fw_chunk *chunk;
- int total_nr = 0;
- int i;
- struct dma_pool *pool;
- void **virts;
- dma_addr_t *phys;
-
- IPW_DEBUG_TRACE("<< :\n");
-
- virts = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(void *),
- GFP_KERNEL);
- if (!virts)
- return -ENOMEM;
-
- phys = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(dma_addr_t),
- GFP_KERNEL);
- if (!phys) {
- kfree(virts);
- return -ENOMEM;
- }
- pool = dma_pool_create("ipw2200", &priv->pci_dev->dev, CB_MAX_LENGTH, 0,
- 0);
- if (!pool) {
- IPW_ERROR("dma_pool_create failed\n");
- kfree(phys);
- kfree(virts);
- return -ENOMEM;
- }
-
- /* Start the Dma */
- ret = ipw_fw_dma_enable(priv);
-
- /* the DMA is already ready this would be a bug. */
- BUG_ON(priv->sram_desc.last_cb_index > 0);
-
- do {
- u32 chunk_len;
- u8 *start;
- int size;
- int nr = 0;
-
- chunk = (struct fw_chunk *)(data + offset);
- offset += sizeof(struct fw_chunk);
- chunk_len = le32_to_cpu(chunk->length);
- start = data + offset;
-
- nr = (chunk_len + CB_MAX_LENGTH - 1) / CB_MAX_LENGTH;
- for (i = 0; i < nr; i++) {
- virts[total_nr] = dma_pool_alloc(pool, GFP_KERNEL,
- &phys[total_nr]);
- if (!virts[total_nr]) {
- ret = -ENOMEM;
- goto out;
- }
- size = min_t(u32, chunk_len - i * CB_MAX_LENGTH,
- CB_MAX_LENGTH);
- memcpy(virts[total_nr], start, size);
- start += size;
- total_nr++;
- /* We don't support fw chunk larger than 64*8K */
- BUG_ON(total_nr > CB_NUMBER_OF_ELEMENTS_SMALL);
- }
-
- /* build DMA packet and queue up for sending */
- /* dma to chunk->address, the chunk->length bytes from data +
- * offeset*/
- /* Dma loading */
- ret = ipw_fw_dma_add_buffer(priv, &phys[total_nr - nr],
- nr, le32_to_cpu(chunk->address),
- chunk_len);
- if (ret) {
- IPW_DEBUG_INFO("dmaAddBuffer Failed\n");
- goto out;
- }
-
- offset += chunk_len;
- } while (offset < len);
-
- /* Run the DMA and wait for the answer */
- ret = ipw_fw_dma_kick(priv);
- if (ret) {
- IPW_ERROR("dmaKick Failed\n");
- goto out;
- }
-
- ret = ipw_fw_dma_wait(priv);
- if (ret) {
- IPW_ERROR("dmaWaitSync Failed\n");
- goto out;
- }
- out:
- for (i = 0; i < total_nr; i++)
- dma_pool_free(pool, virts[i], phys[i]);
-
- dma_pool_destroy(pool);
- kfree(phys);
- kfree(virts);
-
- return ret;
-}
-
-/* stop nic */
-static int ipw_stop_nic(struct ipw_priv *priv)
-{
- int rc = 0;
-
- /* stop */
- ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
-
- rc = ipw_poll_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED, 500);
- if (rc < 0) {
- IPW_ERROR("wait for reg master disabled failed after 500ms\n");
- return rc;
- }
-
- ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
-
- return rc;
-}
-
-static void ipw_start_nic(struct ipw_priv *priv)
-{
- IPW_DEBUG_TRACE(">>\n");
-
- /* prvHwStartNic release ARC */
- ipw_clear_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED |
- IPW_RESET_REG_STOP_MASTER |
- CBD_RESET_REG_PRINCETON_RESET);
-
- /* enable power management */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW,
- IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-static int ipw_init_nic(struct ipw_priv *priv)
-{
- int rc;
-
- IPW_DEBUG_TRACE(">>\n");
- /* reset */
- /*prvHwInitNic */
- /* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
-
- /* low-level PLL activation */
- ipw_write32(priv, IPW_READ_INT_REGISTER,
- IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
-
- /* wait for clock stabilization */
- rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW,
- IPW_GP_CNTRL_BIT_CLOCK_READY, 250);
- if (rc < 0)
- IPW_DEBUG_INFO("FAILED wait for clock stablization\n");
-
- /* assert SW reset */
- ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET);
-
- udelay(10);
-
- /* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
-
- IPW_DEBUG_TRACE(">>\n");
- return 0;
-}
-
-/* Call this function from process context, it will sleep in request_firmware.
- * Probe is an ok place to call this from.
- */
-static int ipw_reset_nic(struct ipw_priv *priv)
-{
- int rc = 0;
- unsigned long flags;
-
- IPW_DEBUG_TRACE(">>\n");
-
- rc = ipw_init_nic(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
- /* Clear the 'host command active' bit... */
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
- priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
- wake_up_interruptible(&priv->wait_state);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IPW_DEBUG_TRACE("<<\n");
- return rc;
-}
-
-
-struct ipw_fw {
- __le32 ver;
- __le32 boot_size;
- __le32 ucode_size;
- __le32 fw_size;
- u8 data[];
-};
-
-static int ipw_get_fw(struct ipw_priv *priv,
- const struct firmware **raw, const char *name)
-{
- struct ipw_fw *fw;
- int rc;
-
- /* ask firmware_class module to get the boot firmware off disk */
- rc = request_firmware(raw, name, &priv->pci_dev->dev);
- if (rc < 0) {
- IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc);
- return rc;
- }
-
- if ((*raw)->size < sizeof(*fw)) {
- IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size);
- return -EINVAL;
- }
-
- fw = (void *)(*raw)->data;
-
- if ((*raw)->size < sizeof(*fw) + le32_to_cpu(fw->boot_size) +
- le32_to_cpu(fw->ucode_size) + le32_to_cpu(fw->fw_size)) {
- IPW_ERROR("%s is too small or corrupt (%zd)\n",
- name, (*raw)->size);
- return -EINVAL;
- }
-
- IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n",
- name,
- le32_to_cpu(fw->ver) >> 16,
- le32_to_cpu(fw->ver) & 0xff,
- (*raw)->size - sizeof(*fw));
- return 0;
-}
-
-#define IPW_RX_BUF_SIZE (3000)
-
-static void ipw_rx_queue_reset(struct ipw_priv *priv,
- struct ipw_rx_queue *rxq)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&rxq->lock, flags);
-
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
- /* In the reset function, these buffers may have been allocated
- * to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- dma_unmap_single(&priv->pci_dev->dev,
- rxq->pool[i].dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb_irq(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
- }
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
- }
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
- spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-#ifdef CONFIG_PM
-static int fw_loaded = 0;
-static const struct firmware *raw = NULL;
-
-static void free_firmware(void)
-{
- if (fw_loaded) {
- release_firmware(raw);
- raw = NULL;
- fw_loaded = 0;
- }
-}
-#else
-#define free_firmware() do {} while (0)
-#endif
-
-static int ipw_load(struct ipw_priv *priv)
-{
-#ifndef CONFIG_PM
- const struct firmware *raw = NULL;
-#endif
- struct ipw_fw *fw;
- u8 *boot_img, *ucode_img, *fw_img;
- u8 *name = NULL;
- int rc = 0, retries = 3;
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- name = "ipw2200-ibss.fw";
- break;
-#ifdef CONFIG_IPW2200_MONITOR
- case IW_MODE_MONITOR:
- name = "ipw2200-sniffer.fw";
- break;
-#endif
- case IW_MODE_INFRA:
- name = "ipw2200-bss.fw";
- break;
- }
-
- if (!name) {
- rc = -EINVAL;
- goto error;
- }
-
-#ifdef CONFIG_PM
- if (!fw_loaded) {
-#endif
- rc = ipw_get_fw(priv, &raw, name);
- if (rc < 0)
- goto error;
-#ifdef CONFIG_PM
- }
-#endif
-
- fw = (void *)raw->data;
- boot_img = &fw->data[0];
- ucode_img = &fw->data[le32_to_cpu(fw->boot_size)];
- fw_img = &fw->data[le32_to_cpu(fw->boot_size) +
- le32_to_cpu(fw->ucode_size)];
-
- if (!priv->rxq)
- priv->rxq = ipw_rx_queue_alloc(priv);
- else
- ipw_rx_queue_reset(priv, priv->rxq);
- if (!priv->rxq) {
- IPW_ERROR("Unable to initialize Rx queue\n");
- rc = -ENOMEM;
- goto error;
- }
-
- retry:
- /* Ensure interrupts are disabled */
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
- priv->status &= ~STATUS_INT_ENABLED;
-
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
- ipw_stop_nic(priv);
-
- rc = ipw_reset_nic(priv);
- if (rc < 0) {
- IPW_ERROR("Unable to reset NIC\n");
- goto error;
- }
-
- ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
- IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
-
- /* DMA the initial boot firmware into the device */
- rc = ipw_load_firmware(priv, boot_img, le32_to_cpu(fw->boot_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load boot firmware: %d\n", rc);
- goto error;
- }
-
- /* kick start the device */
- ipw_start_nic(priv);
-
- /* wait for the device to finish its initial startup sequence */
- rc = ipw_poll_bit(priv, IPW_INTA_RW,
- IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
- if (rc < 0) {
- IPW_ERROR("device failed to boot initial fw image\n");
- goto error;
- }
- IPW_DEBUG_INFO("initial device response after %dms\n", rc);
-
- /* ack fw init done interrupt */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
-
- /* DMA the ucode into the device */
- rc = ipw_load_ucode(priv, ucode_img, le32_to_cpu(fw->ucode_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load ucode: %d\n", rc);
- goto error;
- }
-
- /* stop nic */
- ipw_stop_nic(priv);
-
- /* DMA bss firmware into the device */
- rc = ipw_load_firmware(priv, fw_img, le32_to_cpu(fw->fw_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load firmware: %d\n", rc);
- goto error;
- }
-#ifdef CONFIG_PM
- fw_loaded = 1;
-#endif
-
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
-
- rc = ipw_queue_reset(priv);
- if (rc < 0) {
- IPW_ERROR("Unable to initialize queues\n");
- goto error;
- }
-
- /* Ensure interrupts are disabled */
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
- /* kick start the device */
- ipw_start_nic(priv);
-
- if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) {
- if (retries > 0) {
- IPW_WARNING("Parity error. Retrying init.\n");
- retries--;
- goto retry;
- }
-
- IPW_ERROR("TODO: Handle parity error -- schedule restart?\n");
- rc = -EIO;
- goto error;
- }
-
- /* wait for the device */
- rc = ipw_poll_bit(priv, IPW_INTA_RW,
- IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
- if (rc < 0) {
- IPW_ERROR("device failed to start within 500ms\n");
- goto error;
- }
- IPW_DEBUG_INFO("device response after %dms\n", rc);
-
- /* ack fw init done interrupt */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
-
- /* read eeprom data */
- priv->eeprom_delay = 1;
- ipw_read_eeprom(priv);
- /* initialize the eeprom region of sram */
- ipw_eeprom_init_sram(priv);
-
- /* enable interrupts */
- ipw_enable_interrupts(priv);
-
- /* Ensure our queue has valid packets */
- ipw_rx_queue_replenish(priv);
-
- ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read);
-
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
-#ifndef CONFIG_PM
- release_firmware(raw);
-#endif
- return 0;
-
- error:
- if (priv->rxq) {
- ipw_rx_queue_free(priv, priv->rxq);
- priv->rxq = NULL;
- }
- ipw_tx_queue_free(priv);
- release_firmware(raw);
-#ifdef CONFIG_PM
- fw_loaded = 0;
- raw = NULL;
-#endif
-
- return rc;
-}
-
-/*
- * DMA services
- *
- * Theory of operation
- *
- * A queue is a circular buffers with 'Read' and 'Write' pointers.
- * 2 empty entries always kept in the buffer to protect from overflow.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- * The IPW operates with six queues, one receive queue in the device's
- * sram, one transmit queue for sending commands to the device firmware,
- * and four transmit queues for data.
- *
- * The four transmit queues allow for performing quality of service (qos)
- * transmissions as per the 802.11 protocol. Currently Linux does not
- * provide a mechanism to the user for utilizing prioritized queues, so
- * we only utilize the first data transmit queue (queue1).
- */
-
-/*
- * Driver allocates buffers of this size for Rx
- */
-
-/*
- * ipw_rx_queue_space - Return number of free slots available in queue.
- */
-static int ipw_rx_queue_space(const struct ipw_rx_queue *q)
-{
- int s = q->read - q->write;
- if (s <= 0)
- s += RX_QUEUE_SIZE;
- /* keep some buffer to not confuse full and empty queue */
- s -= 2;
- if (s < 0)
- s = 0;
- return s;
-}
-
-static inline int ipw_tx_queue_space(const struct clx2_queue *q)
-{
- int s = q->last_used - q->first_empty;
- if (s <= 0)
- s += q->n_bd;
- s -= 2; /* keep some reserve to not confuse empty and full situations */
- if (s < 0)
- s = 0;
- return s;
-}
-
-static inline int ipw_queue_inc_wrap(int index, int n_bd)
-{
- return (++index == n_bd) ? 0 : index;
-}
-
-/*
- * Initialize common DMA queue structure
- *
- * @param q queue to init
- * @param count Number of BD's to allocate. Should be power of 2
- * @param read_register Address for 'read' register
- * (not offset within BAR, full address)
- * @param write_register Address for 'write' register
- * (not offset within BAR, full address)
- * @param base_register Address for 'base' register
- * (not offset within BAR, full address)
- * @param size Address for 'size' register
- * (not offset within BAR, full address)
- */
-static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q,
- int count, u32 read, u32 write, u32 base, u32 size)
-{
- q->n_bd = count;
-
- q->low_mark = q->n_bd / 4;
- if (q->low_mark < 4)
- q->low_mark = 4;
-
- q->high_mark = q->n_bd / 8;
- if (q->high_mark < 2)
- q->high_mark = 2;
-
- q->first_empty = q->last_used = 0;
- q->reg_r = read;
- q->reg_w = write;
-
- ipw_write32(priv, base, q->dma_addr);
- ipw_write32(priv, size, count);
- ipw_write32(priv, read, 0);
- ipw_write32(priv, write, 0);
-
- _ipw_read32(priv, 0x90);
-}
-
-static int ipw_queue_tx_init(struct ipw_priv *priv,
- struct clx2_tx_queue *q,
- int count, u32 read, u32 write, u32 base, u32 size)
-{
- struct pci_dev *dev = priv->pci_dev;
-
- q->txb = kmalloc_array(count, sizeof(q->txb[0]), GFP_KERNEL);
- if (!q->txb)
- return -ENOMEM;
-
- q->bd =
- dma_alloc_coherent(&dev->dev, sizeof(q->bd[0]) * count,
- &q->q.dma_addr, GFP_KERNEL);
- if (!q->bd) {
- IPW_ERROR("dma_alloc_coherent(%zd) failed\n",
- sizeof(q->bd[0]) * count);
- kfree(q->txb);
- q->txb = NULL;
- return -ENOMEM;
- }
-
- ipw_queue_init(priv, &q->q, count, read, write, base, size);
- return 0;
-}
-
-/*
- * Free one TFD, those at index [txq->q.last_used].
- * Do NOT advance any indexes
- *
- * @param dev
- * @param txq
- */
-static void ipw_queue_tx_free_tfd(struct ipw_priv *priv,
- struct clx2_tx_queue *txq)
-{
- struct tfd_frame *bd = &txq->bd[txq->q.last_used];
- struct pci_dev *dev = priv->pci_dev;
- int i;
-
- /* classify bd */
- if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE)
- /* nothing to cleanup after for host commands */
- return;
-
- /* sanity check */
- if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) {
- IPW_ERROR("Too many chunks: %i\n",
- le32_to_cpu(bd->u.data.num_chunks));
- /* @todo issue fatal error, it is quite serious situation */
- return;
- }
-
- /* unmap chunks if any */
- for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) {
- dma_unmap_single(&dev->dev,
- le32_to_cpu(bd->u.data.chunk_ptr[i]),
- le16_to_cpu(bd->u.data.chunk_len[i]),
- DMA_TO_DEVICE);
- if (txq->txb[txq->q.last_used]) {
- libipw_txb_free(txq->txb[txq->q.last_used]);
- txq->txb[txq->q.last_used] = NULL;
- }
- }
-}
-
-/*
- * Deallocate DMA queue.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- *
- * @param dev
- * @param q
- */
-static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq)
-{
- struct clx2_queue *q = &txq->q;
- struct pci_dev *dev = priv->pci_dev;
-
- if (q->n_bd == 0)
- return;
-
- /* first, empty all BD's */
- for (; q->first_empty != q->last_used;
- q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
- ipw_queue_tx_free_tfd(priv, txq);
- }
-
- /* free buffers belonging to queue itself */
- dma_free_coherent(&dev->dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd,
- q->dma_addr);
- kfree(txq->txb);
-
- /* 0 fill whole structure */
- memset(txq, 0, sizeof(*txq));
-}
-
-/*
- * Destroy all DMA queues and structures
- *
- * @param priv
- */
-static void ipw_tx_queue_free(struct ipw_priv *priv)
-{
- /* Tx CMD queue */
- ipw_queue_tx_free(priv, &priv->txq_cmd);
-
- /* Tx queues */
- ipw_queue_tx_free(priv, &priv->txq[0]);
- ipw_queue_tx_free(priv, &priv->txq[1]);
- ipw_queue_tx_free(priv, &priv->txq[2]);
- ipw_queue_tx_free(priv, &priv->txq[3]);
-}
-
-static void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
-{
- /* First 3 bytes are manufacturer */
- bssid[0] = priv->mac_addr[0];
- bssid[1] = priv->mac_addr[1];
- bssid[2] = priv->mac_addr[2];
-
- /* Last bytes are random */
- get_random_bytes(&bssid[3], ETH_ALEN - 3);
-
- bssid[0] &= 0xfe; /* clear multicast bit */
- bssid[0] |= 0x02; /* set local assignment bit (IEEE802) */
-}
-
-static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
-{
- struct ipw_station_entry entry;
- int i;
-
- for (i = 0; i < priv->num_stations; i++) {
- if (ether_addr_equal(priv->stations[i], bssid)) {
- /* Another node is active in network */
- priv->missed_adhoc_beacons = 0;
- if (!(priv->config & CFG_STATIC_CHANNEL))
- /* when other nodes drop out, we drop out */
- priv->config &= ~CFG_ADHOC_PERSIST;
-
- return i;
- }
- }
-
- if (i == MAX_STATIONS)
- return IPW_INVALID_STATION;
-
- IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid);
-
- entry.reserved = 0;
- entry.support_mode = 0;
- memcpy(entry.mac_addr, bssid, ETH_ALEN);
- memcpy(priv->stations[i], bssid, ETH_ALEN);
- ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry),
- &entry, sizeof(entry));
- priv->num_stations++;
-
- return i;
-}
-
-static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
-{
- int i;
-
- for (i = 0; i < priv->num_stations; i++)
- if (ether_addr_equal(priv->stations[i], bssid))
- return i;
-
- return IPW_INVALID_STATION;
-}
-
-static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
-{
- int err;
-
- if (priv->status & STATUS_ASSOCIATING) {
- IPW_DEBUG_ASSOC("Disassociating while associating.\n");
- schedule_work(&priv->disassociate);
- return;
- }
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
- return;
- }
-
- IPW_DEBUG_ASSOC("Disassociation attempt from %pM "
- "on channel %d.\n",
- priv->assoc_request.bssid,
- priv->assoc_request.channel);
-
- priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
- priv->status |= STATUS_DISASSOCIATING;
-
- if (quiet)
- priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
- else
- priv->assoc_request.assoc_type = HC_DISASSOCIATE;
-
- err = ipw_send_associate(priv, &priv->assoc_request);
- if (err) {
- IPW_DEBUG_HC("Attempt to send [dis]associate command "
- "failed.\n");
- return;
- }
-
-}
-
-static int ipw_disassociate(void *data)
-{
- struct ipw_priv *priv = data;
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
- return 0;
- ipw_send_disassociate(data, 0);
- netif_carrier_off(priv->net_dev);
- return 1;
-}
-
-static void ipw_bg_disassociate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, disassociate);
- mutex_lock(&priv->mutex);
- ipw_disassociate(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_system_config(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, system_config);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
- }
-#endif
-
- ipw_send_system_config(priv);
-}
-
-struct ipw_status_code {
- u16 status;
- const char *reason;
-};
-
-static const struct ipw_status_code ipw_status_codes[] = {
- {0x00, "Successful"},
- {0x01, "Unspecified failure"},
- {0x0A, "Cannot support all requested capabilities in the "
- "Capability information field"},
- {0x0B, "Reassociation denied due to inability to confirm that "
- "association exists"},
- {0x0C, "Association denied due to reason outside the scope of this "
- "standard"},
- {0x0D,
- "Responding station does not support the specified authentication "
- "algorithm"},
- {0x0E,
- "Received an Authentication frame with authentication sequence "
- "transaction sequence number out of expected sequence"},
- {0x0F, "Authentication rejected because of challenge failure"},
- {0x10, "Authentication rejected due to timeout waiting for next "
- "frame in sequence"},
- {0x11, "Association denied because AP is unable to handle additional "
- "associated stations"},
- {0x12,
- "Association denied due to requesting station not supporting all "
- "of the datarates in the BSSBasicServiceSet Parameter"},
- {0x13,
- "Association denied due to requesting station not supporting "
- "short preamble operation"},
- {0x14,
- "Association denied due to requesting station not supporting "
- "PBCC encoding"},
- {0x15,
- "Association denied due to requesting station not supporting "
- "channel agility"},
- {0x19,
- "Association denied due to requesting station not supporting "
- "short slot operation"},
- {0x1A,
- "Association denied due to requesting station not supporting "
- "DSSS-OFDM operation"},
- {0x28, "Invalid Information Element"},
- {0x29, "Group Cipher is not valid"},
- {0x2A, "Pairwise Cipher is not valid"},
- {0x2B, "AKMP is not valid"},
- {0x2C, "Unsupported RSN IE version"},
- {0x2D, "Invalid RSN IE Capabilities"},
- {0x2E, "Cipher suite is rejected per security policy"},
-};
-
-static const char *ipw_get_status_code(u16 status)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++)
- if (ipw_status_codes[i].status == (status & 0xff))
- return ipw_status_codes[i].reason;
- return "Unknown status value.";
-}
-
-static inline void average_init(struct average *avg)
-{
- memset(avg, 0, sizeof(*avg));
-}
-
-#define DEPTH_RSSI 8
-#define DEPTH_NOISE 16
-static s16 exponential_average(s16 prev_avg, s16 val, u8 depth)
-{
- return ((depth-1)*prev_avg + val)/depth;
-}
-
-static void average_add(struct average *avg, s16 val)
-{
- avg->sum -= avg->entries[avg->pos];
- avg->sum += val;
- avg->entries[avg->pos++] = val;
- if (unlikely(avg->pos == AVG_ENTRIES)) {
- avg->init = 1;
- avg->pos = 0;
- }
-}
-
-static s16 average_value(struct average *avg)
-{
- if (!unlikely(avg->init)) {
- if (avg->pos)
- return avg->sum / avg->pos;
- return 0;
- }
-
- return avg->sum / AVG_ENTRIES;
-}
-
-static void ipw_reset_stats(struct ipw_priv *priv)
-{
- u32 len = sizeof(u32);
-
- priv->quality = 0;
-
- average_init(&priv->average_missed_beacons);
- priv->exp_avg_rssi = -60;
- priv->exp_avg_noise = -85 + 0x100;
-
- priv->last_rate = 0;
- priv->last_missed_beacons = 0;
- priv->last_rx_packets = 0;
- priv->last_tx_packets = 0;
- priv->last_tx_failures = 0;
-
- /* Firmware managed, reset only when NIC is restarted, so we have to
- * normalize on the current value */
- ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC,
- &priv->last_rx_err, &len);
- ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE,
- &priv->last_tx_failures, &len);
-
- /* Driver managed, reset with each association */
- priv->missed_adhoc_beacons = 0;
- priv->missed_beacons = 0;
- priv->tx_packets = 0;
- priv->rx_packets = 0;
-
-}
-
-static u32 ipw_get_max_rate(struct ipw_priv *priv)
-{
- u32 i = 0x80000000;
- u32 mask = priv->rates_mask;
- /* If currently associated in B mode, restrict the maximum
- * rate match to B rates */
- if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- mask &= LIBIPW_CCK_RATES_MASK;
-
- /* TODO: Verify that the rate is supported by the current rates
- * list. */
-
- while (i && !(mask & i))
- i >>= 1;
- switch (i) {
- case LIBIPW_CCK_RATE_1MB_MASK:
- return 1000000;
- case LIBIPW_CCK_RATE_2MB_MASK:
- return 2000000;
- case LIBIPW_CCK_RATE_5MB_MASK:
- return 5500000;
- case LIBIPW_OFDM_RATE_6MB_MASK:
- return 6000000;
- case LIBIPW_OFDM_RATE_9MB_MASK:
- return 9000000;
- case LIBIPW_CCK_RATE_11MB_MASK:
- return 11000000;
- case LIBIPW_OFDM_RATE_12MB_MASK:
- return 12000000;
- case LIBIPW_OFDM_RATE_18MB_MASK:
- return 18000000;
- case LIBIPW_OFDM_RATE_24MB_MASK:
- return 24000000;
- case LIBIPW_OFDM_RATE_36MB_MASK:
- return 36000000;
- case LIBIPW_OFDM_RATE_48MB_MASK:
- return 48000000;
- case LIBIPW_OFDM_RATE_54MB_MASK:
- return 54000000;
- }
-
- if (priv->ieee->mode == IEEE_B)
- return 11000000;
- else
- return 54000000;
-}
-
-static u32 ipw_get_current_rate(struct ipw_priv *priv)
-{
- u32 rate, len = sizeof(rate);
- int err;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return 0;
-
- if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) {
- err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate,
- &len);
- if (err) {
- IPW_DEBUG_INFO("failed querying ordinals.\n");
- return 0;
- }
- } else
- return ipw_get_max_rate(priv);
-
- switch (rate) {
- case IPW_TX_RATE_1MB:
- return 1000000;
- case IPW_TX_RATE_2MB:
- return 2000000;
- case IPW_TX_RATE_5MB:
- return 5500000;
- case IPW_TX_RATE_6MB:
- return 6000000;
- case IPW_TX_RATE_9MB:
- return 9000000;
- case IPW_TX_RATE_11MB:
- return 11000000;
- case IPW_TX_RATE_12MB:
- return 12000000;
- case IPW_TX_RATE_18MB:
- return 18000000;
- case IPW_TX_RATE_24MB:
- return 24000000;
- case IPW_TX_RATE_36MB:
- return 36000000;
- case IPW_TX_RATE_48MB:
- return 48000000;
- case IPW_TX_RATE_54MB:
- return 54000000;
- }
-
- return 0;
-}
-
-#define IPW_STATS_INTERVAL (2 * HZ)
-static void ipw_gather_stats(struct ipw_priv *priv)
-{
- u32 rx_err, rx_err_delta, rx_packets_delta;
- u32 tx_failures, tx_failures_delta, tx_packets_delta;
- u32 missed_beacons_percent, missed_beacons_delta;
- u32 quality = 0;
- u32 len = sizeof(u32);
- s16 rssi;
- u32 beacon_quality, signal_quality, tx_quality, rx_quality,
- rate_quality;
- u32 max_rate;
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- priv->quality = 0;
- return;
- }
-
- /* Update the statistics */
- ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS,
- &priv->missed_beacons, &len);
- missed_beacons_delta = priv->missed_beacons - priv->last_missed_beacons;
- priv->last_missed_beacons = priv->missed_beacons;
- if (priv->assoc_request.beacon_interval) {
- missed_beacons_percent = missed_beacons_delta *
- (HZ * le16_to_cpu(priv->assoc_request.beacon_interval)) /
- (IPW_STATS_INTERVAL * 10);
- } else {
- missed_beacons_percent = 0;
- }
- average_add(&priv->average_missed_beacons, missed_beacons_percent);
-
- ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len);
- rx_err_delta = rx_err - priv->last_rx_err;
- priv->last_rx_err = rx_err;
-
- ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len);
- tx_failures_delta = tx_failures - priv->last_tx_failures;
- priv->last_tx_failures = tx_failures;
-
- rx_packets_delta = priv->rx_packets - priv->last_rx_packets;
- priv->last_rx_packets = priv->rx_packets;
-
- tx_packets_delta = priv->tx_packets - priv->last_tx_packets;
- priv->last_tx_packets = priv->tx_packets;
-
- /* Calculate quality based on the following:
- *
- * Missed beacon: 100% = 0, 0% = 70% missed
- * Rate: 60% = 1Mbs, 100% = Max
- * Rx and Tx errors represent a straight % of total Rx/Tx
- * RSSI: 100% = > -50, 0% = < -80
- * Rx errors: 100% = 0, 0% = 50% missed
- *
- * The lowest computed quality is used.
- *
- */
-#define BEACON_THRESHOLD 5
- beacon_quality = 100 - missed_beacons_percent;
- if (beacon_quality < BEACON_THRESHOLD)
- beacon_quality = 0;
- else
- beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 /
- (100 - BEACON_THRESHOLD);
- IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n",
- beacon_quality, missed_beacons_percent);
-
- priv->last_rate = ipw_get_current_rate(priv);
- max_rate = ipw_get_max_rate(priv);
- rate_quality = priv->last_rate * 40 / max_rate + 60;
- IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n",
- rate_quality, priv->last_rate / 1000000);
-
- if (rx_packets_delta > 100 && rx_packets_delta + rx_err_delta)
- rx_quality = 100 - (rx_err_delta * 100) /
- (rx_packets_delta + rx_err_delta);
- else
- rx_quality = 100;
- IPW_DEBUG_STATS("Rx quality : %3d%% (%u errors, %u packets)\n",
- rx_quality, rx_err_delta, rx_packets_delta);
-
- if (tx_packets_delta > 100 && tx_packets_delta + tx_failures_delta)
- tx_quality = 100 - (tx_failures_delta * 100) /
- (tx_packets_delta + tx_failures_delta);
- else
- tx_quality = 100;
- IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n",
- tx_quality, tx_failures_delta, tx_packets_delta);
-
- rssi = priv->exp_avg_rssi;
- signal_quality =
- (100 *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) -
- (priv->ieee->perfect_rssi - rssi) *
- (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) +
- 62 * (priv->ieee->perfect_rssi - rssi))) /
- ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi));
- if (signal_quality > 100)
- signal_quality = 100;
- else if (signal_quality < 1)
- signal_quality = 0;
-
- IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
- signal_quality, rssi);
-
- quality = min(rx_quality, signal_quality);
- quality = min(tx_quality, quality);
- quality = min(rate_quality, quality);
- quality = min(beacon_quality, quality);
- if (quality == beacon_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n",
- quality);
- if (quality == rate_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to rate quality.\n",
- quality);
- if (quality == tx_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to Tx quality.\n",
- quality);
- if (quality == rx_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to Rx quality.\n",
- quality);
- if (quality == signal_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to signal quality.\n",
- quality);
-
- priv->quality = quality;
-
- schedule_delayed_work(&priv->gather_stats, IPW_STATS_INTERVAL);
-}
-
-static void ipw_bg_gather_stats(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, gather_stats.work);
- mutex_lock(&priv->mutex);
- ipw_gather_stats(priv);
- mutex_unlock(&priv->mutex);
-}
-
-/* Missed beacon behavior:
- * 1st missed -> roaming_threshold, just wait, don't do any scan/roam.
- * roaming_threshold -> disassociate_threshold, scan and roam for better signal.
- * Above disassociate threshold, give up and stop scanning.
- * Roaming is disabled if disassociate_threshold <= roaming_threshold */
-static void ipw_handle_missed_beacon(struct ipw_priv *priv,
- int missed_count)
-{
- priv->notif_missed_beacons = missed_count;
-
- if (missed_count > priv->disassociate_threshold &&
- priv->status & STATUS_ASSOCIATED) {
- /* If associated and we've hit the missed
- * beacon threshold, disassociate, turn
- * off roaming, and abort any active scans */
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE | IPW_DL_ASSOC,
- "Missed beacon: %d - disassociate\n", missed_count);
- priv->status &= ~STATUS_ROAMING;
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE,
- "Aborting scan with missed beacon.\n");
- schedule_work(&priv->abort_scan);
- }
-
- schedule_work(&priv->disassociate);
- return;
- }
-
- if (priv->status & STATUS_ROAMING) {
- /* If we are currently roaming, then just
- * print a debug statement... */
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "Missed beacon: %d - roam in progress\n",
- missed_count);
- return;
- }
-
- if (roaming &&
- (missed_count > priv->roaming_threshold &&
- missed_count <= priv->disassociate_threshold)) {
- /* If we are not already roaming, set the ROAM
- * bit in the status and kick off a scan.
- * This can happen several times before we reach
- * disassociate_threshold. */
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "Missed beacon: %d - initiate "
- "roaming\n", missed_count);
- if (!(priv->status & STATUS_ROAMING)) {
- priv->status |= STATUS_ROAMING;
- if (!(priv->status & STATUS_SCANNING))
- schedule_delayed_work(&priv->request_scan, 0);
- }
- return;
- }
-
- if (priv->status & STATUS_SCANNING &&
- missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) {
- /* Stop scan to keep fw from getting
- * stuck (only if we aren't roaming --
- * otherwise we'll never scan more than 2 or 3
- * channels..) */
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE,
- "Aborting scan with missed beacon.\n");
- schedule_work(&priv->abort_scan);
- }
-
- IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
-}
-
-static void ipw_scan_event(struct work_struct *work)
-{
- union iwreq_data wrqu;
-
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, scan_event.work);
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static void handle_scan_event(struct ipw_priv *priv)
-{
- /* Only userspace-requested scan completion events go out immediately */
- if (!priv->user_requested_scan) {
- schedule_delayed_work(&priv->scan_event,
- round_jiffies_relative(msecs_to_jiffies(4000)));
- } else {
- priv->user_requested_scan = 0;
- mod_delayed_work(system_wq, &priv->scan_event, 0);
- }
-}
-
-/*
- * Handle host notification packet.
- * Called from interrupt routine
- */
-static void ipw_rx_notification(struct ipw_priv *priv,
- struct ipw_rx_notification *notif)
-{
- u16 size = le16_to_cpu(notif->size);
-
- IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
-
- switch (notif->subtype) {
- case HOST_NOTIFICATION_STATUS_ASSOCIATED:{
- struct notif_association *assoc = &notif->u.assoc;
-
- switch (assoc->state) {
- case CMAS_ASSOCIATED:{
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "associated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_INFRA:
- memcpy(priv->ieee->bssid,
- priv->bssid, ETH_ALEN);
- break;
-
- case IW_MODE_ADHOC:
- memcpy(priv->ieee->bssid,
- priv->bssid, ETH_ALEN);
-
- /* clear out the station table */
- priv->num_stations = 0;
-
- IPW_DEBUG_ASSOC
- ("queueing adhoc check\n");
- schedule_delayed_work(
- &priv->adhoc_check,
- le16_to_cpu(priv->
- assoc_request.
- beacon_interval));
- break;
- }
-
- priv->status &= ~STATUS_ASSOCIATING;
- priv->status |= STATUS_ASSOCIATED;
- schedule_work(&priv->system_config);
-
-#ifdef CONFIG_IPW2200_QOS
-#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
- le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control))
- if ((priv->status & STATUS_AUTH) &&
- (IPW_GET_PACKET_STYPE(&notif->u.raw)
- == IEEE80211_STYPE_ASSOC_RESP)) {
- if ((sizeof
- (struct
- libipw_assoc_response)
- <= size)
- && (size <= 2314)) {
- struct
- libipw_rx_stats
- stats = {
- .len = size - 1,
- };
-
- IPW_DEBUG_QOS
- ("QoS Associate "
- "size %d\n", size);
- libipw_rx_mgt(priv->
- ieee,
- (struct
- libipw_hdr_4addr
- *)
- &notif->u.raw, &stats);
- }
- }
-#endif
-
- schedule_work(&priv->link_up);
-
- break;
- }
-
- case CMAS_AUTHENTICATED:{
- if (priv->
- status & (STATUS_ASSOCIATED |
- STATUS_AUTH)) {
- struct notif_authenticate *auth
- = &notif->u.auth;
- IPW_DEBUG(IPW_DL_NOTIF |
- IPW_DL_STATE |
- IPW_DL_ASSOC,
- "deauthenticated: '%*pE' %pM: (0x%04X) - %s\n",
- priv->essid_len,
- priv->essid,
- priv->bssid,
- le16_to_cpu(auth->status),
- ipw_get_status_code
- (le16_to_cpu
- (auth->status)));
-
- priv->status &=
- ~(STATUS_ASSOCIATING |
- STATUS_AUTH |
- STATUS_ASSOCIATED);
-
- schedule_work(&priv->link_down);
- break;
- }
-
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "authenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
- break;
- }
-
- case CMAS_INIT:{
- if (priv->status & STATUS_AUTH) {
- struct
- libipw_assoc_response
- *resp;
- resp =
- (struct
- libipw_assoc_response
- *)&notif->u.raw;
- IPW_DEBUG(IPW_DL_NOTIF |
- IPW_DL_STATE |
- IPW_DL_ASSOC,
- "association failed (0x%04X): %s\n",
- le16_to_cpu(resp->status),
- ipw_get_status_code
- (le16_to_cpu
- (resp->status)));
- }
-
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "disassociated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &=
- ~(STATUS_DISASSOCIATING |
- STATUS_ASSOCIATING |
- STATUS_ASSOCIATED | STATUS_AUTH);
- if (priv->assoc_network
- && (priv->assoc_network->
- capability &
- WLAN_CAPABILITY_IBSS))
- ipw_remove_current_network
- (priv);
-
- schedule_work(&priv->link_down);
-
- break;
- }
-
- case CMAS_RX_ASSOC_RESP:
- break;
-
- default:
- IPW_ERROR("assoc: unknown (%d)\n",
- assoc->state);
- break;
- }
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{
- struct notif_authenticate *auth = &notif->u.auth;
- switch (auth->state) {
- case CMAS_AUTHENTICATED:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "authenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
- priv->status |= STATUS_AUTH;
- break;
-
- case CMAS_INIT:
- if (priv->status & STATUS_AUTH) {
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "authentication failed (0x%04X): %s\n",
- le16_to_cpu(auth->status),
- ipw_get_status_code(le16_to_cpu
- (auth->
- status)));
- }
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "deauthenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &= ~(STATUS_ASSOCIATING |
- STATUS_AUTH |
- STATUS_ASSOCIATED);
-
- schedule_work(&priv->link_down);
- break;
-
- case CMAS_TX_AUTH_SEQ_1:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1\n");
- break;
- case CMAS_RX_AUTH_SEQ_2:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_2\n");
- break;
- case CMAS_AUTH_SEQ_1_PASS:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n");
- break;
- case CMAS_AUTH_SEQ_1_FAIL:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n");
- break;
- case CMAS_TX_AUTH_SEQ_3:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_3\n");
- break;
- case CMAS_RX_AUTH_SEQ_4:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n");
- break;
- case CMAS_AUTH_SEQ_2_PASS:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n");
- break;
- case CMAS_AUTH_SEQ_2_FAIL:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n");
- break;
- case CMAS_TX_ASSOC:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "TX_ASSOC\n");
- break;
- case CMAS_RX_ASSOC_RESP:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
-
- break;
- case CMAS_ASSOCIATED:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "ASSOCIATED\n");
- break;
- default:
- IPW_DEBUG_NOTIF("auth: failure - %d\n",
- auth->state);
- break;
- }
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{
- struct notif_channel_result *x =
- &notif->u.channel_result;
-
- if (size == sizeof(*x)) {
- IPW_DEBUG_SCAN("Scan result for channel %d\n",
- x->channel_num);
- } else {
- IPW_DEBUG_SCAN("Scan result of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{
- struct notif_scan_complete *x = &notif->u.scan_complete;
- if (size == sizeof(*x)) {
- IPW_DEBUG_SCAN
- ("Scan completed: type %d, %d channels, "
- "%d status\n", x->scan_type,
- x->num_channels, x->status);
- } else {
- IPW_ERROR("Scan completed of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
-
- priv->status &=
- ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
-
- wake_up_interruptible(&priv->wait_state);
- cancel_delayed_work(&priv->scan_check);
-
- if (priv->status & STATUS_EXIT_PENDING)
- break;
-
- priv->ieee->scans++;
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- priv->status |= STATUS_SCAN_FORCED;
- schedule_delayed_work(&priv->request_scan, 0);
- break;
- }
- priv->status &= ~STATUS_SCAN_FORCED;
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Do queued direct scans first */
- if (priv->status & STATUS_DIRECT_SCAN_PENDING)
- schedule_delayed_work(&priv->request_direct_scan, 0);
-
- if (!(priv->status & (STATUS_ASSOCIATED |
- STATUS_ASSOCIATING |
- STATUS_ROAMING |
- STATUS_DISASSOCIATING)))
- schedule_work(&priv->associate);
- else if (priv->status & STATUS_ROAMING) {
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
- /* If a scan completed and we are in roam mode, then
- * the scan that completed was the one requested as a
- * result of entering roam... so, schedule the
- * roam work */
- schedule_work(&priv->roam);
- else
- /* Don't schedule if we aborted the scan */
- priv->status &= ~STATUS_ROAMING;
- } else if (priv->status & STATUS_SCAN_PENDING)
- schedule_delayed_work(&priv->request_scan, 0);
- else if (priv->config & CFG_BACKGROUND_SCAN
- && priv->status & STATUS_ASSOCIATED)
- schedule_delayed_work(&priv->request_scan,
- round_jiffies_relative(HZ));
-
- /* Send an empty event to user space.
- * We don't send the received data on the event because
- * it would require us to do complex transcoding, and
- * we want to minimise the work done in the irq handler
- * Use a request to extract the data.
- * Also, we generate this even for any scan, regardless
- * on how the scan was initiated. User space can just
- * sync on periodic scan to get fresh data...
- * Jean II */
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
- handle_scan_event(priv);
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
- struct notif_frag_length *x = &notif->u.frag_len;
-
- if (size == sizeof(*x))
- IPW_ERROR("Frag length: %d\n",
- le16_to_cpu(x->frag_length));
- else
- IPW_ERROR("Frag length of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
- struct notif_link_deterioration *x =
- &notif->u.link_deterioration;
-
- if (size == sizeof(*x)) {
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "link deterioration: type %d, cnt %d\n",
- x->silence_notification_type,
- x->silence_count);
- memcpy(&priv->last_link_deterioration, x,
- sizeof(*x));
- } else {
- IPW_ERROR("Link Deterioration of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
- break;
- }
-
- case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
- IPW_ERROR("Dino config\n");
- if (priv->hcmd
- && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG)
- IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_BEACON_STATE:{
- struct notif_beacon_state *x = &notif->u.beacon_state;
- if (size != sizeof(*x)) {
- IPW_ERROR
- ("Beacon state of wrong size %d (should "
- "be %zd)\n", size, sizeof(*x));
- break;
- }
-
- if (le32_to_cpu(x->state) ==
- HOST_NOTIFICATION_STATUS_BEACON_MISSING)
- ipw_handle_missed_beacon(priv,
- le32_to_cpu(x->
- number));
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{
- struct notif_tgi_tx_key *x = &notif->u.tgi_tx_key;
- if (size == sizeof(*x)) {
- IPW_ERROR("TGi Tx Key: state 0x%02x sec type "
- "0x%02x station %d\n",
- x->key_state, x->security_type,
- x->station_index);
- break;
- }
-
- IPW_ERROR
- ("TGi Tx Key of wrong size %d (should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{
- struct notif_calibration *x = &notif->u.calibration;
-
- if (size == sizeof(*x)) {
- memcpy(&priv->calib, x, sizeof(*x));
- IPW_DEBUG_INFO("TODO: Calibration\n");
- break;
- }
-
- IPW_ERROR
- ("Calibration of wrong size %d (should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_NOISE_STATS:{
- if (size == sizeof(u32)) {
- priv->exp_avg_noise =
- exponential_average(priv->exp_avg_noise,
- (u8) (le32_to_cpu(notif->u.noise.value) & 0xff),
- DEPTH_NOISE);
- break;
- }
-
- IPW_ERROR
- ("Noise stat is wrong size %d (should be %zd)\n",
- size, sizeof(u32));
- break;
- }
-
- default:
- IPW_DEBUG_NOTIF("Unknown notification: "
- "subtype=%d,flags=0x%2x,size=%d\n",
- notif->subtype, notif->flags, size);
- }
-}
-
-/*
- * Destroys all DMA structures and initialise them again
- *
- * @param priv
- * @return error code
- */
-static int ipw_queue_reset(struct ipw_priv *priv)
-{
- int rc = 0;
- /* @todo customize queue sizes */
- int nTx = 64, nTxCmd = 8;
- ipw_tx_queue_free(priv);
- /* Tx CMD queue */
- rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd,
- IPW_TX_CMD_QUEUE_READ_INDEX,
- IPW_TX_CMD_QUEUE_WRITE_INDEX,
- IPW_TX_CMD_QUEUE_BD_BASE,
- IPW_TX_CMD_QUEUE_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx Cmd queue init failed\n");
- goto error;
- }
- /* Tx queue(s) */
- rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx,
- IPW_TX_QUEUE_0_READ_INDEX,
- IPW_TX_QUEUE_0_WRITE_INDEX,
- IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 0 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx,
- IPW_TX_QUEUE_1_READ_INDEX,
- IPW_TX_QUEUE_1_WRITE_INDEX,
- IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 1 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx,
- IPW_TX_QUEUE_2_READ_INDEX,
- IPW_TX_QUEUE_2_WRITE_INDEX,
- IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 2 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx,
- IPW_TX_QUEUE_3_READ_INDEX,
- IPW_TX_QUEUE_3_WRITE_INDEX,
- IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 3 queue init failed\n");
- goto error;
- }
- /* statistics */
- priv->rx_bufs_min = 0;
- priv->rx_pend_max = 0;
- return rc;
-
- error:
- ipw_tx_queue_free(priv);
- return rc;
-}
-
-/*
- * Reclaim Tx queue entries no more used by NIC.
- *
- * When FW advances 'R' index, all entries between old and
- * new 'R' index need to be reclaimed. As result, some free space
- * forms. If there is enough free space (> low mark), wake Tx queue.
- *
- * @note Need to protect against garbage in 'R' index
- * @param priv
- * @param txq
- * @param qindex
- * @return Number of used entries remains in the queue
- */
-static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
- struct clx2_tx_queue *txq, int qindex)
-{
- u32 hw_tail;
- int used;
- struct clx2_queue *q = &txq->q;
-
- hw_tail = ipw_read32(priv, q->reg_r);
- if (hw_tail >= q->n_bd) {
- IPW_ERROR
- ("Read index for DMA queue (%d) is out of range [0-%d)\n",
- hw_tail, q->n_bd);
- goto done;
- }
- for (; q->last_used != hw_tail;
- q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
- ipw_queue_tx_free_tfd(priv, txq);
- priv->tx_packets++;
- }
- done:
- if ((ipw_tx_queue_space(q) > q->low_mark) &&
- (qindex >= 0))
- netif_wake_queue(priv->net_dev);
- used = q->first_empty - q->last_used;
- if (used < 0)
- used += q->n_bd;
-
- return used;
-}
-
-static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, const void *buf,
- int len, int sync)
-{
- struct clx2_tx_queue *txq = &priv->txq_cmd;
- struct clx2_queue *q = &txq->q;
- struct tfd_frame *tfd;
-
- if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) {
- IPW_ERROR("No space for Tx\n");
- return -EBUSY;
- }
-
- tfd = &txq->bd[q->first_empty];
- txq->txb[q->first_empty] = NULL;
-
- memset(tfd, 0, sizeof(*tfd));
- tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE;
- tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
- priv->hcmd_seq++;
- tfd->u.cmd.index = hcmd;
- tfd->u.cmd.length = len;
- memcpy(tfd->u.cmd.payload, buf, len);
- q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
- ipw_write32(priv, q->reg_w, q->first_empty);
- _ipw_read32(priv, 0x90);
-
- return 0;
-}
-
-/*
- * Rx theory of operation
- *
- * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
- * 0 to 31
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer it will advance the READ index
- * and fire the RX interrupt. The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free. When
- * ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- * to replensish the ipw->rxq->rx_free.
- * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the
- * ipw->rxq is replenished and the READ INDEX is updated (updating the
- * 'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- * detached from the ipw->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free
- * list. If there are no allocated buffers in ipw->rxq->rx_free, the READ
- * INDEX is not incremented and ipw->status(RX_STALLED) is set. If there
- * were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * ipw_rx_queue_alloc() Allocates rx_free
- * ipw_rx_queue_replenish() Replenishes rx_free list from rx_used, and calls
- * ipw_rx_queue_restock
- * ipw_rx_queue_restock() Moves available buffers from rx_free into Rx
- * queue, updates firmware pointers, and updates
- * the WRITE index. If insufficient rx_free buffers
- * are available, schedules ipw_rx_queue_replenish
- *
- * -- enable interrupts --
- * ISR - ipw_rx() Detach ipw_rx_mem_buffers from pool up to the
- * READ INDEX, detaching the SKB from the pool.
- * Moves the packet buffer from queue to rx_used.
- * Calls ipw_rx_queue_restock to refill any empty
- * slots.
- * ...
- *
- */
-
-/*
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static void ipw_rx_queue_restock(struct ipw_priv *priv)
-{
- struct ipw_rx_queue *rxq = priv->rxq;
- struct list_head *element;
- struct ipw_rx_mem_buffer *rxb;
- unsigned long flags;
- int write;
-
- spin_lock_irqsave(&rxq->lock, flags);
- write = rxq->write;
- while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
- element = rxq->rx_free.next;
- rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
- list_del(element);
-
- ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
- rxb->dma_addr);
- rxq->queue[rxq->write] = rxb;
- rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
- rxq->free_count--;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- /* If the pre-allocated buffer pool is dropping low, schedule to
- * refill it */
- if (rxq->free_count <= RX_LOW_WATERMARK)
- schedule_work(&priv->rx_replenish);
-
- /* If we've added more space for the firmware to place data, tell it */
- if (write != rxq->write)
- ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write);
-}
-
-/*
- * Move all used packet from rx_used to rx_free, allocating a new SKB for each.
- * Also restock the Rx queue via ipw_rx_queue_restock.
- *
- * This is called as a scheduled work item (except for during initialization)
- */
-static void ipw_rx_queue_replenish(void *data)
-{
- struct ipw_priv *priv = data;
- struct ipw_rx_queue *rxq = priv->rxq;
- struct list_head *element;
- struct ipw_rx_mem_buffer *rxb;
- unsigned long flags;
-
- spin_lock_irqsave(&rxq->lock, flags);
- while (!list_empty(&rxq->rx_used)) {
- element = rxq->rx_used.next;
- rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
- rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC);
- if (!rxb->skb) {
- printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n",
- priv->net_dev->name);
- /* We don't reschedule replenish work here -- we will
- * call the restock method and if it still needs
- * more buffers it will schedule replenish */
- break;
- }
- list_del(element);
-
- rxb->dma_addr =
- dma_map_single(&priv->pci_dev->dev, rxb->skb->data,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
-
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- ipw_rx_queue_restock(priv);
-}
-
-static void ipw_bg_rx_queue_replenish(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, rx_replenish);
- mutex_lock(&priv->mutex);
- ipw_rx_queue_replenish(priv);
- mutex_unlock(&priv->mutex);
-}
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq)
-{
- int i;
-
- if (!rxq)
- return;
-
- for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- dma_unmap_single(&priv->pci_dev->dev,
- rxq->pool[i].dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
- }
- }
-
- kfree(rxq);
-}
-
-static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
-{
- struct ipw_rx_queue *rxq;
- int i;
-
- rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
- if (unlikely(!rxq)) {
- IPW_ERROR("memory allocation failed\n");
- return NULL;
- }
- spin_lock_init(&rxq->lock);
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
-
- return rxq;
-}
-
-static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
-{
- rate &= ~LIBIPW_BASIC_RATE_MASK;
- if (ieee_mode == IEEE_A) {
- switch (rate) {
- case LIBIPW_OFDM_RATE_6MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ?
- 1 : 0;
- case LIBIPW_OFDM_RATE_9MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ?
- 1 : 0;
- case LIBIPW_OFDM_RATE_12MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_18MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_24MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_36MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_48MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_54MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
- default:
- return 0;
- }
- }
-
- /* B and G mixed */
- switch (rate) {
- case LIBIPW_CCK_RATE_1MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_1MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_2MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_2MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_5MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_5MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_11MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_11MB_MASK ? 1 : 0;
- }
-
- /* If we are limited to B modulations, bail at this point */
- if (ieee_mode == IEEE_B)
- return 0;
-
- /* G */
- switch (rate) {
- case LIBIPW_OFDM_RATE_6MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_9MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_12MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_18MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_24MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_36MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_48MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_54MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
- }
-
- return 0;
-}
-
-static int ipw_compatible_rates(struct ipw_priv *priv,
- const struct libipw_network *network,
- struct ipw_supported_rates *rates)
-{
- int num_rates, i;
-
- memset(rates, 0, sizeof(*rates));
- num_rates = min(network->rates_len, (u8) IPW_MAX_RATES);
- rates->num_rates = 0;
- for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask(priv, network->mode,
- network->rates[i])) {
-
- if (network->rates[i] & LIBIPW_BASIC_RATE_MASK) {
- IPW_DEBUG_SCAN("Adding masked mandatory "
- "rate %02X\n",
- network->rates[i]);
- rates->supported_rates[rates->num_rates++] =
- network->rates[i];
- continue;
- }
-
- IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
- network->rates[i], priv->rates_mask);
- continue;
- }
-
- rates->supported_rates[rates->num_rates++] = network->rates[i];
- }
-
- num_rates = min(network->rates_ex_len,
- (u8) (IPW_MAX_RATES - num_rates));
- for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask(priv, network->mode,
- network->rates_ex[i])) {
- if (network->rates_ex[i] & LIBIPW_BASIC_RATE_MASK) {
- IPW_DEBUG_SCAN("Adding masked mandatory "
- "rate %02X\n",
- network->rates_ex[i]);
- rates->supported_rates[rates->num_rates++] =
- network->rates[i];
- continue;
- }
-
- IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
- network->rates_ex[i], priv->rates_mask);
- continue;
- }
-
- rates->supported_rates[rates->num_rates++] =
- network->rates_ex[i];
- }
-
- return 1;
-}
-
-static void ipw_copy_rates(struct ipw_supported_rates *dest,
- const struct ipw_supported_rates *src)
-{
- u8 i;
- for (i = 0; i < src->num_rates; i++)
- dest->supported_rates[i] = src->supported_rates[i];
- dest->num_rates = src->num_rates;
-}
-
-/* TODO: Look at sniffed packets in the air to determine if the basic rate
- * mask should ever be used -- right now all callers to add the scan rates are
- * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */
-static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates,
- u8 modulation, u32 rate_mask)
-{
- u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
- LIBIPW_BASIC_RATE_MASK : 0;
-
- if (rate_mask & LIBIPW_CCK_RATE_1MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_1MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_2MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_2MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_5MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_CCK_RATE_5MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_11MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_CCK_RATE_11MB;
-}
-
-static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates,
- u8 modulation, u32 rate_mask)
-{
- u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
- LIBIPW_BASIC_RATE_MASK : 0;
-
- if (rate_mask & LIBIPW_OFDM_RATE_6MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_6MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_9MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_9MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_12MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_12MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_18MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_18MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_24MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_24MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_36MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_36MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_48MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_48MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_54MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_54MB;
-}
-
-struct ipw_network_match {
- struct libipw_network *network;
- struct ipw_supported_rates rates;
-};
-
-static int ipw_find_adhoc_network(struct ipw_priv *priv,
- struct ipw_network_match *match,
- struct libipw_network *network,
- int roaming)
-{
- struct ipw_supported_rates rates;
-
- /* Verify that this network's capability is compatible with the
- * current mode (AdHoc or Infrastructure) */
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
- !(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (unlikely(roaming)) {
- /* If we are roaming, then ensure check if this is a valid
- * network to try and roam to */
- if ((network->ssid_len != match->network->ssid_len) ||
- memcmp(network->ssid, match->network->ssid,
- network->ssid_len)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
- } else {
- /* If an ESSID has been configured then compare the broadcast
- * ESSID to ours */
- if ((priv->config & CFG_STATIC_ESSID) &&
- ((network->ssid_len != priv->essid_len) ||
- memcmp(network->ssid, priv->essid,
- min(network->ssid_len, priv->essid_len)))) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->essid_len,
- priv->essid);
- return 0;
- }
- }
-
- /* If the old network rate is better than this one, don't bother
- * testing everything else. */
-
- if (network->time_stamp[0] < match->network->time_stamp[0]) {
- IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
- match->network->ssid_len, match->network->ssid);
- return 0;
- } else if (network->time_stamp[1] < match->network->time_stamp[1]) {
- IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
- match->network->ssid_len, match->network->ssid);
- return 0;
- }
-
- /* Now go through and see if the requested network is valid... */
- if (priv->ieee->scan_age != 0 &&
- time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of age: %ums.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_scanned));
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_CHANNEL) &&
- (network->channel != priv->channel)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- network->channel, priv->channel);
- return 0;
- }
-
- /* Verify privacy compatibility */
- if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
- ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- priv->
- capability & CAP_PRIVACY_ON ? "on" : "off",
- network->
- capability & WLAN_CAPABILITY_PRIVACY ? "on" :
- "off");
- return 0;
- }
-
- if (ether_addr_equal(network->bssid, priv->bssid)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of the same BSSID match: %pM.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->bssid);
- return 0;
- }
-
- /* Filter out any incompatible freq / mode combinations */
- if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Ensure that the rates supported by the driver are compatible with
- * this AP, including verification of basic rates (mandatory) */
- if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (rates.num_rates == 0) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* TODO: Perform any further minimal comparititive tests. We do not
- * want to put too much policy logic here; intelligent scan selection
- * should occur within a generic IEEE 802.11 user space tool. */
-
- /* Set up 'new' AP to this network */
- ipw_copy_rates(&match->rates, &rates);
- match->network = network;
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' is a viable match.\n",
- network->ssid_len, network->ssid, network->bssid);
-
- return 1;
-}
-
-static void ipw_merge_adhoc_network(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, merge_networks);
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = priv->assoc_network
- };
-
- if ((priv->status & STATUS_ASSOCIATED) &&
- (priv->ieee->iw_mode == IW_MODE_ADHOC)) {
- /* First pass through ROAM process -- look for a better
- * network */
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list) {
- if (network != priv->assoc_network)
- ipw_find_adhoc_network(priv, &match, network,
- 1);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (match.network == priv->assoc_network) {
- IPW_DEBUG_MERGE("No better ADHOC in this network to "
- "merge to.\n");
- return;
- }
-
- mutex_lock(&priv->mutex);
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- IPW_DEBUG_MERGE("remove network %*pE\n",
- priv->essid_len, priv->essid);
- ipw_remove_current_network(priv);
- }
-
- ipw_disassociate(priv);
- priv->assoc_network = match.network;
- mutex_unlock(&priv->mutex);
- return;
- }
-}
-
-static int ipw_best_network(struct ipw_priv *priv,
- struct ipw_network_match *match,
- struct libipw_network *network, int roaming)
-{
- struct ipw_supported_rates rates;
-
- /* Verify that this network's capability is compatible with the
- * current mode (AdHoc or Infrastructure) */
- if ((priv->ieee->iw_mode == IW_MODE_INFRA &&
- !(network->capability & WLAN_CAPABILITY_ESS)) ||
- (priv->ieee->iw_mode == IW_MODE_ADHOC &&
- !(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (unlikely(roaming)) {
- /* If we are roaming, then ensure check if this is a valid
- * network to try and roam to */
- if ((network->ssid_len != match->network->ssid_len) ||
- memcmp(network->ssid, match->network->ssid,
- network->ssid_len)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
- } else {
- /* If an ESSID has been configured then compare the broadcast
- * ESSID to ours */
- if ((priv->config & CFG_STATIC_ESSID) &&
- ((network->ssid_len != priv->essid_len) ||
- memcmp(network->ssid, priv->essid,
- min(network->ssid_len, priv->essid_len)))) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->essid_len,
- priv->essid);
- return 0;
- }
- }
-
- /* If the old network rate is better than this one, don't bother
- * testing everything else. */
- if (match->network && match->network->stats.rssi > network->stats.rssi) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because '%*pE (%pM)' has a stronger signal.\n",
- network->ssid_len, network->ssid,
- network->bssid, match->network->ssid_len,
- match->network->ssid, match->network->bssid);
- return 0;
- }
-
- /* If this network has already had an association attempt within the
- * last 3 seconds, do not try and associate again... */
- if (network->last_associate &&
- time_after(network->last_associate + (HZ * 3UL), jiffies)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of storming (%ums since last assoc attempt).\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_associate));
- return 0;
- }
-
- /* Now go through and see if the requested network is valid... */
- if (priv->ieee->scan_age != 0 &&
- time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of age: %ums.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_scanned));
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_CHANNEL) &&
- (network->channel != priv->channel)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- network->channel, priv->channel);
- return 0;
- }
-
- /* Verify privacy compatibility */
- if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
- ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- priv->capability & CAP_PRIVACY_ON ? "on" :
- "off",
- network->capability &
- WLAN_CAPABILITY_PRIVACY ? "on" : "off");
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_BSSID) &&
- !ether_addr_equal(network->bssid, priv->bssid)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of BSSID mismatch: %pM.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->bssid);
- return 0;
- }
-
- /* Filter out any incompatible freq / mode combinations */
- if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Filter out invalid channel in current GEO */
- if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid channel in current GEO\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Ensure that the rates supported by the driver are compatible with
- * this AP, including verification of basic rates (mandatory) */
- if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (rates.num_rates == 0) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* TODO: Perform any further minimal comparititive tests. We do not
- * want to put too much policy logic here; intelligent scan selection
- * should occur within a generic IEEE 802.11 user space tool. */
-
- /* Set up 'new' AP to this network */
- ipw_copy_rates(&match->rates, &rates);
- match->network = network;
-
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' is a viable match.\n",
- network->ssid_len, network->ssid, network->bssid);
-
- return 1;
-}
-
-static void ipw_adhoc_create(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int i;
-
- /*
- * For the purposes of scanning, we can set our wireless mode
- * to trigger scans across combinations of bands, but when it
- * comes to creating a new ad-hoc network, we have tell the FW
- * exactly which band to use.
- *
- * We also have the possibility of an invalid channel for the
- * chossen band. Attempting to create a new ad-hoc network
- * with an invalid channel for wireless mode will trigger a
- * FW fatal error.
- *
- */
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- network->mode = IEEE_A;
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_WARNING("Overriding invalid channel\n");
- priv->channel = geo->a[0].channel;
- }
- break;
-
- case LIBIPW_24GHZ_BAND:
- if (priv->ieee->mode & IEEE_G)
- network->mode = IEEE_G;
- else
- network->mode = IEEE_B;
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_WARNING("Overriding invalid channel\n");
- priv->channel = geo->bg[0].channel;
- }
- break;
-
- default:
- IPW_WARNING("Overriding invalid channel\n");
- if (priv->ieee->mode & IEEE_A) {
- network->mode = IEEE_A;
- priv->channel = geo->a[0].channel;
- } else if (priv->ieee->mode & IEEE_G) {
- network->mode = IEEE_G;
- priv->channel = geo->bg[0].channel;
- } else {
- network->mode = IEEE_B;
- priv->channel = geo->bg[0].channel;
- }
- break;
- }
-
- network->channel = priv->channel;
- priv->config |= CFG_ADHOC_PERSIST;
- ipw_create_bssid(priv, network->bssid);
- network->ssid_len = priv->essid_len;
- memcpy(network->ssid, priv->essid, priv->essid_len);
- memset(&network->stats, 0, sizeof(network->stats));
- network->capability = WLAN_CAPABILITY_IBSS;
- if (!(priv->config & CFG_PREAMBLE_LONG))
- network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
- if (priv->capability & CAP_PRIVACY_ON)
- network->capability |= WLAN_CAPABILITY_PRIVACY;
- network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH);
- memcpy(network->rates, priv->rates.supported_rates, network->rates_len);
- network->rates_ex_len = priv->rates.num_rates - network->rates_len;
- memcpy(network->rates_ex,
- &priv->rates.supported_rates[network->rates_len],
- network->rates_ex_len);
- network->last_scanned = 0;
- network->flags = 0;
- network->last_associate = 0;
- network->time_stamp[0] = 0;
- network->time_stamp[1] = 0;
- network->beacon_interval = 100; /* Default */
- network->listen_interval = 10; /* Default */
- network->atim_window = 0; /* Default */
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-}
-
-static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
-{
- struct ipw_tgi_tx_key key;
-
- if (!(priv->ieee->sec.flags & (1 << index)))
- return;
-
- key.key_id = index;
- memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH);
- key.security_type = type;
- key.station_index = 0; /* always 0 for BSS */
- key.flags = 0;
- /* 0 for new key; previous value of counter (after fatal error) */
- key.tx_counter[0] = cpu_to_le32(0);
- key.tx_counter[1] = cpu_to_le32(0);
-
- ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key);
-}
-
-static void ipw_send_wep_keys(struct ipw_priv *priv, int type)
-{
- struct ipw_wep_key key;
- int i;
-
- key.cmd_id = DINO_CMD_WEP_KEY;
- key.seq_num = 0;
-
- /* Note: AES keys cannot be set for multiple times.
- * Only set it at the first time. */
- for (i = 0; i < 4; i++) {
- key.key_index = i | type;
- if (!(priv->ieee->sec.flags & (1 << i))) {
- key.key_size = 0;
- continue;
- }
-
- key.key_size = priv->ieee->sec.key_sizes[i];
- memcpy(key.key, priv->ieee->sec.keys[i], key.key_size);
-
- ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key);
- }
-}
-
-static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level)
-{
- if (priv->ieee->host_encrypt)
- return;
-
- switch (level) {
- case SEC_LEVEL_3:
- priv->sys_config.disable_unicast_decryption = 0;
- priv->ieee->host_decrypt = 0;
- break;
- case SEC_LEVEL_2:
- priv->sys_config.disable_unicast_decryption = 1;
- priv->ieee->host_decrypt = 1;
- break;
- case SEC_LEVEL_1:
- priv->sys_config.disable_unicast_decryption = 0;
- priv->ieee->host_decrypt = 0;
- break;
- case SEC_LEVEL_0:
- priv->sys_config.disable_unicast_decryption = 1;
- break;
- default:
- break;
- }
-}
-
-static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level)
-{
- if (priv->ieee->host_encrypt)
- return;
-
- switch (level) {
- case SEC_LEVEL_3:
- priv->sys_config.disable_multicast_decryption = 0;
- break;
- case SEC_LEVEL_2:
- priv->sys_config.disable_multicast_decryption = 1;
- break;
- case SEC_LEVEL_1:
- priv->sys_config.disable_multicast_decryption = 0;
- break;
- case SEC_LEVEL_0:
- priv->sys_config.disable_multicast_decryption = 1;
- break;
- default:
- break;
- }
-}
-
-static void ipw_set_hwcrypto_keys(struct ipw_priv *priv)
-{
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
- ipw_send_tgi_tx_key(priv,
- DCT_FLAG_EXT_SECURITY_CCM,
- priv->ieee->sec.active_key);
-
- if (!priv->ieee->host_mc_decrypt)
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM);
- break;
- case SEC_LEVEL_2:
- if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
- ipw_send_tgi_tx_key(priv,
- DCT_FLAG_EXT_SECURITY_TKIP,
- priv->ieee->sec.active_key);
- break;
- case SEC_LEVEL_1:
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
- ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level);
- ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level);
- break;
- case SEC_LEVEL_0:
- default:
- break;
- }
-}
-
-static void ipw_adhoc_check(void *data)
-{
- struct ipw_priv *priv = data;
-
- if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold &&
- !(priv->config & CFG_ADHOC_PERSIST)) {
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE | IPW_DL_ASSOC,
- "Missed beacon: %d - disassociate\n",
- priv->missed_adhoc_beacons);
- ipw_remove_current_network(priv);
- ipw_disassociate(priv);
- return;
- }
-
- schedule_delayed_work(&priv->adhoc_check,
- le16_to_cpu(priv->assoc_request.beacon_interval));
-}
-
-static void ipw_bg_adhoc_check(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, adhoc_check.work);
- mutex_lock(&priv->mutex);
- ipw_adhoc_check(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_debug_config(struct ipw_priv *priv)
-{
- IPW_DEBUG_INFO("Scan completed, no valid APs matched "
- "[CFG 0x%08X]\n", priv->config);
- if (priv->config & CFG_STATIC_CHANNEL)
- IPW_DEBUG_INFO("Channel locked to %d\n", priv->channel);
- else
- IPW_DEBUG_INFO("Channel unlocked.\n");
- if (priv->config & CFG_STATIC_ESSID)
- IPW_DEBUG_INFO("ESSID locked to '%*pE'\n",
- priv->essid_len, priv->essid);
- else
- IPW_DEBUG_INFO("ESSID unlocked.\n");
- if (priv->config & CFG_STATIC_BSSID)
- IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid);
- else
- IPW_DEBUG_INFO("BSSID unlocked.\n");
- if (priv->capability & CAP_PRIVACY_ON)
- IPW_DEBUG_INFO("PRIVACY on\n");
- else
- IPW_DEBUG_INFO("PRIVACY off\n");
- IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
-}
-
-static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
-{
- /* TODO: Verify that this works... */
- struct ipw_fixed_rate fr;
- u32 reg;
- u16 mask = 0;
- u16 new_tx_rates = priv->rates_mask;
-
- /* Identify 'current FW band' and match it with the fixed
- * Tx rates */
-
- switch (priv->ieee->freq_band) {
- case LIBIPW_52GHZ_BAND: /* A only */
- /* IEEE_A */
- if (priv->rates_mask & ~LIBIPW_OFDM_RATES_MASK) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- break;
- }
-
- new_tx_rates >>= LIBIPW_OFDM_SHIFT_MASK_A;
- break;
-
- default: /* 2.4Ghz or Mixed */
- /* IEEE_B */
- if (mode == IEEE_B) {
- if (new_tx_rates & ~LIBIPW_CCK_RATES_MASK) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- }
- break;
- }
-
- /* IEEE_G */
- if (new_tx_rates & ~(LIBIPW_CCK_RATES_MASK |
- LIBIPW_OFDM_RATES_MASK)) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- break;
- }
-
- if (LIBIPW_OFDM_RATE_6MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_6MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_6MB_MASK;
- }
-
- if (LIBIPW_OFDM_RATE_9MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_9MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_9MB_MASK;
- }
-
- if (LIBIPW_OFDM_RATE_12MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_12MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_12MB_MASK;
- }
-
- new_tx_rates |= mask;
- break;
- }
-
- fr.tx_rates = cpu_to_le16(new_tx_rates);
-
- reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE);
- ipw_write_reg32(priv, reg, *(u32 *) & fr);
-}
-
-static void ipw_abort_scan(struct ipw_priv *priv)
-{
- int err;
-
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
- return;
- }
- priv->status |= STATUS_SCAN_ABORTING;
-
- err = ipw_send_scan_abort(priv);
- if (err)
- IPW_DEBUG_HC("Request to abort scan failed.\n");
-}
-
-static void ipw_add_scan_channels(struct ipw_priv *priv,
- struct ipw_scan_request_ext *scan,
- int scan_type)
-{
- int channel_index = 0;
- const struct libipw_geo *geo;
- int i;
-
- geo = libipw_get_geo(priv->ieee);
-
- if (priv->ieee->freq_band & LIBIPW_52GHZ_BAND) {
- int start = channel_index;
- for (i = 0; i < geo->a_channels; i++) {
- if ((priv->status & STATUS_ASSOCIATED) &&
- geo->a[i].channel == priv->channel)
- continue;
- channel_index++;
- scan->channels_list[channel_index] = geo->a[i].channel;
- ipw_set_scan_type(scan, channel_index,
- geo->a[i].
- flags & LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN :
- scan_type);
- }
-
- if (start != channel_index) {
- scan->channels_list[start] = (u8) (IPW_A_MODE << 6) |
- (channel_index - start);
- channel_index++;
- }
- }
-
- if (priv->ieee->freq_band & LIBIPW_24GHZ_BAND) {
- int start = channel_index;
- if (priv->config & CFG_SPEED_SCAN) {
- int index;
- u8 channels[LIBIPW_24GHZ_CHANNELS] = {
- /* nop out the list */
- [0] = 0
- };
-
- u8 channel;
- while (channel_index < IPW_SCAN_CHANNELS - 1) {
- channel =
- priv->speed_scan[priv->speed_scan_pos];
- if (channel == 0) {
- priv->speed_scan_pos = 0;
- channel = priv->speed_scan[0];
- }
- if ((priv->status & STATUS_ASSOCIATED) &&
- channel == priv->channel) {
- priv->speed_scan_pos++;
- continue;
- }
-
- /* If this channel has already been
- * added in scan, break from loop
- * and this will be the first channel
- * in the next scan.
- */
- if (channels[channel - 1] != 0)
- break;
-
- channels[channel - 1] = 1;
- priv->speed_scan_pos++;
- channel_index++;
- scan->channels_list[channel_index] = channel;
- index =
- libipw_channel_to_index(priv->ieee, channel);
- ipw_set_scan_type(scan, channel_index,
- geo->bg[index].
- flags &
- LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
- : scan_type);
- }
- } else {
- for (i = 0; i < geo->bg_channels; i++) {
- if ((priv->status & STATUS_ASSOCIATED) &&
- geo->bg[i].channel == priv->channel)
- continue;
- channel_index++;
- scan->channels_list[channel_index] =
- geo->bg[i].channel;
- ipw_set_scan_type(scan, channel_index,
- geo->bg[i].
- flags &
- LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
- : scan_type);
- }
- }
-
- if (start != channel_index) {
- scan->channels_list[start] = (u8) (IPW_B_MODE << 6) |
- (channel_index - start);
- }
- }
-}
-
-static int ipw_passive_dwell_time(struct ipw_priv *priv)
-{
- /* staying on passive channels longer than the DTIM interval during a
- * scan, while associated, causes the firmware to cancel the scan
- * without notification. Hence, don't stay on passive channels longer
- * than the beacon interval.
- */
- if (priv->status & STATUS_ASSOCIATED
- && priv->assoc_network->beacon_interval > 10)
- return priv->assoc_network->beacon_interval - 10;
- else
- return 120;
-}
-
-static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
-{
- struct ipw_scan_request_ext scan;
- int err = 0, scan_type;
-
- if (!(priv->status & STATUS_INIT) ||
- (priv->status & STATUS_EXIT_PENDING))
- return 0;
-
- mutex_lock(&priv->mutex);
-
- if (direct && (priv->direct_scan_ssid_len == 0)) {
- IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n");
- priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
- goto done;
- }
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- if (!(priv->status & STATUS_SCAN_FORCED) &&
- priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- if (priv->status & STATUS_RF_KILL_MASK) {
- IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- memset(&scan, 0, sizeof(scan));
- scan.full_scan_index = cpu_to_le32(libipw_get_scans(priv->ieee));
-
- if (type == IW_SCAN_TYPE_PASSIVE) {
- IPW_DEBUG_WX("use passive scanning\n");
- scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(ipw_passive_dwell_time(priv));
- ipw_add_scan_channels(priv, &scan, scan_type);
- goto send_request;
- }
-
- /* Use active scan by default. */
- if (priv->config & CFG_SPEED_SCAN)
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(30);
- else
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(20);
-
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
- cpu_to_le16(20);
-
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(ipw_passive_dwell_time(priv));
- scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- u8 channel;
- u8 band = 0;
-
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- band = (u8) (IPW_A_MODE << 6) | 1;
- channel = priv->channel;
- break;
-
- case LIBIPW_24GHZ_BAND:
- band = (u8) (IPW_B_MODE << 6) | 1;
- channel = priv->channel;
- break;
-
- default:
- band = (u8) (IPW_B_MODE << 6) | 1;
- channel = 9;
- break;
- }
-
- scan.channels_list[0] = band;
- scan.channels_list[1] = channel;
- ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN);
-
- /* NOTE: The card will sit on this channel for this time
- * period. Scan aborts are timing sensitive and frequently
- * result in firmware restarts. As such, it is best to
- * set a small dwell_time here and just keep re-issuing
- * scans. Otherwise fast channel hopping will not actually
- * hop channels.
- *
- * TODO: Move SPEED SCAN support to all modes and bands */
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(2000);
- } else {
-#endif /* CONFIG_IPW2200_MONITOR */
- /* Honor direct scans first, otherwise if we are roaming make
- * this a direct scan for the current network. Finally,
- * ensure that every other scan is a fast channel hop scan */
- if (direct) {
- err = ipw_send_ssid(priv, priv->direct_scan_ssid,
- priv->direct_scan_ssid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command "
- "failed\n");
- goto done;
- }
-
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
- } else if ((priv->status & STATUS_ROAMING)
- || (!(priv->status & STATUS_ASSOCIATED)
- && (priv->config & CFG_STATIC_ESSID)
- && (le32_to_cpu(scan.full_scan_index) % 2))) {
- err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command "
- "failed.\n");
- goto done;
- }
-
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
- } else
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
-
- ipw_add_scan_channels(priv, &scan, scan_type);
-#ifdef CONFIG_IPW2200_MONITOR
- }
-#endif
-
-send_request:
- err = ipw_send_scan_request_ext(priv, &scan);
- if (err) {
- IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
- goto done;
- }
-
- priv->status |= STATUS_SCANNING;
- if (direct) {
- priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
- priv->direct_scan_ssid_len = 0;
- } else
- priv->status &= ~STATUS_SCAN_PENDING;
-
- schedule_delayed_work(&priv->scan_check, IPW_SCAN_CHECK_WATCHDOG);
-done:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static void ipw_request_passive_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_passive_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0);
-}
-
-static void ipw_request_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0);
-}
-
-static void ipw_request_direct_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_direct_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1);
-}
-
-static void ipw_bg_abort_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, abort_scan);
- mutex_lock(&priv->mutex);
- ipw_abort_scan(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_wpa_enable(struct ipw_priv *priv, int value)
-{
- /* This is called when wpa_supplicant loads and closes the driver
- * interface. */
- priv->ieee->wpa_enabled = value;
- return 0;
-}
-
-static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value)
-{
- struct libipw_device *ieee = priv->ieee;
- struct libipw_security sec = {
- .flags = SEC_AUTH_MODE,
- };
- int ret = 0;
-
- if (value & IW_AUTH_ALG_SHARED_KEY) {
- sec.auth_mode = WLAN_AUTH_SHARED_KEY;
- ieee->open_wep = 0;
- } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
- sec.auth_mode = WLAN_AUTH_OPEN;
- ieee->open_wep = 1;
- } else if (value & IW_AUTH_ALG_LEAP) {
- sec.auth_mode = WLAN_AUTH_LEAP;
- ieee->open_wep = 1;
- } else
- return -EINVAL;
-
- if (ieee->set_security)
- ieee->set_security(ieee->dev, &sec);
- else
- ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie,
- int wpa_ie_len)
-{
- /* make sure WPA is enabled */
- ipw_wpa_enable(priv, 1);
-}
-
-static int ipw_set_rsn_capa(struct ipw_priv *priv,
- char *capabilities, int length)
-{
- IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n");
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length,
- capabilities);
-}
-
-/*
- * WE-18 support
- */
-
-/* SIOCSIWGENIE */
-static int ipw_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- u8 *buf;
- int err = 0;
-
- if (wrqu->data.length > MAX_WPA_IE_LEN ||
- (wrqu->data.length && extra == NULL))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = buf;
- ieee->wpa_ie_len = wrqu->data.length;
- } else {
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = NULL;
- ieee->wpa_ie_len = 0;
- }
-
- ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
- out:
- return err;
-}
-
-/* SIOCGIWGENIE */
-static int ipw_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- int err = 0;
-
- if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
- wrqu->data.length = 0;
- goto out;
- }
-
- if (wrqu->data.length < ieee->wpa_ie_len) {
- err = -E2BIG;
- goto out;
- }
-
- wrqu->data.length = ieee->wpa_ie_len;
- memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
-
- out:
- return err;
-}
-
-static int wext_cipher2level(int cipher)
-{
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- return SEC_LEVEL_0;
- case IW_AUTH_CIPHER_WEP40:
- case IW_AUTH_CIPHER_WEP104:
- return SEC_LEVEL_1;
- case IW_AUTH_CIPHER_TKIP:
- return SEC_LEVEL_2;
- case IW_AUTH_CIPHER_CCMP:
- return SEC_LEVEL_3;
- default:
- return -1;
- }
-}
-
-/* SIOCSIWAUTH */
-static int ipw_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
- unsigned long flags;
- int ret = 0;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- ipw_set_hw_decrypt_unicast(priv,
- wext_cipher2level(param->value));
- break;
- case IW_AUTH_CIPHER_GROUP:
- ipw_set_hw_decrypt_multicast(priv,
- wext_cipher2level(param->value));
- break;
- case IW_AUTH_KEY_MGMT:
- /*
- * ipw2200 does not use these parameters
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
- break;
-
- flags = crypt->ops->get_flags(crypt->priv);
-
- if (param->value)
- flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
- else
- flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
-
- crypt->ops->set_flags(flags, crypt->priv);
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:{
- /* HACK:
- *
- * wpa_supplicant calls set_wpa_enabled when the driver
- * is loaded and unloaded, regardless of if WPA is being
- * used. No other calls are made which can be used to
- * determine if encryption will be used or not prior to
- * association being expected. If encryption is not being
- * used, drop_unencrypted is set to false, else true -- we
- * can use this to determine if the CAP_PRIVACY_ON bit should
- * be set.
- */
- struct libipw_security sec = {
- .flags = SEC_ENABLED,
- .enabled = param->value,
- };
- priv->ieee->drop_unencrypted = param->value;
- /* We only change SEC_LEVEL for open mode. Others
- * are set by ipw_wpa_set_encryption.
- */
- if (!param->value) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_0;
- } else {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- }
- if (priv->ieee->set_security)
- priv->ieee->set_security(priv->ieee->dev, &sec);
- break;
- }
-
- case IW_AUTH_80211_AUTH_ALG:
- ret = ipw_wpa_set_auth_algs(priv, param->value);
- break;
-
- case IW_AUTH_WPA_ENABLED:
- ret = ipw_wpa_enable(priv, param->value);
- ipw_disassociate(priv);
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = param->value;
- break;
-
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = param->value;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return ret;
-}
-
-/* SIOCGIWAUTH */
-static int ipw_wx_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * wpa_supplicant will control these internally
- */
- return -EOPNOTSUPP;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->get_flags)
- break;
-
- param->value = (crypt->ops->get_flags(crypt->priv) &
- IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value = ieee->drop_unencrypted;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- param->value = ieee->sec.auth_mode;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = ieee->wpa_enabled;
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- param->value = ieee->ieee802_1x;
- break;
-
- case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- param->value = ieee->privacy_invoked;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/* SIOCSIWENCODEEXT */
-static int ipw_wx_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-
- if (hwcrypto) {
- if (ext->alg == IW_ENCODE_ALG_TKIP) {
- /* IPW HW can't build TKIP MIC,
- host decryption still needed */
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
- priv->ieee->host_mc_decrypt = 1;
- else {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 1;
- priv->ieee->host_decrypt = 1;
- }
- } else {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 0;
- priv->ieee->host_decrypt = 0;
- priv->ieee->host_mc_decrypt = 0;
- }
- }
-
- return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCGIWENCODEEXT */
-static int ipw_wx_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCSIWMLME */
-static int ipw_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- /* silently ignore */
- break;
-
- case IW_MLME_DISASSOC:
- ipw_disassociate(priv);
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_QOS
-
-/* QoS */
-/*
-* get the modulation type of the current network or
-* the card current mode
-*/
-static u8 ipw_qos_current_mode(struct ipw_priv * priv)
-{
- u8 mode = 0;
-
- if (priv->status & STATUS_ASSOCIATED) {
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- mode = priv->assoc_network->mode;
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
- } else {
- mode = priv->ieee->mode;
- }
- IPW_DEBUG_QOS("QoS network/card mode %d\n", mode);
- return mode;
-}
-
-/*
-* Handle management frame beacon and probe response
-*/
-static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
- int active_network,
- struct libipw_network *network)
-{
- u32 size = sizeof(struct libipw_qos_parameters);
-
- if (network->capability & WLAN_CAPABILITY_IBSS)
- network->qos_data.active = network->qos_data.supported;
-
- if (network->flags & NETWORK_HAS_QOS_MASK) {
- if (active_network &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS))
- network->qos_data.active = network->qos_data.supported;
-
- if ((network->qos_data.active == 1) && (active_network == 1) &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS) &&
- (network->qos_data.old_param_count !=
- network->qos_data.param_count)) {
- network->qos_data.old_param_count =
- network->qos_data.param_count;
- schedule_work(&priv->qos_activate);
- IPW_DEBUG_QOS("QoS parameters change call "
- "qos_activate\n");
- }
- } else {
- if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B))
- memcpy(&network->qos_data.parameters,
- &def_parameters_CCK, size);
- else
- memcpy(&network->qos_data.parameters,
- &def_parameters_OFDM, size);
-
- if ((network->qos_data.active == 1) && (active_network == 1)) {
- IPW_DEBUG_QOS("QoS was disabled call qos_activate\n");
- schedule_work(&priv->qos_activate);
- }
-
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- }
- if ((priv->status & STATUS_ASSOCIATED) &&
- (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) {
- if (!ether_addr_equal(network->bssid, priv->bssid))
- if (network->capability & WLAN_CAPABILITY_IBSS)
- if ((network->ssid_len ==
- priv->assoc_network->ssid_len) &&
- !memcmp(network->ssid,
- priv->assoc_network->ssid,
- network->ssid_len)) {
- schedule_work(&priv->merge_networks);
- }
- }
-
- return 0;
-}
-
-/*
-* This function set up the firmware to support QoS. It sends
-* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO
-*/
-static int ipw_qos_activate(struct ipw_priv *priv,
- struct libipw_qos_data *qos_network_data)
-{
- int err;
- struct libipw_qos_parameters qos_parameters[QOS_QOS_SETS];
- struct libipw_qos_parameters *active_one = NULL;
- u32 size = sizeof(struct libipw_qos_parameters);
- u32 burst_duration;
- int i;
- u8 type;
-
- type = ipw_qos_current_mode(priv);
-
- active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]);
- memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size);
- active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]);
- memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size);
-
- if (qos_network_data == NULL) {
- if (type == IEEE_B) {
- IPW_DEBUG_QOS("QoS activate network mode %d\n", type);
- active_one = &def_parameters_CCK;
- } else
- active_one = &def_parameters_OFDM;
-
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- burst_duration = ipw_qos_get_burst_duration(priv);
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
- cpu_to_le16(burst_duration);
- } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (type == IEEE_B) {
- IPW_DEBUG_QOS("QoS activate IBSS network mode %d\n",
- type);
- if (priv->qos_data.qos_enable == 0)
- active_one = &def_parameters_CCK;
- else
- active_one = priv->qos_data.def_qos_parm_CCK;
- } else {
- if (priv->qos_data.qos_enable == 0)
- active_one = &def_parameters_OFDM;
- else
- active_one = priv->qos_data.def_qos_parm_OFDM;
- }
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- } else {
- unsigned long flags;
- int active;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- active_one = &(qos_network_data->parameters);
- qos_network_data->old_param_count =
- qos_network_data->param_count;
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- active = qos_network_data->supported;
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (active == 0) {
- burst_duration = ipw_qos_get_burst_duration(priv);
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- qos_parameters[QOS_PARAM_SET_ACTIVE].
- tx_op_limit[i] = cpu_to_le16(burst_duration);
- }
- }
-
- IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
- err = ipw_send_qos_params_command(priv, &qos_parameters[0]);
- if (err)
- IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n");
-
- return err;
-}
-
-/*
-* send IPW_CMD_WME_INFO to the firmware
-*/
-static int ipw_qos_set_info_element(struct ipw_priv *priv)
-{
- int ret = 0;
- struct libipw_qos_information_element qos_info;
-
- if (priv == NULL)
- return -1;
-
- qos_info.elementID = QOS_ELEMENT_ID;
- qos_info.length = sizeof(struct libipw_qos_information_element) - 2;
-
- qos_info.version = QOS_VERSION_1;
- qos_info.ac_info = 0;
-
- memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN);
- qos_info.qui_type = QOS_OUI_TYPE;
- qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE;
-
- ret = ipw_send_qos_info_command(priv, &qos_info);
- if (ret != 0) {
- IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n");
- }
- return ret;
-}
-
-/*
-* Set the QoS parameter with the association request structure
-*/
-static int ipw_qos_association(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- int err = 0;
- struct libipw_qos_data *qos_data = NULL;
- struct libipw_qos_data ibss_data = {
- .supported = 1,
- .active = 1,
- };
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS));
-
- qos_data = &ibss_data;
- break;
-
- case IW_MODE_INFRA:
- qos_data = &network->qos_data;
- break;
-
- default:
- BUG();
- break;
- }
-
- err = ipw_qos_activate(priv, qos_data);
- if (err) {
- priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC;
- return err;
- }
-
- if (priv->qos_data.qos_enable && qos_data->supported) {
- IPW_DEBUG_QOS("QoS will be enabled for this association\n");
- priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC;
- return ipw_qos_set_info_element(priv);
- }
-
- return 0;
-}
-
-/*
-* handling the beaconing responses. if we get different QoS setting
-* off the network from the associated setting, adjust the QoS
-* setting
-*/
-static void ipw_qos_association_resp(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- unsigned long flags;
- u32 size = sizeof(struct libipw_qos_parameters);
- int set_qos_param = 0;
-
- if ((priv == NULL) || (network == NULL) ||
- (priv->assoc_network == NULL))
- return;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return;
-
- if ((priv->ieee->iw_mode != IW_MODE_INFRA))
- return;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- if (network->flags & NETWORK_HAS_QOS_PARAMETERS) {
- memcpy(&priv->assoc_network->qos_data, &network->qos_data,
- sizeof(struct libipw_qos_data));
- priv->assoc_network->qos_data.active = 1;
- if ((network->qos_data.old_param_count !=
- network->qos_data.param_count)) {
- set_qos_param = 1;
- network->qos_data.old_param_count =
- network->qos_data.param_count;
- }
-
- } else {
- if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B))
- memcpy(&priv->assoc_network->qos_data.parameters,
- &def_parameters_CCK, size);
- else
- memcpy(&priv->assoc_network->qos_data.parameters,
- &def_parameters_OFDM, size);
- priv->assoc_network->qos_data.active = 0;
- priv->assoc_network->qos_data.supported = 0;
- set_qos_param = 1;
- }
-
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (set_qos_param == 1)
- schedule_work(&priv->qos_activate);
-}
-
-static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv)
-{
- u32 ret = 0;
-
- if (!priv)
- return 0;
-
- if (!(priv->ieee->modulation & LIBIPW_OFDM_MODULATION))
- ret = priv->qos_data.burst_duration_CCK;
- else
- ret = priv->qos_data.burst_duration_OFDM;
-
- return ret;
-}
-
-/*
-* Initialize the setting of QoS global
-*/
-static void ipw_qos_init(struct ipw_priv *priv, int enable,
- int burst_enable, u32 burst_duration_CCK,
- u32 burst_duration_OFDM)
-{
- priv->qos_data.qos_enable = enable;
-
- if (priv->qos_data.qos_enable) {
- priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK;
- priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM;
- IPW_DEBUG_QOS("QoS is enabled\n");
- } else {
- priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK;
- priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM;
- IPW_DEBUG_QOS("QoS is not enabled\n");
- }
-
- priv->qos_data.burst_enable = burst_enable;
-
- if (burst_enable) {
- priv->qos_data.burst_duration_CCK = burst_duration_CCK;
- priv->qos_data.burst_duration_OFDM = burst_duration_OFDM;
- } else {
- priv->qos_data.burst_duration_CCK = 0;
- priv->qos_data.burst_duration_OFDM = 0;
- }
-}
-
-/*
-* map the packet priority to the right TX Queue
-*/
-static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority)
-{
- if (priority > 7 || !priv->qos_data.qos_enable)
- priority = 0;
-
- return from_priority_to_tx_queue[priority] - 1;
-}
-
-static int ipw_is_qos_active(struct net_device *dev,
- struct sk_buff *skb)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_qos_data *qos_data = NULL;
- int active, supported;
- u8 *daddr = skb->data + ETH_ALEN;
- int unicast = !is_multicast_ether_addr(daddr);
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return 0;
-
- qos_data = &priv->assoc_network->qos_data;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (unicast == 0)
- qos_data->active = 0;
- else
- qos_data->active = qos_data->supported;
- }
- active = qos_data->active;
- supported = qos_data->supported;
- IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d "
- "unicast %d\n",
- priv->qos_data.qos_enable, active, supported, unicast);
- if (active && priv->qos_data.qos_enable)
- return 1;
-
- return 0;
-
-}
-/*
-* add QoS parameter to the TX command
-*/
-static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
- u16 priority,
- struct tfd_data *tfd)
-{
- int tx_queue_id = 0;
-
-
- tx_queue_id = from_priority_to_tx_queue[priority] - 1;
- tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED;
-
- if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) {
- tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
- tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK);
- }
- return 0;
-}
-
-/*
-* background support to run QoS activate functionality
-*/
-static void ipw_bg_qos_activate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, qos_activate);
-
- mutex_lock(&priv->mutex);
-
- if (priv->status & STATUS_ASSOCIATED)
- ipw_qos_activate(priv, &(priv->assoc_network->qos_data));
-
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_handle_probe_response(struct net_device *dev,
- struct libipw_probe_response *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int active_network = ((priv->status & STATUS_ASSOCIATED) &&
- (network == priv->assoc_network));
-
- ipw_qos_handle_probe_response(priv, active_network, network);
-
- return 0;
-}
-
-static int ipw_handle_beacon(struct net_device *dev,
- struct libipw_beacon *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int active_network = ((priv->status & STATUS_ASSOCIATED) &&
- (network == priv->assoc_network));
-
- ipw_qos_handle_probe_response(priv, active_network, network);
-
- return 0;
-}
-
-static int ipw_handle_assoc_response(struct net_device *dev,
- struct libipw_assoc_response *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- ipw_qos_association_resp(priv, network);
- return 0;
-}
-
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
- *qos_param)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS,
- sizeof(*qos_param) * 3, qos_param);
-}
-
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
- *qos_param)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param),
- qos_param);
-}
-
-#endif /* CONFIG_IPW2200_QOS */
-
-static int ipw_associate_network(struct ipw_priv *priv,
- struct libipw_network *network,
- struct ipw_supported_rates *rates, int roaming)
-{
- int err;
-
- if (priv->config & CFG_FIXED_RATE)
- ipw_set_fixed_rate(priv, network->mode);
-
- if (!(priv->config & CFG_STATIC_ESSID)) {
- priv->essid_len = min(network->ssid_len,
- (u8) IW_ESSID_MAX_SIZE);
- memcpy(priv->essid, network->ssid, priv->essid_len);
- }
-
- network->last_associate = jiffies;
-
- memset(&priv->assoc_request, 0, sizeof(priv->assoc_request));
- priv->assoc_request.channel = network->channel;
- priv->assoc_request.auth_key = 0;
-
- if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) {
- priv->assoc_request.auth_type = AUTH_SHARED_KEY;
- priv->assoc_request.auth_key = priv->ieee->sec.active_key;
-
- if (priv->ieee->sec.level == SEC_LEVEL_1)
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
-
- } else if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP))
- priv->assoc_request.auth_type = AUTH_LEAP;
- else
- priv->assoc_request.auth_type = AUTH_OPEN;
-
- if (priv->ieee->wpa_ie_len) {
- priv->assoc_request.policy_support = cpu_to_le16(0x02); /* RSN active */
- ipw_set_rsn_capa(priv, priv->ieee->wpa_ie,
- priv->ieee->wpa_ie_len);
- }
-
- /*
- * It is valid for our ieee device to support multiple modes, but
- * when it comes to associating to a given network we have to choose
- * just one mode.
- */
- if (network->mode & priv->ieee->mode & IEEE_A)
- priv->assoc_request.ieee_mode = IPW_A_MODE;
- else if (network->mode & priv->ieee->mode & IEEE_G)
- priv->assoc_request.ieee_mode = IPW_G_MODE;
- else if (network->mode & priv->ieee->mode & IEEE_B)
- priv->assoc_request.ieee_mode = IPW_B_MODE;
-
- priv->assoc_request.capability = cpu_to_le16(network->capability);
- if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
- && !(priv->config & CFG_PREAMBLE_LONG)) {
- priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE;
- } else {
- priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE;
-
- /* Clear the short preamble if we won't be supporting it */
- priv->assoc_request.capability &=
- ~cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
- }
-
- /* Clear capability bits that aren't used in Ad Hoc */
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->assoc_request.capability &=
- ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- IPW_DEBUG_ASSOC("%ssociation attempt: '%*pE', channel %d, 802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
- roaming ? "Rea" : "A",
- priv->essid_len, priv->essid,
- network->channel,
- ipw_modes[priv->assoc_request.ieee_mode],
- rates->num_rates,
- (priv->assoc_request.preamble_length ==
- DCT_FLAG_LONG_PREAMBLE) ? "long" : "short",
- network->capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long",
- priv->capability & CAP_PRIVACY_ON ? "on " : "off",
- priv->capability & CAP_PRIVACY_ON ?
- (priv->capability & CAP_SHARED_KEY ? "(shared)" :
- "(open)") : "",
- priv->capability & CAP_PRIVACY_ON ? " key=" : "",
- priv->capability & CAP_PRIVACY_ON ?
- '1' + priv->ieee->sec.active_key : '.',
- priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
-
- priv->assoc_request.beacon_interval = cpu_to_le16(network->beacon_interval);
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) {
- priv->assoc_request.assoc_type = HC_IBSS_START;
- priv->assoc_request.assoc_tsf_msw = 0;
- priv->assoc_request.assoc_tsf_lsw = 0;
- } else {
- if (unlikely(roaming))
- priv->assoc_request.assoc_type = HC_REASSOCIATE;
- else
- priv->assoc_request.assoc_type = HC_ASSOCIATE;
- priv->assoc_request.assoc_tsf_msw = cpu_to_le32(network->time_stamp[1]);
- priv->assoc_request.assoc_tsf_lsw = cpu_to_le32(network->time_stamp[0]);
- }
-
- memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN);
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- eth_broadcast_addr(priv->assoc_request.dest);
- priv->assoc_request.atim_window = cpu_to_le16(network->atim_window);
- } else {
- memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN);
- priv->assoc_request.atim_window = 0;
- }
-
- priv->assoc_request.listen_interval = cpu_to_le16(network->listen_interval);
-
- err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
- return err;
- }
-
- rates->ieee_mode = priv->assoc_request.ieee_mode;
- rates->purpose = IPW_RATE_CONNECT;
- ipw_send_supported_rates(priv, rates);
-
- if (priv->assoc_request.ieee_mode == IPW_G_MODE)
- priv->sys_config.dot11g_auto_detection = 1;
- else
- priv->sys_config.dot11g_auto_detection = 0;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->sys_config.answer_broadcast_ssid_probe = 1;
- else
- priv->sys_config.answer_broadcast_ssid_probe = 0;
-
- err = ipw_send_system_config(priv);
- if (err) {
- IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
- return err;
- }
-
- IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi);
- err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM);
- if (err) {
- IPW_DEBUG_HC("Attempt to send associate command failed.\n");
- return err;
- }
-
- /*
- * If preemption is enabled, it is possible for the association
- * to complete before we return from ipw_send_associate. Therefore
- * we have to be sure and update our priviate data first.
- */
- priv->channel = network->channel;
- memcpy(priv->bssid, network->bssid, ETH_ALEN);
- priv->status |= STATUS_ASSOCIATING;
- priv->status &= ~STATUS_SECURITY_UPDATED;
-
- priv->assoc_network = network;
-
-#ifdef CONFIG_IPW2200_QOS
- ipw_qos_association(priv, network);
-#endif
-
- err = ipw_send_associate(priv, &priv->assoc_request);
- if (err) {
- IPW_DEBUG_HC("Attempt to send associate command failed.\n");
- return err;
- }
-
- IPW_DEBUG(IPW_DL_STATE, "associating: '%*pE' %pM\n",
- priv->essid_len, priv->essid, priv->bssid);
-
- return 0;
-}
-
-static void ipw_roam(void *data)
-{
- struct ipw_priv *priv = data;
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = priv->assoc_network
- };
-
- /* The roaming process is as follows:
- *
- * 1. Missed beacon threshold triggers the roaming process by
- * setting the status ROAM bit and requesting a scan.
- * 2. When the scan completes, it schedules the ROAM work
- * 3. The ROAM work looks at all of the known networks for one that
- * is a better network than the currently associated. If none
- * found, the ROAM process is over (ROAM bit cleared)
- * 4. If a better network is found, a disassociation request is
- * sent.
- * 5. When the disassociation completes, the roam work is again
- * scheduled. The second time through, the driver is no longer
- * associated, and the newly selected network is sent an
- * association request.
- * 6. At this point ,the roaming process is complete and the ROAM
- * status bit is cleared.
- */
-
- /* If we are no longer associated, and the roaming bit is no longer
- * set, then we are not actively roaming, so just return */
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING)))
- return;
-
- if (priv->status & STATUS_ASSOCIATED) {
- /* First pass through ROAM process -- look for a better
- * network */
- unsigned long flags;
- u8 rssi = priv->assoc_network->stats.rssi;
- priv->assoc_network->stats.rssi = -128;
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list) {
- if (network != priv->assoc_network)
- ipw_best_network(priv, &match, network, 1);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
- priv->assoc_network->stats.rssi = rssi;
-
- if (match.network == priv->assoc_network) {
- IPW_DEBUG_ASSOC("No better APs in this network to "
- "roam to.\n");
- priv->status &= ~STATUS_ROAMING;
- ipw_debug_config(priv);
- return;
- }
-
- ipw_send_disassociate(priv, 1);
- priv->assoc_network = match.network;
-
- return;
- }
-
- /* Second pass through ROAM process -- request association */
- ipw_compatible_rates(priv, priv->assoc_network, &match.rates);
- ipw_associate_network(priv, priv->assoc_network, &match.rates, 1);
- priv->status &= ~STATUS_ROAMING;
-}
-
-static void ipw_bg_roam(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, roam);
- mutex_lock(&priv->mutex);
- ipw_roam(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_associate(void *data)
-{
- struct ipw_priv *priv = data;
-
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = NULL
- };
- struct ipw_supported_rates *rates;
- struct list_head *element;
- unsigned long flags;
-
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
- return 0;
- }
-
- if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_ASSOC("Not attempting association (already in "
- "progress)\n");
- return 0;
- }
-
- if (priv->status & STATUS_DISASSOCIATING) {
- IPW_DEBUG_ASSOC("Not attempting association (in disassociating)\n");
- schedule_work(&priv->associate);
- return 0;
- }
-
- if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) {
- IPW_DEBUG_ASSOC("Not attempting association (scanning or not "
- "initialized)\n");
- return 0;
- }
-
- if (!(priv->config & CFG_ASSOCIATE) &&
- !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) {
- IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
- return 0;
- }
-
- /* Protect our use of the network_list */
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list)
- ipw_best_network(priv, &match, network, 0);
-
- network = match.network;
- rates = &match.rates;
-
- if (network == NULL &&
- priv->ieee->iw_mode == IW_MODE_ADHOC &&
- priv->config & CFG_ADHOC_CREATE &&
- priv->config & CFG_STATIC_ESSID &&
- priv->config & CFG_STATIC_CHANNEL) {
- /* Use oldest network if the free list is empty */
- if (list_empty(&priv->ieee->network_free_list)) {
- struct libipw_network *oldest = NULL;
- struct libipw_network *target;
-
- list_for_each_entry(target, &priv->ieee->network_list, list) {
- if ((oldest == NULL) ||
- (target->last_scanned < oldest->last_scanned))
- oldest = target;
- }
-
- /* If there are no more slots, expire the oldest */
- list_del(&oldest->list);
- target = oldest;
- IPW_DEBUG_ASSOC("Expired '%*pE' (%pM) from network list.\n",
- target->ssid_len, target->ssid,
- target->bssid);
- list_add_tail(&target->list,
- &priv->ieee->network_free_list);
- }
-
- element = priv->ieee->network_free_list.next;
- network = list_entry(element, struct libipw_network, list);
- ipw_adhoc_create(priv, network);
- rates = &priv->rates;
- list_del(element);
- list_add_tail(&network->list, &priv->ieee->network_list);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- /* If we reached the end of the list, then we don't have any valid
- * matching APs */
- if (!network) {
- ipw_debug_config(priv);
-
- if (!(priv->status & STATUS_SCANNING)) {
- if (!(priv->config & CFG_SPEED_SCAN))
- schedule_delayed_work(&priv->request_scan,
- SCAN_INTERVAL);
- else
- schedule_delayed_work(&priv->request_scan, 0);
- }
-
- return 0;
- }
-
- ipw_associate_network(priv, network, rates, 0);
-
- return 1;
-}
-
-static void ipw_bg_associate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, associate);
- mutex_lock(&priv->mutex);
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
- struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- if (!(fc & IEEE80211_FCTL_PROTECTED))
- return;
-
- fc &= ~IEEE80211_FCTL_PROTECTED;
- hdr->frame_control = cpu_to_le16(fc);
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- /* Remove CCMP HDR */
- memmove(skb->data + LIBIPW_3ADDR_LEN,
- skb->data + LIBIPW_3ADDR_LEN + 8,
- skb->len - LIBIPW_3ADDR_LEN - 8);
- skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */
- break;
- case SEC_LEVEL_2:
- break;
- case SEC_LEVEL_1:
- /* Remove IV */
- memmove(skb->data + LIBIPW_3ADDR_LEN,
- skb->data + LIBIPW_3ADDR_LEN + 4,
- skb->len - LIBIPW_3ADDR_LEN - 4);
- skb_trim(skb, skb->len - 8); /* IV + ICV */
- break;
- case SEC_LEVEL_0:
- break;
- default:
- printk(KERN_ERR "Unknown security level %d\n",
- priv->ieee->sec.level);
- break;
- }
-}
-
-static void ipw_handle_data_packet(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct libipw_hdr_4addr *hdr;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- /* We only process data packets if the
- * interface is open */
- if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
- skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- } else if (unlikely(!netif_running(priv->net_dev))) {
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Advance skb->data to the start of the actual payload */
- skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data));
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length));
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
- /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */
- hdr = (struct libipw_hdr_4addr *)rxb->skb->data;
- if (priv->ieee->iw_mode != IW_MODE_MONITOR &&
- (is_multicast_ether_addr(hdr->addr1) ?
- !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt))
- ipw_rebuild_decrypted_skb(priv, rxb->skb);
-
- if (!libipw_rx(priv->ieee, rxb->skb, stats))
- dev->stats.rx_errors++;
- else { /* libipw_rx succeeded, so it now owns the SKB */
- rxb->skb = NULL;
- __ipw_led_activity_on(priv);
- }
-}
-
-#ifdef CONFIG_IPW2200_RADIOTAP
-static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
- struct ipw_rx_frame *frame = &pkt->u.frame;
-
- /* initial pull of some data */
- u16 received_channel = frame->received_channel;
- u8 antennaAndPhy = frame->antennaAndPhy;
- s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */
- u16 pktrate = frame->rate;
-
- /* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE */
- struct ipw_rt_hdr *ipw_rt;
-
- unsigned short len = le16_to_cpu(pkt->u.frame.length);
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- /* We only process data packets if the
- * interface is open */
- if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
- skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- } else if (unlikely(!netif_running(priv->net_dev))) {
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
- * that now */
- if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
- /* FIXME: Should alloc bigger skb instead */
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- /* copy the frame itself */
- memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
- rxb->skb->data + IPW_RX_FRAME_SIZE, len);
-
- ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total header+data */
-
- /* Big bitfield of all the fields we provide in radiotap */
- ipw_rt->rt_hdr.it_present = cpu_to_le32(
- (1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA));
-
- /* Zero the flags, we'll add to them as we go */
- ipw_rt->rt_flags = 0;
- ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
- frame->parent_tsf[2] << 16 |
- frame->parent_tsf[1] << 8 |
- frame->parent_tsf[0]);
-
- /* Convert signal to DBM */
- ipw_rt->rt_dbmsignal = antsignal;
- ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise);
-
- /* Convert the channel data and set the flags */
- ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
- if (received_channel > 14) { /* 802.11a */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- } else if (antennaAndPhy & 32) { /* 802.11b */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- } else { /* 802.11g */
- ipw_rt->rt_chbitmask =
- cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
- }
-
- /* set the rate in multiples of 500k/s */
- switch (pktrate) {
- case IPW_TX_RATE_1MB:
- ipw_rt->rt_rate = 2;
- break;
- case IPW_TX_RATE_2MB:
- ipw_rt->rt_rate = 4;
- break;
- case IPW_TX_RATE_5MB:
- ipw_rt->rt_rate = 10;
- break;
- case IPW_TX_RATE_6MB:
- ipw_rt->rt_rate = 12;
- break;
- case IPW_TX_RATE_9MB:
- ipw_rt->rt_rate = 18;
- break;
- case IPW_TX_RATE_11MB:
- ipw_rt->rt_rate = 22;
- break;
- case IPW_TX_RATE_12MB:
- ipw_rt->rt_rate = 24;
- break;
- case IPW_TX_RATE_18MB:
- ipw_rt->rt_rate = 36;
- break;
- case IPW_TX_RATE_24MB:
- ipw_rt->rt_rate = 48;
- break;
- case IPW_TX_RATE_36MB:
- ipw_rt->rt_rate = 72;
- break;
- case IPW_TX_RATE_48MB:
- ipw_rt->rt_rate = 96;
- break;
- case IPW_TX_RATE_54MB:
- ipw_rt->rt_rate = 108;
- break;
- default:
- ipw_rt->rt_rate = 0;
- break;
- }
-
- /* antenna number */
- ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */
-
- /* set the preamble flag if we have it */
- if ((antennaAndPhy & 64))
- ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr));
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
- if (!libipw_rx(priv->ieee, rxb->skb, stats))
- dev->stats.rx_errors++;
- else { /* libipw_rx succeeded, so it now owns the SKB */
- rxb->skb = NULL;
- /* no LED during capture */
- }
-}
-#endif
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-#define libipw_is_probe_response(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP )
-
-#define libipw_is_management(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
-
-#define libipw_is_control(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
-
-#define libipw_is_data(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
-
-#define libipw_is_assoc_request(fc) \
- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ)
-
-#define libipw_is_reassoc_request(fc) \
- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
-
-static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->prom_net_dev;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
- struct ipw_rx_frame *frame = &pkt->u.frame;
- struct ipw_rt_hdr *ipw_rt;
-
- /* First cache any information we need before we overwrite
- * the information provided in the skb from the hardware */
- struct ieee80211_hdr *hdr;
- u16 channel = frame->received_channel;
- u8 phy_flags = frame->antennaAndPhy;
- s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM;
- s8 noise = (s8) le16_to_cpu(frame->noise);
- u8 rate = frame->rate;
- unsigned short len = le16_to_cpu(pkt->u.frame.length);
- struct sk_buff *skb;
- int hdr_only = 0;
- u16 filter = priv->prom_priv->filter;
-
- /* If the filter is set to not include Rx frames then return */
- if (filter & IPW_PROM_NO_RX)
- return;
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- }
-
- /* We only process data packets if the interface is open */
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_dropped++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
- * that now */
- if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
- /* FIXME: Should alloc bigger skb instead */
- dev->stats.rx_dropped++;
- IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
- if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_MGMT)
- return;
- if (filter & IPW_PROM_MGMT_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_CTL)
- return;
- if (filter & IPW_PROM_CTL_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_DATA)
- return;
- if (filter & IPW_PROM_DATA_HEADER_ONLY)
- hdr_only = 1;
- }
-
- /* Copy the SKB since this is for the promiscuous side */
- skb = skb_copy(rxb->skb, GFP_ATOMIC);
- if (skb == NULL) {
- IPW_ERROR("skb_clone failed for promiscuous copy.\n");
- return;
- }
-
- /* copy the frame data to write after where the radiotap header goes */
- ipw_rt = (void *)skb->data;
-
- if (hdr_only)
- len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
-
- memcpy(ipw_rt->payload, hdr, len);
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */
-
- /* Set the size of the skb to the size of the frame */
- skb_put(skb, sizeof(*ipw_rt) + len);
-
- /* Big bitfield of all the fields we provide in radiotap */
- ipw_rt->rt_hdr.it_present = cpu_to_le32(
- (1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA));
-
- /* Zero the flags, we'll add to them as we go */
- ipw_rt->rt_flags = 0;
- ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
- frame->parent_tsf[2] << 16 |
- frame->parent_tsf[1] << 8 |
- frame->parent_tsf[0]);
-
- /* Convert to DBM */
- ipw_rt->rt_dbmsignal = signal;
- ipw_rt->rt_dbmnoise = noise;
-
- /* Convert the channel data and set the flags */
- ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel));
- if (channel > 14) { /* 802.11a */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- } else if (phy_flags & (1 << 5)) { /* 802.11b */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- } else { /* 802.11g */
- ipw_rt->rt_chbitmask =
- cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
- }
-
- /* set the rate in multiples of 500k/s */
- switch (rate) {
- case IPW_TX_RATE_1MB:
- ipw_rt->rt_rate = 2;
- break;
- case IPW_TX_RATE_2MB:
- ipw_rt->rt_rate = 4;
- break;
- case IPW_TX_RATE_5MB:
- ipw_rt->rt_rate = 10;
- break;
- case IPW_TX_RATE_6MB:
- ipw_rt->rt_rate = 12;
- break;
- case IPW_TX_RATE_9MB:
- ipw_rt->rt_rate = 18;
- break;
- case IPW_TX_RATE_11MB:
- ipw_rt->rt_rate = 22;
- break;
- case IPW_TX_RATE_12MB:
- ipw_rt->rt_rate = 24;
- break;
- case IPW_TX_RATE_18MB:
- ipw_rt->rt_rate = 36;
- break;
- case IPW_TX_RATE_24MB:
- ipw_rt->rt_rate = 48;
- break;
- case IPW_TX_RATE_36MB:
- ipw_rt->rt_rate = 72;
- break;
- case IPW_TX_RATE_48MB:
- ipw_rt->rt_rate = 96;
- break;
- case IPW_TX_RATE_54MB:
- ipw_rt->rt_rate = 108;
- break;
- default:
- ipw_rt->rt_rate = 0;
- break;
- }
-
- /* antenna number */
- ipw_rt->rt_antenna = (phy_flags & 3);
-
- /* set the preamble flag if we have it */
- if (phy_flags & (1 << 6))
- ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len);
-
- if (!libipw_rx(priv->prom_priv->ieee, skb, stats)) {
- dev->stats.rx_errors++;
- dev_kfree_skb_any(skb);
- }
-}
-#endif
-
-static int is_network_packet(struct ipw_priv *priv,
- struct libipw_hdr_4addr *header)
-{
- /* Filter incoming packets to determine if they are targeted toward
- * this network, discarding packets coming from ourselves */
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */
- /* packets from our adapter are dropped (echo) */
- if (ether_addr_equal(header->addr2, priv->net_dev->dev_addr))
- return 0;
-
- /* {broad,multi}cast packets to our BSSID go through */
- if (is_multicast_ether_addr(header->addr1))
- return ether_addr_equal(header->addr3, priv->bssid);
-
- /* packets to our adapter go through */
- return ether_addr_equal(header->addr1,
- priv->net_dev->dev_addr);
-
- case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */
- /* packets from our adapter are dropped (echo) */
- if (ether_addr_equal(header->addr3, priv->net_dev->dev_addr))
- return 0;
-
- /* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(header->addr1))
- return ether_addr_equal(header->addr2, priv->bssid);
-
- /* packets to our adapter go through */
- return ether_addr_equal(header->addr1,
- priv->net_dev->dev_addr);
- }
-
- return 1;
-}
-
-#define IPW_PACKET_RETRY_TIME HZ
-
-static int is_duplicate_packet(struct ipw_priv *priv,
- struct libipw_hdr_4addr *header)
-{
- u16 sc = le16_to_cpu(header->seq_ctl);
- u16 seq = WLAN_GET_SEQ_SEQ(sc);
- u16 frag = WLAN_GET_SEQ_FRAG(sc);
- u16 *last_seq, *last_frag;
- unsigned long *last_time;
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- {
- struct list_head *p;
- struct ipw_ibss_seq *entry = NULL;
- u8 *mac = header->addr2;
- int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE;
-
- list_for_each(p, &priv->ibss_mac_hash[index]) {
- entry =
- list_entry(p, struct ipw_ibss_seq, list);
- if (ether_addr_equal(entry->mac, mac))
- break;
- }
- if (p == &priv->ibss_mac_hash[index]) {
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry) {
- IPW_ERROR
- ("Cannot malloc new mac entry\n");
- return 0;
- }
- memcpy(entry->mac, mac, ETH_ALEN);
- entry->seq_num = seq;
- entry->frag_num = frag;
- entry->packet_time = jiffies;
- list_add(&entry->list,
- &priv->ibss_mac_hash[index]);
- return 0;
- }
- last_seq = &entry->seq_num;
- last_frag = &entry->frag_num;
- last_time = &entry->packet_time;
- break;
- }
- case IW_MODE_INFRA:
- last_seq = &priv->last_seq_num;
- last_frag = &priv->last_frag_num;
- last_time = &priv->last_packet_time;
- break;
- default:
- return 0;
- }
- if ((*last_seq == seq) &&
- time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) {
- if (*last_frag == frag)
- goto drop;
- if (*last_frag + 1 != frag)
- /* out-of-order fragment */
- goto drop;
- } else
- *last_seq = seq;
-
- *last_frag = frag;
- *last_time = jiffies;
- return 0;
-
- drop:
- /* Comment this line now since we observed the card receives
- * duplicate packets but the FCTL_RETRY bit is not set in the
- * IBSS mode with fragmentation enabled.
- BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */
- return 1;
-}
-
-static void ipw_handle_mgmt_packet(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct sk_buff *skb = rxb->skb;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data;
- struct libipw_hdr_4addr *header = (struct libipw_hdr_4addr *)
- (skb->data + IPW_RX_FRAME_SIZE);
-
- libipw_rx_mgt(priv->ieee, header, stats);
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC &&
- ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
- IEEE80211_STYPE_PROBE_RESP) ||
- (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
- IEEE80211_STYPE_BEACON))) {
- if (ether_addr_equal(header->addr3, priv->bssid))
- ipw_add_station(priv, header->addr2);
- }
-
- if (priv->config & CFG_NET_STATS) {
- IPW_DEBUG_HC("sending stat packet\n");
-
- /* Set the size of the skb to the size of the full
- * ipw header and 802.11 frame */
- skb_put(skb, le16_to_cpu(pkt->u.frame.length) +
- IPW_RX_FRAME_SIZE);
-
- /* Advance past the ipw packet header to the 802.11 frame */
- skb_pull(skb, IPW_RX_FRAME_SIZE);
-
- /* Push the libipw_rx_stats before the 802.11 frame */
- memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats));
-
- skb->dev = priv->ieee->dev;
-
- /* Point raw at the libipw_stats */
- skb_reset_mac_header(skb);
-
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_80211_STATS);
- memset(skb->cb, 0, sizeof(rxb->skb->cb));
- netif_rx(skb);
- rxb->skb = NULL;
- }
-}
-
-/*
- * Main entry function for receiving a packet with 80211 headers. This
- * should be called when ever the FW has notified us that there is a new
- * skb in the receive queue.
- */
-static void ipw_rx(struct ipw_priv *priv)
-{
- struct ipw_rx_mem_buffer *rxb;
- struct ipw_rx_packet *pkt;
- struct libipw_hdr_4addr *header;
- u32 r, i;
- u8 network_packet;
- u8 fill_rx = 0;
-
- r = ipw_read32(priv, IPW_RX_READ_INDEX);
- ipw_read32(priv, IPW_RX_WRITE_INDEX);
- i = priv->rxq->read;
-
- if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2))
- fill_rx = 1;
-
- while (i != r) {
- rxb = priv->rxq->queue[i];
- if (unlikely(rxb == NULL)) {
- printk(KERN_CRIT "Queue not allocated!\n");
- break;
- }
- priv->rxq->queue[i] = NULL;
-
- dma_sync_single_for_cpu(&priv->pci_dev->dev, rxb->dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
-
- pkt = (struct ipw_rx_packet *)rxb->skb->data;
- IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n",
- pkt->header.message_type,
- pkt->header.rx_seq_num, pkt->header.control_bits);
-
- switch (pkt->header.message_type) {
- case RX_FRAME_TYPE: /* 802.11 frame */ {
- struct libipw_rx_stats stats = {
- .rssi = pkt->u.frame.rssi_dbm -
- IPW_RSSI_TO_DBM,
- .signal =
- pkt->u.frame.rssi_dbm -
- IPW_RSSI_TO_DBM + 0x100,
- .noise =
- le16_to_cpu(pkt->u.frame.noise),
- .rate = pkt->u.frame.rate,
- .mac_time = jiffies,
- .received_channel =
- pkt->u.frame.received_channel,
- .freq =
- (pkt->u.frame.
- control & (1 << 0)) ?
- LIBIPW_24GHZ_BAND :
- LIBIPW_52GHZ_BAND,
- .len = le16_to_cpu(pkt->u.frame.length),
- };
-
- if (stats.rssi != 0)
- stats.mask |= LIBIPW_STATMASK_RSSI;
- if (stats.signal != 0)
- stats.mask |= LIBIPW_STATMASK_SIGNAL;
- if (stats.noise != 0)
- stats.mask |= LIBIPW_STATMASK_NOISE;
- if (stats.rate != 0)
- stats.mask |= LIBIPW_STATMASK_RATE;
-
- priv->rx_packets++;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev))
- ipw_handle_promiscuous_rx(priv, rxb, &stats);
-#endif
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
-#ifdef CONFIG_IPW2200_RADIOTAP
-
- ipw_handle_data_packet_monitor(priv,
- rxb,
- &stats);
-#else
- ipw_handle_data_packet(priv, rxb,
- &stats);
-#endif
- break;
- }
-#endif
-
- header =
- (struct libipw_hdr_4addr *)(rxb->skb->
- data +
- IPW_RX_FRAME_SIZE);
- /* TODO: Check Ad-Hoc dest/source and make sure
- * that we are actually parsing these packets
- * correctly -- we should probably use the
- * frame control of the packet and disregard
- * the current iw_mode */
-
- network_packet =
- is_network_packet(priv, header);
- if (network_packet && priv->assoc_network) {
- priv->assoc_network->stats.rssi =
- stats.rssi;
- priv->exp_avg_rssi =
- exponential_average(priv->exp_avg_rssi,
- stats.rssi, DEPTH_RSSI);
- }
-
- IPW_DEBUG_RX("Frame: len=%u\n",
- le16_to_cpu(pkt->u.frame.length));
-
- if (le16_to_cpu(pkt->u.frame.length) <
- libipw_get_hdrlen(le16_to_cpu(
- header->frame_ctl))) {
- IPW_DEBUG_DROP
- ("Received packet is too small. "
- "Dropping.\n");
- priv->net_dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- break;
- }
-
- switch (WLAN_FC_GET_TYPE
- (le16_to_cpu(header->frame_ctl))) {
-
- case IEEE80211_FTYPE_MGMT:
- ipw_handle_mgmt_packet(priv, rxb,
- &stats);
- break;
-
- case IEEE80211_FTYPE_CTL:
- break;
-
- case IEEE80211_FTYPE_DATA:
- if (unlikely(!network_packet ||
- is_duplicate_packet(priv,
- header)))
- {
- IPW_DEBUG_DROP("Dropping: "
- "%pM, "
- "%pM, "
- "%pM\n",
- header->addr1,
- header->addr2,
- header->addr3);
- break;
- }
-
- ipw_handle_data_packet(priv, rxb,
- &stats);
-
- break;
- }
- break;
- }
-
- case RX_HOST_NOTIFICATION_TYPE:{
- IPW_DEBUG_RX
- ("Notification: subtype=%02X flags=%02X size=%d\n",
- pkt->u.notification.subtype,
- pkt->u.notification.flags,
- le16_to_cpu(pkt->u.notification.size));
- ipw_rx_notification(priv, &pkt->u.notification);
- break;
- }
-
- default:
- IPW_DEBUG_RX("Bad Rx packet of type %d\n",
- pkt->header.message_type);
- break;
- }
-
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, rxb->dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- list_add_tail(&rxb->list, &priv->rxq->rx_used);
-
- i = (i + 1) % RX_QUEUE_SIZE;
-
- /* If there are a lot of unsued frames, restock the Rx queue
- * so the ucode won't assert */
- if (fill_rx) {
- priv->rxq->read = i;
- ipw_rx_queue_replenish(priv);
- }
- }
-
- /* Backtrack one entry */
- priv->rxq->read = i;
- ipw_rx_queue_restock(priv);
-}
-
-#define DEFAULT_RTS_THRESHOLD 2304U
-#define MIN_RTS_THRESHOLD 1U
-#define MAX_RTS_THRESHOLD 2304U
-#define DEFAULT_BEACON_INTERVAL 100U
-#define DEFAULT_SHORT_RETRY_LIMIT 7U
-#define DEFAULT_LONG_RETRY_LIMIT 4U
-
-/*
- * ipw_sw_reset
- * @option: options to control different reset behaviour
- * 0 = reset everything except the 'disable' module_param
- * 1 = reset everything and print out driver info (for probe only)
- * 2 = reset everything
- */
-static int ipw_sw_reset(struct ipw_priv *priv, int option)
-{
- int band, modulation;
- int old_mode = priv->ieee->iw_mode;
-
- /* Initialize module parameter values here */
- priv->config = 0;
-
- /* We default to disabling the LED code as right now it causes
- * too many systems to lock up... */
- if (!led_support)
- priv->config |= CFG_NO_LED;
-
- if (associate)
- priv->config |= CFG_ASSOCIATE;
- else
- IPW_DEBUG_INFO("Auto associate disabled.\n");
-
- if (auto_create)
- priv->config |= CFG_ADHOC_CREATE;
- else
- IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
-
- priv->config &= ~CFG_STATIC_ESSID;
- priv->essid_len = 0;
- memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-
- if (disable && option) {
- priv->status |= STATUS_RF_KILL_SW;
- IPW_DEBUG_INFO("Radio disabled.\n");
- }
-
- if (default_channel != 0) {
- priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = default_channel;
- IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel);
- /* TODO: Validate that provided channel is in range */
- }
-#ifdef CONFIG_IPW2200_QOS
- ipw_qos_init(priv, qos_enable, qos_burst_enable,
- burst_duration_CCK, burst_duration_OFDM);
-#endif /* CONFIG_IPW2200_QOS */
-
- switch (network_mode) {
- case 1:
- priv->ieee->iw_mode = IW_MODE_ADHOC;
- priv->net_dev->type = ARPHRD_ETHER;
-
- break;
-#ifdef CONFIG_IPW2200_MONITOR
- case 2:
- priv->ieee->iw_mode = IW_MODE_MONITOR;
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
- break;
-#endif
- default:
- case 0:
- priv->net_dev->type = ARPHRD_ETHER;
- priv->ieee->iw_mode = IW_MODE_INFRA;
- break;
- }
-
- if (hwcrypto) {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 0;
- priv->ieee->host_decrypt = 0;
- priv->ieee->host_mc_decrypt = 0;
- }
- IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off");
-
- /* IPW2200/2915 is abled to do hardware fragmentation. */
- priv->ieee->host_open_frag = 0;
-
- if ((priv->pci_dev->device == 0x4223) ||
- (priv->pci_dev->device == 0x4224)) {
- if (option == 1)
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2915ABG Network "
- "Connection\n");
- priv->ieee->abg_true = 1;
- band = LIBIPW_52GHZ_BAND | LIBIPW_24GHZ_BAND;
- modulation = LIBIPW_OFDM_MODULATION |
- LIBIPW_CCK_MODULATION;
- priv->adapter = IPW_2915ABG;
- priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
- } else {
- if (option == 1)
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2200BG Network "
- "Connection\n");
-
- priv->ieee->abg_true = 0;
- band = LIBIPW_24GHZ_BAND;
- modulation = LIBIPW_OFDM_MODULATION |
- LIBIPW_CCK_MODULATION;
- priv->adapter = IPW_2200BG;
- priv->ieee->mode = IEEE_G | IEEE_B;
- }
-
- priv->ieee->freq_band = band;
- priv->ieee->modulation = modulation;
-
- priv->rates_mask = LIBIPW_DEFAULT_RATES_MASK;
-
- priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
- priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
-
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
- priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
- priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
-
- /* If power management is turned on, default to AC mode */
- priv->power_mode = IPW_POWER_AC;
- priv->tx_power = IPW_TX_POWER_DEFAULT;
-
- return old_mode == priv->ieee->iw_mode;
-}
-
-/*
- * This file defines the Wireless Extension handlers. It does not
- * define any methods of hardware manipulation and relies on the
- * functions defined in ipw_main to provide the HW interaction.
- *
- * The exception to this is the use of the ipw_get_ordinal()
- * function used to poll the hardware vs. making unnecessary calls.
- *
- */
-
-static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
-{
- if (channel == 0) {
- IPW_DEBUG_INFO("Setting channel to ANY (0)\n");
- priv->config &= ~CFG_STATIC_CHANNEL;
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- return 0;
- }
-
- priv->config |= CFG_STATIC_CHANNEL;
-
- if (priv->channel == channel) {
- IPW_DEBUG_INFO("Request to set channel to current value (%d)\n",
- channel);
- return 0;
- }
-
- IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel);
- priv->channel = channel;
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- int i;
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan abort triggered due to "
- "channel change.\n");
- ipw_abort_scan(priv);
- }
-
- for (i = 1000; i && (priv->status & STATUS_SCANNING); i--)
- udelay(10);
-
- if (priv->status & STATUS_SCANNING)
- IPW_DEBUG_SCAN("Still scanning...\n");
- else
- IPW_DEBUG_SCAN("Took %dms to abort current scan\n",
- 1000 - i);
-
- return 0;
- }
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- return 0;
-}
-
-static int ipw_wx_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct iw_freq *fwrq = &wrqu->freq;
- int ret = 0, i;
- u8 channel, flags;
- int band;
-
- if (fwrq->m == 0) {
- IPW_DEBUG_WX("SET Freq/Channel -> any\n");
- mutex_lock(&priv->mutex);
- ret = ipw_set_channel(priv, 0);
- mutex_unlock(&priv->mutex);
- return ret;
- }
- /* if setting by freq convert to channel */
- if (fwrq->e == 1) {
- channel = libipw_freq_to_channel(priv->ieee, fwrq->m);
- if (channel == 0)
- return -EINVAL;
- } else
- channel = fwrq->m;
-
- if (!(band = libipw_is_valid_channel(priv->ieee, channel)))
- return -EINVAL;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- i = libipw_channel_to_index(priv->ieee, channel);
- if (i == -1)
- return -EINVAL;
-
- flags = (band == LIBIPW_24GHZ_BAND) ?
- geo->bg[i].flags : geo->a[i].flags;
- if (flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n");
- return -EINVAL;
- }
- }
-
- IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
- mutex_lock(&priv->mutex);
- ret = ipw_set_channel(priv, channel);
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static int ipw_wx_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- wrqu->freq.e = 0;
-
- /* If we are associated, trying to associate, or have a statically
- * configured CHANNEL then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_CHANNEL ||
- priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) {
- int i;
-
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- wrqu->freq.e = 1;
-
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000;
- break;
-
- case LIBIPW_24GHZ_BAND:
- wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000;
- break;
-
- default:
- BUG();
- }
- } else
- wrqu->freq.m = 0;
-
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
- return 0;
-}
-
-static int ipw_wx_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
-
- switch (wrqu->mode) {
-#ifdef CONFIG_IPW2200_MONITOR
- case IW_MODE_MONITOR:
-#endif
- case IW_MODE_ADHOC:
- case IW_MODE_INFRA:
- break;
- case IW_MODE_AUTO:
- wrqu->mode = IW_MODE_INFRA;
- break;
- default:
- return -EINVAL;
- }
- if (wrqu->mode == priv->ieee->iw_mode)
- return 0;
-
- mutex_lock(&priv->mutex);
-
- ipw_sw_reset(priv, 0);
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- priv->net_dev->type = ARPHRD_ETHER;
-
- if (wrqu->mode == IW_MODE_MONITOR)
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Free the existing firmware and reset the fw_loaded
- * flag so ipw_load() will bring in the new firmware */
- free_firmware();
-
- priv->ieee->iw_mode = wrqu->mode;
-
- schedule_work(&priv->adapter_restart);
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->mode = priv->ieee->iw_mode;
- IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-/* Values are in microsecond */
-static const s32 timeout_duration[] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-
-static const s32 period_duration[] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
-static int ipw_wx_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_range *range = (struct iw_range *)extra;
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int i = 0, j;
-
- wrqu->data.length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- /* 54Mbs == ~27 Mb/s real (802.11g) */
- range->throughput = 27 * 1000 * 1000;
-
- range->max_qual.qual = 100;
- /* TODO: Find real max RSSI and stick here */
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
-
- range->avg_qual.qual = 70;
- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
- range->avg_qual.level = 0; /* FIXME to real average level */
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
- mutex_lock(&priv->mutex);
- range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
-
- for (i = 0; i < range->num_bitrates; i++)
- range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) *
- 500000;
-
- range->max_rts = DEFAULT_RTS_THRESHOLD;
- range->min_frag = MIN_FRAG_THRESHOLD;
- range->max_frag = MAX_FRAG_THRESHOLD;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- range->max_encoding_tokens = WEP_KEYS;
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
- i = 0;
- if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
- for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) {
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->bg[j].flags & LIBIPW_CH_PASSIVE_ONLY))
- continue;
-
- range->freq[i].i = geo->bg[j].channel;
- range->freq[i].m = geo->bg[j].freq * 100000;
- range->freq[i].e = 1;
- i++;
- }
- }
-
- if (priv->ieee->mode & IEEE_A) {
- for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) {
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->a[j].flags & LIBIPW_CH_PASSIVE_ONLY))
- continue;
-
- range->freq[i].i = geo->a[j].channel;
- range->freq[i].m = geo->a[j].freq * 100000;
- range->freq[i].e = 1;
- i++;
- }
- }
-
- range->num_channels = i;
- range->num_frequency = i;
-
- mutex_unlock(&priv->mutex);
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE;
-
- IPW_DEBUG_WX("GET Range\n");
- return 0;
-}
-
-static int ipw_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- return -EINVAL;
- mutex_lock(&priv->mutex);
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
- is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
- /* we disable mandatory BSSID association */
- IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
- priv->config &= ~CFG_STATIC_BSSID;
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- priv->config |= CFG_STATIC_BSSID;
- if (ether_addr_equal(priv->bssid, wrqu->ap_addr.sa_data)) {
- IPW_DEBUG_WX("BSSID set to current BSSID.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n",
- wrqu->ap_addr.sa_data);
-
- memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured BSSID then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_BSSID ||
- priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
- } else
- eth_zero_addr(wrqu->ap_addr.sa_data);
-
- IPW_DEBUG_WX("Getting WAP BSSID: %pM\n",
- wrqu->ap_addr.sa_data);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int length;
-
- mutex_lock(&priv->mutex);
-
- if (!wrqu->essid.flags)
- {
- IPW_DEBUG_WX("Setting ESSID to ANY\n");
- ipw_disassociate(priv);
- priv->config &= ~CFG_STATIC_ESSID;
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
-
- priv->config |= CFG_STATIC_ESSID;
-
- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)
- && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) {
- IPW_DEBUG_WX("ESSID set to current ESSID.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, extra, length);
-
- priv->essid_len = length;
- memcpy(priv->essid, extra, priv->essid_len);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured ESSID then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_ESSID ||
- priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_WX("Getting essid: '%*pE'\n",
- priv->essid_len, priv->essid);
- memcpy(extra, priv->essid, priv->essid_len);
- wrqu->essid.length = priv->essid_len;
- wrqu->essid.flags = 1; /* active */
- } else {
- IPW_DEBUG_WX("Getting essid: ANY\n");
- wrqu->essid.length = 0;
- wrqu->essid.flags = 0; /* active */
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
- if (wrqu->data.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
- mutex_lock(&priv->mutex);
- wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
- IPW_DEBUG_TRACE("<<\n");
- mutex_unlock(&priv->mutex);
- return 0;
-
-}
-
-static int ipw_wx_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- IPW_DEBUG_WX("Getting nick\n");
- mutex_lock(&priv->mutex);
- wrqu->data.length = strlen(priv->nick);
- memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value);
- IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value);
- mutex_lock(&priv->mutex);
-
- if (wrqu->sens.fixed == 0)
- {
- priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
- priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
- goto out;
- }
- if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) ||
- (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) {
- err = -EINVAL;
- goto out;
- }
-
- priv->roaming_threshold = wrqu->sens.value;
- priv->disassociate_threshold = 3*wrqu->sens.value;
- out:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->sens.fixed = 1;
- wrqu->sens.value = priv->roaming_threshold;
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET roaming threshold -> %s %d\n",
- wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
-
- return 0;
-}
-
-static int ipw_wx_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /* TODO: We should use semaphores or locks for access to priv */
- struct ipw_priv *priv = libipw_priv(dev);
- u32 target_rate = wrqu->bitrate.value;
- u32 fixed, mask;
-
- /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */
- /* value = X, fixed = 1 means only rate X */
- /* value = X, fixed = 0 means all rates lower equal X */
-
- if (target_rate == -1) {
- fixed = 0;
- mask = LIBIPW_DEFAULT_RATES_MASK;
- /* Now we should reassociate */
- goto apply;
- }
-
- mask = 0;
- fixed = wrqu->bitrate.fixed;
-
- if (target_rate == 1000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_1MB_MASK;
- if (target_rate == 1000000)
- goto apply;
-
- if (target_rate == 2000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_2MB_MASK;
- if (target_rate == 2000000)
- goto apply;
-
- if (target_rate == 5500000 || !fixed)
- mask |= LIBIPW_CCK_RATE_5MB_MASK;
- if (target_rate == 5500000)
- goto apply;
-
- if (target_rate == 6000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_6MB_MASK;
- if (target_rate == 6000000)
- goto apply;
-
- if (target_rate == 9000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_9MB_MASK;
- if (target_rate == 9000000)
- goto apply;
-
- if (target_rate == 11000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_11MB_MASK;
- if (target_rate == 11000000)
- goto apply;
-
- if (target_rate == 12000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_12MB_MASK;
- if (target_rate == 12000000)
- goto apply;
-
- if (target_rate == 18000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_18MB_MASK;
- if (target_rate == 18000000)
- goto apply;
-
- if (target_rate == 24000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_24MB_MASK;
- if (target_rate == 24000000)
- goto apply;
-
- if (target_rate == 36000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_36MB_MASK;
- if (target_rate == 36000000)
- goto apply;
-
- if (target_rate == 48000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_48MB_MASK;
- if (target_rate == 48000000)
- goto apply;
-
- if (target_rate == 54000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_54MB_MASK;
- if (target_rate == 54000000)
- goto apply;
-
- IPW_DEBUG_WX("invalid rate specified, returning error\n");
- return -EINVAL;
-
- apply:
- IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n",
- mask, fixed ? "fixed" : "sub-rates");
- mutex_lock(&priv->mutex);
- if (mask == LIBIPW_DEFAULT_RATES_MASK) {
- priv->config &= ~CFG_FIXED_RATE;
- ipw_set_fixed_rate(priv, priv->ieee->mode);
- } else
- priv->config |= CFG_FIXED_RATE;
-
- if (priv->rates_mask == mask) {
- IPW_DEBUG_WX("Mask set to current mask.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- priv->rates_mask = mask;
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->bitrate.value = priv->last_rate;
- wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0;
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
- return 0;
-}
-
-static int ipw_wx_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (wrqu->rts.disabled || !wrqu->rts.fixed)
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
- else {
- if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
- wrqu->rts.value > MAX_RTS_THRESHOLD) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
- priv->rts_threshold = wrqu->rts.value;
- }
-
- ipw_send_rts_threshold(priv, priv->rts_threshold);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET RTS Threshold -> %d\n", priv->rts_threshold);
- return 0;
-}
-
-static int ipw_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->rts.value = priv->rts_threshold;
- wrqu->rts.fixed = 0; /* no auto select */
- wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET RTS Threshold -> %d\n", wrqu->rts.value);
- return 0;
-}
-
-static int ipw_wx_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->mutex);
- if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) {
- err = -EINPROGRESS;
- goto out;
- }
-
- if (!wrqu->power.fixed)
- wrqu->power.value = IPW_TX_POWER_DEFAULT;
-
- if (wrqu->power.flags != IW_TXPOW_DBM) {
- err = -EINVAL;
- goto out;
- }
-
- if ((wrqu->power.value > IPW_TX_POWER_MAX) ||
- (wrqu->power.value < IPW_TX_POWER_MIN)) {
- err = -EINVAL;
- goto out;
- }
-
- priv->tx_power = wrqu->power.value;
- err = ipw_set_tx_power(priv);
- out:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->power.value = priv->tx_power;
- wrqu->power.fixed = 1;
- wrqu->power.flags = IW_TXPOW_DBM;
- wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET TX Power -> %s %d\n",
- wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
-
- return 0;
-}
-
-static int ipw_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (wrqu->frag.disabled || !wrqu->frag.fixed)
- priv->ieee->fts = DEFAULT_FTS;
- else {
- if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- priv->ieee->fts = wrqu->frag.value & ~0x1;
- }
-
- ipw_send_frag_threshold(priv, wrqu->frag.value);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET Frag Threshold -> %d\n", wrqu->frag.value);
- return 0;
-}
-
-static int ipw_wx_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->frag.value = priv->ieee->fts;
- wrqu->frag.fixed = 0; /* no auto select */
- wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
-
- return 0;
-}
-
-static int ipw_wx_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
- return -EINVAL;
-
- if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
- return 0;
-
- if (wrqu->retry.value < 0 || wrqu->retry.value >= 255)
- return -EINVAL;
-
- mutex_lock(&priv->mutex);
- if (wrqu->retry.flags & IW_RETRY_SHORT)
- priv->short_retry_limit = (u8) wrqu->retry.value;
- else if (wrqu->retry.flags & IW_RETRY_LONG)
- priv->long_retry_limit = (u8) wrqu->retry.value;
- else {
- priv->short_retry_limit = (u8) wrqu->retry.value;
- priv->long_retry_limit = (u8) wrqu->retry.value;
- }
-
- ipw_send_retry_limit(priv, priv->short_retry_limit,
- priv->long_retry_limit);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n",
- priv->short_retry_limit, priv->long_retry_limit);
- return 0;
-}
-
-static int ipw_wx_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- mutex_lock(&priv->mutex);
- wrqu->retry.disabled = 0;
-
- if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- wrqu->retry.value = priv->long_retry_limit;
- } else if (wrqu->retry.flags & IW_RETRY_SHORT) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
- wrqu->retry.value = priv->short_retry_limit;
- } else {
- wrqu->retry.flags = IW_RETRY_LIMIT;
- wrqu->retry.value = priv->short_retry_limit;
- }
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET retry -> %d\n", wrqu->retry.value);
-
- return 0;
-}
-
-static int ipw_wx_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_scan_req *req = (struct iw_scan_req *)extra;
- struct delayed_work *work = NULL;
-
- mutex_lock(&priv->mutex);
-
- priv->user_requested_scan = 1;
-
- if (wrqu->data.length == sizeof(struct iw_scan_req)) {
- if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- int len = min((int)req->essid_len,
- (int)sizeof(priv->direct_scan_ssid));
- memcpy(priv->direct_scan_ssid, req->essid, len);
- priv->direct_scan_ssid_len = len;
- work = &priv->request_direct_scan;
- } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
- work = &priv->request_passive_scan;
- }
- } else {
- /* Normal active broadcast scan */
- work = &priv->request_scan;
- }
-
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("Start scan\n");
-
- schedule_delayed_work(work, 0);
-
- return 0;
-}
-
-static int ipw_wx_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
-}
-
-static int ipw_wx_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int ret;
- u32 cap = priv->capability;
-
- mutex_lock(&priv->mutex);
- ret = libipw_wx_set_encode(priv->ieee, info, wrqu, key);
-
- /* In IBSS mode, we need to notify the firmware to update
- * the beacon info after we changed the capability. */
- if (cap != priv->capability &&
- priv->ieee->iw_mode == IW_MODE_ADHOC &&
- priv->status & STATUS_ASSOCIATED)
- ipw_disassociate(priv);
-
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static int ipw_wx_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err;
- mutex_lock(&priv->mutex);
- if (wrqu->power.disabled) {
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
- IPW_DEBUG_WX("SET Power Management Mode -> off\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitly state all */
- break;
- default: /* Otherwise we don't support it */
- IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
- wrqu->power.flags);
- mutex_unlock(&priv->mutex);
- return -EOPNOTSUPP;
- }
-
- /* If the user hasn't specified a power management mode yet, default
- * to BATTERY */
- if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC)
- priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
- else
- priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
-
- err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
-
- IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- wrqu->power.disabled = 1;
- else
- wrqu->power.disabled = 0;
-
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
-
- return 0;
-}
-
-static int ipw_wx_set_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- int err;
-
- mutex_lock(&priv->mutex);
- if ((mode < 1) || (mode > IPW_POWER_LIMIT))
- mode = IPW_POWER_AC;
-
- if (IPW_POWER_LEVEL(priv->power_mode) != mode) {
- err = ipw_send_power_mode(priv, mode);
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
- priv->power_mode = IPW_POWER_ENABLED | mode;
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#define MAX_WX_STRING 80
-static int ipw_wx_get_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int level = IPW_POWER_LEVEL(priv->power_mode);
- char *p = extra;
-
- p += scnprintf(p, MAX_WX_STRING, "Power save level: %d ", level);
-
- switch (level) {
- case IPW_POWER_AC:
- p += scnprintf(p, MAX_WX_STRING - (p - extra), "(AC)");
- break;
- case IPW_POWER_BATTERY:
- p += scnprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)");
- break;
- default:
- p += scnprintf(p, MAX_WX_STRING - (p - extra),
- "(Timeout %dms, Period %dms)",
- timeout_duration[level - 1] / 1000,
- period_duration[level - 1] / 1000);
- }
-
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- p += scnprintf(p, MAX_WX_STRING - (p - extra), " OFF");
-
- wrqu->data.length = p - extra + 1;
-
- return 0;
-}
-
-static int ipw_wx_set_wireless_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- u8 band = 0, modulation = 0;
-
- if (mode == 0 || mode & ~IEEE_MODE_MASK) {
- IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
- return -EINVAL;
- }
- mutex_lock(&priv->mutex);
- if (priv->adapter == IPW_2915ABG) {
- priv->ieee->abg_true = 1;
- if (mode & IEEE_A) {
- band |= LIBIPW_52GHZ_BAND;
- modulation |= LIBIPW_OFDM_MODULATION;
- } else
- priv->ieee->abg_true = 0;
- } else {
- if (mode & IEEE_A) {
- IPW_WARNING("Attempt to set 2200BG into "
- "802.11a mode\n");
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- priv->ieee->abg_true = 0;
- }
-
- if (mode & IEEE_B) {
- band |= LIBIPW_24GHZ_BAND;
- modulation |= LIBIPW_CCK_MODULATION;
- } else
- priv->ieee->abg_true = 0;
-
- if (mode & IEEE_G) {
- band |= LIBIPW_24GHZ_BAND;
- modulation |= LIBIPW_OFDM_MODULATION;
- } else
- priv->ieee->abg_true = 0;
-
- priv->ieee->mode = mode;
- priv->ieee->freq_band = band;
- priv->ieee->modulation = modulation;
- init_supported_rates(priv, &priv->rates);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n");
- if (!ipw_disassociate(priv)) {
- ipw_send_supported_rates(priv, &priv->rates);
- ipw_associate(priv);
- }
-
- /* Update the band LEDs */
- ipw_led_band_on(priv);
-
- IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
- mode & IEEE_A ? 'a' : '.',
- mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_wireless_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- switch (priv->ieee->mode) {
- case IEEE_A:
- strncpy(extra, "802.11a (1)", MAX_WX_STRING);
- break;
- case IEEE_B:
- strncpy(extra, "802.11b (2)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_B:
- strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
- break;
- case IEEE_G:
- strncpy(extra, "802.11g (4)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_G:
- strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
- break;
- case IEEE_B | IEEE_G:
- strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_B | IEEE_G:
- strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
- break;
- default:
- strncpy(extra, "unknown", MAX_WX_STRING);
- break;
- }
- extra[MAX_WX_STRING - 1] = '\0';
-
- IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
-
- wrqu->data.length = strlen(extra) + 1;
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-static int ipw_wx_set_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- mutex_lock(&priv->mutex);
- /* Switching from SHORT -> LONG requires a disassociation */
- if (mode == 1) {
- if (!(priv->config & CFG_PREAMBLE_LONG)) {
- priv->config |= CFG_PREAMBLE_LONG;
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC
- ("[re]association triggered due to preamble change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
- }
- goto done;
- }
-
- if (mode == 0) {
- priv->config &= ~CFG_PREAMBLE_LONG;
- goto done;
- }
- mutex_unlock(&priv->mutex);
- return -EINVAL;
-
- done:
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_PREAMBLE_LONG)
- snprintf(wrqu->name, IFNAMSIZ, "long (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_MONITOR
-static int ipw_wx_set_monitor(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int *parms = (int *)extra;
- int enable = (parms[0] > 0);
- mutex_lock(&priv->mutex);
- IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
- if (enable) {
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
- schedule_work(&priv->adapter_restart);
- }
-
- ipw_set_channel(priv, parms[1]);
- } else {
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- mutex_unlock(&priv->mutex);
- return 0;
- }
- priv->net_dev->type = ARPHRD_ETHER;
- schedule_work(&priv->adapter_restart);
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#endif /* CONFIG_IPW2200_MONITOR */
-
-static int ipw_wx_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- IPW_DEBUG_WX("RESET\n");
- schedule_work(&priv->adapter_restart);
- return 0;
-}
-
-static int ipw_wx_sw_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- union iwreq_data wrqu_sec = {
- .encoding = {
- .flags = IW_ENCODE_DISABLED,
- },
- };
- int ret;
-
- IPW_DEBUG_WX("SW_RESET\n");
-
- mutex_lock(&priv->mutex);
-
- ret = ipw_sw_reset(priv, 2);
- if (!ret) {
- free_firmware();
- ipw_adapter_restart(priv);
- }
-
- /* The SW reset bit might have been toggled on by the 'disable'
- * module parameter, so take appropriate action */
- ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW);
-
- mutex_unlock(&priv->mutex);
- libipw_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
- mutex_lock(&priv->mutex);
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- /* Configuration likely changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to sw "
- "reset.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
- }
-
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-/* Rebase the WE IOCTLs to zero for the handler array */
-static iw_handler ipw_wx_handlers[] = {
- IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
- IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq),
- IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode),
- IW_HANDLER(SIOCGIWMODE, ipw_wx_get_mode),
- IW_HANDLER(SIOCSIWSENS, ipw_wx_set_sens),
- IW_HANDLER(SIOCGIWSENS, ipw_wx_get_sens),
- IW_HANDLER(SIOCGIWRANGE, ipw_wx_get_range),
- IW_HANDLER(SIOCSIWAP, ipw_wx_set_wap),
- IW_HANDLER(SIOCGIWAP, ipw_wx_get_wap),
- IW_HANDLER(SIOCSIWSCAN, ipw_wx_set_scan),
- IW_HANDLER(SIOCGIWSCAN, ipw_wx_get_scan),
- IW_HANDLER(SIOCSIWESSID, ipw_wx_set_essid),
- IW_HANDLER(SIOCGIWESSID, ipw_wx_get_essid),
- IW_HANDLER(SIOCSIWNICKN, ipw_wx_set_nick),
- IW_HANDLER(SIOCGIWNICKN, ipw_wx_get_nick),
- IW_HANDLER(SIOCSIWRATE, ipw_wx_set_rate),
- IW_HANDLER(SIOCGIWRATE, ipw_wx_get_rate),
- IW_HANDLER(SIOCSIWRTS, ipw_wx_set_rts),
- IW_HANDLER(SIOCGIWRTS, ipw_wx_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ipw_wx_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ipw_wx_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, ipw_wx_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, ipw_wx_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, ipw_wx_set_retry),
- IW_HANDLER(SIOCGIWRETRY, ipw_wx_get_retry),
- IW_HANDLER(SIOCSIWENCODE, ipw_wx_set_encode),
- IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode),
- IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power),
- IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie),
- IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie),
- IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme),
- IW_HANDLER(SIOCSIWAUTH, ipw_wx_set_auth),
- IW_HANDLER(SIOCGIWAUTH, ipw_wx_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, ipw_wx_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, ipw_wx_get_encodeext),
-};
-
-enum {
- IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV,
- IPW_PRIV_GET_POWER,
- IPW_PRIV_SET_MODE,
- IPW_PRIV_GET_MODE,
- IPW_PRIV_SET_PREAMBLE,
- IPW_PRIV_GET_PREAMBLE,
- IPW_PRIV_RESET,
- IPW_PRIV_SW_RESET,
-#ifdef CONFIG_IPW2200_MONITOR
- IPW_PRIV_SET_MONITOR,
-#endif
-};
-
-static struct iw_priv_args ipw_priv_args[] = {
- {
- .cmd = IPW_PRIV_SET_POWER,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_power"},
- {
- .cmd = IPW_PRIV_GET_POWER,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_power"},
- {
- .cmd = IPW_PRIV_SET_MODE,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_mode"},
- {
- .cmd = IPW_PRIV_GET_MODE,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_mode"},
- {
- .cmd = IPW_PRIV_SET_PREAMBLE,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_preamble"},
- {
- .cmd = IPW_PRIV_GET_PREAMBLE,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ,
- .name = "get_preamble"},
- {
- IPW_PRIV_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
- {
- IPW_PRIV_SW_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"},
-#ifdef CONFIG_IPW2200_MONITOR
- {
- IPW_PRIV_SET_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
-#endif /* CONFIG_IPW2200_MONITOR */
-};
-
-static iw_handler ipw_priv_handler[] = {
- ipw_wx_set_powermode,
- ipw_wx_get_powermode,
- ipw_wx_set_wireless_mode,
- ipw_wx_get_wireless_mode,
- ipw_wx_set_preamble,
- ipw_wx_get_preamble,
- ipw_wx_reset,
- ipw_wx_sw_reset,
-#ifdef CONFIG_IPW2200_MONITOR
- ipw_wx_set_monitor,
-#endif
-};
-
-static const struct iw_handler_def ipw_wx_handler_def = {
- .standard = ipw_wx_handlers,
- .num_standard = ARRAY_SIZE(ipw_wx_handlers),
- .num_private = ARRAY_SIZE(ipw_priv_handler),
- .num_private_args = ARRAY_SIZE(ipw_priv_args),
- .private = ipw_priv_handler,
- .private_args = ipw_priv_args,
- .get_wireless_stats = ipw_get_wireless_stats,
-};
-
-/*
- * Get wireless statistics.
- * Called by /proc/net/wireless
- * Also called by SIOCGIWSTATS
- */
-static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_statistics *wstats;
-
- wstats = &priv->wstats;
-
- /* if hw is disabled, then ipw_get_ordinal() can't be called.
- * netdev->get_wireless_stats seems to be called before fw is
- * initialized. STATUS_ASSOCIATED will only be set if the hw is up
- * and associated; if not associcated, the values are all meaningless
- * anyway, so set them all to NULL and INVALID */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->miss.beacon = 0;
- wstats->discard.retries = 0;
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
- return wstats;
- }
-
- wstats->qual.qual = priv->quality;
- wstats->qual.level = priv->exp_avg_rssi;
- wstats->qual.noise = priv->exp_avg_noise;
- wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM;
-
- wstats->miss.beacon = average_value(&priv->average_missed_beacons);
- wstats->discard.retries = priv->last_tx_failures;
- wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable;
-
-/* if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len))
- goto fail_get_ordinal;
- wstats->discard.retries += tx_retry; */
-
- return wstats;
-}
-
-/* net device stuff */
-
-static void init_sys_config(struct ipw_sys_config *sys_config)
-{
- memset(sys_config, 0, sizeof(struct ipw_sys_config));
- sys_config->bt_coexistence = 0;
- sys_config->answer_broadcast_ssid_probe = 0;
- sys_config->accept_all_data_frames = 0;
- sys_config->accept_non_directed_frames = 1;
- sys_config->exclude_unicast_unencrypted = 0;
- sys_config->disable_unicast_decryption = 1;
- sys_config->exclude_multicast_unencrypted = 0;
- sys_config->disable_multicast_decryption = 1;
- if (antenna < CFG_SYS_ANTENNA_BOTH || antenna > CFG_SYS_ANTENNA_B)
- antenna = CFG_SYS_ANTENNA_BOTH;
- sys_config->antenna_diversity = antenna;
- sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */
- sys_config->dot11g_auto_detection = 0;
- sys_config->enable_cts_to_self = 0;
- sys_config->bt_coexist_collision_thr = 0;
- sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */
- sys_config->silence_threshold = 0x1e;
-}
-
-static int ipw_net_open(struct net_device *dev)
-{
- IPW_DEBUG_INFO("dev->open\n");
- netif_start_queue(dev);
- return 0;
-}
-
-static int ipw_net_stop(struct net_device *dev)
-{
- IPW_DEBUG_INFO("dev->close\n");
- netif_stop_queue(dev);
- return 0;
-}
-
-/*
-todo:
-
-modify to send one tfd per fragment instead of using chunking. otherwise
-we need to heavily modify the libipw_skb_to_txb.
-*/
-
-static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb,
- int pri)
-{
- struct libipw_hdr_3addrqos *hdr = (struct libipw_hdr_3addrqos *)
- txb->fragments[0]->data;
- int i = 0;
- struct tfd_frame *tfd;
-#ifdef CONFIG_IPW2200_QOS
- int tx_id = ipw_get_tx_queue_number(priv, pri);
- struct clx2_tx_queue *txq = &priv->txq[tx_id];
-#else
- struct clx2_tx_queue *txq = &priv->txq[0];
-#endif
- struct clx2_queue *q = &txq->q;
- u8 id, hdr_len, unicast;
- int fc;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- goto drop;
-
- hdr_len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- unicast = !is_multicast_ether_addr(hdr->addr1);
- id = ipw_find_station(priv, hdr->addr1);
- if (id == IPW_INVALID_STATION) {
- id = ipw_add_station(priv, hdr->addr1);
- if (id == IPW_INVALID_STATION) {
- IPW_WARNING("Attempt to send data to "
- "invalid cell: %pM\n",
- hdr->addr1);
- goto drop;
- }
- }
- break;
-
- case IW_MODE_INFRA:
- default:
- unicast = !is_multicast_ether_addr(hdr->addr3);
- id = 0;
- break;
- }
-
- tfd = &txq->bd[q->first_empty];
- txq->txb[q->first_empty] = txb;
- memset(tfd, 0, sizeof(*tfd));
- tfd->u.data.station_number = id;
-
- tfd->control_flags.message_type = TX_FRAME_TYPE;
- tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
-
- tfd->u.data.cmd_id = DINO_CMD_TX;
- tfd->u.data.len = cpu_to_le16(txb->payload_size);
-
- if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK;
- else
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM;
-
- if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE)
- tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE;
-
- fc = le16_to_cpu(hdr->frame_ctl);
- hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS);
-
- memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len);
-
- if (likely(unicast))
- tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
-
- if (txb->encrypted && !priv->ieee->host_encrypt) {
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- /* XXX: ACK flag must be set for CCMP even if it
- * is a multicast/broadcast packet, because CCMP
- * group communication encrypted by GTK is
- * actually done by the AP. */
- if (!unicast)
- tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
-
- tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM;
- tfd->u.data.key_index = 0;
- tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE;
- break;
- case SEC_LEVEL_2:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP;
- tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE;
- break;
- case SEC_LEVEL_1:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx;
- if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <=
- 40)
- tfd->u.data.key_index |= DCT_WEP_KEY_64Bit;
- else
- tfd->u.data.key_index |= DCT_WEP_KEY_128Bit;
- break;
- case SEC_LEVEL_0:
- break;
- default:
- printk(KERN_ERR "Unknown security level %d\n",
- priv->ieee->sec.level);
- break;
- }
- } else
- /* No hardware encryption */
- tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP;
-
-#ifdef CONFIG_IPW2200_QOS
- if (fc & IEEE80211_STYPE_QOS_DATA)
- ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data));
-#endif /* CONFIG_IPW2200_QOS */
-
- /* payload */
- tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2),
- txb->nr_frags));
- IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n",
- txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks));
- for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) {
- IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n",
- i, le32_to_cpu(tfd->u.data.num_chunks),
- txb->fragments[i]->len - hdr_len);
- IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n",
- i, tfd->u.data.num_chunks,
- txb->fragments[i]->len - hdr_len);
- printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len,
- txb->fragments[i]->len - hdr_len);
-
- tfd->u.data.chunk_ptr[i] =
- cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
- txb->fragments[i]->data + hdr_len,
- txb->fragments[i]->len - hdr_len,
- DMA_TO_DEVICE));
- tfd->u.data.chunk_len[i] =
- cpu_to_le16(txb->fragments[i]->len - hdr_len);
- }
-
- if (i != txb->nr_frags) {
- struct sk_buff *skb;
- u16 remaining_bytes = 0;
- int j;
-
- for (j = i; j < txb->nr_frags; j++)
- remaining_bytes += txb->fragments[j]->len - hdr_len;
-
- printk(KERN_INFO "Trying to reallocate for %d bytes\n",
- remaining_bytes);
- skb = alloc_skb(remaining_bytes, GFP_ATOMIC);
- if (skb != NULL) {
- tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes);
- for (j = i; j < txb->nr_frags; j++) {
- int size = txb->fragments[j]->len - hdr_len;
-
- printk(KERN_INFO "Adding frag %d %d...\n",
- j, size);
- skb_put_data(skb,
- txb->fragments[j]->data + hdr_len,
- size);
- }
- dev_kfree_skb_any(txb->fragments[i]);
- txb->fragments[i] = skb;
- tfd->u.data.chunk_ptr[i] =
- cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
- skb->data,
- remaining_bytes,
- DMA_TO_DEVICE));
-
- le32_add_cpu(&tfd->u.data.num_chunks, 1);
- }
- }
-
- /* kick DMA */
- q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
- ipw_write32(priv, q->reg_w, q->first_empty);
-
- if (ipw_tx_queue_space(q) < q->high_mark)
- netif_stop_queue(priv->net_dev);
-
- return NETDEV_TX_OK;
-
- drop:
- IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
- libipw_txb_free(txb);
- return NETDEV_TX_OK;
-}
-
-static int ipw_net_is_queue_full(struct net_device *dev, int pri)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-#ifdef CONFIG_IPW2200_QOS
- int tx_id = ipw_get_tx_queue_number(priv, pri);
- struct clx2_tx_queue *txq = &priv->txq[tx_id];
-#else
- struct clx2_tx_queue *txq = &priv->txq[0];
-#endif /* CONFIG_IPW2200_QOS */
-
- if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark)
- return 1;
-
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
- struct libipw_txb *txb)
-{
- struct libipw_rx_stats dummystats;
- struct ieee80211_hdr *hdr;
- u8 n;
- u16 filter = priv->prom_priv->filter;
- int hdr_only = 0;
-
- if (filter & IPW_PROM_NO_TX)
- return;
-
- memset(&dummystats, 0, sizeof(dummystats));
-
- /* Filtering of fragment chains is done against the first fragment */
- hdr = (void *)txb->fragments[0]->data;
- if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_MGMT)
- return;
- if (filter & IPW_PROM_MGMT_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_CTL)
- return;
- if (filter & IPW_PROM_CTL_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_DATA)
- return;
- if (filter & IPW_PROM_DATA_HEADER_ONLY)
- hdr_only = 1;
- }
-
- for(n=0; n<txb->nr_frags; ++n) {
- struct sk_buff *src = txb->fragments[n];
- struct sk_buff *dst;
- struct ieee80211_radiotap_header *rt_hdr;
- int len;
-
- if (hdr_only) {
- hdr = (void *)src->data;
- len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
- } else
- len = src->len;
-
- dst = alloc_skb(len + sizeof(*rt_hdr) + sizeof(u16)*2, GFP_ATOMIC);
- if (!dst)
- continue;
-
- rt_hdr = skb_put(dst, sizeof(*rt_hdr));
-
- rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION;
- rt_hdr->it_pad = 0;
- rt_hdr->it_present = 0; /* after all, it's just an idea */
- rt_hdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL);
-
- *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(
- ieee80211chan2mhz(priv->channel));
- if (priv->channel > 14) /* 802.11a */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ);
- else if (priv->ieee->mode == IEEE_B) /* 802.11b */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ);
- else /* 802.11g */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_2GHZ);
-
- rt_hdr->it_len = cpu_to_le16(dst->len);
-
- skb_copy_from_linear_data(src, skb_put(dst, len), len);
-
- if (!libipw_rx(priv->prom_priv->ieee, dst, &dummystats))
- dev_kfree_skb_any(dst);
- }
-}
-#endif
-
-static netdev_tx_t ipw_net_hard_start_xmit(struct libipw_txb *txb,
- struct net_device *dev, int pri)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- unsigned long flags;
- netdev_tx_t ret;
-
- IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
- spin_lock_irqsave(&priv->lock, flags);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (rtap_iface && netif_running(priv->prom_net_dev))
- ipw_handle_promiscuous_tx(priv, txb);
-#endif
-
- ret = ipw_tx_skb(priv, txb, pri);
- if (ret == NETDEV_TX_OK)
- __ipw_led_activity_on(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return ret;
-}
-
-static void ipw_net_set_multicast_list(struct net_device *dev)
-{
-
-}
-
-static int ipw_net_set_mac_address(struct net_device *dev, void *p)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct sockaddr *addr = p;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
- mutex_lock(&priv->mutex);
- priv->config |= CFG_CUSTOM_MAC;
- memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
- printk(KERN_INFO "%s: Setting MAC to %pM\n",
- priv->net_dev->name, priv->mac_addr);
- schedule_work(&priv->adapter_restart);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static void ipw_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct ipw_priv *p = libipw_priv(dev);
- char vers[64];
- char date[32];
- u32 len;
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
-
- len = sizeof(vers);
- ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len);
- len = sizeof(date);
- ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len);
-
- snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)",
- vers, date);
- strscpy(info->bus_info, pci_name(p->pci_dev),
- sizeof(info->bus_info));
-}
-
-static u32 ipw_ethtool_get_link(struct net_device *dev)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return (priv->status & STATUS_ASSOCIATED) != 0;
-}
-
-static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
-{
- return IPW_EEPROM_IMAGE_SIZE;
-}
-
-static int ipw_ethtool_get_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 * bytes)
-{
- struct ipw_priv *p = libipw_priv(dev);
-
- if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
- return -EINVAL;
- mutex_lock(&p->mutex);
- memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len);
- mutex_unlock(&p->mutex);
- return 0;
-}
-
-static int ipw_ethtool_set_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 * bytes)
-{
- struct ipw_priv *p = libipw_priv(dev);
- int i;
-
- if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
- return -EINVAL;
- mutex_lock(&p->mutex);
- memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len);
- for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
- ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]);
- mutex_unlock(&p->mutex);
- return 0;
-}
-
-static const struct ethtool_ops ipw_ethtool_ops = {
- .get_link = ipw_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
- .get_eeprom_len = ipw_ethtool_get_eeprom_len,
- .get_eeprom = ipw_ethtool_get_eeprom,
- .set_eeprom = ipw_ethtool_set_eeprom,
-};
-
-static irqreturn_t ipw_isr(int irq, void *data)
-{
- struct ipw_priv *priv = data;
- u32 inta, inta_mask;
-
- if (!priv)
- return IRQ_NONE;
-
- spin_lock(&priv->irq_lock);
-
- if (!(priv->status & STATUS_INT_ENABLED)) {
- /* IRQ is disabled */
- goto none;
- }
-
- inta = ipw_read32(priv, IPW_INTA_RW);
- inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n");
- goto none;
- }
-
- if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) {
- /* Shared interrupt */
- goto none;
- }
-
- /* tell the device to stop sending interrupts */
- __ipw_disable_interrupts(priv);
-
- /* ack current interrupts */
- inta &= (IPW_INTA_MASK_ALL & inta_mask);
- ipw_write32(priv, IPW_INTA_RW, inta);
-
- /* Cache INTA value for our tasklet */
- priv->isr_inta = inta;
-
- tasklet_schedule(&priv->irq_tasklet);
-
- spin_unlock(&priv->irq_lock);
-
- return IRQ_HANDLED;
- none:
- spin_unlock(&priv->irq_lock);
- return IRQ_NONE;
-}
-
-static void ipw_rf_kill(void *adapter)
-{
- struct ipw_priv *priv = adapter;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- goto exit_unlock;
- }
-
- /* RF Kill is now disabled, so bring the device back up */
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
- "device\n");
-
- /* we can not do an adapter restart while inside an irq lock */
- schedule_work(&priv->adapter_restart);
- } else
- IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
- "enabled\n");
-
- exit_unlock:
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_rf_kill(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, rf_kill.work);
- mutex_lock(&priv->mutex);
- ipw_rf_kill(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_link_up(struct ipw_priv *priv)
-{
- priv->last_seq_num = -1;
- priv->last_frag_num = -1;
- priv->last_packet_time = 0;
-
- netif_carrier_on(priv->net_dev);
-
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- ipw_reset_stats(priv);
- /* Ensure the rate is updated immediately */
- priv->last_rate = ipw_get_current_rate(priv);
- ipw_gather_stats(priv);
- ipw_led_link_up(priv);
- notify_wx_assoc_event(priv);
-
- if (priv->config & CFG_BACKGROUND_SCAN)
- schedule_delayed_work(&priv->request_scan, HZ);
-}
-
-static void ipw_bg_link_up(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, link_up);
- mutex_lock(&priv->mutex);
- ipw_link_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_link_down(struct ipw_priv *priv)
-{
- ipw_led_link_down(priv);
- netif_carrier_off(priv->net_dev);
- notify_wx_assoc_event(priv);
-
- /* Cancel any queued work ... */
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->adhoc_check);
- cancel_delayed_work(&priv->gather_stats);
-
- ipw_reset_stats(priv);
-
- if (!(priv->status & STATUS_EXIT_PENDING)) {
- /* Queue up another scan... */
- schedule_delayed_work(&priv->request_scan, 0);
- } else
- cancel_delayed_work(&priv->scan_event);
-}
-
-static void ipw_bg_link_down(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, link_down);
- mutex_lock(&priv->mutex);
- ipw_link_down(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_setup_deferred_work(struct ipw_priv *priv)
-{
- init_waitqueue_head(&priv->wait_command_queue);
- init_waitqueue_head(&priv->wait_state);
-
- INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check);
- INIT_WORK(&priv->associate, ipw_bg_associate);
- INIT_WORK(&priv->disassociate, ipw_bg_disassociate);
- INIT_WORK(&priv->system_config, ipw_system_config);
- INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish);
- INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart);
- INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill);
- INIT_WORK(&priv->up, ipw_bg_up);
- INIT_WORK(&priv->down, ipw_bg_down);
- INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
- INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan);
- INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
- INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
- INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
- INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
- INIT_WORK(&priv->roam, ipw_bg_roam);
- INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check);
- INIT_WORK(&priv->link_up, ipw_bg_link_up);
- INIT_WORK(&priv->link_down, ipw_bg_link_down);
- INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on);
- INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off);
- INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off);
- INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network);
-
-#ifdef CONFIG_IPW2200_QOS
- INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate);
-#endif /* CONFIG_IPW2200_QOS */
-
- tasklet_setup(&priv->irq_tasklet, ipw_irq_tasklet);
-}
-
-static void shim__set_security(struct net_device *dev,
- struct libipw_security *sec)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int i;
- for (i = 0; i < 4; i++) {
- if (sec->flags & (1 << i)) {
- priv->ieee->sec.encode_alg[i] = sec->encode_alg[i];
- priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
- if (sec->key_sizes[i] == 0)
- priv->ieee->sec.flags &= ~(1 << i);
- else {
- memcpy(priv->ieee->sec.keys[i], sec->keys[i],
- sec->key_sizes[i]);
- priv->ieee->sec.flags |= (1 << i);
- }
- priv->status |= STATUS_SECURITY_UPDATED;
- } else if (sec->level != SEC_LEVEL_1)
- priv->ieee->sec.flags &= ~(1 << i);
- }
-
- if (sec->flags & SEC_ACTIVE_KEY) {
- priv->ieee->sec.active_key = sec->active_key;
- priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- } else
- priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
-
- if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->ieee->sec.auth_mode != sec->auth_mode)) {
- priv->ieee->sec.auth_mode = sec->auth_mode;
- priv->ieee->sec.flags |= SEC_AUTH_MODE;
- if (sec->auth_mode == WLAN_AUTH_SHARED_KEY)
- priv->capability |= CAP_SHARED_KEY;
- else
- priv->capability &= ~CAP_SHARED_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
- priv->ieee->sec.flags |= SEC_ENABLED;
- priv->ieee->sec.enabled = sec->enabled;
- priv->status |= STATUS_SECURITY_UPDATED;
- if (sec->enabled)
- priv->capability |= CAP_PRIVACY_ON;
- else
- priv->capability &= ~CAP_PRIVACY_ON;
- }
-
- if (sec->flags & SEC_ENCRYPT)
- priv->ieee->sec.encrypt = sec->encrypt;
-
- if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
- priv->ieee->sec.level = sec->level;
- priv->ieee->sec.flags |= SEC_LEVEL;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT))
- ipw_set_hwcrypto_keys(priv);
-
- /* To match current functionality of ipw2100 (which works well w/
- * various supplicants, we don't force a disassociate if the
- * privacy capability changes ... */
-#if 0
- if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) &&
- (((priv->assoc_request.capability &
- cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && !sec->enabled) ||
- (!(priv->assoc_request.capability &
- cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && sec->enabled))) {
- IPW_DEBUG_ASSOC("Disassociating due to capability "
- "change.\n");
- ipw_disassociate(priv);
- }
-#endif
-}
-
-static int init_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *rates)
-{
- /* TODO: Mask out rates based on priv->rates_mask */
-
- memset(rates, 0, sizeof(*rates));
- /* configure supported rates */
- switch (priv->ieee->freq_band) {
- case LIBIPW_52GHZ_BAND:
- rates->ieee_mode = IPW_A_MODE;
- rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_OFDM_DEFAULT_RATES_MASK);
- break;
-
- default: /* Mixed or 2.4Ghz */
- rates->ieee_mode = IPW_G_MODE;
- rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_cck_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_CCK_DEFAULT_RATES_MASK);
- if (priv->ieee->modulation & LIBIPW_OFDM_MODULATION) {
- ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_OFDM_DEFAULT_RATES_MASK);
- }
- break;
- }
-
- return 0;
-}
-
-static int ipw_config(struct ipw_priv *priv)
-{
- /* This is only called from ipw_up, which resets/reloads the firmware
- so, we don't need to first disable the card before we configure
- it */
- if (ipw_set_tx_power(priv))
- goto error;
-
- /* initialize adapter address */
- if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr))
- goto error;
-
- /* set basic system config settings */
- init_sys_config(&priv->sys_config);
-
- /* Support Bluetooth if we have BT h/w on board, and user wants to.
- * Does not support BT priority yet (don't abort or defer our Tx) */
- if (bt_coexist) {
- unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY];
-
- if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG)
- priv->sys_config.bt_coexistence
- |= CFG_BT_COEXISTENCE_SIGNAL_CHNL;
- if (bt_caps & EEPROM_SKU_CAP_BT_OOB)
- priv->sys_config.bt_coexistence
- |= CFG_BT_COEXISTENCE_OOB;
- }
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
- }
-#endif
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->sys_config.answer_broadcast_ssid_probe = 1;
- else
- priv->sys_config.answer_broadcast_ssid_probe = 0;
-
- if (ipw_send_system_config(priv))
- goto error;
-
- init_supported_rates(priv, &priv->rates);
- if (ipw_send_supported_rates(priv, &priv->rates))
- goto error;
-
- /* Set request-to-send threshold */
- if (priv->rts_threshold) {
- if (ipw_send_rts_threshold(priv, priv->rts_threshold))
- goto error;
- }
-#ifdef CONFIG_IPW2200_QOS
- IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n");
- ipw_qos_activate(priv, NULL);
-#endif /* CONFIG_IPW2200_QOS */
-
- if (ipw_set_random_seed(priv))
- goto error;
-
- /* final state transition to the RUN state */
- if (ipw_send_host_complete(priv))
- goto error;
-
- priv->status |= STATUS_INIT;
-
- ipw_led_init(priv);
- ipw_led_radio_on(priv);
- priv->notif_missed_beacons = 0;
-
- /* Set hardware WEP key if it is configured. */
- if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.level == SEC_LEVEL_1) &&
- !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
- ipw_set_hwcrypto_keys(priv);
-
- return 0;
-
- error:
- return -EIO;
-}
-
-/*
- * NOTE:
- *
- * These tables have been tested in conjunction with the
- * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters.
- *
- * Altering this values, using it on other hardware, or in geographies
- * not intended for resale of the above mentioned Intel adapters has
- * not been tested.
- *
- * Remember to update the table in README.ipw2200 when changing this
- * table.
- *
- */
-static const struct libipw_geo ipw_geos[] = {
- { /* Restricted */
- "---",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- },
-
- { /* Custom US/Canada */
- "ZZF",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 8,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Rest of World */
- "ZZD",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}},
- },
-
- { /* Custom USA & Europe & High */
- "ZZA",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149},
- {5765, 153},
- {5785, 157},
- {5805, 161},
- {5825, 165}},
- },
-
- { /* Custom NA & Europe */
- "ZZB",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Custom Japan */
- "ZZC",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 4,
- .a = {{5170, 34}, {5190, 38},
- {5210, 42}, {5230, 46}},
- },
-
- { /* Custom */
- "ZZM",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- },
-
- { /* Europe */
- "ZZE",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}},
- .a_channels = 19,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
- {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
- {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
- {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
- {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
- {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
- {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
- {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
- {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
- {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
- {5700, 140, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Custom Japan */
- "ZZJ",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY}},
- .a_channels = 4,
- .a = {{5170, 34}, {5190, 38},
- {5210, 42}, {5230, 46}},
- },
-
- { /* Rest of World */
- "ZZR",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY |
- LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* High Band */
- "ZZH",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
- {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
- .a_channels = 4,
- .a = {{5745, 149}, {5765, 153},
- {5785, 157}, {5805, 161}},
- },
-
- { /* Custom Europe */
- "ZZG",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12}, {2472, 13}},
- .a_channels = 4,
- .a = {{5180, 36}, {5200, 40},
- {5220, 44}, {5240, 48}},
- },
-
- { /* Europe */
- "ZZK",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
- {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
- .a_channels = 24,
- .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
- {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
- {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
- {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
- {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
- {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
- {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
- {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
- {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
- {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
- {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
- {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
- {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
- {5700, 140, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Europe */
- "ZZL",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
- {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
- {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
- {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- }
-};
-
-static void ipw_set_geo(struct ipw_priv *priv)
-{
- int j;
-
- for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
- if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
- ipw_geos[j].name, 3))
- break;
- }
-
- if (j == ARRAY_SIZE(ipw_geos)) {
- IPW_WARNING("SKU [%c%c%c] not recognized.\n",
- priv->eeprom[EEPROM_COUNTRY_CODE + 0],
- priv->eeprom[EEPROM_COUNTRY_CODE + 1],
- priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
- j = 0;
- }
-
- libipw_set_geo(priv->ieee, &ipw_geos[j]);
-}
-
-#define MAX_HW_RESTARTS 5
-static int ipw_up(struct ipw_priv *priv)
-{
- int rc, i;
-
- /* Age scan list entries found before suspend */
- if (priv->suspend_time) {
- libipw_networks_age(priv->ieee, priv->suspend_time);
- priv->suspend_time = 0;
- }
-
- if (priv->status & STATUS_EXIT_PENDING)
- return -EIO;
-
- if (cmdlog && !priv->cmdlog) {
- priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog),
- GFP_KERNEL);
- if (priv->cmdlog == NULL) {
- IPW_ERROR("Error allocating %d command log entries.\n",
- cmdlog);
- return -ENOMEM;
- } else {
- priv->cmdlog_len = cmdlog;
- }
- }
-
- for (i = 0; i < MAX_HW_RESTARTS; i++) {
- /* Load the microcode, firmware, and eeprom.
- * Also start the clocks. */
- rc = ipw_load(priv);
- if (rc) {
- IPW_ERROR("Unable to load firmware: %d\n", rc);
- return rc;
- }
-
- ipw_init_ordinals(priv);
- if (!(priv->config & CFG_CUSTOM_MAC))
- eeprom_parse_mac(priv, priv->mac_addr);
- eth_hw_addr_set(priv->net_dev, priv->mac_addr);
-
- ipw_set_geo(priv);
-
- if (priv->status & STATUS_RF_KILL_SW) {
- IPW_WARNING("Radio disabled by module parameter.\n");
- return 0;
- } else if (rf_kill_active(priv)) {
- IPW_WARNING("Radio Frequency Kill Switch is On:\n"
- "Kill switch must be turned off for "
- "wireless networking to work.\n");
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- return 0;
- }
-
- rc = ipw_config(priv);
- if (!rc) {
- IPW_DEBUG_INFO("Configured device on count %i\n", i);
-
- /* If configure to try and auto-associate, kick
- * off a scan. */
- schedule_delayed_work(&priv->request_scan, 0);
-
- return 0;
- }
-
- IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc);
- IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n",
- i, MAX_HW_RESTARTS);
-
- /* We had an error bringing up the hardware, so take it
- * all the way back down so we can try again */
- ipw_down(priv);
- }
-
- /* tried to restart and config the device for as long as our
- * patience could withstand */
- IPW_ERROR("Unable to initialize device after %d attempts.\n", i);
-
- return -EIO;
-}
-
-static void ipw_bg_up(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, up);
- mutex_lock(&priv->mutex);
- ipw_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_deinit(struct ipw_priv *priv)
-{
- int i;
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_INFO("Aborting scan during shutdown.\n");
- ipw_abort_scan(priv);
- }
-
- if (priv->status & STATUS_ASSOCIATED) {
- IPW_DEBUG_INFO("Disassociating during shutdown.\n");
- ipw_disassociate(priv);
- }
-
- ipw_led_shutdown(priv);
-
- /* Wait up to 1s for status to change to not scanning and not
- * associated (disassociation can take a while for a ful 802.11
- * exchange */
- for (i = 1000; i && (priv->status &
- (STATUS_DISASSOCIATING |
- STATUS_ASSOCIATED | STATUS_SCANNING)); i--)
- udelay(10);
-
- if (priv->status & (STATUS_DISASSOCIATING |
- STATUS_ASSOCIATED | STATUS_SCANNING))
- IPW_DEBUG_INFO("Still associated or scanning...\n");
- else
- IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i);
-
- /* Attempt to disable the card */
- ipw_send_card_disable(priv, 0);
-
- priv->status &= ~STATUS_INIT;
-}
-
-static void ipw_down(struct ipw_priv *priv)
-{
- int exit_pending = priv->status & STATUS_EXIT_PENDING;
-
- priv->status |= STATUS_EXIT_PENDING;
-
- if (ipw_is_init(priv))
- ipw_deinit(priv);
-
- /* Wipe out the EXIT_PENDING status bit if we are not actually
- * exiting the module */
- if (!exit_pending)
- priv->status &= ~STATUS_EXIT_PENDING;
-
- /* tell the device to stop sending interrupts */
- ipw_disable_interrupts(priv);
-
- /* Clear all bits but the RF Kill */
- priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING;
- netif_carrier_off(priv->net_dev);
-
- ipw_stop_nic(priv);
-
- ipw_led_radio_off(priv);
-}
-
-static void ipw_bg_down(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, down);
- mutex_lock(&priv->mutex);
- ipw_down(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_wdev_init(struct net_device *dev)
-{
- int i, rc = 0;
- struct ipw_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct wireless_dev *wdev = &priv->ieee->wdev;
-
- memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
-
- /* fill-out priv->ieee->bg_band */
- if (geo->bg_channels) {
- struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
-
- bg_band->band = NL80211_BAND_2GHZ;
- bg_band->n_channels = geo->bg_channels;
- bg_band->channels = kcalloc(geo->bg_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!bg_band->channels) {
- rc = -ENOMEM;
- goto out;
- }
- /* translate geo->bg to bg_band.channels */
- for (i = 0; i < geo->bg_channels; i++) {
- bg_band->channels[i].band = NL80211_BAND_2GHZ;
- bg_band->channels[i].center_freq = geo->bg[i].freq;
- bg_band->channels[i].hw_value = geo->bg[i].channel;
- bg_band->channels[i].max_power = geo->bg[i].max_power;
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- bg_band->bitrates = ipw2200_bg_rates;
- bg_band->n_bitrates = ipw2200_num_bg_rates;
-
- wdev->wiphy->bands[NL80211_BAND_2GHZ] = bg_band;
- }
-
- /* fill-out priv->ieee->a_band */
- if (geo->a_channels) {
- struct ieee80211_supported_band *a_band = &priv->ieee->a_band;
-
- a_band->band = NL80211_BAND_5GHZ;
- a_band->n_channels = geo->a_channels;
- a_band->channels = kcalloc(geo->a_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!a_band->channels) {
- rc = -ENOMEM;
- goto out;
- }
- /* translate geo->a to a_band.channels */
- for (i = 0; i < geo->a_channels; i++) {
- a_band->channels[i].band = NL80211_BAND_5GHZ;
- a_band->channels[i].center_freq = geo->a[i].freq;
- a_band->channels[i].hw_value = geo->a[i].channel;
- a_band->channels[i].max_power = geo->a[i].max_power;
- if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- a_band->bitrates = ipw2200_a_rates;
- a_band->n_bitrates = ipw2200_num_a_rates;
-
- wdev->wiphy->bands[NL80211_BAND_5GHZ] = a_band;
- }
-
- wdev->wiphy->cipher_suites = ipw_cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
-
- set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
-
- /* With that information in place, we can now register the wiphy... */
- rc = wiphy_register(wdev->wiphy);
- if (rc)
- goto out;
-
- return 0;
-out:
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- return rc;
-}
-
-/* PCI driver stuff */
-static const struct pci_device_id card_ids[] = {
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
- {PCI_VDEVICE(INTEL, 0x104f), 0},
- {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
- {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
- {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
- {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */
-
- /* required last entry */
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, card_ids);
-
-static struct attribute *ipw_sysfs_entries[] = {
- &dev_attr_rf_kill.attr,
- &dev_attr_direct_dword.attr,
- &dev_attr_indirect_byte.attr,
- &dev_attr_indirect_dword.attr,
- &dev_attr_mem_gpio_reg.attr,
- &dev_attr_command_event_reg.attr,
- &dev_attr_nic_type.attr,
- &dev_attr_status.attr,
- &dev_attr_cfg.attr,
- &dev_attr_error.attr,
- &dev_attr_event_log.attr,
- &dev_attr_cmd_log.attr,
- &dev_attr_eeprom_delay.attr,
- &dev_attr_ucode_version.attr,
- &dev_attr_rtc.attr,
- &dev_attr_scan_age.attr,
- &dev_attr_led.attr,
- &dev_attr_speed_scan.attr,
- &dev_attr_net_stats.attr,
- &dev_attr_channels.attr,
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- &dev_attr_rtap_iface.attr,
- &dev_attr_rtap_filter.attr,
-#endif
- NULL
-};
-
-static const struct attribute_group ipw_attribute_group = {
- .name = NULL, /* put in device directory */
- .attrs = ipw_sysfs_entries,
-};
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static int ipw_prom_open(struct net_device *dev)
-{
- struct ipw_prom_priv *prom_priv = libipw_priv(dev);
- struct ipw_priv *priv = prom_priv->priv;
-
- IPW_DEBUG_INFO("prom dev->open\n");
- netif_carrier_off(dev);
-
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
-
- ipw_send_system_config(priv);
- }
-
- return 0;
-}
-
-static int ipw_prom_stop(struct net_device *dev)
-{
- struct ipw_prom_priv *prom_priv = libipw_priv(dev);
- struct ipw_priv *priv = prom_priv->priv;
-
- IPW_DEBUG_INFO("prom dev->stop\n");
-
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- priv->sys_config.accept_all_data_frames = 0;
- priv->sys_config.accept_non_directed_frames = 0;
- priv->sys_config.accept_all_mgmt_bcpr = 0;
- priv->sys_config.accept_all_mgmt_frames = 0;
-
- ipw_send_system_config(priv);
- }
-
- return 0;
-}
-
-static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- IPW_DEBUG_INFO("prom dev->xmit\n");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops ipw_prom_netdev_ops = {
- .ndo_open = ipw_prom_open,
- .ndo_stop = ipw_prom_stop,
- .ndo_start_xmit = ipw_prom_hard_start_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ipw_prom_alloc(struct ipw_priv *priv)
-{
- int rc = 0;
-
- if (priv->prom_net_dev)
- return -EPERM;
-
- priv->prom_net_dev = alloc_libipw(sizeof(struct ipw_prom_priv), 1);
- if (priv->prom_net_dev == NULL)
- return -ENOMEM;
-
- priv->prom_priv = libipw_priv(priv->prom_net_dev);
- priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev);
- priv->prom_priv->priv = priv;
-
- strcpy(priv->prom_net_dev->name, "rtap%d");
- eth_hw_addr_set(priv->prom_net_dev, priv->mac_addr);
-
- priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- priv->prom_net_dev->netdev_ops = &ipw_prom_netdev_ops;
-
- priv->prom_net_dev->min_mtu = 68;
- priv->prom_net_dev->max_mtu = LIBIPW_DATA_LEN;
-
- priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;
- SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev);
-
- rc = register_netdev(priv->prom_net_dev);
- if (rc) {
- free_libipw(priv->prom_net_dev, 1);
- priv->prom_net_dev = NULL;
- return rc;
- }
-
- return 0;
-}
-
-static void ipw_prom_free(struct ipw_priv *priv)
-{
- if (!priv->prom_net_dev)
- return;
-
- unregister_netdev(priv->prom_net_dev);
- free_libipw(priv->prom_net_dev, 1);
-
- priv->prom_net_dev = NULL;
-}
-
-#endif
-
-static const struct net_device_ops ipw_netdev_ops = {
- .ndo_open = ipw_net_open,
- .ndo_stop = ipw_net_stop,
- .ndo_set_rx_mode = ipw_net_set_multicast_list,
- .ndo_set_mac_address = ipw_net_set_mac_address,
- .ndo_start_xmit = libipw_xmit,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ipw_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err = 0;
- struct net_device *net_dev;
- void __iomem *base;
- u32 length, val;
- struct ipw_priv *priv;
- int i;
-
- net_dev = alloc_libipw(sizeof(struct ipw_priv), 0);
- if (net_dev == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- priv = libipw_priv(net_dev);
- priv->ieee = netdev_priv(net_dev);
-
- priv->net_dev = net_dev;
- priv->pci_dev = pdev;
- ipw_debug_level = debug;
- spin_lock_init(&priv->irq_lock);
- spin_lock_init(&priv->lock);
- for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
- INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
- mutex_init(&priv->mutex);
- if (pci_enable_device(pdev)) {
- err = -ENODEV;
- goto out_free_libipw;
- }
-
- pci_set_master(pdev);
-
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (!err)
- err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (err) {
- printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
- goto out_pci_disable_device;
- }
-
- pci_set_drvdata(pdev, priv);
-
- err = pci_request_regions(pdev, DRV_NAME);
- if (err)
- goto out_pci_disable_device;
-
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- length = pci_resource_len(pdev, 0);
- priv->hw_len = length;
-
- base = pci_ioremap_bar(pdev, 0);
- if (!base) {
- err = -ENODEV;
- goto out_pci_release_regions;
- }
-
- priv->hw_base = base;
- IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length);
- IPW_DEBUG_INFO("pci_resource_base = %p\n", base);
-
- ipw_setup_deferred_work(priv);
-
- ipw_sw_reset(priv, 1);
-
- err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv);
- if (err) {
- IPW_ERROR("Error allocating IRQ %d\n", pdev->irq);
- goto out_iounmap;
- }
-
- SET_NETDEV_DEV(net_dev, &pdev->dev);
-
- mutex_lock(&priv->mutex);
-
- priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
- priv->ieee->set_security = shim__set_security;
- priv->ieee->is_queue_full = ipw_net_is_queue_full;
-
-#ifdef CONFIG_IPW2200_QOS
- priv->ieee->is_qos_active = ipw_is_qos_active;
- priv->ieee->handle_probe_response = ipw_handle_beacon;
- priv->ieee->handle_beacon = ipw_handle_probe_response;
- priv->ieee->handle_assoc_response = ipw_handle_assoc_response;
-#endif /* CONFIG_IPW2200_QOS */
-
- priv->ieee->perfect_rssi = -20;
- priv->ieee->worst_rssi = -85;
-
- net_dev->netdev_ops = &ipw_netdev_ops;
- priv->wireless_data.spy_data = &priv->ieee->spy_data;
- net_dev->wireless_data = &priv->wireless_data;
- net_dev->wireless_handlers = &ipw_wx_handler_def;
- net_dev->ethtool_ops = &ipw_ethtool_ops;
-
- net_dev->min_mtu = 68;
- net_dev->max_mtu = LIBIPW_DATA_LEN;
-
- err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
- if (err) {
- IPW_ERROR("failed to create sysfs device attributes\n");
- mutex_unlock(&priv->mutex);
- goto out_release_irq;
- }
-
- if (ipw_up(priv)) {
- mutex_unlock(&priv->mutex);
- err = -EIO;
- goto out_remove_sysfs;
- }
-
- mutex_unlock(&priv->mutex);
-
- err = ipw_wdev_init(net_dev);
- if (err) {
- IPW_ERROR("failed to register wireless device\n");
- goto out_remove_sysfs;
- }
-
- err = register_netdev(net_dev);
- if (err) {
- IPW_ERROR("failed to register network device\n");
- goto out_unregister_wiphy;
- }
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (rtap_iface) {
- err = ipw_prom_alloc(priv);
- if (err) {
- IPW_ERROR("Failed to register promiscuous network "
- "device (error %d).\n", err);
- unregister_netdev(priv->net_dev);
- goto out_unregister_wiphy;
- }
- }
-#endif
-
- printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg "
- "channels, %d 802.11a channels)\n",
- priv->ieee->geo.name, priv->ieee->geo.bg_channels,
- priv->ieee->geo.a_channels);
-
- return 0;
-
- out_unregister_wiphy:
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- out_remove_sysfs:
- sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
- out_release_irq:
- free_irq(pdev->irq, priv);
- out_iounmap:
- iounmap(priv->hw_base);
- out_pci_release_regions:
- pci_release_regions(pdev);
- out_pci_disable_device:
- pci_disable_device(pdev);
- out_free_libipw:
- free_libipw(priv->net_dev, 0);
- out:
- return err;
-}
-
-static void ipw_pci_remove(struct pci_dev *pdev)
-{
- struct ipw_priv *priv = pci_get_drvdata(pdev);
- struct list_head *p, *q;
- int i;
-
- if (!priv)
- return;
-
- mutex_lock(&priv->mutex);
-
- priv->status |= STATUS_EXIT_PENDING;
- ipw_down(priv);
- sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
-
- mutex_unlock(&priv->mutex);
-
- unregister_netdev(priv->net_dev);
-
- if (priv->rxq) {
- ipw_rx_queue_free(priv, priv->rxq);
- priv->rxq = NULL;
- }
- ipw_tx_queue_free(priv);
-
- if (priv->cmdlog) {
- kfree(priv->cmdlog);
- priv->cmdlog = NULL;
- }
-
- /* make sure all works are inactive */
- cancel_delayed_work_sync(&priv->adhoc_check);
- cancel_work_sync(&priv->associate);
- cancel_work_sync(&priv->disassociate);
- cancel_work_sync(&priv->system_config);
- cancel_work_sync(&priv->rx_replenish);
- cancel_work_sync(&priv->adapter_restart);
- cancel_delayed_work_sync(&priv->rf_kill);
- cancel_work_sync(&priv->up);
- cancel_work_sync(&priv->down);
- cancel_delayed_work_sync(&priv->request_scan);
- cancel_delayed_work_sync(&priv->request_direct_scan);
- cancel_delayed_work_sync(&priv->request_passive_scan);
- cancel_delayed_work_sync(&priv->scan_event);
- cancel_delayed_work_sync(&priv->gather_stats);
- cancel_work_sync(&priv->abort_scan);
- cancel_work_sync(&priv->roam);
- cancel_delayed_work_sync(&priv->scan_check);
- cancel_work_sync(&priv->link_up);
- cancel_work_sync(&priv->link_down);
- cancel_delayed_work_sync(&priv->led_link_on);
- cancel_delayed_work_sync(&priv->led_link_off);
- cancel_delayed_work_sync(&priv->led_act_off);
- cancel_work_sync(&priv->merge_networks);
-
- /* Free MAC hash list for ADHOC */
- for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) {
- list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
- list_del(p);
- kfree(list_entry(p, struct ipw_ibss_seq, list));
- }
- }
-
- kfree(priv->error);
- priv->error = NULL;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- ipw_prom_free(priv);
-#endif
-
- free_irq(pdev->irq, priv);
- iounmap(priv->hw_base);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- /* wiphy_unregister needs to be here, before free_libipw */
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- free_libipw(priv->net_dev, 0);
- free_firmware();
-}
-
-static int __maybe_unused ipw_pci_suspend(struct device *dev_d)
-{
- struct ipw_priv *priv = dev_get_drvdata(dev_d);
- struct net_device *dev = priv->net_dev;
-
- printk(KERN_INFO "%s: Going into suspend...\n", dev->name);
-
- /* Take down the device; powers it off, etc. */
- ipw_down(priv);
-
- /* Remove the PRESENT state of the device */
- netif_device_detach(dev);
-
- priv->suspend_at = ktime_get_boottime_seconds();
-
- return 0;
-}
-
-static int __maybe_unused ipw_pci_resume(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct ipw_priv *priv = pci_get_drvdata(pdev);
- struct net_device *dev = priv->net_dev;
- u32 val;
-
- printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
-
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
- * from interfering with C3 CPU state. pci_restore_state won't help
- * here since it only restores the first 64 bytes pci config header.
- */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- /* Set the device back into the PRESENT state; this will also wake
- * the queue of needed */
- netif_device_attach(dev);
-
- priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at;
-
- /* Bring the device back up */
- schedule_work(&priv->up);
-
- return 0;
-}
-
-static void ipw_pci_shutdown(struct pci_dev *pdev)
-{
- struct ipw_priv *priv = pci_get_drvdata(pdev);
-
- /* Take down the device; powers it off, etc. */
- ipw_down(priv);
-
- pci_disable_device(pdev);
-}
-
-static SIMPLE_DEV_PM_OPS(ipw_pci_pm_ops, ipw_pci_suspend, ipw_pci_resume);
-
-/* driver initialization stuff */
-static struct pci_driver ipw_driver = {
- .name = DRV_NAME,
- .id_table = card_ids,
- .probe = ipw_pci_probe,
- .remove = ipw_pci_remove,
- .driver.pm = &ipw_pci_pm_ops,
- .shutdown = ipw_pci_shutdown,
-};
-
-static int __init ipw_init(void)
-{
- int ret;
-
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-
- ret = pci_register_driver(&ipw_driver);
- if (ret) {
- IPW_ERROR("Unable to initialize PCI module\n");
- return ret;
- }
-
- ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level);
- if (ret) {
- IPW_ERROR("Unable to create driver sysfs file\n");
- pci_unregister_driver(&ipw_driver);
- return ret;
- }
-
- return ret;
-}
-
-static void __exit ipw_exit(void)
-{
- driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level);
- pci_unregister_driver(&ipw_driver);
-}
-
-module_param(disable, int, 0444);
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-
-module_param(associate, int, 0444);
-MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
-
-module_param(auto_create, int, 0444);
-MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
-
-module_param_named(led, led_support, int, 0444);
-MODULE_PARM_DESC(led, "enable led control on some systems (default 1 on)");
-
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
-
-module_param_named(channel, default_channel, int, 0444);
-MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-module_param(rtap_iface, int, 0444);
-MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)");
-#endif
-
-#ifdef CONFIG_IPW2200_QOS
-module_param(qos_enable, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionalities");
-
-module_param(qos_burst_enable, int, 0444);
-MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode");
-
-module_param(qos_no_ack_mask, int, 0444);
-MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack");
-
-module_param(burst_duration_CCK, int, 0444);
-MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value");
-
-module_param(burst_duration_OFDM, int, 0444);
-MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
-#endif /* CONFIG_IPW2200_QOS */
-
-#ifdef CONFIG_IPW2200_MONITOR
-module_param_named(mode, network_mode, int, 0444);
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
-#else
-module_param_named(mode, network_mode, int, 0444);
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
-#endif
-
-module_param(bt_coexist, int, 0444);
-MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)");
-
-module_param(hwcrypto, int, 0444);
-MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)");
-
-module_param(cmdlog, int, 0444);
-MODULE_PARM_DESC(cmdlog,
- "allocate a ring buffer for logging firmware commands");
-
-module_param(roaming, int, 0444);
-MODULE_PARM_DESC(roaming, "enable roaming support (default on)");
-
-module_param(antenna, int, 0444);
-MODULE_PARM_DESC(antenna, "select antenna 1=Main, 3=Aux, default 0 [both], 2=slow_diversity (choose the one with lower background noise)");
-
-module_exit(ipw_exit);
-module_init(ipw_init);
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h
deleted file mode 100644
index 8ebf09121e173..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h
+++ /dev/null
@@ -1,1984 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#ifndef __ipw2200_h__
-#define __ipw2200_h__
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/firmware.h>
-#include <linux/wireless.h>
-#include <linux/jiffies.h>
-#include <asm/io.h>
-
-#include <net/lib80211.h>
-#include <net/ieee80211_radiotap.h>
-
-#define DRV_NAME "ipw2200"
-
-#include <linux/workqueue.h>
-
-#include "libipw.h"
-
-/* Authentication and Association States */
-enum connection_manager_assoc_states {
- CMAS_INIT = 0,
- CMAS_TX_AUTH_SEQ_1,
- CMAS_RX_AUTH_SEQ_2,
- CMAS_AUTH_SEQ_1_PASS,
- CMAS_AUTH_SEQ_1_FAIL,
- CMAS_TX_AUTH_SEQ_3,
- CMAS_RX_AUTH_SEQ_4,
- CMAS_AUTH_SEQ_2_PASS,
- CMAS_AUTH_SEQ_2_FAIL,
- CMAS_AUTHENTICATED,
- CMAS_TX_ASSOC,
- CMAS_RX_ASSOC_RESP,
- CMAS_ASSOCIATED,
- CMAS_LAST
-};
-
-#define IPW_WAIT (1<<0)
-#define IPW_QUIET (1<<1)
-#define IPW_ROAMING (1<<2)
-
-#define IPW_POWER_MODE_CAM 0x00 //(always on)
-#define IPW_POWER_INDEX_1 0x01
-#define IPW_POWER_INDEX_2 0x02
-#define IPW_POWER_INDEX_3 0x03
-#define IPW_POWER_INDEX_4 0x04
-#define IPW_POWER_INDEX_5 0x05
-#define IPW_POWER_AC 0x06
-#define IPW_POWER_BATTERY 0x07
-#define IPW_POWER_LIMIT 0x07
-#define IPW_POWER_MASK 0x0F
-#define IPW_POWER_ENABLED 0x10
-#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
-
-#define IPW_CMD_HOST_COMPLETE 2
-#define IPW_CMD_POWER_DOWN 4
-#define IPW_CMD_SYSTEM_CONFIG 6
-#define IPW_CMD_MULTICAST_ADDRESS 7
-#define IPW_CMD_SSID 8
-#define IPW_CMD_ADAPTER_ADDRESS 11
-#define IPW_CMD_PORT_TYPE 12
-#define IPW_CMD_RTS_THRESHOLD 15
-#define IPW_CMD_FRAG_THRESHOLD 16
-#define IPW_CMD_POWER_MODE 17
-#define IPW_CMD_WEP_KEY 18
-#define IPW_CMD_TGI_TX_KEY 19
-#define IPW_CMD_SCAN_REQUEST 20
-#define IPW_CMD_ASSOCIATE 21
-#define IPW_CMD_SUPPORTED_RATES 22
-#define IPW_CMD_SCAN_ABORT 23
-#define IPW_CMD_TX_FLUSH 24
-#define IPW_CMD_QOS_PARAMETERS 25
-#define IPW_CMD_SCAN_REQUEST_EXT 26
-#define IPW_CMD_DINO_CONFIG 30
-#define IPW_CMD_RSN_CAPABILITIES 31
-#define IPW_CMD_RX_KEY 32
-#define IPW_CMD_CARD_DISABLE 33
-#define IPW_CMD_SEED_NUMBER 34
-#define IPW_CMD_TX_POWER 35
-#define IPW_CMD_COUNTRY_INFO 36
-#define IPW_CMD_AIRONET_INFO 37
-#define IPW_CMD_AP_TX_POWER 38
-#define IPW_CMD_CCKM_INFO 39
-#define IPW_CMD_CCX_VER_INFO 40
-#define IPW_CMD_SET_CALIBRATION 41
-#define IPW_CMD_SENSITIVITY_CALIB 42
-#define IPW_CMD_RETRY_LIMIT 51
-#define IPW_CMD_IPW_PRE_POWER_DOWN 58
-#define IPW_CMD_VAP_BEACON_TEMPLATE 60
-#define IPW_CMD_VAP_DTIM_PERIOD 61
-#define IPW_CMD_EXT_SUPPORTED_RATES 62
-#define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT 63
-#define IPW_CMD_VAP_QUIET_INTERVALS 64
-#define IPW_CMD_VAP_CHANNEL_SWITCH 65
-#define IPW_CMD_VAP_MANDATORY_CHANNELS 66
-#define IPW_CMD_VAP_CELL_PWR_LIMIT 67
-#define IPW_CMD_VAP_CF_PARAM_SET 68
-#define IPW_CMD_VAP_SET_BEACONING_STATE 69
-#define IPW_CMD_MEASUREMENT 80
-#define IPW_CMD_POWER_CAPABILITY 81
-#define IPW_CMD_SUPPORTED_CHANNELS 82
-#define IPW_CMD_TPC_REPORT 83
-#define IPW_CMD_WME_INFO 84
-#define IPW_CMD_PRODUCTION_COMMAND 85
-#define IPW_CMD_LINKSYS_EOU_INFO 90
-
-#define RFD_SIZE 4
-#define NUM_TFD_CHUNKS 6
-
-#define TX_QUEUE_SIZE 32
-#define RX_QUEUE_SIZE 32
-
-#define DINO_CMD_WEP_KEY 0x08
-#define DINO_CMD_TX 0x0B
-#define DCT_ANTENNA_A 0x01
-#define DCT_ANTENNA_B 0x02
-
-#define IPW_A_MODE 0
-#define IPW_B_MODE 1
-#define IPW_G_MODE 2
-
-/*
- * TX Queue Flag Definitions
- */
-
-/* tx wep key definition */
-#define DCT_WEP_KEY_NOT_IMMIDIATE 0x00
-#define DCT_WEP_KEY_64Bit 0x40
-#define DCT_WEP_KEY_128Bit 0x80
-#define DCT_WEP_KEY_128bitIV 0xC0
-#define DCT_WEP_KEY_SIZE_MASK 0xC0
-
-#define DCT_WEP_KEY_INDEX_MASK 0x0F
-#define DCT_WEP_INDEX_USE_IMMEDIATE 0x20
-
-/* abort attempt if mgmt frame is rx'd */
-#define DCT_FLAG_ABORT_MGMT 0x01
-
-/* require CTS */
-#define DCT_FLAG_CTS_REQUIRED 0x02
-
-/* use short preamble */
-#define DCT_FLAG_LONG_PREAMBLE 0x00
-#define DCT_FLAG_SHORT_PREAMBLE 0x04
-
-/* RTS/CTS first */
-#define DCT_FLAG_RTS_REQD 0x08
-
-/* dont calculate duration field */
-#define DCT_FLAG_DUR_SET 0x10
-
-/* even if MAC WEP set (allows pre-encrypt) */
-#define DCT_FLAG_NO_WEP 0x20
-
-/* overwrite TSF field */
-#define DCT_FLAG_TSF_REQD 0x40
-
-/* ACK rx is expected to follow */
-#define DCT_FLAG_ACK_REQD 0x80
-
-/* TX flags extension */
-#define DCT_FLAG_EXT_MODE_CCK 0x01
-#define DCT_FLAG_EXT_MODE_OFDM 0x00
-
-#define DCT_FLAG_EXT_SECURITY_WEP 0x00
-#define DCT_FLAG_EXT_SECURITY_NO DCT_FLAG_EXT_SECURITY_WEP
-#define DCT_FLAG_EXT_SECURITY_CKIP 0x04
-#define DCT_FLAG_EXT_SECURITY_CCM 0x08
-#define DCT_FLAG_EXT_SECURITY_TKIP 0x0C
-#define DCT_FLAG_EXT_SECURITY_MASK 0x0C
-
-#define DCT_FLAG_EXT_QOS_ENABLED 0x10
-
-#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS 0x00
-#define DCT_FLAG_EXT_HC_SIFS 0x20
-#define DCT_FLAG_EXT_HC_PIFS 0x40
-
-#define TX_RX_TYPE_MASK 0xFF
-#define TX_FRAME_TYPE 0x00
-#define TX_HOST_COMMAND_TYPE 0x01
-#define RX_FRAME_TYPE 0x09
-#define RX_HOST_NOTIFICATION_TYPE 0x03
-#define RX_HOST_CMD_RESPONSE_TYPE 0x04
-#define RX_TX_FRAME_RESPONSE_TYPE 0x05
-#define TFD_NEED_IRQ_MASK 0x04
-
-#define HOST_CMD_DINO_CONFIG 30
-
-#define HOST_NOTIFICATION_STATUS_ASSOCIATED 10
-#define HOST_NOTIFICATION_STATUS_AUTHENTICATE 11
-#define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT 12
-#define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED 13
-#define HOST_NOTIFICATION_STATUS_FRAG_LENGTH 14
-#define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION 15
-#define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE 16
-#define HOST_NOTIFICATION_STATUS_BEACON_STATE 17
-#define HOST_NOTIFICATION_STATUS_TGI_TX_KEY 18
-#define HOST_NOTIFICATION_TX_STATUS 19
-#define HOST_NOTIFICATION_CALIB_KEEP_RESULTS 20
-#define HOST_NOTIFICATION_MEASUREMENT_STARTED 21
-#define HOST_NOTIFICATION_MEASUREMENT_ENDED 22
-#define HOST_NOTIFICATION_CHANNEL_SWITCHED 23
-#define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD 24
-#define HOST_NOTIFICATION_NOISE_STATS 25
-#define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED 30
-#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31
-
-#define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1
-#define IPW_MB_SCAN_CANCEL_THRESHOLD 3
-#define IPW_MB_ROAMING_THRESHOLD_MIN 1
-#define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8
-#define IPW_MB_ROAMING_THRESHOLD_MAX 30
-#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 3*IPW_MB_ROAMING_THRESHOLD_DEFAULT
-#define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300
-
-#define MACADRR_BYTE_LEN 6
-
-#define DCR_TYPE_AP 0x01
-#define DCR_TYPE_WLAP 0x02
-#define DCR_TYPE_MU_ESS 0x03
-#define DCR_TYPE_MU_IBSS 0x04
-#define DCR_TYPE_MU_PIBSS 0x05
-#define DCR_TYPE_SNIFFER 0x06
-#define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS
-
-/* QoS definitions */
-
-#define CW_MIN_OFDM 15
-#define CW_MAX_OFDM 1023
-#define CW_MIN_CCK 31
-#define CW_MAX_CCK 1023
-
-#define QOS_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX2_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
-#define QOS_TX3_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/4 - 1)
-
-#define QOS_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX2_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
-#define QOS_TX3_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/4 - 1)
-
-#define QOS_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define QOS_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define QOS_TX2_CW_MAX_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX3_CW_MAX_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
-
-#define QOS_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define QOS_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define QOS_TX2_CW_MAX_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX3_CW_MAX_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
-
-#define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX2_AIFS (2 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX3_AIFS (2 - QOS_AIFSN_MIN_VALUE)
-
-#define QOS_TX0_ACM 0
-#define QOS_TX1_ACM 0
-#define QOS_TX2_ACM 0
-#define QOS_TX3_ACM 0
-
-#define QOS_TX0_TXOP_LIMIT_CCK 0
-#define QOS_TX1_TXOP_LIMIT_CCK 0
-#define QOS_TX2_TXOP_LIMIT_CCK cpu_to_le16(6016)
-#define QOS_TX3_TXOP_LIMIT_CCK cpu_to_le16(3264)
-
-#define QOS_TX0_TXOP_LIMIT_OFDM 0
-#define QOS_TX1_TXOP_LIMIT_OFDM 0
-#define QOS_TX2_TXOP_LIMIT_OFDM cpu_to_le16(3008)
-#define QOS_TX3_TXOP_LIMIT_OFDM cpu_to_le16(1504)
-
-#define DEF_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX2_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX3_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-
-#define DEF_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX2_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX3_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-
-#define DEF_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX2_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX3_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-
-#define DEF_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX2_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX3_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-
-#define DEF_TX0_AIFS 0
-#define DEF_TX1_AIFS 0
-#define DEF_TX2_AIFS 0
-#define DEF_TX3_AIFS 0
-
-#define DEF_TX0_ACM 0
-#define DEF_TX1_ACM 0
-#define DEF_TX2_ACM 0
-#define DEF_TX3_ACM 0
-
-#define DEF_TX0_TXOP_LIMIT_CCK 0
-#define DEF_TX1_TXOP_LIMIT_CCK 0
-#define DEF_TX2_TXOP_LIMIT_CCK 0
-#define DEF_TX3_TXOP_LIMIT_CCK 0
-
-#define DEF_TX0_TXOP_LIMIT_OFDM 0
-#define DEF_TX1_TXOP_LIMIT_OFDM 0
-#define DEF_TX2_TXOP_LIMIT_OFDM 0
-#define DEF_TX3_TXOP_LIMIT_OFDM 0
-
-#define QOS_QOS_SETS 3
-#define QOS_PARAM_SET_ACTIVE 0
-#define QOS_PARAM_SET_DEF_CCK 1
-#define QOS_PARAM_SET_DEF_OFDM 2
-
-#define CTRL_QOS_NO_ACK (0x0020)
-
-#define IPW_TX_QUEUE_1 1
-#define IPW_TX_QUEUE_2 2
-#define IPW_TX_QUEUE_3 3
-#define IPW_TX_QUEUE_4 4
-
-/* QoS sturctures */
-struct ipw_qos_info {
- int qos_enable;
- struct libipw_qos_parameters *def_qos_parm_OFDM;
- struct libipw_qos_parameters *def_qos_parm_CCK;
- u32 burst_duration_CCK;
- u32 burst_duration_OFDM;
- u16 qos_no_ack_mask;
- int burst_enable;
-};
-
-/**************************************************************/
-/**
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues
- */
-struct clx2_queue {
- int n_bd; /**< number of BDs in this queue */
- int first_empty; /**< 1-st empty entry (index) */
- int last_used; /**< last used entry (index) */
- u32 reg_w; /**< 'write' reg (queue head), addr in domain 1 */
- u32 reg_r; /**< 'read' reg (queue tail), addr in domain 1 */
- dma_addr_t dma_addr; /**< physical addr for BD's */
- int low_mark; /**< low watermark, resume queue if free space more than this */
- int high_mark; /**< high watermark, stop queue if free space less than this */
-} __packed; /* XXX */
-
-struct machdr32 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- u8 addr4[MACADRR_BYTE_LEN];
- __le16 qos_ctrl;
-} __packed;
-
-struct machdr30 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- u8 addr4[MACADRR_BYTE_LEN];
-} __packed;
-
-struct machdr26 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- __le16 qos_ctrl;
-} __packed;
-
-struct machdr24 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
-} __packed;
-
-// TX TFD with 32 byte MAC Header
-struct tx_tfd_32 {
- struct machdr32 mchdr; // 32
- __le32 uivplaceholder[2]; // 8
-} __packed;
-
-// TX TFD with 30 byte MAC Header
-struct tx_tfd_30 {
- struct machdr30 mchdr; // 30
- u8 reserved[2]; // 2
- __le32 uivplaceholder[2]; // 8
-} __packed;
-
-// tx tfd with 26 byte mac header
-struct tx_tfd_26 {
- struct machdr26 mchdr; // 26
- u8 reserved1[2]; // 2
- __le32 uivplaceholder[2]; // 8
- u8 reserved2[4]; // 4
-} __packed;
-
-// tx tfd with 24 byte mac header
-struct tx_tfd_24 {
- struct machdr24 mchdr; // 24
- __le32 uivplaceholder[2]; // 8
- u8 reserved[8]; // 8
-} __packed;
-
-#define DCT_WEP_KEY_FIELD_LENGTH 16
-
-struct tfd_command {
- u8 index;
- u8 length;
- __le16 reserved;
- u8 payload[];
-} __packed;
-
-struct tfd_data {
- /* Header */
- __le32 work_area_ptr;
- u8 station_number; /* 0 for BSS */
- u8 reserved1;
- __le16 reserved2;
-
- /* Tx Parameters */
- u8 cmd_id;
- u8 seq_num;
- __le16 len;
- u8 priority;
- u8 tx_flags;
- u8 tx_flags_ext;
- u8 key_index;
- u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH];
- u8 rate;
- u8 antenna;
- __le16 next_packet_duration;
- __le16 next_frag_len;
- __le16 back_off_counter; //////txop;
- u8 retrylimit;
- __le16 cwcurrent;
- u8 reserved3;
-
- /* 802.11 MAC Header */
- union {
- struct tx_tfd_24 tfd_24;
- struct tx_tfd_26 tfd_26;
- struct tx_tfd_30 tfd_30;
- struct tx_tfd_32 tfd_32;
- } tfd;
-
- /* Payload DMA info */
- __le32 num_chunks;
- __le32 chunk_ptr[NUM_TFD_CHUNKS];
- __le16 chunk_len[NUM_TFD_CHUNKS];
-} __packed;
-
-struct txrx_control_flags {
- u8 message_type;
- u8 rx_seq_num;
- u8 control_bits;
- u8 reserved;
-} __packed;
-
-#define TFD_SIZE 128
-#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags))
-
-struct tfd_frame {
- struct txrx_control_flags control_flags;
- union {
- struct tfd_data data;
- struct tfd_command cmd;
- u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
- } u;
-} __packed;
-
-typedef void destructor_func(const void *);
-
-/**
- * Tx Queue for DMA. Queue consists of circular buffer of
- * BD's and required locking structures.
- */
-struct clx2_tx_queue {
- struct clx2_queue q;
- struct tfd_frame *bd;
- struct libipw_txb **txb;
-};
-
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 32
-#define RX_LOW_WATERMARK 8
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
-
-// Used for passing to driver number of successes and failures per rate
-struct rate_histogram {
- union {
- __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
- __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
- __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
- } success;
- union {
- __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
- __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
- __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
- } failed;
-} __packed;
-
-/* statistics command response */
-struct ipw_cmd_stats {
- u8 cmd_id;
- u8 seq_num;
- __le16 good_sfd;
- __le16 bad_plcp;
- __le16 wrong_bssid;
- __le16 valid_mpdu;
- __le16 bad_mac_header;
- __le16 reserved_frame_types;
- __le16 rx_ina;
- __le16 bad_crc32;
- __le16 invalid_cts;
- __le16 invalid_acks;
- __le16 long_distance_ina_fina;
- __le16 dsp_silence_unreachable;
- __le16 accumulated_rssi;
- __le16 rx_ovfl_frame_tossed;
- __le16 rssi_silence_threshold;
- __le16 rx_ovfl_frame_supplied;
- __le16 last_rx_frame_signal;
- __le16 last_rx_frame_noise;
- __le16 rx_autodetec_no_ofdm;
- __le16 rx_autodetec_no_barker;
- __le16 reserved;
-} __packed;
-
-struct notif_channel_result {
- u8 channel_num;
- struct ipw_cmd_stats stats;
- u8 uReserved;
-} __packed;
-
-#define SCAN_COMPLETED_STATUS_COMPLETE 1
-#define SCAN_COMPLETED_STATUS_ABORTED 2
-
-struct notif_scan_complete {
- u8 scan_type;
- u8 num_channels;
- u8 status;
- u8 reserved;
-} __packed;
-
-struct notif_frag_length {
- __le16 frag_length;
- __le16 reserved;
-} __packed;
-
-struct notif_beacon_state {
- __le32 state;
- __le32 number;
-} __packed;
-
-struct notif_tgi_tx_key {
- u8 key_state;
- u8 security_type;
- u8 station_index;
- u8 reserved;
-} __packed;
-
-#define SILENCE_OVER_THRESH (1)
-#define SILENCE_UNDER_THRESH (2)
-
-struct notif_link_deterioration {
- struct ipw_cmd_stats stats;
- u8 rate;
- u8 modulation;
- struct rate_histogram histogram;
- u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */
- __le16 silence_count;
-} __packed;
-
-struct notif_association {
- u8 state;
-} __packed;
-
-struct notif_authenticate {
- u8 state;
- struct machdr24 addr;
- __le16 status;
-} __packed;
-
-struct notif_calibration {
- u8 data[104];
-} __packed;
-
-struct notif_noise {
- __le32 value;
-} __packed;
-
-struct ipw_rx_notification {
- u8 reserved[8];
- u8 subtype;
- u8 flags;
- __le16 size;
- union {
- struct notif_association assoc;
- struct notif_authenticate auth;
- struct notif_channel_result channel_result;
- struct notif_scan_complete scan_complete;
- struct notif_frag_length frag_len;
- struct notif_beacon_state beacon_state;
- struct notif_tgi_tx_key tgi_tx_key;
- struct notif_link_deterioration link_deterioration;
- struct notif_calibration calibration;
- struct notif_noise noise;
- DECLARE_FLEX_ARRAY(u8, raw);
- } u;
-} __packed;
-
-struct ipw_rx_frame {
- __le32 reserved1;
- u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER
- u8 received_channel; // The channel that this frame was received on.
- // Note that for .11b this does not have to be
- // the same as the channel that it was sent.
- // Filled by LMAC
- u8 frameStatus;
- u8 rate;
- u8 rssi;
- u8 agc;
- u8 rssi_dbm;
- __le16 signal;
- __le16 noise;
- u8 antennaAndPhy;
- u8 control; // control bit should be on in bg
- u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate
- // is identical)
- u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen
- __le16 length;
- u8 data[];
-} __packed;
-
-struct ipw_rx_header {
- u8 message_type;
- u8 rx_seq_num;
- u8 control_bits;
- u8 reserved;
-} __packed;
-
-struct ipw_rx_packet {
- struct ipw_rx_header header;
- union {
- struct ipw_rx_frame frame;
- struct ipw_rx_notification notification;
- } u;
-} __packed;
-
-#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
-#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \
- sizeof(struct ipw_rx_frame))
-
-struct ipw_rx_mem_buffer {
- dma_addr_t dma_addr;
- struct sk_buff *skb;
- struct list_head list;
-}; /* Not transferred over network, so not __packed */
-
-struct ipw_rx_queue {
- struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
- struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE];
- u32 processed; /* Internal index to last handled Rx packet */
- u32 read; /* Shared index to newest available Rx buffer */
- u32 write; /* Shared index to oldest written Rx packet */
- u32 free_count; /* Number of pre-allocated buffers in rx_free */
- /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */
- struct list_head rx_free; /* Own an SKBs */
- struct list_head rx_used; /* No SKB allocated */
- spinlock_t lock;
-}; /* Not transferred over network, so not __packed */
-
-struct alive_command_responce {
- u8 alive_command;
- u8 sequence_number;
- __le16 software_revision;
- u8 device_identifier;
- u8 reserved1[5];
- __le16 reserved2;
- __le16 reserved3;
- __le16 clock_settle_time;
- __le16 powerup_settle_time;
- __le16 reserved4;
- u8 time_stamp[5]; /* month, day, year, hours, minutes */
- u8 ucode_valid;
-} __packed;
-
-#define IPW_MAX_RATES 12
-
-struct ipw_rates {
- u8 num_rates;
- u8 rates[IPW_MAX_RATES];
-} __packed;
-
-struct command_block {
- unsigned int control;
- u32 source_addr;
- u32 dest_addr;
- unsigned int status;
-} __packed;
-
-#define CB_NUMBER_OF_ELEMENTS_SMALL 64
-struct fw_image_desc {
- unsigned long last_cb_index;
- unsigned long current_cb_index;
- struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL];
- void *v_addr;
- unsigned long p_addr;
- unsigned long len;
-};
-
-struct ipw_sys_config {
- u8 bt_coexistence;
- u8 reserved1;
- u8 answer_broadcast_ssid_probe;
- u8 accept_all_data_frames;
- u8 accept_non_directed_frames;
- u8 exclude_unicast_unencrypted;
- u8 disable_unicast_decryption;
- u8 exclude_multicast_unencrypted;
- u8 disable_multicast_decryption;
- u8 antenna_diversity;
- u8 pass_crc_to_host;
- u8 dot11g_auto_detection;
- u8 enable_cts_to_self;
- u8 enable_multicast_filtering;
- u8 bt_coexist_collision_thr;
- u8 silence_threshold;
- u8 accept_all_mgmt_bcpr;
- u8 accept_all_mgmt_frames;
- u8 pass_noise_stats_to_host;
- u8 reserved3;
-} __packed;
-
-struct ipw_multicast_addr {
- u8 num_of_multicast_addresses;
- u8 reserved[3];
- u8 mac1[6];
- u8 mac2[6];
- u8 mac3[6];
- u8 mac4[6];
-} __packed;
-
-#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */
-#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */
-
-#define DCW_WEP_KEY_SEC_TYPE_WEP 0x00
-#define DCW_WEP_KEY_SEC_TYPE_CCM 0x20
-#define DCW_WEP_KEY_SEC_TYPE_TKIP 0x30
-
-#define DCW_WEP_KEY_INVALID_SIZE 0x00 /* 0 = Invalid key */
-#define DCW_WEP_KEY64Bit_SIZE 0x05 /* 64-bit encryption */
-#define DCW_WEP_KEY128Bit_SIZE 0x0D /* 128-bit encryption */
-#define DCW_CCM_KEY128Bit_SIZE 0x10 /* 128-bit key */
-//#define DCW_WEP_KEY128BitIV_SIZE 0x10 /* 128-bit key and 128-bit IV */
-
-struct ipw_wep_key {
- u8 cmd_id;
- u8 seq_num;
- u8 key_index;
- u8 key_size;
- u8 key[16];
-} __packed;
-
-struct ipw_tgi_tx_key {
- u8 key_id;
- u8 security_type;
- u8 station_index;
- u8 flags;
- u8 key[16];
- __le32 tx_counter[2];
-} __packed;
-
-#define IPW_SCAN_CHANNELS 54
-
-struct ipw_scan_request {
- u8 scan_type;
- __le16 dwell_time;
- u8 channels_list[IPW_SCAN_CHANNELS];
- u8 channels_reserved[3];
-} __packed;
-
-enum {
- IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN,
- IPW_SCAN_ACTIVE_DIRECT_SCAN,
- IPW_SCAN_ACTIVE_BROADCAST_SCAN,
- IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN,
- IPW_SCAN_TYPES
-};
-
-struct ipw_scan_request_ext {
- __le32 full_scan_index;
- u8 channels_list[IPW_SCAN_CHANNELS];
- u8 scan_type[IPW_SCAN_CHANNELS / 2];
- u8 reserved;
- __le16 dwell_time[IPW_SCAN_TYPES];
-} __packed;
-
-static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
-{
- if (index % 2)
- return scan->scan_type[index / 2] & 0x0F;
- else
- return (scan->scan_type[index / 2] & 0xF0) >> 4;
-}
-
-static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan,
- u8 index, u8 scan_type)
-{
- if (index % 2)
- scan->scan_type[index / 2] =
- (scan->scan_type[index / 2] & 0xF0) | (scan_type & 0x0F);
- else
- scan->scan_type[index / 2] =
- (scan->scan_type[index / 2] & 0x0F) |
- ((scan_type & 0x0F) << 4);
-}
-
-struct ipw_associate {
- u8 channel;
-#ifdef __LITTLE_ENDIAN_BITFIELD
- u8 auth_type:4, auth_key:4;
-#else
- u8 auth_key:4, auth_type:4;
-#endif
- u8 assoc_type;
- u8 reserved;
- __le16 policy_support;
- u8 preamble_length;
- u8 ieee_mode;
- u8 bssid[ETH_ALEN];
- __le32 assoc_tsf_msw;
- __le32 assoc_tsf_lsw;
- __le16 capability;
- __le16 listen_interval;
- __le16 beacon_interval;
- u8 dest[ETH_ALEN];
- __le16 atim_window;
- u8 smr;
- u8 reserved1;
- __le16 reserved2;
-} __packed;
-
-struct ipw_supported_rates {
- u8 ieee_mode;
- u8 num_rates;
- u8 purpose;
- u8 reserved;
- u8 supported_rates[IPW_MAX_RATES];
-} __packed;
-
-struct ipw_rts_threshold {
- __le16 rts_threshold;
- __le16 reserved;
-} __packed;
-
-struct ipw_frag_threshold {
- __le16 frag_threshold;
- __le16 reserved;
-} __packed;
-
-struct ipw_retry_limit {
- u8 short_retry_limit;
- u8 long_retry_limit;
- __le16 reserved;
-} __packed;
-
-struct ipw_dino_config {
- __le32 dino_config_addr;
- __le16 dino_config_size;
- u8 dino_response;
- u8 reserved;
-} __packed;
-
-struct ipw_aironet_info {
- u8 id;
- u8 length;
- __le16 reserved;
-} __packed;
-
-struct ipw_rx_key {
- u8 station_index;
- u8 key_type;
- u8 key_id;
- u8 key_flag;
- u8 key[16];
- u8 station_address[6];
- u8 key_index;
- u8 reserved;
-} __packed;
-
-struct ipw_country_channel_info {
- u8 first_channel;
- u8 no_channels;
- s8 max_tx_power;
-} __packed;
-
-struct ipw_country_info {
- u8 id;
- u8 length;
- u8 country_str[IEEE80211_COUNTRY_STRING_LEN];
- struct ipw_country_channel_info groups[7];
-} __packed;
-
-struct ipw_channel_tx_power {
- u8 channel_number;
- s8 tx_power;
-} __packed;
-
-#define SCAN_ASSOCIATED_INTERVAL (HZ)
-#define SCAN_INTERVAL (HZ / 10)
-#define MAX_A_CHANNELS 37
-#define MAX_B_CHANNELS 14
-
-struct ipw_tx_power {
- u8 num_channels;
- u8 ieee_mode;
- struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
-} __packed;
-
-struct ipw_rsn_capabilities {
- u8 id;
- u8 length;
- __le16 version;
-} __packed;
-
-struct ipw_sensitivity_calib {
- __le16 beacon_rssi_raw;
- __le16 reserved;
-} __packed;
-
-/**
- * Host command structure.
- *
- * On input, the following fields should be filled:
- * - cmd
- * - len
- * - status_len
- * - param (if needed)
- *
- * On output,
- * - \a status contains status;
- * - \a param filled with status parameters.
- */
-struct ipw_cmd { /* XXX */
- u32 cmd; /**< Host command */
- u32 status;/**< Status */
- u32 status_len;
- /**< How many 32 bit parameters in the status */
- u32 len; /**< incoming parameters length, bytes */
- /**
- * command parameters.
- * There should be enough space for incoming and
- * outcoming parameters.
- * Incoming parameters listed 1-st, followed by outcoming params.
- * nParams=(len+3)/4+status_len
- */
- u32 param[];
-} __packed;
-
-#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */
-
-#define STATUS_INT_ENABLED (1<<1)
-#define STATUS_RF_KILL_HW (1<<2)
-#define STATUS_RF_KILL_SW (1<<3)
-#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
-
-#define STATUS_INIT (1<<5)
-#define STATUS_AUTH (1<<6)
-#define STATUS_ASSOCIATED (1<<7)
-#define STATUS_STATE_MASK (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED)
-
-#define STATUS_ASSOCIATING (1<<8)
-#define STATUS_DISASSOCIATING (1<<9)
-#define STATUS_ROAMING (1<<10)
-#define STATUS_EXIT_PENDING (1<<11)
-#define STATUS_DISASSOC_PENDING (1<<12)
-#define STATUS_STATE_PENDING (1<<13)
-
-#define STATUS_DIRECT_SCAN_PENDING (1<<19)
-#define STATUS_SCAN_PENDING (1<<20)
-#define STATUS_SCANNING (1<<21)
-#define STATUS_SCAN_ABORTING (1<<22)
-#define STATUS_SCAN_FORCED (1<<23)
-
-#define STATUS_LED_LINK_ON (1<<24)
-#define STATUS_LED_ACT_ON (1<<25)
-
-#define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */
-#define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */
-#define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */
-
-#define STATUS_SECURITY_UPDATED (1<<31) /* Security sync needed */
-
-#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
-#define CFG_CUSTOM_MAC (1<<3)
-#define CFG_PREAMBLE_LONG (1<<4)
-#define CFG_ADHOC_PERSIST (1<<5)
-#define CFG_ASSOCIATE (1<<6)
-#define CFG_FIXED_RATE (1<<7)
-#define CFG_ADHOC_CREATE (1<<8)
-#define CFG_NO_LED (1<<9)
-#define CFG_BACKGROUND_SCAN (1<<10)
-#define CFG_SPEED_SCAN (1<<11)
-#define CFG_NET_STATS (1<<12)
-
-#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
-
-#define MAX_STATIONS 32
-#define IPW_INVALID_STATION (0xff)
-
-struct ipw_station_entry {
- u8 mac_addr[ETH_ALEN];
- u8 reserved;
- u8 support_mode;
-};
-
-#define AVG_ENTRIES 8
-struct average {
- s16 entries[AVG_ENTRIES];
- u8 pos;
- u8 init;
- s32 sum;
-};
-
-#define MAX_SPEED_SCAN 100
-#define IPW_IBSS_MAC_HASH_SIZE 31
-
-struct ipw_ibss_seq {
- u8 mac[ETH_ALEN];
- u16 seq_num;
- u16 frag_num;
- unsigned long packet_time;
- struct list_head list;
-};
-
-struct ipw_error_elem { /* XXX */
- u32 desc;
- u32 time;
- u32 blink1;
- u32 blink2;
- u32 link1;
- u32 link2;
- u32 data;
-};
-
-struct ipw_event { /* XXX */
- u32 event;
- u32 time;
- u32 data;
-} __packed;
-
-struct ipw_fw_error { /* XXX */
- unsigned long jiffies;
- u32 status;
- u32 config;
- u32 elem_len;
- u32 log_len;
- struct ipw_event *log;
- struct ipw_error_elem elem[];
-} __packed;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-
-enum ipw_prom_filter {
- IPW_PROM_CTL_HEADER_ONLY = (1 << 0),
- IPW_PROM_MGMT_HEADER_ONLY = (1 << 1),
- IPW_PROM_DATA_HEADER_ONLY = (1 << 2),
- IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */
- IPW_PROM_NO_TX = (1 << 4),
- IPW_PROM_NO_RX = (1 << 5),
- IPW_PROM_NO_CTL = (1 << 6),
- IPW_PROM_NO_MGMT = (1 << 7),
- IPW_PROM_NO_DATA = (1 << 8),
-};
-
-struct ipw_priv;
-struct ipw_prom_priv {
- struct ipw_priv *priv;
- struct libipw_device *ieee;
- enum ipw_prom_filter filter;
- int tx_packets;
- int rx_packets;
-};
-#endif
-
-#if defined(CONFIG_IPW2200_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS)
-/* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE
- *
- * When sent to us via the simulated Rx interface in sysfs, the entire
- * structure is provided regardless of any bits unset.
- */
-struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
- u64 rt_tsf; /* TSF */ /* XXX */
- u8 rt_flags; /* radiotap packet flags */
- u8 rt_rate; /* rate in 500kb/s */
- __le16 rt_channel; /* channel in mhz */
- __le16 rt_chbitmask; /* channel bitfield */
- s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
- s8 rt_dbmnoise;
- u8 rt_antenna; /* antenna number */
- u8 payload[]; /* payload... */
-} __packed;
-#endif
-
-struct ipw_priv {
- /* ieee device used by generic ieee processing code */
- struct libipw_device *ieee;
-
- spinlock_t lock;
- spinlock_t irq_lock;
- struct mutex mutex;
-
- /* basic pci-network driver stuff */
- struct pci_dev *pci_dev;
- struct net_device *net_dev;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- /* Promiscuous mode */
- struct ipw_prom_priv *prom_priv;
- struct net_device *prom_net_dev;
-#endif
-
- /* pci hardware address support */
- void __iomem *hw_base;
- unsigned long hw_len;
-
- struct fw_image_desc sram_desc;
-
- /* result of ucode download */
- struct alive_command_responce dino_alive;
-
- wait_queue_head_t wait_command_queue;
- wait_queue_head_t wait_state;
-
- /* Rx and Tx DMA processing queues */
- struct ipw_rx_queue *rxq;
- struct clx2_tx_queue txq_cmd;
- struct clx2_tx_queue txq[4];
- u32 status;
- u32 config;
- u32 capability;
-
- struct average average_missed_beacons;
- s16 exp_avg_rssi;
- s16 exp_avg_noise;
- u32 port_type;
- int rx_bufs_min; /**< minimum number of bufs in Rx queue */
- int rx_pend_max; /**< maximum pending buffers for one IRQ */
- u32 hcmd_seq; /**< sequence number for hcmd */
- u32 disassociate_threshold;
- u32 roaming_threshold;
-
- struct ipw_associate assoc_request;
- struct libipw_network *assoc_network;
-
- unsigned long ts_scan_abort;
- struct ipw_supported_rates rates;
- struct ipw_rates phy[3]; /**< PHY restrictions, per band */
- struct ipw_rates supp; /**< software defined */
- struct ipw_rates extended; /**< use for corresp. IE, AP only */
-
- struct notif_link_deterioration last_link_deterioration; /** for statistics */
- struct ipw_cmd *hcmd; /**< host command currently executed */
-
- wait_queue_head_t hcmd_wq; /**< host command waits for execution */
- u32 tsf_bcn[2]; /**< TSF from latest beacon */
-
- struct notif_calibration calib; /**< last calibration */
-
- /* ordinal interface with firmware */
- u32 table0_addr;
- u32 table0_len;
- u32 table1_addr;
- u32 table1_len;
- u32 table2_addr;
- u32 table2_len;
-
- /* context information */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
- u8 nick[IW_ESSID_MAX_SIZE];
- u16 rates_mask;
- u8 channel;
- struct ipw_sys_config sys_config;
- u32 power_mode;
- u8 bssid[ETH_ALEN];
- u16 rts_threshold;
- u8 mac_addr[ETH_ALEN];
- u8 num_stations;
- u8 stations[MAX_STATIONS][ETH_ALEN];
- u8 short_retry_limit;
- u8 long_retry_limit;
-
- u32 notif_missed_beacons;
-
- /* Statistics and counters normalized with each association */
- u32 last_missed_beacons;
- u32 last_tx_packets;
- u32 last_rx_packets;
- u32 last_tx_failures;
- u32 last_rx_err;
- u32 last_rate;
-
- u32 missed_adhoc_beacons;
- u32 missed_beacons;
- u32 rx_packets;
- u32 tx_packets;
- u32 quality;
-
- u8 speed_scan[MAX_SPEED_SCAN];
- u8 speed_scan_pos;
-
- u16 last_seq_num;
- u16 last_frag_num;
- unsigned long last_packet_time;
- struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE];
-
- /* eeprom */
- u8 eeprom[0x100]; /* 256 bytes of eeprom */
- u8 country[4];
- int eeprom_delay;
-
- struct iw_statistics wstats;
-
- struct iw_public_data wireless_data;
-
- int user_requested_scan;
- u8 direct_scan_ssid[IW_ESSID_MAX_SIZE];
- u8 direct_scan_ssid_len;
-
- struct delayed_work adhoc_check;
- struct work_struct associate;
- struct work_struct disassociate;
- struct work_struct system_config;
- struct work_struct rx_replenish;
- struct delayed_work request_scan;
- struct delayed_work request_direct_scan;
- struct delayed_work request_passive_scan;
- struct delayed_work scan_event;
- struct work_struct adapter_restart;
- struct delayed_work rf_kill;
- struct work_struct up;
- struct work_struct down;
- struct delayed_work gather_stats;
- struct work_struct abort_scan;
- struct work_struct roam;
- struct delayed_work scan_check;
- struct work_struct link_up;
- struct work_struct link_down;
-
- struct tasklet_struct irq_tasklet;
-
- /* LED related variables and work_struct */
- u8 nic_type;
- u32 led_activity_on;
- u32 led_activity_off;
- u32 led_association_on;
- u32 led_association_off;
- u32 led_ofdm_on;
- u32 led_ofdm_off;
-
- struct delayed_work led_link_on;
- struct delayed_work led_link_off;
- struct delayed_work led_act_off;
- struct work_struct merge_networks;
-
- struct ipw_cmd_log *cmdlog;
- int cmdlog_len;
- int cmdlog_pos;
-
-#define IPW_2200BG 1
-#define IPW_2915ABG 2
- u8 adapter;
-
- s8 tx_power;
-
- /* Track time in suspend using CLOCK_BOOTTIME */
- time64_t suspend_at;
- time64_t suspend_time;
-
-#ifdef CONFIG_PM
- u32 pm_state[16];
-#endif
-
- struct ipw_fw_error *error;
-
- /* network state */
-
- /* Used to pass the current INTA value from ISR to Tasklet */
- u32 isr_inta;
-
- /* QoS */
- struct ipw_qos_info qos_data;
- struct work_struct qos_activate;
- /*********************************/
-
- /* debugging info */
- u32 indirect_dword;
- u32 direct_dword;
- u32 indirect_byte;
-}; /*ipw_priv */
-
-/* debug macros */
-
-/* Debug and printf string expansion helpers for printing bitfields */
-#define BIT_FMT8 "%c%c%c%c-%c%c%c%c"
-#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8
-#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16
-
-#define BITC(x,y) (((x>>y)&1)?'1':'0')
-#define BIT_ARG8(x) \
-BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\
-BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0)
-
-#define BIT_ARG16(x) \
-BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\
-BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\
-BIT_ARG8(x)
-
-#define BIT_ARG32(x) \
-BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\
-BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\
-BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\
-BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\
-BIT_ARG16(x)
-
-
-#define IPW_DEBUG(level, fmt, args...) \
-do { if (ipw_debug_level & (level)) \
- printk(KERN_DEBUG DRV_NAME": %s " fmt, __func__ , ## args); } while (0)
-
-#ifdef CONFIG_IPW2200_DEBUG
-#define IPW_LL_DEBUG(level, fmt, args...) \
-do { if (ipw_debug_level & (level)) \
- printk(KERN_DEBUG DRV_NAME": %s " fmt, __func__ , ## args); } while (0)
-#else
-#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0)
-#endif /* CONFIG_IPW2200_DEBUG */
-
-/*
- * To use the debug system;
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define IPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a IPW_xxxx_DEBUG() macro definition for your
- * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ipw/debug_level
- *
- * you simply need to add your entry to the ipw_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/ipw then you do not have
- * CONFIG_IPW2200_DEBUG defined in your kernel configuration
- *
- */
-
-#define IPW_DL_ERROR (1<<0)
-#define IPW_DL_WARNING (1<<1)
-#define IPW_DL_INFO (1<<2)
-#define IPW_DL_WX (1<<3)
-#define IPW_DL_HOST_COMMAND (1<<5)
-#define IPW_DL_STATE (1<<6)
-
-#define IPW_DL_NOTIF (1<<10)
-#define IPW_DL_SCAN (1<<11)
-#define IPW_DL_ASSOC (1<<12)
-#define IPW_DL_DROP (1<<13)
-#define IPW_DL_IOCTL (1<<14)
-
-#define IPW_DL_MANAGE (1<<15)
-#define IPW_DL_FW (1<<16)
-#define IPW_DL_RF_KILL (1<<17)
-#define IPW_DL_FW_ERRORS (1<<18)
-
-#define IPW_DL_LED (1<<19)
-
-#define IPW_DL_ORD (1<<20)
-
-#define IPW_DL_FRAG (1<<21)
-#define IPW_DL_WEP (1<<22)
-#define IPW_DL_TX (1<<23)
-#define IPW_DL_RX (1<<24)
-#define IPW_DL_ISR (1<<25)
-#define IPW_DL_FW_INFO (1<<26)
-#define IPW_DL_IO (1<<27)
-#define IPW_DL_TRACE (1<<28)
-
-#define IPW_DL_STATS (1<<29)
-#define IPW_DL_MERGE (1<<30)
-#define IPW_DL_QOS (1<<31)
-
-#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
-#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_INFO(f, a...) IPW_DEBUG(IPW_DL_INFO, f, ## a)
-
-#define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a)
-#define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a)
-#define IPW_DEBUG_TRACE(f, a...) IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a)
-#define IPW_DEBUG_RX(f, a...) IPW_LL_DEBUG(IPW_DL_RX, f, ## a)
-#define IPW_DEBUG_TX(f, a...) IPW_LL_DEBUG(IPW_DL_TX, f, ## a)
-#define IPW_DEBUG_ISR(f, a...) IPW_LL_DEBUG(IPW_DL_ISR, f, ## a)
-#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
-#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a)
-#define IPW_DEBUG_WEP(f, a...) IPW_LL_DEBUG(IPW_DL_WEP, f, ## a)
-#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
-#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a)
-#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a)
-#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
-#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
-#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a)
-#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a)
-#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a)
-#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
-#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a)
-#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a)
-#define IPW_DEBUG_QOS(f, a...) IPW_LL_DEBUG(IPW_DL_QOS, f, ## a)
-
-#include <linux/ctype.h>
-
-/*
-* Register bit definitions
-*/
-
-#define IPW_INTA_RW 0x00000008
-#define IPW_INTA_MASK_R 0x0000000C
-#define IPW_INDIRECT_ADDR 0x00000010
-#define IPW_INDIRECT_DATA 0x00000014
-#define IPW_AUTOINC_ADDR 0x00000018
-#define IPW_AUTOINC_DATA 0x0000001C
-#define IPW_RESET_REG 0x00000020
-#define IPW_GP_CNTRL_RW 0x00000024
-
-#define IPW_READ_INT_REGISTER 0xFF4
-
-#define IPW_GP_CNTRL_BIT_INIT_DONE 0x00000004
-
-#define IPW_REGISTER_DOMAIN1_END 0x00001000
-#define IPW_SRAM_READ_INT_REGISTER 0x00000ff4
-
-#define IPW_SHARED_LOWER_BOUND 0x00000200
-#define IPW_INTERRUPT_AREA_LOWER_BOUND 0x00000f80
-
-#define IPW_NIC_SRAM_LOWER_BOUND 0x00000000
-#define IPW_NIC_SRAM_UPPER_BOUND 0x00030000
-
-#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
-#define IPW_GP_CNTRL_BIT_CLOCK_READY 0x00000001
-#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
-
-/*
- * RESET Register Bit Indexes
- */
-#define CBD_RESET_REG_PRINCETON_RESET (1<<0)
-#define IPW_START_STANDBY (1<<2)
-#define IPW_ACTIVITY_LED (1<<4)
-#define IPW_ASSOCIATED_LED (1<<5)
-#define IPW_OFDM_LED (1<<6)
-#define IPW_RESET_REG_SW_RESET (1<<7)
-#define IPW_RESET_REG_MASTER_DISABLED (1<<8)
-#define IPW_RESET_REG_STOP_MASTER (1<<9)
-#define IPW_GATE_ODMA (1<<25)
-#define IPW_GATE_IDMA (1<<26)
-#define IPW_ARC_KESHET_CONFIG (1<<27)
-#define IPW_GATE_ADMA (1<<29)
-
-#define IPW_CSR_CIS_UPPER_BOUND 0x00000200
-#define IPW_DOMAIN_0_END 0x1000
-#define CLX_MEM_BAR_SIZE 0x1000
-
-/* Dino/baseband control registers bits */
-
-#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */
-#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */
-#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */
-#define IPW_BASEBAND_CONTROL_STATUS 0X00200000
-#define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004
-#define IPW_BASEBAND_RX_FIFO_READ 0X00200004
-#define IPW_BASEBAND_CONTROL_STORE 0X00200010
-
-#define IPW_INTERNAL_CMD_EVENT 0X00300004
-#define IPW_BASEBAND_POWER_DOWN 0x00000001
-
-#define IPW_MEM_HALT_AND_RESET 0x003000e0
-
-/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */
-#define IPW_BIT_HALT_RESET_ON 0x80000000
-#define IPW_BIT_HALT_RESET_OFF 0x00000000
-
-#define CB_LAST_VALID 0x20000000
-#define CB_INT_ENABLED 0x40000000
-#define CB_VALID 0x80000000
-#define CB_SRC_LE 0x08000000
-#define CB_DEST_LE 0x04000000
-#define CB_SRC_AUTOINC 0x00800000
-#define CB_SRC_IO_GATED 0x00400000
-#define CB_DEST_AUTOINC 0x00080000
-#define CB_SRC_SIZE_LONG 0x00200000
-#define CB_DEST_SIZE_LONG 0x00020000
-
-/* DMA DEFINES */
-
-#define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000
-#define DMA_CB_STOP_AND_ABORT 0x00000C00
-#define DMA_CB_START 0x00000100
-
-#define IPW_SHARED_SRAM_SIZE 0x00030000
-#define IPW_SHARED_SRAM_DMA_CONTROL 0x00027000
-#define CB_MAX_LENGTH 0x1FFF
-
-#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
-#define IPW_EEPROM_IMAGE_SIZE 0x100
-
-/* DMA defs */
-#define IPW_DMA_I_CURRENT_CB 0x003000D0
-#define IPW_DMA_O_CURRENT_CB 0x003000D4
-#define IPW_DMA_I_DMA_CONTROL 0x003000A4
-#define IPW_DMA_I_CB_BASE 0x003000A0
-
-#define IPW_TX_CMD_QUEUE_BD_BASE 0x00000200
-#define IPW_TX_CMD_QUEUE_BD_SIZE 0x00000204
-#define IPW_TX_QUEUE_0_BD_BASE 0x00000208
-#define IPW_TX_QUEUE_0_BD_SIZE (0x0000020C)
-#define IPW_TX_QUEUE_1_BD_BASE 0x00000210
-#define IPW_TX_QUEUE_1_BD_SIZE 0x00000214
-#define IPW_TX_QUEUE_2_BD_BASE 0x00000218
-#define IPW_TX_QUEUE_2_BD_SIZE (0x0000021C)
-#define IPW_TX_QUEUE_3_BD_BASE 0x00000220
-#define IPW_TX_QUEUE_3_BD_SIZE 0x00000224
-#define IPW_RX_BD_BASE 0x00000240
-#define IPW_RX_BD_SIZE 0x00000244
-#define IPW_RFDS_TABLE_LOWER 0x00000500
-
-#define IPW_TX_CMD_QUEUE_READ_INDEX 0x00000280
-#define IPW_TX_QUEUE_0_READ_INDEX 0x00000284
-#define IPW_TX_QUEUE_1_READ_INDEX 0x00000288
-#define IPW_TX_QUEUE_2_READ_INDEX (0x0000028C)
-#define IPW_TX_QUEUE_3_READ_INDEX 0x00000290
-#define IPW_RX_READ_INDEX (0x000002A0)
-
-#define IPW_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80)
-#define IPW_TX_QUEUE_0_WRITE_INDEX (0x00000F84)
-#define IPW_TX_QUEUE_1_WRITE_INDEX (0x00000F88)
-#define IPW_TX_QUEUE_2_WRITE_INDEX (0x00000F8C)
-#define IPW_TX_QUEUE_3_WRITE_INDEX (0x00000F90)
-#define IPW_RX_WRITE_INDEX (0x00000FA0)
-
-/*
- * EEPROM Related Definitions
- */
-
-#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814)
-#define IPW_EEPROM_DATA_SRAM_SIZE (IPW_SHARED_LOWER_BOUND + 0x818)
-#define IPW_EEPROM_LOAD_DISABLE (IPW_SHARED_LOWER_BOUND + 0x81C)
-#define IPW_EEPROM_DATA (IPW_SHARED_LOWER_BOUND + 0x820)
-#define IPW_EEPROM_UPPER_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x9E0)
-
-#define IPW_STATION_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0xA0C)
-#define IPW_STATION_TABLE_UPPER (IPW_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_REQUEST_ATIM (IPW_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_ATIM_SENT (IPW_SHARED_LOWER_BOUND + 0xB10)
-#define IPW_WHO_IS_AWAKE (IPW_SHARED_LOWER_BOUND + 0xB14)
-#define IPW_DURING_ATIM_WINDOW (IPW_SHARED_LOWER_BOUND + 0xB18)
-
-#define MSB 1
-#define LSB 0
-#define WORD_TO_BYTE(_word) ((_word) * sizeof(u16))
-
-#define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \
- ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) )
-
-/* EEPROM access by BYTE */
-#define EEPROM_PME_CAPABILITY (GET_EEPROM_ADDR(0x09,MSB)) /* 1 byte */
-#define EEPROM_MAC_ADDRESS (GET_EEPROM_ADDR(0x21,LSB)) /* 6 byte */
-#define EEPROM_VERSION (GET_EEPROM_ADDR(0x24,MSB)) /* 1 byte */
-#define EEPROM_NIC_TYPE (GET_EEPROM_ADDR(0x25,LSB)) /* 1 byte */
-#define EEPROM_SKU_CAPABILITY (GET_EEPROM_ADDR(0x25,MSB)) /* 1 byte */
-#define EEPROM_COUNTRY_CODE (GET_EEPROM_ADDR(0x26,LSB)) /* 3 bytes */
-#define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB)) /* 2 bytes */
-#define EEPROM_IBSS_CHANNELS_A (GET_EEPROM_ADDR(0x29,MSB)) /* 5 bytes */
-#define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */
-#define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */
-
-/* NIC type as found in the one byte EEPROM_NIC_TYPE offset */
-#define EEPROM_NIC_TYPE_0 0
-#define EEPROM_NIC_TYPE_1 1
-#define EEPROM_NIC_TYPE_2 2
-#define EEPROM_NIC_TYPE_3 3
-#define EEPROM_NIC_TYPE_4 4
-
-/* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */
-#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */
-#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */
-#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */
-
-#define FW_MEM_REG_LOWER_BOUND 0x00300000
-#define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40)
-#define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04)
-#define EEPROM_BIT_SK (1<<0)
-#define EEPROM_BIT_CS (1<<1)
-#define EEPROM_BIT_DI (1<<2)
-#define EEPROM_BIT_DO (1<<4)
-
-#define EEPROM_CMD_READ 0x2
-
-/* Interrupts masks */
-#define IPW_INTA_NONE 0x00000000
-
-#define IPW_INTA_BIT_RX_TRANSFER 0x00000002
-#define IPW_INTA_BIT_STATUS_CHANGE 0x00000010
-#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020
-
-//Inta Bits for CF
-#define IPW_INTA_BIT_TX_CMD_QUEUE 0x00000800
-#define IPW_INTA_BIT_TX_QUEUE_1 0x00001000
-#define IPW_INTA_BIT_TX_QUEUE_2 0x00002000
-#define IPW_INTA_BIT_TX_QUEUE_3 0x00004000
-#define IPW_INTA_BIT_TX_QUEUE_4 0x00008000
-
-#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000
-
-#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000
-#define IPW_INTA_BIT_POWER_DOWN 0x00200000
-
-#define IPW_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000
-#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000
-#define IPW_INTA_BIT_RF_KILL_DONE 0x04000000
-#define IPW_INTA_BIT_FATAL_ERROR 0x40000000
-#define IPW_INTA_BIT_PARITY_ERROR 0x80000000
-
-/* Interrupts enabled at init time. */
-#define IPW_INTA_MASK_ALL \
- (IPW_INTA_BIT_TX_QUEUE_1 | \
- IPW_INTA_BIT_TX_QUEUE_2 | \
- IPW_INTA_BIT_TX_QUEUE_3 | \
- IPW_INTA_BIT_TX_QUEUE_4 | \
- IPW_INTA_BIT_TX_CMD_QUEUE | \
- IPW_INTA_BIT_RX_TRANSFER | \
- IPW_INTA_BIT_FATAL_ERROR | \
- IPW_INTA_BIT_PARITY_ERROR | \
- IPW_INTA_BIT_STATUS_CHANGE | \
- IPW_INTA_BIT_FW_INITIALIZATION_DONE | \
- IPW_INTA_BIT_BEACON_PERIOD_EXPIRED | \
- IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
- IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN | \
- IPW_INTA_BIT_POWER_DOWN | \
- IPW_INTA_BIT_RF_KILL_DONE )
-
-/* FW event log definitions */
-#define EVENT_ELEM_SIZE (3 * sizeof(u32))
-#define EVENT_START_OFFSET (1 * sizeof(u32) + 2 * sizeof(u16))
-
-/* FW error log definitions */
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-
-/* TX power level (dbm) */
-#define IPW_TX_POWER_MIN -12
-#define IPW_TX_POWER_MAX 20
-#define IPW_TX_POWER_DEFAULT IPW_TX_POWER_MAX
-
-enum {
- IPW_FW_ERROR_OK = 0,
- IPW_FW_ERROR_FAIL,
- IPW_FW_ERROR_MEMORY_UNDERFLOW,
- IPW_FW_ERROR_MEMORY_OVERFLOW,
- IPW_FW_ERROR_BAD_PARAM,
- IPW_FW_ERROR_BAD_CHECKSUM,
- IPW_FW_ERROR_NMI_INTERRUPT,
- IPW_FW_ERROR_BAD_DATABASE,
- IPW_FW_ERROR_ALLOC_FAIL,
- IPW_FW_ERROR_DMA_UNDERRUN,
- IPW_FW_ERROR_DMA_STATUS,
- IPW_FW_ERROR_DINO_ERROR,
- IPW_FW_ERROR_EEPROM_ERROR,
- IPW_FW_ERROR_SYSASSERT,
- IPW_FW_ERROR_FATAL_ERROR
-};
-
-#define AUTH_OPEN 0
-#define AUTH_SHARED_KEY 1
-#define AUTH_LEAP 2
-#define AUTH_IGNORE 3
-
-#define HC_ASSOCIATE 0
-#define HC_REASSOCIATE 1
-#define HC_DISASSOCIATE 2
-#define HC_IBSS_START 3
-#define HC_IBSS_RECONF 4
-#define HC_DISASSOC_QUIET 5
-
-#define HC_QOS_SUPPORT_ASSOC cpu_to_le16(0x01)
-
-#define IPW_RATE_CAPABILITIES 1
-#define IPW_RATE_CONNECT 0
-
-/*
- * Rate values and masks
- */
-#define IPW_TX_RATE_1MB 0x0A
-#define IPW_TX_RATE_2MB 0x14
-#define IPW_TX_RATE_5MB 0x37
-#define IPW_TX_RATE_6MB 0x0D
-#define IPW_TX_RATE_9MB 0x0F
-#define IPW_TX_RATE_11MB 0x6E
-#define IPW_TX_RATE_12MB 0x05
-#define IPW_TX_RATE_18MB 0x07
-#define IPW_TX_RATE_24MB 0x09
-#define IPW_TX_RATE_36MB 0x0B
-#define IPW_TX_RATE_48MB 0x01
-#define IPW_TX_RATE_54MB 0x03
-
-#define IPW_ORD_TABLE_ID_MASK 0x0000FF00
-#define IPW_ORD_TABLE_VALUE_MASK 0x000000FF
-
-#define IPW_ORD_TABLE_0_MASK 0x0000F000
-#define IPW_ORD_TABLE_1_MASK 0x0000F100
-#define IPW_ORD_TABLE_2_MASK 0x0000F200
-#define IPW_ORD_TABLE_3_MASK 0x0000F300
-#define IPW_ORD_TABLE_4_MASK 0x0000F400
-#define IPW_ORD_TABLE_5_MASK 0x0000F500
-#define IPW_ORD_TABLE_6_MASK 0x0000F600
-#define IPW_ORD_TABLE_7_MASK 0x0000F700
-
-/*
- * Table 0 Entries (all entries are 32 bits)
- */
-enum {
- IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1,
- IPW_ORD_STAT_FRAG_TRESHOLD,
- IPW_ORD_STAT_RTS_THRESHOLD,
- IPW_ORD_STAT_TX_HOST_REQUESTS,
- IPW_ORD_STAT_TX_HOST_COMPLETE,
- IPW_ORD_STAT_TX_DIR_DATA,
- IPW_ORD_STAT_TX_DIR_DATA_B_1,
- IPW_ORD_STAT_TX_DIR_DATA_B_2,
- IPW_ORD_STAT_TX_DIR_DATA_B_5_5,
- IPW_ORD_STAT_TX_DIR_DATA_B_11,
- /* Hole */
-
- IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19,
- IPW_ORD_STAT_TX_DIR_DATA_G_2,
- IPW_ORD_STAT_TX_DIR_DATA_G_5_5,
- IPW_ORD_STAT_TX_DIR_DATA_G_6,
- IPW_ORD_STAT_TX_DIR_DATA_G_9,
- IPW_ORD_STAT_TX_DIR_DATA_G_11,
- IPW_ORD_STAT_TX_DIR_DATA_G_12,
- IPW_ORD_STAT_TX_DIR_DATA_G_18,
- IPW_ORD_STAT_TX_DIR_DATA_G_24,
- IPW_ORD_STAT_TX_DIR_DATA_G_36,
- IPW_ORD_STAT_TX_DIR_DATA_G_48,
- IPW_ORD_STAT_TX_DIR_DATA_G_54,
- IPW_ORD_STAT_TX_NON_DIR_DATA,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_1,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_2,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_11,
- /* Hole */
-
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_2,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_6,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_9,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_11,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_12,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_18,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_24,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_36,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_48,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_54,
- IPW_ORD_STAT_TX_RETRY,
- IPW_ORD_STAT_TX_FAILURE,
- IPW_ORD_STAT_RX_ERR_CRC,
- IPW_ORD_STAT_RX_ERR_ICV,
- IPW_ORD_STAT_RX_NO_BUFFER,
- IPW_ORD_STAT_FULL_SCANS,
- IPW_ORD_STAT_PARTIAL_SCANS,
- IPW_ORD_STAT_TGH_ABORTED_SCANS,
- IPW_ORD_STAT_TX_TOTAL_BYTES,
- IPW_ORD_STAT_CURR_RSSI_RAW,
- IPW_ORD_STAT_RX_BEACON,
- IPW_ORD_STAT_MISSED_BEACONS,
- IPW_ORD_TABLE_0_LAST
-};
-
-#define IPW_RSSI_TO_DBM 112
-
-/* Table 1 Entries
- */
-enum {
- IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1,
-};
-
-/*
- * Table 2 Entries
- *
- * FW_VERSION: 16 byte string
- * FW_DATE: 16 byte string (only 14 bytes used)
- * UCODE_VERSION: 4 byte version code
- * UCODE_DATE: 5 bytes code code
- * ADDAPTER_MAC: 6 byte MAC address
- * RTC: 4 byte clock
- */
-enum {
- IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1,
- IPW_ORD_STAT_FW_DATE,
- IPW_ORD_STAT_UCODE_VERSION,
- IPW_ORD_STAT_UCODE_DATE,
- IPW_ORD_STAT_ADAPTER_MAC,
- IPW_ORD_STAT_RTC,
- IPW_ORD_TABLE_2_LAST
-};
-
-/* Table 3 */
-enum {
- IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0,
- IPW_ORD_STAT_TX_PACKET_FAILURE,
- IPW_ORD_STAT_TX_PACKET_SUCCESS,
- IPW_ORD_STAT_TX_PACKET_ABORTED,
- IPW_ORD_TABLE_3_LAST
-};
-
-/* Table 4 */
-enum {
- IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK
-};
-
-/* Table 5 */
-enum {
- IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK,
- IPW_ORD_STAT_AP_ASSNS,
- IPW_ORD_STAT_ROAM,
- IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS,
- IPW_ORD_STAT_ROAM_CAUSE_UNASSOC,
- IPW_ORD_STAT_ROAM_CAUSE_RSSI,
- IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY,
- IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE,
- IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX,
- IPW_ORD_STAT_LINK_UP,
- IPW_ORD_STAT_LINK_DOWN,
- IPW_ORD_ANTENNA_DIVERSITY,
- IPW_ORD_CURR_FREQ,
- IPW_ORD_TABLE_5_LAST
-};
-
-/* Table 6 */
-enum {
- IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK,
- IPW_ORD_CURR_BSSID,
- IPW_ORD_CURR_SSID,
- IPW_ORD_TABLE_6_LAST
-};
-
-/* Table 7 */
-enum {
- IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK,
- IPW_ORD_STAT_PERCENT_TX_RETRIES,
- IPW_ORD_STAT_PERCENT_LINK_QUALITY,
- IPW_ORD_STAT_CURR_RSSI_DBM,
- IPW_ORD_TABLE_7_LAST
-};
-
-#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410)
-#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414)
-#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500)
-#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180)
-#define IPW_ORDINALS_TABLE_1 (IPW_SHARED_LOWER_BOUND + 0x184)
-#define IPW_ORDINALS_TABLE_2 (IPW_SHARED_LOWER_BOUND + 0x188)
-#define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C)
-
-struct ipw_fixed_rate {
- __le16 tx_rates;
- __le16 reserved;
-} __packed;
-
-#define IPW_INDIRECT_ADDR_MASK (~0x3ul)
-
-struct host_cmd {
- u8 cmd;
- u8 len;
- u16 reserved;
- const u32 *param;
-} __packed; /* XXX */
-
-struct cmdlog_host_cmd {
- u8 cmd;
- u8 len;
- __le16 reserved;
- char param[124];
-} __packed;
-
-struct ipw_cmd_log {
- unsigned long jiffies;
- int retcode;
- struct cmdlog_host_cmd cmd;
-};
-
-/* SysConfig command parameters ... */
-/* bt_coexistence param */
-#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */
-#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */
-#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */
-#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */
-#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */
-
-/* clear-to-send to self param */
-#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x00
-#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x01
-#define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN
-
-/* Antenna diversity param (h/w can select best antenna, based on signal) */
-#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */
-#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */
-#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */
-#define CFG_SYS_ANTENNA_SLOW_DIV 0x02 /* consider background noise */
-
-#define IPW_MAX_CONFIG_RETRIES 10
-
-#endif /* __ipw2200_h__ */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h
deleted file mode 100644
index 9065ca5b02085..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw.h
+++ /dev/null
@@ -1,1001 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
- * remains copyright by the original authors
- *
- * Portions of the merged code are based on Host AP (software wireless
- * LAN access point) driver for Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <[email protected]>
- * Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <[email protected]>
- * Copyright (c) 2004-2005, Intel Corporation
- *
- * API Version History
- * 1.0.x -- Initial version
- * 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs,
- * various structure changes, and crypto API init method
- */
-#ifndef LIBIPW_H
-#define LIBIPW_H
-#include <linux/if_ether.h> /* ETH_ALEN */
-#include <linux/kernel.h> /* ARRAY_SIZE */
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-
-#include <net/lib80211.h>
-#include <net/cfg80211.h>
-
-#define LIBIPW_VERSION "git-1.1.13"
-
-#define LIBIPW_DATA_LEN 2304
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
- 6.2.1.1.2.
-
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-
-#define LIBIPW_1ADDR_LEN 10
-#define LIBIPW_2ADDR_LEN 16
-#define LIBIPW_3ADDR_LEN 24
-#define LIBIPW_4ADDR_LEN 30
-#define LIBIPW_FCS_LEN 4
-#define LIBIPW_HLEN (LIBIPW_4ADDR_LEN)
-#define LIBIPW_FRAME_LEN (LIBIPW_DATA_LEN + LIBIPW_HLEN)
-
-#define MIN_FRAG_THRESHOLD 256U
-#define MAX_FRAG_THRESHOLD 2346U
-
-/* QOS control */
-#define LIBIPW_QCTL_TID 0x000F
-
-/* debug macros */
-
-#ifdef CONFIG_LIBIPW_DEBUG
-extern u32 libipw_debug_level;
-#define LIBIPW_DEBUG(level, fmt, args...) \
-do { if (libipw_debug_level & (level)) \
- printk(KERN_DEBUG "libipw: %s " fmt, __func__ , ## args); } while (0)
-#else
-#define LIBIPW_DEBUG(level, fmt, args...) do {} while (0)
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-/*
- * To use the debug system:
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define LIBIPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a LIBIPW_xxxx_DEBUG() macro definition for your
- * classification, or use LIBIPW_DEBUG(LIBIPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ieee80211/debug_level
- *
- * you simply need to add your entry to the libipw_debug_level array.
- *
- * If you do not see debug_level in /proc/net/ieee80211 then you do not have
- * CONFIG_LIBIPW_DEBUG defined in your kernel configuration
- *
- */
-
-#define LIBIPW_DL_INFO (1<<0)
-#define LIBIPW_DL_WX (1<<1)
-#define LIBIPW_DL_SCAN (1<<2)
-#define LIBIPW_DL_STATE (1<<3)
-#define LIBIPW_DL_MGMT (1<<4)
-#define LIBIPW_DL_FRAG (1<<5)
-#define LIBIPW_DL_DROP (1<<7)
-
-#define LIBIPW_DL_TX (1<<8)
-#define LIBIPW_DL_RX (1<<9)
-#define LIBIPW_DL_QOS (1<<31)
-
-#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "libipw: " f, ## a)
-#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "libipw: " f, ## a)
-#define LIBIPW_DEBUG_INFO(f, a...) LIBIPW_DEBUG(LIBIPW_DL_INFO, f, ## a)
-
-#define LIBIPW_DEBUG_WX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_WX, f, ## a)
-#define LIBIPW_DEBUG_SCAN(f, a...) LIBIPW_DEBUG(LIBIPW_DL_SCAN, f, ## a)
-#define LIBIPW_DEBUG_STATE(f, a...) LIBIPW_DEBUG(LIBIPW_DL_STATE, f, ## a)
-#define LIBIPW_DEBUG_MGMT(f, a...) LIBIPW_DEBUG(LIBIPW_DL_MGMT, f, ## a)
-#define LIBIPW_DEBUG_FRAG(f, a...) LIBIPW_DEBUG(LIBIPW_DL_FRAG, f, ## a)
-#define LIBIPW_DEBUG_DROP(f, a...) LIBIPW_DEBUG(LIBIPW_DL_DROP, f, ## a)
-#define LIBIPW_DEBUG_TX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_TX, f, ## a)
-#define LIBIPW_DEBUG_RX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_RX, f, ## a)
-#define LIBIPW_DEBUG_QOS(f, a...) LIBIPW_DEBUG(LIBIPW_DL_QOS, f, ## a)
-#include <linux/netdevice.h>
-#include <linux/if_arp.h> /* ARPHRD_ETHER */
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY /* enable iwspy support */
-#endif
-#include <net/iw_handler.h> /* new driver API */
-
-#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
-#endif
-
-/* IEEE 802.11 defines */
-
-#define P80211_OUI_LEN 3
-
-struct libipw_snap_hdr {
-
- u8 dsap; /* always 0xAA */
- u8 ssap; /* always 0xAA */
- u8 ctrl; /* always 0x03 */
- u8 oui[P80211_OUI_LEN]; /* organizational universal id */
-
-} __packed;
-
-#define SNAP_SIZE sizeof(struct libipw_snap_hdr)
-
-#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
-#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
-#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
-
-#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
-#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-
-#define LIBIPW_STATMASK_SIGNAL (1<<0)
-#define LIBIPW_STATMASK_RSSI (1<<1)
-#define LIBIPW_STATMASK_NOISE (1<<2)
-#define LIBIPW_STATMASK_RATE (1<<3)
-#define LIBIPW_STATMASK_WEMASK 0x7
-
-#define LIBIPW_CCK_MODULATION (1<<0)
-#define LIBIPW_OFDM_MODULATION (1<<1)
-
-#define LIBIPW_24GHZ_BAND (1<<0)
-#define LIBIPW_52GHZ_BAND (1<<1)
-
-#define LIBIPW_CCK_RATE_1MB 0x02
-#define LIBIPW_CCK_RATE_2MB 0x04
-#define LIBIPW_CCK_RATE_5MB 0x0B
-#define LIBIPW_CCK_RATE_11MB 0x16
-#define LIBIPW_OFDM_RATE_6MB 0x0C
-#define LIBIPW_OFDM_RATE_9MB 0x12
-#define LIBIPW_OFDM_RATE_12MB 0x18
-#define LIBIPW_OFDM_RATE_18MB 0x24
-#define LIBIPW_OFDM_RATE_24MB 0x30
-#define LIBIPW_OFDM_RATE_36MB 0x48
-#define LIBIPW_OFDM_RATE_48MB 0x60
-#define LIBIPW_OFDM_RATE_54MB 0x6C
-#define LIBIPW_BASIC_RATE_MASK 0x80
-
-#define LIBIPW_CCK_RATE_1MB_MASK (1<<0)
-#define LIBIPW_CCK_RATE_2MB_MASK (1<<1)
-#define LIBIPW_CCK_RATE_5MB_MASK (1<<2)
-#define LIBIPW_CCK_RATE_11MB_MASK (1<<3)
-#define LIBIPW_OFDM_RATE_6MB_MASK (1<<4)
-#define LIBIPW_OFDM_RATE_9MB_MASK (1<<5)
-#define LIBIPW_OFDM_RATE_12MB_MASK (1<<6)
-#define LIBIPW_OFDM_RATE_18MB_MASK (1<<7)
-#define LIBIPW_OFDM_RATE_24MB_MASK (1<<8)
-#define LIBIPW_OFDM_RATE_36MB_MASK (1<<9)
-#define LIBIPW_OFDM_RATE_48MB_MASK (1<<10)
-#define LIBIPW_OFDM_RATE_54MB_MASK (1<<11)
-
-#define LIBIPW_CCK_RATES_MASK 0x0000000F
-#define LIBIPW_CCK_BASIC_RATES_MASK (LIBIPW_CCK_RATE_1MB_MASK | \
- LIBIPW_CCK_RATE_2MB_MASK)
-#define LIBIPW_CCK_DEFAULT_RATES_MASK (LIBIPW_CCK_BASIC_RATES_MASK | \
- LIBIPW_CCK_RATE_5MB_MASK | \
- LIBIPW_CCK_RATE_11MB_MASK)
-
-#define LIBIPW_OFDM_RATES_MASK 0x00000FF0
-#define LIBIPW_OFDM_BASIC_RATES_MASK (LIBIPW_OFDM_RATE_6MB_MASK | \
- LIBIPW_OFDM_RATE_12MB_MASK | \
- LIBIPW_OFDM_RATE_24MB_MASK)
-#define LIBIPW_OFDM_DEFAULT_RATES_MASK (LIBIPW_OFDM_BASIC_RATES_MASK | \
- LIBIPW_OFDM_RATE_9MB_MASK | \
- LIBIPW_OFDM_RATE_18MB_MASK | \
- LIBIPW_OFDM_RATE_36MB_MASK | \
- LIBIPW_OFDM_RATE_48MB_MASK | \
- LIBIPW_OFDM_RATE_54MB_MASK)
-#define LIBIPW_DEFAULT_RATES_MASK (LIBIPW_OFDM_DEFAULT_RATES_MASK | \
- LIBIPW_CCK_DEFAULT_RATES_MASK)
-
-#define LIBIPW_NUM_OFDM_RATES 8
-#define LIBIPW_NUM_CCK_RATES 4
-#define LIBIPW_OFDM_SHIFT_MASK_A 4
-
-/* NOTE: This data is for statistical purposes; not all hardware provides this
- * information for frames received.
- * For libipw_rx_mgt, you need to set at least the 'len' parameter.
- */
-struct libipw_rx_stats {
- u32 mac_time;
- s8 rssi;
- u8 signal;
- u8 noise;
- u16 rate; /* in 100 kbps */
- u8 received_channel;
- u8 control;
- u8 mask;
- u8 freq;
- u16 len;
- u64 tsf;
- u32 beacon_time;
-};
-
-/* IEEE 802.11 requires that STA supports concurrent reception of at least
- * three fragmented frames. This define can be increased to support more
- * concurrent frames, but it should be noted that each entry can consume about
- * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
-#define LIBIPW_FRAG_CACHE_LEN 4
-
-struct libipw_frag_entry {
- unsigned long first_frag_time;
- unsigned int seq;
- unsigned int last_frag;
- struct sk_buff *skb;
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
-};
-
-struct libipw_stats {
- unsigned int tx_unicast_frames;
- unsigned int tx_multicast_frames;
- unsigned int tx_fragments;
- unsigned int tx_unicast_octets;
- unsigned int tx_multicast_octets;
- unsigned int tx_deferred_transmissions;
- unsigned int tx_single_retry_frames;
- unsigned int tx_multiple_retry_frames;
- unsigned int tx_retry_limit_exceeded;
- unsigned int tx_discards;
- unsigned int rx_unicast_frames;
- unsigned int rx_multicast_frames;
- unsigned int rx_fragments;
- unsigned int rx_unicast_octets;
- unsigned int rx_multicast_octets;
- unsigned int rx_fcs_errors;
- unsigned int rx_discards_no_buffer;
- unsigned int tx_discards_wrong_sa;
- unsigned int rx_discards_undecryptable;
- unsigned int rx_message_in_msg_fragments;
- unsigned int rx_message_in_bad_msg_fragments;
-};
-
-struct libipw_device;
-
-#define SEC_KEY_1 (1<<0)
-#define SEC_KEY_2 (1<<1)
-#define SEC_KEY_3 (1<<2)
-#define SEC_KEY_4 (1<<3)
-#define SEC_ACTIVE_KEY (1<<4)
-#define SEC_AUTH_MODE (1<<5)
-#define SEC_UNICAST_GROUP (1<<6)
-#define SEC_LEVEL (1<<7)
-#define SEC_ENABLED (1<<8)
-#define SEC_ENCRYPT (1<<9)
-
-#define SEC_LEVEL_0 0 /* None */
-#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
-#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
-#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
-#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
-
-#define SEC_ALG_NONE 0
-#define SEC_ALG_WEP 1
-#define SEC_ALG_TKIP 2
-#define SEC_ALG_CCMP 3
-
-#define WEP_KEYS 4
-#define WEP_KEY_LEN 13
-#define SCM_KEY_LEN 32
-#define SCM_TEMPORAL_KEY_LENGTH 16
-
-struct libipw_security {
- u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1;
- u8 auth_mode;
- u8 encode_alg[WEP_KEYS];
- u8 key_sizes[WEP_KEYS];
- u8 keys[WEP_KEYS][SCM_KEY_LEN];
- u8 level;
- u16 flags;
-} __packed;
-
-/*
-
- 802.11 data frame from AP
-
- ,-------------------------------------------------------------------.
-Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- |------|------|---------|---------|---------|------|---------|------|
-Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
- | | tion | (BSSID) | | | ence | data | |
- `-------------------------------------------------------------------'
-
-Total: 28-2340 bytes
-
-*/
-
-#define BEACON_PROBE_SSID_ID_POSITION 12
-
-struct libipw_hdr_1addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_2addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_3addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_4addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_3addrqos {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[0];
- __le16 qos_ctl;
-} __packed;
-
-struct libipw_info_element {
- u8 id;
- u8 len;
- u8 data[];
-} __packed;
-
-/*
- * These are the data types that can make up management packets
- *
- u16 auth_algorithm;
- u16 auth_sequence;
- u16 beacon_interval;
- u16 capability;
- u8 current_ap[ETH_ALEN];
- u16 listen_interval;
- struct {
- u16 association_id:14, reserved:2;
- } __packed;
- u32 time_stamp[2];
- u16 reason;
- u16 status;
-*/
-
-struct libipw_auth {
- struct libipw_hdr_3addr header;
- __le16 algorithm;
- __le16 transaction;
- __le16 status;
- /* challenge */
- u8 variable[];
-} __packed;
-
-struct libipw_channel_switch {
- u8 id;
- u8 len;
- u8 mode;
- u8 channel;
- u8 count;
-} __packed;
-
-struct libipw_action {
- struct libipw_hdr_3addr header;
- u8 category;
- u8 action;
- union {
- struct libipw_action_exchange {
- u8 token;
- } exchange;
- struct libipw_channel_switch channel_switch;
-
- } format;
-} __packed;
-
-struct libipw_disassoc {
- struct libipw_hdr_3addr header;
- __le16 reason;
-} __packed;
-
-/* Alias deauth for disassoc */
-#define libipw_deauth libipw_disassoc
-
-struct libipw_probe_request {
- struct libipw_hdr_3addr header;
- /* SSID, supported rates */
- u8 variable[];
-} __packed;
-
-struct libipw_probe_response {
- struct libipw_hdr_3addr header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- /* SSID, supported rates, FH params, DS params,
- * CF params, IBSS params, TIM (if beacon), RSN */
- u8 variable[];
-} __packed;
-
-/* Alias beacon for probe_response */
-#define libipw_beacon libipw_probe_response
-
-struct libipw_assoc_request {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- /* SSID, supported rates, RSN */
- u8 variable[];
-} __packed;
-
-struct libipw_reassoc_request {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- u8 current_ap[ETH_ALEN];
- u8 variable[];
-} __packed;
-
-struct libipw_assoc_response {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 status;
- __le16 aid;
- /* supported rates */
- u8 variable[];
-} __packed;
-
-struct libipw_txb {
- u8 nr_frags;
- u8 encrypted;
- u8 rts_included;
- u8 reserved;
- u16 frag_size;
- u16 payload_size;
- struct sk_buff *fragments[] __counted_by(nr_frags);
-};
-
-/* SWEEP TABLE ENTRIES NUMBER */
-#define MAX_SWEEP_TAB_ENTRIES 42
-#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
-/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
- * only use 8, and then use extended rates for the remaining supported
- * rates. Other APs, however, stick all of their supported rates on the
- * main rates information element... */
-#define MAX_RATES_LENGTH ((u8)12)
-#define MAX_RATES_EX_LENGTH ((u8)16)
-#define MAX_NETWORK_COUNT 128
-
-#define CRC_LENGTH 4U
-
-#define MAX_WPA_IE_LEN 64
-
-#define NETWORK_HAS_OFDM (1<<1)
-#define NETWORK_HAS_CCK (1<<2)
-
-/* QoS structure */
-#define NETWORK_HAS_QOS_PARAMETERS (1<<3)
-#define NETWORK_HAS_QOS_INFORMATION (1<<4)
-#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \
- NETWORK_HAS_QOS_INFORMATION)
-
-/* 802.11h */
-#define NETWORK_HAS_POWER_CONSTRAINT (1<<5)
-#define NETWORK_HAS_CSA (1<<6)
-#define NETWORK_HAS_QUIET (1<<7)
-#define NETWORK_HAS_IBSS_DFS (1<<8)
-#define NETWORK_HAS_TPC_REPORT (1<<9)
-
-#define NETWORK_HAS_ERP_VALUE (1<<10)
-
-#define QOS_QUEUE_NUM 4
-#define QOS_OUI_LEN 3
-#define QOS_OUI_TYPE 2
-#define QOS_ELEMENT_ID 221
-#define QOS_OUI_INFO_SUB_TYPE 0
-#define QOS_OUI_PARAM_SUB_TYPE 1
-#define QOS_VERSION_1 1
-#define QOS_AIFSN_MIN_VALUE 2
-
-struct libipw_qos_information_element {
- u8 elementID;
- u8 length;
- u8 qui[QOS_OUI_LEN];
- u8 qui_type;
- u8 qui_subtype;
- u8 version;
- u8 ac_info;
-} __packed;
-
-struct libipw_qos_ac_parameter {
- u8 aci_aifsn;
- u8 ecw_min_max;
- __le16 tx_op_limit;
-} __packed;
-
-struct libipw_qos_parameter_info {
- struct libipw_qos_information_element info_element;
- u8 reserved;
- struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __packed;
-
-struct libipw_qos_parameters {
- __le16 cw_min[QOS_QUEUE_NUM];
- __le16 cw_max[QOS_QUEUE_NUM];
- u8 aifs[QOS_QUEUE_NUM];
- u8 flag[QOS_QUEUE_NUM];
- __le16 tx_op_limit[QOS_QUEUE_NUM];
-} __packed;
-
-struct libipw_qos_data {
- struct libipw_qos_parameters parameters;
- int active;
- int supported;
- u8 param_count;
- u8 old_param_count;
-};
-
-struct libipw_tim_parameters {
- u8 tim_count;
- u8 tim_period;
-} __packed;
-
-/*******************************************************/
-
-struct libipw_tpc_report {
- u8 transmit_power;
- u8 link_margin;
-} __packed;
-
-struct libipw_channel_map {
- u8 channel;
- u8 map;
-} __packed;
-
-struct libipw_ibss_dfs {
- struct libipw_info_element ie;
- u8 owner[ETH_ALEN];
- u8 recovery_interval;
- struct libipw_channel_map channel_map[];
-};
-
-struct libipw_csa {
- u8 mode;
- u8 channel;
- u8 count;
-} __packed;
-
-struct libipw_quiet {
- u8 count;
- u8 period;
- u8 duration;
- u8 offset;
-} __packed;
-
-struct libipw_network {
- /* These entries are used to identify a unique network */
- u8 bssid[ETH_ALEN];
- u8 channel;
- /* Ensure null-terminated for any debug msgs */
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
-
- struct libipw_qos_data qos_data;
-
- /* These are network statistics */
- struct libipw_rx_stats stats;
- u16 capability;
- u8 rates[MAX_RATES_LENGTH];
- u8 rates_len;
- u8 rates_ex[MAX_RATES_EX_LENGTH];
- u8 rates_ex_len;
- unsigned long last_scanned;
- u8 mode;
- u32 flags;
- u32 last_associate;
- u32 time_stamp[2];
- u16 beacon_interval;
- u16 listen_interval;
- u16 atim_window;
- u8 erp_value;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
- struct libipw_tim_parameters tim;
-
- /* 802.11h info */
-
- /* Power Constraint - mandatory if spctrm mgmt required */
- u8 power_constraint;
-
- /* TPC Report - mandatory if spctrm mgmt required */
- struct libipw_tpc_report tpc_report;
-
- /* Channel Switch Announcement - optional if spctrm mgmt required */
- struct libipw_csa csa;
-
- /* Quiet - optional if spctrm mgmt required */
- struct libipw_quiet quiet;
-
- struct list_head list;
-};
-
-enum libipw_state {
- LIBIPW_UNINITIALIZED = 0,
- LIBIPW_INITIALIZED,
- LIBIPW_ASSOCIATING,
- LIBIPW_ASSOCIATED,
- LIBIPW_AUTHENTICATING,
- LIBIPW_AUTHENTICATED,
- LIBIPW_SHUTDOWN
-};
-
-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
-#define DEFAULT_FTS 2346
-
-#define CFG_LIBIPW_RESERVE_FCS (1<<0)
-#define CFG_LIBIPW_COMPUTE_FCS (1<<1)
-#define CFG_LIBIPW_RTS (1<<2)
-
-#define LIBIPW_24GHZ_MIN_CHANNEL 1
-#define LIBIPW_24GHZ_MAX_CHANNEL 14
-#define LIBIPW_24GHZ_CHANNELS (LIBIPW_24GHZ_MAX_CHANNEL - \
- LIBIPW_24GHZ_MIN_CHANNEL + 1)
-
-#define LIBIPW_52GHZ_MIN_CHANNEL 34
-#define LIBIPW_52GHZ_MAX_CHANNEL 165
-#define LIBIPW_52GHZ_CHANNELS (LIBIPW_52GHZ_MAX_CHANNEL - \
- LIBIPW_52GHZ_MIN_CHANNEL + 1)
-
-enum {
- LIBIPW_CH_PASSIVE_ONLY = (1 << 0),
- LIBIPW_CH_80211H_RULES = (1 << 1),
- LIBIPW_CH_B_ONLY = (1 << 2),
- LIBIPW_CH_NO_IBSS = (1 << 3),
- LIBIPW_CH_UNIFORM_SPREADING = (1 << 4),
- LIBIPW_CH_RADAR_DETECT = (1 << 5),
- LIBIPW_CH_INVALID = (1 << 6),
-};
-
-struct libipw_channel {
- u32 freq; /* in MHz */
- u8 channel;
- u8 flags;
- u8 max_power; /* in dBm */
-};
-
-struct libipw_geo {
- u8 name[4];
- u8 bg_channels;
- u8 a_channels;
- struct libipw_channel bg[LIBIPW_24GHZ_CHANNELS];
- struct libipw_channel a[LIBIPW_52GHZ_CHANNELS];
-};
-
-struct libipw_device {
- struct net_device *dev;
- struct wireless_dev wdev;
- struct libipw_security sec;
-
- /* Bookkeeping structures */
- struct libipw_stats ieee_stats;
-
- struct libipw_geo geo;
- struct ieee80211_supported_band bg_band;
- struct ieee80211_supported_band a_band;
-
- /* Probe / Beacon management */
- struct list_head network_free_list;
- struct list_head network_list;
- struct libipw_network *networks[MAX_NETWORK_COUNT];
- int scans;
- int scan_age;
-
- int iw_mode; /* operating mode (IW_MODE_*) */
- struct iw_spy_data spy_data; /* iwspy support */
-
- spinlock_t lock;
-
- int tx_headroom; /* Set to size of any additional room needed at front
- * of allocated Tx SKBs */
- u32 config;
-
- /* WEP and other encryption related settings at the device level */
- int open_wep; /* Set to 1 to allow unencrypted frames */
-
- /* If the host performs {en,de}cryption, then set to 1 */
- int host_encrypt;
- int host_encrypt_msdu;
- int host_decrypt;
- /* host performs multicast decryption */
- int host_mc_decrypt;
-
- /* host should strip IV and ICV from protected frames */
- /* meaningful only when hardware decryption is being used */
- int host_strip_iv_icv;
-
- int host_open_frag;
- int ieee802_1x; /* is IEEE 802.1X used */
-
- /* WPA data */
- int wpa_enabled;
- int drop_unencrypted;
- int privacy_invoked;
- size_t wpa_ie_len;
- u8 *wpa_ie;
-
- struct lib80211_crypt_info crypt_info;
-
- int bcrx_sta_key; /* use individual keys to override default keys even
- * with RX of broad/multicast frames */
-
- /* Fragmentation structures */
- struct libipw_frag_entry frag_cache[LIBIPW_FRAG_CACHE_LEN];
- unsigned int frag_next_idx;
- u16 fts; /* Fragmentation Threshold */
- u16 rts; /* RTS threshold */
-
- /* Association info */
- u8 bssid[ETH_ALEN];
-
- enum libipw_state state;
-
- int mode; /* A, B, G */
- int modulation; /* CCK, OFDM */
- int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */
- int abg_true; /* ABG flag */
-
- int perfect_rssi;
- int worst_rssi;
-
- u16 prev_seq_ctl; /* used to drop duplicate frames */
-
- /* Callback functions */
- void (*set_security) (struct net_device * dev,
- struct libipw_security * sec);
- netdev_tx_t (*hard_start_xmit) (struct libipw_txb * txb,
- struct net_device * dev, int pri);
- int (*is_queue_full) (struct net_device * dev, int pri);
-
- int (*handle_management) (struct net_device * dev,
- struct libipw_network * network, u16 type);
- int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
-
- /* Typical STA methods */
- int (*handle_auth) (struct net_device * dev,
- struct libipw_auth * auth);
- int (*handle_deauth) (struct net_device * dev,
- struct libipw_deauth * auth);
- int (*handle_action) (struct net_device * dev,
- struct libipw_action * action,
- struct libipw_rx_stats * stats);
- int (*handle_disassoc) (struct net_device * dev,
- struct libipw_disassoc * assoc);
- int (*handle_beacon) (struct net_device * dev,
- struct libipw_beacon * beacon,
- struct libipw_network * network);
- int (*handle_probe_response) (struct net_device * dev,
- struct libipw_probe_response * resp,
- struct libipw_network * network);
- int (*handle_probe_request) (struct net_device * dev,
- struct libipw_probe_request * req,
- struct libipw_rx_stats * stats);
- int (*handle_assoc_response) (struct net_device * dev,
- struct libipw_assoc_response * resp,
- struct libipw_network * network);
-
- /* Typical AP methods */
- int (*handle_assoc_request) (struct net_device * dev);
- int (*handle_reassoc_request) (struct net_device * dev,
- struct libipw_reassoc_request * req);
-
- /* This must be the last item so that it points to the data
- * allocated beyond this structure by alloc_libipw */
- u8 priv[];
-};
-
-#define IEEE_A (1<<0)
-#define IEEE_B (1<<1)
-#define IEEE_G (1<<2)
-#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
-
-static inline void *libipw_priv(struct net_device *dev)
-{
- return ((struct libipw_device *)netdev_priv(dev))->priv;
-}
-
-static inline int libipw_is_valid_mode(struct libipw_device *ieee,
- int mode)
-{
- /*
- * It is possible for both access points and our device to support
- * combinations of modes, so as long as there is one valid combination
- * of ap/device supported modes, then return success
- *
- */
- if ((mode & IEEE_A) &&
- (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
- (ieee->freq_band & LIBIPW_52GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_G) &&
- (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
- (ieee->freq_band & LIBIPW_24GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_B) &&
- (ieee->modulation & LIBIPW_CCK_MODULATION) &&
- (ieee->freq_band & LIBIPW_24GHZ_BAND))
- return 1;
-
- return 0;
-}
-
-static inline int libipw_get_hdrlen(u16 fc)
-{
- int hdrlen = LIBIPW_3ADDR_LEN;
- u16 stype = WLAN_FC_GET_STYPE(fc);
-
- switch (WLAN_FC_GET_TYPE(fc)) {
- case IEEE80211_FTYPE_DATA:
- if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = LIBIPW_4ADDR_LEN;
- if (stype & IEEE80211_STYPE_QOS_DATA)
- hdrlen += 2;
- break;
- case IEEE80211_FTYPE_CTL:
- switch (WLAN_FC_GET_STYPE(fc)) {
- case IEEE80211_STYPE_CTS:
- case IEEE80211_STYPE_ACK:
- hdrlen = LIBIPW_1ADDR_LEN;
- break;
- default:
- hdrlen = LIBIPW_2ADDR_LEN;
- break;
- }
- break;
- }
-
- return hdrlen;
-}
-
-static inline u8 *libipw_get_payload(struct ieee80211_hdr *hdr)
-{
- switch (libipw_get_hdrlen(le16_to_cpu(hdr->frame_control))) {
- case LIBIPW_1ADDR_LEN:
- return ((struct libipw_hdr_1addr *)hdr)->payload;
- case LIBIPW_2ADDR_LEN:
- return ((struct libipw_hdr_2addr *)hdr)->payload;
- case LIBIPW_3ADDR_LEN:
- return ((struct libipw_hdr_3addr *)hdr)->payload;
- case LIBIPW_4ADDR_LEN:
- return ((struct libipw_hdr_4addr *)hdr)->payload;
- }
- return NULL;
-}
-
-static inline int libipw_is_ofdm_rate(u8 rate)
-{
- switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
- case LIBIPW_OFDM_RATE_6MB:
- case LIBIPW_OFDM_RATE_9MB:
- case LIBIPW_OFDM_RATE_12MB:
- case LIBIPW_OFDM_RATE_18MB:
- case LIBIPW_OFDM_RATE_24MB:
- case LIBIPW_OFDM_RATE_36MB:
- case LIBIPW_OFDM_RATE_48MB:
- case LIBIPW_OFDM_RATE_54MB:
- return 1;
- }
- return 0;
-}
-
-static inline int libipw_is_cck_rate(u8 rate)
-{
- switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
- case LIBIPW_CCK_RATE_1MB:
- case LIBIPW_CCK_RATE_2MB:
- case LIBIPW_CCK_RATE_5MB:
- case LIBIPW_CCK_RATE_11MB:
- return 1;
- }
- return 0;
-}
-
-/* libipw.c */
-void free_libipw(struct net_device *dev, int monitor);
-struct net_device *alloc_libipw(int sizeof_priv, int monitor);
-
-void libipw_networks_age(struct libipw_device *ieee, unsigned long age_secs);
-
-int libipw_set_encryption(struct libipw_device *ieee);
-
-/* libipw_tx.c */
-netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev);
-void libipw_txb_free(struct libipw_txb *);
-
-/* libipw_rx.c */
-void libipw_rx_any(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *stats);
-int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats);
-/* make sure to set stats->len */
-void libipw_rx_mgt(struct libipw_device *ieee, struct libipw_hdr_4addr *header,
- struct libipw_rx_stats *stats);
-
-/* libipw_geo.c */
-const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee);
-void libipw_set_geo(struct libipw_device *ieee, const struct libipw_geo *geo);
-
-int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel);
-int libipw_channel_to_index(struct libipw_device *ieee, u8 channel);
-u8 libipw_freq_to_channel(struct libipw_device *ieee, u32 freq);
-u8 libipw_get_channel_flags(struct libipw_device *ieee, u8 channel);
-const struct libipw_channel *libipw_get_channel(struct libipw_device *ieee,
- u8 channel);
-u32 libipw_channel_to_freq(struct libipw_device *ieee, u8 channel);
-
-/* libipw_wx.c */
-int libipw_wx_get_scan(struct libipw_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-int libipw_wx_set_encode(struct libipw_device *ieee,
- struct iw_request_info *info, union iwreq_data *wrqu,
- char *key);
-int libipw_wx_get_encode(struct libipw_device *ieee,
- struct iw_request_info *info, union iwreq_data *wrqu,
- char *key);
-int libipw_wx_set_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-int libipw_wx_get_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-static inline void libipw_increment_scans(struct libipw_device *ieee)
-{
- ieee->scans++;
-}
-
-static inline int libipw_get_scans(struct libipw_device *ieee)
-{
- return ieee->scans;
-}
-
-#endif /* LIBIPW_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
deleted file mode 100644
index f2ae3f8f2f5cb..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2005 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-
-#include "libipw.h"
-
-int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- /* NOTE: If G mode is currently supported but
- * this is a B only channel, we don't see it
- * as valid. */
- if ((ieee->geo.bg[i].channel == channel) &&
- !(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) &&
- (!(ieee->mode & IEEE_G) ||
- !(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY)))
- return LIBIPW_24GHZ_BAND;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if ((ieee->geo.a[i].channel == channel) &&
- !(ieee->geo.a[i].flags & LIBIPW_CH_INVALID))
- return LIBIPW_52GHZ_BAND;
-
- return 0;
-}
-
-int libipw_channel_to_index(struct libipw_device *ieee, u8 channel)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return -1;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- if (ieee->geo.bg[i].channel == channel)
- return i;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if (ieee->geo.a[i].channel == channel)
- return i;
-
- return -1;
-}
-
-u32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel)
-{
- const struct libipw_channel * ch;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- ch = libipw_get_channel(ieee, channel);
- if (!ch->channel)
- return 0;
- return ch->freq;
-}
-
-u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- freq /= 100000;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- if (ieee->geo.bg[i].freq == freq)
- return ieee->geo.bg[i].channel;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if (ieee->geo.a[i].freq == freq)
- return ieee->geo.a[i].channel;
-
- return 0;
-}
-
-void libipw_set_geo(struct libipw_device *ieee,
- const struct libipw_geo *geo)
-{
- memcpy(ieee->geo.name, geo->name, 3);
- ieee->geo.name[3] = '\0';
- ieee->geo.bg_channels = geo->bg_channels;
- ieee->geo.a_channels = geo->a_channels;
- memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
- sizeof(struct libipw_channel));
- memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
- sizeof(struct libipw_channel));
-}
-
-const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee)
-{
- return &ieee->geo;
-}
-
-u8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel)
-{
- int index = libipw_channel_to_index(ieee, channel);
-
- if (index == -1)
- return LIBIPW_CH_INVALID;
-
- if (channel <= LIBIPW_24GHZ_CHANNELS)
- return ieee->geo.bg[index].flags;
-
- return ieee->geo.a[index].flags;
-}
-
-static const struct libipw_channel bad_channel = {
- .channel = 0,
- .flags = LIBIPW_CH_INVALID,
- .max_power = 0,
-};
-
-const struct libipw_channel *libipw_get_channel(struct libipw_device
- *ieee, u8 channel)
-{
- int index = libipw_channel_to_index(ieee, channel);
-
- if (index == -1)
- return &bad_channel;
-
- if (channel <= LIBIPW_24GHZ_CHANNELS)
- return &ieee->geo.bg[index];
-
- return &ieee->geo.a[index];
-}
-
-EXPORT_SYMBOL(libipw_get_channel);
-EXPORT_SYMBOL(libipw_get_channel_flags);
-EXPORT_SYMBOL(libipw_is_valid_channel);
-EXPORT_SYMBOL(libipw_freq_to_channel);
-EXPORT_SYMBOL(libipw_channel_to_freq);
-EXPORT_SYMBOL(libipw_channel_to_index);
-EXPORT_SYMBOL(libipw_set_geo);
-EXPORT_SYMBOL(libipw_get_geo);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
deleted file mode 100644
index 43bab92a4148f..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c
+++ /dev/null
@@ -1,297 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*******************************************************************************
-
- Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
-
- Portions of this file are based on the WEP enablement code provided by the
- Host AP project hostap-drivers v0.1.3
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <[email protected]>
- Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <net/net_namespace.h>
-#include <net/arp.h>
-
-#include "libipw.h"
-
-#define DRV_DESCRIPTION "802.11 data/management/control stack"
-#define DRV_NAME "libipw"
-#define DRV_PROCNAME "ieee80211"
-#define DRV_VERSION LIBIPW_VERSION
-#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <[email protected]>"
-
-MODULE_VERSION(DRV_VERSION);
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-
-static struct cfg80211_ops libipw_config_ops = { };
-static void *libipw_wiphy_privid = &libipw_wiphy_privid;
-
-static int libipw_networks_allocate(struct libipw_device *ieee)
-{
- int i, j;
-
- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
- ieee->networks[i] = kzalloc(sizeof(struct libipw_network),
- GFP_KERNEL);
- if (!ieee->networks[i]) {
- LIBIPW_ERROR("Out of memory allocating beacons\n");
- for (j = 0; j < i; j++)
- kfree(ieee->networks[j]);
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-
-static inline void libipw_networks_free(struct libipw_device *ieee)
-{
- int i;
-
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- kfree(ieee->networks[i]);
-}
-
-void libipw_networks_age(struct libipw_device *ieee,
- unsigned long age_secs)
-{
- struct libipw_network *network = NULL;
- unsigned long flags;
- unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
-
- spin_lock_irqsave(&ieee->lock, flags);
- list_for_each_entry(network, &ieee->network_list, list) {
- network->last_scanned -= age_jiffies;
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-EXPORT_SYMBOL(libipw_networks_age);
-
-static void libipw_networks_initialize(struct libipw_device *ieee)
-{
- int i;
-
- INIT_LIST_HEAD(&ieee->network_free_list);
- INIT_LIST_HEAD(&ieee->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- list_add_tail(&ieee->networks[i]->list,
- &ieee->network_free_list);
-}
-
-struct net_device *alloc_libipw(int sizeof_priv, int monitor)
-{
- struct libipw_device *ieee;
- struct net_device *dev;
- int err;
-
- LIBIPW_DEBUG_INFO("Initializing...\n");
-
- dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
- if (!dev)
- goto failed;
-
- ieee = netdev_priv(dev);
-
- ieee->dev = dev;
-
- if (!monitor) {
- ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
- if (!ieee->wdev.wiphy) {
- LIBIPW_ERROR("Unable to allocate wiphy.\n");
- goto failed_free_netdev;
- }
-
- ieee->dev->ieee80211_ptr = &ieee->wdev;
- ieee->wdev.iftype = NL80211_IFTYPE_STATION;
-
- /* Fill-out wiphy structure bits we know... Not enough info
- here to call set_wiphy_dev or set MAC address or channel info
- -- have to do that in ->ndo_init... */
- ieee->wdev.wiphy->privid = libipw_wiphy_privid;
-
- ieee->wdev.wiphy->max_scan_ssids = 1;
- ieee->wdev.wiphy->max_scan_ie_len = 0;
- ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
- | BIT(NL80211_IFTYPE_ADHOC);
- }
-
- err = libipw_networks_allocate(ieee);
- if (err) {
- LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
- goto failed_free_wiphy;
- }
- libipw_networks_initialize(ieee);
-
- /* Default fragmentation threshold is maximum payload size */
- ieee->fts = DEFAULT_FTS;
- ieee->rts = DEFAULT_FTS;
- ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
- ieee->open_wep = 1;
-
- /* Default to enabling full open WEP with host based encrypt/decrypt */
- ieee->host_encrypt = 1;
- ieee->host_decrypt = 1;
- ieee->host_mc_decrypt = 1;
-
- /* Host fragmentation in Open mode. Default is enabled.
- * Note: host fragmentation is always enabled if host encryption
- * is enabled. For cards can do hardware encryption, they must do
- * hardware fragmentation as well. So we don't need a variable
- * like host_enc_frag. */
- ieee->host_open_frag = 1;
- ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
-
- spin_lock_init(&ieee->lock);
-
- lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
-
- ieee->wpa_enabled = 0;
- ieee->drop_unencrypted = 0;
- ieee->privacy_invoked = 0;
-
- return dev;
-
-failed_free_wiphy:
- if (!monitor)
- wiphy_free(ieee->wdev.wiphy);
-failed_free_netdev:
- free_netdev(dev);
-failed:
- return NULL;
-}
-EXPORT_SYMBOL(alloc_libipw);
-
-void free_libipw(struct net_device *dev, int monitor)
-{
- struct libipw_device *ieee = netdev_priv(dev);
-
- lib80211_crypt_info_free(&ieee->crypt_info);
-
- libipw_networks_free(ieee);
-
- /* free cfg80211 resources */
- if (!monitor)
- wiphy_free(ieee->wdev.wiphy);
-
- free_netdev(dev);
-}
-EXPORT_SYMBOL(free_libipw);
-
-#ifdef CONFIG_LIBIPW_DEBUG
-
-static int debug = 0;
-u32 libipw_debug_level = 0;
-EXPORT_SYMBOL_GPL(libipw_debug_level);
-static struct proc_dir_entry *libipw_proc = NULL;
-
-static int debug_level_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "0x%08X\n", libipw_debug_level);
- return 0;
-}
-
-static int debug_level_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_level_proc_show, NULL);
-}
-
-static ssize_t debug_level_proc_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *pos)
-{
- char buf[] = "0x00000000\n";
- size_t len = min(sizeof(buf) - 1, count);
- unsigned long val;
-
- if (copy_from_user(buf, buffer, len))
- return count;
- buf[len] = 0;
- if (sscanf(buf, "%li", &val) != 1)
- printk(KERN_INFO DRV_NAME
- ": %s is not in hex or decimal form.\n", buf);
- else
- libipw_debug_level = val;
-
- return strnlen(buf, len);
-}
-
-static const struct proc_ops debug_level_proc_ops = {
- .proc_open = debug_level_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = single_release,
- .proc_write = debug_level_proc_write,
-};
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-static int __init libipw_init(void)
-{
-#ifdef CONFIG_LIBIPW_DEBUG
- struct proc_dir_entry *e;
-
- libipw_debug_level = debug;
- libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
- if (libipw_proc == NULL) {
- LIBIPW_ERROR("Unable to create " DRV_PROCNAME
- " proc directory\n");
- return -EIO;
- }
- e = proc_create("debug_level", 0644, libipw_proc,
- &debug_level_proc_ops);
- if (!e) {
- remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
- libipw_proc = NULL;
- return -EIO;
- }
-#endif /* CONFIG_LIBIPW_DEBUG */
-
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-
- return 0;
-}
-
-static void __exit libipw_exit(void)
-{
-#ifdef CONFIG_LIBIPW_DEBUG
- if (libipw_proc) {
- remove_proc_entry("debug_level", libipw_proc);
- remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
- libipw_proc = NULL;
- }
-#endif /* CONFIG_LIBIPW_DEBUG */
-}
-
-#ifdef CONFIG_LIBIPW_DEBUG
-#include <linux/moduleparam.h>
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-module_exit(libipw_exit);
-module_init(libipw_init);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
deleted file mode 100644
index 48d6870bbf4e2..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
+++ /dev/null
@@ -1,1737 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Original code based Host AP (software wireless LAN access point) driver
- * for Intersil Prism2/2.5/3 - hostap.o module, common routines
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <[email protected]>
- * Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
- * Copyright (c) 2004-2005, Intel Corporation
- */
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/gfp.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <linux/ctype.h>
-
-#include <net/lib80211.h>
-
-#include "libipw.h"
-
-static void libipw_monitor_rx(struct libipw_device *ieee,
- struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
-
- skb->dev = ieee->dev;
- skb_reset_mac_header(skb);
- skb_pull(skb, libipw_get_hdrlen(fc));
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_80211_RAW);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-}
-
-/* Called only as a tasklet (software IRQ) */
-static struct libipw_frag_entry *libipw_frag_cache_find(struct
- libipw_device
- *ieee,
- unsigned int seq,
- unsigned int frag,
- u8 * src,
- u8 * dst)
-{
- struct libipw_frag_entry *entry;
- int i;
-
- for (i = 0; i < LIBIPW_FRAG_CACHE_LEN; i++) {
- entry = &ieee->frag_cache[i];
- if (entry->skb != NULL &&
- time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
- LIBIPW_DEBUG_FRAG("expiring fragment cache entry "
- "seq=%u last_frag=%u\n",
- entry->seq, entry->last_frag);
- dev_kfree_skb_any(entry->skb);
- entry->skb = NULL;
- }
-
- if (entry->skb != NULL && entry->seq == seq &&
- (entry->last_frag + 1 == frag || frag == -1) &&
- ether_addr_equal(entry->src_addr, src) &&
- ether_addr_equal(entry->dst_addr, dst))
- return entry;
- }
-
- return NULL;
-}
-
-/* Called only as a tasklet (software IRQ) */
-static struct sk_buff *libipw_frag_cache_get(struct libipw_device *ieee,
- struct libipw_hdr_4addr *hdr)
-{
- struct sk_buff *skb = NULL;
- u16 sc;
- unsigned int frag, seq;
- struct libipw_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctl);
- frag = WLAN_GET_SEQ_FRAG(sc);
- seq = WLAN_GET_SEQ_SEQ(sc);
-
- if (frag == 0) {
- /* Reserve enough space to fit maximum frame length */
- skb = dev_alloc_skb(ieee->dev->mtu +
- sizeof(struct libipw_hdr_4addr) +
- 8 /* LLC */ +
- 2 /* alignment */ +
- 8 /* WEP */ + ETH_ALEN /* WDS */ );
- if (skb == NULL)
- return NULL;
-
- entry = &ieee->frag_cache[ieee->frag_next_idx];
- ieee->frag_next_idx++;
- if (ieee->frag_next_idx >= LIBIPW_FRAG_CACHE_LEN)
- ieee->frag_next_idx = 0;
-
- if (entry->skb != NULL)
- dev_kfree_skb_any(entry->skb);
-
- entry->first_frag_time = jiffies;
- entry->seq = seq;
- entry->last_frag = frag;
- entry->skb = skb;
- memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
- } else {
- /* received a fragment of a frame for which the head fragment
- * should have already been received */
- entry = libipw_frag_cache_find(ieee, seq, frag, hdr->addr2,
- hdr->addr1);
- if (entry != NULL) {
- entry->last_frag = frag;
- skb = entry->skb;
- }
- }
-
- return skb;
-}
-
-/* Called only as a tasklet (software IRQ) */
-static int libipw_frag_cache_invalidate(struct libipw_device *ieee,
- struct libipw_hdr_4addr *hdr)
-{
- u16 sc;
- unsigned int seq;
- struct libipw_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctl);
- seq = WLAN_GET_SEQ_SEQ(sc);
-
- entry = libipw_frag_cache_find(ieee, seq, -1, hdr->addr2,
- hdr->addr1);
-
- if (entry == NULL) {
- LIBIPW_DEBUG_FRAG("could not invalidate fragment cache "
- "entry (seq=%u)\n", seq);
- return -1;
- }
-
- entry->skb = NULL;
- return 0;
-}
-
-#ifdef NOT_YET
-/* libipw_rx_frame_mgtmt
- *
- * Responsible for handling management control frames
- *
- * Called by libipw_rx */
-static int
-libipw_rx_frame_mgmt(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats, u16 type,
- u16 stype)
-{
- if (ieee->iw_mode == IW_MODE_MASTER) {
- printk(KERN_DEBUG "%s: Master mode not yet supported.\n",
- ieee->dev->name);
- return 0;
-/*
- hostap_update_sta_ps(ieee, (struct hostap_libipw_hdr_4addr *)
- skb->data);*/
- }
-
- if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {
- if (stype == WLAN_FC_STYPE_BEACON &&
- ieee->iw_mode == IW_MODE_MASTER) {
- struct sk_buff *skb2;
- /* Process beacon frames also in kernel driver to
- * update STA(AP) table statistics */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2)
- hostap_rx(skb2->dev, skb2, rx_stats);
- }
-
- /* send management frames to the user space daemon for
- * processing */
- ieee->apdevstats.rx_packets++;
- ieee->apdevstats.rx_bytes += skb->len;
- prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
- return 0;
- }
-
- if (ieee->iw_mode == IW_MODE_MASTER) {
- if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
- printk(KERN_DEBUG "%s: unknown management frame "
- "(type=0x%02x, stype=0x%02x) dropped\n",
- skb->dev->name, type, stype);
- return -1;
- }
-
- hostap_rx(skb->dev, skb, rx_stats);
- return 0;
- }
-
- printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
- "received in non-Host AP mode\n", skb->dev->name);
- return -1;
-}
-#endif
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char libipw_rfc1042_header[] =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char libipw_bridge_tunnel_header[] =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-/* Called by libipw_rx_frame_decrypt */
-static int libipw_is_eapol_frame(struct libipw_device *ieee,
- struct sk_buff *skb)
-{
- struct net_device *dev = ieee->dev;
- u16 fc, ethertype;
- struct libipw_hdr_3addr *hdr;
- u8 *pos;
-
- if (skb->len < 24)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
-
- /* check that the frame is unicast frame to us */
- if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr) &&
- ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- /* ToDS frame with own addr BSSID and DA */
- } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- /* FromDS frame with own addr as DA */
- } else
- return 0;
-
- if (skb->len < 24 + 8)
- return 0;
-
- /* check for port access entity Ethernet type */
- pos = skb->data + 24;
- ethertype = (pos[6] << 8) | pos[7];
- if (ethertype == ETH_P_PAE)
- return 1;
-
- return 0;
-}
-
-/* Called only as a tasklet (software IRQ), by libipw_rx */
-static int
-libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct libipw_hdr_3addr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- LIBIPW_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
- hdr->addr2, res);
- if (res == -2)
- LIBIPW_DEBUG_DROP("Decryption failed ICV "
- "mismatch (key %d)\n",
- skb->data[hdrlen + 3] >> 6);
- ieee->ieee_stats.rx_discards_undecryptable++;
- return -1;
- }
-
- return res;
-}
-
-/* Called only as a tasklet (software IRQ), by libipw_rx */
-static int
-libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee,
- struct sk_buff *skb, int keyidx,
- struct lib80211_crypt_data *crypt)
-{
- struct libipw_hdr_3addr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2,
- keyidx);
- return -1;
- }
-
- return 0;
-}
-
-/* All received frames are sent to this function. @skb contains the frame in
- * IEEE 802.11 format, i.e., in the format it was sent over air.
- * This function is called only as a tasklet (software IRQ). */
-int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats)
-{
- struct net_device *dev = ieee->dev;
- struct libipw_hdr_4addr *hdr;
- size_t hdrlen;
- u16 fc, type, stype, sc;
- unsigned int frag;
- u8 *payload;
- u16 ethertype;
-#ifdef NOT_YET
- struct net_device *wds = NULL;
- struct sk_buff *skb2 = NULL;
- struct net_device *wds = NULL;
- int frame_authorized = 0;
- int from_assoc_ap = 0;
- void *sta = NULL;
-#endif
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
- struct lib80211_crypt_data *crypt = NULL;
- int keyidx = 0;
- int can_be_decrypted = 0;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- if (skb->len < 10) {
- printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
- goto rx_dropped;
- }
-
- fc = le16_to_cpu(hdr->frame_ctl);
- type = WLAN_FC_GET_TYPE(fc);
- stype = WLAN_FC_GET_STYPE(fc);
- sc = le16_to_cpu(hdr->seq_ctl);
- frag = WLAN_GET_SEQ_FRAG(sc);
- hdrlen = libipw_get_hdrlen(fc);
-
- if (skb->len < hdrlen) {
- printk(KERN_INFO "%s: invalid SKB length %d\n",
- dev->name, skb->len);
- goto rx_dropped;
- }
-
- /* Put this code here so that we avoid duplicating it in all
- * Rx paths. - Jean II */
-#ifdef CONFIG_WIRELESS_EXT
-#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
- /* If spy monitoring on */
- if (ieee->spy_data.spy_number > 0) {
- struct iw_quality wstats;
-
- wstats.updated = 0;
- if (rx_stats->mask & LIBIPW_STATMASK_RSSI) {
- wstats.level = rx_stats->signal;
- wstats.updated |= IW_QUAL_LEVEL_UPDATED;
- } else
- wstats.updated |= IW_QUAL_LEVEL_INVALID;
-
- if (rx_stats->mask & LIBIPW_STATMASK_NOISE) {
- wstats.noise = rx_stats->noise;
- wstats.updated |= IW_QUAL_NOISE_UPDATED;
- } else
- wstats.updated |= IW_QUAL_NOISE_INVALID;
-
- if (rx_stats->mask & LIBIPW_STATMASK_SIGNAL) {
- wstats.qual = rx_stats->signal;
- wstats.updated |= IW_QUAL_QUAL_UPDATED;
- } else
- wstats.updated |= IW_QUAL_QUAL_INVALID;
-
- /* Update spy records */
- wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
- }
-#endif /* IW_WIRELESS_SPY */
-#endif /* CONFIG_WIRELESS_EXT */
-
-#ifdef NOT_YET
- hostap_update_rx_stats(local->ap, hdr, rx_stats);
-#endif
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- libipw_monitor_rx(ieee, skb, rx_stats);
- return 1;
- }
-
- can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
- is_broadcast_ether_addr(hdr->addr2)) ?
- ieee->host_mc_decrypt : ieee->host_decrypt;
-
- if (can_be_decrypted) {
- if (skb->len >= hdrlen + 3) {
- /* Top two-bits of byte 3 are the key index */
- keyidx = skb->data[hdrlen + 3] >> 6;
- }
-
- /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx
- * is only allowed 2-bits of storage, no value of keyidx can
- * be provided via above code that would result in keyidx
- * being out of range */
- crypt = ieee->crypt_info.crypt[keyidx];
-
-#ifdef NOT_YET
- sta = NULL;
-
- /* Use station specific key to override default keys if the
- * receiver address is a unicast address ("individual RA"). If
- * bcrx_sta_key parameter is set, station specific key is used
- * even with broad/multicast targets (this is against IEEE
- * 802.11, but makes it easier to use different keys with
- * stations that do not support WEP key mapping). */
-
- if (is_unicast_ether_addr(hdr->addr1) || local->bcrx_sta_key)
- (void)hostap_handle_sta_crypto(local, hdr, &crypt,
- &sta);
-#endif
-
- /* allow NULL decrypt to indicate an station specific override
- * for default encryption */
- if (crypt && (crypt->ops == NULL ||
- crypt->ops->decrypt_mpdu == NULL))
- crypt = NULL;
-
- if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
- /* This seems to be triggered by some (multicast?)
- * frames from other than current BSS, so just drop the
- * frames silently instead of filling system log with
- * these reports. */
- LIBIPW_DEBUG_DROP("Decryption failed (not set)"
- " (SA=%pM)\n", hdr->addr2);
- ieee->ieee_stats.rx_discards_undecryptable++;
- goto rx_dropped;
- }
- }
-#ifdef NOT_YET
- if (type != WLAN_FC_TYPE_DATA) {
- if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
- fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
- (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
- printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from %pM\n", dev->name, hdr->addr2);
- /* TODO: could inform hostapd about this so that it
- * could send auth failure report */
- goto rx_dropped;
- }
-
- if (libipw_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
- goto rx_dropped;
- else
- goto rx_exit;
- }
-#endif
- /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */
- if (sc == ieee->prev_seq_ctl)
- goto rx_dropped;
- else
- ieee->prev_seq_ctl = sc;
-
- /* Data frame - extract src/dst addresses */
- if (skb->len < LIBIPW_3ADDR_LEN)
- goto rx_dropped;
-
- switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_FROMDS:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr3, ETH_ALEN);
- break;
- case IEEE80211_FCTL_TODS:
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- if (skb->len < LIBIPW_4ADDR_LEN)
- goto rx_dropped;
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr4, ETH_ALEN);
- break;
- default:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- }
-
-#ifdef NOT_YET
- if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
- goto rx_dropped;
- if (wds) {
- skb->dev = dev = wds;
- stats = hostap_get_stats(dev);
- }
-
- if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
- (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS && ieee->stadev &&
- ether_addr_equal(hdr->addr2, ieee->assoc_ap_addr)) {
- /* Frame from BSSID of the AP for which we are a client */
- skb->dev = dev = ieee->stadev;
- stats = hostap_get_stats(dev);
- from_assoc_ap = 1;
- }
-#endif
-
-#ifdef NOT_YET
- if ((ieee->iw_mode == IW_MODE_MASTER ||
- ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
- switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
- wds != NULL)) {
- case AP_RX_CONTINUE_NOT_AUTHORIZED:
- frame_authorized = 0;
- break;
- case AP_RX_CONTINUE:
- frame_authorized = 1;
- break;
- case AP_RX_DROP:
- goto rx_dropped;
- case AP_RX_EXIT:
- goto rx_exit;
- }
- }
-#endif
-
- /* Nullfunc frames may have PS-bit set, so they must be passed to
- * hostap_handle_sta_rx() before being dropped here. */
-
- stype &= ~IEEE80211_STYPE_QOS_DATA;
-
- if (stype != IEEE80211_STYPE_DATA &&
- stype != IEEE80211_STYPE_DATA_CFACK &&
- stype != IEEE80211_STYPE_DATA_CFPOLL &&
- stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
- if (stype != IEEE80211_STYPE_NULLFUNC)
- LIBIPW_DEBUG_DROP("RX: dropped data frame "
- "with no data (type=0x%02x, "
- "subtype=0x%02x, len=%d)\n",
- type, stype, skb->len);
- goto rx_dropped;
- }
-
- /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
-
- if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- (keyidx = libipw_rx_frame_decrypt(ieee, skb, crypt)) < 0)
- goto rx_dropped;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
-
- /* skb: hdr + (possibly fragmented) plaintext payload */
- // PR: FIXME: hostap has additional conditions in the "if" below:
- // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
- int flen;
- struct sk_buff *frag_skb = libipw_frag_cache_get(ieee, hdr);
- LIBIPW_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
-
- if (!frag_skb) {
- LIBIPW_DEBUG(LIBIPW_DL_RX | LIBIPW_DL_FRAG,
- "Rx cannot get skb from fragment "
- "cache (morefrag=%d seq=%u frag=%u)\n",
- (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
- WLAN_GET_SEQ_SEQ(sc), frag);
- goto rx_dropped;
- }
-
- flen = skb->len;
- if (frag != 0)
- flen -= hdrlen;
-
- if (frag_skb->tail + flen > frag_skb->end) {
- printk(KERN_WARNING "%s: host decrypted and "
- "reassembled frame did not fit skb\n",
- dev->name);
- libipw_frag_cache_invalidate(ieee, hdr);
- goto rx_dropped;
- }
-
- if (frag == 0) {
- /* copy first fragment (including full headers) into
- * beginning of the fragment cache skb */
- skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
- } else {
- /* append frame payload to the end of the fragment
- * cache skb */
- skb_copy_from_linear_data_offset(skb, hdrlen,
- skb_put(frag_skb, flen), flen);
- }
- dev_kfree_skb_any(skb);
- skb = NULL;
-
- if (fc & IEEE80211_FCTL_MOREFRAGS) {
- /* more fragments expected - leave the skb in fragment
- * cache for now; it will be delivered to upper layers
- * after all fragments have been received */
- goto rx_exit;
- }
-
- /* this was the last fragment and the frame will be
- * delivered, so remove skb from fragment cache */
- skb = frag_skb;
- hdr = (struct libipw_hdr_4addr *)skb->data;
- libipw_frag_cache_invalidate(ieee, hdr);
- }
-
- /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
- * encrypted/authenticated */
- if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- libipw_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
- goto rx_dropped;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
- if ( /*ieee->ieee802_1x && */
- libipw_is_eapol_frame(ieee, skb)) {
- /* pass unencrypted EAPOL frames even if encryption is
- * configured */
- } else {
- LIBIPW_DEBUG_DROP("encryption configured, but RX "
- "frame not encrypted (SA=%pM)\n",
- hdr->addr2);
- goto rx_dropped;
- }
- }
-
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
- !libipw_is_eapol_frame(ieee, skb)) {
- LIBIPW_DEBUG_DROP("dropped unencrypted RX data "
- "frame from %pM (drop_unencrypted=1)\n",
- hdr->addr2);
- goto rx_dropped;
- }
-
- /* If the frame was decrypted in hardware, we may need to strip off
- * any security data (IV, ICV, etc) that was left behind */
- if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
- ieee->host_strip_iv_icv) {
- int trimlen = 0;
-
- /* Top two-bits of byte 3 are the key index */
- if (skb->len >= hdrlen + 3)
- keyidx = skb->data[hdrlen + 3] >> 6;
-
- /* To strip off any security data which appears before the
- * payload, we simply increase hdrlen (as the header gets
- * chopped off immediately below). For the security data which
- * appears after the payload, we use skb_trim. */
-
- switch (ieee->sec.encode_alg[keyidx]) {
- case SEC_ALG_WEP:
- /* 4 byte IV */
- hdrlen += 4;
- /* 4 byte ICV */
- trimlen = 4;
- break;
- case SEC_ALG_TKIP:
- /* 4 byte IV, 4 byte ExtIV */
- hdrlen += 8;
- /* 8 byte MIC, 4 byte ICV */
- trimlen = 12;
- break;
- case SEC_ALG_CCMP:
- /* 8 byte CCMP header */
- hdrlen += 8;
- /* 8 byte MIC */
- trimlen = 8;
- break;
- }
-
- if (skb->len < trimlen)
- goto rx_dropped;
-
- __skb_trim(skb, skb->len - trimlen);
-
- if (skb->len < hdrlen)
- goto rx_dropped;
- }
-
- /* skb: hdr + (possible reassembled) full plaintext payload */
-
- payload = skb->data + hdrlen;
- ethertype = (payload[6] << 8) | payload[7];
-
-#ifdef NOT_YET
- /* If IEEE 802.1X is used, check whether the port is authorized to send
- * the received frame. */
- if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
- if (ethertype == ETH_P_PAE) {
- printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
- dev->name);
- if (ieee->hostapd && ieee->apdev) {
- /* Send IEEE 802.1X frames to the user
- * space daemon for processing */
- prism2_rx_80211(ieee->apdev, skb, rx_stats,
- PRISM2_RX_MGMT);
- ieee->apdevstats.rx_packets++;
- ieee->apdevstats.rx_bytes += skb->len;
- goto rx_exit;
- }
- } else if (!frame_authorized) {
- printk(KERN_DEBUG "%s: dropped frame from "
- "unauthorized port (IEEE 802.1X): "
- "ethertype=0x%04x\n", dev->name, ethertype);
- goto rx_dropped;
- }
- }
-#endif
-
- /* convert hdr + possible LLC headers into Ethernet header */
- if (skb->len - hdrlen >= 8 &&
- ((memcmp(payload, libipw_rfc1042_header, SNAP_SIZE) == 0 &&
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- memcmp(payload, libipw_bridge_tunnel_header, SNAP_SIZE) == 0)) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation and
- * replace EtherType */
- skb_pull(skb, hdrlen + SNAP_SIZE);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- } else {
- __be16 len;
- /* Leave Ethernet header part of hdr and full payload */
- skb_pull(skb, hdrlen);
- len = htons(skb->len);
- memcpy(skb_push(skb, 2), &len, 2);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- }
-
-#ifdef NOT_YET
- if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
- /* Non-standard frame: get addr4 from its bogus location after
- * the payload */
- skb_copy_to_linear_data_offset(skb, ETH_ALEN,
- skb->data + skb->len - ETH_ALEN,
- ETH_ALEN);
- skb_trim(skb, skb->len - ETH_ALEN);
- }
-#endif
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
-
-#ifdef NOT_YET
- if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
- if (is_multicast_ether_addr(dst)) {
- /* copy multicast frame both to the higher layers and
- * to the wireless media */
- ieee->ap->bridged_multicast++;
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- printk(KERN_DEBUG "%s: skb_clone failed for "
- "multicast frame\n", dev->name);
- } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
- /* send frame directly to the associated STA using
- * wireless media and not passing to higher layers */
- ieee->ap->bridged_unicast++;
- skb2 = skb;
- skb = NULL;
- }
- }
-
- if (skb2 != NULL) {
- /* send to wireless media */
- skb2->dev = dev;
- skb2->protocol = htons(ETH_P_802_3);
- skb_reset_mac_header(skb2);
- skb_reset_network_header(skb2);
- /* skb2->network_header += ETH_HLEN; */
- dev_queue_xmit(skb2);
- }
-#endif
-
- if (skb) {
- skb->protocol = eth_type_trans(skb, dev);
- memset(skb->cb, 0, sizeof(skb->cb));
- skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
- if (netif_rx(skb) == NET_RX_DROP) {
- /* netif_rx always succeeds, but it might drop
- * the packet. If it drops the packet, we log that
- * in our stats. */
- LIBIPW_DEBUG_DROP
- ("RX: netif_rx dropped the packet\n");
- dev->stats.rx_dropped++;
- }
- }
-
- rx_exit:
-#ifdef NOT_YET
- if (sta)
- hostap_handle_sta_release(sta);
-#endif
- return 1;
-
- rx_dropped:
- dev->stats.rx_dropped++;
-
- /* Returning 0 indicates to caller that we have not handled the SKB--
- * so it is still allocated and can be used again by underlying
- * hardware as a DMA target */
- return 0;
-}
-
-/* Filter out unrelated packets, call libipw_rx[_mgt]
- * This function takes over the skb, it should not be used again after calling
- * this function. */
-void libipw_rx_any(struct libipw_device *ieee,
- struct sk_buff *skb, struct libipw_rx_stats *stats)
-{
- struct libipw_hdr_4addr *hdr;
- int is_packet_for_us;
- u16 fc;
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- if (!libipw_rx(ieee, skb, stats))
- dev_kfree_skb_irq(skb);
- return;
- }
-
- if (skb->len < sizeof(struct ieee80211_hdr))
- goto drop_free;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
-
- if ((fc & IEEE80211_FCTL_VERS) != 0)
- goto drop_free;
-
- switch (fc & IEEE80211_FCTL_FTYPE) {
- case IEEE80211_FTYPE_MGMT:
- if (skb->len < sizeof(struct libipw_hdr_3addr))
- goto drop_free;
- libipw_rx_mgt(ieee, hdr, stats);
- dev_kfree_skb_irq(skb);
- return;
- case IEEE80211_FTYPE_DATA:
- break;
- case IEEE80211_FTYPE_CTL:
- return;
- default:
- return;
- }
-
- is_packet_for_us = 0;
- switch (ieee->iw_mode) {
- case IW_MODE_ADHOC:
- /* our BSS and not from/to DS */
- if (ether_addr_equal(hdr->addr3, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
- /* promisc: get all */
- if (ieee->dev->flags & IFF_PROMISC)
- is_packet_for_us = 1;
- /* to us */
- else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- /* mcast */
- else if (is_multicast_ether_addr(hdr->addr1))
- is_packet_for_us = 1;
- }
- break;
- case IW_MODE_INFRA:
- /* our BSS (== from our AP) and from DS */
- if (ether_addr_equal(hdr->addr2, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
- /* promisc: get all */
- if (ieee->dev->flags & IFF_PROMISC)
- is_packet_for_us = 1;
- /* to us */
- else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- /* mcast */
- else if (is_multicast_ether_addr(hdr->addr1)) {
- /* not our own packet bcasted from AP */
- if (!ether_addr_equal(hdr->addr3, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- }
- }
- break;
- default:
- /* ? */
- break;
- }
-
- if (is_packet_for_us)
- if (!libipw_rx(ieee, skb, stats))
- dev_kfree_skb_irq(skb);
- return;
-
-drop_free:
- dev_kfree_skb_irq(skb);
- ieee->dev->stats.rx_dropped++;
-}
-
-#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
-
-static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
-
-/*
-* Make the structure we read from the beacon packet to have
-* the right values
-*/
-static int libipw_verify_qos_info(struct libipw_qos_information_element
- *info_element, int sub_type)
-{
- if (info_element->elementID != QOS_ELEMENT_ID)
- return -1;
- if (info_element->qui_subtype != sub_type)
- return -1;
- if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
- return -1;
- if (info_element->qui_type != QOS_OUI_TYPE)
- return -1;
- if (info_element->version != QOS_VERSION_1)
- return -1;
-
- return 0;
-}
-
-/*
- * Parse a QoS parameter element
- */
-static int libipw_read_qos_param_element(
- struct libipw_qos_parameter_info *element_param,
- struct libipw_info_element *info_element)
-{
- size_t size = sizeof(*element_param);
-
- if (!element_param || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_param, info_element, size);
- return libipw_verify_qos_info(&element_param->info_element,
- QOS_OUI_PARAM_SUB_TYPE);
-}
-
-/*
- * Parse a QoS information element
- */
-static int libipw_read_qos_info_element(
- struct libipw_qos_information_element *element_info,
- struct libipw_info_element *info_element)
-{
- size_t size = sizeof(struct libipw_qos_information_element) - 2;
-
- if (!element_info || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_info, info_element, size);
- return libipw_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE);
-}
-
-/*
- * Write QoS parameters from the ac parameters.
- */
-static void libipw_qos_convert_ac_to_parameters(struct
- libipw_qos_parameter_info
- *param_elm, struct
- libipw_qos_parameters
- *qos_param)
-{
- int i;
- struct libipw_qos_ac_parameter *ac_params;
- u32 txop;
- u8 cw_min;
- u8 cw_max;
-
- for (i = 0; i < QOS_QUEUE_NUM; i++) {
- ac_params = &(param_elm->ac_params_record[i]);
-
- qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F;
- qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2;
-
- cw_min = ac_params->ecw_min_max & 0x0F;
- qos_param->cw_min[i] = cpu_to_le16((1 << cw_min) - 1);
-
- cw_max = (ac_params->ecw_min_max & 0xF0) >> 4;
- qos_param->cw_max[i] = cpu_to_le16((1 << cw_max) - 1);
-
- qos_param->flag[i] =
- (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
-
- txop = le16_to_cpu(ac_params->tx_op_limit) * 32;
- qos_param->tx_op_limit[i] = cpu_to_le16(txop);
- }
-}
-
-/*
- * we have a generic data element which it may contain QoS information or
- * parameters element. check the information element length to decide
- * which type to read
- */
-static int libipw_parse_qos_info_param_IE(struct libipw_info_element
- *info_element,
- struct libipw_network *network)
-{
- int rc = 0;
- struct libipw_qos_parameters *qos_param = NULL;
- struct libipw_qos_information_element qos_info_element;
-
- rc = libipw_read_qos_info_element(&qos_info_element, info_element);
-
- if (rc == 0) {
- network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
- network->flags |= NETWORK_HAS_QOS_INFORMATION;
- } else {
- struct libipw_qos_parameter_info param_element;
-
- rc = libipw_read_qos_param_element(&param_element,
- info_element);
- if (rc == 0) {
- qos_param = &(network->qos_data.parameters);
- libipw_qos_convert_ac_to_parameters(&param_element,
- qos_param);
- network->flags |= NETWORK_HAS_QOS_PARAMETERS;
- network->qos_data.param_count =
- param_element.info_element.ac_info & 0x0F;
- }
- }
-
- if (rc == 0) {
- LIBIPW_DEBUG_QOS("QoS is supported\n");
- network->qos_data.supported = 1;
- }
- return rc;
-}
-
-#ifdef CONFIG_LIBIPW_DEBUG
-#define MFIE_STRING(x) case WLAN_EID_ ##x: return #x
-
-static const char *get_info_element_string(u16 id)
-{
- switch (id) {
- MFIE_STRING(SSID);
- MFIE_STRING(SUPP_RATES);
- MFIE_STRING(FH_PARAMS);
- MFIE_STRING(DS_PARAMS);
- MFIE_STRING(CF_PARAMS);
- MFIE_STRING(TIM);
- MFIE_STRING(IBSS_PARAMS);
- MFIE_STRING(COUNTRY);
- MFIE_STRING(REQUEST);
- MFIE_STRING(CHALLENGE);
- MFIE_STRING(PWR_CONSTRAINT);
- MFIE_STRING(PWR_CAPABILITY);
- MFIE_STRING(TPC_REQUEST);
- MFIE_STRING(TPC_REPORT);
- MFIE_STRING(SUPPORTED_CHANNELS);
- MFIE_STRING(CHANNEL_SWITCH);
- MFIE_STRING(MEASURE_REQUEST);
- MFIE_STRING(MEASURE_REPORT);
- MFIE_STRING(QUIET);
- MFIE_STRING(IBSS_DFS);
- MFIE_STRING(ERP_INFO);
- MFIE_STRING(RSN);
- MFIE_STRING(EXT_SUPP_RATES);
- MFIE_STRING(VENDOR_SPECIFIC);
- MFIE_STRING(QOS_PARAMETER);
- default:
- return "UNKNOWN";
- }
-}
-#endif
-
-static int libipw_parse_info_param(struct libipw_info_element
- *info_element, u16 length,
- struct libipw_network *network)
-{
- u8 i;
-#ifdef CONFIG_LIBIPW_DEBUG
- char rates_str[64];
- char *p;
-#endif
-
- while (length >= sizeof(*info_element)) {
- if (sizeof(*info_element) + info_element->len > length) {
- LIBIPW_DEBUG_MGMT("Info elem: parse failed: "
- "info_element->len + 2 > left : "
- "info_element->len+2=%zd left=%d, id=%d.\n",
- info_element->len +
- sizeof(*info_element),
- length, info_element->id);
- /* We stop processing but don't return an error here
- * because some misbehaviour APs break this rule. ie.
- * Orinoco AP1000. */
- break;
- }
-
- switch (info_element->id) {
- case WLAN_EID_SSID:
- network->ssid_len = min(info_element->len,
- (u8) IW_ESSID_MAX_SIZE);
- memcpy(network->ssid, info_element->data,
- network->ssid_len);
- if (network->ssid_len < IW_ESSID_MAX_SIZE)
- memset(network->ssid + network->ssid_len, 0,
- IW_ESSID_MAX_SIZE - network->ssid_len);
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%*pE' len=%d.\n",
- network->ssid_len, network->ssid,
- network->ssid_len);
- break;
-
- case WLAN_EID_SUPP_RATES:
-#ifdef CONFIG_LIBIPW_DEBUG
- p = rates_str;
-#endif
- network->rates_len = min(info_element->len,
- MAX_RATES_LENGTH);
- for (i = 0; i < network->rates_len; i++) {
- network->rates[i] = info_element->data[i];
-#ifdef CONFIG_LIBIPW_DEBUG
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates[i]);
-#endif
- if (libipw_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- LIBIPW_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
- }
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n",
- rates_str, network->rates_len);
- break;
-
- case WLAN_EID_EXT_SUPP_RATES:
-#ifdef CONFIG_LIBIPW_DEBUG
- p = rates_str;
-#endif
- network->rates_ex_len = min(info_element->len,
- MAX_RATES_EX_LENGTH);
- for (i = 0; i < network->rates_ex_len; i++) {
- network->rates_ex[i] = info_element->data[i];
-#ifdef CONFIG_LIBIPW_DEBUG
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates_ex[i]);
-#endif
- if (libipw_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- LIBIPW_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
- }
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n",
- rates_str, network->rates_ex_len);
- break;
-
- case WLAN_EID_DS_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n",
- info_element->data[0]);
- network->channel = info_element->data[0];
- break;
-
- case WLAN_EID_FH_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n");
- break;
-
- case WLAN_EID_CF_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n");
- break;
-
- case WLAN_EID_TIM:
- network->tim.tim_count = info_element->data[0];
- network->tim.tim_period = info_element->data[1];
- LIBIPW_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n");
- break;
-
- case WLAN_EID_ERP_INFO:
- network->erp_value = info_element->data[0];
- network->flags |= NETWORK_HAS_ERP_VALUE;
- LIBIPW_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
- network->erp_value);
- break;
-
- case WLAN_EID_IBSS_PARAMS:
- network->atim_window = info_element->data[0];
- LIBIPW_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n",
- network->atim_window);
- break;
-
- case WLAN_EID_CHALLENGE:
- LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
- break;
-
- case WLAN_EID_VENDOR_SPECIFIC:
- LIBIPW_DEBUG_MGMT("WLAN_EID_VENDOR_SPECIFIC: %d bytes\n",
- info_element->len);
- if (!libipw_parse_qos_info_param_IE(info_element,
- network))
- break;
-
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x50 &&
- info_element->data[2] == 0xf2 &&
- info_element->data[3] == 0x01) {
- network->wpa_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->wpa_ie, info_element,
- network->wpa_ie_len);
- }
- break;
-
- case WLAN_EID_RSN:
- LIBIPW_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n",
- info_element->len);
- network->rsn_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->rsn_ie, info_element,
- network->rsn_ie_len);
- break;
-
- case WLAN_EID_QOS_PARAMETER:
- printk(KERN_ERR
- "QoS Error need to parse QOS_PARAMETER IE\n");
- break;
- /* 802.11h */
- case WLAN_EID_PWR_CONSTRAINT:
- network->power_constraint = info_element->data[0];
- network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
- break;
-
- case WLAN_EID_CHANNEL_SWITCH:
- network->power_constraint = info_element->data[0];
- network->flags |= NETWORK_HAS_CSA;
- break;
-
- case WLAN_EID_QUIET:
- network->quiet.count = info_element->data[0];
- network->quiet.period = info_element->data[1];
- network->quiet.duration = info_element->data[2];
- network->quiet.offset = info_element->data[3];
- network->flags |= NETWORK_HAS_QUIET;
- break;
-
- case WLAN_EID_IBSS_DFS:
- network->flags |= NETWORK_HAS_IBSS_DFS;
- break;
-
- case WLAN_EID_TPC_REPORT:
- network->tpc_report.transmit_power =
- info_element->data[0];
- network->tpc_report.link_margin = info_element->data[1];
- network->flags |= NETWORK_HAS_TPC_REPORT;
- break;
-
- default:
- LIBIPW_DEBUG_MGMT
- ("Unsupported info element: %s (%d)\n",
- get_info_element_string(info_element->id),
- info_element->id);
- break;
- }
-
- length -= sizeof(*info_element) + info_element->len;
- info_element =
- (struct libipw_info_element *)&info_element->
- data[info_element->len];
- }
-
- return 0;
-}
-
-static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response
- *frame, struct libipw_rx_stats *stats)
-{
- struct libipw_network network_resp = { };
- struct libipw_network *network = &network_resp;
- struct net_device *dev = ieee->dev;
-
- network->flags = 0;
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- network->qos_data.param_count = 0;
- network->qos_data.old_param_count = 0;
-
- //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
- network->atim_window = le16_to_cpu(frame->aid);
- network->listen_interval = le16_to_cpu(frame->status);
- memcpy(network->bssid, frame->header.addr3, ETH_ALEN);
- network->capability = le16_to_cpu(frame->capability);
- network->last_scanned = jiffies;
- network->rates_len = network->rates_ex_len = 0;
- network->last_associate = 0;
- network->ssid_len = 0;
- network->erp_value =
- (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0;
-
- if (stats->freq == LIBIPW_52GHZ_BAND) {
- /* for A band (No DS info) */
- network->channel = stats->received_channel;
- } else
- network->flags |= NETWORK_HAS_CCK;
-
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-
- if (libipw_parse_info_param((void *)frame->variable,
- stats->len - sizeof(*frame), network))
- return 1;
-
- network->mode = 0;
- if (stats->freq == LIBIPW_52GHZ_BAND)
- network->mode = IEEE_A;
- else {
- if (network->flags & NETWORK_HAS_OFDM)
- network->mode |= IEEE_G;
- if (network->flags & NETWORK_HAS_CCK)
- network->mode |= IEEE_B;
- }
-
- memcpy(&network->stats, stats, sizeof(network->stats));
-
- if (ieee->handle_assoc_response != NULL)
- ieee->handle_assoc_response(dev, frame, network);
-
- return 0;
-}
-
-/***************************************************/
-
-static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_response
- *beacon,
- struct libipw_network *network,
- struct libipw_rx_stats *stats)
-{
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- network->qos_data.param_count = 0;
- network->qos_data.old_param_count = 0;
-
- /* Pull out fixed field data */
- memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
- network->capability = le16_to_cpu(beacon->capability);
- network->last_scanned = jiffies;
- network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
- network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
- network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
- /* Where to pull this? beacon->listen_interval; */
- network->listen_interval = 0x0A;
- network->rates_len = network->rates_ex_len = 0;
- network->last_associate = 0;
- network->ssid_len = 0;
- network->flags = 0;
- network->atim_window = 0;
- network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
- 0x3 : 0x0;
-
- if (stats->freq == LIBIPW_52GHZ_BAND) {
- /* for A band (No DS info) */
- network->channel = stats->received_channel;
- } else
- network->flags |= NETWORK_HAS_CCK;
-
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-
- if (libipw_parse_info_param((void *)beacon->variable,
- stats->len - sizeof(*beacon), network))
- return 1;
-
- network->mode = 0;
- if (stats->freq == LIBIPW_52GHZ_BAND)
- network->mode = IEEE_A;
- else {
- if (network->flags & NETWORK_HAS_OFDM)
- network->mode |= IEEE_G;
- if (network->flags & NETWORK_HAS_CCK)
- network->mode |= IEEE_B;
- }
-
- if (network->mode == 0) {
- LIBIPW_DEBUG_SCAN("Filtered out '%*pE (%pM)' network.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 1;
- }
-
- memcpy(&network->stats, stats, sizeof(network->stats));
-
- return 0;
-}
-
-static inline int is_same_network(struct libipw_network *src,
- struct libipw_network *dst)
-{
- /* A network is only a duplicate if the channel, BSSID, and ESSID
- * all match. We treat all <hidden> with the same BSSID and channel
- * as one network */
- return ((src->ssid_len == dst->ssid_len) &&
- (src->channel == dst->channel) &&
- ether_addr_equal_64bits(src->bssid, dst->bssid) &&
- !memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
-static void update_network(struct libipw_network *dst,
- struct libipw_network *src)
-{
- int qos_active;
- u8 old_param;
-
- /* We only update the statistics if they were created by receiving
- * the network information on the actual channel the network is on.
- *
- * This keeps beacons received on neighbor channels from bringing
- * down the signal level of an AP. */
- if (dst->channel == src->stats.received_channel)
- memcpy(&dst->stats, &src->stats,
- sizeof(struct libipw_rx_stats));
- else
- LIBIPW_DEBUG_SCAN("Network %pM info received "
- "off channel (%d vs. %d)\n", src->bssid,
- dst->channel, src->stats.received_channel);
-
- dst->capability = src->capability;
- memcpy(dst->rates, src->rates, src->rates_len);
- dst->rates_len = src->rates_len;
- memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
- dst->rates_ex_len = src->rates_ex_len;
-
- dst->mode = src->mode;
- dst->flags = src->flags;
- dst->time_stamp[0] = src->time_stamp[0];
- dst->time_stamp[1] = src->time_stamp[1];
-
- dst->beacon_interval = src->beacon_interval;
- dst->listen_interval = src->listen_interval;
- dst->atim_window = src->atim_window;
- dst->erp_value = src->erp_value;
- dst->tim = src->tim;
-
- memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
- dst->wpa_ie_len = src->wpa_ie_len;
- memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
- dst->rsn_ie_len = src->rsn_ie_len;
-
- dst->last_scanned = jiffies;
- qos_active = src->qos_data.active;
- old_param = dst->qos_data.old_param_count;
- if (dst->flags & NETWORK_HAS_QOS_MASK)
- memcpy(&dst->qos_data, &src->qos_data,
- sizeof(struct libipw_qos_data));
- else {
- dst->qos_data.supported = src->qos_data.supported;
- dst->qos_data.param_count = src->qos_data.param_count;
- }
-
- if (dst->qos_data.supported == 1) {
- if (dst->ssid_len)
- LIBIPW_DEBUG_QOS
- ("QoS the network %s is QoS supported\n",
- dst->ssid);
- else
- LIBIPW_DEBUG_QOS
- ("QoS the network is QoS supported\n");
- }
- dst->qos_data.active = qos_active;
- dst->qos_data.old_param_count = old_param;
-
- /* dst->last_associate is not overwritten */
-}
-
-static inline int is_beacon(__le16 fc)
-{
- return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
-}
-
-static void libipw_process_probe_response(struct libipw_device
- *ieee, struct
- libipw_probe_response
- *beacon, struct libipw_rx_stats
- *stats)
-{
- struct net_device *dev = ieee->dev;
- struct libipw_network network = { };
- struct libipw_network *target;
- struct libipw_network *oldest = NULL;
-#ifdef CONFIG_LIBIPW_DEBUG
- struct libipw_info_element *info_element = (void *)beacon->variable;
-#endif
- unsigned long flags;
-
- LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
- info_element->len, info_element->data,
- beacon->header.addr3,
- (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xc)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xb)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xa)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x9)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x8)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x7)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x6)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x5)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x4)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x3)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x2)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
-
- if (libipw_network_init(ieee, beacon, &network, stats)) {
- LIBIPW_DEBUG_SCAN("Dropped '%*pE' (%pM) via %s.\n",
- info_element->len, info_element->data,
- beacon->header.addr3,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
- return;
- }
-
- /* The network parsed correctly -- so now we scan our known networks
- * to see if we can find it in our list.
- *
- * NOTE: This search is definitely not optimized. Once its doing
- * the "right thing" we'll optimize it for efficiency if
- * necessary */
-
- /* Search for this entry in the list and update it if it is
- * already there. */
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(target, &ieee->network_list, list) {
- if (is_same_network(target, &network))
- break;
-
- if ((oldest == NULL) ||
- time_before(target->last_scanned, oldest->last_scanned))
- oldest = target;
- }
-
- /* If we didn't find a match, then get a new network slot to initialize
- * with this beacon's information */
- if (&target->list == &ieee->network_list) {
- if (list_empty(&ieee->network_free_list)) {
- /* If there are no more slots, expire the oldest */
- list_del(&oldest->list);
- target = oldest;
- LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
- target->ssid_len, target->ssid,
- target->bssid);
- } else {
- /* Otherwise just pull from the free list */
- target = list_entry(ieee->network_free_list.next,
- struct libipw_network, list);
- list_del(ieee->network_free_list.next);
- }
-
-#ifdef CONFIG_LIBIPW_DEBUG
- LIBIPW_DEBUG_SCAN("Adding '%*pE' (%pM) via %s.\n",
- network.ssid_len, network.ssid,
- network.bssid,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
-#endif
- memcpy(target, &network, sizeof(*target));
- list_add_tail(&target->list, &ieee->network_list);
- } else {
- LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
- target->ssid_len, target->ssid,
- target->bssid,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
- update_network(target, &network);
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- if (is_beacon(beacon->header.frame_ctl)) {
- if (ieee->handle_beacon != NULL)
- ieee->handle_beacon(dev, beacon, target);
- } else {
- if (ieee->handle_probe_response != NULL)
- ieee->handle_probe_response(dev, beacon, target);
- }
-}
-
-void libipw_rx_mgt(struct libipw_device *ieee,
- struct libipw_hdr_4addr *header,
- struct libipw_rx_stats *stats)
-{
- switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) {
- case IEEE80211_STYPE_ASSOC_RESP:
- LIBIPW_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- libipw_handle_assoc_resp(ieee,
- (struct libipw_assoc_response *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_REASSOC_RESP:
- LIBIPW_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- break;
-
- case IEEE80211_STYPE_PROBE_REQ:
- LIBIPW_DEBUG_MGMT("received auth (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- if (ieee->handle_probe_request != NULL)
- ieee->handle_probe_request(ieee->dev,
- (struct
- libipw_probe_request *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_PROBE_RESP:
- LIBIPW_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_SCAN("Probe response\n");
- libipw_process_probe_response(ieee,
- (struct
- libipw_probe_response *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_BEACON:
- LIBIPW_DEBUG_MGMT("received BEACON (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_SCAN("Beacon\n");
- libipw_process_probe_response(ieee,
- (struct
- libipw_probe_response *)
- header, stats);
- break;
- case IEEE80211_STYPE_AUTH:
-
- LIBIPW_DEBUG_MGMT("received auth (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- if (ieee->handle_auth != NULL)
- ieee->handle_auth(ieee->dev,
- (struct libipw_auth *)header);
- break;
-
- case IEEE80211_STYPE_DISASSOC:
- if (ieee->handle_disassoc != NULL)
- ieee->handle_disassoc(ieee->dev,
- (struct libipw_disassoc *)
- header);
- break;
-
- case IEEE80211_STYPE_ACTION:
- LIBIPW_DEBUG_MGMT("ACTION\n");
- if (ieee->handle_action)
- ieee->handle_action(ieee->dev,
- (struct libipw_action *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_REASSOC_REQ:
- LIBIPW_DEBUG_MGMT("received reassoc (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- LIBIPW_DEBUG_MGMT("%s: LIBIPW_REASSOC_REQ received\n",
- ieee->dev->name);
- if (ieee->handle_reassoc_request != NULL)
- ieee->handle_reassoc_request(ieee->dev,
- (struct libipw_reassoc_request *)
- header);
- break;
-
- case IEEE80211_STYPE_ASSOC_REQ:
- LIBIPW_DEBUG_MGMT("received assoc (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- LIBIPW_DEBUG_MGMT("%s: LIBIPW_ASSOC_REQ received\n",
- ieee->dev->name);
- if (ieee->handle_assoc_request != NULL)
- ieee->handle_assoc_request(ieee->dev);
- break;
-
- case IEEE80211_STYPE_DEAUTH:
- LIBIPW_DEBUG_MGMT("DEAUTH\n");
- if (ieee->handle_deauth != NULL)
- ieee->handle_deauth(ieee->dev,
- (struct libipw_deauth *)
- header);
- break;
- default:
- LIBIPW_DEBUG_MGMT("received UNKNOWN (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_MGMT("%s: Unknown management packet: %d\n",
- ieee->dev->name,
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- break;
- }
-}
-
-EXPORT_SYMBOL_GPL(libipw_rx_any);
-EXPORT_SYMBOL(libipw_rx_mgt);
-EXPORT_SYMBOL(libipw_rx);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
deleted file mode 100644
index 4aec1fce1ae29..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
+++ /dev/null
@@ -1,519 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-
-#include "libipw.h"
-
-/*
-
-802.11 Data Frame
-
- ,-------------------------------------------------------------------.
-Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- |------|------|---------|---------|---------|------|---------|------|
-Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
- | | tion | (BSSID) | | | ence | data | |
- `--------------------------------------------------| |------'
-Total: 28 non-data bytes `----.----'
- |
- .- 'Frame data' expands, if WEP enabled, to <----------'
- |
- V
- ,-----------------------.
-Bytes | 4 | 0-2296 | 4 |
- |-----|-----------|-----|
-Desc. | IV | Encrypted | ICV |
- | | Packet | |
- `-----| |-----'
- `-----.-----'
- |
- .- 'Encrypted Packet' expands to
- |
- V
- ,---------------------------------------------------.
-Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
- |------|------|---------|----------|------|---------|
-Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
- | DSAP | SSAP | | | | Packet |
- | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
- `----------------------------------------------------
-Total: 8 non-data bytes
-
-802.3 Ethernet Data Frame
-
- ,-----------------------------------------.
-Bytes | 6 | 6 | 2 | Variable | 4 |
- |-------|-------|------|-----------|------|
-Desc. | Dest. | Source| Type | IP Packet | fcs |
- | MAC | MAC | | | |
- `-----------------------------------------'
-Total: 18 non-data bytes
-
-In the event that fragmentation is required, the incoming payload is split into
-N parts of size ieee->fts. The first fragment contains the SNAP header and the
-remaining packets are just data.
-
-If encryption is enabled, each fragment payload size is reduced by enough space
-to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
-So if you have 1500 bytes of payload with ieee->fts set to 500 without
-encryption it will take 3 frames. With WEP it will take 4 frames as the
-payload of each frame is reduced to 492 bytes.
-
-* SKB visualization
-*
-* ,- skb->data
-* |
-* | ETHERNET HEADER ,-<-- PAYLOAD
-* | | 14 bytes from skb->data
-* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
-* | | | |
-* |,-Dest.--. ,--Src.---. | | |
-* | 6 bytes| | 6 bytes | | | |
-* v | | | | | |
-* 0 | v 1 | v | v 2
-* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
-* ^ | ^ | ^ |
-* | | | | | |
-* | | | | `T' <---- 2 bytes for Type
-* | | | |
-* | | '---SNAP--' <-------- 6 bytes for SNAP
-* | |
-* `-IV--' <-------------------- 4 bytes for IV (WEP)
-*
-* SNAP HEADER
-*
-*/
-
-static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
-static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
-
-static int libipw_copy_snap(u8 * data, __be16 h_proto)
-{
- struct libipw_snap_hdr *snap;
- u8 *oui;
-
- snap = (struct libipw_snap_hdr *)data;
- snap->dsap = 0xaa;
- snap->ssap = 0xaa;
- snap->ctrl = 0x03;
-
- if (h_proto == htons(ETH_P_AARP) || h_proto == htons(ETH_P_IPX))
- oui = P802_1H_OUI;
- else
- oui = RFC1042_OUI;
- snap->oui[0] = oui[0];
- snap->oui[1] = oui[1];
- snap->oui[2] = oui[2];
-
- memcpy(data + SNAP_SIZE, &h_proto, sizeof(u16));
-
- return SNAP_SIZE + sizeof(u16);
-}
-
-static int libipw_encrypt_fragment(struct libipw_device *ieee,
- struct sk_buff *frag, int hdr_len)
-{
- struct lib80211_crypt_data *crypt =
- ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- int res;
-
- if (crypt == NULL)
- return -1;
-
- /* To encrypt, frame format is:
- * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
- atomic_inc(&crypt->refcnt);
- res = 0;
- if (crypt->ops && crypt->ops->encrypt_mpdu)
- res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
-
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
- ieee->dev->name, frag->len);
- ieee->ieee_stats.tx_discards++;
- return -1;
- }
-
- return 0;
-}
-
-void libipw_txb_free(struct libipw_txb *txb)
-{
- int i;
- if (unlikely(!txb))
- return;
- for (i = 0; i < txb->nr_frags; i++)
- if (txb->fragments[i])
- dev_kfree_skb_any(txb->fragments[i]);
- kfree(txb);
-}
-
-static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size,
- int headroom, gfp_t gfp_mask)
-{
- struct libipw_txb *txb;
- int i;
-
- txb = kmalloc(struct_size(txb, fragments, nr_frags), gfp_mask);
- if (!txb)
- return NULL;
-
- memset(txb, 0, sizeof(struct libipw_txb));
- txb->nr_frags = nr_frags;
- txb->frag_size = txb_size;
-
- for (i = 0; i < nr_frags; i++) {
- txb->fragments[i] = __dev_alloc_skb(txb_size + headroom,
- gfp_mask);
- if (unlikely(!txb->fragments[i])) {
- i--;
- break;
- }
- skb_reserve(txb->fragments[i], headroom);
- }
- if (unlikely(i != nr_frags)) {
- while (i >= 0)
- dev_kfree_skb_any(txb->fragments[i--]);
- kfree(txb);
- return NULL;
- }
- return txb;
-}
-
-static int libipw_classify(struct sk_buff *skb)
-{
- struct ethhdr *eth;
- struct iphdr *ip;
-
- eth = (struct ethhdr *)skb->data;
- if (eth->h_proto != htons(ETH_P_IP))
- return 0;
-
- ip = ip_hdr(skb);
- switch (ip->tos & 0xfc) {
- case 0x20:
- return 2;
- case 0x40:
- return 1;
- case 0x60:
- return 3;
- case 0x80:
- return 4;
- case 0xa0:
- return 5;
- case 0xc0:
- return 6;
- case 0xe0:
- return 7;
- default:
- return 0;
- }
-}
-
-/* Incoming skb is converted to a txb which consists of
- * a block of 802.11 fragment packets (stored as skbs) */
-netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct libipw_device *ieee = netdev_priv(dev);
- struct libipw_txb *txb = NULL;
- struct libipw_hdr_3addrqos *frag_hdr;
- int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
- rts_required;
- unsigned long flags;
- int encrypt, host_encrypt, host_encrypt_msdu;
- __be16 ether_type;
- int bytes, fc, hdr_len;
- struct sk_buff *skb_frag;
- struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */
- .duration_id = 0,
- .seq_ctl = 0,
- .qos_ctl = 0
- };
- u8 dest[ETH_ALEN], src[ETH_ALEN];
- struct lib80211_crypt_data *crypt;
- int priority = skb->priority;
- int snapped = 0;
-
- if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority))
- return NETDEV_TX_BUSY;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- /* If there is no driver handler to take the TXB, dont' bother
- * creating it... */
- if (!ieee->hard_start_xmit) {
- printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
- goto success;
- }
-
- if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
- printk(KERN_WARNING "%s: skb too small (%d).\n",
- ieee->dev->name, skb->len);
- goto success;
- }
-
- ether_type = ((struct ethhdr *)skb->data)->h_proto;
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
-
- encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) &&
- ieee->sec.encrypt;
-
- host_encrypt = ieee->host_encrypt && encrypt && crypt;
- host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
-
- if (!encrypt && ieee->ieee802_1x &&
- ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
- dev->stats.tx_dropped++;
- goto success;
- }
-
- /* Save source and destination addresses */
- skb_copy_from_linear_data(skb, dest, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
-
- if (host_encrypt)
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
- IEEE80211_FCTL_PROTECTED;
- else
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
-
- if (ieee->iw_mode == IW_MODE_INFRA) {
- fc |= IEEE80211_FCTL_TODS;
- /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
- memcpy(header.addr1, ieee->bssid, ETH_ALEN);
- memcpy(header.addr2, src, ETH_ALEN);
- memcpy(header.addr3, dest, ETH_ALEN);
- } else if (ieee->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
- memcpy(header.addr1, dest, ETH_ALEN);
- memcpy(header.addr2, src, ETH_ALEN);
- memcpy(header.addr3, ieee->bssid, ETH_ALEN);
- }
- hdr_len = LIBIPW_3ADDR_LEN;
-
- if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
- fc |= IEEE80211_STYPE_QOS_DATA;
- hdr_len += 2;
-
- skb->priority = libipw_classify(skb);
- header.qos_ctl |= cpu_to_le16(skb->priority & LIBIPW_QCTL_TID);
- }
- header.frame_ctl = cpu_to_le16(fc);
-
- /* Advance the SKB to the start of the payload */
- skb_pull(skb, sizeof(struct ethhdr));
-
- /* Determine total amount of storage required for TXB packets */
- bytes = skb->len + SNAP_SIZE + sizeof(u16);
-
- /* Encrypt msdu first on the whole data packet. */
- if ((host_encrypt || host_encrypt_msdu) &&
- crypt && crypt->ops && crypt->ops->encrypt_msdu) {
- int res = 0;
- int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
- crypt->ops->extra_msdu_postfix_len;
- struct sk_buff *skb_new = dev_alloc_skb(len);
-
- if (unlikely(!skb_new))
- goto failed;
-
- skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
- skb_put_data(skb_new, &header, hdr_len);
- snapped = 1;
- libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
- ether_type);
- skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
- res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
- if (res < 0) {
- LIBIPW_ERROR("msdu encryption failed\n");
- dev_kfree_skb_any(skb_new);
- goto failed;
- }
- dev_kfree_skb_any(skb);
- skb = skb_new;
- bytes += crypt->ops->extra_msdu_prefix_len +
- crypt->ops->extra_msdu_postfix_len;
- skb_pull(skb, hdr_len);
- }
-
- if (host_encrypt || ieee->host_open_frag) {
- /* Determine fragmentation size based on destination (multicast
- * and broadcast are not fragmented) */
- if (is_multicast_ether_addr(dest) ||
- is_broadcast_ether_addr(dest))
- frag_size = MAX_FRAG_THRESHOLD;
- else
- frag_size = ieee->fts;
-
- /* Determine amount of payload per fragment. Regardless of if
- * this stack is providing the full 802.11 header, one will
- * eventually be affixed to this fragment -- so we must account
- * for it when determining the amount of payload space. */
- bytes_per_frag = frag_size - hdr_len;
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- bytes_per_frag -= LIBIPW_FCS_LEN;
-
- /* Each fragment may need to have room for encryption
- * pre/postfix */
- if (host_encrypt && crypt && crypt->ops)
- bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_mpdu_postfix_len;
-
- /* Number of fragments is the total
- * bytes_per_frag / payload_per_fragment */
- nr_frags = bytes / bytes_per_frag;
- bytes_last_frag = bytes % bytes_per_frag;
- if (bytes_last_frag)
- nr_frags++;
- else
- bytes_last_frag = bytes_per_frag;
- } else {
- nr_frags = 1;
- bytes_per_frag = bytes_last_frag = bytes;
- frag_size = bytes + hdr_len;
- }
-
- rts_required = (frag_size > ieee->rts
- && ieee->config & CFG_LIBIPW_RTS);
- if (rts_required)
- nr_frags++;
-
- /* When we allocate the TXB we allocate enough space for the reserve
- * and full fragment bytes (bytes_per_frag doesn't include prefix,
- * postfix, header, FCS, etc.) */
- txb = libipw_alloc_txb(nr_frags, frag_size,
- ieee->tx_headroom, GFP_ATOMIC);
- if (unlikely(!txb)) {
- printk(KERN_WARNING "%s: Could not allocate TXB\n",
- ieee->dev->name);
- goto failed;
- }
- txb->encrypted = encrypt;
- if (host_encrypt)
- txb->payload_size = frag_size * (nr_frags - 1) +
- bytes_last_frag;
- else
- txb->payload_size = bytes;
-
- if (rts_required) {
- skb_frag = txb->fragments[0];
- frag_hdr = skb_put(skb_frag, hdr_len);
-
- /*
- * Set header frame_ctl to the RTS.
- */
- header.frame_ctl =
- cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
- memcpy(frag_hdr, &header, hdr_len);
-
- /*
- * Restore header frame_ctl to the original data setting.
- */
- header.frame_ctl = cpu_to_le16(fc);
-
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- skb_put(skb_frag, 4);
-
- txb->rts_included = 1;
- i = 1;
- } else
- i = 0;
-
- for (; i < nr_frags; i++) {
- skb_frag = txb->fragments[i];
-
- if (host_encrypt)
- skb_reserve(skb_frag,
- crypt->ops->extra_mpdu_prefix_len);
-
- frag_hdr = skb_put_data(skb_frag, &header, hdr_len);
-
- /* If this is not the last fragment, then add the MOREFRAGS
- * bit to the frame control */
- if (i != nr_frags - 1) {
- frag_hdr->frame_ctl =
- cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
- bytes = bytes_per_frag;
- } else {
- /* The last fragment takes the remaining length */
- bytes = bytes_last_frag;
- }
-
- if (i == 0 && !snapped) {
- libipw_copy_snap(skb_put
- (skb_frag, SNAP_SIZE + sizeof(u16)),
- ether_type);
- bytes -= SNAP_SIZE + sizeof(u16);
- }
-
- skb_copy_from_linear_data(skb, skb_put(skb_frag, bytes), bytes);
-
- /* Advance the SKB... */
- skb_pull(skb, bytes);
-
- /* Encryption routine will move the header forward in order
- * to insert the IV between the header and the payload */
- if (host_encrypt)
- libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
-
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- skb_put(skb_frag, 4);
- }
-
- success:
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- dev_kfree_skb_any(skb);
-
- if (txb) {
- netdev_tx_t ret = (*ieee->hard_start_xmit)(txb, dev, priority);
- if (ret == NETDEV_TX_OK) {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += txb->payload_size;
- return NETDEV_TX_OK;
- }
-
- libipw_txb_free(txb);
- }
-
- return NETDEV_TX_OK;
-
- failed:
- spin_unlock_irqrestore(&ieee->lock, flags);
- netif_stop_queue(dev);
- dev->stats.tx_errors++;
- return NETDEV_TX_BUSY;
-}
-EXPORT_SYMBOL(libipw_xmit);
-
-EXPORT_SYMBOL(libipw_txb_free);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
deleted file mode 100644
index 903de34028efb..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
+++ /dev/null
@@ -1,726 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
-
- Portions of this file are based on the WEP enablement code provided by the
- Host AP project hostap-drivers v0.1.3
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <[email protected]>
- Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#include <linux/hardirq.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/jiffies.h>
-
-#include <net/lib80211.h>
-#include <linux/wireless.h>
-
-#include "libipw.h"
-
-static const char *libipw_modes[] = {
- "?", "a", "b", "ab", "g", "ag", "bg", "abg"
-};
-
-static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
-{
- unsigned long end = jiffies;
-
- if (end >= start)
- return jiffies_to_msecs(end - start);
-
- return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
-}
-
-#define MAX_CUSTOM_LEN 64
-static char *libipw_translate_scan(struct libipw_device *ieee,
- char *start, char *stop,
- struct libipw_network *network,
- struct iw_request_info *info)
-{
- char custom[MAX_CUSTOM_LEN];
- char *p;
- struct iw_event iwe;
- int i, j;
- char *current_val; /* For rates */
- u8 rate;
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
-
- /* Remaining entries will be displayed in the order we provide them */
-
- /* Add the ESSID */
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- iwe.u.data.length = min(network->ssid_len, (u8) 32);
- start = iwe_stream_add_point(info, start, stop,
- &iwe, network->ssid);
-
- /* Add the protocol name */
- iwe.cmd = SIOCGIWNAME;
- snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
- libipw_modes[network->mode]);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (network->capability & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
-
- start = iwe_stream_add_event(info, start, stop,
- &iwe, IW_EV_UINT_LEN);
- }
-
- /* Add channel and frequency */
- /* Note : userspace automatically computes channel using iwrange */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel);
- iwe.u.freq.e = 6;
- iwe.u.freq.i = 0;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (network->capability & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- start = iwe_stream_add_point(info, start, stop,
- &iwe, network->ssid);
-
- /* Add basic and extended rates */
- /* Rate : stuffing multiple values in a single event require a bit
- * more of magic - Jean II */
- current_val = start + iwe_stream_lcp_len(info);
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 0, j = 0; i < network->rates_len;) {
- if (j < network->rates_ex_len &&
- ((network->rates_ex[j] & 0x7F) <
- (network->rates[i] & 0x7F)))
- rate = network->rates_ex[j++] & 0x7F;
- else
- rate = network->rates[i++] & 0x7F;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- for (; j < network->rates_ex_len; j++) {
- rate = network->rates_ex[j] & 0x7F;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any rate */
- if ((current_val - start) > iwe_stream_lcp_len(info))
- start = current_val;
-
- /* Add quality statistics */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED;
-
- if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) {
- iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
- IW_QUAL_LEVEL_INVALID;
- iwe.u.qual.qual = 0;
- } else {
- if (ieee->perfect_rssi == ieee->worst_rssi)
- iwe.u.qual.qual = 100;
- else
- iwe.u.qual.qual =
- (100 *
- (ieee->perfect_rssi - ieee->worst_rssi) *
- (ieee->perfect_rssi - ieee->worst_rssi) -
- (ieee->perfect_rssi - network->stats.rssi) *
- (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
- 62 * (ieee->perfect_rssi -
- network->stats.rssi))) /
- ((ieee->perfect_rssi -
- ieee->worst_rssi) * (ieee->perfect_rssi -
- ieee->worst_rssi));
- if (iwe.u.qual.qual > 100)
- iwe.u.qual.qual = 100;
- else if (iwe.u.qual.qual < 1)
- iwe.u.qual.qual = 0;
- }
-
- if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) {
- iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
- iwe.u.qual.noise = 0;
- } else {
- iwe.u.qual.noise = network->stats.noise;
- }
-
- if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) {
- iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
- iwe.u.qual.level = 0;
- } else {
- iwe.u.qual.level = network->stats.signal;
- }
-
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-
- iwe.cmd = IWEVCUSTOM;
- p = custom;
-
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- memset(&iwe, 0, sizeof(iwe));
- if (network->wpa_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, network->wpa_ie, network->wpa_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->wpa_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- if (network->rsn_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, network->rsn_ie, network->rsn_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->rsn_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
- " Last beacon: %ums ago",
- elapsed_jiffies_msecs(network->last_scanned));
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- /* Add spectrum management information */
- iwe.cmd = -1;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
-
- if (libipw_get_channel_flags(ieee, network->channel) &
- LIBIPW_CH_INVALID) {
- iwe.cmd = IWEVCUSTOM;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
- }
-
- if (libipw_get_channel_flags(ieee, network->channel) &
- LIBIPW_CH_RADAR_DETECT) {
- iwe.cmd = IWEVCUSTOM;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
- }
-
- if (iwe.cmd == IWEVCUSTOM) {
- iwe.u.data.length = p - custom;
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
- }
-
- return start;
-}
-
-#define SCAN_ITEM_SIZE 128
-
-int libipw_wx_get_scan(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct libipw_network *network;
- unsigned long flags;
- int err = 0;
-
- char *ev = extra;
- char *stop = ev + wrqu->data.length;
- int i = 0;
-
- LIBIPW_DEBUG_WX("Getting scan\n");
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(network, &ieee->network_list, list) {
- i++;
- if (stop - ev < SCAN_ITEM_SIZE) {
- err = -E2BIG;
- break;
- }
-
- if (ieee->scan_age == 0 ||
- time_after(network->last_scanned + ieee->scan_age, jiffies))
- ev = libipw_translate_scan(ieee, ev, stop, network,
- info);
- else {
- LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n",
- network->ssid_len, network->ssid,
- network->bssid,
- elapsed_jiffies_msecs(
- network->last_scanned));
- }
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- wrqu->data.length = ev - extra;
- wrqu->data.flags = 0;
-
- LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i);
-
- return err;
-}
-
-int libipw_wx_set_encode(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &(wrqu->encoding);
- struct net_device *dev = ieee->dev;
- struct libipw_security sec = {
- .flags = 0
- };
- int i, key, key_provided, len;
- struct lib80211_crypt_data **crypt;
- int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
-
- LIBIPW_DEBUG_WX("SET_ENCODE\n");
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > WEP_KEYS)
- return -EINVAL;
- key--;
- key_provided = 1;
- } else {
- key_provided = 0;
- key = ieee->crypt_info.tx_keyidx;
- }
-
- LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
- "provided" : "default");
-
- crypt = &ieee->crypt_info.crypt[key];
-
- if (erq->flags & IW_ENCODE_DISABLED) {
- if (key_provided && *crypt) {
- LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
- key);
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- } else
- LIBIPW_DEBUG_WX("Disabling encryption.\n");
-
- /* Check all the keys to see if any are still configured,
- * and if no key index was provided, de-init them all */
- for (i = 0; i < WEP_KEYS; i++) {
- if (ieee->crypt_info.crypt[i] != NULL) {
- if (key_provided)
- break;
- lib80211_crypt_delayed_deinit(&ieee->crypt_info,
- &ieee->crypt_info.crypt[i]);
- }
- }
-
- if (i == WEP_KEYS) {
- sec.enabled = 0;
- sec.encrypt = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
- }
-
- goto done;
- }
-
- sec.enabled = 1;
- sec.encrypt = 1;
- sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
-
- if (*crypt != NULL && (*crypt)->ops != NULL &&
- strcmp((*crypt)->ops->name, "WEP") != 0) {
- /* changing to use WEP; deinit previously used algorithm
- * on this key */
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- }
-
- if (*crypt == NULL && host_crypto) {
- struct lib80211_crypt_data *new_crypt;
-
- /* take WEP into use */
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL)
- return -ENOMEM;
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- if (!new_crypt->ops) {
- request_module("lib80211_crypt_wep");
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- }
-
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(key);
-
- if (!new_crypt->ops || !new_crypt->priv) {
- kfree(new_crypt);
- new_crypt = NULL;
-
- printk(KERN_WARNING "%s: could not initialize WEP: "
- "load module lib80211_crypt_wep\n", dev->name);
- return -EOPNOTSUPP;
- }
- *crypt = new_crypt;
- }
-
- /* If a new key was provided, set it up */
- if (erq->length > 0) {
- len = erq->length <= 5 ? 5 : 13;
- memcpy(sec.keys[key], keybuf, erq->length);
- if (len > erq->length)
- memset(sec.keys[key] + erq->length, 0,
- len - erq->length);
- LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n",
- key, len, sec.keys[key],
- erq->length, len);
- sec.key_sizes[key] = len;
- if (*crypt)
- (*crypt)->ops->set_key(sec.keys[key], len, NULL,
- (*crypt)->priv);
- sec.flags |= (1 << key);
- /* This ensures a key will be activated if no key is
- * explicitly set */
- if (key == sec.active_key)
- sec.flags |= SEC_ACTIVE_KEY;
-
- } else {
- if (host_crypto) {
- len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
- NULL, (*crypt)->priv);
- if (len == 0) {
- /* Set a default key of all 0 */
- LIBIPW_DEBUG_WX("Setting key %d to all "
- "zero.\n", key);
- memset(sec.keys[key], 0, 13);
- (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
- (*crypt)->priv);
- sec.key_sizes[key] = 13;
- sec.flags |= (1 << key);
- }
- }
- /* No key data - just set the default TX key index */
- if (key_provided) {
- LIBIPW_DEBUG_WX("Setting key %d to default Tx "
- "key.\n", key);
- ieee->crypt_info.tx_keyidx = key;
- sec.active_key = key;
- sec.flags |= SEC_ACTIVE_KEY;
- }
- }
- if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
- ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
- sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
- WLAN_AUTH_SHARED_KEY;
- sec.flags |= SEC_AUTH_MODE;
- LIBIPW_DEBUG_WX("Auth: %s\n",
- sec.auth_mode == WLAN_AUTH_OPEN ?
- "OPEN" : "SHARED KEY");
- }
-
- /* For now we just support WEP, so only set that security level...
- * TODO: When WPA is added this is one place that needs to change */
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
- sec.encode_alg[key] = SEC_ALG_WEP;
-
- done:
- if (ieee->set_security)
- ieee->set_security(dev, &sec);
-
- return 0;
-}
-
-int libipw_wx_get_encode(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &(wrqu->encoding);
- int len, key;
- struct libipw_security *sec = &ieee->sec;
-
- LIBIPW_DEBUG_WX("GET_ENCODE\n");
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > WEP_KEYS)
- return -EINVAL;
- key--;
- } else
- key = ieee->crypt_info.tx_keyidx;
-
- erq->flags = key + 1;
-
- if (!sec->enabled) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- len = sec->key_sizes[key];
- memcpy(keybuf, sec->keys[key], len);
-
- erq->length = len;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (ieee->open_wep)
- erq->flags |= IW_ENCODE_OPEN;
- else
- erq->flags |= IW_ENCODE_RESTRICTED;
-
- return 0;
-}
-
-int libipw_wx_set_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct net_device *dev = ieee->dev;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int i, idx, ret = 0;
- int group_key = 0;
- const char *alg, *module;
- struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
-
- struct libipw_security sec = {
- .flags = 0,
- };
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
- return -EINVAL;
- idx--;
- } else
- idx = ieee->crypt_info.tx_keyidx;
-
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
- crypt = &ieee->crypt_info.crypt[idx];
- group_key = 1;
- } else {
- /* some Cisco APs use idx>0 for unicast in dynamic WEP */
- if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
- return -EINVAL;
- if (ieee->iw_mode == IW_MODE_INFRA)
- crypt = &ieee->crypt_info.crypt[idx];
- else
- return -EINVAL;
- }
-
- sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
- if ((encoding->flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- for (i = 0; i < WEP_KEYS; i++)
- if (ieee->crypt_info.crypt[i] != NULL)
- break;
-
- if (i == WEP_KEYS) {
- sec.enabled = 0;
- sec.encrypt = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_LEVEL;
- }
- goto done;
- }
-
- sec.enabled = 1;
- sec.encrypt = 1;
-
- if (group_key ? !ieee->host_mc_decrypt :
- !(ieee->host_encrypt || ieee->host_decrypt ||
- ieee->host_encrypt_msdu))
- goto skip_host_crypt;
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_WEP:
- alg = "WEP";
- module = "lib80211_crypt_wep";
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = "TKIP";
- module = "lib80211_crypt_tkip";
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = "CCMP";
- module = "lib80211_crypt_ccmp";
- break;
- default:
- LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
- dev->name, ext->alg);
- ret = -EINVAL;
- goto done;
- }
-
- ops = lib80211_get_crypto_ops(alg);
- if (ops == NULL) {
- request_module(module);
- ops = lib80211_get_crypto_ops(alg);
- }
- if (ops == NULL) {
- LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
- dev->name, ext->alg);
- ret = -EINVAL;
- goto done;
- }
-
- if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
- if (new_crypt == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- new_crypt->ops = ops;
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(idx);
- if (new_crypt->priv == NULL) {
- kfree(new_crypt);
- ret = -EINVAL;
- goto done;
- }
- *crypt = new_crypt;
- }
-
- if (ext->key_len > 0 && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
- (*crypt)->priv) < 0) {
- LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name);
- ret = -EINVAL;
- goto done;
- }
-
- skip_host_crypt:
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- ieee->crypt_info.tx_keyidx = idx;
- sec.active_key = idx;
- sec.flags |= SEC_ACTIVE_KEY;
- }
-
- if (ext->alg != IW_ENCODE_ALG_NONE) {
- int key_len = clamp_val(ext->key_len, 0, SCM_KEY_LEN);
-
- memcpy(sec.keys[idx], ext->key, key_len);
- sec.key_sizes[idx] = key_len;
- sec.flags |= (1 << idx);
- if (ext->alg == IW_ENCODE_ALG_WEP) {
- sec.encode_alg[idx] = SEC_ALG_WEP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
- sec.encode_alg[idx] = SEC_ALG_TKIP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_2;
- } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
- sec.encode_alg[idx] = SEC_ALG_CCMP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_3;
- }
- /* Don't set sec level for group keys. */
- if (group_key)
- sec.flags &= ~SEC_LEVEL;
- }
- done:
- if (ieee->set_security)
- ieee->set_security(dev, &sec);
-
- return ret;
-}
-
-int libipw_wx_get_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- struct libipw_security *sec = &ieee->sec;
- int idx, max_key_len;
-
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
- return -EINVAL;
- idx--;
- } else
- idx = ieee->crypt_info.tx_keyidx;
-
- if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
- ext->alg != IW_ENCODE_ALG_WEP)
- if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
- return -EINVAL;
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- if (!sec->enabled) {
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- encoding->flags |= IW_ENCODE_DISABLED;
- } else {
- if (sec->encode_alg[idx] == SEC_ALG_WEP)
- ext->alg = IW_ENCODE_ALG_WEP;
- else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
- ext->alg = IW_ENCODE_ALG_TKIP;
- else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
- ext->alg = IW_ENCODE_ALG_CCMP;
- else
- return -EINVAL;
-
- ext->key_len = sec->key_sizes[idx];
- memcpy(ext->key, sec->keys[idx], ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- if (ext->key_len &&
- (ext->alg == IW_ENCODE_ALG_TKIP ||
- ext->alg == IW_ENCODE_ALG_CCMP))
- ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
-
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(libipw_wx_set_encodeext);
-EXPORT_SYMBOL(libipw_wx_get_encodeext);
-
-EXPORT_SYMBOL(libipw_wx_get_scan);
-EXPORT_SYMBOL(libipw_wx_set_encode);
-EXPORT_SYMBOL(libipw_wx_get_encode);
--
2.39.2

2023-10-23 13:23:48

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH 10/10] wifi: remove ipw2100/ipw2200 drivers

From: Arnd Bergmann <[email protected]>

These two drivers were used for the earliest "Centrino" branded Intel
laptops during the late 32-bit Pentium-M era, roughly 2003 to 2005, which
probably makes it the most modern platform that still uses the wireless
extension interface instead of cfg80211. Unlike the other drivers that
are suggested for removal, this one is still officially maintained.

According to Johannes Berg, there was an effort to finish the move away
from wext in the past, but the last evidence of this that I could find
is from commit a3caa99e6c68f ("libipw: initiate cfg80211 API conversion
(v2)") in 2009.

Link: https://lore.kernel.org/all/[email protected]/
Cc: Stanislav Yakovlev <[email protected]>
Cc: Linux Wireless <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
.../networking/device_drivers/wifi/index.rst | 19 -
.../device_drivers/wifi/intel/ipw2100.rst | 323 -
.../device_drivers/wifi/intel/ipw2200.rst | 526 -
MAINTAINERS | 8 -
drivers/net/wireless/intel/Kconfig | 1 -
drivers/net/wireless/intel/Makefile | 3 -
drivers/net/wireless/intel/ipw2x00/Kconfig | 195 -
drivers/net/wireless/intel/ipw2x00/Makefile | 15 -
drivers/net/wireless/intel/ipw2x00/ipw.h | 20 -
drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8587 -----------
drivers/net/wireless/intel/ipw2x00/ipw2100.h | 1142 --
drivers/net/wireless/intel/ipw2x00/ipw2200.c | 11965 ----------------
drivers/net/wireless/intel/ipw2x00/ipw2200.h | 1984 ---
drivers/net/wireless/intel/ipw2x00/libipw.h | 1001 --
.../net/wireless/intel/ipw2x00/libipw_geo.c | 179 -
.../wireless/intel/ipw2x00/libipw_module.c | 297 -
.../net/wireless/intel/ipw2x00/libipw_rx.c | 1737 ---
.../net/wireless/intel/ipw2x00/libipw_tx.c | 519 -
.../net/wireless/intel/ipw2x00/libipw_wx.c | 726 -
19 files changed, 29247 deletions(-)
delete mode 100644 Documentation/networking/device_drivers/wifi/index.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Kconfig
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Makefile
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_geo.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_module.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_rx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_tx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_wx.c

diff --git a/Documentation/networking/device_drivers/wifi/index.rst b/Documentation/networking/device_drivers/wifi/index.rst
deleted file mode 100644
index fb394f5de4a94..0000000000000
--- a/Documentation/networking/device_drivers/wifi/index.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-
-Wi-Fi Device Drivers
-====================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- intel/ipw2100
- intel/ipw2200
-
-.. only:: subproject and html
-
- Indices
- =======
-
- * :ref:`genindex`
diff --git a/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst b/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
deleted file mode 100644
index 883e963557992..0000000000000
--- a/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
+++ /dev/null
@@ -1,323 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-===========================================
-Intel(R) PRO/Wireless 2100 Driver for Linux
-===========================================
-
-Support for:
-
-- Intel(R) PRO/Wireless 2100 Network Connection
-
-Copyright |copy| 2003-2006, Intel Corporation
-
-README.ipw2100
-
-:Version: git-1.1.5
-:Date: January 25, 2006
-
-.. Index
-
- 0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
- 1. Introduction
- 2. Release git-1.1.5 Current Features
- 3. Command Line Parameters
- 4. Sysfs Helper Files
- 5. Radio Kill Switch
- 6. Dynamic Firmware
- 7. Power Management
- 8. Support
- 9. License
-
-
-0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
-=================================================
-
-Important Notice FOR ALL USERS OR DISTRIBUTORS!!!!
-
-Intel wireless LAN adapters are engineered, manufactured, tested, and
-quality checked to ensure that they meet all necessary local and
-governmental regulatory agency requirements for the regions that they
-are designated and/or marked to ship into. Since wireless LANs are
-generally unlicensed devices that share spectrum with radars,
-satellites, and other licensed and unlicensed devices, it is sometimes
-necessary to dynamically detect, avoid, and limit usage to avoid
-interference with these devices. In many instances Intel is required to
-provide test data to prove regional and local compliance to regional and
-governmental regulations before certification or approval to use the
-product is granted. Intel's wireless LAN's EEPROM, firmware, and
-software driver are designed to carefully control parameters that affect
-radio operation and to ensure electromagnetic compliance (EMC). These
-parameters include, without limitation, RF power, spectrum usage,
-channel scanning, and human exposure.
-
-For these reasons Intel cannot permit any manipulation by third parties
-of the software provided in binary format with the wireless WLAN
-adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
-patches, utilities, or code with the Intel wireless LAN adapters that
-have been manipulated by an unauthorized party (i.e., patches,
-utilities, or code (including open source code modifications) which have
-not been validated by Intel), (i) you will be solely responsible for
-ensuring the regulatory compliance of the products, (ii) Intel will bear
-no liability, under any theory of liability for any issues associated
-with the modified products, including without limitation, claims under
-the warranty and/or issues arising from regulatory non-compliance, and
-(iii) Intel will not provide or be required to assist in providing
-support to any third parties for such modified products.
-
-Note: Many regulatory agencies consider Wireless LAN adapters to be
-modules, and accordingly, condition system-level regulatory approval
-upon receipt and review of test data documenting that the antennas and
-system configuration do not cause the EMC and radio operation to be
-non-compliant.
-
-The drivers available for download from SourceForge are provided as a
-part of a development project. Conformance to local regulatory
-requirements is the responsibility of the individual developer. As
-such, if you are interested in deploying or shipping a driver as part of
-solution intended to be used for purposes other than development, please
-obtain a tested driver from Intel Customer Support at:
-
-https://www.intel.com/support/wireless/sb/CS-006408.htm
-
-1. Introduction
-===============
-
-This document provides a brief overview of the features supported by the
-IPW2100 driver project. The main project website, where the latest
-development version of the driver can be found, is:
-
- http://ipw2100.sourceforge.net
-
-There you can find the not only the latest releases, but also information about
-potential fixes and patches, as well as links to the development mailing list
-for the driver project.
-
-
-2. Release git-1.1.5 Current Supported Features
-===============================================
-
-- Managed (BSS) and Ad-Hoc (IBSS)
-- WEP (shared key and open)
-- Wireless Tools support
-- 802.1x (tested with XSupplicant 1.0.1)
-
-Enabled (but not supported) features:
-- Monitor/RFMon mode
-- WPA/WPA2
-
-The distinction between officially supported and enabled is a reflection
-on the amount of validation and interoperability testing that has been
-performed on a given feature.
-
-
-3. Command Line Parameters
-==========================
-
-If the driver is built as a module, the following optional parameters are used
-by entering them on the command line with the modprobe command using this
-syntax::
-
- modprobe ipw2100 [<option>=<VAL1><,VAL2>...]
-
-For example, to disable the radio on driver loading, enter:
-
- modprobe ipw2100 disable=1
-
-The ipw2100 driver supports the following module parameters:
-
-========= ============== ============ ==============================
-Name Value Example Meaning
-========= ============== ============ ==============================
-debug 0x0-0xffffffff debug=1024 Debug level set to 1024
-mode 0,1,2 mode=1 AdHoc
-channel int channel=3 Only valid in AdHoc or Monitor
-associate boolean associate=0 Do NOT auto associate
-disable boolean disable=1 Do not power the HW
-========= ============== ============ ==============================
-
-
-4. Sysfs Helper Files
-=====================
-
-There are several ways to control the behavior of the driver. Many of the
-general capabilities are exposed through the Wireless Tools (iwconfig). There
-are a few capabilities that are exposed through entries in the Linux Sysfs.
-
-
-**Driver Level**
-
-For the driver level files, look in /sys/bus/pci/drivers/ipw2100/
-
- debug_level
- This controls the same global as the 'debug' module parameter. For
- information on the various debugging levels available, run the 'dvals'
- script found in the driver source directory.
-
- .. note::
-
- 'debug_level' is only enabled if CONFIG_IPW2100_DEBUG is turn on.
-
-**Device Level**
-
-For the device level files look in::
-
- /sys/bus/pci/drivers/ipw2100/{PCI-ID}/
-
-For example::
-
- /sys/bus/pci/drivers/ipw2100/0000:02:01.0
-
-For the device level files, see /sys/bus/pci/drivers/ipw2100:
-
- rf_kill
- read
-
- == =========================================
- 0 RF kill not enabled (radio on)
- 1 SW based RF kill active (radio off)
- 2 HW based RF kill active (radio off)
- 3 Both HW and SW RF kill active (radio off)
- == =========================================
-
- write
-
- == ==================================================
- 0 If SW based RF kill active, turn the radio back on
- 1 If radio is on, activate SW based RF kill
- == ==================================================
-
- .. note::
-
- If you enable the SW based RF kill and then toggle the HW
- based RF kill from ON -> OFF -> ON, the radio will NOT come back on
-
-
-5. Radio Kill Switch
-====================
-
-Most laptops provide the ability for the user to physically disable the radio.
-Some vendors have implemented this as a physical switch that requires no
-software to turn the radio off and on. On other laptops, however, the switch
-is controlled through a button being pressed and a software driver then making
-calls to turn the radio off and on. This is referred to as a "software based
-RF kill switch"
-
-See the Sysfs helper file 'rf_kill' for determining the state of the RF switch
-on your system.
-
-
-6. Dynamic Firmware
-===================
-
-As the firmware is licensed under a restricted use license, it can not be
-included within the kernel sources. To enable the IPW2100 you will need a
-firmware image to load into the wireless NIC's processors.
-
-You can obtain these images from <http://ipw2100.sf.net/firmware.php>.
-
-See INSTALL for instructions on installing the firmware.
-
-
-7. Power Management
-===================
-
-The IPW2100 supports the configuration of the Power Save Protocol
-through a private wireless extension interface. The IPW2100 supports
-the following different modes:
-
- === ===========================================================
- off No power management. Radio is always on.
- on Automatic power management
- 1-5 Different levels of power management. The higher the
- number the greater the power savings, but with an impact to
- packet latencies.
- === ===========================================================
-
-Power management works by powering down the radio after a certain
-interval of time has passed where no packets are passed through the
-radio. Once powered down, the radio remains in that state for a given
-period of time. For higher power savings, the interval between last
-packet processed to sleep is shorter and the sleep period is longer.
-
-When the radio is asleep, the access point sending data to the station
-must buffer packets at the AP until the station wakes up and requests
-any buffered packets. If you have an AP that does not correctly support
-the PSP protocol you may experience packet loss or very poor performance
-while power management is enabled. If this is the case, you will need
-to try and find a firmware update for your AP, or disable power
-management (via ``iwconfig eth1 power off``)
-
-To configure the power level on the IPW2100 you use a combination of
-iwconfig and iwpriv. iwconfig is used to turn power management on, off,
-and set it to auto.
-
- ========================= ====================================
- iwconfig eth1 power off Disables radio power down
- iwconfig eth1 power on Enables radio power management to
- last set level (defaults to AUTO)
- iwpriv eth1 set_power 0 Sets power level to AUTO and enables
- power management if not previously
- enabled.
- iwpriv eth1 set_power 1-5 Set the power level as specified,
- enabling power management if not
- previously enabled.
- ========================= ====================================
-
-You can view the current power level setting via::
-
- iwpriv eth1 get_power
-
-It will return the current period or timeout that is configured as a string
-in the form of xxxx/yyyy (z) where xxxx is the timeout interval (amount of
-time after packet processing), yyyy is the period to sleep (amount of time to
-wait before powering the radio and querying the access point for buffered
-packets), and z is the 'power level'. If power management is turned off the
-xxxx/yyyy will be replaced with 'off' -- the level reported will be the active
-level if `iwconfig eth1 power on` is invoked.
-
-
-8. Support
-==========
-
-For general development information and support,
-go to:
-
- http://ipw2100.sf.net/
-
-The ipw2100 1.1.0 driver and firmware can be downloaded from:
-
- http://support.intel.com
-
-For installation support on the ipw2100 1.1.0 driver on Linux kernels
-2.6.8 or greater, email support is available from:
-
- http://supportmail.intel.com
-
-9. License
-==========
-
- Copyright |copy| 2003 - 2006 Intel Corporation. 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.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- License Contact Information:
-
- James P. Ketrenos <[email protected]>
-
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
diff --git a/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst b/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
deleted file mode 100644
index 0cb42d2fd7e5f..0000000000000
--- a/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
+++ /dev/null
@@ -1,526 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-==============================================
-Intel(R) PRO/Wireless 2915ABG Driver for Linux
-==============================================
-
-
-Support for:
-
-- Intel(R) PRO/Wireless 2200BG Network Connection
-- Intel(R) PRO/Wireless 2915ABG Network Connection
-
-Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R)
-PRO/Wireless 2200BG Driver for Linux is a unified driver that works on
-both hardware adapters listed above. In this document the Intel(R)
-PRO/Wireless 2915ABG Driver for Linux will be used to reference the
-unified driver.
-
-Copyright |copy| 2004-2006, Intel Corporation
-
-README.ipw2200
-
-:Version: 1.1.2
-:Date: March 30, 2006
-
-
-.. Index
-
- 0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
- 1. Introduction
- 1.1. Overview of features
- 1.2. Module parameters
- 1.3. Wireless Extension Private Methods
- 1.4. Sysfs Helper Files
- 1.5. Supported channels
- 2. Ad-Hoc Networking
- 3. Interacting with Wireless Tools
- 3.1. iwconfig mode
- 3.2. iwconfig sens
- 4. About the Version Numbers
- 5. Firmware installation
- 6. Support
- 7. License
-
-
-0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
-=================================================
-
-Important Notice FOR ALL USERS OR DISTRIBUTORS!!!!
-
-Intel wireless LAN adapters are engineered, manufactured, tested, and
-quality checked to ensure that they meet all necessary local and
-governmental regulatory agency requirements for the regions that they
-are designated and/or marked to ship into. Since wireless LANs are
-generally unlicensed devices that share spectrum with radars,
-satellites, and other licensed and unlicensed devices, it is sometimes
-necessary to dynamically detect, avoid, and limit usage to avoid
-interference with these devices. In many instances Intel is required to
-provide test data to prove regional and local compliance to regional and
-governmental regulations before certification or approval to use the
-product is granted. Intel's wireless LAN's EEPROM, firmware, and
-software driver are designed to carefully control parameters that affect
-radio operation and to ensure electromagnetic compliance (EMC). These
-parameters include, without limitation, RF power, spectrum usage,
-channel scanning, and human exposure.
-
-For these reasons Intel cannot permit any manipulation by third parties
-of the software provided in binary format with the wireless WLAN
-adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
-patches, utilities, or code with the Intel wireless LAN adapters that
-have been manipulated by an unauthorized party (i.e., patches,
-utilities, or code (including open source code modifications) which have
-not been validated by Intel), (i) you will be solely responsible for
-ensuring the regulatory compliance of the products, (ii) Intel will bear
-no liability, under any theory of liability for any issues associated
-with the modified products, including without limitation, claims under
-the warranty and/or issues arising from regulatory non-compliance, and
-(iii) Intel will not provide or be required to assist in providing
-support to any third parties for such modified products.
-
-Note: Many regulatory agencies consider Wireless LAN adapters to be
-modules, and accordingly, condition system-level regulatory approval
-upon receipt and review of test data documenting that the antennas and
-system configuration do not cause the EMC and radio operation to be
-non-compliant.
-
-The drivers available for download from SourceForge are provided as a
-part of a development project. Conformance to local regulatory
-requirements is the responsibility of the individual developer. As
-such, if you are interested in deploying or shipping a driver as part of
-solution intended to be used for purposes other than development, please
-obtain a tested driver from Intel Customer Support at:
-
-http://support.intel.com
-
-
-1. Introduction
-===============
-
-The following sections attempt to provide a brief introduction to using
-the Intel(R) PRO/Wireless 2915ABG Driver for Linux.
-
-This document is not meant to be a comprehensive manual on
-understanding or using wireless technologies, but should be sufficient
-to get you moving without wires on Linux.
-
-For information on building and installing the driver, see the INSTALL
-file.
-
-
-1.1. Overview of Features
--------------------------
-The current release (1.1.2) supports the following features:
-
-+ BSS mode (Infrastructure, Managed)
-+ IBSS mode (Ad-Hoc)
-+ WEP (OPEN and SHARED KEY mode)
-+ 802.1x EAP via wpa_supplicant and xsupplicant
-+ Wireless Extension support
-+ Full B and G rate support (2200 and 2915)
-+ Full A rate support (2915 only)
-+ Transmit power control
-+ S state support (ACPI suspend/resume)
-
-The following features are currently enabled, but not officially
-supported:
-
-+ WPA
-+ long/short preamble support
-+ Monitor mode (aka RFMon)
-
-The distinction between officially supported and enabled is a reflection
-on the amount of validation and interoperability testing that has been
-performed on a given feature.
-
-
-
-1.2. Command Line Parameters
-----------------------------
-
-Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless
-2915ABG Driver for Linux allows configuration options to be provided
-as module parameters. The most common way to specify a module parameter
-is via the command line.
-
-The general form is::
-
- % modprobe ipw2200 parameter=value
-
-Where the supported parameter are:
-
- associate
- Set to 0 to disable the auto scan-and-associate functionality of the
- driver. If disabled, the driver will not attempt to scan
- for and associate to a network until it has been configured with
- one or more properties for the target network, for example configuring
- the network SSID. Default is 0 (do not auto-associate)
-
- Example: % modprobe ipw2200 associate=0
-
- auto_create
- Set to 0 to disable the auto creation of an Ad-Hoc network
- matching the channel and network name parameters provided.
- Default is 1.
-
- channel
- channel number for association. The normal method for setting
- the channel would be to use the standard wireless tools
- (i.e. `iwconfig eth1 channel 10`), but it is useful sometimes
- to set this while debugging. Channel 0 means 'ANY'
-
- debug
- If using a debug build, this is used to control the amount of debug
- info is logged. See the 'dvals' and 'load' script for more info on
- how to use this (the dvals and load scripts are provided as part
- of the ipw2200 development snapshot releases available from the
- SourceForge project at http://ipw2200.sf.net)
-
- led
- Can be used to turn on experimental LED code.
- 0 = Off, 1 = On. Default is 1.
-
- mode
- Can be used to set the default mode of the adapter.
- 0 = Managed, 1 = Ad-Hoc, 2 = Monitor
-
-
-1.3. Wireless Extension Private Methods
----------------------------------------
-
-As an interface designed to handle generic hardware, there are certain
-capabilities not exposed through the normal Wireless Tool interface. As
-such, a provision is provided for a driver to declare custom, or
-private, methods. The Intel(R) PRO/Wireless 2915ABG Driver for Linux
-defines several of these to configure various settings.
-
-The general form of using the private wireless methods is::
-
- % iwpriv $IFNAME method parameters
-
-Where $IFNAME is the interface name the device is registered with
-(typically eth1, customized via one of the various network interface
-name managers, such as ifrename)
-
-The supported private methods are:
-
- get_mode
- Can be used to report out which IEEE mode the driver is
- configured to support. Example:
-
- % iwpriv eth1 get_mode
- eth1 get_mode:802.11bg (6)
-
- set_mode
- Can be used to configure which IEEE mode the driver will
- support.
-
- Usage::
-
- % iwpriv eth1 set_mode {mode}
-
- Where {mode} is a number in the range 1-7:
-
- == =====================
- 1 802.11a (2915 only)
- 2 802.11b
- 3 802.11ab (2915 only)
- 4 802.11g
- 5 802.11ag (2915 only)
- 6 802.11bg
- 7 802.11abg (2915 only)
- == =====================
-
- get_preamble
- Can be used to report configuration of preamble length.
-
- set_preamble
- Can be used to set the configuration of preamble length:
-
- Usage::
-
- % iwpriv eth1 set_preamble {mode}
-
- Where {mode} is one of:
-
- == ========================================
- 1 Long preamble only
- 0 Auto (long or short based on connection)
- == ========================================
-
-
-1.4. Sysfs Helper Files
------------------------
-
-The Linux kernel provides a pseudo file system that can be used to
-access various components of the operating system. The Intel(R)
-PRO/Wireless 2915ABG Driver for Linux exposes several configuration
-parameters through this mechanism.
-
-An entry in the sysfs can support reading and/or writing. You can
-typically query the contents of a sysfs entry through the use of cat,
-and can set the contents via echo. For example::
-
- % cat /sys/bus/pci/drivers/ipw2200/debug_level
-
-Will report the current debug level of the driver's logging subsystem
-(only available if CONFIG_IPW2200_DEBUG was configured when the driver
-was built).
-
-You can set the debug level via::
-
- % echo $VALUE > /sys/bus/pci/drivers/ipw2200/debug_level
-
-Where $VALUE would be a number in the case of this sysfs entry. The
-input to sysfs files does not have to be a number. For example, the
-firmware loader used by hotplug utilizes sysfs entries for transferring
-the firmware image from user space into the driver.
-
-The Intel(R) PRO/Wireless 2915ABG Driver for Linux exposes sysfs entries
-at two levels -- driver level, which apply to all instances of the driver
-(in the event that there are more than one device installed) and device
-level, which applies only to the single specific instance.
-
-
-1.4.1 Driver Level Sysfs Helper Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-For the driver level files, look in /sys/bus/pci/drivers/ipw2200/
-
- debug_level
- This controls the same global as the 'debug' module parameter
-
-
-
-1.4.2 Device Level Sysfs Helper Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-For the device level files, look in::
-
- /sys/bus/pci/drivers/ipw2200/{PCI-ID}/
-
-For example:::
-
- /sys/bus/pci/drivers/ipw2200/0000:02:01.0
-
-For the device level files, see /sys/bus/pci/drivers/ipw2200:
-
- rf_kill
- read -
-
- == =========================================
- 0 RF kill not enabled (radio on)
- 1 SW based RF kill active (radio off)
- 2 HW based RF kill active (radio off)
- 3 Both HW and SW RF kill active (radio off)
- == =========================================
-
- write -
-
- == ==================================================
- 0 If SW based RF kill active, turn the radio back on
- 1 If radio is on, activate SW based RF kill
- == ==================================================
-
- .. note::
-
- If you enable the SW based RF kill and then toggle the HW
- based RF kill from ON -> OFF -> ON, the radio will NOT come back on
-
- ucode
- read-only access to the ucode version number
-
- led
- read -
-
- == =================
- 0 LED code disabled
- 1 LED code enabled
- == =================
-
- write -
-
- == ================
- 0 Disable LED code
- 1 Enable LED code
- == ================
-
-
- .. note::
-
- The LED code has been reported to hang some systems when
- running ifconfig and is therefore disabled by default.
-
-
-1.5. Supported channels
------------------------
-
-Upon loading the Intel(R) PRO/Wireless 2915ABG Driver for Linux, a
-message stating the detected geography code and the number of 802.11
-channels supported by the card will be displayed in the log.
-
-The geography code corresponds to a regulatory domain as shown in the
-table below.
-
- +------+----------------------------+--------------------+
- | | | Supported channels |
- | Code | Geography +----------+---------+
- | | | 802.11bg | 802.11a |
- +======+============================+==========+=========+
- | --- | Restricted | 11 | 0 |
- +------+----------------------------+----------+---------+
- | ZZF | Custom US/Canada | 11 | 8 |
- +------+----------------------------+----------+---------+
- | ZZD | Rest of World | 13 | 0 |
- +------+----------------------------+----------+---------+
- | ZZA | Custom USA & Europe & High | 11 | 13 |
- +------+----------------------------+----------+---------+
- | ZZB | Custom NA & Europe | 11 | 13 |
- +------+----------------------------+----------+---------+
- | ZZC | Custom Japan | 11 | 4 |
- +------+----------------------------+----------+---------+
- | ZZM | Custom | 11 | 0 |
- +------+----------------------------+----------+---------+
- | ZZE | Europe | 13 | 19 |
- +------+----------------------------+----------+---------+
- | ZZJ | Custom Japan | 14 | 4 |
- +------+----------------------------+----------+---------+
- | ZZR | Rest of World | 14 | 0 |
- +------+----------------------------+----------+---------+
- | ZZH | High Band | 13 | 4 |
- +------+----------------------------+----------+---------+
- | ZZG | Custom Europe | 13 | 4 |
- +------+----------------------------+----------+---------+
- | ZZK | Europe | 13 | 24 |
- +------+----------------------------+----------+---------+
- | ZZL | Europe | 11 | 13 |
- +------+----------------------------+----------+---------+
-
-2. Ad-Hoc Networking
-=====================
-
-When using a device in an Ad-Hoc network, it is useful to understand the
-sequence and requirements for the driver to be able to create, join, or
-merge networks.
-
-The following attempts to provide enough information so that you can
-have a consistent experience while using the driver as a member of an
-Ad-Hoc network.
-
-2.1. Joining an Ad-Hoc Network
-------------------------------
-
-The easiest way to get onto an Ad-Hoc network is to join one that
-already exists.
-
-2.2. Creating an Ad-Hoc Network
--------------------------------
-
-An Ad-Hoc networks is created using the syntax of the Wireless tool.
-
-For Example:
-iwconfig eth1 mode ad-hoc essid testing channel 2
-
-2.3. Merging Ad-Hoc Networks
-----------------------------
-
-
-3. Interaction with Wireless Tools
-==================================
-
-3.1 iwconfig mode
------------------
-
-When configuring the mode of the adapter, all run-time configured parameters
-are reset to the value used when the module was loaded. This includes
-channels, rates, ESSID, etc.
-
-3.2 iwconfig sens
------------------
-
-The 'iwconfig ethX sens XX' command will not set the signal sensitivity
-threshold, as described in iwconfig documentation, but rather the number
-of consecutive missed beacons that will trigger handover, i.e. roaming
-to another access point. At the same time, it will set the disassociation
-threshold to 3 times the given value.
-
-
-4. About the Version Numbers
-=============================
-
-Due to the nature of open source development projects, there are
-frequently changes being incorporated that have not gone through
-a complete validation process. These changes are incorporated into
-development snapshot releases.
-
-Releases are numbered with a three level scheme:
-
- major.minor.development
-
-Any version where the 'development' portion is 0 (for example
-1.0.0, 1.1.0, etc.) indicates a stable version that will be made
-available for kernel inclusion.
-
-Any version where the 'development' portion is not a 0 (for
-example 1.0.1, 1.1.5, etc.) indicates a development version that is
-being made available for testing and cutting edge users. The stability
-and functionality of the development releases are not know. We make
-efforts to try and keep all snapshots reasonably stable, but due to the
-frequency of their release, and the desire to get those releases
-available as quickly as possible, unknown anomalies should be expected.
-
-The major version number will be incremented when significant changes
-are made to the driver. Currently, there are no major changes planned.
-
-5. Firmware installation
-========================
-
-The driver requires a firmware image, download it and extract the
-files under /lib/firmware (or wherever your hotplug's firmware.agent
-will look for firmware files)
-
-The firmware can be downloaded from the following URL:
-
- http://ipw2200.sf.net/
-
-
-6. Support
-==========
-
-For direct support of the 1.0.0 version, you can contact
-http://supportmail.intel.com, or you can use the open source project
-support.
-
-For general information and support, go to:
-
- http://ipw2200.sf.net/
-
-
-7. License
-==========
-
- Copyright |copy| 2003 - 2006 Intel Corporation. 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.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- Contact Information:
-
- James P. Ketrenos <[email protected]>
-
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
diff --git a/MAINTAINERS b/MAINTAINERS
index 3a0e63038872b..9cf287971cd8c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10723,14 +10723,6 @@ M: David E. Box <[email protected]>
S: Supported
F: drivers/platform/x86/intel/pmt/

-INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
-M: Stanislav Yakovlev <[email protected]>
-L: [email protected]
-S: Maintained
-F: Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
-F: Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
-F: drivers/net/wireless/intel/ipw2x00/
-
INTEL PSTATE DRIVER
M: Srinivas Pandruvada <[email protected]>
M: Len Brown <[email protected]>
diff --git a/drivers/net/wireless/intel/Kconfig b/drivers/net/wireless/intel/Kconfig
index 3d1d7d11a3961..12c380ddb0cb0 100644
--- a/drivers/net/wireless/intel/Kconfig
+++ b/drivers/net/wireless/intel/Kconfig
@@ -12,7 +12,6 @@ config WLAN_VENDOR_INTEL

if WLAN_VENDOR_INTEL

-source "drivers/net/wireless/intel/ipw2x00/Kconfig"
source "drivers/net/wireless/intel/iwlegacy/Kconfig"
source "drivers/net/wireless/intel/iwlwifi/Kconfig"

diff --git a/drivers/net/wireless/intel/Makefile b/drivers/net/wireless/intel/Makefile
index 208e73a160519..6d5762d96f739 100644
--- a/drivers/net/wireless/intel/Makefile
+++ b/drivers/net/wireless/intel/Makefile
@@ -1,7 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_IPW2100) += ipw2x00/
-obj-$(CONFIG_IPW2200) += ipw2x00/
-
obj-$(CONFIG_IWLEGACY) += iwlegacy/

obj-$(CONFIG_IWLWIFI) += iwlwifi/
diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig
deleted file mode 100644
index 1650d5865aa02..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/Kconfig
+++ /dev/null
@@ -1,195 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Intel Centrino wireless drivers
-#
-
-config IPW2100
- tristate "Intel PRO/Wireless 2100 Network Connection"
- depends on PCI && CFG80211
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select LIB80211
- select LIBIPW
- help
- A driver for the Intel PRO/Wireless 2100 Network
- Connection 802.11b wireless network adapter.
-
- See <file:Documentation/networking/device_drivers/wifi/intel/ipw2100.rst>
- for information on the capabilities currently enabled in this driver
- and for tips for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2100.sf.net/>. Once you have the firmware image, you
- will need to place it in /lib/firmware.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2100_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2100
- help
- Enables promiscuous/monitor mode support for the ipw2100 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2100_DEBUG
- bool "Enable full debugging output in IPW2100 module."
- depends on IPW2100
- help
- This option will enable debug tracing output for the IPW2100.
-
- This will result in the kernel module being ~60k larger. You can
- control which debug output is sent to the kernel log by setting the
- value in
-
- /sys/bus/pci/drivers/ipw2100/debug_level
-
- This entry will only exist if this option is enabled.
-
- If you are not trying to debug or develop the IPW2100 driver, you
- most likely want to say N here.
-
-config IPW2200
- tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
- depends on PCI && CFG80211
- select CFG80211_WEXT_EXPORT
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select LIB80211
- select LIBIPW
- help
- A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
- Connection adapters.
-
- See <file:Documentation/networking/device_drivers/wifi/intel/ipw2200.rst>
- for information on the capabilities currently enabled in this
- driver and for tips for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2200.sf.net/>. See the above referenced README.ipw2200
- for information on where to install the firmware images.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2200_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2200
- help
- Enables promiscuous/monitor mode support for the ipw2200 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2200_RADIOTAP
- bool "Enable radiotap format 802.11 raw packet support"
- depends on IPW2200_MONITOR
-
-config IPW2200_PROMISCUOUS
- bool "Enable creation of a RF radiotap promiscuous interface"
- depends on IPW2200_MONITOR
- select IPW2200_RADIOTAP
- help
- Enables the creation of a second interface prefixed 'rtap'.
- This second interface will provide every received in radiotap
- format.
-
- This is useful for performing wireless network analysis while
- maintaining an active association.
-
- Example usage:
-
- % modprobe ipw2200 rtap_iface=1
- % ifconfig rtap0 up
- % tethereal -i rtap0
-
- If you do not specify 'rtap_iface=1' as a module parameter then
- the rtap interface will not be created and you will need to turn
- it on via sysfs:
-
- % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
-
-config IPW2200_QOS
- bool "Enable QoS support"
- depends on IPW2200
-
-config IPW2200_DEBUG
- bool "Enable full debugging output in IPW2200 module."
- depends on IPW2200
- help
- This option will enable low level debug tracing output for IPW2200.
-
- Note, normal debug code is already compiled in. This low level
- debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
- will result in the kernel module being ~70 larger. Most users
- will typically not need this high verbosity debug information.
-
- If you are not sure, say N here.
-
-config LIBIPW
- tristate
- depends on PCI && CFG80211
- select WIRELESS_EXT
- select WEXT_SPY
- select CRYPTO
- select CRYPTO_MICHAEL_MIC
- select CRC32
- select LIB80211
- select LIB80211_CRYPT_WEP
- select LIB80211_CRYPT_TKIP
- select LIB80211_CRYPT_CCMP
- help
- This option enables the hardware independent IEEE 802.11
- networking stack. This component is deprecated in favor of the
- mac80211 component.
-
-config LIBIPW_DEBUG
- bool "Full debugging output for the LIBIPW component"
- depends on LIBIPW
- help
- This option will enable debug tracing output for the
- libipw component.
-
- This will result in the kernel module being ~70k larger. You
- can control which debug output is sent to the kernel log by
- setting the value in
-
- /proc/net/ieee80211/debug_level
-
- For example:
-
- % echo 0x00000FFO > /proc/net/ieee80211/debug_level
-
- For a list of values you can assign to debug_level, you
- can look at the bit mask values in ieee80211.h
-
- If you are not trying to debug or develop the libipw
- component, you most likely want to say N here.
diff --git a/drivers/net/wireless/intel/ipw2x00/Makefile b/drivers/net/wireless/intel/ipw2x00/Makefile
deleted file mode 100644
index e1ec50359dffc..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the Intel Centrino wireless drivers
-#
-
-obj-$(CONFIG_IPW2100) += ipw2100.o
-obj-$(CONFIG_IPW2200) += ipw2200.o
-
-obj-$(CONFIG_LIBIPW) += libipw.o
-libipw-objs := \
- libipw_module.o \
- libipw_tx.o \
- libipw_rx.o \
- libipw_wx.o \
- libipw_geo.o
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw.h b/drivers/net/wireless/intel/ipw2x00/ipw.h
deleted file mode 100644
index 7b230a132daa7..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver
- *
- * Copyright 2012 Stanislav Yakovlev <[email protected]>
- */
-
-#ifndef __IPW_H__
-#define __IPW_H__
-
-#include <linux/ieee80211.h>
-
-static const u32 ipw_cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
-};
-
-#endif
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
deleted file mode 100644
index 0812db8936f13..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ /dev/null
@@ -1,8587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
- Portions of this file are based on the sample_* files provided by Wireless
- Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes
- <[email protected]>
-
- Portions of this file are based on the Host AP project,
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <[email protected]>
- Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
-
- Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
- ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
- available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox
-
-******************************************************************************/
-/*
-
- Initial driver on which this is based was developed by Janusz Gorycki,
- Maciej Urbaniak, and Maciej Sosnowski.
-
- Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak.
-
-Theory of Operation
-
-Tx - Commands and Data
-
-Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs)
-Each TBD contains a pointer to the physical (dma_addr_t) address of data being
-sent to the firmware as well as the length of the data.
-
-The host writes to the TBD queue at the WRITE index. The WRITE index points
-to the _next_ packet to be written and is advanced when after the TBD has been
-filled.
-
-The firmware pulls from the TBD queue at the READ index. The READ index points
-to the currently being read entry, and is advanced once the firmware is
-done with a packet.
-
-When data is sent to the firmware, the first TBD is used to indicate to the
-firmware if a Command or Data is being sent. If it is Command, all of the
-command information is contained within the physical address referred to by the
-TBD. If it is Data, the first TBD indicates the type of data packet, number
-of fragments, etc. The next TBD then refers to the actual packet location.
-
-The Tx flow cycle is as follows:
-
-1) ipw2100_tx() is called by kernel with SKB to transmit
-2) Packet is move from the tx_free_list and appended to the transmit pending
- list (tx_pend_list)
-3) work is scheduled to move pending packets into the shared circular queue.
-4) when placing packet in the circular queue, the incoming SKB is DMA mapped
- to a physical address. That address is entered into a TBD. Two TBDs are
- filled out. The first indicating a data packet, the second referring to the
- actual payload data.
-5) the packet is removed from tx_pend_list and placed on the end of the
- firmware pending list (fw_pend_list)
-6) firmware is notified that the WRITE index has
-7) Once the firmware has processed the TBD, INTA is triggered.
-8) For each Tx interrupt received from the firmware, the READ index is checked
- to see which TBDs are done being processed.
-9) For each TBD that has been processed, the ISR pulls the oldest packet
- from the fw_pend_list.
-10)The packet structure contained in the fw_pend_list is then used
- to unmap the DMA address and to free the SKB originally passed to the driver
- from the kernel.
-11)The packet structure is placed onto the tx_free_list
-
-The above steps are the same for commands, only the msg_free_list/msg_pend_list
-are used instead of tx_free_list/tx_pend_list
-
-...
-
-Critical Sections / Locking :
-
-There are two locks utilized. The first is the low level lock (priv->low_lock)
-that protects the following:
-
-- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows:
-
- tx_free_list : Holds pre-allocated Tx buffers.
- TAIL modified in __ipw2100_tx_process()
- HEAD modified in ipw2100_tx()
-
- tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring
- TAIL modified ipw2100_tx()
- HEAD modified by ipw2100_tx_send_data()
-
- msg_free_list : Holds pre-allocated Msg (Command) buffers
- TAIL modified in __ipw2100_tx_process()
- HEAD modified in ipw2100_hw_send_command()
-
- msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring
- TAIL modified in ipw2100_hw_send_command()
- HEAD modified in ipw2100_tx_send_commands()
-
- The flow of data on the TX side is as follows:
-
- MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST
- TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST
-
- The methods that work on the TBD ring are protected via priv->low_lock.
-
-- The internal data state of the device itself
-- Access to the firmware read/write indexes for the BD queues
- and associated logic
-
-All external entry functions are locked with the priv->action_lock to ensure
-that only one external action is invoked at a time.
-
-
-*/
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/stringify.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/firmware.h>
-#include <linux/acpi.h>
-#include <linux/ctype.h>
-#include <linux/pm_qos.h>
-
-#include <net/lib80211.h>
-
-#include "ipw2100.h"
-#include "ipw.h"
-
-#define IPW2100_VERSION "git-1.2.2"
-
-#define DRV_NAME "ipw2100"
-#define DRV_VERSION IPW2100_VERSION
-#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-
-static struct pm_qos_request ipw2100_pm_qos_req;
-
-/* Debugging stuff */
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW2100_RX_DEBUG /* Reception debugging */
-#endif
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-
-static int debug = 0;
-static int network_mode = 0;
-static int channel = 0;
-static int associate = 0;
-static int disable = 0;
-#ifdef CONFIG_PM
-static struct ipw2100_fw ipw2100_firmware;
-#endif
-
-#include <linux/moduleparam.h>
-module_param(debug, int, 0444);
-module_param_named(mode, network_mode, int, 0444);
-module_param(channel, int, 0444);
-module_param(associate, int, 0444);
-module_param(disable, int, 0444);
-
-MODULE_PARM_DESC(debug, "debug level");
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
-MODULE_PARM_DESC(channel, "channel");
-MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-
-static u32 ipw2100_debug_level = IPW_DL_NONE;
-
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW_DEBUG(level, message...) \
-do { \
- if (ipw2100_debug_level & (level)) { \
- printk(KERN_DEBUG "ipw2100: %s ", __func__); \
- printk(message); \
- } \
-} while (0)
-#else
-#define IPW_DEBUG(level, message...) do {} while (0)
-#endif /* CONFIG_IPW2100_DEBUG */
-
-#ifdef CONFIG_IPW2100_DEBUG
-static const char *command_types[] = {
- "undefined",
- "unused", /* HOST_ATTENTION */
- "HOST_COMPLETE",
- "unused", /* SLEEP */
- "unused", /* HOST_POWER_DOWN */
- "unused",
- "SYSTEM_CONFIG",
- "unused", /* SET_IMR */
- "SSID",
- "MANDATORY_BSSID",
- "AUTHENTICATION_TYPE",
- "ADAPTER_ADDRESS",
- "PORT_TYPE",
- "INTERNATIONAL_MODE",
- "CHANNEL",
- "RTS_THRESHOLD",
- "FRAG_THRESHOLD",
- "POWER_MODE",
- "TX_RATES",
- "BASIC_TX_RATES",
- "WEP_KEY_INFO",
- "unused",
- "unused",
- "unused",
- "unused",
- "WEP_KEY_INDEX",
- "WEP_FLAGS",
- "ADD_MULTICAST",
- "CLEAR_ALL_MULTICAST",
- "BEACON_INTERVAL",
- "ATIM_WINDOW",
- "CLEAR_STATISTICS",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "TX_POWER_INDEX",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "BROADCAST_SCAN",
- "CARD_DISABLE",
- "PREFERRED_BSSID",
- "SET_SCAN_OPTIONS",
- "SCAN_DWELL_TIME",
- "SWEEP_TABLE",
- "AP_OR_STATION_TABLE",
- "GROUP_ORDINALS",
- "SHORT_RETRY_LIMIT",
- "LONG_RETRY_LIMIT",
- "unused", /* SAVE_CALIBRATION */
- "unused", /* RESTORE_CALIBRATION */
- "undefined",
- "undefined",
- "undefined",
- "HOST_PRE_POWER_DOWN",
- "unused", /* HOST_INTERRUPT_COALESCING */
- "undefined",
- "CARD_DISABLE_PHY_OFF",
- "MSDU_TX_RATES",
- "undefined",
- "SET_STATION_STAT_BITS",
- "CLEAR_STATIONS_STAT_BITS",
- "LEAP_ROGUE_MODE",
- "SET_SECURITY_INFORMATION",
- "DISASSOCIATION_BSSID",
- "SET_WPA_ASS_IE"
-};
-#endif
-
-static const long ipw2100_frequencies[] = {
- 2412, 2417, 2422, 2427,
- 2432, 2437, 2442, 2447,
- 2452, 2457, 2462, 2467,
- 2472, 2484
-};
-
-#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
-
-static struct ieee80211_rate ipw2100_bg_rates[] = {
- { .bitrate = 10 },
- { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-};
-
-#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
-
-/* Pre-decl until we get the code solid and then we can clean it up */
-static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
-static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
-static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
-
-static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
-static void ipw2100_queues_free(struct ipw2100_priv *priv);
-static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
-
-static int ipw2100_fw_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_get_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
- size_t max);
-static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
- size_t max);
-static void ipw2100_release_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_ucode_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static void ipw2100_wx_event_work(struct work_struct *work);
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
-static const struct iw_handler_def ipw2100_wx_handler_def;
-
-static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread32(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
-}
-
-static inline void write_register(struct net_device *dev, u32 reg, u32 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite32(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
-}
-
-static inline void read_register_word(struct net_device *dev, u32 reg,
- u16 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread16(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
-}
-
-static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread8(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
-}
-
-static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite16(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
-}
-
-static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite8(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
-}
-
-static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
- const u8 * buf)
-{
- u32 aligned_addr;
- u32 aligned_len;
- u32 dif_len;
- u32 i;
-
- /* read first nibble byte by byte */
- aligned_addr = addr & (~0x3);
- dif_len = addr - aligned_addr;
- if (dif_len) {
- /* Start reading at aligned_addr + dif_len */
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- write_register_byte(dev,
- IPW_REG_INDIRECT_ACCESS_DATA + i,
- *buf);
-
- len -= dif_len;
- aligned_addr += 4;
- }
-
- /* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
- aligned_len = len & (~0x3);
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
-
- /* copy the last nibble */
- dif_len = len - aligned_len;
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
- *buf);
-}
-
-static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
- u8 * buf)
-{
- u32 aligned_addr;
- u32 aligned_len;
- u32 dif_len;
- u32 i;
-
- /* read first nibble byte by byte */
- aligned_addr = addr & (~0x3);
- dif_len = addr - aligned_addr;
- if (dif_len) {
- /* Start reading at aligned_addr + dif_len */
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- read_register_byte(dev,
- IPW_REG_INDIRECT_ACCESS_DATA + i,
- buf);
-
- len -= dif_len;
- aligned_addr += 4;
- }
-
- /* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
- aligned_len = len & (~0x3);
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
-
- /* copy the last nibble */
- dif_len = len - aligned_len;
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
-}
-
-static bool ipw2100_hw_is_adapter_in_system(struct net_device *dev)
-{
- u32 dbg;
-
- read_register(dev, IPW_REG_DOA_DEBUG_AREA_START, &dbg);
-
- return dbg == IPW_DATA_DOA_DEBUG_VALUE;
-}
-
-static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
- void *val, u32 * len)
-{
- struct ipw2100_ordinals *ordinals = &priv->ordinals;
- u32 addr;
- u32 field_info;
- u16 field_len;
- u16 field_count;
- u32 total_length;
-
- if (ordinals->table1_addr == 0) {
- printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
- "before they have been loaded.\n");
- return -EINVAL;
- }
-
- if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
- if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- printk(KERN_WARNING DRV_NAME
- ": ordinal buffer length too small, need %zd\n",
- IPW_ORD_TAB_1_ENTRY_SIZE);
-
- return -EINVAL;
- }
-
- read_nic_dword(priv->net_dev,
- ordinals->table1_addr + (ord << 2), &addr);
- read_nic_dword(priv->net_dev, addr, val);
-
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- return 0;
- }
-
- if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
-
- ord -= IPW_START_ORD_TAB_2;
-
- /* get the address of statistic */
- read_nic_dword(priv->net_dev,
- ordinals->table2_addr + (ord << 3), &addr);
-
- /* get the second DW of statistics ;
- * two 16-bit words - first is length, second is count */
- read_nic_dword(priv->net_dev,
- ordinals->table2_addr + (ord << 3) + sizeof(u32),
- &field_info);
-
- /* get each entry length */
- field_len = *((u16 *) & field_info);
-
- /* get number of entries */
- field_count = *(((u16 *) & field_info) + 1);
-
- /* abort if no enough memory */
- total_length = field_len * field_count;
- if (total_length > *len) {
- *len = total_length;
- return -EINVAL;
- }
-
- *len = total_length;
- if (!total_length)
- return 0;
-
- /* read the ordinal data from the SRAM */
- read_nic_memory(priv->net_dev, addr, total_length, val);
-
- return 0;
- }
-
- printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
- "in table 2\n", ord);
-
- return -EINVAL;
-}
-
-static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
- u32 * len)
-{
- struct ipw2100_ordinals *ordinals = &priv->ordinals;
- u32 addr;
-
- if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
- if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
- IPW_DEBUG_INFO("wrong size\n");
- return -EINVAL;
- }
-
- read_nic_dword(priv->net_dev,
- ordinals->table1_addr + (ord << 2), &addr);
-
- write_nic_dword(priv->net_dev, addr, *val);
-
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- return 0;
- }
-
- IPW_DEBUG_INFO("wrong table\n");
- if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
- return -EINVAL;
-
- return -EINVAL;
-}
-
-static char *snprint_line(char *buf, size_t count,
- const u8 * data, u32 len, u32 ofs)
-{
- int out, i, j, l;
- char c;
-
- out = scnprintf(buf, count, "%08X", ofs);
-
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++)
- out += scnprintf(buf + out, count - out, "%02X ",
- data[(i * 8 + j)]);
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- out += scnprintf(buf + out, count - out, " ");
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++) {
- c = data[(i * 8 + j)];
- if (!isascii(c) || !isprint(c))
- c = '.';
-
- out += scnprintf(buf + out, count - out, "%c", c);
- }
-
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- return buf;
-}
-
-static void printk_buf(int level, const u8 * data, u32 len)
-{
- char line[81];
- u32 ofs = 0;
- if (!(ipw2100_debug_level & level))
- return;
-
- while (len) {
- printk(KERN_DEBUG "%s\n",
- snprint_line(line, sizeof(line), &data[ofs],
- min(len, 16U), ofs));
- ofs += 16;
- len -= min(len, 16U);
- }
-}
-
-#define MAX_RESET_BACKOFF 10
-
-static void schedule_reset(struct ipw2100_priv *priv)
-{
- time64_t now = ktime_get_boottime_seconds();
-
- /* If we haven't received a reset request within the backoff period,
- * then we can reset the backoff interval so this reset occurs
- * immediately */
- if (priv->reset_backoff &&
- (now - priv->last_reset > priv->reset_backoff))
- priv->reset_backoff = 0;
-
- priv->last_reset = now;
-
- if (!(priv->status & STATUS_RESET_PENDING)) {
- IPW_DEBUG_INFO("%s: Scheduling firmware restart (%llds).\n",
- priv->net_dev->name, priv->reset_backoff);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
- priv->status |= STATUS_RESET_PENDING;
- if (priv->reset_backoff)
- schedule_delayed_work(&priv->reset_work,
- priv->reset_backoff * HZ);
- else
- schedule_delayed_work(&priv->reset_work, 0);
-
- if (priv->reset_backoff < MAX_RESET_BACKOFF)
- priv->reset_backoff++;
-
- wake_up_interruptible(&priv->wait_command_queue);
- } else
- IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
- priv->net_dev->name);
-
-}
-
-#define HOST_COMPLETE_TIMEOUT (2 * HZ)
-static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
- struct host_command *cmd)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- unsigned long flags;
- int err = 0;
-
- IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
- command_types[cmd->host_command], cmd->host_command,
- cmd->host_command_length);
- printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
- cmd->host_command_length);
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->fatal_error) {
- IPW_DEBUG_INFO
- ("Attempt to send command while hardware in fatal error condition.\n");
- err = -EIO;
- goto fail_unlock;
- }
-
- if (!(priv->status & STATUS_RUNNING)) {
- IPW_DEBUG_INFO
- ("Attempt to send command while hardware is not running.\n");
- err = -EIO;
- goto fail_unlock;
- }
-
- if (priv->status & STATUS_CMD_ACTIVE) {
- IPW_DEBUG_INFO
- ("Attempt to send command while another command is pending.\n");
- err = -EBUSY;
- goto fail_unlock;
- }
-
- if (list_empty(&priv->msg_free_list)) {
- IPW_DEBUG_INFO("no available msg buffers\n");
- goto fail_unlock;
- }
-
- priv->status |= STATUS_CMD_ACTIVE;
- priv->messages_sent++;
-
- element = priv->msg_free_list.next;
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
- packet->jiffy_start = jiffies;
-
- /* initialize the firmware command packet */
- packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
- packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
- packet->info.c_struct.cmd->host_command_len_reg =
- cmd->host_command_length;
- packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
-
- memcpy(packet->info.c_struct.cmd->host_command_params_reg,
- cmd->host_command_parameters,
- sizeof(packet->info.c_struct.cmd->host_command_params_reg));
-
- list_del(element);
- DEC_STAT(&priv->msg_free_stat);
-
- list_add_tail(element, &priv->msg_pend_list);
- INC_STAT(&priv->msg_pend_stat);
-
- ipw2100_tx_send_commands(priv);
- ipw2100_tx_send_data(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- /*
- * We must wait for this command to complete before another
- * command can be sent... but if we wait more than 3 seconds
- * then there is a problem.
- */
-
- err =
- wait_event_interruptible_timeout(priv->wait_command_queue,
- !(priv->
- status & STATUS_CMD_ACTIVE),
- HOST_COMPLETE_TIMEOUT);
-
- if (err == 0) {
- IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
- 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
- priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
- priv->status &= ~STATUS_CMD_ACTIVE;
- schedule_reset(priv);
- return -EIO;
- }
-
- if (priv->fatal_error) {
- printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* !!!!! HACK TEST !!!!!
- * When lots of debug trace statements are enabled, the driver
- * doesn't seem to have as many firmware restart cycles...
- *
- * As a test, we're sticking in a 1/100s delay here */
- schedule_timeout_uninterruptible(msecs_to_jiffies(10));
-
- return 0;
-
- fail_unlock:
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- return err;
-}
-
-/*
- * Verify the values and data access of the hardware
- * No locks needed or used. No functions called.
- */
-static int ipw2100_verify(struct ipw2100_priv *priv)
-{
- u32 data1, data2;
- u32 address;
-
- u32 val1 = 0x76543210;
- u32 val2 = 0xFEDCBA98;
-
- /* Domain 0 check - all values should be DOA_DEBUG */
- for (address = IPW_REG_DOA_DEBUG_AREA_START;
- address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
- read_register(priv->net_dev, address, &data1);
- if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
- return -EIO;
- }
-
- /* Domain 1 check - use arbitrary read/write compare */
- for (address = 0; address < 5; address++) {
- /* The memory area is not used now */
- write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
- val1);
- write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
- val2);
- read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
- &data1);
- read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
- &data2);
- if (val1 == data1 && val2 == data2)
- return 0;
- }
-
- return -EIO;
-}
-
-/*
- *
- * Loop until the CARD_DISABLED bit is the same value as the
- * supplied parameter
- *
- * TODO: See if it would be more efficient to do a wait/wake
- * cycle and have the completion event trigger the wakeup
- *
- */
-#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
-static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
-{
- int i;
- u32 card_state;
- u32 len = sizeof(card_state);
- int err;
-
- for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
- err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
- &card_state, &len);
- if (err) {
- IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
- "failed.\n");
- return 0;
- }
-
- /* We'll break out if either the HW state says it is
- * in the state we want, or if HOST_COMPLETE command
- * finishes */
- if ((card_state == state) ||
- ((priv->status & STATUS_ENABLED) ?
- IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
- if (state == IPW_HW_STATE_ENABLED)
- priv->status |= STATUS_ENABLED;
- else
- priv->status &= ~STATUS_ENABLED;
-
- return 0;
- }
-
- udelay(50);
- }
-
- IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
- state ? "DISABLED" : "ENABLED");
- return -EIO;
-}
-
-/*********************************************************************
- Procedure : sw_reset_and_clock
- Purpose : Asserts s/w reset, asserts clock initialization
- and waits for clock stabilization
- ********************************************************************/
-static int sw_reset_and_clock(struct ipw2100_priv *priv)
-{
- int i;
- u32 r;
-
- // assert s/w reset
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- // wait for clock stabilization
- for (i = 0; i < 1000; i++) {
- udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
-
- // check clock ready bit
- read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
- if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
- break;
- }
-
- if (i == 1000)
- return -EIO; // TODO: better error value
-
- /* set "initialization complete" bit to move adapter to
- * D0 state */
- write_register(priv->net_dev, IPW_REG_GP_CNTRL,
- IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
-
- /* wait for clock stabilization */
- for (i = 0; i < 10000; i++) {
- udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
-
- /* check clock ready bit */
- read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
- if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
- break;
- }
-
- if (i == 10000)
- return -EIO; /* TODO: better error value */
-
- /* set D0 standby bit */
- read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
- write_register(priv->net_dev, IPW_REG_GP_CNTRL,
- r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
-
- return 0;
-}
-
-/*********************************************************************
- Procedure : ipw2100_download_firmware
- Purpose : Initiaze adapter after power on.
- The sequence is:
- 1. assert s/w reset first!
- 2. awake clocks & wait for clock stabilization
- 3. hold ARC (don't ask me why...)
- 4. load Dino ucode and reset/clock init again
- 5. zero-out shared mem
- 6. download f/w
- *******************************************************************/
-static int ipw2100_download_firmware(struct ipw2100_priv *priv)
-{
- u32 address;
- int err;
-
-#ifndef CONFIG_PM
- /* Fetch the firmware and microcode */
- struct ipw2100_fw ipw2100_firmware;
-#endif
-
- if (priv->fatal_error) {
- IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
- "fatal error %d. Interface must be brought down.\n",
- priv->net_dev->name, priv->fatal_error);
- return -EINVAL;
- }
-#ifdef CONFIG_PM
- if (!ipw2100_firmware.version) {
- err = ipw2100_get_firmware(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
- priv->fatal_error = IPW2100_ERR_FW_LOAD;
- goto fail;
- }
- }
-#else
- err = ipw2100_get_firmware(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
- priv->fatal_error = IPW2100_ERR_FW_LOAD;
- goto fail;
- }
-#endif
- priv->firmware_version = ipw2100_firmware.version;
-
- /* s/w reset and clock stabilization */
- err = sw_reset_and_clock(priv);
- if (err) {
- IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- err = ipw2100_verify(priv);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* Hold ARC */
- write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
-
- /* allow ARC to run */
- write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
-
- /* load microcode */
- err = ipw2100_ucode_download(priv, &ipw2100_firmware);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* release ARC */
- write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
-
- /* s/w reset and clock stabilization (again!!!) */
- err = sw_reset_and_clock(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: sw_reset_and_clock failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* load f/w */
- err = ipw2100_fw_download(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-#ifndef CONFIG_PM
- /*
- * When the .resume method of the driver is called, the other
- * part of the system, i.e. the ide driver could still stay in
- * the suspend stage. This prevents us from loading the firmware
- * from the disk. --YZ
- */
-
- /* free any storage allocated for firmware image */
- ipw2100_release_firmware(priv, &ipw2100_firmware);
-#endif
-
- /* zero out Domain 1 area indirectly (Si requirement) */
- for (address = IPW_HOST_FW_SHARED_AREA0;
- address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA1;
- address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA2;
- address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA3;
- address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_INTERRUPT_AREA;
- address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
-
- return 0;
-
- fail:
- ipw2100_release_firmware(priv, &ipw2100_firmware);
- return err;
-}
-
-static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
-{
- if (priv->status & STATUS_INT_ENABLED)
- return;
- priv->status |= STATUS_INT_ENABLED;
- write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
-}
-
-static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
-{
- if (!(priv->status & STATUS_INT_ENABLED))
- return;
- priv->status &= ~STATUS_INT_ENABLED;
- write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
-}
-
-static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
-{
- struct ipw2100_ordinals *ord = &priv->ordinals;
-
- IPW_DEBUG_INFO("enter\n");
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
- &ord->table1_addr);
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
- &ord->table2_addr);
-
- read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
- read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
-
- ord->table2_size &= 0x0000FFFF;
-
- IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
- IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
- IPW_DEBUG_INFO("exit\n");
-}
-
-static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
-{
- u32 reg = 0;
- /*
- * Set GPIO 3 writable by FW; GPIO 1 writable
- * by driver and enable clock
- */
- reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
- IPW_BIT_GPIO_LED_OFF);
- write_register(priv->net_dev, IPW_REG_GPIO, reg);
-}
-
-static int rf_kill_active(struct ipw2100_priv *priv)
-{
-#define MAX_RF_KILL_CHECKS 5
-#define RF_KILL_CHECK_DELAY 40
-
- unsigned short value = 0;
- u32 reg = 0;
- int i;
-
- if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- priv->status &= ~STATUS_RF_KILL_HW;
- return 0;
- }
-
- for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
- udelay(RF_KILL_CHECK_DELAY);
- read_register(priv->net_dev, IPW_REG_GPIO, &reg);
- value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
- }
-
- if (value == 0) {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- priv->status |= STATUS_RF_KILL_HW;
- } else {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- priv->status &= ~STATUS_RF_KILL_HW;
- }
-
- return (value == 0);
-}
-
-static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
-{
- u32 addr, len;
- u32 val;
-
- /*
- * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
- */
- len = sizeof(addr);
- if (ipw2100_get_ordinal
- (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return -EIO;
- }
-
- IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
-
- /*
- * EEPROM version is the byte at offset 0xfd in firmware
- * We read 4 bytes, then shift out the byte we actually want */
- read_nic_dword(priv->net_dev, addr + 0xFC, &val);
- priv->eeprom_version = (val >> 24) & 0xFF;
- IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
-
- /*
- * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
- *
- * notice that the EEPROM bit is reverse polarity, i.e.
- * bit = 0 signifies HW RF kill switch is supported
- * bit = 1 signifies HW RF kill switch is NOT supported
- */
- read_nic_dword(priv->net_dev, addr + 0x20, &val);
- if (!((val >> 24) & 0x01))
- priv->hw_features |= HW_FEATURE_RFKILL;
-
- IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
- (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
-
- return 0;
-}
-
-/*
- * Start firmware execution after power on and initialization
- * The sequence is:
- * 1. Release ARC
- * 2. Wait for f/w initialization completes;
- */
-static int ipw2100_start_adapter(struct ipw2100_priv *priv)
-{
- int i;
- u32 inta, inta_mask, gpio;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->status & STATUS_RUNNING)
- return 0;
-
- /*
- * Initialize the hw - drive adapter to DO state by setting
- * init_done bit. Wait for clk_ready bit and Download
- * fw & dino ucode
- */
- if (ipw2100_download_firmware(priv)) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to power on the adapter.\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* Clear the Tx, Rx and Msg queues and the r/w indexes
- * in the firmware RBD and TBD ring queue */
- ipw2100_queues_initialize(priv);
-
- ipw2100_hw_set_gpio(priv);
-
- /* TODO -- Look at disabling interrupts here to make sure none
- * get fired during FW initialization */
-
- /* Release ARC - clear reset bit */
- write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
-
- /* wait for f/w initialization complete */
- IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
- i = 5000;
- do {
- schedule_timeout_uninterruptible(msecs_to_jiffies(40));
- /* Todo... wait for sync command ... */
-
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
-
- /* check "init done" bit */
- if (inta & IPW2100_INTA_FW_INIT_DONE) {
- /* reset "init done" bit */
- write_register(priv->net_dev, IPW_REG_INTA,
- IPW2100_INTA_FW_INIT_DONE);
- break;
- }
-
- /* check error conditions : we check these after the firmware
- * check so that if there is an error, the interrupt handler
- * will see it and the adapter will be reset */
- if (inta &
- (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
- /* clear error conditions */
- write_register(priv->net_dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR);
- }
- } while (--i);
-
- /* Clear out any pending INTAs since we aren't supposed to have
- * interrupts enabled at this point... */
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
- read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
- inta &= IPW_INTERRUPT_MASK;
- /* Clear out any pending interrupts */
- if (inta & inta_mask)
- write_register(priv->net_dev, IPW_REG_INTA, inta);
-
- IPW_DEBUG_FW("f/w initialization complete: %s\n",
- i ? "SUCCESS" : "FAILED");
-
- if (!i) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Firmware did not initialize.\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* allow firmware to write to GPIO1 & GPIO3 */
- read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
-
- gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
-
- write_register(priv->net_dev, IPW_REG_GPIO, gpio);
-
- /* Ready to receive commands */
- priv->status |= STATUS_RUNNING;
-
- /* The adapter has been reset; we are not associated */
- priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
-{
- if (!priv->fatal_error)
- return;
-
- priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
- priv->fatal_index %= IPW2100_ERROR_QUEUE;
- priv->fatal_error = 0;
-}
-
-/* NOTE: Our interrupt is disabled when this method is called */
-static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
-{
- u32 reg;
- int i;
-
- IPW_DEBUG_INFO("Power cycling the hardware.\n");
-
- ipw2100_hw_set_gpio(priv);
-
- /* Step 1. Stop Master Assert */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
-
- /* Step 2. Wait for stop Master Assert
- * (not more than 50us, otherwise ret error */
- i = 5;
- do {
- udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
- read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- } while (--i);
-
- priv->status &= ~STATUS_RESET_PENDING;
-
- if (!i) {
- IPW_DEBUG_INFO
- ("exit - waited too long for master assert stop\n");
- return -EIO;
- }
-
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- /* Reset any fatal_error conditions */
- ipw2100_reset_fatalerror(priv);
-
- /* At this point, the adapter is now stopped and disabled */
- priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
- STATUS_ASSOCIATED | STATUS_ENABLED);
-
- return 0;
-}
-
-/*
- * Send the CARD_DISABLE_PHY_OFF command to the card to disable it
- *
- * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
- *
- * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
- * if STATUS_ASSN_LOST is sent.
- */
-static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
-{
-
-#define HW_PHY_OFF_LOOP_DELAY (msecs_to_jiffies(50))
-
- struct host_command cmd = {
- .host_command = CARD_DISABLE_PHY_OFF,
- .host_command_sequence = 0,
- .host_command_length = 0,
- };
- int err, i;
- u32 val1, val2;
-
- IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
-
- /* Turn off the radio */
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- for (i = 0; i < 2500; i++) {
- read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
- read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
-
- if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
- (val2 & IPW2100_COMMAND_PHY_OFF))
- return 0;
-
- schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
- }
-
- return -EIO;
-}
-
-static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = HOST_COMPLETE,
- .host_command_sequence = 0,
- .host_command_length = 0
- };
- int err = 0;
-
- IPW_DEBUG_HC("HOST_COMPLETE\n");
-
- if (priv->status & STATUS_ENABLED)
- return 0;
-
- mutex_lock(&priv->adapter_mutex);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
- goto fail_up;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
- goto fail_up;
- }
-
- err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
- if (err) {
- IPW_DEBUG_INFO("%s: card not responding to init command.\n",
- priv->net_dev->name);
- goto fail_up;
- }
-
- if (priv->stop_hang_check) {
- priv->stop_hang_check = 0;
- schedule_delayed_work(&priv->hang_check, HZ / 2);
- }
-
- fail_up:
- mutex_unlock(&priv->adapter_mutex);
- return err;
-}
-
-static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
-{
-#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
-
- struct host_command cmd = {
- .host_command = HOST_PRE_POWER_DOWN,
- .host_command_sequence = 0,
- .host_command_length = 0,
- };
- int err, i;
- u32 reg;
-
- if (!(priv->status & STATUS_RUNNING))
- return 0;
-
- priv->status |= STATUS_STOPPING;
-
- /* We can only shut down the card if the firmware is operational. So,
- * if we haven't reset since a fatal_error, then we can not send the
- * shutdown commands. */
- if (!priv->fatal_error) {
- /* First, make sure the adapter is enabled so that the PHY_OFF
- * command can shut it down */
- ipw2100_enable_adapter(priv);
-
- err = ipw2100_hw_phy_off(priv);
- if (err)
- printk(KERN_WARNING DRV_NAME
- ": Error disabling radio %d\n", err);
-
- /*
- * If in D0-standby mode going directly to D3 may cause a
- * PCI bus violation. Therefore we must change out of the D0
- * state.
- *
- * Sending the PREPARE_FOR_POWER_DOWN will restrict the
- * hardware from going into standby mode and will transition
- * out of D0-standby if it is already in that state.
- *
- * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
- * driver upon completion. Once received, the driver can
- * proceed to the D3 state.
- *
- * Prepare for power down command to fw. This command would
- * take HW out of D0-standby and prepare it for D3 state.
- *
- * Currently FW does not support event notification for this
- * event. Therefore, skip waiting for it. Just wait a fixed
- * 100ms
- */
- IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Power down command failed: Error %d\n",
- priv->net_dev->name, err);
- else
- schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
- }
-
- priv->status &= ~STATUS_ENABLED;
-
- /*
- * Set GPIO 3 writable by FW; GPIO 1 writable
- * by driver and enable clock
- */
- ipw2100_hw_set_gpio(priv);
-
- /*
- * Power down adapter. Sequence:
- * 1. Stop master assert (RESET_REG[9]=1)
- * 2. Wait for stop master (RESET_REG[8]==1)
- * 3. S/w reset assert (RESET_REG[7] = 1)
- */
-
- /* Stop master assert */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
-
- /* wait stop master not more than 50 usec.
- * Otherwise return error. */
- for (i = 5; i > 0; i--) {
- udelay(10);
-
- /* Check master stop bit */
- read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- }
-
- if (i == 0)
- printk(KERN_WARNING DRV_NAME
- ": %s: Could now power down adapter.\n",
- priv->net_dev->name);
-
- /* assert s/w reset */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
-
- return 0;
-}
-
-static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = CARD_DISABLE,
- .host_command_sequence = 0,
- .host_command_length = 0
- };
- int err = 0;
-
- IPW_DEBUG_HC("CARD_DISABLE\n");
-
- if (!(priv->status & STATUS_ENABLED))
- return 0;
-
- /* Make sure we clear the associated state */
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
-
- if (!priv->stop_hang_check) {
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
- }
-
- mutex_lock(&priv->adapter_mutex);
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": exit - failed to send CARD_DISABLE command\n");
- goto fail_up;
- }
-
- err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": exit - card failed to change to DISABLED\n");
- goto fail_up;
- }
-
- IPW_DEBUG_INFO("TODO: implement scan state machine\n");
-
- fail_up:
- mutex_unlock(&priv->adapter_mutex);
- return err;
-}
-
-static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = SET_SCAN_OPTIONS,
- .host_command_sequence = 0,
- .host_command_length = 8
- };
- int err;
-
- IPW_DEBUG_INFO("enter\n");
-
- IPW_DEBUG_SCAN("setting scan options\n");
-
- cmd.host_command_parameters[0] = 0;
-
- if (!(priv->config & CFG_ASSOCIATE))
- cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
- if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
- cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
- if (priv->config & CFG_PASSIVE_SCAN)
- cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
-
- cmd.host_command_parameters[1] = priv->channel_mask;
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
- cmd.host_command_parameters[0]);
-
- return err;
-}
-
-static int ipw2100_start_scan(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = BROADCAST_SCAN,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- IPW_DEBUG_HC("START_SCAN\n");
-
- cmd.host_command_parameters[0] = 0;
-
- /* No scanning if in monitor mode */
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- return 1;
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
- return 0;
- }
-
- IPW_DEBUG_INFO("enter\n");
-
- /* Not clearing here; doing so makes iwlist always return nothing...
- *
- * We should modify the table logic to use aging tables vs. clearing
- * the table on each scan start.
- */
- IPW_DEBUG_SCAN("starting scan\n");
-
- priv->status |= STATUS_SCANNING;
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- priv->status &= ~STATUS_SCANNING;
-
- IPW_DEBUG_INFO("exit\n");
-
- return err;
-}
-
-static const struct libipw_geo ipw_geos[] = {
- { /* Restricted */
- "---",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14}},
- },
-};
-
-static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
-{
- unsigned long flags;
- int err = 0;
- u32 lock;
- u32 ord_len = sizeof(lock);
-
- /* Age scan list entries found before suspend */
- if (priv->suspend_time) {
- libipw_networks_age(priv->ieee, priv->suspend_time);
- priv->suspend_time = 0;
- }
-
- /* Quiet if manually disabled. */
- if (priv->status & STATUS_RF_KILL_SW) {
- IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
- "switch\n", priv->net_dev->name);
- return 0;
- }
-
- /* the ipw2100 hardware really doesn't want power management delays
- * longer than 175usec
- */
- cpu_latency_qos_update_request(&ipw2100_pm_qos_req, 175);
-
- /* If the interrupt is enabled, turn it off... */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
-
- /* Reset any fatal_error conditions */
- ipw2100_reset_fatalerror(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- if (priv->status & STATUS_POWERED ||
- (priv->status & STATUS_RESET_PENDING)) {
- /* Power cycle the card ... */
- err = ipw2100_power_cycle_adapter(priv);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Could not cycle adapter.\n",
- priv->net_dev->name);
- goto exit;
- }
- } else
- priv->status |= STATUS_POWERED;
-
- /* Load the firmware, start the clocks, etc. */
- err = ipw2100_start_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to start the firmware.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- ipw2100_initialize_ordinals(priv);
-
- /* Determine capabilities of this particular HW configuration */
- err = ipw2100_get_hw_features(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to determine HW features.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- /* Initialize the geo */
- libipw_set_geo(priv->ieee, &ipw_geos[0]);
- priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
-
- lock = LOCK_NONE;
- err = ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to clear ordinal lock.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- priv->status &= ~STATUS_SCANNING;
-
- if (rf_kill_active(priv)) {
- printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
- priv->net_dev->name);
-
- if (priv->stop_rf_kill) {
- priv->stop_rf_kill = 0;
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(HZ));
- }
-
- deferred = 1;
- }
-
- /* Turn on the interrupt so that commands can be processed */
- ipw2100_enable_interrupts(priv);
-
- /* Send all of the commands that must be sent prior to
- * HOST_COMPLETE */
- err = ipw2100_adapter_setup(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- if (!deferred) {
- /* Enable the adapter - sends HOST_COMPLETE */
- err = ipw2100_enable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: failed in call to enable adapter.\n",
- priv->net_dev->name);
- ipw2100_hw_stop_adapter(priv);
- goto exit;
- }
-
- /* Start a scan . . . */
- ipw2100_set_scan_options(priv);
- ipw2100_start_scan(priv);
- }
-
- exit:
- return err;
-}
-
-static void ipw2100_down(struct ipw2100_priv *priv)
-{
- unsigned long flags;
- union iwreq_data wrqu = {
- .ap_addr = {
- .sa_family = ARPHRD_ETHER}
- };
- int associated = priv->status & STATUS_ASSOCIATED;
-
- /* Kill the RF switch timer */
- if (!priv->stop_rf_kill) {
- priv->stop_rf_kill = 1;
- cancel_delayed_work(&priv->rf_kill);
- }
-
- /* Kill the firmware hang check timer */
- if (!priv->stop_hang_check) {
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
- }
-
- /* Kill any pending resets */
- if (priv->status & STATUS_RESET_PENDING)
- cancel_delayed_work(&priv->reset_work);
-
- /* Make sure the interrupt is on so that FW commands will be
- * processed correctly */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- if (ipw2100_hw_stop_adapter(priv))
- printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
- priv->net_dev->name);
-
- /* Do not disable the interrupt until _after_ we disable
- * the adaptor. Otherwise the CARD_DISABLE command will never
- * be ack'd by the firmware */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- cpu_latency_qos_update_request(&ipw2100_pm_qos_req,
- PM_QOS_DEFAULT_VALUE);
-
- /* We have to signal any supplicant if we are disassociating */
- if (associated)
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
-}
-
-static int ipw2100_wdev_init(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct wireless_dev *wdev = &priv->ieee->wdev;
- int i;
-
- memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
-
- /* fill-out priv->ieee->bg_band */
- if (geo->bg_channels) {
- struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
-
- bg_band->band = NL80211_BAND_2GHZ;
- bg_band->n_channels = geo->bg_channels;
- bg_band->channels = kcalloc(geo->bg_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!bg_band->channels) {
- ipw2100_down(priv);
- return -ENOMEM;
- }
- /* translate geo->bg to bg_band.channels */
- for (i = 0; i < geo->bg_channels; i++) {
- bg_band->channels[i].band = NL80211_BAND_2GHZ;
- bg_band->channels[i].center_freq = geo->bg[i].freq;
- bg_band->channels[i].hw_value = geo->bg[i].channel;
- bg_band->channels[i].max_power = geo->bg[i].max_power;
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- bg_band->bitrates = ipw2100_bg_rates;
- bg_band->n_bitrates = RATE_COUNT;
-
- wdev->wiphy->bands[NL80211_BAND_2GHZ] = bg_band;
- }
-
- wdev->wiphy->cipher_suites = ipw_cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
-
- set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
- if (wiphy_register(wdev->wiphy))
- return -EIO;
- return 0;
-}
-
-static void ipw2100_reset_adapter(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, reset_work.work);
- unsigned long flags;
- union iwreq_data wrqu = {
- .ap_addr = {
- .sa_family = ARPHRD_ETHER}
- };
- int associated = priv->status & STATUS_ASSOCIATED;
-
- spin_lock_irqsave(&priv->low_lock, flags);
- IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
- priv->resets++;
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- priv->status |= STATUS_SECURITY_UPDATED;
-
- /* Force a power cycle even if interface hasn't been opened
- * yet */
- cancel_delayed_work(&priv->reset_work);
- priv->status |= STATUS_RESET_PENDING;
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- mutex_lock(&priv->action_mutex);
- /* stop timed checks so that they don't interfere with reset */
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
-
- /* We have to signal any supplicant if we are disassociating */
- if (associated)
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-
- ipw2100_up(priv, 0);
- mutex_unlock(&priv->action_mutex);
-
-}
-
-static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
-{
-
-#define MAC_ASSOCIATION_READ_DELAY (HZ)
- int ret;
- unsigned int len, essid_len;
- char essid[IW_ESSID_MAX_SIZE];
- u32 txrate;
- u32 chan;
- char *txratename;
- u8 bssid[ETH_ALEN];
-
- /*
- * TBD: BSSID is usually 00:00:00:00:00:00 here and not
- * an actual MAC of the AP. Seems like FW sets this
- * address too late. Read it later and expose through
- * /proc or schedule a later task to query and update
- */
-
- essid_len = IW_ESSID_MAX_SIZE;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
- essid, &essid_len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
-
- len = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
-
- len = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
- len = ETH_ALEN;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid,
- &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
- memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
-
- switch (txrate) {
- case TX_RATE_1_MBIT:
- txratename = "1Mbps";
- break;
- case TX_RATE_2_MBIT:
- txratename = "2Mbsp";
- break;
- case TX_RATE_5_5_MBIT:
- txratename = "5.5Mbps";
- break;
- case TX_RATE_11_MBIT:
- txratename = "11Mbps";
- break;
- default:
- IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
- txratename = "unknown rate";
- break;
- }
-
- IPW_DEBUG_INFO("%s: Associated with '%*pE' at %s, channel %d (BSSID=%pM)\n",
- priv->net_dev->name, essid_len, essid,
- txratename, chan, bssid);
-
- /* now we copy read ssid into dev */
- if (!(priv->config & CFG_STATIC_ESSID)) {
- priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
- memcpy(priv->essid, essid, priv->essid_len);
- }
- priv->channel = chan;
- memcpy(priv->bssid, bssid, ETH_ALEN);
-
- priv->status |= STATUS_ASSOCIATING;
- priv->connect_start = ktime_get_boottime_seconds();
-
- schedule_delayed_work(&priv->wx_event_work, HZ / 10);
-}
-
-static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
- int length, int batch_mode)
-{
- int ssid_len = min(length, IW_ESSID_MAX_SIZE);
- struct host_command cmd = {
- .host_command = SSID,
- .host_command_sequence = 0,
- .host_command_length = ssid_len
- };
- int err;
-
- IPW_DEBUG_HC("SSID: '%*pE'\n", ssid_len, essid);
-
- if (ssid_len)
- memcpy(cmd.host_command_parameters, essid, ssid_len);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
- * disable auto association -- so we cheat by setting a bogus SSID */
- if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
- int i;
- u8 *bogus = (u8 *) cmd.host_command_parameters;
- for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
- bogus[i] = 0x18 + i;
- cmd.host_command_length = IW_ESSID_MAX_SIZE;
- }
-
- /* NOTE: We always send the SSID command even if the provided ESSID is
- * the same as what we currently think is set. */
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (!err) {
- memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
- memcpy(priv->essid, essid, ssid_len);
- priv->essid_len = ssid_len;
- }
-
- if (!batch_mode) {
- if (ipw2100_enable_adapter(priv))
- err = -EIO;
- }
-
- return err;
-}
-
-static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
- "disassociated: '%*pE' %pM\n", priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
-
- if (priv->status & STATUS_STOPPING) {
- IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
- return;
- }
-
- eth_zero_addr(priv->bssid);
- eth_zero_addr(priv->ieee->bssid);
-
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
-
- if (!(priv->status & STATUS_RUNNING))
- return;
-
- if (priv->status & STATUS_SECURITY_UPDATED)
- schedule_delayed_work(&priv->security_work, 0);
-
- schedule_delayed_work(&priv->wx_event_work, 0);
-}
-
-static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
- priv->net_dev->name);
-
- /* RF_KILL is now enabled (else we wouldn't be here) */
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- priv->status |= STATUS_RF_KILL_HW;
-
- /* Make sure the RF Kill check timer is running */
- priv->stop_rf_kill = 0;
- mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
-}
-
-static void ipw2100_scan_event(struct work_struct *work)
-{
- struct ipw2100_priv *priv = container_of(work, struct ipw2100_priv,
- scan_event.work);
- union iwreq_data wrqu;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_SCAN("scan complete\n");
- /* Age the scan results... */
- priv->ieee->scans++;
- priv->status &= ~STATUS_SCANNING;
-
- /* Only userspace-requested scan completion events go out immediately */
- if (!priv->user_requested_scan) {
- schedule_delayed_work(&priv->scan_event,
- round_jiffies_relative(msecs_to_jiffies(4000)));
- } else {
- priv->user_requested_scan = 0;
- mod_delayed_work(system_wq, &priv->scan_event, 0);
- }
-}
-
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW2100_HANDLER(v, f) { v, f, # v }
-struct ipw2100_status_indicator {
- int status;
- void (*cb) (struct ipw2100_priv * priv, u32 status);
- char *name;
-};
-#else
-#define IPW2100_HANDLER(v, f) { v, f }
-struct ipw2100_status_indicator {
- int status;
- void (*cb) (struct ipw2100_priv * priv, u32 status);
-};
-#endif /* CONFIG_IPW2100_DEBUG */
-
-static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_SCAN("Scanning...\n");
- priv->status |= STATUS_SCANNING;
-}
-
-static const struct ipw2100_status_indicator status_handlers[] = {
- IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
- IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
- IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
- IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
- IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
- IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
- IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
- IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
- IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
- IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
- IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
- IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
- IPW2100_HANDLER(-1, NULL)
-};
-
-static void isr_status_change(struct ipw2100_priv *priv, int status)
-{
- int i;
-
- if (status == IPW_STATE_SCANNING &&
- priv->status & STATUS_ASSOCIATED &&
- !(priv->status & STATUS_SCANNING)) {
- IPW_DEBUG_INFO("Scan detected while associated, with "
- "no scan request. Restarting firmware.\n");
-
- /* Wake up any sleeping jobs */
- schedule_reset(priv);
- }
-
- for (i = 0; status_handlers[i].status != -1; i++) {
- if (status == status_handlers[i].status) {
- IPW_DEBUG_NOTIF("Status change: %s\n",
- status_handlers[i].name);
- if (status_handlers[i].cb)
- status_handlers[i].cb(priv, status);
- priv->wstats.status = status;
- return;
- }
- }
-
- IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
-}
-
-static void isr_rx_complete_command(struct ipw2100_priv *priv,
- struct ipw2100_cmd_header *cmd)
-{
-#ifdef CONFIG_IPW2100_DEBUG
- if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
- IPW_DEBUG_HC("Command completed '%s (%d)'\n",
- command_types[cmd->host_command_reg],
- cmd->host_command_reg);
- }
-#endif
- if (cmd->host_command_reg == HOST_COMPLETE)
- priv->status |= STATUS_ENABLED;
-
- if (cmd->host_command_reg == CARD_DISABLE)
- priv->status &= ~STATUS_ENABLED;
-
- priv->status &= ~STATUS_CMD_ACTIVE;
-
- wake_up_interruptible(&priv->wait_command_queue);
-}
-
-#ifdef CONFIG_IPW2100_DEBUG
-static const char *frame_types[] = {
- "COMMAND_STATUS_VAL",
- "STATUS_CHANGE_VAL",
- "P80211_DATA_VAL",
- "P8023_DATA_VAL",
- "HOST_NOTIFICATION_VAL"
-};
-#endif
-
-static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
- struct ipw2100_rx_packet *packet)
-{
- packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
- if (!packet->skb)
- return -ENOMEM;
-
- packet->rxp = (struct ipw2100_rx *)packet->skb->data;
- packet->dma_addr = dma_map_single(&priv->pci_dev->dev,
- packet->skb->data,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&priv->pci_dev->dev, packet->dma_addr)) {
- dev_kfree_skb(packet->skb);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-#define SEARCH_ERROR 0xffffffff
-#define SEARCH_FAIL 0xfffffffe
-#define SEARCH_SUCCESS 0xfffffff0
-#define SEARCH_DISCARD 0
-#define SEARCH_SNAPSHOT 1
-
-#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
-static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
-{
- int i;
- if (!priv->snapshot[0])
- return;
- for (i = 0; i < 0x30; i++)
- kfree(priv->snapshot[i]);
- priv->snapshot[0] = NULL;
-}
-
-#ifdef IPW2100_DEBUG_C3
-static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
-{
- int i;
- if (priv->snapshot[0])
- return 1;
- for (i = 0; i < 0x30; i++) {
- priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
- if (!priv->snapshot[i]) {
- IPW_DEBUG_INFO("%s: Error allocating snapshot "
- "buffer %d\n", priv->net_dev->name, i);
- while (i > 0)
- kfree(priv->snapshot[--i]);
- priv->snapshot[0] = NULL;
- return 0;
- }
- }
-
- return 1;
-}
-
-static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
- size_t len, int mode)
-{
- u32 i, j;
- u32 tmp;
- u8 *s, *d;
- u32 ret;
-
- s = in_buf;
- if (mode == SEARCH_SNAPSHOT) {
- if (!ipw2100_snapshot_alloc(priv))
- mode = SEARCH_DISCARD;
- }
-
- for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
- read_nic_dword(priv->net_dev, i, &tmp);
- if (mode == SEARCH_SNAPSHOT)
- *(u32 *) SNAPSHOT_ADDR(i) = tmp;
- if (ret == SEARCH_FAIL) {
- d = (u8 *) & tmp;
- for (j = 0; j < 4; j++) {
- if (*s != *d) {
- s = in_buf;
- continue;
- }
-
- s++;
- d++;
-
- if ((s - in_buf) == len)
- ret = (i + j) - len + 1;
- }
- } else if (mode == SEARCH_DISCARD)
- return ret;
- }
-
- return ret;
-}
-#endif
-
-/*
- *
- * 0) Disconnect the SKB from the firmware (just unmap)
- * 1) Pack the ETH header into the SKB
- * 2) Pass the SKB to the network stack
- *
- * When packet is provided by the firmware, it contains the following:
- *
- * . libipw_hdr
- * . libipw_snap_hdr
- *
- * The size of the constructed ethernet
- *
- */
-#ifdef IPW2100_RX_DEBUG
-static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
-#endif
-
-static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
-{
-#ifdef IPW2100_DEBUG_C3
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- u32 match, reg;
- int j;
-#endif
-
- IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
- i * sizeof(struct ipw2100_status));
-
-#ifdef IPW2100_DEBUG_C3
- /* Halt the firmware so we can get a good image */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
- j = 5;
- do {
- udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
- read_register(priv->net_dev, IPW_REG_RESET_REG, &reg);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- } while (j--);
-
- match = ipw2100_match_buf(priv, (u8 *) status,
- sizeof(struct ipw2100_status),
- SEARCH_SNAPSHOT);
- if (match < SEARCH_SUCCESS)
- IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
- "offset 0x%06X, length %d:\n",
- priv->net_dev->name, match,
- sizeof(struct ipw2100_status));
- else
- IPW_DEBUG_INFO("%s: No DMA status match in "
- "Firmware.\n", priv->net_dev->name);
-
- printk_buf((u8 *) priv->status_queue.drv,
- sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
-#endif
-
- priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
- priv->net_dev->stats.rx_errors++;
- schedule_reset(priv);
-}
-
-static void isr_rx(struct ipw2100_priv *priv, int i,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- IPW_DEBUG_RX("Handler...\n");
-
- if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
- IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
- " Dropping.\n",
- dev->name,
- status->frame_size, skb_tailroom(packet->skb));
- dev->stats.rx_errors++;
- return;
- }
-
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
- !(priv->status & STATUS_ASSOCIATED))) {
- IPW_DEBUG_DROP("Dropping packet while not associated.\n");
- priv->wstats.discard.misc++;
- return;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
-
- skb_put(packet->skb, status->frame_size);
-
-#ifdef IPW2100_RX_DEBUG
- /* Make a copy of the frame so we can dump it to the logs if
- * libipw_rx fails */
- skb_copy_from_linear_data(packet->skb, packet_data,
- min_t(u32, status->frame_size,
- IPW_RX_NIC_BUFFER_LENGTH));
-#endif
-
- if (!libipw_rx(priv->ieee, packet->skb, stats)) {
-#ifdef IPW2100_RX_DEBUG
- IPW_DEBUG_DROP("%s: Non consumed packet:\n",
- dev->name);
- printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
-#endif
- dev->stats.rx_errors++;
-
- /* libipw_rx failed, so it didn't free the SKB */
- dev_kfree_skb_any(packet->skb);
- packet->skb = NULL;
- }
-
- /* We need to allocate a new SKB and attach it to the RDB. */
- if (unlikely(ipw2100_alloc_skb(priv, packet))) {
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Unable to allocate SKB onto RBD ring - disabling "
- "adapter.\n", dev->name);
- /* TODO: schedule adapter shutdown */
- IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
- }
-
- /* Update the RDB entry */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
-}
-
-#ifdef CONFIG_IPW2100_MONITOR
-
-static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- /* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE */
- struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
- s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
- } *ipw_rt;
-
- IPW_DEBUG_RX("Handler...\n");
-
- if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
- sizeof(struct ipw_rt_hdr))) {
- IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
- " Dropping.\n",
- dev->name,
- status->frame_size,
- skb_tailroom(packet->skb));
- dev->stats.rx_errors++;
- return;
- }
-
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- if (unlikely(priv->config & CFG_CRC_CHECK &&
- status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
- IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
- dev->stats.rx_errors++;
- return;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
- memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
- packet->skb->data, status->frame_size);
-
- ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
-
- ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
-
- ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
-
- skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
-
- if (!libipw_rx(priv->ieee, packet->skb, stats)) {
- dev->stats.rx_errors++;
-
- /* libipw_rx failed, so it didn't free the SKB */
- dev_kfree_skb_any(packet->skb);
- packet->skb = NULL;
- }
-
- /* We need to allocate a new SKB and attach it to the RDB. */
- if (unlikely(ipw2100_alloc_skb(priv, packet))) {
- IPW_DEBUG_WARNING(
- "%s: Unable to allocate SKB onto RBD ring - disabling "
- "adapter.\n", dev->name);
- /* TODO: schedule adapter shutdown */
- IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
- }
-
- /* Update the RDB entry */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
-}
-
-#endif
-
-static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
-{
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
- u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
-
- switch (frame_type) {
- case COMMAND_STATUS_VAL:
- return (status->frame_size != sizeof(u->rx_data.command));
- case STATUS_CHANGE_VAL:
- return (status->frame_size != sizeof(u->rx_data.status));
- case HOST_NOTIFICATION_VAL:
- return (status->frame_size < sizeof(u->rx_data.notification));
- case P80211_DATA_VAL:
- case P8023_DATA_VAL:
-#ifdef CONFIG_IPW2100_MONITOR
- return 0;
-#else
- switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
- case IEEE80211_FTYPE_MGMT:
- case IEEE80211_FTYPE_CTL:
- return 0;
- case IEEE80211_FTYPE_DATA:
- return (status->frame_size >
- IPW_MAX_802_11_PAYLOAD_LENGTH);
- }
-#endif
- }
-
- return 1;
-}
-
-/*
- * ipw2100 interrupts are disabled at this point, and the ISR
- * is the only code that calls this method. So, we do not need
- * to play with any locks.
- *
- * RX Queue works as follows:
- *
- * Read index - firmware places packet in entry identified by the
- * Read index and advances Read index. In this manner,
- * Read index will always point to the next packet to
- * be filled--but not yet valid.
- *
- * Write index - driver fills this entry with an unused RBD entry.
- * This entry has not filled by the firmware yet.
- *
- * In between the W and R indexes are the RBDs that have been received
- * but not yet processed.
- *
- * The process of handling packets will start at WRITE + 1 and advance
- * until it reaches the READ index.
- *
- * The WRITE index is cached in the variable 'priv->rx_queue.next'.
- *
- */
-static void __ipw2100_rx_process(struct ipw2100_priv *priv)
-{
- struct ipw2100_bd_queue *rxq = &priv->rx_queue;
- struct ipw2100_status_queue *sq = &priv->status_queue;
- struct ipw2100_rx_packet *packet;
- u16 frame_type;
- u32 r, w, i, s;
- struct ipw2100_rx *u;
- struct libipw_rx_stats stats = {
- .mac_time = jiffies,
- };
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
-
- if (r >= rxq->entries) {
- IPW_DEBUG_RX("exit - bad read index\n");
- return;
- }
-
- i = (rxq->next + 1) % rxq->entries;
- s = i;
- while (i != r) {
- /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
- r, rxq->next, i); */
-
- packet = &priv->rx_buffers[i];
-
- /* Sync the DMA for the RX buffer so CPU is sure to get
- * the correct values */
- dma_sync_single_for_cpu(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
-
- if (unlikely(ipw2100_corruption_check(priv, i))) {
- ipw2100_corruption_detected(priv, i);
- goto increment;
- }
-
- u = packet->rxp;
- frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
- stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
- stats.len = sq->drv[i].frame_size;
-
- stats.mask = 0;
- if (stats.rssi != 0)
- stats.mask |= LIBIPW_STATMASK_RSSI;
- stats.freq = LIBIPW_24GHZ_BAND;
-
- IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
- priv->net_dev->name, frame_types[frame_type],
- stats.len);
-
- switch (frame_type) {
- case COMMAND_STATUS_VAL:
- /* Reset Rx watchdog */
- isr_rx_complete_command(priv, &u->rx_data.command);
- break;
-
- case STATUS_CHANGE_VAL:
- isr_status_change(priv, u->rx_data.status);
- break;
-
- case P80211_DATA_VAL:
- case P8023_DATA_VAL:
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- isr_rx_monitor(priv, i, &stats);
- break;
- }
-#endif
- if (stats.len < sizeof(struct libipw_hdr_3addr))
- break;
- switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
- case IEEE80211_FTYPE_MGMT:
- libipw_rx_mgt(priv->ieee,
- &u->rx_data.header, &stats);
- break;
-
- case IEEE80211_FTYPE_CTL:
- break;
-
- case IEEE80211_FTYPE_DATA:
- isr_rx(priv, i, &stats);
- break;
-
- }
- break;
- }
-
- increment:
- /* clear status field associated with this RBD */
- rxq->drv[i].status.info.field = 0;
-
- i = (i + 1) % rxq->entries;
- }
-
- if (i != s) {
- /* backtrack one entry, wrapping to end if at 0 */
- rxq->next = (i ? i : rxq->entries) - 1;
-
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
- }
-}
-
-/*
- * __ipw2100_tx_process
- *
- * This routine will determine whether the next packet on
- * the fw_pend_list has been processed by the firmware yet.
- *
- * If not, then it does nothing and returns.
- *
- * If so, then it removes the item from the fw_pend_list, frees
- * any associated storage, and places the item back on the
- * free list of its source (either msg_free_list or tx_free_list)
- *
- * TX Queue works as follows:
- *
- * Read index - points to the next TBD that the firmware will
- * process. The firmware will read the data, and once
- * done processing, it will advance the Read index.
- *
- * Write index - driver fills this entry with an constructed TBD
- * entry. The Write index is not advanced until the
- * packet has been configured.
- *
- * In between the W and R indexes are the TBDs that have NOT been
- * processed. Lagging behind the R index are packets that have
- * been processed but have not been freed by the driver.
- *
- * In order to free old storage, an internal index will be maintained
- * that points to the next packet to be freed. When all used
- * packets have been freed, the oldest index will be the same as the
- * firmware's read index.
- *
- * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
- *
- * Because the TBD structure can not contain arbitrary data, the
- * driver must keep an internal queue of cached allocations such that
- * it can put that data back into the tx_free_list and msg_free_list
- * for use by future command and data packets.
- *
- */
-static int __ipw2100_tx_process(struct ipw2100_priv *priv)
-{
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- int descriptors_used;
- int e, i;
- u32 r, w, frag_num = 0;
-
- if (list_empty(&priv->fw_pend_list))
- return 0;
-
- element = priv->fw_pend_list.next;
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
- tbd = &txq->drv[packet->index];
-
- /* Determine how many TBD entries must be finished... */
- switch (packet->type) {
- case COMMAND:
- /* COMMAND uses only one slot; don't advance */
- descriptors_used = 1;
- e = txq->oldest;
- break;
-
- case DATA:
- /* DATA uses two slots; advance and loop position. */
- descriptors_used = tbd->num_fragments;
- frag_num = tbd->num_fragments - 1;
- e = txq->oldest + frag_num;
- e %= txq->entries;
- break;
-
- default:
- printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
- priv->net_dev->name);
- return 0;
- }
-
- /* if the last TBD is not done by NIC yet, then packet is
- * not ready to be released.
- *
- */
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
- &r);
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- &w);
- if (w != txq->next)
- printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
- priv->net_dev->name);
-
- /*
- * txq->next is the index of the last packet written txq->oldest is
- * the index of the r is the index of the next packet to be read by
- * firmware
- */
-
- /*
- * Quick graphic to help you visualize the following
- * if / else statement
- *
- * ===>| s---->|===============
- * e>|
- * | a | b | c | d | e | f | g | h | i | j | k | l
- * r---->|
- * w
- *
- * w - updated by driver
- * r - updated by firmware
- * s - start of oldest BD entry (txq->oldest)
- * e - end of oldest BD entry
- *
- */
- if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
- IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
- return 0;
- }
-
- list_del(element);
- DEC_STAT(&priv->fw_pend_stat);
-
-#ifdef CONFIG_IPW2100_DEBUG
- {
- i = txq->oldest;
- IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
- txq->drv[i].host_addr, txq->drv[i].buf_length);
-
- if (packet->type == DATA) {
- i = (i + 1) % txq->entries;
-
- IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32) (txq->nic + i *
- sizeof(struct ipw2100_bd)),
- (u32) txq->drv[i].host_addr,
- txq->drv[i].buf_length);
- }
- }
-#endif
-
- switch (packet->type) {
- case DATA:
- if (txq->drv[txq->oldest].status.info.fields.txType != 0)
- printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
- "Expecting DATA TBD but pulled "
- "something else: ids %d=%d.\n",
- priv->net_dev->name, txq->oldest, packet->index);
-
- /* DATA packet; we have to unmap and free the SKB */
- for (i = 0; i < frag_num; i++) {
- tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
-
- IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
- (packet->index + 1 + i) % txq->entries,
- tbd->host_addr, tbd->buf_length);
-
- dma_unmap_single(&priv->pci_dev->dev, tbd->host_addr,
- tbd->buf_length, DMA_TO_DEVICE);
- }
-
- libipw_txb_free(packet->info.d_struct.txb);
- packet->info.d_struct.txb = NULL;
-
- list_add_tail(element, &priv->tx_free_list);
- INC_STAT(&priv->tx_free_stat);
-
- /* We have a free slot in the Tx queue, so wake up the
- * transmit layer if it is stopped. */
- if (priv->status & STATUS_ASSOCIATED)
- netif_wake_queue(priv->net_dev);
-
- /* A packet was processed by the hardware, so update the
- * watchdog */
- netif_trans_update(priv->net_dev);
-
- break;
-
- case COMMAND:
- if (txq->drv[txq->oldest].status.info.fields.txType != 1)
- printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
- "Expecting COMMAND TBD but pulled "
- "something else: ids %d=%d.\n",
- priv->net_dev->name, txq->oldest, packet->index);
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (packet->info.c_struct.cmd->host_command_reg <
- ARRAY_SIZE(command_types))
- IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
- command_types[packet->info.c_struct.cmd->
- host_command_reg],
- packet->info.c_struct.cmd->
- host_command_reg,
- packet->info.c_struct.cmd->cmd_status_reg);
-#endif
-
- list_add_tail(element, &priv->msg_free_list);
- INC_STAT(&priv->msg_free_stat);
- break;
- }
-
- /* advance oldest used TBD pointer to start of next entry */
- txq->oldest = (e + 1) % txq->entries;
- /* increase available TBDs number */
- txq->available += descriptors_used;
- SET_STAT(&priv->txq_stat, txq->available);
-
- IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
- jiffies - packet->jiffy_start);
-
- return (!list_empty(&priv->fw_pend_list));
-}
-
-static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
-{
- int i = 0;
-
- while (__ipw2100_tx_process(priv) && i < 200)
- i++;
-
- if (i == 200) {
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Driver is running slow (%d iters).\n",
- priv->net_dev->name, i);
- }
-}
-
-static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- int next = txq->next;
-
- while (!list_empty(&priv->msg_pend_list)) {
- /* if there isn't enough space in TBD queue, then
- * don't stuff a new one in.
- * NOTE: 3 are needed as a command will take one,
- * and there is a minimum of 2 that must be
- * maintained between the r and w indexes
- */
- if (txq->available <= 3) {
- IPW_DEBUG_TX("no room in tx_queue\n");
- break;
- }
-
- element = priv->msg_pend_list.next;
- list_del(element);
- DEC_STAT(&priv->msg_pend_stat);
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
- &txq->drv[txq->next],
- (u32) (txq->nic + txq->next *
- sizeof(struct ipw2100_bd)));
-
- packet->index = txq->next;
-
- tbd = &txq->drv[txq->next];
-
- /* initialize TBD */
- tbd->host_addr = packet->info.c_struct.cmd_phys;
- tbd->buf_length = sizeof(struct ipw2100_cmd_header);
- /* not marking number of fragments causes problems
- * with f/w debug version */
- tbd->num_fragments = 1;
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_COMMAND |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
-
- /* update TBD queue counters */
- txq->next++;
- txq->next %= txq->entries;
- txq->available--;
- DEC_STAT(&priv->txq_stat);
-
- list_add_tail(element, &priv->fw_pend_list);
- INC_STAT(&priv->fw_pend_stat);
- }
-
- if (txq->next != next) {
- /* kick off the DMA by notifying firmware the
- * write index has moved; make sure TBD stores are sync'd */
- wmb();
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- txq->next);
- }
-}
-
-/*
- * ipw2100_tx_send_data
- *
- */
-static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- int next = txq->next;
- int i = 0;
- struct ipw2100_data_header *ipw_hdr;
- struct libipw_hdr_3addr *hdr;
-
- while (!list_empty(&priv->tx_pend_list)) {
- /* if there isn't enough space in TBD queue, then
- * don't stuff a new one in.
- * NOTE: 4 are needed as a data will take two,
- * and there is a minimum of 2 that must be
- * maintained between the r and w indexes
- */
- element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
- IPW_MAX_BDS)) {
- /* TODO: Support merging buffers if more than
- * IPW_MAX_BDS are used */
- IPW_DEBUG_INFO("%s: Maximum BD threshold exceeded. "
- "Increase fragmentation level.\n",
- priv->net_dev->name);
- }
-
- if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
- IPW_DEBUG_TX("no room in tx_queue\n");
- break;
- }
-
- list_del(element);
- DEC_STAT(&priv->tx_pend_stat);
-
- tbd = &txq->drv[txq->next];
-
- packet->index = txq->next;
-
- ipw_hdr = packet->info.d_struct.data;
- hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
- fragments[0]->data;
-
- if (priv->ieee->iw_mode == IW_MODE_INFRA) {
- /* To DS: Addr1 = BSSID, Addr2 = SA,
- Addr3 = DA */
- memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
- } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA,
- Addr3 = BSSID */
- memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
- }
-
- ipw_hdr->host_command_reg = SEND;
- ipw_hdr->host_command_reg1 = 0;
-
- /* For now we only support host based encryption */
- ipw_hdr->needs_encryption = 0;
- ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
- if (packet->info.d_struct.txb->nr_frags > 1)
- ipw_hdr->fragment_size =
- packet->info.d_struct.txb->frag_size -
- LIBIPW_3ADDR_LEN;
- else
- ipw_hdr->fragment_size = 0;
-
- tbd->host_addr = packet->info.d_struct.data_phys;
- tbd->buf_length = sizeof(struct ipw2100_data_header);
- tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
- txq->next++;
- txq->next %= txq->entries;
-
- IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
- packet->index, tbd->host_addr, tbd->buf_length);
-#ifdef CONFIG_IPW2100_DEBUG
- if (packet->info.d_struct.txb->nr_frags > 1)
- IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
- packet->info.d_struct.txb->nr_frags);
-#endif
-
- for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
- tbd = &txq->drv[txq->next];
- if (i == packet->info.d_struct.txb->nr_frags - 1)
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
- else
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
-
- tbd->buf_length = packet->info.d_struct.txb->
- fragments[i]->len - LIBIPW_3ADDR_LEN;
-
- tbd->host_addr = dma_map_single(&priv->pci_dev->dev,
- packet->info.d_struct.
- txb->fragments[i]->data +
- LIBIPW_3ADDR_LEN,
- tbd->buf_length,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&priv->pci_dev->dev, tbd->host_addr)) {
- IPW_DEBUG_TX("dma mapping error\n");
- break;
- }
-
- IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
- txq->next, tbd->host_addr,
- tbd->buf_length);
-
- dma_sync_single_for_device(&priv->pci_dev->dev,
- tbd->host_addr,
- tbd->buf_length,
- DMA_TO_DEVICE);
-
- txq->next++;
- txq->next %= txq->entries;
- }
-
- txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
- SET_STAT(&priv->txq_stat, txq->available);
-
- list_add_tail(element, &priv->fw_pend_list);
- INC_STAT(&priv->fw_pend_stat);
- }
-
- if (txq->next != next) {
- /* kick off the DMA by notifying firmware the
- * write index has moved; make sure TBD stores are sync'd */
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- txq->next);
- }
-}
-
-static void ipw2100_irq_tasklet(struct tasklet_struct *t)
-{
- struct ipw2100_priv *priv = from_tasklet(priv, t, irq_tasklet);
- struct net_device *dev = priv->net_dev;
- unsigned long flags;
- u32 inta, tmp;
-
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
-
- read_register(dev, IPW_REG_INTA, &inta);
-
- IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
- (unsigned long)inta & IPW_INTERRUPT_MASK);
-
- priv->in_isr++;
- priv->interrupts++;
-
- /* We do not loop and keep polling for more interrupts as this
- * is frowned upon and doesn't play nicely with other potentially
- * chained IRQs */
- IPW_DEBUG_ISR("INTA: 0x%08lX\n",
- (unsigned long)inta & IPW_INTERRUPT_MASK);
-
- if (inta & IPW2100_INTA_FATAL_ERROR) {
- printk(KERN_WARNING DRV_NAME
- ": Fatal interrupt. Scheduling firmware restart.\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
-
- read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
- IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
- priv->net_dev->name, priv->fatal_error);
-
- read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
- IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
- priv->net_dev->name, tmp);
-
- /* Wake up any sleeping jobs */
- schedule_reset(priv);
- }
-
- if (inta & IPW2100_INTA_PARITY_ERROR) {
- printk(KERN_ERR DRV_NAME
- ": ***** PARITY ERROR INTERRUPT !!!!\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
- }
-
- if (inta & IPW2100_INTA_RX_TRANSFER) {
- IPW_DEBUG_ISR("RX interrupt\n");
-
- priv->rx_interrupts++;
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
-
- __ipw2100_rx_process(priv);
- __ipw2100_tx_complete(priv);
- }
-
- if (inta & IPW2100_INTA_TX_TRANSFER) {
- IPW_DEBUG_ISR("TX interrupt\n");
-
- priv->tx_interrupts++;
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
-
- __ipw2100_tx_complete(priv);
- ipw2100_tx_send_commands(priv);
- ipw2100_tx_send_data(priv);
- }
-
- if (inta & IPW2100_INTA_TX_COMPLETE) {
- IPW_DEBUG_ISR("TX complete\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
-
- __ipw2100_tx_complete(priv);
- }
-
- if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
- /* ipw2100_handle_event(dev); */
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
- }
-
- if (inta & IPW2100_INTA_FW_INIT_DONE) {
- IPW_DEBUG_ISR("FW init done interrupt\n");
- priv->inta_other++;
-
- read_register(dev, IPW_REG_INTA, &tmp);
- if (tmp & (IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR)) {
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR);
- }
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
- }
-
- if (inta & IPW2100_INTA_STATUS_CHANGE) {
- IPW_DEBUG_ISR("Status change interrupt\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
- }
-
- if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
- IPW_DEBUG_ISR("slave host mode interrupt\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
- }
-
- priv->in_isr--;
- ipw2100_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- IPW_DEBUG_ISR("exit\n");
-}
-
-static irqreturn_t ipw2100_interrupt(int irq, void *data)
-{
- struct ipw2100_priv *priv = data;
- u32 inta, inta_mask;
-
- if (!data)
- return IRQ_NONE;
-
- spin_lock(&priv->low_lock);
-
- /* We check to see if we should be ignoring interrupts before
- * we touch the hardware. During ucode load if we try and handle
- * an interrupt we can cause keyboard problems as well as cause
- * the ucode to fail to initialize */
- if (!(priv->status & STATUS_INT_ENABLED)) {
- /* Shared IRQ */
- goto none;
- }
-
- read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
- goto none;
- }
-
- inta &= IPW_INTERRUPT_MASK;
-
- if (!(inta & inta_mask)) {
- /* Shared interrupt */
- goto none;
- }
-
- /* We disable the hardware interrupt here just to prevent unneeded
- * calls to be made. We disable this again within the actual
- * work tasklet, so if another part of the code re-enables the
- * interrupt, that is fine */
- ipw2100_disable_interrupts(priv);
-
- tasklet_schedule(&priv->irq_tasklet);
- spin_unlock(&priv->low_lock);
-
- return IRQ_HANDLED;
- none:
- spin_unlock(&priv->low_lock);
- return IRQ_NONE;
-}
-
-static netdev_tx_t ipw2100_tx(struct libipw_txb *txb,
- struct net_device *dev, int pri)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_INFO("Can not transmit when not connected.\n");
- priv->net_dev->stats.tx_carrier_errors++;
- netif_stop_queue(dev);
- goto fail_unlock;
- }
-
- if (list_empty(&priv->tx_free_list))
- goto fail_unlock;
-
- element = priv->tx_free_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- packet->info.d_struct.txb = txb;
-
- IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
- printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
-
- packet->jiffy_start = jiffies;
-
- list_del(element);
- DEC_STAT(&priv->tx_free_stat);
-
- list_add_tail(element, &priv->tx_pend_list);
- INC_STAT(&priv->tx_pend_stat);
-
- ipw2100_tx_send_data(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
- return NETDEV_TX_OK;
-
-fail_unlock:
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&priv->low_lock, flags);
- return NETDEV_TX_BUSY;
-}
-
-static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err = -EINVAL;
- void *v;
- dma_addr_t p;
-
- priv->msg_buffers =
- kmalloc_array(IPW_COMMAND_POOL_SIZE,
- sizeof(struct ipw2100_tx_packet),
- GFP_KERNEL);
- if (!priv->msg_buffers)
- return -ENOMEM;
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
- v = dma_alloc_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header), &p,
- GFP_KERNEL);
- if (!v) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: PCI alloc failed for msg "
- "buffers.\n", priv->net_dev->name);
- err = -ENOMEM;
- break;
- }
-
- priv->msg_buffers[i].type = COMMAND;
- priv->msg_buffers[i].info.c_struct.cmd =
- (struct ipw2100_cmd_header *)v;
- priv->msg_buffers[i].info.c_struct.cmd_phys = p;
- }
-
- if (i == IPW_COMMAND_POOL_SIZE)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header),
- priv->msg_buffers[j].info.c_struct.cmd,
- priv->msg_buffers[j].info.c_struct.cmd_phys);
- }
-
- kfree(priv->msg_buffers);
- priv->msg_buffers = NULL;
-
- return err;
-}
-
-static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
-{
- int i;
-
- INIT_LIST_HEAD(&priv->msg_free_list);
- INIT_LIST_HEAD(&priv->msg_pend_list);
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
- list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
- SET_STAT(&priv->msg_free_stat, i);
-
- return 0;
-}
-
-static void ipw2100_msg_free(struct ipw2100_priv *priv)
-{
- int i;
-
- if (!priv->msg_buffers)
- return;
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header),
- priv->msg_buffers[i].info.c_struct.cmd,
- priv->msg_buffers[i].info.c_struct.cmd_phys);
- }
-
- kfree(priv->msg_buffers);
- priv->msg_buffers = NULL;
-}
-
-static ssize_t pci_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct pci_dev *pci_dev = to_pci_dev(d);
- char *out = buf;
- int i, j;
- u32 val;
-
- for (i = 0; i < 16; i++) {
- out += sprintf(out, "[%08X] ", i * 16);
- for (j = 0; j < 16; j += 4) {
- pci_read_config_dword(pci_dev, i * 16 + j, &val);
- out += sprintf(out, "%08X ", val);
- }
- out += sprintf(out, "\n");
- }
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(pci);
-
-static ssize_t cfg_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->config);
-}
-
-static DEVICE_ATTR_RO(cfg);
-
-static ssize_t status_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->status);
-}
-
-static DEVICE_ATTR_RO(status);
-
-static ssize_t capability_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->capability);
-}
-
-static DEVICE_ATTR_RO(capability);
-
-#define IPW2100_REG(x) { IPW_ ##x, #x }
-static const struct {
- u32 addr;
- const char *name;
-} hw_data[] = {
-IPW2100_REG(REG_GP_CNTRL),
- IPW2100_REG(REG_GPIO),
- IPW2100_REG(REG_INTA),
- IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
-#define IPW2100_NIC(x, s) { x, #x, s }
-static const struct {
- u32 addr;
- const char *name;
- size_t size;
-} nic_data[] = {
-IPW2100_NIC(IPW2100_CONTROL_REG, 2),
- IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
-#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
-static const struct {
- u8 index;
- const char *name;
- const char *desc;
-} ord_data[] = {
-IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_HOST_COMPLETE,
- "successful Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA,
- "successful Directed Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA1,
- "successful Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA2,
- "successful Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA5_5,
- "successful Directed Tx's (MSDU) @ 5_5MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA11,
- "successful Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA1,
- "successful Non_Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA2,
- "successful Non_Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
- "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA11,
- "successful Non_Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
- IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
- IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
- IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
- IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
- IPW2100_ORD(STAT_TX_ASSN_RESP,
- "successful Association response Tx's"),
- IPW2100_ORD(STAT_TX_REASSN,
- "successful Reassociation Tx's"),
- IPW2100_ORD(STAT_TX_REASSN_RESP,
- "successful Reassociation response Tx's"),
- IPW2100_ORD(STAT_TX_PROBE,
- "probes successfully transmitted"),
- IPW2100_ORD(STAT_TX_PROBE_RESP,
- "probe responses successfully transmitted"),
- IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
- IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
- IPW2100_ORD(STAT_TX_DISASSN,
- "successful Disassociation TX"),
- IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
- IPW2100_ORD(STAT_TX_DEAUTH,
- "successful Deauthentication TX"),
- IPW2100_ORD(STAT_TX_TOTAL_BYTES,
- "Total successful Tx data bytes"),
- IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
- IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
- IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
- IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
- IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
- IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
- IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
- "times max tries in a hop failed"),
- IPW2100_ORD(STAT_TX_DISASSN_FAIL,
- "times disassociation failed"),
- IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
- IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
- IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
- IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
- IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA5_5,
- "directed packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
- IPW2100_ORD(STAT_RX_NODIR_DATA1,
- "nondirected packets at 1MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA2,
- "nondirected packets at 2MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
- "nondirected packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA11,
- "nondirected packets at 11MB"),
- IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
- IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
- "Rx CTS"),
- IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
- IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
- IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
- IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
- IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
- IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
- IPW2100_ORD(STAT_RX_REASSN_RESP,
- "Reassociation response Rx's"),
- IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
- IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
- IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
- IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
- IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
- IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
- IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
- IPW2100_ORD(STAT_RX_TOTAL_BYTES,
- "Total rx data bytes received"),
- IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
- IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE1,
- "duplicate rx packets at 1MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE2,
- "duplicate rx packets at 2MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE5_5,
- "duplicate rx packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE11,
- "duplicate rx packets at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
- IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
- IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
- IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
- IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
- "rx frames with invalid protocol"),
- IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
- IPW2100_ORD(STAT_RX_NO_BUFFER,
- "rx frames rejected due to no buffer"),
- IPW2100_ORD(STAT_RX_MISSING_FRAG,
- "rx frames dropped due to missing fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
- "rx frames dropped due to non-sequential fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
- "rx frames dropped due to unmatched 1st frame"),
- IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
- "rx frames dropped due to uncompleted frame"),
- IPW2100_ORD(STAT_RX_ICV_ERRORS,
- "ICV errors during decryption"),
- IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
- IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
- IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
- "poll response timeouts"),
- IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
- "timeouts waiting for last {broad,multi}cast pkt"),
- IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
- IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
- IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
- IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
- IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
- "current calculation of % missed beacons"),
- IPW2100_ORD(STAT_PERCENT_RETRIES,
- "current calculation of % missed tx retries"),
- IPW2100_ORD(ASSOCIATED_AP_PTR,
- "0 if not associated, else pointer to AP table entry"),
- IPW2100_ORD(AVAILABLE_AP_CNT,
- "AP's described in the AP table"),
- IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
- IPW2100_ORD(STAT_AP_ASSNS, "associations"),
- IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
- IPW2100_ORD(STAT_ASSN_RESP_FAIL,
- "failures due to response fail"),
- IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
- IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
- IPW2100_ORD(STAT_ROAM_INHIBIT,
- "times roaming was inhibited due to activity"),
- IPW2100_ORD(RSSI_AT_ASSN,
- "RSSI of associated AP at time of association"),
- IPW2100_ORD(STAT_ASSN_CAUSE1,
- "reassociation: no probe response or TX on hop"),
- IPW2100_ORD(STAT_ASSN_CAUSE2,
- "reassociation: poor tx/rx quality"),
- IPW2100_ORD(STAT_ASSN_CAUSE3,
- "reassociation: tx/rx quality (excessive AP load"),
- IPW2100_ORD(STAT_ASSN_CAUSE4,
- "reassociation: AP RSSI level"),
- IPW2100_ORD(STAT_ASSN_CAUSE5,
- "reassociations due to load leveling"),
- IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
- IPW2100_ORD(STAT_AUTH_RESP_FAIL,
- "times authentication response failed"),
- IPW2100_ORD(STATION_TABLE_CNT,
- "entries in association table"),
- IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
- IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
- IPW2100_ORD(COUNTRY_CODE,
- "IEEE country code as recv'd from beacon"),
- IPW2100_ORD(COUNTRY_CHANNELS,
- "channels supported by country"),
- IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
- IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
- IPW2100_ORD(ANTENNA_DIVERSITY,
- "TRUE if antenna diversity is disabled"),
- IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
- IPW2100_ORD(OUR_FREQ,
- "current radio freq lower digits - channel ID"),
- IPW2100_ORD(RTC_TIME, "current RTC time"),
- IPW2100_ORD(PORT_TYPE, "operating mode"),
- IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
- IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
- IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
- IPW2100_ORD(BASIC_RATES, "basic tx rates"),
- IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
- IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
- IPW2100_ORD(CAPABILITIES,
- "Management frame capability field"),
- IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
- IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
- IPW2100_ORD(RTS_THRESHOLD,
- "Min packet length for RTS handshaking"),
- IPW2100_ORD(INT_MODE, "International mode"),
- IPW2100_ORD(FRAGMENTATION_THRESHOLD,
- "protocol frag threshold"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
- "EEPROM offset in SRAM"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
- "EEPROM size in SRAM"),
- IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
- IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
- "EEPROM IBSS 11b channel set"),
- IPW2100_ORD(MAC_VERSION, "MAC Version"),
- IPW2100_ORD(MAC_REVISION, "MAC Revision"),
- IPW2100_ORD(RADIO_VERSION, "Radio Version"),
- IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
- IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
-
-static ssize_t registers_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- int i;
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- char *out = buf;
- u32 val = 0;
-
- out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
-
- for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
- read_register(dev, hw_data[i].addr, &val);
- out += sprintf(out, "%30s [%08X] : %08X\n",
- hw_data[i].name, hw_data[i].addr, val);
- }
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(registers);
-
-static ssize_t hardware_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- char *out = buf;
- int i;
-
- out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
-
- for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
- u8 tmp8;
- u16 tmp16;
- u32 tmp32;
-
- switch (nic_data[i].size) {
- case 1:
- read_nic_byte(dev, nic_data[i].addr, &tmp8);
- out += sprintf(out, "%30s [%08X] : %02X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp8);
- break;
- case 2:
- read_nic_word(dev, nic_data[i].addr, &tmp16);
- out += sprintf(out, "%30s [%08X] : %04X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp16);
- break;
- case 4:
- read_nic_dword(dev, nic_data[i].addr, &tmp32);
- out += sprintf(out, "%30s [%08X] : %08X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp32);
- break;
- }
- }
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(hardware);
-
-static ssize_t memory_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- static unsigned long loop = 0;
- int len = 0;
- u32 buffer[4];
- int i;
- char line[81];
-
- if (loop >= 0x30000)
- loop = 0;
-
- /* sysfs provides us PAGE_SIZE buffer */
- while (len < PAGE_SIZE - 128 && loop < 0x30000) {
-
- if (priv->snapshot[0])
- for (i = 0; i < 4; i++)
- buffer[i] =
- *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
- else
- for (i = 0; i < 4; i++)
- read_nic_dword(dev, loop + i * 4, &buffer[i]);
-
- if (priv->dump_raw)
- len += sprintf(buf + len,
- "%c%c%c%c"
- "%c%c%c%c"
- "%c%c%c%c"
- "%c%c%c%c",
- ((u8 *) buffer)[0x0],
- ((u8 *) buffer)[0x1],
- ((u8 *) buffer)[0x2],
- ((u8 *) buffer)[0x3],
- ((u8 *) buffer)[0x4],
- ((u8 *) buffer)[0x5],
- ((u8 *) buffer)[0x6],
- ((u8 *) buffer)[0x7],
- ((u8 *) buffer)[0x8],
- ((u8 *) buffer)[0x9],
- ((u8 *) buffer)[0xa],
- ((u8 *) buffer)[0xb],
- ((u8 *) buffer)[0xc],
- ((u8 *) buffer)[0xd],
- ((u8 *) buffer)[0xe],
- ((u8 *) buffer)[0xf]);
- else
- len += sprintf(buf + len, "%s\n",
- snprint_line(line, sizeof(line),
- (u8 *) buffer, 16, loop));
- loop += 16;
- }
-
- return len;
-}
-
-static ssize_t memory_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- const char *p = buf;
-
- (void)dev; /* kill unused-var warning for debug-only code */
-
- if (count < 1)
- return count;
-
- if (p[0] == '1' ||
- (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
- IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
- dev->name);
- priv->dump_raw = 1;
-
- } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
- tolower(p[1]) == 'f')) {
- IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
- dev->name);
- priv->dump_raw = 0;
-
- } else if (tolower(p[0]) == 'r') {
- IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
- ipw2100_snapshot_free(priv);
-
- } else
- IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
- "reset = clear memory snapshot\n", dev->name);
-
- return count;
-}
-
-static DEVICE_ATTR_RW(memory);
-
-static ssize_t ordinals_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- u32 val = 0;
- int len = 0;
- u32 val_len;
- static int loop = 0;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return 0;
-
- if (loop >= ARRAY_SIZE(ord_data))
- loop = 0;
-
- /* sysfs provides us PAGE_SIZE buffer */
- while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
- val_len = sizeof(u32);
-
- if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
- &val_len))
- len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
- ord_data[loop].index,
- ord_data[loop].desc);
- else
- len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
- ord_data[loop].index, val,
- ord_data[loop].desc);
- loop++;
- }
-
- return len;
-}
-
-static DEVICE_ATTR_RO(ordinals);
-
-static ssize_t stats_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char *out = buf;
-
- out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
- priv->interrupts, priv->tx_interrupts,
- priv->rx_interrupts, priv->inta_other);
- out += sprintf(out, "firmware resets: %d\n", priv->resets);
- out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
-#ifdef CONFIG_IPW2100_DEBUG
- out += sprintf(out, "packet mismatch image: %s\n",
- priv->snapshot[0] ? "YES" : "NO");
-#endif
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(stats);
-
-static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
-{
- int err;
-
- if (mode == priv->ieee->iw_mode)
- return 0;
-
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
-
- switch (mode) {
- case IW_MODE_INFRA:
- priv->net_dev->type = ARPHRD_ETHER;
- break;
- case IW_MODE_ADHOC:
- priv->net_dev->type = ARPHRD_ETHER;
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- priv->last_mode = priv->ieee->iw_mode;
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- break;
-#endif /* CONFIG_IPW2100_MONITOR */
- }
-
- priv->ieee->iw_mode = mode;
-
-#ifdef CONFIG_PM
- /* Indicate ipw2100_download_firmware download firmware
- * from disk instead of memory. */
- ipw2100_firmware.version = 0;
-#endif
-
- printk(KERN_INFO "%s: Resetting on mode change.\n", priv->net_dev->name);
- priv->reset_backoff = 0;
- schedule_reset(priv);
-
- return 0;
-}
-
-static ssize_t internals_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- int len = 0;
-
-#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
-
- if (priv->status & STATUS_ASSOCIATED)
- len += sprintf(buf + len, "connected: %llu\n",
- ktime_get_boottime_seconds() - priv->connect_start);
- else
- len += sprintf(buf + len, "not connected\n");
-
- DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
- DUMP_VAR(status, "08lx");
- DUMP_VAR(config, "08lx");
- DUMP_VAR(capability, "08lx");
-
- len +=
- sprintf(buf + len, "last_rtc: %lu\n",
- (unsigned long)priv->last_rtc);
-
- DUMP_VAR(fatal_error, "d");
- DUMP_VAR(stop_hang_check, "d");
- DUMP_VAR(stop_rf_kill, "d");
- DUMP_VAR(messages_sent, "d");
-
- DUMP_VAR(tx_pend_stat.value, "d");
- DUMP_VAR(tx_pend_stat.hi, "d");
-
- DUMP_VAR(tx_free_stat.value, "d");
- DUMP_VAR(tx_free_stat.lo, "d");
-
- DUMP_VAR(msg_free_stat.value, "d");
- DUMP_VAR(msg_free_stat.lo, "d");
-
- DUMP_VAR(msg_pend_stat.value, "d");
- DUMP_VAR(msg_pend_stat.hi, "d");
-
- DUMP_VAR(fw_pend_stat.value, "d");
- DUMP_VAR(fw_pend_stat.hi, "d");
-
- DUMP_VAR(txq_stat.value, "d");
- DUMP_VAR(txq_stat.lo, "d");
-
- DUMP_VAR(ieee->scans, "d");
- DUMP_VAR(reset_backoff, "lld");
-
- return len;
-}
-
-static DEVICE_ATTR_RO(internals);
-
-static ssize_t bssinfo_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char essid[IW_ESSID_MAX_SIZE + 1];
- u8 bssid[ETH_ALEN];
- u32 chan = 0;
- char *out = buf;
- unsigned int length;
- int ret;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return 0;
-
- memset(essid, 0, sizeof(essid));
- memset(bssid, 0, sizeof(bssid));
-
- length = IW_ESSID_MAX_SIZE;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- length = sizeof(bssid);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
- bssid, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- length = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- out += sprintf(out, "ESSID: %s\n", essid);
- out += sprintf(out, "BSSID: %pM\n", bssid);
- out += sprintf(out, "Channel: %d\n", chan);
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(bssinfo);
-
-#ifdef CONFIG_IPW2100_DEBUG
-static ssize_t debug_level_show(struct device_driver *d, char *buf)
-{
- return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
-}
-
-static ssize_t debug_level_store(struct device_driver *d,
- const char *buf, size_t count)
-{
- u32 val;
- int ret;
-
- ret = kstrtou32(buf, 0, &val);
- if (ret)
- IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
- else
- ipw2100_debug_level = val;
-
- return strnlen(buf, count);
-}
-static DRIVER_ATTR_RW(debug_level);
-#endif /* CONFIG_IPW2100_DEBUG */
-
-static ssize_t fatal_error_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char *out = buf;
- int i;
-
- if (priv->fatal_error)
- out += sprintf(out, "0x%08X\n", priv->fatal_error);
- else
- out += sprintf(out, "0\n");
-
- for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
- if (!priv->fatal_errors[(priv->fatal_index - i) %
- IPW2100_ERROR_QUEUE])
- continue;
-
- out += sprintf(out, "%d. 0x%08X\n", i,
- priv->fatal_errors[(priv->fatal_index - i) %
- IPW2100_ERROR_QUEUE]);
- }
-
- return out - buf;
-}
-
-static ssize_t fatal_error_store(struct device *d,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- schedule_reset(priv);
- return count;
-}
-
-static DEVICE_ATTR_RW(fatal_error);
-
-static ssize_t scan_age_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", priv->ieee->scan_age);
-}
-
-static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- unsigned long val;
- int ret;
-
- (void)dev; /* kill unused-var warning for debug-only code */
-
- IPW_DEBUG_INFO("enter\n");
-
- ret = kstrtoul(buf, 0, &val);
- if (ret) {
- IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
- } else {
- priv->ieee->scan_age = val;
- IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(scan_age);
-
-static ssize_t rf_kill_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- /* 0 - RF kill not enabled
- 1 - SW based RF kill active (sysfs)
- 2 - HW based RF kill active
- 3 - Both HW and SW baed RF kill active */
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
- (rf_kill_active(priv) ? 0x2 : 0x0);
- return sprintf(buf, "%i\n", val);
-}
-
-static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
-{
- if ((disable_radio ? 1 : 0) ==
- (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
- return 0;
-
- IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
- disable_radio ? "OFF" : "ON");
-
- mutex_lock(&priv->action_mutex);
-
- if (disable_radio) {
- priv->status |= STATUS_RF_KILL_SW;
- ipw2100_down(priv);
- } else {
- priv->status &= ~STATUS_RF_KILL_SW;
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("Can not turn radio back on - "
- "disabled by HW switch\n");
- /* Make sure the RF_KILL check timer is running */
- priv->stop_rf_kill = 0;
- mod_delayed_work(system_wq, &priv->rf_kill,
- round_jiffies_relative(HZ));
- } else
- schedule_reset(priv);
- }
-
- mutex_unlock(&priv->action_mutex);
- return 1;
-}
-
-static ssize_t rf_kill_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- ipw_radio_kill_sw(priv, buf[0] == '1');
- return count;
-}
-
-static DEVICE_ATTR_RW(rf_kill);
-
-static struct attribute *ipw2100_sysfs_entries[] = {
- &dev_attr_hardware.attr,
- &dev_attr_registers.attr,
- &dev_attr_ordinals.attr,
- &dev_attr_pci.attr,
- &dev_attr_stats.attr,
- &dev_attr_internals.attr,
- &dev_attr_bssinfo.attr,
- &dev_attr_memory.attr,
- &dev_attr_scan_age.attr,
- &dev_attr_fatal_error.attr,
- &dev_attr_rf_kill.attr,
- &dev_attr_cfg.attr,
- &dev_attr_status.attr,
- &dev_attr_capability.attr,
- NULL,
-};
-
-static const struct attribute_group ipw2100_attribute_group = {
- .attrs = ipw2100_sysfs_entries,
-};
-
-static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
-{
- struct ipw2100_status_queue *q = &priv->status_queue;
-
- IPW_DEBUG_INFO("enter\n");
-
- q->size = entries * sizeof(struct ipw2100_status);
- q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
- GFP_KERNEL);
- if (!q->drv) {
- IPW_DEBUG_WARNING("Can not allocate status queue.\n");
- return -ENOMEM;
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void status_queue_free(struct ipw2100_priv *priv)
-{
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->status_queue.drv) {
- dma_free_coherent(&priv->pci_dev->dev,
- priv->status_queue.size,
- priv->status_queue.drv,
- priv->status_queue.nic);
- priv->status_queue.drv = NULL;
- }
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int bd_queue_allocate(struct ipw2100_priv *priv,
- struct ipw2100_bd_queue *q, int entries)
-{
- IPW_DEBUG_INFO("enter\n");
-
- memset(q, 0, sizeof(struct ipw2100_bd_queue));
-
- q->entries = entries;
- q->size = entries * sizeof(struct ipw2100_bd);
- q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
- GFP_KERNEL);
- if (!q->drv) {
- IPW_DEBUG_INFO
- ("can't allocate shared memory for buffer descriptors\n");
- return -ENOMEM;
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
-{
- IPW_DEBUG_INFO("enter\n");
-
- if (!q)
- return;
-
- if (q->drv) {
- dma_free_coherent(&priv->pci_dev->dev, q->size, q->drv,
- q->nic);
- q->drv = NULL;
- }
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void bd_queue_initialize(struct ipw2100_priv *priv,
- struct ipw2100_bd_queue *q, u32 base, u32 size,
- u32 r, u32 w)
-{
- IPW_DEBUG_INFO("enter\n");
-
- IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
- (u32) q->nic);
-
- write_register(priv->net_dev, base, q->nic);
- write_register(priv->net_dev, size, q->entries);
- write_register(priv->net_dev, r, q->oldest);
- write_register(priv->net_dev, w, q->next);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void ipw2100_kill_works(struct ipw2100_priv *priv)
-{
- priv->stop_rf_kill = 1;
- priv->stop_hang_check = 1;
- cancel_delayed_work_sync(&priv->reset_work);
- cancel_delayed_work_sync(&priv->security_work);
- cancel_delayed_work_sync(&priv->wx_event_work);
- cancel_delayed_work_sync(&priv->hang_check);
- cancel_delayed_work_sync(&priv->rf_kill);
- cancel_delayed_work_sync(&priv->scan_event);
-}
-
-static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err;
- void *v;
- dma_addr_t p;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
- priv->net_dev->name);
- return err;
- }
-
- priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH,
- sizeof(struct ipw2100_tx_packet),
- GFP_KERNEL);
- if (!priv->tx_buffers) {
- bd_queue_free(priv, &priv->tx_queue);
- return -ENOMEM;
- }
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- v = dma_alloc_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header), &p,
- GFP_KERNEL);
- if (!v) {
- printk(KERN_ERR DRV_NAME
- ": %s: PCI alloc failed for tx " "buffers.\n",
- priv->net_dev->name);
- err = -ENOMEM;
- break;
- }
-
- priv->tx_buffers[i].type = DATA;
- priv->tx_buffers[i].info.d_struct.data =
- (struct ipw2100_data_header *)v;
- priv->tx_buffers[i].info.d_struct.data_phys = p;
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
-
- if (i == TX_PENDED_QUEUE_LENGTH)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[j].info.d_struct.data,
- priv->tx_buffers[j].info.d_struct.data_phys);
- }
-
- kfree(priv->tx_buffers);
- priv->tx_buffers = NULL;
-
- return err;
-}
-
-static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- /*
- * reinitialize packet info lists
- */
- INIT_LIST_HEAD(&priv->fw_pend_list);
- INIT_STAT(&priv->fw_pend_stat);
-
- /*
- * reinitialize lists
- */
- INIT_LIST_HEAD(&priv->tx_pend_list);
- INIT_LIST_HEAD(&priv->tx_free_list);
- INIT_STAT(&priv->tx_pend_stat);
- INIT_STAT(&priv->tx_free_stat);
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- /* We simply drop any SKBs that have been queued for
- * transmit */
- if (priv->tx_buffers[i].info.d_struct.txb) {
- libipw_txb_free(priv->tx_buffers[i].info.d_struct.
- txb);
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
-
- list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
- }
-
- SET_STAT(&priv->tx_free_stat, i);
-
- priv->tx_queue.oldest = 0;
- priv->tx_queue.available = priv->tx_queue.entries;
- priv->tx_queue.next = 0;
- INIT_STAT(&priv->txq_stat);
- SET_STAT(&priv->txq_stat, priv->tx_queue.available);
-
- bd_queue_initialize(priv, &priv->tx_queue,
- IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
- IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
- IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
-
- IPW_DEBUG_INFO("exit\n");
-
-}
-
-static void ipw2100_tx_free(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- bd_queue_free(priv, &priv->tx_queue);
-
- if (!priv->tx_buffers)
- return;
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- if (priv->tx_buffers[i].info.d_struct.txb) {
- libipw_txb_free(priv->tx_buffers[i].info.d_struct.
- txb);
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
- if (priv->tx_buffers[i].info.d_struct.data)
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[i].info.d_struct.data,
- priv->tx_buffers[i].info.d_struct.data_phys);
- }
-
- kfree(priv->tx_buffers);
- priv->tx_buffers = NULL;
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err = -EINVAL;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_INFO("failed bd_queue_allocate\n");
- return err;
- }
-
- err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_INFO("failed status_queue_allocate\n");
- bd_queue_free(priv, &priv->rx_queue);
- return err;
- }
-
- /*
- * allocate packets
- */
- priv->rx_buffers = kmalloc_array(RX_QUEUE_LENGTH,
- sizeof(struct ipw2100_rx_packet),
- GFP_KERNEL);
- if (!priv->rx_buffers) {
- IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
-
- bd_queue_free(priv, &priv->rx_queue);
-
- status_queue_free(priv);
-
- return -ENOMEM;
- }
-
- for (i = 0; i < RX_QUEUE_LENGTH; i++) {
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- err = ipw2100_alloc_skb(priv, packet);
- if (unlikely(err)) {
- err = -ENOMEM;
- break;
- }
-
- /* The BD holds the cache aligned address */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
- priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
- priv->status_queue.drv[i].status_fields = 0;
- }
-
- if (i == RX_QUEUE_LENGTH)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_unmap_single(&priv->pci_dev->dev,
- priv->rx_buffers[j].dma_addr,
- sizeof(struct ipw2100_rx_packet),
- DMA_FROM_DEVICE);
- dev_kfree_skb(priv->rx_buffers[j].skb);
- }
-
- kfree(priv->rx_buffers);
- priv->rx_buffers = NULL;
-
- bd_queue_free(priv, &priv->rx_queue);
-
- status_queue_free(priv);
-
- return err;
-}
-
-static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
-{
- IPW_DEBUG_INFO("enter\n");
-
- priv->rx_queue.oldest = 0;
- priv->rx_queue.available = priv->rx_queue.entries - 1;
- priv->rx_queue.next = priv->rx_queue.entries - 1;
-
- INIT_STAT(&priv->rxq_stat);
- SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
-
- bd_queue_initialize(priv, &priv->rx_queue,
- IPW_MEM_HOST_SHARED_RX_BD_BASE,
- IPW_MEM_HOST_SHARED_RX_BD_SIZE,
- IPW_MEM_HOST_SHARED_RX_READ_INDEX,
- IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
-
- /* set up the status queue */
- write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
- priv->status_queue.nic);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void ipw2100_rx_free(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- bd_queue_free(priv, &priv->rx_queue);
- status_queue_free(priv);
-
- if (!priv->rx_buffers)
- return;
-
- for (i = 0; i < RX_QUEUE_LENGTH; i++) {
- if (priv->rx_buffers[i].rxp) {
- dma_unmap_single(&priv->pci_dev->dev,
- priv->rx_buffers[i].dma_addr,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
- dev_kfree_skb(priv->rx_buffers[i].skb);
- }
- }
-
- kfree(priv->rx_buffers);
- priv->rx_buffers = NULL;
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
-{
- u32 length = ETH_ALEN;
- u8 addr[ETH_ALEN];
-
- int err;
-
- err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
- if (err) {
- IPW_DEBUG_INFO("MAC address read failed\n");
- return -EIO;
- }
-
- eth_hw_addr_set(priv->net_dev, addr);
- IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
-
- return 0;
-}
-
-/********************************************************************
- *
- * Firmware Commands
- *
- ********************************************************************/
-
-static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = ADAPTER_ADDRESS,
- .host_command_sequence = 0,
- .host_command_length = ETH_ALEN
- };
- int err;
-
- IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->config & CFG_CUSTOM_MAC) {
- memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
- eth_hw_addr_set(priv->net_dev, priv->mac_addr);
- } else
- memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
- ETH_ALEN);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- IPW_DEBUG_INFO("exit\n");
- return err;
-}
-
-static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = PORT_TYPE,
- .host_command_sequence = 0,
- .host_command_length = sizeof(u32)
- };
- int err;
-
- switch (port_type) {
- case IW_MODE_INFRA:
- cmd.host_command_parameters[0] = IPW_BSS;
- break;
- case IW_MODE_ADHOC:
- cmd.host_command_parameters[0] = IPW_IBSS;
- break;
- }
-
- IPW_DEBUG_HC("PORT_TYPE: %s\n",
- port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = CHANNEL,
- .host_command_sequence = 0,
- .host_command_length = sizeof(u32)
- };
- int err;
-
- cmd.host_command_parameters[0] = channel;
-
- IPW_DEBUG_HC("CHANNEL: %d\n", channel);
-
- /* If BSS then we don't support channel selection */
- if (priv->ieee->iw_mode == IW_MODE_INFRA)
- return 0;
-
- if ((channel != 0) &&
- ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
- return -EINVAL;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- IPW_DEBUG_INFO("Failed to set channel to %d", channel);
- return err;
- }
-
- if (channel)
- priv->config |= CFG_STATIC_CHANNEL;
- else
- priv->config &= ~CFG_STATIC_CHANNEL;
-
- priv->channel = channel;
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SYSTEM_CONFIG,
- .host_command_sequence = 0,
- .host_command_length = 12,
- };
- u32 ibss_mask, len = sizeof(u32);
- int err;
-
- /* Set system configuration */
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
-
- cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
- IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
-
- if (!(priv->config & CFG_LONG_PREAMBLE))
- cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
-
- err = ipw2100_get_ordinal(priv,
- IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
- &ibss_mask, &len);
- if (err)
- ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
-
- cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
- cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
-
- /* 11b only */
- /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
-/* If IPv6 is configured in the kernel then we don't want to filter out all
- * of the multicast packets as IPv6 needs some. */
-#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
- cmd.host_command = ADD_MULTICAST;
- cmd.host_command_sequence = 0;
- cmd.host_command_length = 0;
-
- ipw2100_hw_send_command(priv, &cmd);
-#endif
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = BASIC_TX_RATES,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- /* Set BASIC TX Rate first */
- ipw2100_hw_send_command(priv, &cmd);
-
- /* Set TX Rate */
- cmd.host_command = TX_RATES;
- ipw2100_hw_send_command(priv, &cmd);
-
- /* Set MSDU TX Rate */
- cmd.host_command = MSDU_TX_RATES;
- ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- priv->tx_rates = rate;
-
- return 0;
-}
-
-static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
-{
- struct host_command cmd = {
- .host_command = POWER_MODE,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = power_level;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- if (power_level == IPW_POWER_MODE_CAM)
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- else
- priv->power_mode = IPW_POWER_ENABLED | power_level;
-
-#ifdef IPW2100_TX_POWER
- if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
- /* Set beacon interval */
- cmd.host_command = TX_POWER_INDEX;
- cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
- }
-#endif
-
- return 0;
-}
-
-static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
-{
- struct host_command cmd = {
- .host_command = RTS_THRESHOLD,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- if (threshold & RTS_DISABLED)
- cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
- else
- cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->rts_threshold = threshold;
-
- return 0;
-}
-
-#if 0
-int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
- u32 threshold, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = FRAG_THRESHOLD,
- .host_command_sequence = 0,
- .host_command_length = 4,
- .host_command_parameters[0] = 0,
- };
- int err;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (threshold == 0)
- threshold = DEFAULT_FRAG_THRESHOLD;
- else {
- threshold = max(threshold, MIN_FRAG_THRESHOLD);
- threshold = min(threshold, MAX_FRAG_THRESHOLD);
- }
-
- cmd.host_command_parameters[0] = threshold;
-
- IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- if (!err)
- priv->frag_threshold = threshold;
-
- return err;
-}
-#endif
-
-static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
-{
- struct host_command cmd = {
- .host_command = SHORT_RETRY_LIMIT,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = retry;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->short_retry_limit = retry;
-
- return 0;
-}
-
-static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
-{
- struct host_command cmd = {
- .host_command = LONG_RETRY_LIMIT,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = retry;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->long_retry_limit = retry;
-
- return 0;
-}
-
-static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = MANDATORY_BSSID,
- .host_command_sequence = 0,
- .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
- };
- int err;
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (bssid != NULL)
- IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
- else
- IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
-#endif
- /* if BSSID is empty then we disable mandatory bssid mode */
- if (bssid != NULL)
- memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = DISASSOCIATION_BSSID,
- .host_command_sequence = 0,
- .host_command_length = ETH_ALEN
- };
- int err;
-
- IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
-
- /* The Firmware currently ignores the BSSID and just disassociates from
- * the currently associated AP -- but in the off chance that a future
- * firmware does use the BSSID provided here, we go ahead and try and
- * set it to the currently associated AP's BSSID */
- memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- return err;
-}
-
-static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
- struct ipw2100_wpa_assoc_frame *, int)
- __attribute__ ((unused));
-
-static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
- struct ipw2100_wpa_assoc_frame *wpa_frame,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SET_WPA_IE,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
- };
- int err;
-
- IPW_DEBUG_HC("SET_WPA_IE\n");
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- memcpy(cmd.host_command_parameters, wpa_frame,
- sizeof(struct ipw2100_wpa_assoc_frame));
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- if (ipw2100_enable_adapter(priv))
- err = -EIO;
- }
-
- return err;
-}
-
-struct security_info_params {
- u32 allowed_ciphers;
- u16 version;
- u8 auth_mode;
- u8 replay_counters_number;
- u8 unicast_using_group;
-} __packed;
-
-static int ipw2100_set_security_information(struct ipw2100_priv *priv,
- int auth_mode,
- int security_level,
- int unicast_using_group,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SET_SECURITY_INFORMATION,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct security_info_params)
- };
- struct security_info_params *security =
- (struct security_info_params *)&cmd.host_command_parameters;
- int err;
- memset(security, 0, sizeof(*security));
-
- /* If shared key AP authentication is turned on, then we need to
- * configure the firmware to try and use it.
- *
- * Actual data encryption/decryption is handled by the host. */
- security->auth_mode = auth_mode;
- security->unicast_using_group = unicast_using_group;
-
- switch (security_level) {
- default:
- case SEC_LEVEL_0:
- security->allowed_ciphers = IPW_NONE_CIPHER;
- break;
- case SEC_LEVEL_1:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER;
- break;
- case SEC_LEVEL_2:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
- break;
- case SEC_LEVEL_2_CKIP:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
- break;
- case SEC_LEVEL_3:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
- break;
- }
-
- IPW_DEBUG_HC
- ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
- security->auth_mode, security->allowed_ciphers, security_level);
-
- security->replay_counters_number = 0;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
-{
- struct host_command cmd = {
- .host_command = TX_POWER_INDEX,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err = 0;
- u32 tmp = tx_power;
-
- if (tx_power != IPW_TX_POWER_DEFAULT)
- tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
- (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
-
- cmd.host_command_parameters[0] = tmp;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- err = ipw2100_hw_send_command(priv, &cmd);
- if (!err)
- priv->tx_power = tx_power;
-
- return 0;
-}
-
-static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
- u32 interval, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = BEACON_INTERVAL,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = interval;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
-{
- ipw2100_tx_initialize(priv);
- ipw2100_rx_initialize(priv);
- ipw2100_msg_initialize(priv);
-}
-
-static void ipw2100_queues_free(struct ipw2100_priv *priv)
-{
- ipw2100_tx_free(priv);
- ipw2100_rx_free(priv);
- ipw2100_msg_free(priv);
-}
-
-static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
-{
- if (ipw2100_tx_allocate(priv) ||
- ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
- goto fail;
-
- return 0;
-
- fail:
- ipw2100_tx_free(priv);
- ipw2100_rx_free(priv);
- ipw2100_msg_free(priv);
- return -ENOMEM;
-}
-
-#define IPW_PRIVACY_CAPABLE 0x0008
-
-static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = WEP_FLAGS,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = flags;
-
- IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-struct ipw2100_wep_key {
- u8 idx;
- u8 len;
- u8 key[13];
-};
-
-/* Macros to ease up priting WEP keys */
-#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
-#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
-#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
-#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
-
-/**
- * ipw2100_set_key() - Set a the wep key
- *
- * @priv: struct to work on
- * @idx: index of the key we want to set
- * @key: ptr to the key data to set
- * @len: length of the buffer at @key
- * @batch_mode: FIXME perform the operation in batch mode, not
- * disabling the device.
- *
- * @returns 0 if OK, < 0 errno code on error.
- *
- * Fill out a command structure with the new wep key, length an
- * index and send it down the wire.
- */
-static int ipw2100_set_key(struct ipw2100_priv *priv,
- int idx, char *key, int len, int batch_mode)
-{
- int keylen = len ? (len <= 5 ? 5 : 13) : 0;
- struct host_command cmd = {
- .host_command = WEP_KEY_INFO,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct ipw2100_wep_key),
- };
- struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
- int err;
-
- IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
- idx, keylen, len);
-
- /* NOTE: We don't check cached values in case the firmware was reset
- * or some other problem is occurring. If the user is setting the key,
- * then we push the change */
-
- wep_key->idx = idx;
- wep_key->len = keylen;
-
- if (keylen) {
- memcpy(wep_key->key, key, len);
- memset(wep_key->key + len, 0, keylen - len);
- }
-
- /* Will be optimized out on debug not being configured in */
- if (keylen == 0)
- IPW_DEBUG_WEP("%s: Clearing key %d\n",
- priv->net_dev->name, wep_key->idx);
- else if (keylen == 5)
- IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_64(wep_key->key));
- else
- IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
- "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_128(wep_key->key));
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- int err2 = ipw2100_enable_adapter(priv);
- if (err == 0)
- err = err2;
- }
- return err;
-}
-
-static int ipw2100_set_key_index(struct ipw2100_priv *priv,
- int idx, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = WEP_KEY_INDEX,
- .host_command_sequence = 0,
- .host_command_length = 4,
- .host_command_parameters = {idx},
- };
- int err;
-
- IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
-
- if (idx < 0 || idx > 3)
- return -EINVAL;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
-{
- int i, err, auth_mode, sec_level, use_group;
-
- if (!(priv->status & STATUS_RUNNING))
- return 0;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (!priv->ieee->sec.enabled) {
- err =
- ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
- SEC_LEVEL_0, 0, 1);
- } else {
- auth_mode = IPW_AUTH_OPEN;
- if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
- if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
- auth_mode = IPW_AUTH_SHARED;
- else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
- auth_mode = IPW_AUTH_LEAP_CISCO_ID;
- }
-
- sec_level = SEC_LEVEL_0;
- if (priv->ieee->sec.flags & SEC_LEVEL)
- sec_level = priv->ieee->sec.level;
-
- use_group = 0;
- if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
- use_group = priv->ieee->sec.unicast_uses_group;
-
- err =
- ipw2100_set_security_information(priv, auth_mode, sec_level,
- use_group, 1);
- }
-
- if (err)
- goto exit;
-
- if (priv->ieee->sec.enabled) {
- for (i = 0; i < 4; i++) {
- if (!(priv->ieee->sec.flags & (1 << i))) {
- memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
- priv->ieee->sec.key_sizes[i] = 0;
- } else {
- err = ipw2100_set_key(priv, i,
- priv->ieee->sec.keys[i],
- priv->ieee->sec.
- key_sizes[i], 1);
- if (err)
- goto exit;
- }
- }
-
- ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
- }
-
- /* Always enable privacy so the Host can filter WEP packets if
- * encrypted data is sent up */
- err =
- ipw2100_set_wep_flags(priv,
- priv->ieee->sec.
- enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
- if (err)
- goto exit;
-
- priv->status &= ~STATUS_SECURITY_UPDATED;
-
- exit:
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static void ipw2100_security_work(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, security_work.work);
-
- /* If we happen to have reconnected before we get a chance to
- * process this, then update the security settings--which causes
- * a disassociation to occur */
- if (!(priv->status & STATUS_ASSOCIATED) &&
- priv->status & STATUS_SECURITY_UPDATED)
- ipw2100_configure_security(priv, 0);
-}
-
-static void shim__set_security(struct net_device *dev,
- struct libipw_security *sec)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int i;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED))
- goto done;
-
- for (i = 0; i < 4; i++) {
- if (sec->flags & (1 << i)) {
- priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
- if (sec->key_sizes[i] == 0)
- priv->ieee->sec.flags &= ~(1 << i);
- else
- memcpy(priv->ieee->sec.keys[i], sec->keys[i],
- sec->key_sizes[i]);
- if (sec->level == SEC_LEVEL_1) {
- priv->ieee->sec.flags |= (1 << i);
- priv->status |= STATUS_SECURITY_UPDATED;
- } else
- priv->ieee->sec.flags &= ~(1 << i);
- }
- }
-
- if ((sec->flags & SEC_ACTIVE_KEY) &&
- priv->ieee->sec.active_key != sec->active_key) {
- priv->ieee->sec.active_key = sec->active_key;
- priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->ieee->sec.auth_mode != sec->auth_mode)) {
- priv->ieee->sec.auth_mode = sec->auth_mode;
- priv->ieee->sec.flags |= SEC_AUTH_MODE;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
- priv->ieee->sec.flags |= SEC_ENABLED;
- priv->ieee->sec.enabled = sec->enabled;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENCRYPT)
- priv->ieee->sec.encrypt = sec->encrypt;
-
- if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
- priv->ieee->sec.level = sec->level;
- priv->ieee->sec.flags |= SEC_LEVEL;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
- priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
-
-/* As a temporary work around to enable WPA until we figure out why
- * wpa_supplicant toggles the security capability of the driver, which
- * forces a disassociation with force_update...
- *
- * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
- ipw2100_configure_security(priv, 0);
- done:
- mutex_unlock(&priv->action_mutex);
-}
-
-static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
-{
- int err;
- int batch_mode = 1;
- u8 *bssid;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- err = ipw2100_set_channel(priv, priv->channel, batch_mode);
- if (err)
- return err;
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
- }
-#endif /* CONFIG_IPW2100_MONITOR */
-
- err = ipw2100_read_mac_address(priv);
- if (err)
- return -EIO;
-
- err = ipw2100_set_mac_address(priv, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
- if (err)
- return err;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- err = ipw2100_set_channel(priv, priv->channel, batch_mode);
- if (err)
- return err;
- }
-
- err = ipw2100_system_config(priv, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
- if (err)
- return err;
-
- /* Default to power mode OFF */
- err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
- if (err)
- return err;
-
- err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
- if (err)
- return err;
-
- if (priv->config & CFG_STATIC_BSSID)
- bssid = priv->bssid;
- else
- bssid = NULL;
- err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
- if (err)
- return err;
-
- if (priv->config & CFG_STATIC_ESSID)
- err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
- batch_mode);
- else
- err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_configure_security(priv, batch_mode);
- if (err)
- return err;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- err =
- ipw2100_set_ibss_beacon_interval(priv,
- priv->beacon_interval,
- batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_tx_power(priv, priv->tx_power);
- if (err)
- return err;
- }
-
- /*
- err = ipw2100_set_fragmentation_threshold(
- priv, priv->frag_threshold, batch_mode);
- if (err)
- return err;
- */
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-/*************************************************************************
- *
- * EXTERNALLY CALLED METHODS
- *
- *************************************************************************/
-
-/* This method is called by the network layer -- not to be confused with
- * ipw2100_set_mac_address() declared above called by this driver (and this
- * method as well) to talk to the firmware */
-static int ipw2100_set_address(struct net_device *dev, void *p)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct sockaddr *addr = p;
- int err = 0;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
-
- mutex_lock(&priv->action_mutex);
-
- priv->config |= CFG_CUSTOM_MAC;
- memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
-
- err = ipw2100_set_mac_address(priv, 0);
- if (err)
- goto done;
-
- priv->reset_backoff = 0;
- mutex_unlock(&priv->action_mutex);
- ipw2100_reset_adapter(&priv->reset_work.work);
- return 0;
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_open(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- unsigned long flags;
- IPW_DEBUG_INFO("dev->open\n");
-
- spin_lock_irqsave(&priv->low_lock, flags);
- if (priv->status & STATUS_ASSOCIATED) {
- netif_carrier_on(dev);
- netif_start_queue(dev);
- }
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- return 0;
-}
-
-static int ipw2100_close(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- unsigned long flags;
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
-
- IPW_DEBUG_INFO("enter\n");
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->status & STATUS_ASSOCIATED)
- netif_carrier_off(dev);
- netif_stop_queue(dev);
-
- /* Flush the TX queue ... */
- while (!list_empty(&priv->tx_pend_list)) {
- element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- list_del(element);
- DEC_STAT(&priv->tx_pend_stat);
-
- libipw_txb_free(packet->info.d_struct.txb);
- packet->info.d_struct.txb = NULL;
-
- list_add_tail(element, &priv->tx_free_list);
- INC_STAT(&priv->tx_free_stat);
- }
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-/*
- * TODO: Fix this function... its just wrong
- */
-static void ipw2100_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- dev->stats.tx_errors++;
-
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- return;
-#endif
-
- IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
- dev->name);
- schedule_reset(priv);
-}
-
-static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
-{
- /* This is called when wpa_supplicant loads and closes the driver
- * interface. */
- priv->ieee->wpa_enabled = value;
- return 0;
-}
-
-static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
-{
-
- struct libipw_device *ieee = priv->ieee;
- struct libipw_security sec = {
- .flags = SEC_AUTH_MODE,
- };
- int ret = 0;
-
- if (value & IW_AUTH_ALG_SHARED_KEY) {
- sec.auth_mode = WLAN_AUTH_SHARED_KEY;
- ieee->open_wep = 0;
- } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
- sec.auth_mode = WLAN_AUTH_OPEN;
- ieee->open_wep = 1;
- } else if (value & IW_AUTH_ALG_LEAP) {
- sec.auth_mode = WLAN_AUTH_LEAP;
- ieee->open_wep = 1;
- } else
- return -EINVAL;
-
- if (ieee->set_security)
- ieee->set_security(ieee->dev, &sec);
- else
- ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
- char *wpa_ie, int wpa_ie_len)
-{
-
- struct ipw2100_wpa_assoc_frame frame;
-
- frame.fixed_ie_mask = 0;
-
- /* copy WPA IE */
- memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
- frame.var_ie_len = wpa_ie_len;
-
- /* make sure WPA is enabled */
- ipw2100_wpa_enable(priv, 1);
- ipw2100_set_wpa_ie(priv, &frame, 0);
-}
-
-static void ipw_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- char fw_ver[64], ucode_ver[64];
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
-
- ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
- ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
-
- snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
- fw_ver, priv->eeprom_version, ucode_ver);
-
- strscpy(info->bus_info, pci_name(priv->pci_dev),
- sizeof(info->bus_info));
-}
-
-static u32 ipw2100_ethtool_get_link(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
-}
-
-static const struct ethtool_ops ipw2100_ethtool_ops = {
- .get_link = ipw2100_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
-};
-
-static void ipw2100_hang_check(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, hang_check.work);
- unsigned long flags;
- u32 rtc = 0xa5a5a5a5;
- u32 len = sizeof(rtc);
- int restart = 0;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->fatal_error != 0) {
- /* If fatal_error is set then we need to restart */
- IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
- priv->net_dev->name);
-
- restart = 1;
- } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
- (rtc == priv->last_rtc)) {
- /* Check if firmware is hung */
- IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
- priv->net_dev->name);
-
- restart = 1;
- }
-
- if (restart) {
- /* Kill timer */
- priv->stop_hang_check = 1;
- priv->hangs++;
-
- /* Restart the NIC */
- schedule_reset(priv);
- }
-
- priv->last_rtc = rtc;
-
- if (!priv->stop_hang_check)
- schedule_delayed_work(&priv->hang_check, HZ / 2);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-}
-
-static void ipw2100_rf_kill(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, rf_kill.work);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
- if (!priv->stop_rf_kill)
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(HZ));
- goto exit_unlock;
- }
-
- /* RF Kill is now disabled, so bring the device back up */
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
- "device\n");
- schedule_reset(priv);
- } else
- IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
- "enabled\n");
-
- exit_unlock:
- spin_unlock_irqrestore(&priv->low_lock, flags);
-}
-
-static void ipw2100_irq_tasklet(struct tasklet_struct *t);
-
-static const struct net_device_ops ipw2100_netdev_ops = {
- .ndo_open = ipw2100_open,
- .ndo_stop = ipw2100_close,
- .ndo_start_xmit = libipw_xmit,
- .ndo_tx_timeout = ipw2100_tx_timeout,
- .ndo_set_mac_address = ipw2100_set_address,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* Look into using netdev destructor to shutdown libipw? */
-
-static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
- void __iomem * ioaddr)
-{
- struct ipw2100_priv *priv;
- struct net_device *dev;
-
- dev = alloc_libipw(sizeof(struct ipw2100_priv), 0);
- if (!dev)
- return NULL;
- priv = libipw_priv(dev);
- priv->ieee = netdev_priv(dev);
- priv->pci_dev = pci_dev;
- priv->net_dev = dev;
- priv->ioaddr = ioaddr;
-
- priv->ieee->hard_start_xmit = ipw2100_tx;
- priv->ieee->set_security = shim__set_security;
-
- priv->ieee->perfect_rssi = -20;
- priv->ieee->worst_rssi = -85;
-
- dev->netdev_ops = &ipw2100_netdev_ops;
- dev->ethtool_ops = &ipw2100_ethtool_ops;
- dev->wireless_handlers = &ipw2100_wx_handler_def;
- priv->wireless_data.libipw = priv->ieee;
- dev->wireless_data = &priv->wireless_data;
- dev->watchdog_timeo = 3 * HZ;
- dev->irq = 0;
- dev->min_mtu = 68;
- dev->max_mtu = LIBIPW_DATA_LEN;
-
- /* NOTE: We don't use the wireless_handlers hook
- * in dev as the system will start throwing WX requests
- * to us before we're actually initialized and it just
- * ends up causing problems. So, we just handle
- * the WX extensions through the ipw2100_ioctl interface */
-
- /* memset() puts everything to 0, so we only have explicitly set
- * those values that need to be something else */
-
- /* If power management is turned on, default to AUTO mode */
- priv->power_mode = IPW_POWER_AUTO;
-
-#ifdef CONFIG_IPW2100_MONITOR
- priv->config |= CFG_CRC_CHECK;
-#endif
- priv->ieee->wpa_enabled = 0;
- priv->ieee->drop_unencrypted = 0;
- priv->ieee->privacy_invoked = 0;
- priv->ieee->ieee802_1x = 1;
-
- /* Set module parameters */
- switch (network_mode) {
- case 1:
- priv->ieee->iw_mode = IW_MODE_ADHOC;
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case 2:
- priv->ieee->iw_mode = IW_MODE_MONITOR;
- break;
-#endif
- default:
- case 0:
- priv->ieee->iw_mode = IW_MODE_INFRA;
- break;
- }
-
- if (disable == 1)
- priv->status |= STATUS_RF_KILL_SW;
-
- if (channel != 0 &&
- ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
- priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = channel;
- }
-
- if (associate)
- priv->config |= CFG_ASSOCIATE;
-
- priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
- priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
- priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
- priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
- priv->tx_power = IPW_TX_POWER_DEFAULT;
- priv->tx_rates = DEFAULT_TX_RATES;
-
- strcpy(priv->nick, "ipw2100");
-
- spin_lock_init(&priv->low_lock);
- mutex_init(&priv->action_mutex);
- mutex_init(&priv->adapter_mutex);
-
- init_waitqueue_head(&priv->wait_command_queue);
-
- netif_carrier_off(dev);
-
- INIT_LIST_HEAD(&priv->msg_free_list);
- INIT_LIST_HEAD(&priv->msg_pend_list);
- INIT_STAT(&priv->msg_free_stat);
- INIT_STAT(&priv->msg_pend_stat);
-
- INIT_LIST_HEAD(&priv->tx_free_list);
- INIT_LIST_HEAD(&priv->tx_pend_list);
- INIT_STAT(&priv->tx_free_stat);
- INIT_STAT(&priv->tx_pend_stat);
-
- INIT_LIST_HEAD(&priv->fw_pend_list);
- INIT_STAT(&priv->fw_pend_stat);
-
- INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
- INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
- INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
- INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
- INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
- INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event);
-
- tasklet_setup(&priv->irq_tasklet, ipw2100_irq_tasklet);
-
- /* NOTE: We do not start the deferred work for status checks yet */
- priv->stop_rf_kill = 1;
- priv->stop_hang_check = 1;
-
- return dev;
-}
-
-static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
- const struct pci_device_id *ent)
-{
- void __iomem *ioaddr;
- struct net_device *dev = NULL;
- struct ipw2100_priv *priv = NULL;
- int err = 0;
- int registered = 0;
- u32 val;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (!(pci_resource_flags(pci_dev, 0) & IORESOURCE_MEM)) {
- IPW_DEBUG_INFO("weird - resource type is not memory\n");
- err = -ENODEV;
- goto out;
- }
-
- ioaddr = pci_iomap(pci_dev, 0, 0);
- if (!ioaddr) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ioremap.\n");
- err = -EIO;
- goto fail;
- }
-
- /* allocate and initialize our net_device */
- dev = ipw2100_alloc_device(pci_dev, ioaddr);
- if (!dev) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ipw2100_alloc_device.\n");
- err = -ENOMEM;
- goto fail;
- }
-
- /* set up PCI mappings for device */
- err = pci_enable_device(pci_dev);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_enable_device.\n");
- return err;
- }
-
- priv = libipw_priv(dev);
-
- pci_set_master(pci_dev);
- pci_set_drvdata(pci_dev, priv);
-
- err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_set_dma_mask.\n");
- pci_disable_device(pci_dev);
- return err;
- }
-
- err = pci_request_regions(pci_dev, DRV_NAME);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_request_regions.\n");
- pci_disable_device(pci_dev);
- return err;
- }
-
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_read_config_dword(pci_dev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
-
- if (!ipw2100_hw_is_adapter_in_system(dev)) {
- printk(KERN_WARNING DRV_NAME
- "Device not found via register read.\n");
- err = -ENODEV;
- goto fail;
- }
-
- SET_NETDEV_DEV(dev, &pci_dev->dev);
-
- /* Force interrupts to be shut off on the device */
- priv->status |= STATUS_INT_ENABLED;
- ipw2100_disable_interrupts(priv);
-
- /* Allocate and initialize the Tx/Rx queues and lists */
- if (ipw2100_queues_allocate(priv)) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ipw2100_queues_allocate.\n");
- err = -ENOMEM;
- goto fail;
- }
- ipw2100_queues_initialize(priv);
-
- err = request_irq(pci_dev->irq,
- ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling request_irq: %d.\n", pci_dev->irq);
- goto fail;
- }
- dev->irq = pci_dev->irq;
-
- IPW_DEBUG_INFO("Attempting to register device...\n");
-
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2100 Network Connection\n");
-
- err = ipw2100_up(priv, 1);
- if (err)
- goto fail;
-
- err = ipw2100_wdev_init(dev);
- if (err)
- goto fail;
- registered = 1;
-
- /* Bring up the interface. Pre 0.46, after we registered the
- * network device we would call ipw2100_up. This introduced a race
- * condition with newer hotplug configurations (network was coming
- * up and making calls before the device was initialized).
- */
- err = register_netdev(dev);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling register_netdev.\n");
- goto fail;
- }
- registered = 2;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
-
- /* perform this after register_netdev so that dev->name is set */
- err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
- if (err)
- goto fail_unlock;
-
- /* If the RF Kill switch is disabled, go ahead and complete the
- * startup sequence */
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- /* Enable the adapter - sends HOST_COMPLETE */
- if (ipw2100_enable_adapter(priv)) {
- printk(KERN_WARNING DRV_NAME
- ": %s: failed in call to enable adapter.\n",
- priv->net_dev->name);
- ipw2100_hw_stop_adapter(priv);
- err = -EIO;
- goto fail_unlock;
- }
-
- /* Start a scan . . . */
- ipw2100_set_scan_options(priv);
- ipw2100_start_scan(priv);
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- priv->status |= STATUS_INITIALIZED;
-
- mutex_unlock(&priv->action_mutex);
-out:
- return err;
-
- fail_unlock:
- mutex_unlock(&priv->action_mutex);
- fail:
- if (dev) {
- if (registered >= 2)
- unregister_netdev(dev);
-
- if (registered) {
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->bg_band.channels);
- }
-
- ipw2100_hw_stop_adapter(priv);
-
- ipw2100_disable_interrupts(priv);
-
- if (dev->irq)
- free_irq(dev->irq, priv);
-
- ipw2100_kill_works(priv);
-
- /* These are safe to call even if they weren't allocated */
- ipw2100_queues_free(priv);
- sysfs_remove_group(&pci_dev->dev.kobj,
- &ipw2100_attribute_group);
-
- free_libipw(dev, 0);
- }
-
- pci_iounmap(pci_dev, ioaddr);
-
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
- goto out;
-}
-
-static void ipw2100_pci_remove_one(struct pci_dev *pci_dev)
-{
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
- struct net_device *dev = priv->net_dev;
-
- mutex_lock(&priv->action_mutex);
-
- priv->status &= ~STATUS_INITIALIZED;
-
- sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
-
-#ifdef CONFIG_PM
- if (ipw2100_firmware.version)
- ipw2100_release_firmware(priv, &ipw2100_firmware);
-#endif
- /* Take down the hardware */
- ipw2100_down(priv);
-
- /* Release the mutex so that the network subsystem can
- * complete any needed calls into the driver... */
- mutex_unlock(&priv->action_mutex);
-
- /* Unregister the device first - this results in close()
- * being called if the device is open. If we free storage
- * first, then close() will crash.
- * FIXME: remove the comment above. */
- unregister_netdev(dev);
-
- ipw2100_kill_works(priv);
-
- ipw2100_queues_free(priv);
-
- /* Free potential debugging firmware snapshot */
- ipw2100_snapshot_free(priv);
-
- free_irq(dev->irq, priv);
-
- pci_iounmap(pci_dev, priv->ioaddr);
-
- /* wiphy_unregister needs to be here, before free_libipw */
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->bg_band.channels);
- free_libipw(dev, 0);
-
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int __maybe_unused ipw2100_suspend(struct device *dev_d)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(dev_d);
- struct net_device *dev = priv->net_dev;
-
- IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
-
- mutex_lock(&priv->action_mutex);
- if (priv->status & STATUS_INITIALIZED) {
- /* Take down the device; powers it off, etc. */
- ipw2100_down(priv);
- }
-
- /* Remove the PRESENT state of the device */
- netif_device_detach(dev);
-
- priv->suspend_at = ktime_get_boottime_seconds();
-
- mutex_unlock(&priv->action_mutex);
-
- return 0;
-}
-
-static int __maybe_unused ipw2100_resume(struct device *dev_d)
-{
- struct pci_dev *pci_dev = to_pci_dev(dev_d);
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
- struct net_device *dev = priv->net_dev;
- u32 val;
-
- if (IPW2100_PM_DISABLED)
- return 0;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
-
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
- * from interfering with C3 CPU state. pci_restore_state won't help
- * here since it only restores the first 64 bytes pci config header.
- */
- pci_read_config_dword(pci_dev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
-
- /* Set the device back into the PRESENT state; this will also wake
- * the queue of needed */
- netif_device_attach(dev);
-
- priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at;
-
- /* Bring the device back up */
- if (!(priv->status & STATUS_RF_KILL_SW))
- ipw2100_up(priv, 0);
-
- mutex_unlock(&priv->action_mutex);
-
- return 0;
-}
-
-static void ipw2100_shutdown(struct pci_dev *pci_dev)
-{
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
-
- /* Take down the device; powers it off, etc. */
- ipw2100_down(priv);
-
- pci_disable_device(pci_dev);
-}
-
-#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
-
-static const struct pci_device_id ipw2100_pci_id_table[] = {
- IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
- IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
-
-static SIMPLE_DEV_PM_OPS(ipw2100_pm_ops, ipw2100_suspend, ipw2100_resume);
-
-static struct pci_driver ipw2100_pci_driver = {
- .name = DRV_NAME,
- .id_table = ipw2100_pci_id_table,
- .probe = ipw2100_pci_init_one,
- .remove = ipw2100_pci_remove_one,
- .driver.pm = &ipw2100_pm_ops,
- .shutdown = ipw2100_shutdown,
-};
-
-/*
- * Initialize the ipw2100 driver/module
- *
- * @returns 0 if ok, < 0 errno node con error.
- *
- * Note: we cannot init the /proc stuff until the PCI driver is there,
- * or we risk an unlikely race condition on someone accessing
- * uninitialized data in the PCI dev struct through /proc.
- */
-static int __init ipw2100_init(void)
-{
- int ret;
-
- printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
- printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
-
- cpu_latency_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
-
- ret = pci_register_driver(&ipw2100_pci_driver);
- if (ret)
- goto out;
-
-#ifdef CONFIG_IPW2100_DEBUG
- ipw2100_debug_level = debug;
- ret = driver_create_file(&ipw2100_pci_driver.driver,
- &driver_attr_debug_level);
-#endif
-
-out:
- return ret;
-}
-
-/*
- * Cleanup ipw2100 driver registration
- */
-static void __exit ipw2100_exit(void)
-{
- /* FIXME: IPG: check that we have no instances of the devices open */
-#ifdef CONFIG_IPW2100_DEBUG
- driver_remove_file(&ipw2100_pci_driver.driver,
- &driver_attr_debug_level);
-#endif
- pci_unregister_driver(&ipw2100_pci_driver);
- cpu_latency_qos_remove_request(&ipw2100_pm_qos_req);
-}
-
-module_init(ipw2100_init);
-module_exit(ipw2100_exit);
-
-static int ipw2100_wx_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- if (!(priv->status & STATUS_ASSOCIATED))
- strcpy(wrqu->name, "unassociated");
- else
- snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
-
- IPW_DEBUG_WX("Name: %s\n", wrqu->name);
- return 0;
-}
-
-static int ipw2100_wx_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_freq *fwrq = &wrqu->freq;
- int err = 0;
-
- if (priv->ieee->iw_mode == IW_MODE_INFRA)
- return -EOPNOTSUPP;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- /* if setting by freq convert to channel */
- if (fwrq->e == 1) {
- if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
- int f = fwrq->m / 100000;
- int c = 0;
-
- while ((c < REG_MAX_CHANNEL) &&
- (f != ipw2100_frequencies[c]))
- c++;
-
- /* hack to fall through */
- fwrq->e = 0;
- fwrq->m = c + 1;
- }
- }
-
- if (fwrq->e > 0 || fwrq->m > 1000) {
- err = -EOPNOTSUPP;
- goto done;
- } else { /* Set the channel */
- IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
- err = ipw2100_set_channel(priv, fwrq->m, 0);
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->freq.e = 0;
-
- /* If we are associated, trying to associate, or have a statically
- * configured CHANNEL then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_CHANNEL ||
- priv->status & STATUS_ASSOCIATED)
- wrqu->freq.m = priv->channel;
- else
- wrqu->freq.m = 0;
-
- IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
- return 0;
-
-}
-
-static int ipw2100_wx_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
-
- if (wrqu->mode == priv->ieee->iw_mode)
- return 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- switch (wrqu->mode) {
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
- break;
-#endif /* CONFIG_IPW2100_MONITOR */
- case IW_MODE_ADHOC:
- err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
- break;
- case IW_MODE_INFRA:
- case IW_MODE_AUTO:
- default:
- err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
- break;
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->mode = priv->ieee->iw_mode;
- IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
-
- return 0;
-}
-
-#define POWER_MODES 5
-
-/* Values are in microsecond */
-static const s32 timeout_duration[POWER_MODES] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-
-static const s32 period_duration[POWER_MODES] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
-static int ipw2100_wx_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_range *range = (struct iw_range *)extra;
- u16 val;
- int i, level;
-
- wrqu->data.length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- /* Let's try to keep this struct in the same order as in
- * linux/include/wireless.h
- */
-
- /* TODO: See what values we can set, and remove the ones we can't
- * set, or fill them with some default data.
- */
-
- /* ~5 Mb/s real (802.11b) */
- range->throughput = 5 * 1000 * 1000;
-
-// range->sensitivity; /* signal level threshold range */
-
- range->max_qual.qual = 100;
- /* TODO: Find real max RSSI and stick here */
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
-
- range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
- range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
-
- range->num_bitrates = RATE_COUNT;
-
- for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
- range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
- }
-
- range->min_rts = MIN_RTS_THRESHOLD;
- range->max_rts = MAX_RTS_THRESHOLD;
- range->min_frag = MIN_FRAG_THRESHOLD;
- range->max_frag = MAX_FRAG_THRESHOLD;
-
- range->min_pmp = period_duration[0]; /* Minimal PM period */
- range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
- range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
- range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
-
- /* How to decode max/min PM period */
- range->pmp_flags = IW_POWER_PERIOD;
- /* How to decode max/min PM period */
- range->pmt_flags = IW_POWER_TIMEOUT;
- /* What PM options are supported */
- range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13; /* Different token sizes */
- range->num_encoding_sizes = 2; /* Number of entry in the list */
- range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
-// range->encoding_login_index; /* token index for login token */
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- range->txpower_capa = IW_TXPOW_DBM;
- range->num_txpower = IW_MAX_TXPOWER;
- for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
- i < IW_MAX_TXPOWER;
- i++, level -=
- ((IPW_TX_POWER_MAX_DBM -
- IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
- range->txpower[i] = level / 16;
- } else {
- range->txpower_capa = 0;
- range->num_txpower = 0;
- }
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
-// range->retry_capa; /* What retry options are supported */
-// range->retry_flags; /* How to decode max/min retry limit */
-// range->r_time_flags; /* How to decode max/min retry life */
-// range->min_retry; /* Minimal number of retries */
-// range->max_retry; /* Maximal number of retries */
-// range->min_r_time; /* Minimal retry lifetime */
-// range->max_r_time; /* Maximal retry lifetime */
-
- range->num_channels = FREQ_COUNT;
-
- val = 0;
- for (i = 0; i < FREQ_COUNT; i++) {
- // TODO: Include only legal frequencies for some countries
-// if (local->channel_mask & (1 << i)) {
- range->freq[val].i = i + 1;
- range->freq[val].m = ipw2100_frequencies[i] * 100000;
- range->freq[val].e = 1;
- val++;
-// }
- if (val == IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = val;
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWAP));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- IPW_DEBUG_WX("GET Range\n");
-
- return 0;
-}
-
-static int ipw2100_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- // sanity checks
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- return -EINVAL;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
- is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
- /* we disable mandatory BSSID association */
- IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
- priv->config &= ~CFG_STATIC_BSSID;
- err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
- goto done;
- }
-
- priv->config |= CFG_STATIC_BSSID;
- memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
-
- err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
-
- IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured BSSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
- } else
- eth_zero_addr(wrqu->ap_addr.sa_data);
-
- IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
- return 0;
-}
-
-static int ipw2100_wx_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- char *essid = ""; /* ANY */
- int length = 0;
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->essid.flags && wrqu->essid.length) {
- length = wrqu->essid.length;
- essid = extra;
- }
-
- if (length == 0) {
- IPW_DEBUG_WX("Setting ESSID to ANY\n");
- priv->config &= ~CFG_STATIC_ESSID;
- err = ipw2100_set_essid(priv, NULL, 0, 0);
- goto done;
- }
-
- length = min(length, IW_ESSID_MAX_SIZE);
-
- priv->config |= CFG_STATIC_ESSID;
-
- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
- IPW_DEBUG_WX("ESSID set to current ESSID.\n");
- err = 0;
- goto done;
- }
-
- IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, essid, length);
-
- priv->essid_len = length;
- memcpy(priv->essid, essid, priv->essid_len);
-
- err = ipw2100_set_essid(priv, essid, length, 0);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured ESSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
- IPW_DEBUG_WX("Getting essid: '%*pE'\n",
- priv->essid_len, priv->essid);
- memcpy(extra, priv->essid, priv->essid_len);
- wrqu->essid.length = priv->essid_len;
- wrqu->essid.flags = 1; /* active */
- } else {
- IPW_DEBUG_WX("Getting essid: ANY\n");
- wrqu->essid.length = 0;
- wrqu->essid.flags = 0; /* active */
- }
-
- return 0;
-}
-
-static int ipw2100_wx_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (wrqu->data.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
-
- IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
-
- return 0;
-}
-
-static int ipw2100_wx_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->data.length = strlen(priv->nick);
- memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
-
- IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
-
- return 0;
-}
-
-static int ipw2100_wx_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- u32 target_rate = wrqu->bitrate.value;
- u32 rate;
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- rate = 0;
-
- if (target_rate == 1000000 ||
- (!wrqu->bitrate.fixed && target_rate > 1000000))
- rate |= TX_RATE_1_MBIT;
- if (target_rate == 2000000 ||
- (!wrqu->bitrate.fixed && target_rate > 2000000))
- rate |= TX_RATE_2_MBIT;
- if (target_rate == 5500000 ||
- (!wrqu->bitrate.fixed && target_rate > 5500000))
- rate |= TX_RATE_5_5_MBIT;
- if (target_rate == 11000000 ||
- (!wrqu->bitrate.fixed && target_rate > 11000000))
- rate |= TX_RATE_11_MBIT;
- if (rate == 0)
- rate = DEFAULT_TX_RATES;
-
- err = ipw2100_set_tx_rates(priv, rate, 0);
-
- IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int val;
- unsigned int len = sizeof(val);
- int err = 0;
-
- if (!(priv->status & STATUS_ENABLED) ||
- priv->status & STATUS_RF_KILL_MASK ||
- !(priv->status & STATUS_ASSOCIATED)) {
- wrqu->bitrate.value = 0;
- return 0;
- }
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
- if (err) {
- IPW_DEBUG_WX("failed querying ordinals.\n");
- goto done;
- }
-
- switch (val & TX_RATE_MASK) {
- case TX_RATE_1_MBIT:
- wrqu->bitrate.value = 1000000;
- break;
- case TX_RATE_2_MBIT:
- wrqu->bitrate.value = 2000000;
- break;
- case TX_RATE_5_5_MBIT:
- wrqu->bitrate.value = 5500000;
- break;
- case TX_RATE_11_MBIT:
- wrqu->bitrate.value = 11000000;
- break;
- default:
- wrqu->bitrate.value = 0;
- }
-
- IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int value, err;
-
- /* Auto RTS not yet supported */
- if (wrqu->rts.fixed == 0)
- return -EINVAL;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->rts.disabled)
- value = priv->rts_threshold | RTS_DISABLED;
- else {
- if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
- err = -EINVAL;
- goto done;
- }
- value = wrqu->rts.value;
- }
-
- err = ipw2100_set_rts_threshold(priv, value);
-
- IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
- wrqu->rts.fixed = 1; /* no auto select */
-
- /* If RTS is set to the default value, then it is disabled */
- wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
-
- IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0, value;
-
- if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
- return -EINPROGRESS;
-
- if (priv->ieee->iw_mode != IW_MODE_ADHOC)
- return 0;
-
- if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
- return -EINVAL;
-
- if (wrqu->txpower.fixed == 0)
- value = IPW_TX_POWER_DEFAULT;
- else {
- if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
- wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
- return -EINVAL;
-
- value = wrqu->txpower.value;
- }
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- err = ipw2100_set_tx_power(priv, value);
-
- IPW_DEBUG_WX("SET TX Power -> %d\n", value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
-
- if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
- wrqu->txpower.fixed = 0;
- wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
- } else {
- wrqu->txpower.fixed = 1;
- wrqu->txpower.value = priv->tx_power;
- }
-
- wrqu->txpower.flags = IW_TXPOW_DBM;
-
- IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (!wrqu->frag.fixed)
- return -EINVAL;
-
- if (wrqu->frag.disabled) {
- priv->frag_threshold |= FRAG_DISABLED;
- priv->ieee->fts = DEFAULT_FTS;
- } else {
- if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD)
- return -EINVAL;
-
- priv->ieee->fts = wrqu->frag.value & ~0x1;
- priv->frag_threshold = priv->ieee->fts;
- }
-
- IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
-
- return 0;
-}
-
-static int ipw2100_wx_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
- wrqu->frag.fixed = 0; /* no auto select */
- wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
-
- IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
- return -EINVAL;
-
- if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
- return 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->retry.flags & IW_RETRY_SHORT) {
- err = ipw2100_set_short_retry(priv, wrqu->retry.value);
- IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
- wrqu->retry.value);
- goto done;
- }
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- err = ipw2100_set_long_retry(priv, wrqu->retry.value);
- IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
- wrqu->retry.value);
- goto done;
- }
-
- err = ipw2100_set_short_retry(priv, wrqu->retry.value);
- if (!err)
- err = ipw2100_set_long_retry(priv, wrqu->retry.value);
-
- IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->retry.disabled = 0; /* can't be disabled */
-
- if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
- return -EINVAL;
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- wrqu->retry.value = priv->long_retry_limit;
- } else {
- wrqu->retry.flags =
- (priv->short_retry_limit !=
- priv->long_retry_limit) ?
- IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
-
- wrqu->retry.value = priv->short_retry_limit;
- }
-
- IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- IPW_DEBUG_WX("Initiating scan...\n");
-
- priv->user_requested_scan = 1;
- if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
- IPW_DEBUG_WX("Start scan failed.\n");
-
- /* TODO: Mark a scan as pending so when hardware initialized
- * a scan starts */
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
-}
-
-/*
- * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
- */
-static int ipw2100_wx_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- /*
- * No check of STATUS_INITIALIZED required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw2100_wx_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw2100_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->power.disabled) {
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
- IPW_DEBUG_WX("SET Power Management Mode -> off\n");
- goto done;
- }
-
- switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitly state all */
- break;
- default: /* Otherwise we don't support it */
- IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
- wrqu->power.flags);
- err = -EOPNOTSUPP;
- goto done;
- }
-
- /* If the user hasn't specified a power management mode yet, default
- * to BATTERY */
- priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
- err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
-
- IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-
-}
-
-static int ipw2100_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- wrqu->power.disabled = 1;
- else {
- wrqu->power.disabled = 0;
- wrqu->power.flags = 0;
- }
-
- IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
-
- return 0;
-}
-
-/*
- * WE-18 WPA support
- */
-
-/* SIOCSIWGENIE */
-static int ipw2100_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- u8 *buf;
-
- if (!ieee->wpa_enabled)
- return -EOPNOTSUPP;
-
- if (wrqu->data.length > MAX_WPA_IE_LEN ||
- (wrqu->data.length && extra == NULL))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = buf;
- ieee->wpa_ie_len = wrqu->data.length;
- } else {
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = NULL;
- ieee->wpa_ie_len = 0;
- }
-
- ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
-
- return 0;
-}
-
-/* SIOCGIWGENIE */
-static int ipw2100_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
-
- if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
- wrqu->data.length = 0;
- return 0;
- }
-
- if (wrqu->data.length < ieee->wpa_ie_len)
- return -E2BIG;
-
- wrqu->data.length = ieee->wpa_ie_len;
- memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
-
- return 0;
-}
-
-/* SIOCSIWAUTH */
-static int ipw2100_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
- unsigned long flags;
- int ret = 0;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * ipw2200 does not use these parameters
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
- break;
-
- flags = crypt->ops->get_flags(crypt->priv);
-
- if (param->value)
- flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
- else
- flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
-
- crypt->ops->set_flags(flags, crypt->priv);
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:{
- /* HACK:
- *
- * wpa_supplicant calls set_wpa_enabled when the driver
- * is loaded and unloaded, regardless of if WPA is being
- * used. No other calls are made which can be used to
- * determine if encryption will be used or not prior to
- * association being expected. If encryption is not being
- * used, drop_unencrypted is set to false, else true -- we
- * can use this to determine if the CAP_PRIVACY_ON bit should
- * be set.
- */
- struct libipw_security sec = {
- .flags = SEC_ENABLED,
- .enabled = param->value,
- };
- priv->ieee->drop_unencrypted = param->value;
- /* We only change SEC_LEVEL for open mode. Others
- * are set by ipw_wpa_set_encryption.
- */
- if (!param->value) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_0;
- } else {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- }
- if (priv->ieee->set_security)
- priv->ieee->set_security(priv->ieee->dev, &sec);
- break;
- }
-
- case IW_AUTH_80211_AUTH_ALG:
- ret = ipw2100_wpa_set_auth_algs(priv, param->value);
- break;
-
- case IW_AUTH_WPA_ENABLED:
- ret = ipw2100_wpa_enable(priv, param->value);
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = param->value;
- break;
-
- //case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = param->value;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return ret;
-}
-
-/* SIOCGIWAUTH */
-static int ipw2100_wx_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * wpa_supplicant will control these internally
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->get_flags) {
- IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
- "crypt not set!\n");
- break;
- }
-
- param->value = (crypt->ops->get_flags(crypt->priv) &
- IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value = ieee->drop_unencrypted;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- param->value = priv->ieee->sec.auth_mode;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = ieee->wpa_enabled;
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- param->value = ieee->ieee802_1x;
- break;
-
- case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- param->value = ieee->privacy_invoked;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/* SIOCSIWENCODEEXT */
-static int ipw2100_wx_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCGIWENCODEEXT */
-static int ipw2100_wx_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCSIWMLME */
-static int ipw2100_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- // silently ignore
- break;
-
- case IW_MLME_DISASSOC:
- ipw2100_disassociate_bssid(priv);
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/*
- *
- * IWPRIV handlers
- *
- */
-#ifdef CONFIG_IPW2100_MONITOR
-static int ipw2100_wx_set_promisc(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int *parms = (int *)extra;
- int enable = (parms[0] > 0);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (enable) {
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- err = ipw2100_set_channel(priv, parms[1], 0);
- goto done;
- }
- priv->channel = parms[1];
- err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
- } else {
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- err = ipw2100_switch_mode(priv, priv->last_mode);
- }
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- if (priv->status & STATUS_INITIALIZED)
- schedule_reset(priv);
- return 0;
-}
-
-#endif
-
-static int ipw2100_wx_set_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if ((mode < 0) || (mode > POWER_MODES))
- mode = IPW_POWER_AUTO;
-
- if (IPW_POWER_LEVEL(priv->power_mode) != mode)
- err = ipw2100_set_power_mode(priv, mode);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-#define MAX_POWER_STRING 80
-static int ipw2100_wx_get_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- int level = IPW_POWER_LEVEL(priv->power_mode);
- s32 timeout, period;
-
- if (!(priv->power_mode & IPW_POWER_ENABLED)) {
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Off)", level);
- } else {
- switch (level) {
- case IPW_POWER_MODE_CAM:
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (None)", level);
- break;
- case IPW_POWER_AUTO:
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Auto)", level);
- break;
- default:
- timeout = timeout_duration[level - 1] / 1000;
- period = period_duration[level - 1] / 1000;
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d "
- "(Timeout %dms, Period %dms)",
- level, timeout, period);
- }
- }
-
- wrqu->data.length = strlen(extra) + 1;
-
- return 0;
-}
-
-static int ipw2100_wx_set_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (mode == 1)
- priv->config |= CFG_LONG_PREAMBLE;
- else if (mode == 0)
- priv->config &= ~CFG_LONG_PREAMBLE;
- else {
- err = -EINVAL;
- goto done;
- }
-
- err = ipw2100_system_config(priv, 0);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (priv->config & CFG_LONG_PREAMBLE)
- snprintf(wrqu->name, IFNAMSIZ, "long (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
-
- return 0;
-}
-
-#ifdef CONFIG_IPW2100_MONITOR
-static int ipw2100_wx_set_crc_check(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (mode == 1)
- priv->config |= CFG_CRC_CHECK;
- else if (mode == 0)
- priv->config &= ~CFG_CRC_CHECK;
- else {
- err = -EINVAL;
- goto done;
- }
- err = 0;
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_crc_check(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (priv->config & CFG_CRC_CHECK)
- snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
-
- return 0;
-}
-#endif /* CONFIG_IPW2100_MONITOR */
-
-static iw_handler ipw2100_wx_handlers[] = {
- IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
- IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
- IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
- IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
- IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
- IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
- IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
- IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
- IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
- IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
- IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
- IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
- IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
- IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
- IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
- IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
- IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
- IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
- IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
- IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
- IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
- IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
- IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
- IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
- IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
- IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
- IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
-};
-
-#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
-#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
-#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
-#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
-#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
-#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
-#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
-#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
-
-static const struct iw_priv_args ipw2100_private_args[] = {
-
-#ifdef CONFIG_IPW2100_MONITOR
- {
- IPW2100_PRIV_SET_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
- {
- IPW2100_PRIV_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
-#endif /* CONFIG_IPW2100_MONITOR */
-
- {
- IPW2100_PRIV_SET_POWER,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
- {
- IPW2100_PRIV_GET_POWER,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
- "get_power"},
- {
- IPW2100_PRIV_SET_LONGPREAMBLE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
- {
- IPW2100_PRIV_GET_LONGPREAMBLE,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
-#ifdef CONFIG_IPW2100_MONITOR
- {
- IPW2100_PRIV_SET_CRC_CHECK,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
- {
- IPW2100_PRIV_GET_CRC_CHECK,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
-#endif /* CONFIG_IPW2100_MONITOR */
-};
-
-static iw_handler ipw2100_private_handler[] = {
-#ifdef CONFIG_IPW2100_MONITOR
- ipw2100_wx_set_promisc,
- ipw2100_wx_reset,
-#else /* CONFIG_IPW2100_MONITOR */
- NULL,
- NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
- ipw2100_wx_set_powermode,
- ipw2100_wx_get_powermode,
- ipw2100_wx_set_preamble,
- ipw2100_wx_get_preamble,
-#ifdef CONFIG_IPW2100_MONITOR
- ipw2100_wx_set_crc_check,
- ipw2100_wx_get_crc_check,
-#else /* CONFIG_IPW2100_MONITOR */
- NULL,
- NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
-};
-
-/*
- * Get wireless statistics.
- * Called by /proc/net/wireless
- * Also called by SIOCGIWSTATS
- */
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
-{
- enum {
- POOR = 30,
- FAIR = 60,
- GOOD = 80,
- VERY_GOOD = 90,
- EXCELLENT = 95,
- PERFECT = 100
- };
- int rssi_qual;
- int tx_qual;
- int beacon_qual;
- int quality;
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_statistics *wstats;
- u32 rssi, tx_retries, missed_beacons, tx_failures;
- u32 ord_len = sizeof(u32);
-
- if (!priv)
- return (struct iw_statistics *)NULL;
-
- wstats = &priv->wstats;
-
- /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
- * ipw2100_wx_wireless_stats seems to be called before fw is
- * initialized. STATUS_ASSOCIATED will only be set if the hw is up
- * and associated; if not associcated, the values are all meaningless
- * anyway, so set them all to NULL and INVALID */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->miss.beacon = 0;
- wstats->discard.retries = 0;
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
- return wstats;
- }
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
- &missed_beacons, &ord_len))
- goto fail_get_ordinal;
-
- /* If we don't have a connection the quality and level is 0 */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- } else {
- if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
- &rssi, &ord_len))
- goto fail_get_ordinal;
- wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
- if (rssi < 10)
- rssi_qual = rssi * POOR / 10;
- else if (rssi < 15)
- rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
- else if (rssi < 20)
- rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
- else if (rssi < 30)
- rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
- 10 + GOOD;
- else
- rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
- 10 + VERY_GOOD;
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
- &tx_retries, &ord_len))
- goto fail_get_ordinal;
-
- if (tx_retries > 75)
- tx_qual = (90 - tx_retries) * POOR / 15;
- else if (tx_retries > 70)
- tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
- else if (tx_retries > 65)
- tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
- else if (tx_retries > 50)
- tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
- 15 + GOOD;
- else
- tx_qual = (50 - tx_retries) *
- (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
-
- if (missed_beacons > 50)
- beacon_qual = (60 - missed_beacons) * POOR / 10;
- else if (missed_beacons > 40)
- beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
- 10 + POOR;
- else if (missed_beacons > 32)
- beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
- 18 + FAIR;
- else if (missed_beacons > 20)
- beacon_qual = (32 - missed_beacons) *
- (VERY_GOOD - GOOD) / 20 + GOOD;
- else
- beacon_qual = (20 - missed_beacons) *
- (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
-
- quality = min(tx_qual, rssi_qual);
- quality = min(beacon_qual, quality);
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (beacon_qual == quality)
- IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
- else if (tx_qual == quality)
- IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
- else if (quality != 100)
- IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
- else
- IPW_DEBUG_WX("Quality not clamped.\n");
-#endif
-
- wstats->qual.qual = quality;
- wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
- }
-
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
-
- /* FIXME: this is percent and not a # */
- wstats->miss.beacon = missed_beacons;
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
- &tx_failures, &ord_len))
- goto fail_get_ordinal;
- wstats->discard.retries = tx_failures;
-
- return wstats;
-
- fail_get_ordinal:
- IPW_DEBUG_WX("failed querying ordinals.\n");
-
- return (struct iw_statistics *)NULL;
-}
-
-static const struct iw_handler_def ipw2100_wx_handler_def = {
- .standard = ipw2100_wx_handlers,
- .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
- .num_private = ARRAY_SIZE(ipw2100_private_handler),
- .num_private_args = ARRAY_SIZE(ipw2100_private_args),
- .private = (iw_handler *) ipw2100_private_handler,
- .private_args = (struct iw_priv_args *)ipw2100_private_args,
- .get_wireless_stats = ipw2100_wx_wireless_stats,
-};
-
-static void ipw2100_wx_event_work(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, wx_event_work.work);
- union iwreq_data wrqu;
- unsigned int len = ETH_ALEN;
-
- if (priv->status & STATUS_STOPPING)
- return;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_WX("enter\n");
-
- mutex_unlock(&priv->action_mutex);
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /* Fetch BSSID from the hardware */
- if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
- priv->status & STATUS_RF_KILL_MASK ||
- ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
- &priv->bssid, &len)) {
- eth_zero_addr(wrqu.ap_addr.sa_data);
- } else {
- /* We now have the BSSID, so can finish setting to the full
- * associated state */
- memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
- priv->status &= ~STATUS_ASSOCIATING;
- priv->status |= STATUS_ASSOCIATED;
- netif_carrier_on(priv->net_dev);
- netif_wake_queue(priv->net_dev);
- }
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_WX("Configuring ESSID\n");
- mutex_lock(&priv->action_mutex);
- /* This is a disassociation event, so kick the firmware to
- * look for another AP */
- if (priv->config & CFG_STATIC_ESSID)
- ipw2100_set_essid(priv, priv->essid, priv->essid_len,
- 0);
- else
- ipw2100_set_essid(priv, NULL, 0, 0);
- mutex_unlock(&priv->action_mutex);
- }
-
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-#define IPW2100_FW_MAJOR_VERSION 1
-#define IPW2100_FW_MINOR_VERSION 3
-
-#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
-#define IPW2100_FW_MAJOR(x) (x & 0xff)
-
-#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
- IPW2100_FW_MAJOR_VERSION)
-
-#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
-"." __stringify(IPW2100_FW_MINOR_VERSION)
-
-#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
-
-/*
-
-BINARY FIRMWARE HEADER FORMAT
-
-offset length desc
-0 2 version
-2 2 mode == 0:BSS,1:IBSS,2:MONITOR
-4 4 fw_len
-8 4 uc_len
-C fw_len firmware data
-12 + fw_len uc_len microcode data
-
-*/
-
-struct ipw2100_fw_header {
- short version;
- short mode;
- unsigned int fw_size;
- unsigned int uc_size;
-} __packed;
-
-static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
-{
- struct ipw2100_fw_header *h =
- (struct ipw2100_fw_header *)fw->fw_entry->data;
-
- if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
- printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
- "(detected version id of %u). "
- "See Documentation/networking/device_drivers/wifi/intel/ipw2100.rst\n",
- h->version);
- return 1;
- }
-
- fw->version = h->version;
- fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
- fw->fw.size = h->fw_size;
- fw->uc.data = fw->fw.data + h->fw_size;
- fw->uc.size = h->uc_size;
-
- return 0;
-}
-
-static int ipw2100_get_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- char *fw_name;
- int rc;
-
- IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
- priv->net_dev->name);
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- fw_name = IPW2100_FW_NAME("-i");
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- fw_name = IPW2100_FW_NAME("-p");
- break;
-#endif
- case IW_MODE_INFRA:
- default:
- fw_name = IPW2100_FW_NAME("");
- break;
- }
-
- rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
-
- if (rc < 0) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: Firmware '%s' not available or load failed.\n",
- priv->net_dev->name, fw_name);
- return rc;
- }
- IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
- fw->fw_entry->size);
-
- ipw2100_mod_firmware_load(fw);
-
- return 0;
-}
-
-MODULE_FIRMWARE(IPW2100_FW_NAME("-i"));
-#ifdef CONFIG_IPW2100_MONITOR
-MODULE_FIRMWARE(IPW2100_FW_NAME("-p"));
-#endif
-MODULE_FIRMWARE(IPW2100_FW_NAME(""));
-
-static void ipw2100_release_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- fw->version = 0;
- release_firmware(fw->fw_entry);
- fw->fw_entry = NULL;
-}
-
-static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
- size_t max)
-{
- char ver[MAX_FW_VERSION_LEN];
- u32 len = MAX_FW_VERSION_LEN;
- u32 tmp;
- int i;
- /* firmware version is an ascii string (max len of 14) */
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
- return -EIO;
- tmp = max;
- if (len >= max)
- len = max - 1;
- for (i = 0; i < len; i++)
- buf[i] = ver[i];
- buf[i] = '\0';
- return tmp;
-}
-
-static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
- size_t max)
-{
- u32 ver;
- u32 len = sizeof(ver);
- /* microcode version is a 32 bit integer */
- if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
- return -EIO;
- return snprintf(buf, max, "%08X", ver);
-}
-
-/*
- * On exit, the firmware will have been freed from the fw list
- */
-static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
-{
- /* firmware is constructed of N contiguous entries, each entry is
- * structured as:
- *
- * offset sie desc
- * 0 4 address to write to
- * 4 2 length of data run
- * 6 length data
- */
- unsigned int addr;
- unsigned short len;
-
- const unsigned char *firmware_data = fw->fw.data;
- unsigned int firmware_data_left = fw->fw.size;
-
- while (firmware_data_left > 0) {
- addr = *(u32 *) (firmware_data);
- firmware_data += 4;
- firmware_data_left -= 4;
-
- len = *(u16 *) (firmware_data);
- firmware_data += 2;
- firmware_data_left -= 2;
-
- if (len > 32) {
- printk(KERN_ERR DRV_NAME ": "
- "Invalid firmware run-length of %d bytes\n",
- len);
- return -EINVAL;
- }
-
- write_nic_memory(priv->net_dev, addr, len, firmware_data);
- firmware_data += len;
- firmware_data_left -= len;
- }
-
- return 0;
-}
-
-struct symbol_alive_response {
- u8 cmd_id;
- u8 seq_num;
- u8 ucode_rev;
- u8 eeprom_valid;
- u16 valid_flags;
- u8 IEEE_addr[6];
- u16 flags;
- u16 pcb_rev;
- u16 clock_settle_time; // 1us LSB
- u16 powerup_settle_time; // 1us LSB
- u16 hop_settle_time; // 1us LSB
- u8 date[3]; // month, day, year
- u8 time[2]; // hours, minutes
- u8 ucode_valid;
-};
-
-static int ipw2100_ucode_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- struct net_device *dev = priv->net_dev;
- const unsigned char *microcode_data = fw->uc.data;
- unsigned int microcode_data_left = fw->uc.size;
- void __iomem *reg = priv->ioaddr;
-
- struct symbol_alive_response response;
- int i, j;
- u8 data;
-
- /* Symbol control */
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
- readl(reg);
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
- readl(reg);
-
- /* HW config */
- write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
- readl(reg);
- write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
- readl(reg);
-
- /* EN_CS_ACCESS bit to reset control store pointer */
- write_nic_byte(dev, 0x210000, 0x40);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x40);
- readl(reg);
-
- /* copy microcode from buffer into Symbol */
-
- while (microcode_data_left > 0) {
- write_nic_byte(dev, 0x210010, *microcode_data++);
- write_nic_byte(dev, 0x210010, *microcode_data++);
- microcode_data_left -= 2;
- }
-
- /* EN_CS_ACCESS bit to reset the control store pointer */
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
-
- /* Enable System (Reg 0)
- * first enable causes garbage in RX FIFO */
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x80);
- readl(reg);
-
- /* Reset External Baseband Reg */
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
- readl(reg);
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
- readl(reg);
-
- /* HW Config (Reg 5) */
- write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
- readl(reg);
- write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
- readl(reg);
-
- /* Enable System (Reg 0)
- * second enable should be OK */
- write_nic_byte(dev, 0x210000, 0x00); // clear enable system
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x80); // set enable system
-
- /* check Symbol is enabled - upped this from 5 as it wasn't always
- * catching the update */
- for (i = 0; i < 10; i++) {
- udelay(10);
-
- /* check Dino is enabled bit */
- read_nic_byte(dev, 0x210000, &data);
- if (data & 0x1)
- break;
- }
-
- if (i == 10) {
- printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
- dev->name);
- return -EIO;
- }
-
- /* Get Symbol alive response */
- for (i = 0; i < 30; i++) {
- /* Read alive response structure */
- for (j = 0;
- j < (sizeof(struct symbol_alive_response) >> 1); j++)
- read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
-
- if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
- break;
- udelay(10);
- }
-
- if (i == 30) {
- printk(KERN_ERR DRV_NAME
- ": %s: No response from Symbol - hw not alive\n",
- dev->name);
- printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
- return -EIO;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h
deleted file mode 100644
index b34085ade3aa1..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h
+++ /dev/null
@@ -1,1142 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#ifndef _IPW2100_H
-#define _IPW2100_H
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <asm/io.h>
-#include <linux/socket.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h> // new driver API
-
-#ifdef CONFIG_IPW2100_MONITOR
-#include <net/ieee80211_radiotap.h>
-#endif
-
-#include <linux/workqueue.h>
-#include <linux/mutex.h>
-
-#include "libipw.h"
-
-struct ipw2100_priv;
-struct ipw2100_tx_packet;
-struct ipw2100_rx_packet;
-
-#define IPW_DL_UNINIT 0x80000000
-#define IPW_DL_NONE 0x00000000
-#define IPW_DL_ALL 0x7FFFFFFF
-
-/*
- * To use the debug system;
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define IPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your
- * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ipw2100/debug_level
- *
- * you simply need to add your entry to the ipw2100_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/ipw2100 then you do not have
- * CONFIG_IPW2100_DEBUG defined in your kernel configuration
- *
- */
-
-#define IPW_DL_ERROR (1<<0)
-#define IPW_DL_WARNING (1<<1)
-#define IPW_DL_INFO (1<<2)
-#define IPW_DL_WX (1<<3)
-#define IPW_DL_HC (1<<5)
-#define IPW_DL_STATE (1<<6)
-
-#define IPW_DL_NOTIF (1<<10)
-#define IPW_DL_SCAN (1<<11)
-#define IPW_DL_ASSOC (1<<12)
-#define IPW_DL_DROP (1<<13)
-
-#define IPW_DL_IOCTL (1<<14)
-#define IPW_DL_RF_KILL (1<<17)
-
-#define IPW_DL_MANAGE (1<<15)
-#define IPW_DL_FW (1<<16)
-
-#define IPW_DL_FRAG (1<<21)
-#define IPW_DL_WEP (1<<22)
-#define IPW_DL_TX (1<<23)
-#define IPW_DL_RX (1<<24)
-#define IPW_DL_ISR (1<<25)
-#define IPW_DL_IO (1<<26)
-#define IPW_DL_TRACE (1<<28)
-
-#define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_INFO(f...) IPW_DEBUG(IPW_DL_INFO, ## f)
-#define IPW_DEBUG_WX(f...) IPW_DEBUG(IPW_DL_WX, ## f)
-#define IPW_DEBUG_SCAN(f...) IPW_DEBUG(IPW_DL_SCAN, ## f)
-#define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f)
-#define IPW_DEBUG_TRACE(f...) IPW_DEBUG(IPW_DL_TRACE, ## f)
-#define IPW_DEBUG_RX(f...) IPW_DEBUG(IPW_DL_RX, ## f)
-#define IPW_DEBUG_TX(f...) IPW_DEBUG(IPW_DL_TX, ## f)
-#define IPW_DEBUG_ISR(f...) IPW_DEBUG(IPW_DL_ISR, ## f)
-#define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f)
-#define IPW_DEBUG_WEP(f...) IPW_DEBUG(IPW_DL_WEP, ## f)
-#define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f)
-#define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f)
-#define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f)
-#define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f)
-#define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f)
-#define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f)
-#define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f)
-#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-
-enum {
- IPW_HW_STATE_DISABLED = 1,
- IPW_HW_STATE_ENABLED = 0
-};
-
-extern const char *port_type_str[];
-extern const char *band_str[];
-
-#define NUMBER_OF_BD_PER_COMMAND_PACKET 1
-#define NUMBER_OF_BD_PER_DATA_PACKET 2
-
-#define IPW_MAX_BDS 6
-#define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR 2
-#define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS 1
-
-#define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \
- (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET)
-
-struct bd_status {
- union {
- struct {
- u8 nlf:1, txType:2, intEnabled:1, reserved:4;
- } fields;
- u8 field;
- } info;
-} __packed;
-
-struct ipw2100_bd {
- u32 host_addr;
- u32 buf_length;
- struct bd_status status;
- /* number of fragments for frame (should be set only for
- * 1st TBD) */
- u8 num_fragments;
- u8 reserved[6];
-} __packed;
-
-#define IPW_BD_QUEUE_LENGTH(n) (1<<n)
-#define IPW_BD_ALIGNMENT(L) (L*sizeof(struct ipw2100_bd))
-
-#define IPW_BD_STATUS_TX_FRAME_802_3 0x00
-#define IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT 0x01
-#define IPW_BD_STATUS_TX_FRAME_COMMAND 0x02
-#define IPW_BD_STATUS_TX_FRAME_802_11 0x04
-#define IPW_BD_STATUS_TX_INTERRUPT_ENABLE 0x08
-
-struct ipw2100_bd_queue {
- /* driver (virtual) pointer to queue */
- struct ipw2100_bd *drv;
-
- /* firmware (physical) pointer to queue */
- dma_addr_t nic;
-
- /* Length of phy memory allocated for BDs */
- u32 size;
-
- /* Number of BDs in queue (and in array) */
- u32 entries;
-
- /* Number of available BDs (invalid for NIC BDs) */
- u32 available;
-
- /* Offset of oldest used BD in array (next one to
- * check for completion) */
- u32 oldest;
-
- /* Offset of next available (unused) BD */
- u32 next;
-};
-
-#define RX_QUEUE_LENGTH 256
-#define TX_QUEUE_LENGTH 256
-#define HW_QUEUE_LENGTH 256
-
-#define TX_PENDED_QUEUE_LENGTH (TX_QUEUE_LENGTH / NUMBER_OF_BD_PER_DATA_PACKET)
-
-#define STATUS_TYPE_MASK 0x0000000f
-#define COMMAND_STATUS_VAL 0
-#define STATUS_CHANGE_VAL 1
-#define P80211_DATA_VAL 2
-#define P8023_DATA_VAL 3
-#define HOST_NOTIFICATION_VAL 4
-
-#define IPW2100_RSSI_TO_DBM (-98)
-
-struct ipw2100_status {
- u32 frame_size;
- u16 status_fields;
- u8 flags;
-#define IPW_STATUS_FLAG_DECRYPTED (1<<0)
-#define IPW_STATUS_FLAG_WEP_ENCRYPTED (1<<1)
-#define IPW_STATUS_FLAG_CRC_ERROR (1<<2)
- u8 rssi;
-} __packed;
-
-struct ipw2100_status_queue {
- /* driver (virtual) pointer to queue */
- struct ipw2100_status *drv;
-
- /* firmware (physical) pointer to queue */
- dma_addr_t nic;
-
- /* Length of phy memory allocated for BDs */
- u32 size;
-};
-
-#define HOST_COMMAND_PARAMS_REG_LEN 100
-#define CMD_STATUS_PARAMS_REG_LEN 3
-
-#define IPW_WPA_CAPABILITIES 0x1
-#define IPW_WPA_LISTENINTERVAL 0x2
-#define IPW_WPA_AP_ADDRESS 0x4
-
-#define IPW_MAX_VAR_IE_LEN ((HOST_COMMAND_PARAMS_REG_LEN - 4) * sizeof(u32))
-
-struct ipw2100_wpa_assoc_frame {
- u16 fixed_ie_mask;
- struct {
- u16 capab_info;
- u16 listen_interval;
- u8 current_ap[ETH_ALEN];
- } fixed_ies;
- u32 var_ie_len;
- u8 var_ie[IPW_MAX_VAR_IE_LEN];
-};
-
-#define IPW_BSS 1
-#define IPW_MONITOR 2
-#define IPW_IBSS 3
-
-/**
- * @struct _tx_cmd - HWCommand
- * @brief H/W command structure.
- */
-struct ipw2100_cmd_header {
- u32 host_command_reg;
- u32 host_command_reg1;
- u32 sequence;
- u32 host_command_len_reg;
- u32 host_command_params_reg[HOST_COMMAND_PARAMS_REG_LEN];
- u32 cmd_status_reg;
- u32 cmd_status_params_reg[CMD_STATUS_PARAMS_REG_LEN];
- u32 rxq_base_ptr;
- u32 rxq_next_ptr;
- u32 rxq_host_ptr;
- u32 txq_base_ptr;
- u32 txq_next_ptr;
- u32 txq_host_ptr;
- u32 tx_status_reg;
- u32 reserved;
- u32 status_change_reg;
- u32 reserved1[3];
- u32 *ordinal1_ptr;
- u32 *ordinal2_ptr;
-} __packed;
-
-struct ipw2100_data_header {
- u32 host_command_reg;
- u32 host_command_reg1;
- u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver
- u8 needs_encryption; // BOOLEAN in win! TRUE if frma need to be enc in NIC
- u8 wep_index; // 0 no key, 1-4 key index, 0xff immediate key
- u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
- u8 key[16];
- u8 reserved[10]; // f/w reserved
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
- u16 fragment_size;
-} __packed;
-
-/* Host command data structure */
-struct host_command {
- u32 host_command; // COMMAND ID
- u32 host_command1; // COMMAND ID
- u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID)
- u32 host_command_length; // LENGTH
- u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS
-} __packed;
-
-typedef enum {
- POWER_ON_RESET,
- EXIT_POWER_DOWN_RESET,
- SW_RESET,
- EEPROM_RW,
- SW_RE_INIT
-} ipw2100_reset_event;
-
-enum {
- COMMAND = 0xCAFE,
- DATA,
- RX
-};
-
-struct ipw2100_tx_packet {
- int type;
- int index;
- union {
- struct { /* COMMAND */
- struct ipw2100_cmd_header *cmd;
- dma_addr_t cmd_phys;
- } c_struct;
- struct { /* DATA */
- struct ipw2100_data_header *data;
- dma_addr_t data_phys;
- struct libipw_txb *txb;
- } d_struct;
- } info;
- int jiffy_start;
-
- struct list_head list;
-};
-
-struct ipw2100_rx_packet {
- struct ipw2100_rx *rxp;
- dma_addr_t dma_addr;
- int jiffy_start;
- struct sk_buff *skb;
- struct list_head list;
-};
-
-#define FRAG_DISABLED (1<<31)
-#define RTS_DISABLED (1<<31)
-#define MAX_RTS_THRESHOLD 2304U
-#define MIN_RTS_THRESHOLD 1U
-#define DEFAULT_RTS_THRESHOLD 1000U
-
-#define DEFAULT_BEACON_INTERVAL 100U
-#define DEFAULT_SHORT_RETRY_LIMIT 7U
-#define DEFAULT_LONG_RETRY_LIMIT 4U
-
-struct ipw2100_ordinals {
- u32 table1_addr;
- u32 table2_addr;
- u32 table1_size;
- u32 table2_size;
-};
-
-/* Host Notification header */
-struct ipw2100_notification {
- u32 hnhdr_subtype; /* type of host notification */
- u32 hnhdr_size; /* size in bytes of data
- or number of entries, if table.
- Does NOT include header */
-} __packed;
-
-#define MAX_KEY_SIZE 16
-#define MAX_KEYS 8
-
-#define IPW2100_WEP_ENABLE (1<<1)
-#define IPW2100_WEP_DROP_CLEAR (1<<2)
-
-#define IPW_NONE_CIPHER (1<<0)
-#define IPW_WEP40_CIPHER (1<<1)
-#define IPW_TKIP_CIPHER (1<<2)
-#define IPW_CCMP_CIPHER (1<<4)
-#define IPW_WEP104_CIPHER (1<<5)
-#define IPW_CKIP_CIPHER (1<<6)
-
-#define IPW_AUTH_OPEN 0
-#define IPW_AUTH_SHARED 1
-#define IPW_AUTH_LEAP 2
-#define IPW_AUTH_LEAP_CISCO_ID 0x80
-
-struct statistic {
- int value;
- int hi;
- int lo;
-};
-
-#define INIT_STAT(x) do { \
- (x)->value = (x)->hi = 0; \
- (x)->lo = 0x7fffffff; \
-} while (0)
-#define SET_STAT(x,y) do { \
- (x)->value = y; \
- if ((x)->value > (x)->hi) (x)->hi = (x)->value; \
- if ((x)->value < (x)->lo) (x)->lo = (x)->value; \
-} while (0)
-#define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \
-while (0)
-#define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \
-while (0)
-
-#define IPW2100_ERROR_QUEUE 5
-
-/* Power management code: enable or disable? */
-enum {
-#ifdef CONFIG_PM
- IPW2100_PM_DISABLED = 0,
- PM_STATE_SIZE = 16,
-#else
- IPW2100_PM_DISABLED = 1,
- PM_STATE_SIZE = 0,
-#endif
-};
-
-#define STATUS_POWERED (1<<0)
-#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */
-#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */
-#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */
-#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */
-#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */
-#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */
-#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */
-#define STATUS_INT_ENABLED (1<<11)
-#define STATUS_RF_KILL_HW (1<<12)
-#define STATUS_RF_KILL_SW (1<<13)
-#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
-#define STATUS_EXIT_PENDING (1<<14)
-
-#define STATUS_SCAN_PENDING (1<<23)
-#define STATUS_SCANNING (1<<24)
-#define STATUS_SCAN_ABORTING (1<<25)
-#define STATUS_SCAN_COMPLETE (1<<26)
-#define STATUS_WX_EVENT_PENDING (1<<27)
-#define STATUS_RESET_PENDING (1<<29)
-#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
-
-/* Internal NIC states */
-#define IPW_STATE_INITIALIZED (1<<0)
-#define IPW_STATE_COUNTRY_FOUND (1<<1)
-#define IPW_STATE_ASSOCIATED (1<<2)
-#define IPW_STATE_ASSN_LOST (1<<3)
-#define IPW_STATE_ASSN_CHANGED (1<<4)
-#define IPW_STATE_SCAN_COMPLETE (1<<5)
-#define IPW_STATE_ENTERED_PSP (1<<6)
-#define IPW_STATE_LEFT_PSP (1<<7)
-#define IPW_STATE_RF_KILL (1<<8)
-#define IPW_STATE_DISABLED (1<<9)
-#define IPW_STATE_POWER_DOWN (1<<10)
-#define IPW_STATE_SCANNING (1<<11)
-
-#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
-#define CFG_CUSTOM_MAC (1<<3)
-#define CFG_LONG_PREAMBLE (1<<4)
-#define CFG_ASSOCIATE (1<<6)
-#define CFG_FIXED_RATE (1<<7)
-#define CFG_ADHOC_CREATE (1<<8)
-#define CFG_PASSIVE_SCAN (1<<10)
-#ifdef CONFIG_IPW2100_MONITOR
-#define CFG_CRC_CHECK (1<<11)
-#endif
-
-#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
-
-struct ipw2100_priv {
- void __iomem *ioaddr;
-
- int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
- int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
-
- struct libipw_device *ieee;
- unsigned long status;
- unsigned long config;
- unsigned long capability;
-
- /* Statistics */
- int resets;
- time64_t reset_backoff;
-
- /* Context */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
- u8 bssid[ETH_ALEN];
- u8 channel;
- int last_mode;
-
- time64_t connect_start;
- time64_t last_reset;
-
- u32 channel_mask;
- u32 fatal_error;
- u32 fatal_errors[IPW2100_ERROR_QUEUE];
- u32 fatal_index;
- int eeprom_version;
- int firmware_version;
- unsigned long hw_features;
- int hangs;
- u32 last_rtc;
- int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
- u8 *snapshot[0x30];
-
- u8 mandatory_bssid_mac[ETH_ALEN];
- u8 mac_addr[ETH_ALEN];
-
- int power_mode;
-
- int messages_sent;
-
- int short_retry_limit;
- int long_retry_limit;
-
- u32 rts_threshold;
- u32 frag_threshold;
-
- int in_isr;
-
- u32 tx_rates;
- int tx_power;
- u32 beacon_interval;
-
- char nick[IW_ESSID_MAX_SIZE + 1];
-
- struct ipw2100_status_queue status_queue;
-
- struct statistic txq_stat;
- struct statistic rxq_stat;
- struct ipw2100_bd_queue rx_queue;
- struct ipw2100_bd_queue tx_queue;
- struct ipw2100_rx_packet *rx_buffers;
-
- struct statistic fw_pend_stat;
- struct list_head fw_pend_list;
-
- struct statistic msg_free_stat;
- struct statistic msg_pend_stat;
- struct list_head msg_free_list;
- struct list_head msg_pend_list;
- struct ipw2100_tx_packet *msg_buffers;
-
- struct statistic tx_free_stat;
- struct statistic tx_pend_stat;
- struct list_head tx_free_list;
- struct list_head tx_pend_list;
- struct ipw2100_tx_packet *tx_buffers;
-
- struct ipw2100_ordinals ordinals;
-
- struct pci_dev *pci_dev;
-
- struct proc_dir_entry *dir_dev;
-
- struct net_device *net_dev;
- struct iw_statistics wstats;
-
- struct iw_public_data wireless_data;
-
- struct tasklet_struct irq_tasklet;
-
- struct delayed_work reset_work;
- struct delayed_work security_work;
- struct delayed_work wx_event_work;
- struct delayed_work hang_check;
- struct delayed_work rf_kill;
- struct delayed_work scan_event;
-
- int user_requested_scan;
-
- /* Track time in suspend, using CLOCK_BOOTTIME */
- time64_t suspend_at;
- time64_t suspend_time;
-
- u32 interrupts;
- int tx_interrupts;
- int rx_interrupts;
- int inta_other;
-
- spinlock_t low_lock;
- struct mutex action_mutex;
- struct mutex adapter_mutex;
-
- wait_queue_head_t wait_command_queue;
-};
-
-/*********************************************************
- * Host Command -> From Driver to FW
- *********************************************************/
-
-/**
- * Host command identifiers
- */
-#define HOST_COMPLETE 2
-#define SYSTEM_CONFIG 6
-#define SSID 8
-#define MANDATORY_BSSID 9
-#define AUTHENTICATION_TYPE 10
-#define ADAPTER_ADDRESS 11
-#define PORT_TYPE 12
-#define INTERNATIONAL_MODE 13
-#define CHANNEL 14
-#define RTS_THRESHOLD 15
-#define FRAG_THRESHOLD 16
-#define POWER_MODE 17
-#define TX_RATES 18
-#define BASIC_TX_RATES 19
-#define WEP_KEY_INFO 20
-#define WEP_KEY_INDEX 25
-#define WEP_FLAGS 26
-#define ADD_MULTICAST 27
-#define CLEAR_ALL_MULTICAST 28
-#define BEACON_INTERVAL 29
-#define ATIM_WINDOW 30
-#define CLEAR_STATISTICS 31
-#define SEND 33
-#define TX_POWER_INDEX 36
-#define BROADCAST_SCAN 43
-#define CARD_DISABLE 44
-#define PREFERRED_BSSID 45
-#define SET_SCAN_OPTIONS 46
-#define SCAN_DWELL_TIME 47
-#define SWEEP_TABLE 48
-#define AP_OR_STATION_TABLE 49
-#define GROUP_ORDINALS 50
-#define SHORT_RETRY_LIMIT 51
-#define LONG_RETRY_LIMIT 52
-
-#define HOST_PRE_POWER_DOWN 58
-#define CARD_DISABLE_PHY_OFF 61
-#define MSDU_TX_RATES 62
-
-/* Rogue AP Detection */
-#define SET_STATION_STAT_BITS 64
-#define CLEAR_STATIONS_STAT_BITS 65
-#define LEAP_ROGUE_MODE 66 //TODO tbw replaced by CFG_LEAP_ROGUE_AP
-#define SET_SECURITY_INFORMATION 67
-#define DISASSOCIATION_BSSID 68
-#define SET_WPA_IE 69
-
-/* system configuration bit mask: */
-#define IPW_CFG_MONITOR 0x00004
-#define IPW_CFG_PREAMBLE_AUTO 0x00010
-#define IPW_CFG_IBSS_AUTO_START 0x00020
-#define IPW_CFG_LOOPBACK 0x00100
-#define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800
-#define IPW_CFG_BT_SIDEBAND_SIGNAL 0x02000
-#define IPW_CFG_802_1x_ENABLE 0x04000
-#define IPW_CFG_BSS_MASK 0x08000
-#define IPW_CFG_IBSS_MASK 0x10000
-
-#define IPW_SCAN_NOASSOCIATE (1<<0)
-#define IPW_SCAN_MIXED_CELL (1<<1)
-/* RESERVED (1<<2) */
-#define IPW_SCAN_PASSIVE (1<<3)
-
-#define IPW_NIC_FATAL_ERROR 0x2A7F0
-#define IPW_ERROR_ADDR(x) (x & 0x3FFFF)
-#define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24)
-#define IPW2100_ERR_C3_CORRUPTION (0x10 << 24)
-#define IPW2100_ERR_MSG_TIMEOUT (0x11 << 24)
-#define IPW2100_ERR_FW_LOAD (0x12 << 24)
-
-#define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND 0x200
-#define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80
-
-#define IPW_MEM_HOST_SHARED_RX_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40)
-#define IPW_MEM_HOST_SHARED_RX_STATUS_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44)
-#define IPW_MEM_HOST_SHARED_RX_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48)
-#define IPW_MEM_HOST_SHARED_RX_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0)
-
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00)
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04)
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80)
-
-#define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \
- (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20)
-
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \
- (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND)
-
-#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180)
-#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184)
-
-#define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB)
-#define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1
-#define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2
-#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3
-#define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4
-#define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5
-#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16
-#define IPW2100_INTA_FW_INIT_DONE (0x01000000) // Bit 24
-#define IPW2100_INTA_FW_CALIBRATION_CALC (0x02000000) // Bit 25
-#define IPW2100_INTA_FATAL_ERROR (0x40000000) // Bit 30
-#define IPW2100_INTA_PARITY_ERROR (0x80000000) // Bit 31 (MSB)
-
-#define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET (0x00000001)
-#define IPW_AUX_HOST_RESET_REG_FORCE_NMI (0x00000002)
-#define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI (0x00000004)
-#define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI (0x00000008)
-#define IPW_AUX_HOST_RESET_REG_SW_RESET (0x00000080)
-#define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED (0x00000100)
-#define IPW_AUX_HOST_RESET_REG_STOP_MASTER (0x00000200)
-
-#define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY (0x00000001) // Bit 0 (LSB)
-#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY (0x00000002) // Bit 1
-#define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE (0x00000004) // Bit 2
-#define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG (0x000007c0) // Bits 6-10
-#define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE (0x00000200) // Bit 9
-#define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE (0x00000400) // Bit 10
-#define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE (0x20000000) // Bit 29
-#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK (0x40000000) // Bit 30
-#define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK (0x80000000) // Bit 31 (MSB)
-
-#define IPW_BIT_GPIO_GPIO1_MASK 0x0000000C
-#define IPW_BIT_GPIO_GPIO3_MASK 0x000000C0
-#define IPW_BIT_GPIO_GPIO1_ENABLE 0x00000008
-#define IPW_BIT_GPIO_RF_KILL 0x00010000
-
-#define IPW_BIT_GPIO_LED_OFF 0x00002000 // Bit 13 = 1
-
-#define IPW_REG_DOMAIN_0_OFFSET 0x0000
-#define IPW_REG_DOMAIN_1_OFFSET IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND
-
-#define IPW_REG_INTA IPW_REG_DOMAIN_0_OFFSET + 0x0008
-#define IPW_REG_INTA_MASK IPW_REG_DOMAIN_0_OFFSET + 0x000C
-#define IPW_REG_INDIRECT_ACCESS_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0010
-#define IPW_REG_INDIRECT_ACCESS_DATA IPW_REG_DOMAIN_0_OFFSET + 0x0014
-#define IPW_REG_AUTOINCREMENT_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0018
-#define IPW_REG_AUTOINCREMENT_DATA IPW_REG_DOMAIN_0_OFFSET + 0x001C
-#define IPW_REG_RESET_REG IPW_REG_DOMAIN_0_OFFSET + 0x0020
-#define IPW_REG_GP_CNTRL IPW_REG_DOMAIN_0_OFFSET + 0x0024
-#define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030
-#define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188
-#define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C
-#define IPW_REG_FW_COMPATIBILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190
-
-#define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC
-
-#define IPW_INTERRUPT_MASK 0xC1010013
-
-#define IPW2100_CONTROL_REG 0x220000
-#define IPW2100_CONTROL_PHY_OFF 0x8
-
-#define IPW2100_COMMAND 0x00300004
-#define IPW2100_COMMAND_PHY_ON 0x0
-#define IPW2100_COMMAND_PHY_OFF 0x1
-
-/* in DEBUG_AREA, values of memory always 0xd55555d5 */
-#define IPW_REG_DOA_DEBUG_AREA_START IPW_REG_DOMAIN_0_OFFSET + 0x0090
-#define IPW_REG_DOA_DEBUG_AREA_END IPW_REG_DOMAIN_0_OFFSET + 0x00FF
-#define IPW_DATA_DOA_DEBUG_VALUE 0xd55555d5
-
-#define IPW_INTERNAL_REGISTER_HALT_AND_RESET 0x003000e0
-
-#define IPW_WAIT_CLOCK_STABILIZATION_DELAY 50 // micro seconds
-#define IPW_WAIT_RESET_ARC_COMPLETE_DELAY 10 // micro seconds
-#define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds
-
-// BD ring queue read/write difference
-#define IPW_BD_QUEUE_W_R_MIN_SPARE 2
-
-#define IPW_CACHE_LINE_LENGTH_DEFAULT 0x80
-
-#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli
-#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli
-
-#define IPW_HEADER_802_11_SIZE sizeof(struct libipw_hdr_3addr)
-#define IPW_MAX_80211_PAYLOAD_SIZE 2304U
-#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312
-#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536
-#define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH 60
-#define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \
- (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \
- sizeof(struct ethhdr))
-
-#define IPW_802_11_FCS_LENGTH 4
-#define IPW_RX_NIC_BUFFER_LENGTH \
- (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \
- IPW_802_11_FCS_LENGTH)
-
-#define IPW_802_11_PAYLOAD_OFFSET \
- (sizeof(struct libipw_hdr_3addr) + \
- sizeof(struct libipw_snap_hdr))
-
-struct ipw2100_rx {
- union {
- unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
- struct libipw_hdr_4addr header;
- u32 status;
- struct ipw2100_notification notification;
- struct ipw2100_cmd_header command;
- } rx_data;
-} __packed;
-
-/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */
-#define TX_RATE_1_MBIT 0x0001
-#define TX_RATE_2_MBIT 0x0002
-#define TX_RATE_5_5_MBIT 0x0004
-#define TX_RATE_11_MBIT 0x0008
-#define TX_RATE_MASK 0x000F
-#define DEFAULT_TX_RATES 0x000F
-
-#define IPW_POWER_MODE_CAM 0x00 //(always on)
-#define IPW_POWER_INDEX_1 0x01
-#define IPW_POWER_INDEX_2 0x02
-#define IPW_POWER_INDEX_3 0x03
-#define IPW_POWER_INDEX_4 0x04
-#define IPW_POWER_INDEX_5 0x05
-#define IPW_POWER_AUTO 0x06
-#define IPW_POWER_MASK 0x0F
-#define IPW_POWER_ENABLED 0x10
-#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
-
-#define IPW_TX_POWER_AUTO 0
-#define IPW_TX_POWER_ENHANCED 1
-
-#define IPW_TX_POWER_DEFAULT 32
-#define IPW_TX_POWER_MIN 0
-#define IPW_TX_POWER_MAX 16
-#define IPW_TX_POWER_MIN_DBM (-12)
-#define IPW_TX_POWER_MAX_DBM 16
-
-#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan
-#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan
-
-#define REG_MIN_CHANNEL 0
-#define REG_MAX_CHANNEL 14
-
-#define REG_CHANNEL_MASK 0x00003FFF
-#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff
-
-#define DIVERSITY_EITHER 0 // Use both antennas
-#define DIVERSITY_ANTENNA_A 1 // Use antenna A
-#define DIVERSITY_ANTENNA_B 2 // Use antenna B
-
-#define HOST_COMMAND_WAIT 0
-#define HOST_COMMAND_NO_WAIT 1
-
-#define LOCK_NONE 0
-#define LOCK_DRIVER 1
-#define LOCK_FW 2
-
-#define TYPE_SWEEP_ORD 0x000D
-#define TYPE_IBSS_STTN_ORD 0x000E
-#define TYPE_BSS_AP_ORD 0x000F
-#define TYPE_RAW_BEACON_ENTRY 0x0010
-#define TYPE_CALIBRATION_DATA 0x0011
-#define TYPE_ROGUE_AP_DATA 0x0012
-#define TYPE_ASSOCIATION_REQUEST 0x0013
-#define TYPE_REASSOCIATION_REQUEST 0x0014
-
-#define HW_FEATURE_RFKILL 0x0001
-#define RF_KILLSWITCH_OFF 1
-#define RF_KILLSWITCH_ON 0
-
-#define IPW_COMMAND_POOL_SIZE 40
-
-#define IPW_START_ORD_TAB_1 1
-#define IPW_START_ORD_TAB_2 1000
-
-#define IPW_ORD_TAB_1_ENTRY_SIZE sizeof(u32)
-
-#define IS_ORDINAL_TABLE_ONE(mgr,id) \
- ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size))
-#define IS_ORDINAL_TABLE_TWO(mgr,id) \
- ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2)))
-
-#define BSS_ID_LENGTH 6
-
-// Fixed size data: Ordinal Table 1
-typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
-// Transmit statistics
- IPW_ORD_STAT_TX_HOST_REQUESTS = 1, // # of requested Host Tx's (MSDU)
- IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU)
- IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU)
-
- IPW_ORD_STAT_TX_DIR_DATA1 = 4, // # of successful Directed Tx's (MSDU) @ 1MB
- IPW_ORD_STAT_TX_DIR_DATA2, // # of successful Directed Tx's (MSDU) @ 2MB
- IPW_ORD_STAT_TX_DIR_DATA5_5, // # of successful Directed Tx's (MSDU) @ 5_5MB
- IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB
- IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB
-
- IPW_ORD_STAT_TX_NODIR_DATA1 = 13, // # of successful Non_Directed Tx's (MSDU) @ 1MB
- IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB
- IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB
- IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB
-
- IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's
- IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS
- IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS
- IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK
- IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's
- IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's
- IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's
- IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's
- IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted
- IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted
- IPW_ORD_STAT_TX_BEACON, // # of tx beacon
- IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM
- IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX
- IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx
- IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX
-
- IPW_ORD_STAT_TX_TOTAL_BYTES = 41, // Total successful Tx data bytes
- IPW_ORD_STAT_TX_RETRIES, // # of Tx retries
- IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS
- IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS
- IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS
- IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS
-
- IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures
- IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time
- IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP, // # of times max tries in a hop failed
- IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup
- IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted
- IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed
- IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames
- IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent
- IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks
-
- // Receive statistics
- IPW_ORD_STAT_RX_HOST = 61, // # of packets passed to host
- IPW_ORD_STAT_RX_DIR_DATA, // # of directed packets
- IPW_ORD_STAT_RX_DIR_DATA1, // # of directed packets at 1MB
- IPW_ORD_STAT_RX_DIR_DATA2, // # of directed packets at 2MB
- IPW_ORD_STAT_RX_DIR_DATA5_5, // # of directed packets at 5.5MB
- IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB
- IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB
-
- IPW_ORD_STAT_RX_NODIR_DATA = 71, // # of nondirected packets
- IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB
- IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB
- IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB
- IPW_ORD_STAT_RX_NODIR_DATA11, // # of nondirected packets at 11MB
-
- IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's
- IPW_ORD_STAT_RX_POLL, //NS // # of poll rx
- IPW_ORD_STAT_RX_RTS, // # of Rx RTS
- IPW_ORD_STAT_RX_CTS, // # of Rx CTS
- IPW_ORD_STAT_RX_ACK, // # of Rx ACK
- IPW_ORD_STAT_RX_CFEND, // # of Rx CF End
- IPW_ORD_STAT_RX_CFEND_ACK, // # of Rx CF End + CF Ack
- IPW_ORD_STAT_RX_ASSN, // # of Association Rx's
- IPW_ORD_STAT_RX_ASSN_RESP, // # of Association response Rx's
- IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's
- IPW_ORD_STAT_RX_REASSN_RESP, // # of Reassociation response Rx's
- IPW_ORD_STAT_RX_PROBE, // # of probe Rx's
- IPW_ORD_STAT_RX_PROBE_RESP, // # of probe response Rx's
- IPW_ORD_STAT_RX_BEACON, // # of Rx beacon
- IPW_ORD_STAT_RX_ATIM, // # of Rx ATIM
- IPW_ORD_STAT_RX_DISASSN, // # of disassociation Rx
- IPW_ORD_STAT_RX_AUTH, // # of authentication Rx
- IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx
-
- IPW_ORD_STAT_RX_TOTAL_BYTES = 101, // Total rx data bytes received
- IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error
- IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB
- IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB
- IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB
- IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB
-
- IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
- IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB
- IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB
- IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB
- IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
-
- IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db
- IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db
- IPW_ORD_PERS_DB_ADDR, // # address of fw permanent db
- IPW_ORD_STAT_RX_INVALID_PROTOCOL, // # of rx frames with invalid protocol
- IPW_ORD_SYS_BOOT_TIME, // # Boot time
- IPW_ORD_STAT_RX_NO_BUFFER, // # of rx frames rejected due to no buffer
- IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late
- IPW_ORD_STAT_RX_ABORT_AT_HOP, //NS // # of rx frames aborted due to hop
- IPW_ORD_STAT_RX_MISSING_FRAG, // # of rx frames dropped due to missing fragment
- IPW_ORD_STAT_RX_ORPHAN_FRAG, // # of rx frames dropped due to non-sequential fragment
- IPW_ORD_STAT_RX_ORPHAN_FRAME, // # of rx frames dropped due to unmatched 1st frame
- IPW_ORD_STAT_RX_FRAG_AGEOUT, // # of rx frames dropped due to uncompleted frame
- IPW_ORD_STAT_RX_BAD_SSID, //NS // Bad SSID (unused)
- IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption
-
-// PSP Statistics
- IPW_ORD_STAT_PSP_SUSPENSION = 137, // # of times adapter suspended
- IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout
- IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts
- IPW_ORD_STAT_PSP_NONDIR_TIMEOUT, // # of timeouts waiting for last broadcast/muticast pkt
- IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received
- IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received
- IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID
-
-// Association and roaming
- IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association
- IPW_ORD_STAT_PERCENT_MISSED_BCNS, // current calculation of % missed beacons
- IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries
- IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated
- // AP table entry. set to 0 if not associated
- IPW_ORD_AVAILABLE_AP_CNT, // # of AP's described in the AP table
- IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs
- IPW_ORD_STAT_AP_ASSNS, // # of associations
- IPW_ORD_STAT_ASSN_FAIL, // # of association failures
- IPW_ORD_STAT_ASSN_RESP_FAIL, // # of failuresdue to response fail
- IPW_ORD_STAT_FULL_SCANS, // # of full scans
-
- IPW_ORD_CARD_DISABLED, // # Card Disabled
- IPW_ORD_STAT_ROAM_INHIBIT, // # of times roaming was inhibited due to ongoing activity
- IPW_FILLER_40,
- IPW_ORD_RSSI_AT_ASSN = 160, // RSSI of associated AP at time of association
- IPW_ORD_STAT_ASSN_CAUSE1, // # of reassociations due to no tx from AP in last N
- // hops or no prob_ responses in last 3 minutes
- IPW_ORD_STAT_ASSN_CAUSE2, // # of reassociations due to poor tx/rx quality
- IPW_ORD_STAT_ASSN_CAUSE3, // # of reassociations due to tx/rx quality with excessive
- // load at the AP
- IPW_ORD_STAT_ASSN_CAUSE4, // # of reassociations due to AP RSSI level fell below
- // eligible group
- IPW_ORD_STAT_ASSN_CAUSE5, // # of reassociations due to load leveling
- IPW_ORD_STAT_ASSN_CAUSE6, //NS // # of reassociations due to dropped by Ap
- IPW_FILLER_41,
- IPW_FILLER_42,
- IPW_FILLER_43,
- IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed
- IPW_ORD_STAT_AUTH_RESP_FAIL, // # of times authentication response failed
- IPW_ORD_STATION_TABLE_CNT, // # of entries in association table
-
-// Other statistics
- IPW_ORD_RSSI_AVG_CURR = 173, // Current avg RSSI
- IPW_ORD_STEST_RESULTS_CURR, //NS // Current self test results word
- IPW_ORD_STEST_RESULTS_CUM, //NS // Cummulative self test results word
- IPW_ORD_SELF_TEST_STATUS, //NS //
- IPW_ORD_POWER_MGMT_MODE, // Power mode - 0=CAM, 1=PSP
- IPW_ORD_POWER_MGMT_INDEX, //NS //
- IPW_ORD_COUNTRY_CODE, // IEEE country code as recv'd from beacon
- IPW_ORD_COUNTRY_CHANNELS, // channels supported by country
-// IPW_ORD_COUNTRY_CHANNELS:
-// For 11b the lower 2-byte are used for channels from 1-14
-// and the higher 2-byte are not used.
- IPW_ORD_RESET_CNT, // # of adapter resets (warm)
- IPW_ORD_BEACON_INTERVAL, // Beacon interval
-
- IPW_ORD_PRINCETON_VERSION = 184, //NS // Princeton Version
- IPW_ORD_ANTENNA_DIVERSITY, // TRUE if antenna diversity is disabled
- IPW_ORD_CCA_RSSI, //NS // CCA RSSI value (factory programmed)
- IPW_ORD_STAT_EEPROM_UPDATE, //NS // # of times config EEPROM updated
- IPW_ORD_DTIM_PERIOD, // # of beacon intervals between DTIMs
- IPW_ORD_OUR_FREQ, // current radio freq lower digits - channel ID
-
- IPW_ORD_RTC_TIME = 190, // current RTC time
- IPW_ORD_PORT_TYPE, // operating mode
- IPW_ORD_CURRENT_TX_RATE, // current tx rate
- IPW_ORD_SUPPORTED_RATES, // Bitmap of supported tx rates
- IPW_ORD_ATIM_WINDOW, // current ATIM Window
- IPW_ORD_BASIC_RATES, // bitmap of basic tx rates
- IPW_ORD_NIC_HIGHEST_RATE, // bitmap of basic tx rates
- IPW_ORD_AP_HIGHEST_RATE, // bitmap of basic tx rates
- IPW_ORD_CAPABILITIES, // Management frame capability field
- IPW_ORD_AUTH_TYPE, // Type of authentication
- IPW_ORD_RADIO_TYPE, // Adapter card platform type
- IPW_ORD_RTS_THRESHOLD = 201, // Min length of packet after which RTS handshaking is used
- IPW_ORD_INT_MODE, // International mode
- IPW_ORD_FRAGMENTATION_THRESHOLD, // protocol frag threshold
- IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, // EEPROM offset in SRAM
- IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE, // EEPROM size in SRAM
- IPW_ORD_EEPROM_SKU_CAPABILITY, // EEPROM SKU Capability 206 =
- IPW_ORD_EEPROM_IBSS_11B_CHANNELS, // EEPROM IBSS 11b channel set
-
- IPW_ORD_MAC_VERSION = 209, // MAC Version
- IPW_ORD_MAC_REVISION, // MAC Revision
- IPW_ORD_RADIO_VERSION, // Radio Version
- IPW_ORD_NIC_MANF_DATE_TIME, // MANF Date/Time STAMP
- IPW_ORD_UCODE_VERSION, // Ucode Version
- IPW_ORD_HW_RF_SWITCH_STATE = 214, // HW RF Kill Switch State
-} ORDINALTABLE1;
-
-// ordinal table 2
-// Variable length data:
-#define IPW_FIRST_VARIABLE_LENGTH_ORDINAL 1001
-
-typedef enum _ORDINAL_TABLE_2 { // NS - means Not Supported by FW
- IPW_ORD_STAT_BASE = 1000, // contains number of variable ORDs
- IPW_ORD_STAT_ADAPTER_MAC = 1001, // 6 bytes: our adapter MAC address
- IPW_ORD_STAT_PREFERRED_BSSID = 1002, // 6 bytes: BSSID of the preferred AP
- IPW_ORD_STAT_MANDATORY_BSSID = 1003, // 6 bytes: BSSID of the mandatory AP
- IPW_FILL_1, //NS //
- IPW_ORD_STAT_COUNTRY_TEXT = 1005, // 36 bytes: Country name text, First two bytes are Country code
- IPW_ORD_STAT_ASSN_SSID = 1006, // 32 bytes: ESSID String
- IPW_ORD_STATION_TABLE = 1007, // ? bytes: Station/AP table (via Direct SSID Scans)
- IPW_ORD_STAT_SWEEP_TABLE = 1008, // ? bytes: Sweep/Host Table table (via Broadcast Scans)
- IPW_ORD_STAT_ROAM_LOG = 1009, // ? bytes: Roaming log
- IPW_ORD_STAT_RATE_LOG = 1010, //NS // 0 bytes: Rate log
- IPW_ORD_STAT_FIFO = 1011, //NS // 0 bytes: Fifo buffer data structures
- IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011")
- IPW_ORD_STAT_FW_DATE = 1013, // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002")
- IPW_ORD_STAT_ASSN_AP_BSSID = 1014, // 6 bytes: MAC address of associated AP
- IPW_ORD_STAT_DEBUG = 1015, //NS // ? bytes:
- IPW_ORD_STAT_NIC_BPA_NUM = 1016, // 11 bytes: NIC BPA number in ASCII
- IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date
- IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018,
-} ORDINALTABLE2; // NS - means Not Supported by FW
-
-#define IPW_LAST_VARIABLE_LENGTH_ORDINAL 1018
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY // enable iwspy support
-#endif
-
-#define IPW_HOST_FW_SHARED_AREA0 0x0002f200
-#define IPW_HOST_FW_SHARED_AREA0_END 0x0002f510 // 0x310 bytes
-
-#define IPW_HOST_FW_SHARED_AREA1 0x0002f610
-#define IPW_HOST_FW_SHARED_AREA1_END 0x0002f630 // 0x20 bytes
-
-#define IPW_HOST_FW_SHARED_AREA2 0x0002fa00
-#define IPW_HOST_FW_SHARED_AREA2_END 0x0002fa20 // 0x20 bytes
-
-#define IPW_HOST_FW_SHARED_AREA3 0x0002fc00
-#define IPW_HOST_FW_SHARED_AREA3_END 0x0002fc10 // 0x10 bytes
-
-#define IPW_HOST_FW_INTERRUPT_AREA 0x0002ff80
-#define IPW_HOST_FW_INTERRUPT_AREA_END 0x00030000 // 0x80 bytes
-
-struct ipw2100_fw_chunk {
- unsigned char *buf;
- long len;
- long pos;
- struct list_head list;
-};
-
-struct ipw2100_fw_chunk_set {
- const void *data;
- unsigned long size;
-};
-
-struct ipw2100_fw {
- int version;
- struct ipw2100_fw_chunk_set fw;
- struct ipw2100_fw_chunk_set uc;
- const struct firmware *fw_entry;
-};
-
-#define MAX_FW_VERSION_LEN 14
-
-#endif /* _IPW2100_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
deleted file mode 100644
index 820100cac4915..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ /dev/null
@@ -1,11965 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
- 802.11 status code portion of this file from ethereal-0.10.6:
- Copyright 2000, Axis Communications AB
- Ethereal - Network traffic analyzer
- By Gerald Combs <[email protected]>
- Copyright 1998 Gerald Combs
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <net/cfg80211-wext.h>
-#include "ipw2200.h"
-#include "ipw.h"
-
-
-#ifndef KBUILD_EXTMOD
-#define VK "k"
-#else
-#define VK
-#endif
-
-#ifdef CONFIG_IPW2200_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#ifdef CONFIG_IPW2200_MONITOR
-#define VM "m"
-#else
-#define VM
-#endif
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-#define VP "p"
-#else
-#define VP
-#endif
-
-#ifdef CONFIG_IPW2200_RADIOTAP
-#define VR "r"
-#else
-#define VR
-#endif
-
-#ifdef CONFIG_IPW2200_QOS
-#define VQ "q"
-#else
-#define VQ
-#endif
-
-#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ
-#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-#define DRV_VERSION IPW2200_VERSION
-
-#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1)
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("ipw2200-ibss.fw");
-#ifdef CONFIG_IPW2200_MONITOR
-MODULE_FIRMWARE("ipw2200-sniffer.fw");
-#endif
-MODULE_FIRMWARE("ipw2200-bss.fw");
-
-static int cmdlog = 0;
-static int debug = 0;
-static int default_channel = 0;
-static int network_mode = 0;
-
-static u32 ipw_debug_level;
-static int associate;
-static int auto_create = 1;
-static int led_support = 1;
-static int disable = 0;
-static int bt_coexist = 0;
-static int hwcrypto = 0;
-static int roaming = 1;
-static const char ipw_modes[] = {
- 'a', 'b', 'g', '?'
-};
-static int antenna = CFG_SYS_ANTENNA_BOTH;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */
-#endif
-
-static struct ieee80211_rate ipw2200_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 }
-};
-
-#define ipw2200_a_rates (ipw2200_rates + 4)
-#define ipw2200_num_a_rates 8
-#define ipw2200_bg_rates (ipw2200_rates + 0)
-#define ipw2200_num_bg_rates 12
-
-/* Ugly macro to convert literal channel numbers into their mhz equivalents
- * There are certianly some conditions that will break this (like feeding it '30')
- * but they shouldn't arise since nothing talks on channel 30. */
-#define ieee80211chan2mhz(x) \
- (((x) <= 14) ? \
- (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
- ((x) + 1000) * 5)
-
-#ifdef CONFIG_IPW2200_QOS
-static int qos_enable = 0;
-static int qos_burst_enable = 0;
-static int qos_no_ack_mask = 0;
-static int burst_duration_CCK = 0;
-static int burst_duration_OFDM = 0;
-
-static struct libipw_qos_parameters def_qos_parameters_OFDM = {
- {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM,
- QOS_TX3_CW_MIN_OFDM},
- {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM,
- QOS_TX3_CW_MAX_OFDM},
- {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
- {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
- {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM,
- QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM}
-};
-
-static struct libipw_qos_parameters def_qos_parameters_CCK = {
- {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK,
- QOS_TX3_CW_MIN_CCK},
- {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK,
- QOS_TX3_CW_MAX_CCK},
- {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
- {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
- {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK,
- QOS_TX3_TXOP_LIMIT_CCK}
-};
-
-static struct libipw_qos_parameters def_parameters_OFDM = {
- {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM,
- DEF_TX3_CW_MIN_OFDM},
- {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM,
- DEF_TX3_CW_MAX_OFDM},
- {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
- {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
- {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM,
- DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM}
-};
-
-static struct libipw_qos_parameters def_parameters_CCK = {
- {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK,
- DEF_TX3_CW_MIN_CCK},
- {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK,
- DEF_TX3_CW_MAX_CCK},
- {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
- {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
- {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK,
- DEF_TX3_TXOP_LIMIT_CCK}
-};
-
-static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
-
-static int from_priority_to_tx_queue[] = {
- IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1,
- IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4
-};
-
-static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv);
-
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
- *qos_param);
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
- *qos_param);
-#endif /* CONFIG_IPW2200_QOS */
-
-static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev);
-static void ipw_remove_current_network(struct ipw_priv *priv);
-static void ipw_rx(struct ipw_priv *priv);
-static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
- struct clx2_tx_queue *txq, int qindex);
-static int ipw_queue_reset(struct ipw_priv *priv);
-
-static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, const void *buf,
- int len, int sync);
-
-static void ipw_tx_queue_free(struct ipw_priv *);
-
-static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);
-static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
-static void ipw_rx_queue_replenish(void *);
-static int ipw_up(struct ipw_priv *);
-static void ipw_bg_up(struct work_struct *work);
-static void ipw_down(struct ipw_priv *);
-static void ipw_bg_down(struct work_struct *work);
-static int ipw_config(struct ipw_priv *);
-static int init_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *prates);
-static void ipw_set_hwcrypto_keys(struct ipw_priv *);
-static void ipw_send_wep_keys(struct ipw_priv *, int);
-
-static int snprint_line(char *buf, size_t count,
- const u8 * data, u32 len, u32 ofs)
-{
- int out, i, j, l;
- char c;
-
- out = scnprintf(buf, count, "%08X", ofs);
-
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++)
- out += scnprintf(buf + out, count - out, "%02X ",
- data[(i * 8 + j)]);
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- out += scnprintf(buf + out, count - out, " ");
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++) {
- c = data[(i * 8 + j)];
- if (!isascii(c) || !isprint(c))
- c = '.';
-
- out += scnprintf(buf + out, count - out, "%c", c);
- }
-
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- return out;
-}
-
-static void printk_buf(int level, const u8 * data, u32 len)
-{
- char line[81];
- u32 ofs = 0;
- if (!(ipw_debug_level & level))
- return;
-
- while (len) {
- snprint_line(line, sizeof(line), &data[ofs],
- min(len, 16U), ofs);
- printk(KERN_DEBUG "%s\n", line);
- ofs += 16;
- len -= min(len, 16U);
- }
-}
-
-static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len)
-{
- size_t out = size;
- u32 ofs = 0;
- int total = 0;
-
- while (size && len) {
- out = snprint_line(output, size, &data[ofs],
- min_t(size_t, len, 16U), ofs);
-
- ofs += 16;
- output += out;
- size -= out;
- len -= min_t(size_t, len, 16U);
- total += out;
- }
- return total;
-}
-
-/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
-static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
-#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
-
-/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
-static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg);
-#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b)
-
-/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value);
-static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg8(a, b, c);
-}
-
-/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value);
-static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg16(a, b, c);
-}
-
-/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value);
-static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg32(a, b, c);
-}
-
-/* 8-bit direct write (low 4K) */
-static inline void _ipw_write8(struct ipw_priv *ipw, unsigned long ofs,
- u8 val)
-{
- writeb(val, ipw->hw_base + ofs);
-}
-
-/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write8(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write8(ipw, ofs, val); \
-} while (0)
-
-/* 16-bit direct write (low 4K) */
-static inline void _ipw_write16(struct ipw_priv *ipw, unsigned long ofs,
- u16 val)
-{
- writew(val, ipw->hw_base + ofs);
-}
-
-/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write16(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write16(ipw, ofs, val); \
-} while (0)
-
-/* 32-bit direct write (low 4K) */
-static inline void _ipw_write32(struct ipw_priv *ipw, unsigned long ofs,
- u32 val)
-{
- writel(val, ipw->hw_base + ofs);
-}
-
-/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write32(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write32(ipw, ofs, val); \
-} while (0)
-
-/* 8-bit direct read (low 4K) */
-static inline u8 _ipw_read8(struct ipw_priv *ipw, unsigned long ofs)
-{
- return readb(ipw->hw_base + ofs);
-}
-
-/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read8(ipw, ofs) ({ \
- IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", __FILE__, __LINE__, \
- (u32)(ofs)); \
- _ipw_read8(ipw, ofs); \
-})
-
-/* 32-bit direct read (low 4K) */
-static inline u32 _ipw_read32(struct ipw_priv *ipw, unsigned long ofs)
-{
- return readl(ipw->hw_base + ofs);
-}
-
-/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read32(ipw, ofs) ({ \
- IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", __FILE__, __LINE__, \
- (u32)(ofs)); \
- _ipw_read32(ipw, ofs); \
-})
-
-static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
-/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
-#define ipw_read_indirect(a, b, c, d) ({ \
- IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %u bytes\n", __FILE__, \
- __LINE__, (u32)(b), (u32)(d)); \
- _ipw_read_indirect(a, b, c, d); \
-})
-
-/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
-static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
- int num);
-#define ipw_write_indirect(a, b, c, d) do { \
- IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %u bytes\n", __FILE__, \
- __LINE__, (u32)(b), (u32)(d)); \
- _ipw_write_indirect(a, b, c, d); \
-} while (0)
-
-/* 32-bit indirect write (above 4K) */
-static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
-{
- IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
- _ipw_write32(priv, IPW_INDIRECT_DATA, value);
-}
-
-/* 8-bit indirect write (above 4K) */
-static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
-{
- u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = reg - aligned_addr;
-
- IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value);
-}
-
-/* 16-bit indirect write (above 4K) */
-static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
-{
- u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = (reg - aligned_addr) & (~0x1ul);
-
- IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value);
-}
-
-/* 8-bit indirect read (above 4K) */
-static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
-{
- u32 word;
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
- IPW_DEBUG_IO(" reg = 0x%8X :\n", reg);
- word = _ipw_read32(priv, IPW_INDIRECT_DATA);
- return (word >> ((reg & 0x3) * 8)) & 0xff;
-}
-
-/* 32-bit indirect read (above 4K) */
-static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
-{
- u32 value;
-
- IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg);
-
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
- value = _ipw_read32(priv, IPW_INDIRECT_DATA);
- IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x\n", reg, value);
- return value;
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) read, */
-/* for area above 1st 4K of SRAM/reg space */
-static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
- int num)
-{
- u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = addr - aligned_addr;
- u32 i;
-
- IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
-
- if (num <= 0) {
- return;
- }
-
- /* Read the first dword (or portion) byte by byte */
- if (unlikely(dif_len)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- /* Start reading at aligned_addr + dif_len */
- for (i = dif_len; ((i < 4) && (num > 0)); i++, num--)
- *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i);
- aligned_addr += 4;
- }
-
- /* Read all of the middle dwords as dwords, with auto-increment */
- _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
- for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
- *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA);
-
- /* Read the last dword (or portion) byte by byte */
- if (unlikely(num)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- for (i = 0; num > 0; i++, num--)
- *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i);
- }
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) write, */
-/* for area above 1st 4K of SRAM/reg space */
-static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
- int num)
-{
- u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = addr - aligned_addr;
- u32 i;
-
- IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
-
- if (num <= 0) {
- return;
- }
-
- /* Write the first dword (or portion) byte by byte */
- if (unlikely(dif_len)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- /* Start writing at aligned_addr + dif_len */
- for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++)
- _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
- aligned_addr += 4;
- }
-
- /* Write all of the middle dwords as dwords, with auto-increment */
- _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
- for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
- _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf);
-
- /* Write the last dword (or portion) byte by byte */
- if (unlikely(num)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- for (i = 0; num > 0; i++, num--, buf++)
- _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
- }
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) write, */
-/* for 1st 4K of SRAM/regs space */
-static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
- int num)
-{
- memcpy_toio((priv->hw_base + addr), buf, num);
-}
-
-/* Set bit(s) in low 4K of SRAM/regs */
-static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask)
-{
- ipw_write32(priv, reg, ipw_read32(priv, reg) | mask);
-}
-
-/* Clear bit(s) in low 4K of SRAM/regs */
-static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
-{
- ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
-}
-
-static inline void __ipw_enable_interrupts(struct ipw_priv *priv)
-{
- if (priv->status & STATUS_INT_ENABLED)
- return;
- priv->status |= STATUS_INT_ENABLED;
- ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
-}
-
-static inline void __ipw_disable_interrupts(struct ipw_priv *priv)
-{
- if (!(priv->status & STATUS_INT_ENABLED))
- return;
- priv->status &= ~STATUS_INT_ENABLED;
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
-}
-
-static inline void ipw_enable_interrupts(struct ipw_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- __ipw_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void ipw_disable_interrupts(struct ipw_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- __ipw_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static char *ipw_error_desc(u32 val)
-{
- switch (val) {
- case IPW_FW_ERROR_OK:
- return "ERROR_OK";
- case IPW_FW_ERROR_FAIL:
- return "ERROR_FAIL";
- case IPW_FW_ERROR_MEMORY_UNDERFLOW:
- return "MEMORY_UNDERFLOW";
- case IPW_FW_ERROR_MEMORY_OVERFLOW:
- return "MEMORY_OVERFLOW";
- case IPW_FW_ERROR_BAD_PARAM:
- return "BAD_PARAM";
- case IPW_FW_ERROR_BAD_CHECKSUM:
- return "BAD_CHECKSUM";
- case IPW_FW_ERROR_NMI_INTERRUPT:
- return "NMI_INTERRUPT";
- case IPW_FW_ERROR_BAD_DATABASE:
- return "BAD_DATABASE";
- case IPW_FW_ERROR_ALLOC_FAIL:
- return "ALLOC_FAIL";
- case IPW_FW_ERROR_DMA_UNDERRUN:
- return "DMA_UNDERRUN";
- case IPW_FW_ERROR_DMA_STATUS:
- return "DMA_STATUS";
- case IPW_FW_ERROR_DINO_ERROR:
- return "DINO_ERROR";
- case IPW_FW_ERROR_EEPROM_ERROR:
- return "EEPROM_ERROR";
- case IPW_FW_ERROR_SYSASSERT:
- return "SYSASSERT";
- case IPW_FW_ERROR_FATAL_ERROR:
- return "FATAL_ERROR";
- default:
- return "UNKNOWN_ERROR";
- }
-}
-
-static void ipw_dump_error_log(struct ipw_priv *priv,
- struct ipw_fw_error *error)
-{
- u32 i;
-
- if (!error) {
- IPW_ERROR("Error allocating and capturing error log. "
- "Nothing to dump.\n");
- return;
- }
-
- IPW_ERROR("Start IPW Error Log Dump:\n");
- IPW_ERROR("Status: 0x%08X, Config: %08X\n",
- error->status, error->config);
-
- for (i = 0; i < error->elem_len; i++)
- IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
- ipw_error_desc(error->elem[i].desc),
- error->elem[i].time,
- error->elem[i].blink1,
- error->elem[i].blink2,
- error->elem[i].link1,
- error->elem[i].link2, error->elem[i].data);
- for (i = 0; i < error->log_len; i++)
- IPW_ERROR("%i\t0x%08x\t%i\n",
- error->log[i].time,
- error->log[i].data, error->log[i].event);
-}
-
-static inline int ipw_is_init(struct ipw_priv *priv)
-{
- return (priv->status & STATUS_INIT) ? 1 : 0;
-}
-
-static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
-{
- u32 addr, field_info, field_len, field_count, total_len;
-
- IPW_DEBUG_ORD("ordinal = %i\n", ord);
-
- if (!priv || !val || !len) {
- IPW_DEBUG_ORD("Invalid argument\n");
- return -EINVAL;
- }
-
- /* verify device ordinal tables have been initialized */
- if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) {
- IPW_DEBUG_ORD("Access ordinals before initialization\n");
- return -EINVAL;
- }
-
- switch (IPW_ORD_TABLE_ID_MASK & ord) {
- case IPW_ORD_TABLE_0_MASK:
- /*
- * TABLE 0: Direct access to a table of 32 bit values
- *
- * This is a very simple table with the data directly
- * read from the table
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table0_len) {
- IPW_DEBUG_ORD("ordinal value (%i) longer then "
- "max (%i)\n", ord, priv->table0_len);
- return -EINVAL;
- }
-
- /* verify we have enough room to store the value */
- if (*len < sizeof(u32)) {
- IPW_DEBUG_ORD("ordinal buffer length too small, "
- "need %zd\n", sizeof(u32));
- return -EINVAL;
- }
-
- IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n",
- ord, priv->table0_addr + (ord << 2));
-
- *len = sizeof(u32);
- ord <<= 2;
- *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord);
- break;
-
- case IPW_ORD_TABLE_1_MASK:
- /*
- * TABLE 1: Indirect access to a table of 32 bit values
- *
- * This is a fairly large table of u32 values each
- * representing starting addr for the data (which is
- * also a u32)
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table1_len) {
- IPW_DEBUG_ORD("ordinal value too long\n");
- return -EINVAL;
- }
-
- /* verify we have enough room to store the value */
- if (*len < sizeof(u32)) {
- IPW_DEBUG_ORD("ordinal buffer length too small, "
- "need %zd\n", sizeof(u32));
- return -EINVAL;
- }
-
- *((u32 *) val) =
- ipw_read_reg32(priv, (priv->table1_addr + (ord << 2)));
- *len = sizeof(u32);
- break;
-
- case IPW_ORD_TABLE_2_MASK:
- /*
- * TABLE 2: Indirect access to a table of variable sized values
- *
- * This table consist of six values, each containing
- * - dword containing the starting offset of the data
- * - dword containing the lengh in the first 16bits
- * and the count in the second 16bits
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table2_len) {
- IPW_DEBUG_ORD("ordinal value too long\n");
- return -EINVAL;
- }
-
- /* get the address of statistic */
- addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3));
-
- /* get the second DW of statistics ;
- * two 16-bit words - first is length, second is count */
- field_info =
- ipw_read_reg32(priv,
- priv->table2_addr + (ord << 3) +
- sizeof(u32));
-
- /* get each entry length */
- field_len = *((u16 *) & field_info);
-
- /* get number of entries */
- field_count = *(((u16 *) & field_info) + 1);
-
- /* abort if not enough memory */
- total_len = field_len * field_count;
- if (total_len > *len) {
- *len = total_len;
- return -EINVAL;
- }
-
- *len = total_len;
- if (!total_len)
- return 0;
-
- IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, "
- "field_info = 0x%08x\n",
- addr, total_len, field_info);
- ipw_read_indirect(priv, addr, val, total_len);
- break;
-
- default:
- IPW_DEBUG_ORD("Invalid ordinal!\n");
- return -EINVAL;
-
- }
-
- return 0;
-}
-
-static void ipw_init_ordinals(struct ipw_priv *priv)
-{
- priv->table0_addr = IPW_ORDINALS_TABLE_LOWER;
- priv->table0_len = ipw_read32(priv, priv->table0_addr);
-
- IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n",
- priv->table0_addr, priv->table0_len);
-
- priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1);
- priv->table1_len = ipw_read_reg32(priv, priv->table1_addr);
-
- IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n",
- priv->table1_addr, priv->table1_len);
-
- priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2);
- priv->table2_len = ipw_read_reg32(priv, priv->table2_addr);
- priv->table2_len &= 0x0000ffff; /* use first two bytes */
-
- IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n",
- priv->table2_addr, priv->table2_len);
-
-}
-
-static u32 ipw_register_toggle(u32 reg)
-{
- reg &= ~IPW_START_STANDBY;
- if (reg & IPW_GATE_ODMA)
- reg &= ~IPW_GATE_ODMA;
- if (reg & IPW_GATE_IDMA)
- reg &= ~IPW_GATE_IDMA;
- if (reg & IPW_GATE_ADMA)
- reg &= ~IPW_GATE_ADMA;
- return reg;
-}
-
-/*
- * LED behavior:
- * - On radio ON, turn on any LEDs that require to be on during start
- * - On initialization, start unassociated blink
- * - On association, disable unassociated blink
- * - On disassociation, start unassociated blink
- * - On radio OFF, turn off any LEDs started during radio on
- *
- */
-#define LD_TIME_LINK_ON msecs_to_jiffies(300)
-#define LD_TIME_LINK_OFF msecs_to_jiffies(2700)
-#define LD_TIME_ACT_ON msecs_to_jiffies(250)
-
-static void ipw_led_link_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* If configured to not use LEDs, or nic_type is 1,
- * then we don't toggle a LINK led */
- if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (!(priv->status & STATUS_RF_KILL_MASK) &&
- !(priv->status & STATUS_LED_LINK_ON)) {
- IPW_DEBUG_LED("Link LED On\n");
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led |= priv->led_association_on;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- priv->status |= STATUS_LED_LINK_ON;
-
- /* If we aren't associated, schedule turning the LED off */
- if (!(priv->status & STATUS_ASSOCIATED))
- schedule_delayed_work(&priv->led_link_off,
- LD_TIME_LINK_ON);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_link_on(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_link_on.work);
- mutex_lock(&priv->mutex);
- ipw_led_link_on(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_led_link_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* If configured not to use LEDs, or nic type is 1,
- * then we don't goggle the LINK led. */
- if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->status & STATUS_LED_LINK_ON) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_association_off;
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Link LED Off\n");
-
- priv->status &= ~STATUS_LED_LINK_ON;
-
- /* If we aren't associated and the radio is on, schedule
- * turning the LED on (blink while unassociated) */
- if (!(priv->status & STATUS_RF_KILL_MASK) &&
- !(priv->status & STATUS_ASSOCIATED))
- schedule_delayed_work(&priv->led_link_on,
- LD_TIME_LINK_OFF);
-
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_link_off(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_link_off.work);
- mutex_lock(&priv->mutex);
- ipw_led_link_off(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void __ipw_led_activity_on(struct ipw_priv *priv)
-{
- u32 led;
-
- if (priv->config & CFG_NO_LED)
- return;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return;
-
- if (!(priv->status & STATUS_LED_ACT_ON)) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led |= priv->led_activity_on;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Activity LED On\n");
-
- priv->status |= STATUS_LED_ACT_ON;
-
- cancel_delayed_work(&priv->led_act_off);
- schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
- } else {
- /* Reschedule LED off for full time period */
- cancel_delayed_work(&priv->led_act_off);
- schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
- }
-}
-
-#if 0
-void ipw_led_activity_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- __ipw_led_activity_on(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-#endif /* 0 */
-
-static void ipw_led_activity_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- if (priv->config & CFG_NO_LED)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->status & STATUS_LED_ACT_ON) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_activity_off;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Activity LED Off\n");
-
- priv->status &= ~STATUS_LED_ACT_ON;
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_activity_off(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_act_off.work);
- mutex_lock(&priv->mutex);
- ipw_led_activity_off(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_led_band_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* Only nic type 1 supports mode LEDs */
- if (priv->config & CFG_NO_LED ||
- priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- if (priv->assoc_network->mode == IEEE_A) {
- led |= priv->led_ofdm_on;
- led &= priv->led_association_off;
- IPW_DEBUG_LED("Mode LED On: 802.11a\n");
- } else if (priv->assoc_network->mode == IEEE_G) {
- led |= priv->led_ofdm_on;
- led |= priv->led_association_on;
- IPW_DEBUG_LED("Mode LED On: 802.11g\n");
- } else {
- led &= priv->led_ofdm_off;
- led |= priv->led_association_on;
- IPW_DEBUG_LED("Mode LED On: 802.11b\n");
- }
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_led_band_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* Only nic type 1 supports mode LEDs */
- if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_ofdm_off;
- led &= priv->led_association_off;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_led_radio_on(struct ipw_priv *priv)
-{
- ipw_led_link_on(priv);
-}
-
-static void ipw_led_radio_off(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
-}
-
-static void ipw_led_link_up(struct ipw_priv *priv)
-{
- /* Set the Link Led on for all nic types */
- ipw_led_link_on(priv);
-}
-
-static void ipw_led_link_down(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
-
- if (priv->status & STATUS_RF_KILL_MASK)
- ipw_led_radio_off(priv);
-}
-
-static void ipw_led_init(struct ipw_priv *priv)
-{
- priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE];
-
- /* Set the default PINs for the link and activity leds */
- priv->led_activity_on = IPW_ACTIVITY_LED;
- priv->led_activity_off = ~(IPW_ACTIVITY_LED);
-
- priv->led_association_on = IPW_ASSOCIATED_LED;
- priv->led_association_off = ~(IPW_ASSOCIATED_LED);
-
- /* Set the default PINs for the OFDM leds */
- priv->led_ofdm_on = IPW_OFDM_LED;
- priv->led_ofdm_off = ~(IPW_OFDM_LED);
-
- switch (priv->nic_type) {
- case EEPROM_NIC_TYPE_1:
- /* In this NIC type, the LEDs are reversed.... */
- priv->led_activity_on = IPW_ASSOCIATED_LED;
- priv->led_activity_off = ~(IPW_ASSOCIATED_LED);
- priv->led_association_on = IPW_ACTIVITY_LED;
- priv->led_association_off = ~(IPW_ACTIVITY_LED);
-
- if (!(priv->config & CFG_NO_LED))
- ipw_led_band_on(priv);
-
- /* And we don't blink link LEDs for this nic, so
- * just return here */
- return;
-
- case EEPROM_NIC_TYPE_3:
- case EEPROM_NIC_TYPE_2:
- case EEPROM_NIC_TYPE_4:
- case EEPROM_NIC_TYPE_0:
- break;
-
- default:
- IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n",
- priv->nic_type);
- priv->nic_type = EEPROM_NIC_TYPE_0;
- break;
- }
-
- if (!(priv->config & CFG_NO_LED)) {
- if (priv->status & STATUS_ASSOCIATED)
- ipw_led_link_on(priv);
- else
- ipw_led_link_off(priv);
- }
-}
-
-static void ipw_led_shutdown(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
- ipw_led_band_off(priv);
- cancel_delayed_work(&priv->led_link_on);
- cancel_delayed_work(&priv->led_link_off);
- cancel_delayed_work(&priv->led_act_off);
-}
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
- * used for controlling the debug level.
- *
- * See the level definitions in ipw for details.
- */
-static ssize_t debug_level_show(struct device_driver *d, char *buf)
-{
- return sprintf(buf, "0x%08X\n", ipw_debug_level);
-}
-
-static ssize_t debug_level_store(struct device_driver *d, const char *buf,
- size_t count)
-{
- unsigned long val;
-
- int result = kstrtoul(buf, 0, &val);
-
- if (result == -EINVAL)
- printk(KERN_INFO DRV_NAME
- ": %s is not in hex or decimal form.\n", buf);
- else if (result == -ERANGE)
- printk(KERN_INFO DRV_NAME
- ": %s has overflowed.\n", buf);
- else
- ipw_debug_level = val;
-
- return count;
-}
-static DRIVER_ATTR_RW(debug_level);
-
-static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
-{
- /* length = 1st dword in log */
- return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG));
-}
-
-static void ipw_capture_event_log(struct ipw_priv *priv,
- u32 log_len, struct ipw_event *log)
-{
- u32 base;
-
- if (log_len) {
- base = ipw_read32(priv, IPW_EVENT_LOG);
- ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32),
- (u8 *) log, sizeof(*log) * log_len);
- }
-}
-
-static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
-{
- struct ipw_fw_error *error;
- u32 log_len = ipw_get_event_log_len(priv);
- u32 base = ipw_read32(priv, IPW_ERROR_LOG);
- u32 elem_len = ipw_read_reg32(priv, base);
-
- error = kmalloc(size_add(struct_size(error, elem, elem_len),
- array_size(sizeof(*error->log), log_len)),
- GFP_ATOMIC);
- if (!error) {
- IPW_ERROR("Memory allocation for firmware error log "
- "failed.\n");
- return NULL;
- }
- error->jiffies = jiffies;
- error->status = priv->status;
- error->config = priv->config;
- error->elem_len = elem_len;
- error->log_len = log_len;
- error->log = (struct ipw_event *)(error->elem + elem_len);
-
- ipw_capture_event_log(priv, log_len, error->log);
-
- if (elem_len)
- ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem,
- sizeof(*error->elem) * elem_len);
-
- return error;
-}
-
-static ssize_t event_log_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 log_len = ipw_get_event_log_len(priv);
- u32 log_size;
- struct ipw_event *log;
- u32 len = 0, i;
-
- /* not using min() because of its strict type checking */
- log_size = PAGE_SIZE / sizeof(*log) > log_len ?
- sizeof(*log) * log_len : PAGE_SIZE;
- log = kzalloc(log_size, GFP_KERNEL);
- if (!log) {
- IPW_ERROR("Unable to allocate memory for log\n");
- return 0;
- }
- log_len = log_size / sizeof(*log);
- ipw_capture_event_log(priv, log_len, log);
-
- len += scnprintf(buf + len, PAGE_SIZE - len, "%08X", log_len);
- for (i = 0; i < log_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X",
- log[i].time, log[i].event, log[i].data);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- kfree(log);
- return len;
-}
-
-static DEVICE_ATTR_RO(event_log);
-
-static ssize_t error_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 len = 0, i;
- if (!priv->error)
- return 0;
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "%08lX%08X%08X%08X",
- priv->error->jiffies,
- priv->error->status,
- priv->error->config, priv->error->elem_len);
- for (i = 0; i < priv->error->elem_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X%08X%08X%08X%08X",
- priv->error->elem[i].time,
- priv->error->elem[i].desc,
- priv->error->elem[i].blink1,
- priv->error->elem[i].blink2,
- priv->error->elem[i].link1,
- priv->error->elem[i].link2,
- priv->error->elem[i].data);
-
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X", priv->error->log_len);
- for (i = 0; i < priv->error->log_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X",
- priv->error->log[i].time,
- priv->error->log[i].event,
- priv->error->log[i].data);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- return len;
-}
-
-static ssize_t error_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- kfree(priv->error);
- priv->error = NULL;
- return count;
-}
-
-static DEVICE_ATTR_RW(error);
-
-static ssize_t cmd_log_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 len = 0, i;
- if (!priv->cmdlog)
- return 0;
- for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
- (i != priv->cmdlog_pos) && (len < PAGE_SIZE);
- i = (i + 1) % priv->cmdlog_len) {
- len +=
- scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies,
- priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd,
- priv->cmdlog[i].cmd.len);
- len +=
- snprintk_buf(buf + len, PAGE_SIZE - len,
- (u8 *) priv->cmdlog[i].cmd.param,
- priv->cmdlog[i].cmd.len);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- }
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- return len;
-}
-
-static DEVICE_ATTR_RO(cmd_log);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static void ipw_prom_free(struct ipw_priv *priv);
-static int ipw_prom_alloc(struct ipw_priv *priv);
-static ssize_t rtap_iface_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int rc = 0;
-
- if (count < 1)
- return -EINVAL;
-
- switch (buf[0]) {
- case '0':
- if (!rtap_iface)
- return count;
-
- if (netif_running(priv->prom_net_dev)) {
- IPW_WARNING("Interface is up. Cannot unregister.\n");
- return count;
- }
-
- ipw_prom_free(priv);
- rtap_iface = 0;
- break;
-
- case '1':
- if (rtap_iface)
- return count;
-
- rc = ipw_prom_alloc(priv);
- if (!rc)
- rtap_iface = 1;
- break;
-
- default:
- return -EINVAL;
- }
-
- if (rc) {
- IPW_ERROR("Failed to register promiscuous network "
- "device (error %d).\n", rc);
- }
-
- return count;
-}
-
-static ssize_t rtap_iface_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- if (rtap_iface)
- return sprintf(buf, "%s", priv->prom_net_dev->name);
- else {
- buf[0] = '-';
- buf[1] = '1';
- buf[2] = '\0';
- return 3;
- }
-}
-
-static DEVICE_ATTR_ADMIN_RW(rtap_iface);
-
-static ssize_t rtap_filter_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (!priv->prom_priv) {
- IPW_ERROR("Attempting to set filter without "
- "rtap_iface enabled.\n");
- return -EPERM;
- }
-
- priv->prom_priv->filter = simple_strtol(buf, NULL, 0);
-
- IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n",
- BIT_ARG16(priv->prom_priv->filter));
-
- return count;
-}
-
-static ssize_t rtap_filter_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "0x%04X",
- priv->prom_priv ? priv->prom_priv->filter : 0);
-}
-
-static DEVICE_ATTR_ADMIN_RW(rtap_filter);
-#endif
-
-static ssize_t scan_age_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", priv->ieee->scan_age);
-}
-
-static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
-
- IPW_DEBUG_INFO("enter\n");
-
- unsigned long val;
- int result = kstrtoul(buf, 0, &val);
-
- if (result == -EINVAL || result == -ERANGE) {
- IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
- } else {
- priv->ieee->scan_age = val;
- IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return count;
-}
-
-static DEVICE_ATTR_RW(scan_age);
-
-static ssize_t led_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1);
-}
-
-static ssize_t led_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- IPW_DEBUG_INFO("enter\n");
-
- if (count == 0)
- return 0;
-
- if (*buf == 0) {
- IPW_DEBUG_LED("Disabling LED control.\n");
- priv->config |= CFG_NO_LED;
- ipw_led_shutdown(priv);
- } else {
- IPW_DEBUG_LED("Enabling LED control.\n");
- priv->config &= ~CFG_NO_LED;
- ipw_led_init(priv);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return count;
-}
-
-static DEVICE_ATTR_RW(led);
-
-static ssize_t status_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->status);
-}
-
-static DEVICE_ATTR_RO(status);
-
-static ssize_t cfg_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->config);
-}
-
-static DEVICE_ATTR_RO(cfg);
-
-static ssize_t nic_type_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "TYPE: %d\n", priv->nic_type);
-}
-
-static DEVICE_ATTR_RO(nic_type);
-
-static ssize_t ucode_version_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 len = sizeof(u32), tmp = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len))
- return 0;
-
- return sprintf(buf, "0x%08x\n", tmp);
-}
-
-static DEVICE_ATTR_RO(ucode_version);
-
-static ssize_t rtc_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- u32 len = sizeof(u32), tmp = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len))
- return 0;
-
- return sprintf(buf, "0x%08x\n", tmp);
-}
-
-static DEVICE_ATTR_RO(rtc);
-
-/*
- * Add a device attribute to view/control the delay between eeprom
- * operations.
- */
-static ssize_t eeprom_delay_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- int n = p->eeprom_delay;
- return sprintf(buf, "%i\n", n);
-}
-static ssize_t eeprom_delay_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- sscanf(buf, "%i", &p->eeprom_delay);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(eeprom_delay);
-
-static ssize_t command_event_reg_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT);
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t command_event_reg_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- u32 reg;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &reg);
- ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(command_event_reg);
-
-static ssize_t mem_gpio_reg_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- reg = ipw_read_reg32(p, 0x301100);
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t mem_gpio_reg_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- u32 reg;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &reg);
- ipw_write_reg32(p, 0x301100, reg);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(mem_gpio_reg);
-
-static ssize_t indirect_dword_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_INDIRECT_DWORD)
- reg = ipw_read_reg32(priv, priv->indirect_dword);
- else
- reg = 0;
-
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t indirect_dword_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->indirect_dword);
- priv->status |= STATUS_INDIRECT_DWORD;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(indirect_dword);
-
-static ssize_t indirect_byte_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u8 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_INDIRECT_BYTE)
- reg = ipw_read_reg8(priv, priv->indirect_byte);
- else
- reg = 0;
-
- return sprintf(buf, "0x%02x\n", reg);
-}
-static ssize_t indirect_byte_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->indirect_byte);
- priv->status |= STATUS_INDIRECT_BYTE;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(indirect_byte);
-
-static ssize_t direct_dword_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_DIRECT_DWORD)
- reg = ipw_read32(priv, priv->direct_dword);
- else
- reg = 0;
-
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t direct_dword_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->direct_dword);
- priv->status |= STATUS_DIRECT_DWORD;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(direct_dword);
-
-static int rf_kill_active(struct ipw_priv *priv)
-{
- if (0 == (ipw_read32(priv, 0x30) & 0x10000)) {
- priv->status |= STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- } else {
- priv->status &= ~STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- }
-
- return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;
-}
-
-static ssize_t rf_kill_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- /* 0 - RF kill not enabled
- 1 - SW based RF kill active (sysfs)
- 2 - HW based RF kill active
- 3 - Both HW and SW baed RF kill active */
- struct ipw_priv *priv = dev_get_drvdata(d);
- int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
- (rf_kill_active(priv) ? 0x2 : 0x0);
- return sprintf(buf, "%i\n", val);
-}
-
-static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
-{
- if ((disable_radio ? 1 : 0) ==
- ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0))
- return 0;
-
- IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
- disable_radio ? "OFF" : "ON");
-
- if (disable_radio) {
- priv->status |= STATUS_RF_KILL_SW;
-
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- schedule_work(&priv->down);
- } else {
- priv->status &= ~STATUS_RF_KILL_SW;
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("Can not turn radio back on - "
- "disabled by HW switch\n");
- /* Make sure the RF_KILL check timer is running */
- cancel_delayed_work(&priv->rf_kill);
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(2 * HZ));
- } else
- schedule_work(&priv->up);
- }
-
- return 1;
-}
-
-static ssize_t rf_kill_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- ipw_radio_kill_sw(priv, buf[0] == '1');
-
- return count;
-}
-
-static DEVICE_ATTR_RW(rf_kill);
-
-static ssize_t speed_scan_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int pos = 0, len = 0;
- if (priv->config & CFG_SPEED_SCAN) {
- while (priv->speed_scan[pos] != 0)
- len += sprintf(&buf[len], "%d ",
- priv->speed_scan[pos++]);
- return len + sprintf(&buf[len], "\n");
- }
-
- return sprintf(buf, "0\n");
-}
-
-static ssize_t speed_scan_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int channel, pos = 0;
- const char *p = buf;
-
- /* list of space separated channels to scan, optionally ending with 0 */
- while ((channel = simple_strtol(p, NULL, 0))) {
- if (pos == MAX_SPEED_SCAN - 1) {
- priv->speed_scan[pos] = 0;
- break;
- }
-
- if (libipw_is_valid_channel(priv->ieee, channel))
- priv->speed_scan[pos++] = channel;
- else
- IPW_WARNING("Skipping invalid channel request: %d\n",
- channel);
- p = strchr(p, ' ');
- if (!p)
- break;
- while (*p == ' ' || *p == '\t')
- p++;
- }
-
- if (pos == 0)
- priv->config &= ~CFG_SPEED_SCAN;
- else {
- priv->speed_scan_pos = 0;
- priv->config |= CFG_SPEED_SCAN;
- }
-
- return count;
-}
-
-static DEVICE_ATTR_RW(speed_scan);
-
-static ssize_t net_stats_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0');
-}
-
-static ssize_t net_stats_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- if (buf[0] == '1')
- priv->config |= CFG_NET_STATS;
- else
- priv->config &= ~CFG_NET_STATS;
-
- return count;
-}
-
-static DEVICE_ATTR_RW(net_stats);
-
-static ssize_t channels_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int len = 0, i;
-
- len = sprintf(&buf[len],
- "Displaying %d channels in 2.4Ghz band "
- "(802.11bg):\n", geo->bg_channels);
-
- for (i = 0; i < geo->bg_channels; i++) {
- len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
- geo->bg[i].channel,
- geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT ?
- " (radar spectrum)" : "",
- ((geo->bg[i].flags & LIBIPW_CH_NO_IBSS) ||
- (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT))
- ? "" : ", IBSS",
- geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
- "passive only" : "active/passive",
- geo->bg[i].flags & LIBIPW_CH_B_ONLY ?
- "B" : "B/G");
- }
-
- len += sprintf(&buf[len],
- "Displaying %d channels in 5.2Ghz band "
- "(802.11a):\n", geo->a_channels);
- for (i = 0; i < geo->a_channels; i++) {
- len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
- geo->a[i].channel,
- geo->a[i].flags & LIBIPW_CH_RADAR_DETECT ?
- " (radar spectrum)" : "",
- ((geo->a[i].flags & LIBIPW_CH_NO_IBSS) ||
- (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT))
- ? "" : ", IBSS",
- geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
- "passive only" : "active/passive");
- }
-
- return len;
-}
-
-static DEVICE_ATTR_ADMIN_RO(channels);
-
-static void notify_wx_assoc_event(struct ipw_priv *priv)
-{
- union iwreq_data wrqu;
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- if (priv->status & STATUS_ASSOCIATED)
- memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- else
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void ipw_irq_tasklet(struct tasklet_struct *t)
-{
- struct ipw_priv *priv = from_tasklet(priv, t, irq_tasklet);
- u32 inta, inta_mask, handled = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
-
- inta = ipw_read32(priv, IPW_INTA_RW);
- inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- IPW_WARNING("TASKLET INTA == 0xFFFFFFFF\n");
- /* Only handle the cached INTA values */
- inta = 0;
- }
- inta &= (IPW_INTA_MASK_ALL & inta_mask);
-
- /* Add any cached INTA values that need to be handled */
- inta |= priv->isr_inta;
-
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* handle all the justifications for the interrupt */
- if (inta & IPW_INTA_BIT_RX_TRANSFER) {
- ipw_rx(priv);
- handled |= IPW_INTA_BIT_RX_TRANSFER;
- }
-
- if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) {
- IPW_DEBUG_HC("Command completed.\n");
- ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1);
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
- handled |= IPW_INTA_BIT_TX_CMD_QUEUE;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_1) {
- IPW_DEBUG_TX("TX_QUEUE_1\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[0], 0);
- handled |= IPW_INTA_BIT_TX_QUEUE_1;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_2) {
- IPW_DEBUG_TX("TX_QUEUE_2\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[1], 1);
- handled |= IPW_INTA_BIT_TX_QUEUE_2;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_3) {
- IPW_DEBUG_TX("TX_QUEUE_3\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[2], 2);
- handled |= IPW_INTA_BIT_TX_QUEUE_3;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_4) {
- IPW_DEBUG_TX("TX_QUEUE_4\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[3], 3);
- handled |= IPW_INTA_BIT_TX_QUEUE_4;
- }
-
- if (inta & IPW_INTA_BIT_STATUS_CHANGE) {
- IPW_WARNING("STATUS_CHANGE\n");
- handled |= IPW_INTA_BIT_STATUS_CHANGE;
- }
-
- if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) {
- IPW_WARNING("TX_PERIOD_EXPIRED\n");
- handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED;
- }
-
- if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
- IPW_WARNING("HOST_CMD_DONE\n");
- handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) {
- IPW_WARNING("FW_INITIALIZATION_DONE\n");
- handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
- IPW_WARNING("PHY_OFF_DONE\n");
- handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
- }
-
- if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
- IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
- priv->status |= STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- wake_up_interruptible(&priv->wait_command_queue);
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- schedule_work(&priv->link_down);
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- handled |= IPW_INTA_BIT_RF_KILL_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FATAL_ERROR) {
- IPW_WARNING("Firmware error detected. Restarting.\n");
- if (priv->error) {
- IPW_DEBUG_FW("Sysfs 'error' log already exists.\n");
- if (ipw_debug_level & IPW_DL_FW_ERRORS) {
- struct ipw_fw_error *error =
- ipw_alloc_error_log(priv);
- ipw_dump_error_log(priv, error);
- kfree(error);
- }
- } else {
- priv->error = ipw_alloc_error_log(priv);
- if (priv->error)
- IPW_DEBUG_FW("Sysfs 'error' log captured.\n");
- else
- IPW_DEBUG_FW("Error allocating sysfs 'error' "
- "log.\n");
- if (ipw_debug_level & IPW_DL_FW_ERRORS)
- ipw_dump_error_log(priv, priv->error);
- }
-
- /* XXX: If hardware encryption is for WPA/WPA2,
- * we have to notify the supplicant. */
- if (priv->ieee->sec.encrypt) {
- priv->status &= ~STATUS_ASSOCIATED;
- notify_wx_assoc_event(priv);
- }
-
- /* Keep the restart process from trying to send host
- * commands by clearing the INIT status bit */
- priv->status &= ~STATUS_INIT;
-
- /* Cancel currently queued command. */
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
-
- schedule_work(&priv->adapter_restart);
- handled |= IPW_INTA_BIT_FATAL_ERROR;
- }
-
- if (inta & IPW_INTA_BIT_PARITY_ERROR) {
- IPW_ERROR("Parity error\n");
- handled |= IPW_INTA_BIT_PARITY_ERROR;
- }
-
- if (handled != inta) {
- IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* enable all interrupts */
- ipw_enable_interrupts(priv);
-}
-
-#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
-static char *get_cmd_string(u8 cmd)
-{
- switch (cmd) {
- IPW_CMD(HOST_COMPLETE);
- IPW_CMD(POWER_DOWN);
- IPW_CMD(SYSTEM_CONFIG);
- IPW_CMD(MULTICAST_ADDRESS);
- IPW_CMD(SSID);
- IPW_CMD(ADAPTER_ADDRESS);
- IPW_CMD(PORT_TYPE);
- IPW_CMD(RTS_THRESHOLD);
- IPW_CMD(FRAG_THRESHOLD);
- IPW_CMD(POWER_MODE);
- IPW_CMD(WEP_KEY);
- IPW_CMD(TGI_TX_KEY);
- IPW_CMD(SCAN_REQUEST);
- IPW_CMD(SCAN_REQUEST_EXT);
- IPW_CMD(ASSOCIATE);
- IPW_CMD(SUPPORTED_RATES);
- IPW_CMD(SCAN_ABORT);
- IPW_CMD(TX_FLUSH);
- IPW_CMD(QOS_PARAMETERS);
- IPW_CMD(DINO_CONFIG);
- IPW_CMD(RSN_CAPABILITIES);
- IPW_CMD(RX_KEY);
- IPW_CMD(CARD_DISABLE);
- IPW_CMD(SEED_NUMBER);
- IPW_CMD(TX_POWER);
- IPW_CMD(COUNTRY_INFO);
- IPW_CMD(AIRONET_INFO);
- IPW_CMD(AP_TX_POWER);
- IPW_CMD(CCKM_INFO);
- IPW_CMD(CCX_VER_INFO);
- IPW_CMD(SET_CALIBRATION);
- IPW_CMD(SENSITIVITY_CALIB);
- IPW_CMD(RETRY_LIMIT);
- IPW_CMD(IPW_PRE_POWER_DOWN);
- IPW_CMD(VAP_BEACON_TEMPLATE);
- IPW_CMD(VAP_DTIM_PERIOD);
- IPW_CMD(EXT_SUPPORTED_RATES);
- IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT);
- IPW_CMD(VAP_QUIET_INTERVALS);
- IPW_CMD(VAP_CHANNEL_SWITCH);
- IPW_CMD(VAP_MANDATORY_CHANNELS);
- IPW_CMD(VAP_CELL_PWR_LIMIT);
- IPW_CMD(VAP_CF_PARAM_SET);
- IPW_CMD(VAP_SET_BEACONING_STATE);
- IPW_CMD(MEASUREMENT);
- IPW_CMD(POWER_CAPABILITY);
- IPW_CMD(SUPPORTED_CHANNELS);
- IPW_CMD(TPC_REPORT);
- IPW_CMD(WME_INFO);
- IPW_CMD(PRODUCTION_COMMAND);
- default:
- return "UNKNOWN";
- }
-}
-
-#define HOST_COMPLETE_TIMEOUT HZ
-
-static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
-{
- int rc = 0;
- unsigned long flags;
- unsigned long now, end;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->status & STATUS_HCMD_ACTIVE) {
- IPW_ERROR("Failed to send %s: Already sending a command.\n",
- get_cmd_string(cmd->cmd));
- spin_unlock_irqrestore(&priv->lock, flags);
- return -EAGAIN;
- }
-
- priv->status |= STATUS_HCMD_ACTIVE;
-
- if (priv->cmdlog) {
- priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies;
- priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd;
- priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len;
- memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param,
- cmd->len);
- priv->cmdlog[priv->cmdlog_pos].retcode = -1;
- }
-
- IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n",
- get_cmd_string(cmd->cmd), cmd->cmd, cmd->len,
- priv->status);
-
-#ifndef DEBUG_CMD_WEP_KEY
- if (cmd->cmd == IPW_CMD_WEP_KEY)
- IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n");
- else
-#endif
- printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
-
- rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0);
- if (rc) {
- priv->status &= ~STATUS_HCMD_ACTIVE;
- IPW_ERROR("Failed to send %s: Reason %d\n",
- get_cmd_string(cmd->cmd), rc);
- spin_unlock_irqrestore(&priv->lock, flags);
- goto exit;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- now = jiffies;
- end = now + HOST_COMPLETE_TIMEOUT;
-again:
- rc = wait_event_interruptible_timeout(priv->wait_command_queue,
- !(priv->
- status & STATUS_HCMD_ACTIVE),
- end - now);
- if (rc < 0) {
- now = jiffies;
- if (time_before(now, end))
- goto again;
- rc = 0;
- }
-
- if (rc == 0) {
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->status & STATUS_HCMD_ACTIVE) {
- IPW_ERROR("Failed to send %s: Command timed out.\n",
- get_cmd_string(cmd->cmd));
- priv->status &= ~STATUS_HCMD_ACTIVE;
- spin_unlock_irqrestore(&priv->lock, flags);
- rc = -EIO;
- goto exit;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- } else
- rc = 0;
-
- if (priv->status & STATUS_RF_KILL_HW) {
- IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n",
- get_cmd_string(cmd->cmd));
- rc = -EIO;
- goto exit;
- }
-
- exit:
- if (priv->cmdlog) {
- priv->cmdlog[priv->cmdlog_pos++].retcode = rc;
- priv->cmdlog_pos %= priv->cmdlog_len;
- }
- return rc;
-}
-
-static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command)
-{
- struct host_cmd cmd = {
- .cmd = command,
- };
-
- return __ipw_send_cmd(priv, &cmd);
-}
-
-static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len,
- const void *data)
-{
- struct host_cmd cmd = {
- .cmd = command,
- .len = len,
- .param = data,
- };
-
- return __ipw_send_cmd(priv, &cmd);
-}
-
-static int ipw_send_host_complete(struct ipw_priv *priv)
-{
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE);
-}
-
-static int ipw_send_system_config(struct ipw_priv *priv)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG,
- sizeof(priv->sys_config),
- &priv->sys_config);
-}
-
-static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
-{
- if (!priv || !ssid) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE),
- ssid);
-}
-
-static int ipw_send_adapter_address(struct ipw_priv *priv, const u8 * mac)
-{
- if (!priv || !mac) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- IPW_DEBUG_INFO("%s: Setting MAC to %pM\n",
- priv->net_dev->name, mac);
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
-}
-
-static void ipw_adapter_restart(void *adapter)
-{
- struct ipw_priv *priv = adapter;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return;
-
- ipw_down(priv);
-
- if (priv->assoc_network &&
- (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS))
- ipw_remove_current_network(priv);
-
- if (ipw_up(priv)) {
- IPW_ERROR("Failed to up device\n");
- return;
- }
-}
-
-static void ipw_bg_adapter_restart(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, adapter_restart);
- mutex_lock(&priv->mutex);
- ipw_adapter_restart(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_abort_scan(struct ipw_priv *priv);
-
-#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
-
-static void ipw_scan_check(void *data)
-{
- struct ipw_priv *priv = data;
-
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_SCAN("Scan completion watchdog resetting "
- "adapter after (%dms).\n",
- jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
- schedule_work(&priv->adapter_restart);
- } else if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan completion watchdog aborting scan "
- "after (%dms).\n",
- jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
- ipw_abort_scan(priv);
- schedule_delayed_work(&priv->scan_check, HZ);
- }
-}
-
-static void ipw_bg_scan_check(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, scan_check.work);
- mutex_lock(&priv->mutex);
- ipw_scan_check(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_send_scan_request_ext(struct ipw_priv *priv,
- struct ipw_scan_request_ext *request)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT,
- sizeof(*request), request);
-}
-
-static int ipw_send_scan_abort(struct ipw_priv *priv)
-{
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT);
-}
-
-static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
-{
- struct ipw_sensitivity_calib calib = {
- .beacon_rssi_raw = cpu_to_le16(sens),
- };
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib),
- &calib);
-}
-
-static int ipw_send_associate(struct ipw_priv *priv,
- struct ipw_associate *associate)
-{
- if (!priv || !associate) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(*associate),
- associate);
-}
-
-static int ipw_send_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *rates)
-{
- if (!priv || !rates) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates),
- rates);
-}
-
-static int ipw_set_random_seed(struct ipw_priv *priv)
-{
- u32 val;
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- get_random_bytes(&val, sizeof(val));
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val);
-}
-
-static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
-{
- __le32 v = cpu_to_le32(phy_off);
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(v), &v);
-}
-
-static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
-{
- if (!priv || !power) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power);
-}
-
-static int ipw_set_tx_power(struct ipw_priv *priv)
-{
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct ipw_tx_power tx_power;
- s8 max_power;
- int i;
-
- memset(&tx_power, 0, sizeof(tx_power));
-
- /* configure device for 'G' band */
- tx_power.ieee_mode = IPW_G_MODE;
- tx_power.num_channels = geo->bg_channels;
- for (i = 0; i < geo->bg_channels; i++) {
- max_power = geo->bg[i].max_power;
- tx_power.channels_tx_power[i].channel_number =
- geo->bg[i].channel;
- tx_power.channels_tx_power[i].tx_power = max_power ?
- min(max_power, priv->tx_power) : priv->tx_power;
- }
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
-
- /* configure device to also handle 'B' band */
- tx_power.ieee_mode = IPW_B_MODE;
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
-
- /* configure device to also handle 'A' band */
- if (priv->ieee->abg_true) {
- tx_power.ieee_mode = IPW_A_MODE;
- tx_power.num_channels = geo->a_channels;
- for (i = 0; i < tx_power.num_channels; i++) {
- max_power = geo->a[i].max_power;
- tx_power.channels_tx_power[i].channel_number =
- geo->a[i].channel;
- tx_power.channels_tx_power[i].tx_power = max_power ?
- min(max_power, priv->tx_power) : priv->tx_power;
- }
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
- }
- return 0;
-}
-
-static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
-{
- struct ipw_rts_threshold rts_threshold = {
- .rts_threshold = cpu_to_le16(rts),
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD,
- sizeof(rts_threshold), &rts_threshold);
-}
-
-static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
-{
- struct ipw_frag_threshold frag_threshold = {
- .frag_threshold = cpu_to_le16(frag),
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD,
- sizeof(frag_threshold), &frag_threshold);
-}
-
-static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
-{
- __le32 param;
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- /* If on battery, set to 3, if AC set to CAM, else user
- * level */
- switch (mode) {
- case IPW_POWER_BATTERY:
- param = cpu_to_le32(IPW_POWER_INDEX_3);
- break;
- case IPW_POWER_AC:
- param = cpu_to_le32(IPW_POWER_MODE_CAM);
- break;
- default:
- param = cpu_to_le32(mode);
- break;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
- &param);
-}
-
-static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit)
-{
- struct ipw_retry_limit retry_limit = {
- .short_retry_limit = slimit,
- .long_retry_limit = llimit
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit),
- &retry_limit);
-}
-
-/*
- * The IPW device contains a Microwire compatible EEPROM that stores
- * various data like the MAC address. Usually the firmware has exclusive
- * access to the eeprom, but during device initialization (before the
- * device driver has sent the HostComplete command to the firmware) the
- * device driver has read access to the EEPROM by way of indirect addressing
- * through a couple of memory mapped registers.
- *
- * The following is a simplified implementation for pulling data out of the
- * eeprom, along with some helper functions to find information in
- * the per device private data's copy of the eeprom.
- *
- * NOTE: To better understand how these functions work (i.e what is a chip
- * select and why do have to keep driving the eeprom clock?), read
- * just about any data sheet for a Microwire compatible EEPROM.
- */
-
-/* write a 32 bit value into the indirect accessor register */
-static inline void eeprom_write_reg(struct ipw_priv *p, u32 data)
-{
- ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data);
-
- /* the eeprom requires some time to complete the operation */
- udelay(p->eeprom_delay);
-}
-
-/* perform a chip select operation */
-static void eeprom_cs(struct ipw_priv *priv)
-{
- eeprom_write_reg(priv, 0);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
-}
-
-/* perform a chip select operation */
-static void eeprom_disable_cs(struct ipw_priv *priv)
-{
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- eeprom_write_reg(priv, 0);
- eeprom_write_reg(priv, EEPROM_BIT_SK);
-}
-
-/* push a single bit down to the eeprom */
-static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit)
-{
- int d = (bit ? EEPROM_BIT_DI : 0);
- eeprom_write_reg(p, EEPROM_BIT_CS | d);
- eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK);
-}
-
-/* push an opcode followed by an address down to the eeprom */
-static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr)
-{
- int i;
-
- eeprom_cs(priv);
- eeprom_write_bit(priv, 1);
- eeprom_write_bit(priv, op & 2);
- eeprom_write_bit(priv, op & 1);
- for (i = 7; i >= 0; i--) {
- eeprom_write_bit(priv, addr & (1 << i));
- }
-}
-
-/* pull 16 bits off the eeprom, one bit at a time */
-static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr)
-{
- int i;
- u16 r = 0;
-
- /* Send READ Opcode */
- eeprom_op(priv, EEPROM_CMD_READ, addr);
-
- /* Send dummy bit */
- eeprom_write_reg(priv, EEPROM_BIT_CS);
-
- /* Read the byte off the eeprom one bit at a time */
- for (i = 0; i < 16; i++) {
- u32 data = 0;
- eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS);
- r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0);
- }
-
- /* Send another dummy bit */
- eeprom_write_reg(priv, 0);
- eeprom_disable_cs(priv);
-
- return r;
-}
-
-/* helper function for pulling the mac address out of the private */
-/* data's copy of the eeprom data */
-static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
-{
- memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], ETH_ALEN);
-}
-
-static void ipw_read_eeprom(struct ipw_priv *priv)
-{
- int i;
- __le16 *eeprom = (__le16 *) priv->eeprom;
-
- IPW_DEBUG_TRACE(">>\n");
-
- /* read entire contents of eeprom into private buffer */
- for (i = 0; i < 128; i++)
- eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-/*
- * Either the device driver (i.e. the host) or the firmware can
- * load eeprom data into the designated region in SRAM. If neither
- * happens then the FW will shutdown with a fatal error.
- *
- * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE
- * bit needs region of shared SRAM needs to be non-zero.
- */
-static void ipw_eeprom_init_sram(struct ipw_priv *priv)
-{
- int i;
-
- IPW_DEBUG_TRACE(">>\n");
-
- /*
- If the data looks correct, then copy it to our private
- copy. Otherwise let the firmware know to perform the operation
- on its own.
- */
- if (priv->eeprom[EEPROM_VERSION] != 0) {
- IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
-
- /* write the eeprom data to sram */
- for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
- ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]);
-
- /* Do not load eeprom data on fatal error or suspend */
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
- } else {
- IPW_DEBUG_INFO("Enabling FW initialization of SRAM\n");
-
- /* Load eeprom data on fatal error or suspend */
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1);
- }
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-static void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
-{
- count >>= 2;
- if (!count)
- return;
- _ipw_write32(priv, IPW_AUTOINC_ADDR, start);
- while (count--)
- _ipw_write32(priv, IPW_AUTOINC_DATA, 0);
-}
-
-static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
-{
- ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL,
- CB_NUMBER_OF_ELEMENTS_SMALL *
- sizeof(struct command_block));
-}
-
-static int ipw_fw_dma_enable(struct ipw_priv *priv)
-{ /* start dma engine but no transfers yet */
-
- IPW_DEBUG_FW(">> :\n");
-
- /* Start the dma */
- ipw_fw_dma_reset_command_blocks(priv);
-
- /* Write CB base address */
- ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL);
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-}
-
-static void ipw_fw_dma_abort(struct ipw_priv *priv)
-{
- u32 control = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- /* set the Stop and Abort bit */
- control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
- ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
- priv->sram_desc.last_cb_index = 0;
-
- IPW_DEBUG_FW("<<\n");
-}
-
-static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
- struct command_block *cb)
-{
- u32 address =
- IPW_SHARED_SRAM_DMA_CONTROL +
- (sizeof(struct command_block) * index);
- IPW_DEBUG_FW(">> :\n");
-
- ipw_write_indirect(priv, address, (u8 *) cb,
- (int)sizeof(struct command_block));
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-
-}
-
-static int ipw_fw_dma_kick(struct ipw_priv *priv)
-{
- u32 control = 0;
- u32 index = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- for (index = 0; index < priv->sram_desc.last_cb_index; index++)
- ipw_fw_dma_write_command_block(priv, index,
- &priv->sram_desc.cb_list[index]);
-
- /* Enable the DMA in the CSR register */
- ipw_clear_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED |
- IPW_RESET_REG_STOP_MASTER);
-
- /* Set the Start bit. */
- control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START;
- ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-}
-
-static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
-{
- u32 address;
- u32 register_value = 0;
- u32 cb_fields_address = 0;
-
- IPW_DEBUG_FW(">> :\n");
- address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
- IPW_DEBUG_FW_INFO("Current CB is 0x%x\n", address);
-
- /* Read the DMA Controlor register */
- register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL);
- IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x\n", register_value);
-
- /* Print the CB values */
- cb_fields_address = address;
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Control Field is 0x%x\n", register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x\n", register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x\n",
- register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x\n", register_value);
-
- IPW_DEBUG_FW(">> :\n");
-}
-
-static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
-{
- u32 current_cb_address = 0;
- u32 current_cb_index = 0;
-
- IPW_DEBUG_FW("<< :\n");
- current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
-
- current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) /
- sizeof(struct command_block);
-
- IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X\n",
- current_cb_index, current_cb_address);
-
- IPW_DEBUG_FW(">> :\n");
- return current_cb_index;
-
-}
-
-static int ipw_fw_dma_add_command_block(struct ipw_priv *priv,
- u32 src_address,
- u32 dest_address,
- u32 length,
- int interrupt_enabled, int is_last)
-{
-
- u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC |
- CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG |
- CB_DEST_SIZE_LONG;
- struct command_block *cb;
- u32 last_cb_element = 0;
-
- IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n",
- src_address, dest_address, length);
-
- if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL)
- return -1;
-
- last_cb_element = priv->sram_desc.last_cb_index;
- cb = &priv->sram_desc.cb_list[last_cb_element];
- priv->sram_desc.last_cb_index++;
-
- /* Calculate the new CB control word */
- if (interrupt_enabled)
- control |= CB_INT_ENABLED;
-
- if (is_last)
- control |= CB_LAST_VALID;
-
- control |= length;
-
- /* Calculate the CB Element's checksum value */
- cb->status = control ^ src_address ^ dest_address;
-
- /* Copy the Source and Destination addresses */
- cb->dest_addr = dest_address;
- cb->source_addr = src_address;
-
- /* Copy the Control Word last */
- cb->control = control;
-
- return 0;
-}
-
-static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address,
- int nr, u32 dest_address, u32 len)
-{
- int ret, i;
- u32 size;
-
- IPW_DEBUG_FW(">>\n");
- IPW_DEBUG_FW_INFO("nr=%d dest_address=0x%x len=0x%x\n",
- nr, dest_address, len);
-
- for (i = 0; i < nr; i++) {
- size = min_t(u32, len - i * CB_MAX_LENGTH, CB_MAX_LENGTH);
- ret = ipw_fw_dma_add_command_block(priv, src_address[i],
- dest_address +
- i * CB_MAX_LENGTH, size,
- 0, 0);
- if (ret) {
- IPW_DEBUG_FW_INFO(": Failed\n");
- return -1;
- } else
- IPW_DEBUG_FW_INFO(": Added new cb\n");
- }
-
- IPW_DEBUG_FW("<<\n");
- return 0;
-}
-
-static int ipw_fw_dma_wait(struct ipw_priv *priv)
-{
- u32 current_index = 0, previous_index;
- u32 watchdog = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- current_index = ipw_fw_dma_command_block_index(priv);
- IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n",
- (int)priv->sram_desc.last_cb_index);
-
- while (current_index < priv->sram_desc.last_cb_index) {
- udelay(50);
- previous_index = current_index;
- current_index = ipw_fw_dma_command_block_index(priv);
-
- if (previous_index < current_index) {
- watchdog = 0;
- continue;
- }
- if (++watchdog > 400) {
- IPW_DEBUG_FW_INFO("Timeout\n");
- ipw_fw_dma_dump_command_block(priv);
- ipw_fw_dma_abort(priv);
- return -1;
- }
- }
-
- ipw_fw_dma_abort(priv);
-
- /*Disable the DMA in the CSR register */
- ipw_set_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER);
-
- IPW_DEBUG_FW("<< dmaWaitSync\n");
- return 0;
-}
-
-static void ipw_remove_current_network(struct ipw_priv *priv)
-{
- struct list_head *element, *safe;
- struct libipw_network *network = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_safe(element, safe, &priv->ieee->network_list) {
- network = list_entry(element, struct libipw_network, list);
- if (ether_addr_equal(network->bssid, priv->bssid)) {
- list_del(element);
- list_add_tail(&network->list,
- &priv->ieee->network_free_list);
- }
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-}
-
-/* timeout in msec, attempted in 10-msec quanta */
-static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
- int timeout)
-{
- int i = 0;
-
- do {
- if ((ipw_read32(priv, addr) & mask) == mask)
- return i;
- mdelay(10);
- i += 10;
- } while (i < timeout);
-
- return -ETIME;
-}
-
-/* These functions load the firmware and micro code for the operation of
- * the ipw hardware. It assumes the buffer has all the bits for the
- * image and the caller is handling the memory allocation and clean up.
- */
-
-static int ipw_stop_master(struct ipw_priv *priv)
-{
- int rc;
-
- IPW_DEBUG_TRACE(">>\n");
- /* stop master. typical delay - 0 */
- ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
-
- /* timeout is in msec, polled in 10-msec quanta */
- rc = ipw_poll_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED, 100);
- if (rc < 0) {
- IPW_ERROR("wait for stop master failed after 100ms\n");
- return -1;
- }
-
- IPW_DEBUG_INFO("stop master %dms\n", rc);
-
- return rc;
-}
-
-static void ipw_arc_release(struct ipw_priv *priv)
-{
- IPW_DEBUG_TRACE(">>\n");
- mdelay(5);
-
- ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
-
- /* no one knows timing, for safety add some delay */
- mdelay(5);
-}
-
-struct fw_chunk {
- __le32 address;
- __le32 length;
-};
-
-static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
-{
- int rc = 0, i, addr;
- u8 cr = 0;
- __le16 *image;
-
- image = (__le16 *) data;
-
- IPW_DEBUG_TRACE(">>\n");
-
- rc = ipw_stop_master(priv);
-
- if (rc < 0)
- return rc;
-
- for (addr = IPW_SHARED_LOWER_BOUND;
- addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
- ipw_write32(priv, addr, 0);
- }
-
- /* no ucode (yet) */
- memset(&priv->dino_alive, 0, sizeof(priv->dino_alive));
- /* destroy DMA queues */
- /* reset sequence */
-
- ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON);
- ipw_arc_release(priv);
- ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF);
- mdelay(1);
-
- /* reset PHY */
- ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN);
- mdelay(1);
-
- ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0);
- mdelay(1);
-
- /* enable ucode store */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0);
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS);
- mdelay(1);
-
- /* write ucode */
- /*
- * @bug
- * Do NOT set indirect address register once and then
- * store data to indirect data register in the loop.
- * It seems very reasonable, but in this case DINO do not
- * accept ucode. It is essential to set address each time.
- */
- /* load new ipw uCode */
- for (i = 0; i < len / 2; i++)
- ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE,
- le16_to_cpu(image[i]));
-
- /* enable DINO */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
-
- /* this is where the igx / win driver deveates from the VAP driver. */
-
- /* wait for alive response */
- for (i = 0; i < 100; i++) {
- /* poll for incoming data */
- cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS);
- if (cr & DINO_RXFIFO_DATA)
- break;
- mdelay(1);
- }
-
- if (cr & DINO_RXFIFO_DATA) {
- /* alive_command_responce size is NOT multiple of 4 */
- __le32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4];
-
- for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
- response_buffer[i] =
- cpu_to_le32(ipw_read_reg32(priv,
- IPW_BASEBAND_RX_FIFO_READ));
- memcpy(&priv->dino_alive, response_buffer,
- sizeof(priv->dino_alive));
- if (priv->dino_alive.alive_command == 1
- && priv->dino_alive.ucode_valid == 1) {
- rc = 0;
- IPW_DEBUG_INFO
- ("Microcode OK, rev. %d (0x%x) dev. %d (0x%x) "
- "of %02d/%02d/%02d %02d:%02d\n",
- priv->dino_alive.software_revision,
- priv->dino_alive.software_revision,
- priv->dino_alive.device_identifier,
- priv->dino_alive.device_identifier,
- priv->dino_alive.time_stamp[0],
- priv->dino_alive.time_stamp[1],
- priv->dino_alive.time_stamp[2],
- priv->dino_alive.time_stamp[3],
- priv->dino_alive.time_stamp[4]);
- } else {
- IPW_DEBUG_INFO("Microcode is not alive\n");
- rc = -EINVAL;
- }
- } else {
- IPW_DEBUG_INFO("No alive response from DINO\n");
- rc = -ETIME;
- }
-
- /* disable DINO, otherwise for some reason
- firmware have problem getting alive resp. */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
-
- return rc;
-}
-
-static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
-{
- int ret = -1;
- int offset = 0;
- struct fw_chunk *chunk;
- int total_nr = 0;
- int i;
- struct dma_pool *pool;
- void **virts;
- dma_addr_t *phys;
-
- IPW_DEBUG_TRACE("<< :\n");
-
- virts = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(void *),
- GFP_KERNEL);
- if (!virts)
- return -ENOMEM;
-
- phys = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(dma_addr_t),
- GFP_KERNEL);
- if (!phys) {
- kfree(virts);
- return -ENOMEM;
- }
- pool = dma_pool_create("ipw2200", &priv->pci_dev->dev, CB_MAX_LENGTH, 0,
- 0);
- if (!pool) {
- IPW_ERROR("dma_pool_create failed\n");
- kfree(phys);
- kfree(virts);
- return -ENOMEM;
- }
-
- /* Start the Dma */
- ret = ipw_fw_dma_enable(priv);
-
- /* the DMA is already ready this would be a bug. */
- BUG_ON(priv->sram_desc.last_cb_index > 0);
-
- do {
- u32 chunk_len;
- u8 *start;
- int size;
- int nr = 0;
-
- chunk = (struct fw_chunk *)(data + offset);
- offset += sizeof(struct fw_chunk);
- chunk_len = le32_to_cpu(chunk->length);
- start = data + offset;
-
- nr = (chunk_len + CB_MAX_LENGTH - 1) / CB_MAX_LENGTH;
- for (i = 0; i < nr; i++) {
- virts[total_nr] = dma_pool_alloc(pool, GFP_KERNEL,
- &phys[total_nr]);
- if (!virts[total_nr]) {
- ret = -ENOMEM;
- goto out;
- }
- size = min_t(u32, chunk_len - i * CB_MAX_LENGTH,
- CB_MAX_LENGTH);
- memcpy(virts[total_nr], start, size);
- start += size;
- total_nr++;
- /* We don't support fw chunk larger than 64*8K */
- BUG_ON(total_nr > CB_NUMBER_OF_ELEMENTS_SMALL);
- }
-
- /* build DMA packet and queue up for sending */
- /* dma to chunk->address, the chunk->length bytes from data +
- * offeset*/
- /* Dma loading */
- ret = ipw_fw_dma_add_buffer(priv, &phys[total_nr - nr],
- nr, le32_to_cpu(chunk->address),
- chunk_len);
- if (ret) {
- IPW_DEBUG_INFO("dmaAddBuffer Failed\n");
- goto out;
- }
-
- offset += chunk_len;
- } while (offset < len);
-
- /* Run the DMA and wait for the answer */
- ret = ipw_fw_dma_kick(priv);
- if (ret) {
- IPW_ERROR("dmaKick Failed\n");
- goto out;
- }
-
- ret = ipw_fw_dma_wait(priv);
- if (ret) {
- IPW_ERROR("dmaWaitSync Failed\n");
- goto out;
- }
- out:
- for (i = 0; i < total_nr; i++)
- dma_pool_free(pool, virts[i], phys[i]);
-
- dma_pool_destroy(pool);
- kfree(phys);
- kfree(virts);
-
- return ret;
-}
-
-/* stop nic */
-static int ipw_stop_nic(struct ipw_priv *priv)
-{
- int rc = 0;
-
- /* stop */
- ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
-
- rc = ipw_poll_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED, 500);
- if (rc < 0) {
- IPW_ERROR("wait for reg master disabled failed after 500ms\n");
- return rc;
- }
-
- ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
-
- return rc;
-}
-
-static void ipw_start_nic(struct ipw_priv *priv)
-{
- IPW_DEBUG_TRACE(">>\n");
-
- /* prvHwStartNic release ARC */
- ipw_clear_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED |
- IPW_RESET_REG_STOP_MASTER |
- CBD_RESET_REG_PRINCETON_RESET);
-
- /* enable power management */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW,
- IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-static int ipw_init_nic(struct ipw_priv *priv)
-{
- int rc;
-
- IPW_DEBUG_TRACE(">>\n");
- /* reset */
- /*prvHwInitNic */
- /* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
-
- /* low-level PLL activation */
- ipw_write32(priv, IPW_READ_INT_REGISTER,
- IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
-
- /* wait for clock stabilization */
- rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW,
- IPW_GP_CNTRL_BIT_CLOCK_READY, 250);
- if (rc < 0)
- IPW_DEBUG_INFO("FAILED wait for clock stablization\n");
-
- /* assert SW reset */
- ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET);
-
- udelay(10);
-
- /* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
-
- IPW_DEBUG_TRACE(">>\n");
- return 0;
-}
-
-/* Call this function from process context, it will sleep in request_firmware.
- * Probe is an ok place to call this from.
- */
-static int ipw_reset_nic(struct ipw_priv *priv)
-{
- int rc = 0;
- unsigned long flags;
-
- IPW_DEBUG_TRACE(">>\n");
-
- rc = ipw_init_nic(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
- /* Clear the 'host command active' bit... */
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
- priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
- wake_up_interruptible(&priv->wait_state);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IPW_DEBUG_TRACE("<<\n");
- return rc;
-}
-
-
-struct ipw_fw {
- __le32 ver;
- __le32 boot_size;
- __le32 ucode_size;
- __le32 fw_size;
- u8 data[];
-};
-
-static int ipw_get_fw(struct ipw_priv *priv,
- const struct firmware **raw, const char *name)
-{
- struct ipw_fw *fw;
- int rc;
-
- /* ask firmware_class module to get the boot firmware off disk */
- rc = request_firmware(raw, name, &priv->pci_dev->dev);
- if (rc < 0) {
- IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc);
- return rc;
- }
-
- if ((*raw)->size < sizeof(*fw)) {
- IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size);
- return -EINVAL;
- }
-
- fw = (void *)(*raw)->data;
-
- if ((*raw)->size < sizeof(*fw) + le32_to_cpu(fw->boot_size) +
- le32_to_cpu(fw->ucode_size) + le32_to_cpu(fw->fw_size)) {
- IPW_ERROR("%s is too small or corrupt (%zd)\n",
- name, (*raw)->size);
- return -EINVAL;
- }
-
- IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n",
- name,
- le32_to_cpu(fw->ver) >> 16,
- le32_to_cpu(fw->ver) & 0xff,
- (*raw)->size - sizeof(*fw));
- return 0;
-}
-
-#define IPW_RX_BUF_SIZE (3000)
-
-static void ipw_rx_queue_reset(struct ipw_priv *priv,
- struct ipw_rx_queue *rxq)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&rxq->lock, flags);
-
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
- /* In the reset function, these buffers may have been allocated
- * to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- dma_unmap_single(&priv->pci_dev->dev,
- rxq->pool[i].dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb_irq(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
- }
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
- }
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
- spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-#ifdef CONFIG_PM
-static int fw_loaded = 0;
-static const struct firmware *raw = NULL;
-
-static void free_firmware(void)
-{
- if (fw_loaded) {
- release_firmware(raw);
- raw = NULL;
- fw_loaded = 0;
- }
-}
-#else
-#define free_firmware() do {} while (0)
-#endif
-
-static int ipw_load(struct ipw_priv *priv)
-{
-#ifndef CONFIG_PM
- const struct firmware *raw = NULL;
-#endif
- struct ipw_fw *fw;
- u8 *boot_img, *ucode_img, *fw_img;
- u8 *name = NULL;
- int rc = 0, retries = 3;
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- name = "ipw2200-ibss.fw";
- break;
-#ifdef CONFIG_IPW2200_MONITOR
- case IW_MODE_MONITOR:
- name = "ipw2200-sniffer.fw";
- break;
-#endif
- case IW_MODE_INFRA:
- name = "ipw2200-bss.fw";
- break;
- }
-
- if (!name) {
- rc = -EINVAL;
- goto error;
- }
-
-#ifdef CONFIG_PM
- if (!fw_loaded) {
-#endif
- rc = ipw_get_fw(priv, &raw, name);
- if (rc < 0)
- goto error;
-#ifdef CONFIG_PM
- }
-#endif
-
- fw = (void *)raw->data;
- boot_img = &fw->data[0];
- ucode_img = &fw->data[le32_to_cpu(fw->boot_size)];
- fw_img = &fw->data[le32_to_cpu(fw->boot_size) +
- le32_to_cpu(fw->ucode_size)];
-
- if (!priv->rxq)
- priv->rxq = ipw_rx_queue_alloc(priv);
- else
- ipw_rx_queue_reset(priv, priv->rxq);
- if (!priv->rxq) {
- IPW_ERROR("Unable to initialize Rx queue\n");
- rc = -ENOMEM;
- goto error;
- }
-
- retry:
- /* Ensure interrupts are disabled */
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
- priv->status &= ~STATUS_INT_ENABLED;
-
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
- ipw_stop_nic(priv);
-
- rc = ipw_reset_nic(priv);
- if (rc < 0) {
- IPW_ERROR("Unable to reset NIC\n");
- goto error;
- }
-
- ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
- IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
-
- /* DMA the initial boot firmware into the device */
- rc = ipw_load_firmware(priv, boot_img, le32_to_cpu(fw->boot_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load boot firmware: %d\n", rc);
- goto error;
- }
-
- /* kick start the device */
- ipw_start_nic(priv);
-
- /* wait for the device to finish its initial startup sequence */
- rc = ipw_poll_bit(priv, IPW_INTA_RW,
- IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
- if (rc < 0) {
- IPW_ERROR("device failed to boot initial fw image\n");
- goto error;
- }
- IPW_DEBUG_INFO("initial device response after %dms\n", rc);
-
- /* ack fw init done interrupt */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
-
- /* DMA the ucode into the device */
- rc = ipw_load_ucode(priv, ucode_img, le32_to_cpu(fw->ucode_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load ucode: %d\n", rc);
- goto error;
- }
-
- /* stop nic */
- ipw_stop_nic(priv);
-
- /* DMA bss firmware into the device */
- rc = ipw_load_firmware(priv, fw_img, le32_to_cpu(fw->fw_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load firmware: %d\n", rc);
- goto error;
- }
-#ifdef CONFIG_PM
- fw_loaded = 1;
-#endif
-
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
-
- rc = ipw_queue_reset(priv);
- if (rc < 0) {
- IPW_ERROR("Unable to initialize queues\n");
- goto error;
- }
-
- /* Ensure interrupts are disabled */
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
- /* kick start the device */
- ipw_start_nic(priv);
-
- if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) {
- if (retries > 0) {
- IPW_WARNING("Parity error. Retrying init.\n");
- retries--;
- goto retry;
- }
-
- IPW_ERROR("TODO: Handle parity error -- schedule restart?\n");
- rc = -EIO;
- goto error;
- }
-
- /* wait for the device */
- rc = ipw_poll_bit(priv, IPW_INTA_RW,
- IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
- if (rc < 0) {
- IPW_ERROR("device failed to start within 500ms\n");
- goto error;
- }
- IPW_DEBUG_INFO("device response after %dms\n", rc);
-
- /* ack fw init done interrupt */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
-
- /* read eeprom data */
- priv->eeprom_delay = 1;
- ipw_read_eeprom(priv);
- /* initialize the eeprom region of sram */
- ipw_eeprom_init_sram(priv);
-
- /* enable interrupts */
- ipw_enable_interrupts(priv);
-
- /* Ensure our queue has valid packets */
- ipw_rx_queue_replenish(priv);
-
- ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read);
-
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
-#ifndef CONFIG_PM
- release_firmware(raw);
-#endif
- return 0;
-
- error:
- if (priv->rxq) {
- ipw_rx_queue_free(priv, priv->rxq);
- priv->rxq = NULL;
- }
- ipw_tx_queue_free(priv);
- release_firmware(raw);
-#ifdef CONFIG_PM
- fw_loaded = 0;
- raw = NULL;
-#endif
-
- return rc;
-}
-
-/*
- * DMA services
- *
- * Theory of operation
- *
- * A queue is a circular buffers with 'Read' and 'Write' pointers.
- * 2 empty entries always kept in the buffer to protect from overflow.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- * The IPW operates with six queues, one receive queue in the device's
- * sram, one transmit queue for sending commands to the device firmware,
- * and four transmit queues for data.
- *
- * The four transmit queues allow for performing quality of service (qos)
- * transmissions as per the 802.11 protocol. Currently Linux does not
- * provide a mechanism to the user for utilizing prioritized queues, so
- * we only utilize the first data transmit queue (queue1).
- */
-
-/*
- * Driver allocates buffers of this size for Rx
- */
-
-/*
- * ipw_rx_queue_space - Return number of free slots available in queue.
- */
-static int ipw_rx_queue_space(const struct ipw_rx_queue *q)
-{
- int s = q->read - q->write;
- if (s <= 0)
- s += RX_QUEUE_SIZE;
- /* keep some buffer to not confuse full and empty queue */
- s -= 2;
- if (s < 0)
- s = 0;
- return s;
-}
-
-static inline int ipw_tx_queue_space(const struct clx2_queue *q)
-{
- int s = q->last_used - q->first_empty;
- if (s <= 0)
- s += q->n_bd;
- s -= 2; /* keep some reserve to not confuse empty and full situations */
- if (s < 0)
- s = 0;
- return s;
-}
-
-static inline int ipw_queue_inc_wrap(int index, int n_bd)
-{
- return (++index == n_bd) ? 0 : index;
-}
-
-/*
- * Initialize common DMA queue structure
- *
- * @param q queue to init
- * @param count Number of BD's to allocate. Should be power of 2
- * @param read_register Address for 'read' register
- * (not offset within BAR, full address)
- * @param write_register Address for 'write' register
- * (not offset within BAR, full address)
- * @param base_register Address for 'base' register
- * (not offset within BAR, full address)
- * @param size Address for 'size' register
- * (not offset within BAR, full address)
- */
-static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q,
- int count, u32 read, u32 write, u32 base, u32 size)
-{
- q->n_bd = count;
-
- q->low_mark = q->n_bd / 4;
- if (q->low_mark < 4)
- q->low_mark = 4;
-
- q->high_mark = q->n_bd / 8;
- if (q->high_mark < 2)
- q->high_mark = 2;
-
- q->first_empty = q->last_used = 0;
- q->reg_r = read;
- q->reg_w = write;
-
- ipw_write32(priv, base, q->dma_addr);
- ipw_write32(priv, size, count);
- ipw_write32(priv, read, 0);
- ipw_write32(priv, write, 0);
-
- _ipw_read32(priv, 0x90);
-}
-
-static int ipw_queue_tx_init(struct ipw_priv *priv,
- struct clx2_tx_queue *q,
- int count, u32 read, u32 write, u32 base, u32 size)
-{
- struct pci_dev *dev = priv->pci_dev;
-
- q->txb = kmalloc_array(count, sizeof(q->txb[0]), GFP_KERNEL);
- if (!q->txb)
- return -ENOMEM;
-
- q->bd =
- dma_alloc_coherent(&dev->dev, sizeof(q->bd[0]) * count,
- &q->q.dma_addr, GFP_KERNEL);
- if (!q->bd) {
- IPW_ERROR("dma_alloc_coherent(%zd) failed\n",
- sizeof(q->bd[0]) * count);
- kfree(q->txb);
- q->txb = NULL;
- return -ENOMEM;
- }
-
- ipw_queue_init(priv, &q->q, count, read, write, base, size);
- return 0;
-}
-
-/*
- * Free one TFD, those at index [txq->q.last_used].
- * Do NOT advance any indexes
- *
- * @param dev
- * @param txq
- */
-static void ipw_queue_tx_free_tfd(struct ipw_priv *priv,
- struct clx2_tx_queue *txq)
-{
- struct tfd_frame *bd = &txq->bd[txq->q.last_used];
- struct pci_dev *dev = priv->pci_dev;
- int i;
-
- /* classify bd */
- if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE)
- /* nothing to cleanup after for host commands */
- return;
-
- /* sanity check */
- if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) {
- IPW_ERROR("Too many chunks: %i\n",
- le32_to_cpu(bd->u.data.num_chunks));
- /* @todo issue fatal error, it is quite serious situation */
- return;
- }
-
- /* unmap chunks if any */
- for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) {
- dma_unmap_single(&dev->dev,
- le32_to_cpu(bd->u.data.chunk_ptr[i]),
- le16_to_cpu(bd->u.data.chunk_len[i]),
- DMA_TO_DEVICE);
- if (txq->txb[txq->q.last_used]) {
- libipw_txb_free(txq->txb[txq->q.last_used]);
- txq->txb[txq->q.last_used] = NULL;
- }
- }
-}
-
-/*
- * Deallocate DMA queue.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- *
- * @param dev
- * @param q
- */
-static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq)
-{
- struct clx2_queue *q = &txq->q;
- struct pci_dev *dev = priv->pci_dev;
-
- if (q->n_bd == 0)
- return;
-
- /* first, empty all BD's */
- for (; q->first_empty != q->last_used;
- q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
- ipw_queue_tx_free_tfd(priv, txq);
- }
-
- /* free buffers belonging to queue itself */
- dma_free_coherent(&dev->dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd,
- q->dma_addr);
- kfree(txq->txb);
-
- /* 0 fill whole structure */
- memset(txq, 0, sizeof(*txq));
-}
-
-/*
- * Destroy all DMA queues and structures
- *
- * @param priv
- */
-static void ipw_tx_queue_free(struct ipw_priv *priv)
-{
- /* Tx CMD queue */
- ipw_queue_tx_free(priv, &priv->txq_cmd);
-
- /* Tx queues */
- ipw_queue_tx_free(priv, &priv->txq[0]);
- ipw_queue_tx_free(priv, &priv->txq[1]);
- ipw_queue_tx_free(priv, &priv->txq[2]);
- ipw_queue_tx_free(priv, &priv->txq[3]);
-}
-
-static void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
-{
- /* First 3 bytes are manufacturer */
- bssid[0] = priv->mac_addr[0];
- bssid[1] = priv->mac_addr[1];
- bssid[2] = priv->mac_addr[2];
-
- /* Last bytes are random */
- get_random_bytes(&bssid[3], ETH_ALEN - 3);
-
- bssid[0] &= 0xfe; /* clear multicast bit */
- bssid[0] |= 0x02; /* set local assignment bit (IEEE802) */
-}
-
-static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
-{
- struct ipw_station_entry entry;
- int i;
-
- for (i = 0; i < priv->num_stations; i++) {
- if (ether_addr_equal(priv->stations[i], bssid)) {
- /* Another node is active in network */
- priv->missed_adhoc_beacons = 0;
- if (!(priv->config & CFG_STATIC_CHANNEL))
- /* when other nodes drop out, we drop out */
- priv->config &= ~CFG_ADHOC_PERSIST;
-
- return i;
- }
- }
-
- if (i == MAX_STATIONS)
- return IPW_INVALID_STATION;
-
- IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid);
-
- entry.reserved = 0;
- entry.support_mode = 0;
- memcpy(entry.mac_addr, bssid, ETH_ALEN);
- memcpy(priv->stations[i], bssid, ETH_ALEN);
- ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry),
- &entry, sizeof(entry));
- priv->num_stations++;
-
- return i;
-}
-
-static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
-{
- int i;
-
- for (i = 0; i < priv->num_stations; i++)
- if (ether_addr_equal(priv->stations[i], bssid))
- return i;
-
- return IPW_INVALID_STATION;
-}
-
-static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
-{
- int err;
-
- if (priv->status & STATUS_ASSOCIATING) {
- IPW_DEBUG_ASSOC("Disassociating while associating.\n");
- schedule_work(&priv->disassociate);
- return;
- }
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
- return;
- }
-
- IPW_DEBUG_ASSOC("Disassociation attempt from %pM "
- "on channel %d.\n",
- priv->assoc_request.bssid,
- priv->assoc_request.channel);
-
- priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
- priv->status |= STATUS_DISASSOCIATING;
-
- if (quiet)
- priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
- else
- priv->assoc_request.assoc_type = HC_DISASSOCIATE;
-
- err = ipw_send_associate(priv, &priv->assoc_request);
- if (err) {
- IPW_DEBUG_HC("Attempt to send [dis]associate command "
- "failed.\n");
- return;
- }
-
-}
-
-static int ipw_disassociate(void *data)
-{
- struct ipw_priv *priv = data;
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
- return 0;
- ipw_send_disassociate(data, 0);
- netif_carrier_off(priv->net_dev);
- return 1;
-}
-
-static void ipw_bg_disassociate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, disassociate);
- mutex_lock(&priv->mutex);
- ipw_disassociate(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_system_config(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, system_config);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
- }
-#endif
-
- ipw_send_system_config(priv);
-}
-
-struct ipw_status_code {
- u16 status;
- const char *reason;
-};
-
-static const struct ipw_status_code ipw_status_codes[] = {
- {0x00, "Successful"},
- {0x01, "Unspecified failure"},
- {0x0A, "Cannot support all requested capabilities in the "
- "Capability information field"},
- {0x0B, "Reassociation denied due to inability to confirm that "
- "association exists"},
- {0x0C, "Association denied due to reason outside the scope of this "
- "standard"},
- {0x0D,
- "Responding station does not support the specified authentication "
- "algorithm"},
- {0x0E,
- "Received an Authentication frame with authentication sequence "
- "transaction sequence number out of expected sequence"},
- {0x0F, "Authentication rejected because of challenge failure"},
- {0x10, "Authentication rejected due to timeout waiting for next "
- "frame in sequence"},
- {0x11, "Association denied because AP is unable to handle additional "
- "associated stations"},
- {0x12,
- "Association denied due to requesting station not supporting all "
- "of the datarates in the BSSBasicServiceSet Parameter"},
- {0x13,
- "Association denied due to requesting station not supporting "
- "short preamble operation"},
- {0x14,
- "Association denied due to requesting station not supporting "
- "PBCC encoding"},
- {0x15,
- "Association denied due to requesting station not supporting "
- "channel agility"},
- {0x19,
- "Association denied due to requesting station not supporting "
- "short slot operation"},
- {0x1A,
- "Association denied due to requesting station not supporting "
- "DSSS-OFDM operation"},
- {0x28, "Invalid Information Element"},
- {0x29, "Group Cipher is not valid"},
- {0x2A, "Pairwise Cipher is not valid"},
- {0x2B, "AKMP is not valid"},
- {0x2C, "Unsupported RSN IE version"},
- {0x2D, "Invalid RSN IE Capabilities"},
- {0x2E, "Cipher suite is rejected per security policy"},
-};
-
-static const char *ipw_get_status_code(u16 status)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++)
- if (ipw_status_codes[i].status == (status & 0xff))
- return ipw_status_codes[i].reason;
- return "Unknown status value.";
-}
-
-static inline void average_init(struct average *avg)
-{
- memset(avg, 0, sizeof(*avg));
-}
-
-#define DEPTH_RSSI 8
-#define DEPTH_NOISE 16
-static s16 exponential_average(s16 prev_avg, s16 val, u8 depth)
-{
- return ((depth-1)*prev_avg + val)/depth;
-}
-
-static void average_add(struct average *avg, s16 val)
-{
- avg->sum -= avg->entries[avg->pos];
- avg->sum += val;
- avg->entries[avg->pos++] = val;
- if (unlikely(avg->pos == AVG_ENTRIES)) {
- avg->init = 1;
- avg->pos = 0;
- }
-}
-
-static s16 average_value(struct average *avg)
-{
- if (!unlikely(avg->init)) {
- if (avg->pos)
- return avg->sum / avg->pos;
- return 0;
- }
-
- return avg->sum / AVG_ENTRIES;
-}
-
-static void ipw_reset_stats(struct ipw_priv *priv)
-{
- u32 len = sizeof(u32);
-
- priv->quality = 0;
-
- average_init(&priv->average_missed_beacons);
- priv->exp_avg_rssi = -60;
- priv->exp_avg_noise = -85 + 0x100;
-
- priv->last_rate = 0;
- priv->last_missed_beacons = 0;
- priv->last_rx_packets = 0;
- priv->last_tx_packets = 0;
- priv->last_tx_failures = 0;
-
- /* Firmware managed, reset only when NIC is restarted, so we have to
- * normalize on the current value */
- ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC,
- &priv->last_rx_err, &len);
- ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE,
- &priv->last_tx_failures, &len);
-
- /* Driver managed, reset with each association */
- priv->missed_adhoc_beacons = 0;
- priv->missed_beacons = 0;
- priv->tx_packets = 0;
- priv->rx_packets = 0;
-
-}
-
-static u32 ipw_get_max_rate(struct ipw_priv *priv)
-{
- u32 i = 0x80000000;
- u32 mask = priv->rates_mask;
- /* If currently associated in B mode, restrict the maximum
- * rate match to B rates */
- if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- mask &= LIBIPW_CCK_RATES_MASK;
-
- /* TODO: Verify that the rate is supported by the current rates
- * list. */
-
- while (i && !(mask & i))
- i >>= 1;
- switch (i) {
- case LIBIPW_CCK_RATE_1MB_MASK:
- return 1000000;
- case LIBIPW_CCK_RATE_2MB_MASK:
- return 2000000;
- case LIBIPW_CCK_RATE_5MB_MASK:
- return 5500000;
- case LIBIPW_OFDM_RATE_6MB_MASK:
- return 6000000;
- case LIBIPW_OFDM_RATE_9MB_MASK:
- return 9000000;
- case LIBIPW_CCK_RATE_11MB_MASK:
- return 11000000;
- case LIBIPW_OFDM_RATE_12MB_MASK:
- return 12000000;
- case LIBIPW_OFDM_RATE_18MB_MASK:
- return 18000000;
- case LIBIPW_OFDM_RATE_24MB_MASK:
- return 24000000;
- case LIBIPW_OFDM_RATE_36MB_MASK:
- return 36000000;
- case LIBIPW_OFDM_RATE_48MB_MASK:
- return 48000000;
- case LIBIPW_OFDM_RATE_54MB_MASK:
- return 54000000;
- }
-
- if (priv->ieee->mode == IEEE_B)
- return 11000000;
- else
- return 54000000;
-}
-
-static u32 ipw_get_current_rate(struct ipw_priv *priv)
-{
- u32 rate, len = sizeof(rate);
- int err;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return 0;
-
- if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) {
- err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate,
- &len);
- if (err) {
- IPW_DEBUG_INFO("failed querying ordinals.\n");
- return 0;
- }
- } else
- return ipw_get_max_rate(priv);
-
- switch (rate) {
- case IPW_TX_RATE_1MB:
- return 1000000;
- case IPW_TX_RATE_2MB:
- return 2000000;
- case IPW_TX_RATE_5MB:
- return 5500000;
- case IPW_TX_RATE_6MB:
- return 6000000;
- case IPW_TX_RATE_9MB:
- return 9000000;
- case IPW_TX_RATE_11MB:
- return 11000000;
- case IPW_TX_RATE_12MB:
- return 12000000;
- case IPW_TX_RATE_18MB:
- return 18000000;
- case IPW_TX_RATE_24MB:
- return 24000000;
- case IPW_TX_RATE_36MB:
- return 36000000;
- case IPW_TX_RATE_48MB:
- return 48000000;
- case IPW_TX_RATE_54MB:
- return 54000000;
- }
-
- return 0;
-}
-
-#define IPW_STATS_INTERVAL (2 * HZ)
-static void ipw_gather_stats(struct ipw_priv *priv)
-{
- u32 rx_err, rx_err_delta, rx_packets_delta;
- u32 tx_failures, tx_failures_delta, tx_packets_delta;
- u32 missed_beacons_percent, missed_beacons_delta;
- u32 quality = 0;
- u32 len = sizeof(u32);
- s16 rssi;
- u32 beacon_quality, signal_quality, tx_quality, rx_quality,
- rate_quality;
- u32 max_rate;
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- priv->quality = 0;
- return;
- }
-
- /* Update the statistics */
- ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS,
- &priv->missed_beacons, &len);
- missed_beacons_delta = priv->missed_beacons - priv->last_missed_beacons;
- priv->last_missed_beacons = priv->missed_beacons;
- if (priv->assoc_request.beacon_interval) {
- missed_beacons_percent = missed_beacons_delta *
- (HZ * le16_to_cpu(priv->assoc_request.beacon_interval)) /
- (IPW_STATS_INTERVAL * 10);
- } else {
- missed_beacons_percent = 0;
- }
- average_add(&priv->average_missed_beacons, missed_beacons_percent);
-
- ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len);
- rx_err_delta = rx_err - priv->last_rx_err;
- priv->last_rx_err = rx_err;
-
- ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len);
- tx_failures_delta = tx_failures - priv->last_tx_failures;
- priv->last_tx_failures = tx_failures;
-
- rx_packets_delta = priv->rx_packets - priv->last_rx_packets;
- priv->last_rx_packets = priv->rx_packets;
-
- tx_packets_delta = priv->tx_packets - priv->last_tx_packets;
- priv->last_tx_packets = priv->tx_packets;
-
- /* Calculate quality based on the following:
- *
- * Missed beacon: 100% = 0, 0% = 70% missed
- * Rate: 60% = 1Mbs, 100% = Max
- * Rx and Tx errors represent a straight % of total Rx/Tx
- * RSSI: 100% = > -50, 0% = < -80
- * Rx errors: 100% = 0, 0% = 50% missed
- *
- * The lowest computed quality is used.
- *
- */
-#define BEACON_THRESHOLD 5
- beacon_quality = 100 - missed_beacons_percent;
- if (beacon_quality < BEACON_THRESHOLD)
- beacon_quality = 0;
- else
- beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 /
- (100 - BEACON_THRESHOLD);
- IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n",
- beacon_quality, missed_beacons_percent);
-
- priv->last_rate = ipw_get_current_rate(priv);
- max_rate = ipw_get_max_rate(priv);
- rate_quality = priv->last_rate * 40 / max_rate + 60;
- IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n",
- rate_quality, priv->last_rate / 1000000);
-
- if (rx_packets_delta > 100 && rx_packets_delta + rx_err_delta)
- rx_quality = 100 - (rx_err_delta * 100) /
- (rx_packets_delta + rx_err_delta);
- else
- rx_quality = 100;
- IPW_DEBUG_STATS("Rx quality : %3d%% (%u errors, %u packets)\n",
- rx_quality, rx_err_delta, rx_packets_delta);
-
- if (tx_packets_delta > 100 && tx_packets_delta + tx_failures_delta)
- tx_quality = 100 - (tx_failures_delta * 100) /
- (tx_packets_delta + tx_failures_delta);
- else
- tx_quality = 100;
- IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n",
- tx_quality, tx_failures_delta, tx_packets_delta);
-
- rssi = priv->exp_avg_rssi;
- signal_quality =
- (100 *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) -
- (priv->ieee->perfect_rssi - rssi) *
- (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) +
- 62 * (priv->ieee->perfect_rssi - rssi))) /
- ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi));
- if (signal_quality > 100)
- signal_quality = 100;
- else if (signal_quality < 1)
- signal_quality = 0;
-
- IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
- signal_quality, rssi);
-
- quality = min(rx_quality, signal_quality);
- quality = min(tx_quality, quality);
- quality = min(rate_quality, quality);
- quality = min(beacon_quality, quality);
- if (quality == beacon_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n",
- quality);
- if (quality == rate_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to rate quality.\n",
- quality);
- if (quality == tx_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to Tx quality.\n",
- quality);
- if (quality == rx_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to Rx quality.\n",
- quality);
- if (quality == signal_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to signal quality.\n",
- quality);
-
- priv->quality = quality;
-
- schedule_delayed_work(&priv->gather_stats, IPW_STATS_INTERVAL);
-}
-
-static void ipw_bg_gather_stats(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, gather_stats.work);
- mutex_lock(&priv->mutex);
- ipw_gather_stats(priv);
- mutex_unlock(&priv->mutex);
-}
-
-/* Missed beacon behavior:
- * 1st missed -> roaming_threshold, just wait, don't do any scan/roam.
- * roaming_threshold -> disassociate_threshold, scan and roam for better signal.
- * Above disassociate threshold, give up and stop scanning.
- * Roaming is disabled if disassociate_threshold <= roaming_threshold */
-static void ipw_handle_missed_beacon(struct ipw_priv *priv,
- int missed_count)
-{
- priv->notif_missed_beacons = missed_count;
-
- if (missed_count > priv->disassociate_threshold &&
- priv->status & STATUS_ASSOCIATED) {
- /* If associated and we've hit the missed
- * beacon threshold, disassociate, turn
- * off roaming, and abort any active scans */
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE | IPW_DL_ASSOC,
- "Missed beacon: %d - disassociate\n", missed_count);
- priv->status &= ~STATUS_ROAMING;
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE,
- "Aborting scan with missed beacon.\n");
- schedule_work(&priv->abort_scan);
- }
-
- schedule_work(&priv->disassociate);
- return;
- }
-
- if (priv->status & STATUS_ROAMING) {
- /* If we are currently roaming, then just
- * print a debug statement... */
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "Missed beacon: %d - roam in progress\n",
- missed_count);
- return;
- }
-
- if (roaming &&
- (missed_count > priv->roaming_threshold &&
- missed_count <= priv->disassociate_threshold)) {
- /* If we are not already roaming, set the ROAM
- * bit in the status and kick off a scan.
- * This can happen several times before we reach
- * disassociate_threshold. */
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "Missed beacon: %d - initiate "
- "roaming\n", missed_count);
- if (!(priv->status & STATUS_ROAMING)) {
- priv->status |= STATUS_ROAMING;
- if (!(priv->status & STATUS_SCANNING))
- schedule_delayed_work(&priv->request_scan, 0);
- }
- return;
- }
-
- if (priv->status & STATUS_SCANNING &&
- missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) {
- /* Stop scan to keep fw from getting
- * stuck (only if we aren't roaming --
- * otherwise we'll never scan more than 2 or 3
- * channels..) */
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE,
- "Aborting scan with missed beacon.\n");
- schedule_work(&priv->abort_scan);
- }
-
- IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
-}
-
-static void ipw_scan_event(struct work_struct *work)
-{
- union iwreq_data wrqu;
-
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, scan_event.work);
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static void handle_scan_event(struct ipw_priv *priv)
-{
- /* Only userspace-requested scan completion events go out immediately */
- if (!priv->user_requested_scan) {
- schedule_delayed_work(&priv->scan_event,
- round_jiffies_relative(msecs_to_jiffies(4000)));
- } else {
- priv->user_requested_scan = 0;
- mod_delayed_work(system_wq, &priv->scan_event, 0);
- }
-}
-
-/*
- * Handle host notification packet.
- * Called from interrupt routine
- */
-static void ipw_rx_notification(struct ipw_priv *priv,
- struct ipw_rx_notification *notif)
-{
- u16 size = le16_to_cpu(notif->size);
-
- IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
-
- switch (notif->subtype) {
- case HOST_NOTIFICATION_STATUS_ASSOCIATED:{
- struct notif_association *assoc = &notif->u.assoc;
-
- switch (assoc->state) {
- case CMAS_ASSOCIATED:{
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "associated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_INFRA:
- memcpy(priv->ieee->bssid,
- priv->bssid, ETH_ALEN);
- break;
-
- case IW_MODE_ADHOC:
- memcpy(priv->ieee->bssid,
- priv->bssid, ETH_ALEN);
-
- /* clear out the station table */
- priv->num_stations = 0;
-
- IPW_DEBUG_ASSOC
- ("queueing adhoc check\n");
- schedule_delayed_work(
- &priv->adhoc_check,
- le16_to_cpu(priv->
- assoc_request.
- beacon_interval));
- break;
- }
-
- priv->status &= ~STATUS_ASSOCIATING;
- priv->status |= STATUS_ASSOCIATED;
- schedule_work(&priv->system_config);
-
-#ifdef CONFIG_IPW2200_QOS
-#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
- le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control))
- if ((priv->status & STATUS_AUTH) &&
- (IPW_GET_PACKET_STYPE(&notif->u.raw)
- == IEEE80211_STYPE_ASSOC_RESP)) {
- if ((sizeof
- (struct
- libipw_assoc_response)
- <= size)
- && (size <= 2314)) {
- struct
- libipw_rx_stats
- stats = {
- .len = size - 1,
- };
-
- IPW_DEBUG_QOS
- ("QoS Associate "
- "size %d\n", size);
- libipw_rx_mgt(priv->
- ieee,
- (struct
- libipw_hdr_4addr
- *)
- &notif->u.raw, &stats);
- }
- }
-#endif
-
- schedule_work(&priv->link_up);
-
- break;
- }
-
- case CMAS_AUTHENTICATED:{
- if (priv->
- status & (STATUS_ASSOCIATED |
- STATUS_AUTH)) {
- struct notif_authenticate *auth
- = &notif->u.auth;
- IPW_DEBUG(IPW_DL_NOTIF |
- IPW_DL_STATE |
- IPW_DL_ASSOC,
- "deauthenticated: '%*pE' %pM: (0x%04X) - %s\n",
- priv->essid_len,
- priv->essid,
- priv->bssid,
- le16_to_cpu(auth->status),
- ipw_get_status_code
- (le16_to_cpu
- (auth->status)));
-
- priv->status &=
- ~(STATUS_ASSOCIATING |
- STATUS_AUTH |
- STATUS_ASSOCIATED);
-
- schedule_work(&priv->link_down);
- break;
- }
-
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "authenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
- break;
- }
-
- case CMAS_INIT:{
- if (priv->status & STATUS_AUTH) {
- struct
- libipw_assoc_response
- *resp;
- resp =
- (struct
- libipw_assoc_response
- *)&notif->u.raw;
- IPW_DEBUG(IPW_DL_NOTIF |
- IPW_DL_STATE |
- IPW_DL_ASSOC,
- "association failed (0x%04X): %s\n",
- le16_to_cpu(resp->status),
- ipw_get_status_code
- (le16_to_cpu
- (resp->status)));
- }
-
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "disassociated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &=
- ~(STATUS_DISASSOCIATING |
- STATUS_ASSOCIATING |
- STATUS_ASSOCIATED | STATUS_AUTH);
- if (priv->assoc_network
- && (priv->assoc_network->
- capability &
- WLAN_CAPABILITY_IBSS))
- ipw_remove_current_network
- (priv);
-
- schedule_work(&priv->link_down);
-
- break;
- }
-
- case CMAS_RX_ASSOC_RESP:
- break;
-
- default:
- IPW_ERROR("assoc: unknown (%d)\n",
- assoc->state);
- break;
- }
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{
- struct notif_authenticate *auth = &notif->u.auth;
- switch (auth->state) {
- case CMAS_AUTHENTICATED:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "authenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
- priv->status |= STATUS_AUTH;
- break;
-
- case CMAS_INIT:
- if (priv->status & STATUS_AUTH) {
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "authentication failed (0x%04X): %s\n",
- le16_to_cpu(auth->status),
- ipw_get_status_code(le16_to_cpu
- (auth->
- status)));
- }
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "deauthenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &= ~(STATUS_ASSOCIATING |
- STATUS_AUTH |
- STATUS_ASSOCIATED);
-
- schedule_work(&priv->link_down);
- break;
-
- case CMAS_TX_AUTH_SEQ_1:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1\n");
- break;
- case CMAS_RX_AUTH_SEQ_2:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_2\n");
- break;
- case CMAS_AUTH_SEQ_1_PASS:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n");
- break;
- case CMAS_AUTH_SEQ_1_FAIL:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n");
- break;
- case CMAS_TX_AUTH_SEQ_3:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_3\n");
- break;
- case CMAS_RX_AUTH_SEQ_4:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n");
- break;
- case CMAS_AUTH_SEQ_2_PASS:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n");
- break;
- case CMAS_AUTH_SEQ_2_FAIL:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n");
- break;
- case CMAS_TX_ASSOC:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "TX_ASSOC\n");
- break;
- case CMAS_RX_ASSOC_RESP:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
-
- break;
- case CMAS_ASSOCIATED:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "ASSOCIATED\n");
- break;
- default:
- IPW_DEBUG_NOTIF("auth: failure - %d\n",
- auth->state);
- break;
- }
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{
- struct notif_channel_result *x =
- &notif->u.channel_result;
-
- if (size == sizeof(*x)) {
- IPW_DEBUG_SCAN("Scan result for channel %d\n",
- x->channel_num);
- } else {
- IPW_DEBUG_SCAN("Scan result of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{
- struct notif_scan_complete *x = &notif->u.scan_complete;
- if (size == sizeof(*x)) {
- IPW_DEBUG_SCAN
- ("Scan completed: type %d, %d channels, "
- "%d status\n", x->scan_type,
- x->num_channels, x->status);
- } else {
- IPW_ERROR("Scan completed of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
-
- priv->status &=
- ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
-
- wake_up_interruptible(&priv->wait_state);
- cancel_delayed_work(&priv->scan_check);
-
- if (priv->status & STATUS_EXIT_PENDING)
- break;
-
- priv->ieee->scans++;
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- priv->status |= STATUS_SCAN_FORCED;
- schedule_delayed_work(&priv->request_scan, 0);
- break;
- }
- priv->status &= ~STATUS_SCAN_FORCED;
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Do queued direct scans first */
- if (priv->status & STATUS_DIRECT_SCAN_PENDING)
- schedule_delayed_work(&priv->request_direct_scan, 0);
-
- if (!(priv->status & (STATUS_ASSOCIATED |
- STATUS_ASSOCIATING |
- STATUS_ROAMING |
- STATUS_DISASSOCIATING)))
- schedule_work(&priv->associate);
- else if (priv->status & STATUS_ROAMING) {
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
- /* If a scan completed and we are in roam mode, then
- * the scan that completed was the one requested as a
- * result of entering roam... so, schedule the
- * roam work */
- schedule_work(&priv->roam);
- else
- /* Don't schedule if we aborted the scan */
- priv->status &= ~STATUS_ROAMING;
- } else if (priv->status & STATUS_SCAN_PENDING)
- schedule_delayed_work(&priv->request_scan, 0);
- else if (priv->config & CFG_BACKGROUND_SCAN
- && priv->status & STATUS_ASSOCIATED)
- schedule_delayed_work(&priv->request_scan,
- round_jiffies_relative(HZ));
-
- /* Send an empty event to user space.
- * We don't send the received data on the event because
- * it would require us to do complex transcoding, and
- * we want to minimise the work done in the irq handler
- * Use a request to extract the data.
- * Also, we generate this even for any scan, regardless
- * on how the scan was initiated. User space can just
- * sync on periodic scan to get fresh data...
- * Jean II */
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
- handle_scan_event(priv);
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
- struct notif_frag_length *x = &notif->u.frag_len;
-
- if (size == sizeof(*x))
- IPW_ERROR("Frag length: %d\n",
- le16_to_cpu(x->frag_length));
- else
- IPW_ERROR("Frag length of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
- struct notif_link_deterioration *x =
- &notif->u.link_deterioration;
-
- if (size == sizeof(*x)) {
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "link deterioration: type %d, cnt %d\n",
- x->silence_notification_type,
- x->silence_count);
- memcpy(&priv->last_link_deterioration, x,
- sizeof(*x));
- } else {
- IPW_ERROR("Link Deterioration of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
- break;
- }
-
- case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
- IPW_ERROR("Dino config\n");
- if (priv->hcmd
- && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG)
- IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_BEACON_STATE:{
- struct notif_beacon_state *x = &notif->u.beacon_state;
- if (size != sizeof(*x)) {
- IPW_ERROR
- ("Beacon state of wrong size %d (should "
- "be %zd)\n", size, sizeof(*x));
- break;
- }
-
- if (le32_to_cpu(x->state) ==
- HOST_NOTIFICATION_STATUS_BEACON_MISSING)
- ipw_handle_missed_beacon(priv,
- le32_to_cpu(x->
- number));
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{
- struct notif_tgi_tx_key *x = &notif->u.tgi_tx_key;
- if (size == sizeof(*x)) {
- IPW_ERROR("TGi Tx Key: state 0x%02x sec type "
- "0x%02x station %d\n",
- x->key_state, x->security_type,
- x->station_index);
- break;
- }
-
- IPW_ERROR
- ("TGi Tx Key of wrong size %d (should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{
- struct notif_calibration *x = &notif->u.calibration;
-
- if (size == sizeof(*x)) {
- memcpy(&priv->calib, x, sizeof(*x));
- IPW_DEBUG_INFO("TODO: Calibration\n");
- break;
- }
-
- IPW_ERROR
- ("Calibration of wrong size %d (should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_NOISE_STATS:{
- if (size == sizeof(u32)) {
- priv->exp_avg_noise =
- exponential_average(priv->exp_avg_noise,
- (u8) (le32_to_cpu(notif->u.noise.value) & 0xff),
- DEPTH_NOISE);
- break;
- }
-
- IPW_ERROR
- ("Noise stat is wrong size %d (should be %zd)\n",
- size, sizeof(u32));
- break;
- }
-
- default:
- IPW_DEBUG_NOTIF("Unknown notification: "
- "subtype=%d,flags=0x%2x,size=%d\n",
- notif->subtype, notif->flags, size);
- }
-}
-
-/*
- * Destroys all DMA structures and initialise them again
- *
- * @param priv
- * @return error code
- */
-static int ipw_queue_reset(struct ipw_priv *priv)
-{
- int rc = 0;
- /* @todo customize queue sizes */
- int nTx = 64, nTxCmd = 8;
- ipw_tx_queue_free(priv);
- /* Tx CMD queue */
- rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd,
- IPW_TX_CMD_QUEUE_READ_INDEX,
- IPW_TX_CMD_QUEUE_WRITE_INDEX,
- IPW_TX_CMD_QUEUE_BD_BASE,
- IPW_TX_CMD_QUEUE_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx Cmd queue init failed\n");
- goto error;
- }
- /* Tx queue(s) */
- rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx,
- IPW_TX_QUEUE_0_READ_INDEX,
- IPW_TX_QUEUE_0_WRITE_INDEX,
- IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 0 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx,
- IPW_TX_QUEUE_1_READ_INDEX,
- IPW_TX_QUEUE_1_WRITE_INDEX,
- IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 1 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx,
- IPW_TX_QUEUE_2_READ_INDEX,
- IPW_TX_QUEUE_2_WRITE_INDEX,
- IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 2 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx,
- IPW_TX_QUEUE_3_READ_INDEX,
- IPW_TX_QUEUE_3_WRITE_INDEX,
- IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 3 queue init failed\n");
- goto error;
- }
- /* statistics */
- priv->rx_bufs_min = 0;
- priv->rx_pend_max = 0;
- return rc;
-
- error:
- ipw_tx_queue_free(priv);
- return rc;
-}
-
-/*
- * Reclaim Tx queue entries no more used by NIC.
- *
- * When FW advances 'R' index, all entries between old and
- * new 'R' index need to be reclaimed. As result, some free space
- * forms. If there is enough free space (> low mark), wake Tx queue.
- *
- * @note Need to protect against garbage in 'R' index
- * @param priv
- * @param txq
- * @param qindex
- * @return Number of used entries remains in the queue
- */
-static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
- struct clx2_tx_queue *txq, int qindex)
-{
- u32 hw_tail;
- int used;
- struct clx2_queue *q = &txq->q;
-
- hw_tail = ipw_read32(priv, q->reg_r);
- if (hw_tail >= q->n_bd) {
- IPW_ERROR
- ("Read index for DMA queue (%d) is out of range [0-%d)\n",
- hw_tail, q->n_bd);
- goto done;
- }
- for (; q->last_used != hw_tail;
- q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
- ipw_queue_tx_free_tfd(priv, txq);
- priv->tx_packets++;
- }
- done:
- if ((ipw_tx_queue_space(q) > q->low_mark) &&
- (qindex >= 0))
- netif_wake_queue(priv->net_dev);
- used = q->first_empty - q->last_used;
- if (used < 0)
- used += q->n_bd;
-
- return used;
-}
-
-static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, const void *buf,
- int len, int sync)
-{
- struct clx2_tx_queue *txq = &priv->txq_cmd;
- struct clx2_queue *q = &txq->q;
- struct tfd_frame *tfd;
-
- if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) {
- IPW_ERROR("No space for Tx\n");
- return -EBUSY;
- }
-
- tfd = &txq->bd[q->first_empty];
- txq->txb[q->first_empty] = NULL;
-
- memset(tfd, 0, sizeof(*tfd));
- tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE;
- tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
- priv->hcmd_seq++;
- tfd->u.cmd.index = hcmd;
- tfd->u.cmd.length = len;
- memcpy(tfd->u.cmd.payload, buf, len);
- q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
- ipw_write32(priv, q->reg_w, q->first_empty);
- _ipw_read32(priv, 0x90);
-
- return 0;
-}
-
-/*
- * Rx theory of operation
- *
- * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
- * 0 to 31
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer it will advance the READ index
- * and fire the RX interrupt. The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free. When
- * ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- * to replensish the ipw->rxq->rx_free.
- * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the
- * ipw->rxq is replenished and the READ INDEX is updated (updating the
- * 'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- * detached from the ipw->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free
- * list. If there are no allocated buffers in ipw->rxq->rx_free, the READ
- * INDEX is not incremented and ipw->status(RX_STALLED) is set. If there
- * were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * ipw_rx_queue_alloc() Allocates rx_free
- * ipw_rx_queue_replenish() Replenishes rx_free list from rx_used, and calls
- * ipw_rx_queue_restock
- * ipw_rx_queue_restock() Moves available buffers from rx_free into Rx
- * queue, updates firmware pointers, and updates
- * the WRITE index. If insufficient rx_free buffers
- * are available, schedules ipw_rx_queue_replenish
- *
- * -- enable interrupts --
- * ISR - ipw_rx() Detach ipw_rx_mem_buffers from pool up to the
- * READ INDEX, detaching the SKB from the pool.
- * Moves the packet buffer from queue to rx_used.
- * Calls ipw_rx_queue_restock to refill any empty
- * slots.
- * ...
- *
- */
-
-/*
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static void ipw_rx_queue_restock(struct ipw_priv *priv)
-{
- struct ipw_rx_queue *rxq = priv->rxq;
- struct list_head *element;
- struct ipw_rx_mem_buffer *rxb;
- unsigned long flags;
- int write;
-
- spin_lock_irqsave(&rxq->lock, flags);
- write = rxq->write;
- while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
- element = rxq->rx_free.next;
- rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
- list_del(element);
-
- ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
- rxb->dma_addr);
- rxq->queue[rxq->write] = rxb;
- rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
- rxq->free_count--;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- /* If the pre-allocated buffer pool is dropping low, schedule to
- * refill it */
- if (rxq->free_count <= RX_LOW_WATERMARK)
- schedule_work(&priv->rx_replenish);
-
- /* If we've added more space for the firmware to place data, tell it */
- if (write != rxq->write)
- ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write);
-}
-
-/*
- * Move all used packet from rx_used to rx_free, allocating a new SKB for each.
- * Also restock the Rx queue via ipw_rx_queue_restock.
- *
- * This is called as a scheduled work item (except for during initialization)
- */
-static void ipw_rx_queue_replenish(void *data)
-{
- struct ipw_priv *priv = data;
- struct ipw_rx_queue *rxq = priv->rxq;
- struct list_head *element;
- struct ipw_rx_mem_buffer *rxb;
- unsigned long flags;
-
- spin_lock_irqsave(&rxq->lock, flags);
- while (!list_empty(&rxq->rx_used)) {
- element = rxq->rx_used.next;
- rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
- rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC);
- if (!rxb->skb) {
- printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n",
- priv->net_dev->name);
- /* We don't reschedule replenish work here -- we will
- * call the restock method and if it still needs
- * more buffers it will schedule replenish */
- break;
- }
- list_del(element);
-
- rxb->dma_addr =
- dma_map_single(&priv->pci_dev->dev, rxb->skb->data,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
-
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- ipw_rx_queue_restock(priv);
-}
-
-static void ipw_bg_rx_queue_replenish(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, rx_replenish);
- mutex_lock(&priv->mutex);
- ipw_rx_queue_replenish(priv);
- mutex_unlock(&priv->mutex);
-}
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq)
-{
- int i;
-
- if (!rxq)
- return;
-
- for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- dma_unmap_single(&priv->pci_dev->dev,
- rxq->pool[i].dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
- }
- }
-
- kfree(rxq);
-}
-
-static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
-{
- struct ipw_rx_queue *rxq;
- int i;
-
- rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
- if (unlikely(!rxq)) {
- IPW_ERROR("memory allocation failed\n");
- return NULL;
- }
- spin_lock_init(&rxq->lock);
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
-
- return rxq;
-}
-
-static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
-{
- rate &= ~LIBIPW_BASIC_RATE_MASK;
- if (ieee_mode == IEEE_A) {
- switch (rate) {
- case LIBIPW_OFDM_RATE_6MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ?
- 1 : 0;
- case LIBIPW_OFDM_RATE_9MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ?
- 1 : 0;
- case LIBIPW_OFDM_RATE_12MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_18MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_24MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_36MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_48MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_54MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
- default:
- return 0;
- }
- }
-
- /* B and G mixed */
- switch (rate) {
- case LIBIPW_CCK_RATE_1MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_1MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_2MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_2MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_5MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_5MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_11MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_11MB_MASK ? 1 : 0;
- }
-
- /* If we are limited to B modulations, bail at this point */
- if (ieee_mode == IEEE_B)
- return 0;
-
- /* G */
- switch (rate) {
- case LIBIPW_OFDM_RATE_6MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_9MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_12MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_18MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_24MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_36MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_48MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_54MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
- }
-
- return 0;
-}
-
-static int ipw_compatible_rates(struct ipw_priv *priv,
- const struct libipw_network *network,
- struct ipw_supported_rates *rates)
-{
- int num_rates, i;
-
- memset(rates, 0, sizeof(*rates));
- num_rates = min(network->rates_len, (u8) IPW_MAX_RATES);
- rates->num_rates = 0;
- for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask(priv, network->mode,
- network->rates[i])) {
-
- if (network->rates[i] & LIBIPW_BASIC_RATE_MASK) {
- IPW_DEBUG_SCAN("Adding masked mandatory "
- "rate %02X\n",
- network->rates[i]);
- rates->supported_rates[rates->num_rates++] =
- network->rates[i];
- continue;
- }
-
- IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
- network->rates[i], priv->rates_mask);
- continue;
- }
-
- rates->supported_rates[rates->num_rates++] = network->rates[i];
- }
-
- num_rates = min(network->rates_ex_len,
- (u8) (IPW_MAX_RATES - num_rates));
- for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask(priv, network->mode,
- network->rates_ex[i])) {
- if (network->rates_ex[i] & LIBIPW_BASIC_RATE_MASK) {
- IPW_DEBUG_SCAN("Adding masked mandatory "
- "rate %02X\n",
- network->rates_ex[i]);
- rates->supported_rates[rates->num_rates++] =
- network->rates[i];
- continue;
- }
-
- IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
- network->rates_ex[i], priv->rates_mask);
- continue;
- }
-
- rates->supported_rates[rates->num_rates++] =
- network->rates_ex[i];
- }
-
- return 1;
-}
-
-static void ipw_copy_rates(struct ipw_supported_rates *dest,
- const struct ipw_supported_rates *src)
-{
- u8 i;
- for (i = 0; i < src->num_rates; i++)
- dest->supported_rates[i] = src->supported_rates[i];
- dest->num_rates = src->num_rates;
-}
-
-/* TODO: Look at sniffed packets in the air to determine if the basic rate
- * mask should ever be used -- right now all callers to add the scan rates are
- * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */
-static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates,
- u8 modulation, u32 rate_mask)
-{
- u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
- LIBIPW_BASIC_RATE_MASK : 0;
-
- if (rate_mask & LIBIPW_CCK_RATE_1MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_1MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_2MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_2MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_5MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_CCK_RATE_5MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_11MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_CCK_RATE_11MB;
-}
-
-static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates,
- u8 modulation, u32 rate_mask)
-{
- u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
- LIBIPW_BASIC_RATE_MASK : 0;
-
- if (rate_mask & LIBIPW_OFDM_RATE_6MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_6MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_9MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_9MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_12MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_12MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_18MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_18MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_24MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_24MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_36MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_36MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_48MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_48MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_54MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_54MB;
-}
-
-struct ipw_network_match {
- struct libipw_network *network;
- struct ipw_supported_rates rates;
-};
-
-static int ipw_find_adhoc_network(struct ipw_priv *priv,
- struct ipw_network_match *match,
- struct libipw_network *network,
- int roaming)
-{
- struct ipw_supported_rates rates;
-
- /* Verify that this network's capability is compatible with the
- * current mode (AdHoc or Infrastructure) */
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
- !(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (unlikely(roaming)) {
- /* If we are roaming, then ensure check if this is a valid
- * network to try and roam to */
- if ((network->ssid_len != match->network->ssid_len) ||
- memcmp(network->ssid, match->network->ssid,
- network->ssid_len)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
- } else {
- /* If an ESSID has been configured then compare the broadcast
- * ESSID to ours */
- if ((priv->config & CFG_STATIC_ESSID) &&
- ((network->ssid_len != priv->essid_len) ||
- memcmp(network->ssid, priv->essid,
- min(network->ssid_len, priv->essid_len)))) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->essid_len,
- priv->essid);
- return 0;
- }
- }
-
- /* If the old network rate is better than this one, don't bother
- * testing everything else. */
-
- if (network->time_stamp[0] < match->network->time_stamp[0]) {
- IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
- match->network->ssid_len, match->network->ssid);
- return 0;
- } else if (network->time_stamp[1] < match->network->time_stamp[1]) {
- IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
- match->network->ssid_len, match->network->ssid);
- return 0;
- }
-
- /* Now go through and see if the requested network is valid... */
- if (priv->ieee->scan_age != 0 &&
- time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of age: %ums.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_scanned));
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_CHANNEL) &&
- (network->channel != priv->channel)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- network->channel, priv->channel);
- return 0;
- }
-
- /* Verify privacy compatibility */
- if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
- ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- priv->
- capability & CAP_PRIVACY_ON ? "on" : "off",
- network->
- capability & WLAN_CAPABILITY_PRIVACY ? "on" :
- "off");
- return 0;
- }
-
- if (ether_addr_equal(network->bssid, priv->bssid)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of the same BSSID match: %pM.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->bssid);
- return 0;
- }
-
- /* Filter out any incompatible freq / mode combinations */
- if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Ensure that the rates supported by the driver are compatible with
- * this AP, including verification of basic rates (mandatory) */
- if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (rates.num_rates == 0) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* TODO: Perform any further minimal comparititive tests. We do not
- * want to put too much policy logic here; intelligent scan selection
- * should occur within a generic IEEE 802.11 user space tool. */
-
- /* Set up 'new' AP to this network */
- ipw_copy_rates(&match->rates, &rates);
- match->network = network;
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' is a viable match.\n",
- network->ssid_len, network->ssid, network->bssid);
-
- return 1;
-}
-
-static void ipw_merge_adhoc_network(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, merge_networks);
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = priv->assoc_network
- };
-
- if ((priv->status & STATUS_ASSOCIATED) &&
- (priv->ieee->iw_mode == IW_MODE_ADHOC)) {
- /* First pass through ROAM process -- look for a better
- * network */
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list) {
- if (network != priv->assoc_network)
- ipw_find_adhoc_network(priv, &match, network,
- 1);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (match.network == priv->assoc_network) {
- IPW_DEBUG_MERGE("No better ADHOC in this network to "
- "merge to.\n");
- return;
- }
-
- mutex_lock(&priv->mutex);
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- IPW_DEBUG_MERGE("remove network %*pE\n",
- priv->essid_len, priv->essid);
- ipw_remove_current_network(priv);
- }
-
- ipw_disassociate(priv);
- priv->assoc_network = match.network;
- mutex_unlock(&priv->mutex);
- return;
- }
-}
-
-static int ipw_best_network(struct ipw_priv *priv,
- struct ipw_network_match *match,
- struct libipw_network *network, int roaming)
-{
- struct ipw_supported_rates rates;
-
- /* Verify that this network's capability is compatible with the
- * current mode (AdHoc or Infrastructure) */
- if ((priv->ieee->iw_mode == IW_MODE_INFRA &&
- !(network->capability & WLAN_CAPABILITY_ESS)) ||
- (priv->ieee->iw_mode == IW_MODE_ADHOC &&
- !(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (unlikely(roaming)) {
- /* If we are roaming, then ensure check if this is a valid
- * network to try and roam to */
- if ((network->ssid_len != match->network->ssid_len) ||
- memcmp(network->ssid, match->network->ssid,
- network->ssid_len)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
- } else {
- /* If an ESSID has been configured then compare the broadcast
- * ESSID to ours */
- if ((priv->config & CFG_STATIC_ESSID) &&
- ((network->ssid_len != priv->essid_len) ||
- memcmp(network->ssid, priv->essid,
- min(network->ssid_len, priv->essid_len)))) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->essid_len,
- priv->essid);
- return 0;
- }
- }
-
- /* If the old network rate is better than this one, don't bother
- * testing everything else. */
- if (match->network && match->network->stats.rssi > network->stats.rssi) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because '%*pE (%pM)' has a stronger signal.\n",
- network->ssid_len, network->ssid,
- network->bssid, match->network->ssid_len,
- match->network->ssid, match->network->bssid);
- return 0;
- }
-
- /* If this network has already had an association attempt within the
- * last 3 seconds, do not try and associate again... */
- if (network->last_associate &&
- time_after(network->last_associate + (HZ * 3UL), jiffies)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of storming (%ums since last assoc attempt).\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_associate));
- return 0;
- }
-
- /* Now go through and see if the requested network is valid... */
- if (priv->ieee->scan_age != 0 &&
- time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of age: %ums.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_scanned));
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_CHANNEL) &&
- (network->channel != priv->channel)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- network->channel, priv->channel);
- return 0;
- }
-
- /* Verify privacy compatibility */
- if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
- ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- priv->capability & CAP_PRIVACY_ON ? "on" :
- "off",
- network->capability &
- WLAN_CAPABILITY_PRIVACY ? "on" : "off");
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_BSSID) &&
- !ether_addr_equal(network->bssid, priv->bssid)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of BSSID mismatch: %pM.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->bssid);
- return 0;
- }
-
- /* Filter out any incompatible freq / mode combinations */
- if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Filter out invalid channel in current GEO */
- if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid channel in current GEO\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Ensure that the rates supported by the driver are compatible with
- * this AP, including verification of basic rates (mandatory) */
- if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (rates.num_rates == 0) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* TODO: Perform any further minimal comparititive tests. We do not
- * want to put too much policy logic here; intelligent scan selection
- * should occur within a generic IEEE 802.11 user space tool. */
-
- /* Set up 'new' AP to this network */
- ipw_copy_rates(&match->rates, &rates);
- match->network = network;
-
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' is a viable match.\n",
- network->ssid_len, network->ssid, network->bssid);
-
- return 1;
-}
-
-static void ipw_adhoc_create(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int i;
-
- /*
- * For the purposes of scanning, we can set our wireless mode
- * to trigger scans across combinations of bands, but when it
- * comes to creating a new ad-hoc network, we have tell the FW
- * exactly which band to use.
- *
- * We also have the possibility of an invalid channel for the
- * chossen band. Attempting to create a new ad-hoc network
- * with an invalid channel for wireless mode will trigger a
- * FW fatal error.
- *
- */
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- network->mode = IEEE_A;
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_WARNING("Overriding invalid channel\n");
- priv->channel = geo->a[0].channel;
- }
- break;
-
- case LIBIPW_24GHZ_BAND:
- if (priv->ieee->mode & IEEE_G)
- network->mode = IEEE_G;
- else
- network->mode = IEEE_B;
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_WARNING("Overriding invalid channel\n");
- priv->channel = geo->bg[0].channel;
- }
- break;
-
- default:
- IPW_WARNING("Overriding invalid channel\n");
- if (priv->ieee->mode & IEEE_A) {
- network->mode = IEEE_A;
- priv->channel = geo->a[0].channel;
- } else if (priv->ieee->mode & IEEE_G) {
- network->mode = IEEE_G;
- priv->channel = geo->bg[0].channel;
- } else {
- network->mode = IEEE_B;
- priv->channel = geo->bg[0].channel;
- }
- break;
- }
-
- network->channel = priv->channel;
- priv->config |= CFG_ADHOC_PERSIST;
- ipw_create_bssid(priv, network->bssid);
- network->ssid_len = priv->essid_len;
- memcpy(network->ssid, priv->essid, priv->essid_len);
- memset(&network->stats, 0, sizeof(network->stats));
- network->capability = WLAN_CAPABILITY_IBSS;
- if (!(priv->config & CFG_PREAMBLE_LONG))
- network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
- if (priv->capability & CAP_PRIVACY_ON)
- network->capability |= WLAN_CAPABILITY_PRIVACY;
- network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH);
- memcpy(network->rates, priv->rates.supported_rates, network->rates_len);
- network->rates_ex_len = priv->rates.num_rates - network->rates_len;
- memcpy(network->rates_ex,
- &priv->rates.supported_rates[network->rates_len],
- network->rates_ex_len);
- network->last_scanned = 0;
- network->flags = 0;
- network->last_associate = 0;
- network->time_stamp[0] = 0;
- network->time_stamp[1] = 0;
- network->beacon_interval = 100; /* Default */
- network->listen_interval = 10; /* Default */
- network->atim_window = 0; /* Default */
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-}
-
-static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
-{
- struct ipw_tgi_tx_key key;
-
- if (!(priv->ieee->sec.flags & (1 << index)))
- return;
-
- key.key_id = index;
- memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH);
- key.security_type = type;
- key.station_index = 0; /* always 0 for BSS */
- key.flags = 0;
- /* 0 for new key; previous value of counter (after fatal error) */
- key.tx_counter[0] = cpu_to_le32(0);
- key.tx_counter[1] = cpu_to_le32(0);
-
- ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key);
-}
-
-static void ipw_send_wep_keys(struct ipw_priv *priv, int type)
-{
- struct ipw_wep_key key;
- int i;
-
- key.cmd_id = DINO_CMD_WEP_KEY;
- key.seq_num = 0;
-
- /* Note: AES keys cannot be set for multiple times.
- * Only set it at the first time. */
- for (i = 0; i < 4; i++) {
- key.key_index = i | type;
- if (!(priv->ieee->sec.flags & (1 << i))) {
- key.key_size = 0;
- continue;
- }
-
- key.key_size = priv->ieee->sec.key_sizes[i];
- memcpy(key.key, priv->ieee->sec.keys[i], key.key_size);
-
- ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key);
- }
-}
-
-static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level)
-{
- if (priv->ieee->host_encrypt)
- return;
-
- switch (level) {
- case SEC_LEVEL_3:
- priv->sys_config.disable_unicast_decryption = 0;
- priv->ieee->host_decrypt = 0;
- break;
- case SEC_LEVEL_2:
- priv->sys_config.disable_unicast_decryption = 1;
- priv->ieee->host_decrypt = 1;
- break;
- case SEC_LEVEL_1:
- priv->sys_config.disable_unicast_decryption = 0;
- priv->ieee->host_decrypt = 0;
- break;
- case SEC_LEVEL_0:
- priv->sys_config.disable_unicast_decryption = 1;
- break;
- default:
- break;
- }
-}
-
-static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level)
-{
- if (priv->ieee->host_encrypt)
- return;
-
- switch (level) {
- case SEC_LEVEL_3:
- priv->sys_config.disable_multicast_decryption = 0;
- break;
- case SEC_LEVEL_2:
- priv->sys_config.disable_multicast_decryption = 1;
- break;
- case SEC_LEVEL_1:
- priv->sys_config.disable_multicast_decryption = 0;
- break;
- case SEC_LEVEL_0:
- priv->sys_config.disable_multicast_decryption = 1;
- break;
- default:
- break;
- }
-}
-
-static void ipw_set_hwcrypto_keys(struct ipw_priv *priv)
-{
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
- ipw_send_tgi_tx_key(priv,
- DCT_FLAG_EXT_SECURITY_CCM,
- priv->ieee->sec.active_key);
-
- if (!priv->ieee->host_mc_decrypt)
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM);
- break;
- case SEC_LEVEL_2:
- if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
- ipw_send_tgi_tx_key(priv,
- DCT_FLAG_EXT_SECURITY_TKIP,
- priv->ieee->sec.active_key);
- break;
- case SEC_LEVEL_1:
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
- ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level);
- ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level);
- break;
- case SEC_LEVEL_0:
- default:
- break;
- }
-}
-
-static void ipw_adhoc_check(void *data)
-{
- struct ipw_priv *priv = data;
-
- if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold &&
- !(priv->config & CFG_ADHOC_PERSIST)) {
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE | IPW_DL_ASSOC,
- "Missed beacon: %d - disassociate\n",
- priv->missed_adhoc_beacons);
- ipw_remove_current_network(priv);
- ipw_disassociate(priv);
- return;
- }
-
- schedule_delayed_work(&priv->adhoc_check,
- le16_to_cpu(priv->assoc_request.beacon_interval));
-}
-
-static void ipw_bg_adhoc_check(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, adhoc_check.work);
- mutex_lock(&priv->mutex);
- ipw_adhoc_check(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_debug_config(struct ipw_priv *priv)
-{
- IPW_DEBUG_INFO("Scan completed, no valid APs matched "
- "[CFG 0x%08X]\n", priv->config);
- if (priv->config & CFG_STATIC_CHANNEL)
- IPW_DEBUG_INFO("Channel locked to %d\n", priv->channel);
- else
- IPW_DEBUG_INFO("Channel unlocked.\n");
- if (priv->config & CFG_STATIC_ESSID)
- IPW_DEBUG_INFO("ESSID locked to '%*pE'\n",
- priv->essid_len, priv->essid);
- else
- IPW_DEBUG_INFO("ESSID unlocked.\n");
- if (priv->config & CFG_STATIC_BSSID)
- IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid);
- else
- IPW_DEBUG_INFO("BSSID unlocked.\n");
- if (priv->capability & CAP_PRIVACY_ON)
- IPW_DEBUG_INFO("PRIVACY on\n");
- else
- IPW_DEBUG_INFO("PRIVACY off\n");
- IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
-}
-
-static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
-{
- /* TODO: Verify that this works... */
- struct ipw_fixed_rate fr;
- u32 reg;
- u16 mask = 0;
- u16 new_tx_rates = priv->rates_mask;
-
- /* Identify 'current FW band' and match it with the fixed
- * Tx rates */
-
- switch (priv->ieee->freq_band) {
- case LIBIPW_52GHZ_BAND: /* A only */
- /* IEEE_A */
- if (priv->rates_mask & ~LIBIPW_OFDM_RATES_MASK) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- break;
- }
-
- new_tx_rates >>= LIBIPW_OFDM_SHIFT_MASK_A;
- break;
-
- default: /* 2.4Ghz or Mixed */
- /* IEEE_B */
- if (mode == IEEE_B) {
- if (new_tx_rates & ~LIBIPW_CCK_RATES_MASK) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- }
- break;
- }
-
- /* IEEE_G */
- if (new_tx_rates & ~(LIBIPW_CCK_RATES_MASK |
- LIBIPW_OFDM_RATES_MASK)) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- break;
- }
-
- if (LIBIPW_OFDM_RATE_6MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_6MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_6MB_MASK;
- }
-
- if (LIBIPW_OFDM_RATE_9MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_9MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_9MB_MASK;
- }
-
- if (LIBIPW_OFDM_RATE_12MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_12MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_12MB_MASK;
- }
-
- new_tx_rates |= mask;
- break;
- }
-
- fr.tx_rates = cpu_to_le16(new_tx_rates);
-
- reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE);
- ipw_write_reg32(priv, reg, *(u32 *) & fr);
-}
-
-static void ipw_abort_scan(struct ipw_priv *priv)
-{
- int err;
-
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
- return;
- }
- priv->status |= STATUS_SCAN_ABORTING;
-
- err = ipw_send_scan_abort(priv);
- if (err)
- IPW_DEBUG_HC("Request to abort scan failed.\n");
-}
-
-static void ipw_add_scan_channels(struct ipw_priv *priv,
- struct ipw_scan_request_ext *scan,
- int scan_type)
-{
- int channel_index = 0;
- const struct libipw_geo *geo;
- int i;
-
- geo = libipw_get_geo(priv->ieee);
-
- if (priv->ieee->freq_band & LIBIPW_52GHZ_BAND) {
- int start = channel_index;
- for (i = 0; i < geo->a_channels; i++) {
- if ((priv->status & STATUS_ASSOCIATED) &&
- geo->a[i].channel == priv->channel)
- continue;
- channel_index++;
- scan->channels_list[channel_index] = geo->a[i].channel;
- ipw_set_scan_type(scan, channel_index,
- geo->a[i].
- flags & LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN :
- scan_type);
- }
-
- if (start != channel_index) {
- scan->channels_list[start] = (u8) (IPW_A_MODE << 6) |
- (channel_index - start);
- channel_index++;
- }
- }
-
- if (priv->ieee->freq_band & LIBIPW_24GHZ_BAND) {
- int start = channel_index;
- if (priv->config & CFG_SPEED_SCAN) {
- int index;
- u8 channels[LIBIPW_24GHZ_CHANNELS] = {
- /* nop out the list */
- [0] = 0
- };
-
- u8 channel;
- while (channel_index < IPW_SCAN_CHANNELS - 1) {
- channel =
- priv->speed_scan[priv->speed_scan_pos];
- if (channel == 0) {
- priv->speed_scan_pos = 0;
- channel = priv->speed_scan[0];
- }
- if ((priv->status & STATUS_ASSOCIATED) &&
- channel == priv->channel) {
- priv->speed_scan_pos++;
- continue;
- }
-
- /* If this channel has already been
- * added in scan, break from loop
- * and this will be the first channel
- * in the next scan.
- */
- if (channels[channel - 1] != 0)
- break;
-
- channels[channel - 1] = 1;
- priv->speed_scan_pos++;
- channel_index++;
- scan->channels_list[channel_index] = channel;
- index =
- libipw_channel_to_index(priv->ieee, channel);
- ipw_set_scan_type(scan, channel_index,
- geo->bg[index].
- flags &
- LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
- : scan_type);
- }
- } else {
- for (i = 0; i < geo->bg_channels; i++) {
- if ((priv->status & STATUS_ASSOCIATED) &&
- geo->bg[i].channel == priv->channel)
- continue;
- channel_index++;
- scan->channels_list[channel_index] =
- geo->bg[i].channel;
- ipw_set_scan_type(scan, channel_index,
- geo->bg[i].
- flags &
- LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
- : scan_type);
- }
- }
-
- if (start != channel_index) {
- scan->channels_list[start] = (u8) (IPW_B_MODE << 6) |
- (channel_index - start);
- }
- }
-}
-
-static int ipw_passive_dwell_time(struct ipw_priv *priv)
-{
- /* staying on passive channels longer than the DTIM interval during a
- * scan, while associated, causes the firmware to cancel the scan
- * without notification. Hence, don't stay on passive channels longer
- * than the beacon interval.
- */
- if (priv->status & STATUS_ASSOCIATED
- && priv->assoc_network->beacon_interval > 10)
- return priv->assoc_network->beacon_interval - 10;
- else
- return 120;
-}
-
-static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
-{
- struct ipw_scan_request_ext scan;
- int err = 0, scan_type;
-
- if (!(priv->status & STATUS_INIT) ||
- (priv->status & STATUS_EXIT_PENDING))
- return 0;
-
- mutex_lock(&priv->mutex);
-
- if (direct && (priv->direct_scan_ssid_len == 0)) {
- IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n");
- priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
- goto done;
- }
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- if (!(priv->status & STATUS_SCAN_FORCED) &&
- priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- if (priv->status & STATUS_RF_KILL_MASK) {
- IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- memset(&scan, 0, sizeof(scan));
- scan.full_scan_index = cpu_to_le32(libipw_get_scans(priv->ieee));
-
- if (type == IW_SCAN_TYPE_PASSIVE) {
- IPW_DEBUG_WX("use passive scanning\n");
- scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(ipw_passive_dwell_time(priv));
- ipw_add_scan_channels(priv, &scan, scan_type);
- goto send_request;
- }
-
- /* Use active scan by default. */
- if (priv->config & CFG_SPEED_SCAN)
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(30);
- else
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(20);
-
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
- cpu_to_le16(20);
-
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(ipw_passive_dwell_time(priv));
- scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- u8 channel;
- u8 band = 0;
-
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- band = (u8) (IPW_A_MODE << 6) | 1;
- channel = priv->channel;
- break;
-
- case LIBIPW_24GHZ_BAND:
- band = (u8) (IPW_B_MODE << 6) | 1;
- channel = priv->channel;
- break;
-
- default:
- band = (u8) (IPW_B_MODE << 6) | 1;
- channel = 9;
- break;
- }
-
- scan.channels_list[0] = band;
- scan.channels_list[1] = channel;
- ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN);
-
- /* NOTE: The card will sit on this channel for this time
- * period. Scan aborts are timing sensitive and frequently
- * result in firmware restarts. As such, it is best to
- * set a small dwell_time here and just keep re-issuing
- * scans. Otherwise fast channel hopping will not actually
- * hop channels.
- *
- * TODO: Move SPEED SCAN support to all modes and bands */
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(2000);
- } else {
-#endif /* CONFIG_IPW2200_MONITOR */
- /* Honor direct scans first, otherwise if we are roaming make
- * this a direct scan for the current network. Finally,
- * ensure that every other scan is a fast channel hop scan */
- if (direct) {
- err = ipw_send_ssid(priv, priv->direct_scan_ssid,
- priv->direct_scan_ssid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command "
- "failed\n");
- goto done;
- }
-
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
- } else if ((priv->status & STATUS_ROAMING)
- || (!(priv->status & STATUS_ASSOCIATED)
- && (priv->config & CFG_STATIC_ESSID)
- && (le32_to_cpu(scan.full_scan_index) % 2))) {
- err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command "
- "failed.\n");
- goto done;
- }
-
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
- } else
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
-
- ipw_add_scan_channels(priv, &scan, scan_type);
-#ifdef CONFIG_IPW2200_MONITOR
- }
-#endif
-
-send_request:
- err = ipw_send_scan_request_ext(priv, &scan);
- if (err) {
- IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
- goto done;
- }
-
- priv->status |= STATUS_SCANNING;
- if (direct) {
- priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
- priv->direct_scan_ssid_len = 0;
- } else
- priv->status &= ~STATUS_SCAN_PENDING;
-
- schedule_delayed_work(&priv->scan_check, IPW_SCAN_CHECK_WATCHDOG);
-done:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static void ipw_request_passive_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_passive_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0);
-}
-
-static void ipw_request_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0);
-}
-
-static void ipw_request_direct_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_direct_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1);
-}
-
-static void ipw_bg_abort_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, abort_scan);
- mutex_lock(&priv->mutex);
- ipw_abort_scan(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_wpa_enable(struct ipw_priv *priv, int value)
-{
- /* This is called when wpa_supplicant loads and closes the driver
- * interface. */
- priv->ieee->wpa_enabled = value;
- return 0;
-}
-
-static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value)
-{
- struct libipw_device *ieee = priv->ieee;
- struct libipw_security sec = {
- .flags = SEC_AUTH_MODE,
- };
- int ret = 0;
-
- if (value & IW_AUTH_ALG_SHARED_KEY) {
- sec.auth_mode = WLAN_AUTH_SHARED_KEY;
- ieee->open_wep = 0;
- } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
- sec.auth_mode = WLAN_AUTH_OPEN;
- ieee->open_wep = 1;
- } else if (value & IW_AUTH_ALG_LEAP) {
- sec.auth_mode = WLAN_AUTH_LEAP;
- ieee->open_wep = 1;
- } else
- return -EINVAL;
-
- if (ieee->set_security)
- ieee->set_security(ieee->dev, &sec);
- else
- ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie,
- int wpa_ie_len)
-{
- /* make sure WPA is enabled */
- ipw_wpa_enable(priv, 1);
-}
-
-static int ipw_set_rsn_capa(struct ipw_priv *priv,
- char *capabilities, int length)
-{
- IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n");
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length,
- capabilities);
-}
-
-/*
- * WE-18 support
- */
-
-/* SIOCSIWGENIE */
-static int ipw_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- u8 *buf;
- int err = 0;
-
- if (wrqu->data.length > MAX_WPA_IE_LEN ||
- (wrqu->data.length && extra == NULL))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = buf;
- ieee->wpa_ie_len = wrqu->data.length;
- } else {
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = NULL;
- ieee->wpa_ie_len = 0;
- }
-
- ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
- out:
- return err;
-}
-
-/* SIOCGIWGENIE */
-static int ipw_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- int err = 0;
-
- if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
- wrqu->data.length = 0;
- goto out;
- }
-
- if (wrqu->data.length < ieee->wpa_ie_len) {
- err = -E2BIG;
- goto out;
- }
-
- wrqu->data.length = ieee->wpa_ie_len;
- memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
-
- out:
- return err;
-}
-
-static int wext_cipher2level(int cipher)
-{
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- return SEC_LEVEL_0;
- case IW_AUTH_CIPHER_WEP40:
- case IW_AUTH_CIPHER_WEP104:
- return SEC_LEVEL_1;
- case IW_AUTH_CIPHER_TKIP:
- return SEC_LEVEL_2;
- case IW_AUTH_CIPHER_CCMP:
- return SEC_LEVEL_3;
- default:
- return -1;
- }
-}
-
-/* SIOCSIWAUTH */
-static int ipw_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
- unsigned long flags;
- int ret = 0;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- ipw_set_hw_decrypt_unicast(priv,
- wext_cipher2level(param->value));
- break;
- case IW_AUTH_CIPHER_GROUP:
- ipw_set_hw_decrypt_multicast(priv,
- wext_cipher2level(param->value));
- break;
- case IW_AUTH_KEY_MGMT:
- /*
- * ipw2200 does not use these parameters
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
- break;
-
- flags = crypt->ops->get_flags(crypt->priv);
-
- if (param->value)
- flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
- else
- flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
-
- crypt->ops->set_flags(flags, crypt->priv);
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:{
- /* HACK:
- *
- * wpa_supplicant calls set_wpa_enabled when the driver
- * is loaded and unloaded, regardless of if WPA is being
- * used. No other calls are made which can be used to
- * determine if encryption will be used or not prior to
- * association being expected. If encryption is not being
- * used, drop_unencrypted is set to false, else true -- we
- * can use this to determine if the CAP_PRIVACY_ON bit should
- * be set.
- */
- struct libipw_security sec = {
- .flags = SEC_ENABLED,
- .enabled = param->value,
- };
- priv->ieee->drop_unencrypted = param->value;
- /* We only change SEC_LEVEL for open mode. Others
- * are set by ipw_wpa_set_encryption.
- */
- if (!param->value) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_0;
- } else {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- }
- if (priv->ieee->set_security)
- priv->ieee->set_security(priv->ieee->dev, &sec);
- break;
- }
-
- case IW_AUTH_80211_AUTH_ALG:
- ret = ipw_wpa_set_auth_algs(priv, param->value);
- break;
-
- case IW_AUTH_WPA_ENABLED:
- ret = ipw_wpa_enable(priv, param->value);
- ipw_disassociate(priv);
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = param->value;
- break;
-
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = param->value;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return ret;
-}
-
-/* SIOCGIWAUTH */
-static int ipw_wx_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * wpa_supplicant will control these internally
- */
- return -EOPNOTSUPP;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->get_flags)
- break;
-
- param->value = (crypt->ops->get_flags(crypt->priv) &
- IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value = ieee->drop_unencrypted;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- param->value = ieee->sec.auth_mode;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = ieee->wpa_enabled;
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- param->value = ieee->ieee802_1x;
- break;
-
- case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- param->value = ieee->privacy_invoked;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/* SIOCSIWENCODEEXT */
-static int ipw_wx_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-
- if (hwcrypto) {
- if (ext->alg == IW_ENCODE_ALG_TKIP) {
- /* IPW HW can't build TKIP MIC,
- host decryption still needed */
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
- priv->ieee->host_mc_decrypt = 1;
- else {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 1;
- priv->ieee->host_decrypt = 1;
- }
- } else {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 0;
- priv->ieee->host_decrypt = 0;
- priv->ieee->host_mc_decrypt = 0;
- }
- }
-
- return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCGIWENCODEEXT */
-static int ipw_wx_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCSIWMLME */
-static int ipw_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- /* silently ignore */
- break;
-
- case IW_MLME_DISASSOC:
- ipw_disassociate(priv);
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_QOS
-
-/* QoS */
-/*
-* get the modulation type of the current network or
-* the card current mode
-*/
-static u8 ipw_qos_current_mode(struct ipw_priv * priv)
-{
- u8 mode = 0;
-
- if (priv->status & STATUS_ASSOCIATED) {
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- mode = priv->assoc_network->mode;
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
- } else {
- mode = priv->ieee->mode;
- }
- IPW_DEBUG_QOS("QoS network/card mode %d\n", mode);
- return mode;
-}
-
-/*
-* Handle management frame beacon and probe response
-*/
-static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
- int active_network,
- struct libipw_network *network)
-{
- u32 size = sizeof(struct libipw_qos_parameters);
-
- if (network->capability & WLAN_CAPABILITY_IBSS)
- network->qos_data.active = network->qos_data.supported;
-
- if (network->flags & NETWORK_HAS_QOS_MASK) {
- if (active_network &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS))
- network->qos_data.active = network->qos_data.supported;
-
- if ((network->qos_data.active == 1) && (active_network == 1) &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS) &&
- (network->qos_data.old_param_count !=
- network->qos_data.param_count)) {
- network->qos_data.old_param_count =
- network->qos_data.param_count;
- schedule_work(&priv->qos_activate);
- IPW_DEBUG_QOS("QoS parameters change call "
- "qos_activate\n");
- }
- } else {
- if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B))
- memcpy(&network->qos_data.parameters,
- &def_parameters_CCK, size);
- else
- memcpy(&network->qos_data.parameters,
- &def_parameters_OFDM, size);
-
- if ((network->qos_data.active == 1) && (active_network == 1)) {
- IPW_DEBUG_QOS("QoS was disabled call qos_activate\n");
- schedule_work(&priv->qos_activate);
- }
-
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- }
- if ((priv->status & STATUS_ASSOCIATED) &&
- (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) {
- if (!ether_addr_equal(network->bssid, priv->bssid))
- if (network->capability & WLAN_CAPABILITY_IBSS)
- if ((network->ssid_len ==
- priv->assoc_network->ssid_len) &&
- !memcmp(network->ssid,
- priv->assoc_network->ssid,
- network->ssid_len)) {
- schedule_work(&priv->merge_networks);
- }
- }
-
- return 0;
-}
-
-/*
-* This function set up the firmware to support QoS. It sends
-* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO
-*/
-static int ipw_qos_activate(struct ipw_priv *priv,
- struct libipw_qos_data *qos_network_data)
-{
- int err;
- struct libipw_qos_parameters qos_parameters[QOS_QOS_SETS];
- struct libipw_qos_parameters *active_one = NULL;
- u32 size = sizeof(struct libipw_qos_parameters);
- u32 burst_duration;
- int i;
- u8 type;
-
- type = ipw_qos_current_mode(priv);
-
- active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]);
- memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size);
- active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]);
- memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size);
-
- if (qos_network_data == NULL) {
- if (type == IEEE_B) {
- IPW_DEBUG_QOS("QoS activate network mode %d\n", type);
- active_one = &def_parameters_CCK;
- } else
- active_one = &def_parameters_OFDM;
-
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- burst_duration = ipw_qos_get_burst_duration(priv);
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
- cpu_to_le16(burst_duration);
- } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (type == IEEE_B) {
- IPW_DEBUG_QOS("QoS activate IBSS network mode %d\n",
- type);
- if (priv->qos_data.qos_enable == 0)
- active_one = &def_parameters_CCK;
- else
- active_one = priv->qos_data.def_qos_parm_CCK;
- } else {
- if (priv->qos_data.qos_enable == 0)
- active_one = &def_parameters_OFDM;
- else
- active_one = priv->qos_data.def_qos_parm_OFDM;
- }
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- } else {
- unsigned long flags;
- int active;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- active_one = &(qos_network_data->parameters);
- qos_network_data->old_param_count =
- qos_network_data->param_count;
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- active = qos_network_data->supported;
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (active == 0) {
- burst_duration = ipw_qos_get_burst_duration(priv);
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- qos_parameters[QOS_PARAM_SET_ACTIVE].
- tx_op_limit[i] = cpu_to_le16(burst_duration);
- }
- }
-
- IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
- err = ipw_send_qos_params_command(priv, &qos_parameters[0]);
- if (err)
- IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n");
-
- return err;
-}
-
-/*
-* send IPW_CMD_WME_INFO to the firmware
-*/
-static int ipw_qos_set_info_element(struct ipw_priv *priv)
-{
- int ret = 0;
- struct libipw_qos_information_element qos_info;
-
- if (priv == NULL)
- return -1;
-
- qos_info.elementID = QOS_ELEMENT_ID;
- qos_info.length = sizeof(struct libipw_qos_information_element) - 2;
-
- qos_info.version = QOS_VERSION_1;
- qos_info.ac_info = 0;
-
- memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN);
- qos_info.qui_type = QOS_OUI_TYPE;
- qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE;
-
- ret = ipw_send_qos_info_command(priv, &qos_info);
- if (ret != 0) {
- IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n");
- }
- return ret;
-}
-
-/*
-* Set the QoS parameter with the association request structure
-*/
-static int ipw_qos_association(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- int err = 0;
- struct libipw_qos_data *qos_data = NULL;
- struct libipw_qos_data ibss_data = {
- .supported = 1,
- .active = 1,
- };
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS));
-
- qos_data = &ibss_data;
- break;
-
- case IW_MODE_INFRA:
- qos_data = &network->qos_data;
- break;
-
- default:
- BUG();
- break;
- }
-
- err = ipw_qos_activate(priv, qos_data);
- if (err) {
- priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC;
- return err;
- }
-
- if (priv->qos_data.qos_enable && qos_data->supported) {
- IPW_DEBUG_QOS("QoS will be enabled for this association\n");
- priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC;
- return ipw_qos_set_info_element(priv);
- }
-
- return 0;
-}
-
-/*
-* handling the beaconing responses. if we get different QoS setting
-* off the network from the associated setting, adjust the QoS
-* setting
-*/
-static void ipw_qos_association_resp(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- unsigned long flags;
- u32 size = sizeof(struct libipw_qos_parameters);
- int set_qos_param = 0;
-
- if ((priv == NULL) || (network == NULL) ||
- (priv->assoc_network == NULL))
- return;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return;
-
- if ((priv->ieee->iw_mode != IW_MODE_INFRA))
- return;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- if (network->flags & NETWORK_HAS_QOS_PARAMETERS) {
- memcpy(&priv->assoc_network->qos_data, &network->qos_data,
- sizeof(struct libipw_qos_data));
- priv->assoc_network->qos_data.active = 1;
- if ((network->qos_data.old_param_count !=
- network->qos_data.param_count)) {
- set_qos_param = 1;
- network->qos_data.old_param_count =
- network->qos_data.param_count;
- }
-
- } else {
- if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B))
- memcpy(&priv->assoc_network->qos_data.parameters,
- &def_parameters_CCK, size);
- else
- memcpy(&priv->assoc_network->qos_data.parameters,
- &def_parameters_OFDM, size);
- priv->assoc_network->qos_data.active = 0;
- priv->assoc_network->qos_data.supported = 0;
- set_qos_param = 1;
- }
-
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (set_qos_param == 1)
- schedule_work(&priv->qos_activate);
-}
-
-static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv)
-{
- u32 ret = 0;
-
- if (!priv)
- return 0;
-
- if (!(priv->ieee->modulation & LIBIPW_OFDM_MODULATION))
- ret = priv->qos_data.burst_duration_CCK;
- else
- ret = priv->qos_data.burst_duration_OFDM;
-
- return ret;
-}
-
-/*
-* Initialize the setting of QoS global
-*/
-static void ipw_qos_init(struct ipw_priv *priv, int enable,
- int burst_enable, u32 burst_duration_CCK,
- u32 burst_duration_OFDM)
-{
- priv->qos_data.qos_enable = enable;
-
- if (priv->qos_data.qos_enable) {
- priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK;
- priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM;
- IPW_DEBUG_QOS("QoS is enabled\n");
- } else {
- priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK;
- priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM;
- IPW_DEBUG_QOS("QoS is not enabled\n");
- }
-
- priv->qos_data.burst_enable = burst_enable;
-
- if (burst_enable) {
- priv->qos_data.burst_duration_CCK = burst_duration_CCK;
- priv->qos_data.burst_duration_OFDM = burst_duration_OFDM;
- } else {
- priv->qos_data.burst_duration_CCK = 0;
- priv->qos_data.burst_duration_OFDM = 0;
- }
-}
-
-/*
-* map the packet priority to the right TX Queue
-*/
-static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority)
-{
- if (priority > 7 || !priv->qos_data.qos_enable)
- priority = 0;
-
- return from_priority_to_tx_queue[priority] - 1;
-}
-
-static int ipw_is_qos_active(struct net_device *dev,
- struct sk_buff *skb)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_qos_data *qos_data = NULL;
- int active, supported;
- u8 *daddr = skb->data + ETH_ALEN;
- int unicast = !is_multicast_ether_addr(daddr);
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return 0;
-
- qos_data = &priv->assoc_network->qos_data;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (unicast == 0)
- qos_data->active = 0;
- else
- qos_data->active = qos_data->supported;
- }
- active = qos_data->active;
- supported = qos_data->supported;
- IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d "
- "unicast %d\n",
- priv->qos_data.qos_enable, active, supported, unicast);
- if (active && priv->qos_data.qos_enable)
- return 1;
-
- return 0;
-
-}
-/*
-* add QoS parameter to the TX command
-*/
-static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
- u16 priority,
- struct tfd_data *tfd)
-{
- int tx_queue_id = 0;
-
-
- tx_queue_id = from_priority_to_tx_queue[priority] - 1;
- tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED;
-
- if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) {
- tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
- tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK);
- }
- return 0;
-}
-
-/*
-* background support to run QoS activate functionality
-*/
-static void ipw_bg_qos_activate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, qos_activate);
-
- mutex_lock(&priv->mutex);
-
- if (priv->status & STATUS_ASSOCIATED)
- ipw_qos_activate(priv, &(priv->assoc_network->qos_data));
-
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_handle_probe_response(struct net_device *dev,
- struct libipw_probe_response *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int active_network = ((priv->status & STATUS_ASSOCIATED) &&
- (network == priv->assoc_network));
-
- ipw_qos_handle_probe_response(priv, active_network, network);
-
- return 0;
-}
-
-static int ipw_handle_beacon(struct net_device *dev,
- struct libipw_beacon *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int active_network = ((priv->status & STATUS_ASSOCIATED) &&
- (network == priv->assoc_network));
-
- ipw_qos_handle_probe_response(priv, active_network, network);
-
- return 0;
-}
-
-static int ipw_handle_assoc_response(struct net_device *dev,
- struct libipw_assoc_response *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- ipw_qos_association_resp(priv, network);
- return 0;
-}
-
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
- *qos_param)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS,
- sizeof(*qos_param) * 3, qos_param);
-}
-
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
- *qos_param)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param),
- qos_param);
-}
-
-#endif /* CONFIG_IPW2200_QOS */
-
-static int ipw_associate_network(struct ipw_priv *priv,
- struct libipw_network *network,
- struct ipw_supported_rates *rates, int roaming)
-{
- int err;
-
- if (priv->config & CFG_FIXED_RATE)
- ipw_set_fixed_rate(priv, network->mode);
-
- if (!(priv->config & CFG_STATIC_ESSID)) {
- priv->essid_len = min(network->ssid_len,
- (u8) IW_ESSID_MAX_SIZE);
- memcpy(priv->essid, network->ssid, priv->essid_len);
- }
-
- network->last_associate = jiffies;
-
- memset(&priv->assoc_request, 0, sizeof(priv->assoc_request));
- priv->assoc_request.channel = network->channel;
- priv->assoc_request.auth_key = 0;
-
- if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) {
- priv->assoc_request.auth_type = AUTH_SHARED_KEY;
- priv->assoc_request.auth_key = priv->ieee->sec.active_key;
-
- if (priv->ieee->sec.level == SEC_LEVEL_1)
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
-
- } else if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP))
- priv->assoc_request.auth_type = AUTH_LEAP;
- else
- priv->assoc_request.auth_type = AUTH_OPEN;
-
- if (priv->ieee->wpa_ie_len) {
- priv->assoc_request.policy_support = cpu_to_le16(0x02); /* RSN active */
- ipw_set_rsn_capa(priv, priv->ieee->wpa_ie,
- priv->ieee->wpa_ie_len);
- }
-
- /*
- * It is valid for our ieee device to support multiple modes, but
- * when it comes to associating to a given network we have to choose
- * just one mode.
- */
- if (network->mode & priv->ieee->mode & IEEE_A)
- priv->assoc_request.ieee_mode = IPW_A_MODE;
- else if (network->mode & priv->ieee->mode & IEEE_G)
- priv->assoc_request.ieee_mode = IPW_G_MODE;
- else if (network->mode & priv->ieee->mode & IEEE_B)
- priv->assoc_request.ieee_mode = IPW_B_MODE;
-
- priv->assoc_request.capability = cpu_to_le16(network->capability);
- if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
- && !(priv->config & CFG_PREAMBLE_LONG)) {
- priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE;
- } else {
- priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE;
-
- /* Clear the short preamble if we won't be supporting it */
- priv->assoc_request.capability &=
- ~cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
- }
-
- /* Clear capability bits that aren't used in Ad Hoc */
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->assoc_request.capability &=
- ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- IPW_DEBUG_ASSOC("%ssociation attempt: '%*pE', channel %d, 802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
- roaming ? "Rea" : "A",
- priv->essid_len, priv->essid,
- network->channel,
- ipw_modes[priv->assoc_request.ieee_mode],
- rates->num_rates,
- (priv->assoc_request.preamble_length ==
- DCT_FLAG_LONG_PREAMBLE) ? "long" : "short",
- network->capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long",
- priv->capability & CAP_PRIVACY_ON ? "on " : "off",
- priv->capability & CAP_PRIVACY_ON ?
- (priv->capability & CAP_SHARED_KEY ? "(shared)" :
- "(open)") : "",
- priv->capability & CAP_PRIVACY_ON ? " key=" : "",
- priv->capability & CAP_PRIVACY_ON ?
- '1' + priv->ieee->sec.active_key : '.',
- priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
-
- priv->assoc_request.beacon_interval = cpu_to_le16(network->beacon_interval);
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) {
- priv->assoc_request.assoc_type = HC_IBSS_START;
- priv->assoc_request.assoc_tsf_msw = 0;
- priv->assoc_request.assoc_tsf_lsw = 0;
- } else {
- if (unlikely(roaming))
- priv->assoc_request.assoc_type = HC_REASSOCIATE;
- else
- priv->assoc_request.assoc_type = HC_ASSOCIATE;
- priv->assoc_request.assoc_tsf_msw = cpu_to_le32(network->time_stamp[1]);
- priv->assoc_request.assoc_tsf_lsw = cpu_to_le32(network->time_stamp[0]);
- }
-
- memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN);
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- eth_broadcast_addr(priv->assoc_request.dest);
- priv->assoc_request.atim_window = cpu_to_le16(network->atim_window);
- } else {
- memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN);
- priv->assoc_request.atim_window = 0;
- }
-
- priv->assoc_request.listen_interval = cpu_to_le16(network->listen_interval);
-
- err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
- return err;
- }
-
- rates->ieee_mode = priv->assoc_request.ieee_mode;
- rates->purpose = IPW_RATE_CONNECT;
- ipw_send_supported_rates(priv, rates);
-
- if (priv->assoc_request.ieee_mode == IPW_G_MODE)
- priv->sys_config.dot11g_auto_detection = 1;
- else
- priv->sys_config.dot11g_auto_detection = 0;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->sys_config.answer_broadcast_ssid_probe = 1;
- else
- priv->sys_config.answer_broadcast_ssid_probe = 0;
-
- err = ipw_send_system_config(priv);
- if (err) {
- IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
- return err;
- }
-
- IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi);
- err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM);
- if (err) {
- IPW_DEBUG_HC("Attempt to send associate command failed.\n");
- return err;
- }
-
- /*
- * If preemption is enabled, it is possible for the association
- * to complete before we return from ipw_send_associate. Therefore
- * we have to be sure and update our priviate data first.
- */
- priv->channel = network->channel;
- memcpy(priv->bssid, network->bssid, ETH_ALEN);
- priv->status |= STATUS_ASSOCIATING;
- priv->status &= ~STATUS_SECURITY_UPDATED;
-
- priv->assoc_network = network;
-
-#ifdef CONFIG_IPW2200_QOS
- ipw_qos_association(priv, network);
-#endif
-
- err = ipw_send_associate(priv, &priv->assoc_request);
- if (err) {
- IPW_DEBUG_HC("Attempt to send associate command failed.\n");
- return err;
- }
-
- IPW_DEBUG(IPW_DL_STATE, "associating: '%*pE' %pM\n",
- priv->essid_len, priv->essid, priv->bssid);
-
- return 0;
-}
-
-static void ipw_roam(void *data)
-{
- struct ipw_priv *priv = data;
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = priv->assoc_network
- };
-
- /* The roaming process is as follows:
- *
- * 1. Missed beacon threshold triggers the roaming process by
- * setting the status ROAM bit and requesting a scan.
- * 2. When the scan completes, it schedules the ROAM work
- * 3. The ROAM work looks at all of the known networks for one that
- * is a better network than the currently associated. If none
- * found, the ROAM process is over (ROAM bit cleared)
- * 4. If a better network is found, a disassociation request is
- * sent.
- * 5. When the disassociation completes, the roam work is again
- * scheduled. The second time through, the driver is no longer
- * associated, and the newly selected network is sent an
- * association request.
- * 6. At this point ,the roaming process is complete and the ROAM
- * status bit is cleared.
- */
-
- /* If we are no longer associated, and the roaming bit is no longer
- * set, then we are not actively roaming, so just return */
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING)))
- return;
-
- if (priv->status & STATUS_ASSOCIATED) {
- /* First pass through ROAM process -- look for a better
- * network */
- unsigned long flags;
- u8 rssi = priv->assoc_network->stats.rssi;
- priv->assoc_network->stats.rssi = -128;
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list) {
- if (network != priv->assoc_network)
- ipw_best_network(priv, &match, network, 1);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
- priv->assoc_network->stats.rssi = rssi;
-
- if (match.network == priv->assoc_network) {
- IPW_DEBUG_ASSOC("No better APs in this network to "
- "roam to.\n");
- priv->status &= ~STATUS_ROAMING;
- ipw_debug_config(priv);
- return;
- }
-
- ipw_send_disassociate(priv, 1);
- priv->assoc_network = match.network;
-
- return;
- }
-
- /* Second pass through ROAM process -- request association */
- ipw_compatible_rates(priv, priv->assoc_network, &match.rates);
- ipw_associate_network(priv, priv->assoc_network, &match.rates, 1);
- priv->status &= ~STATUS_ROAMING;
-}
-
-static void ipw_bg_roam(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, roam);
- mutex_lock(&priv->mutex);
- ipw_roam(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_associate(void *data)
-{
- struct ipw_priv *priv = data;
-
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = NULL
- };
- struct ipw_supported_rates *rates;
- struct list_head *element;
- unsigned long flags;
-
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
- return 0;
- }
-
- if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_ASSOC("Not attempting association (already in "
- "progress)\n");
- return 0;
- }
-
- if (priv->status & STATUS_DISASSOCIATING) {
- IPW_DEBUG_ASSOC("Not attempting association (in disassociating)\n");
- schedule_work(&priv->associate);
- return 0;
- }
-
- if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) {
- IPW_DEBUG_ASSOC("Not attempting association (scanning or not "
- "initialized)\n");
- return 0;
- }
-
- if (!(priv->config & CFG_ASSOCIATE) &&
- !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) {
- IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
- return 0;
- }
-
- /* Protect our use of the network_list */
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list)
- ipw_best_network(priv, &match, network, 0);
-
- network = match.network;
- rates = &match.rates;
-
- if (network == NULL &&
- priv->ieee->iw_mode == IW_MODE_ADHOC &&
- priv->config & CFG_ADHOC_CREATE &&
- priv->config & CFG_STATIC_ESSID &&
- priv->config & CFG_STATIC_CHANNEL) {
- /* Use oldest network if the free list is empty */
- if (list_empty(&priv->ieee->network_free_list)) {
- struct libipw_network *oldest = NULL;
- struct libipw_network *target;
-
- list_for_each_entry(target, &priv->ieee->network_list, list) {
- if ((oldest == NULL) ||
- (target->last_scanned < oldest->last_scanned))
- oldest = target;
- }
-
- /* If there are no more slots, expire the oldest */
- list_del(&oldest->list);
- target = oldest;
- IPW_DEBUG_ASSOC("Expired '%*pE' (%pM) from network list.\n",
- target->ssid_len, target->ssid,
- target->bssid);
- list_add_tail(&target->list,
- &priv->ieee->network_free_list);
- }
-
- element = priv->ieee->network_free_list.next;
- network = list_entry(element, struct libipw_network, list);
- ipw_adhoc_create(priv, network);
- rates = &priv->rates;
- list_del(element);
- list_add_tail(&network->list, &priv->ieee->network_list);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- /* If we reached the end of the list, then we don't have any valid
- * matching APs */
- if (!network) {
- ipw_debug_config(priv);
-
- if (!(priv->status & STATUS_SCANNING)) {
- if (!(priv->config & CFG_SPEED_SCAN))
- schedule_delayed_work(&priv->request_scan,
- SCAN_INTERVAL);
- else
- schedule_delayed_work(&priv->request_scan, 0);
- }
-
- return 0;
- }
-
- ipw_associate_network(priv, network, rates, 0);
-
- return 1;
-}
-
-static void ipw_bg_associate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, associate);
- mutex_lock(&priv->mutex);
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
- struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- if (!(fc & IEEE80211_FCTL_PROTECTED))
- return;
-
- fc &= ~IEEE80211_FCTL_PROTECTED;
- hdr->frame_control = cpu_to_le16(fc);
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- /* Remove CCMP HDR */
- memmove(skb->data + LIBIPW_3ADDR_LEN,
- skb->data + LIBIPW_3ADDR_LEN + 8,
- skb->len - LIBIPW_3ADDR_LEN - 8);
- skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */
- break;
- case SEC_LEVEL_2:
- break;
- case SEC_LEVEL_1:
- /* Remove IV */
- memmove(skb->data + LIBIPW_3ADDR_LEN,
- skb->data + LIBIPW_3ADDR_LEN + 4,
- skb->len - LIBIPW_3ADDR_LEN - 4);
- skb_trim(skb, skb->len - 8); /* IV + ICV */
- break;
- case SEC_LEVEL_0:
- break;
- default:
- printk(KERN_ERR "Unknown security level %d\n",
- priv->ieee->sec.level);
- break;
- }
-}
-
-static void ipw_handle_data_packet(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct libipw_hdr_4addr *hdr;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- /* We only process data packets if the
- * interface is open */
- if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
- skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- } else if (unlikely(!netif_running(priv->net_dev))) {
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Advance skb->data to the start of the actual payload */
- skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data));
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length));
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
- /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */
- hdr = (struct libipw_hdr_4addr *)rxb->skb->data;
- if (priv->ieee->iw_mode != IW_MODE_MONITOR &&
- (is_multicast_ether_addr(hdr->addr1) ?
- !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt))
- ipw_rebuild_decrypted_skb(priv, rxb->skb);
-
- if (!libipw_rx(priv->ieee, rxb->skb, stats))
- dev->stats.rx_errors++;
- else { /* libipw_rx succeeded, so it now owns the SKB */
- rxb->skb = NULL;
- __ipw_led_activity_on(priv);
- }
-}
-
-#ifdef CONFIG_IPW2200_RADIOTAP
-static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
- struct ipw_rx_frame *frame = &pkt->u.frame;
-
- /* initial pull of some data */
- u16 received_channel = frame->received_channel;
- u8 antennaAndPhy = frame->antennaAndPhy;
- s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */
- u16 pktrate = frame->rate;
-
- /* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE */
- struct ipw_rt_hdr *ipw_rt;
-
- unsigned short len = le16_to_cpu(pkt->u.frame.length);
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- /* We only process data packets if the
- * interface is open */
- if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
- skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- } else if (unlikely(!netif_running(priv->net_dev))) {
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
- * that now */
- if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
- /* FIXME: Should alloc bigger skb instead */
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- /* copy the frame itself */
- memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
- rxb->skb->data + IPW_RX_FRAME_SIZE, len);
-
- ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total header+data */
-
- /* Big bitfield of all the fields we provide in radiotap */
- ipw_rt->rt_hdr.it_present = cpu_to_le32(
- (1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA));
-
- /* Zero the flags, we'll add to them as we go */
- ipw_rt->rt_flags = 0;
- ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
- frame->parent_tsf[2] << 16 |
- frame->parent_tsf[1] << 8 |
- frame->parent_tsf[0]);
-
- /* Convert signal to DBM */
- ipw_rt->rt_dbmsignal = antsignal;
- ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise);
-
- /* Convert the channel data and set the flags */
- ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
- if (received_channel > 14) { /* 802.11a */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- } else if (antennaAndPhy & 32) { /* 802.11b */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- } else { /* 802.11g */
- ipw_rt->rt_chbitmask =
- cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
- }
-
- /* set the rate in multiples of 500k/s */
- switch (pktrate) {
- case IPW_TX_RATE_1MB:
- ipw_rt->rt_rate = 2;
- break;
- case IPW_TX_RATE_2MB:
- ipw_rt->rt_rate = 4;
- break;
- case IPW_TX_RATE_5MB:
- ipw_rt->rt_rate = 10;
- break;
- case IPW_TX_RATE_6MB:
- ipw_rt->rt_rate = 12;
- break;
- case IPW_TX_RATE_9MB:
- ipw_rt->rt_rate = 18;
- break;
- case IPW_TX_RATE_11MB:
- ipw_rt->rt_rate = 22;
- break;
- case IPW_TX_RATE_12MB:
- ipw_rt->rt_rate = 24;
- break;
- case IPW_TX_RATE_18MB:
- ipw_rt->rt_rate = 36;
- break;
- case IPW_TX_RATE_24MB:
- ipw_rt->rt_rate = 48;
- break;
- case IPW_TX_RATE_36MB:
- ipw_rt->rt_rate = 72;
- break;
- case IPW_TX_RATE_48MB:
- ipw_rt->rt_rate = 96;
- break;
- case IPW_TX_RATE_54MB:
- ipw_rt->rt_rate = 108;
- break;
- default:
- ipw_rt->rt_rate = 0;
- break;
- }
-
- /* antenna number */
- ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */
-
- /* set the preamble flag if we have it */
- if ((antennaAndPhy & 64))
- ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr));
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
- if (!libipw_rx(priv->ieee, rxb->skb, stats))
- dev->stats.rx_errors++;
- else { /* libipw_rx succeeded, so it now owns the SKB */
- rxb->skb = NULL;
- /* no LED during capture */
- }
-}
-#endif
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-#define libipw_is_probe_response(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP )
-
-#define libipw_is_management(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
-
-#define libipw_is_control(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
-
-#define libipw_is_data(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
-
-#define libipw_is_assoc_request(fc) \
- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ)
-
-#define libipw_is_reassoc_request(fc) \
- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
-
-static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->prom_net_dev;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
- struct ipw_rx_frame *frame = &pkt->u.frame;
- struct ipw_rt_hdr *ipw_rt;
-
- /* First cache any information we need before we overwrite
- * the information provided in the skb from the hardware */
- struct ieee80211_hdr *hdr;
- u16 channel = frame->received_channel;
- u8 phy_flags = frame->antennaAndPhy;
- s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM;
- s8 noise = (s8) le16_to_cpu(frame->noise);
- u8 rate = frame->rate;
- unsigned short len = le16_to_cpu(pkt->u.frame.length);
- struct sk_buff *skb;
- int hdr_only = 0;
- u16 filter = priv->prom_priv->filter;
-
- /* If the filter is set to not include Rx frames then return */
- if (filter & IPW_PROM_NO_RX)
- return;
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- }
-
- /* We only process data packets if the interface is open */
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_dropped++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
- * that now */
- if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
- /* FIXME: Should alloc bigger skb instead */
- dev->stats.rx_dropped++;
- IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
- if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_MGMT)
- return;
- if (filter & IPW_PROM_MGMT_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_CTL)
- return;
- if (filter & IPW_PROM_CTL_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_DATA)
- return;
- if (filter & IPW_PROM_DATA_HEADER_ONLY)
- hdr_only = 1;
- }
-
- /* Copy the SKB since this is for the promiscuous side */
- skb = skb_copy(rxb->skb, GFP_ATOMIC);
- if (skb == NULL) {
- IPW_ERROR("skb_clone failed for promiscuous copy.\n");
- return;
- }
-
- /* copy the frame data to write after where the radiotap header goes */
- ipw_rt = (void *)skb->data;
-
- if (hdr_only)
- len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
-
- memcpy(ipw_rt->payload, hdr, len);
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */
-
- /* Set the size of the skb to the size of the frame */
- skb_put(skb, sizeof(*ipw_rt) + len);
-
- /* Big bitfield of all the fields we provide in radiotap */
- ipw_rt->rt_hdr.it_present = cpu_to_le32(
- (1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA));
-
- /* Zero the flags, we'll add to them as we go */
- ipw_rt->rt_flags = 0;
- ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
- frame->parent_tsf[2] << 16 |
- frame->parent_tsf[1] << 8 |
- frame->parent_tsf[0]);
-
- /* Convert to DBM */
- ipw_rt->rt_dbmsignal = signal;
- ipw_rt->rt_dbmnoise = noise;
-
- /* Convert the channel data and set the flags */
- ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel));
- if (channel > 14) { /* 802.11a */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- } else if (phy_flags & (1 << 5)) { /* 802.11b */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- } else { /* 802.11g */
- ipw_rt->rt_chbitmask =
- cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
- }
-
- /* set the rate in multiples of 500k/s */
- switch (rate) {
- case IPW_TX_RATE_1MB:
- ipw_rt->rt_rate = 2;
- break;
- case IPW_TX_RATE_2MB:
- ipw_rt->rt_rate = 4;
- break;
- case IPW_TX_RATE_5MB:
- ipw_rt->rt_rate = 10;
- break;
- case IPW_TX_RATE_6MB:
- ipw_rt->rt_rate = 12;
- break;
- case IPW_TX_RATE_9MB:
- ipw_rt->rt_rate = 18;
- break;
- case IPW_TX_RATE_11MB:
- ipw_rt->rt_rate = 22;
- break;
- case IPW_TX_RATE_12MB:
- ipw_rt->rt_rate = 24;
- break;
- case IPW_TX_RATE_18MB:
- ipw_rt->rt_rate = 36;
- break;
- case IPW_TX_RATE_24MB:
- ipw_rt->rt_rate = 48;
- break;
- case IPW_TX_RATE_36MB:
- ipw_rt->rt_rate = 72;
- break;
- case IPW_TX_RATE_48MB:
- ipw_rt->rt_rate = 96;
- break;
- case IPW_TX_RATE_54MB:
- ipw_rt->rt_rate = 108;
- break;
- default:
- ipw_rt->rt_rate = 0;
- break;
- }
-
- /* antenna number */
- ipw_rt->rt_antenna = (phy_flags & 3);
-
- /* set the preamble flag if we have it */
- if (phy_flags & (1 << 6))
- ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len);
-
- if (!libipw_rx(priv->prom_priv->ieee, skb, stats)) {
- dev->stats.rx_errors++;
- dev_kfree_skb_any(skb);
- }
-}
-#endif
-
-static int is_network_packet(struct ipw_priv *priv,
- struct libipw_hdr_4addr *header)
-{
- /* Filter incoming packets to determine if they are targeted toward
- * this network, discarding packets coming from ourselves */
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */
- /* packets from our adapter are dropped (echo) */
- if (ether_addr_equal(header->addr2, priv->net_dev->dev_addr))
- return 0;
-
- /* {broad,multi}cast packets to our BSSID go through */
- if (is_multicast_ether_addr(header->addr1))
- return ether_addr_equal(header->addr3, priv->bssid);
-
- /* packets to our adapter go through */
- return ether_addr_equal(header->addr1,
- priv->net_dev->dev_addr);
-
- case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */
- /* packets from our adapter are dropped (echo) */
- if (ether_addr_equal(header->addr3, priv->net_dev->dev_addr))
- return 0;
-
- /* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(header->addr1))
- return ether_addr_equal(header->addr2, priv->bssid);
-
- /* packets to our adapter go through */
- return ether_addr_equal(header->addr1,
- priv->net_dev->dev_addr);
- }
-
- return 1;
-}
-
-#define IPW_PACKET_RETRY_TIME HZ
-
-static int is_duplicate_packet(struct ipw_priv *priv,
- struct libipw_hdr_4addr *header)
-{
- u16 sc = le16_to_cpu(header->seq_ctl);
- u16 seq = WLAN_GET_SEQ_SEQ(sc);
- u16 frag = WLAN_GET_SEQ_FRAG(sc);
- u16 *last_seq, *last_frag;
- unsigned long *last_time;
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- {
- struct list_head *p;
- struct ipw_ibss_seq *entry = NULL;
- u8 *mac = header->addr2;
- int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE;
-
- list_for_each(p, &priv->ibss_mac_hash[index]) {
- entry =
- list_entry(p, struct ipw_ibss_seq, list);
- if (ether_addr_equal(entry->mac, mac))
- break;
- }
- if (p == &priv->ibss_mac_hash[index]) {
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry) {
- IPW_ERROR
- ("Cannot malloc new mac entry\n");
- return 0;
- }
- memcpy(entry->mac, mac, ETH_ALEN);
- entry->seq_num = seq;
- entry->frag_num = frag;
- entry->packet_time = jiffies;
- list_add(&entry->list,
- &priv->ibss_mac_hash[index]);
- return 0;
- }
- last_seq = &entry->seq_num;
- last_frag = &entry->frag_num;
- last_time = &entry->packet_time;
- break;
- }
- case IW_MODE_INFRA:
- last_seq = &priv->last_seq_num;
- last_frag = &priv->last_frag_num;
- last_time = &priv->last_packet_time;
- break;
- default:
- return 0;
- }
- if ((*last_seq == seq) &&
- time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) {
- if (*last_frag == frag)
- goto drop;
- if (*last_frag + 1 != frag)
- /* out-of-order fragment */
- goto drop;
- } else
- *last_seq = seq;
-
- *last_frag = frag;
- *last_time = jiffies;
- return 0;
-
- drop:
- /* Comment this line now since we observed the card receives
- * duplicate packets but the FCTL_RETRY bit is not set in the
- * IBSS mode with fragmentation enabled.
- BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */
- return 1;
-}
-
-static void ipw_handle_mgmt_packet(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct sk_buff *skb = rxb->skb;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data;
- struct libipw_hdr_4addr *header = (struct libipw_hdr_4addr *)
- (skb->data + IPW_RX_FRAME_SIZE);
-
- libipw_rx_mgt(priv->ieee, header, stats);
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC &&
- ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
- IEEE80211_STYPE_PROBE_RESP) ||
- (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
- IEEE80211_STYPE_BEACON))) {
- if (ether_addr_equal(header->addr3, priv->bssid))
- ipw_add_station(priv, header->addr2);
- }
-
- if (priv->config & CFG_NET_STATS) {
- IPW_DEBUG_HC("sending stat packet\n");
-
- /* Set the size of the skb to the size of the full
- * ipw header and 802.11 frame */
- skb_put(skb, le16_to_cpu(pkt->u.frame.length) +
- IPW_RX_FRAME_SIZE);
-
- /* Advance past the ipw packet header to the 802.11 frame */
- skb_pull(skb, IPW_RX_FRAME_SIZE);
-
- /* Push the libipw_rx_stats before the 802.11 frame */
- memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats));
-
- skb->dev = priv->ieee->dev;
-
- /* Point raw at the libipw_stats */
- skb_reset_mac_header(skb);
-
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_80211_STATS);
- memset(skb->cb, 0, sizeof(rxb->skb->cb));
- netif_rx(skb);
- rxb->skb = NULL;
- }
-}
-
-/*
- * Main entry function for receiving a packet with 80211 headers. This
- * should be called when ever the FW has notified us that there is a new
- * skb in the receive queue.
- */
-static void ipw_rx(struct ipw_priv *priv)
-{
- struct ipw_rx_mem_buffer *rxb;
- struct ipw_rx_packet *pkt;
- struct libipw_hdr_4addr *header;
- u32 r, i;
- u8 network_packet;
- u8 fill_rx = 0;
-
- r = ipw_read32(priv, IPW_RX_READ_INDEX);
- ipw_read32(priv, IPW_RX_WRITE_INDEX);
- i = priv->rxq->read;
-
- if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2))
- fill_rx = 1;
-
- while (i != r) {
- rxb = priv->rxq->queue[i];
- if (unlikely(rxb == NULL)) {
- printk(KERN_CRIT "Queue not allocated!\n");
- break;
- }
- priv->rxq->queue[i] = NULL;
-
- dma_sync_single_for_cpu(&priv->pci_dev->dev, rxb->dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
-
- pkt = (struct ipw_rx_packet *)rxb->skb->data;
- IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n",
- pkt->header.message_type,
- pkt->header.rx_seq_num, pkt->header.control_bits);
-
- switch (pkt->header.message_type) {
- case RX_FRAME_TYPE: /* 802.11 frame */ {
- struct libipw_rx_stats stats = {
- .rssi = pkt->u.frame.rssi_dbm -
- IPW_RSSI_TO_DBM,
- .signal =
- pkt->u.frame.rssi_dbm -
- IPW_RSSI_TO_DBM + 0x100,
- .noise =
- le16_to_cpu(pkt->u.frame.noise),
- .rate = pkt->u.frame.rate,
- .mac_time = jiffies,
- .received_channel =
- pkt->u.frame.received_channel,
- .freq =
- (pkt->u.frame.
- control & (1 << 0)) ?
- LIBIPW_24GHZ_BAND :
- LIBIPW_52GHZ_BAND,
- .len = le16_to_cpu(pkt->u.frame.length),
- };
-
- if (stats.rssi != 0)
- stats.mask |= LIBIPW_STATMASK_RSSI;
- if (stats.signal != 0)
- stats.mask |= LIBIPW_STATMASK_SIGNAL;
- if (stats.noise != 0)
- stats.mask |= LIBIPW_STATMASK_NOISE;
- if (stats.rate != 0)
- stats.mask |= LIBIPW_STATMASK_RATE;
-
- priv->rx_packets++;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev))
- ipw_handle_promiscuous_rx(priv, rxb, &stats);
-#endif
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
-#ifdef CONFIG_IPW2200_RADIOTAP
-
- ipw_handle_data_packet_monitor(priv,
- rxb,
- &stats);
-#else
- ipw_handle_data_packet(priv, rxb,
- &stats);
-#endif
- break;
- }
-#endif
-
- header =
- (struct libipw_hdr_4addr *)(rxb->skb->
- data +
- IPW_RX_FRAME_SIZE);
- /* TODO: Check Ad-Hoc dest/source and make sure
- * that we are actually parsing these packets
- * correctly -- we should probably use the
- * frame control of the packet and disregard
- * the current iw_mode */
-
- network_packet =
- is_network_packet(priv, header);
- if (network_packet && priv->assoc_network) {
- priv->assoc_network->stats.rssi =
- stats.rssi;
- priv->exp_avg_rssi =
- exponential_average(priv->exp_avg_rssi,
- stats.rssi, DEPTH_RSSI);
- }
-
- IPW_DEBUG_RX("Frame: len=%u\n",
- le16_to_cpu(pkt->u.frame.length));
-
- if (le16_to_cpu(pkt->u.frame.length) <
- libipw_get_hdrlen(le16_to_cpu(
- header->frame_ctl))) {
- IPW_DEBUG_DROP
- ("Received packet is too small. "
- "Dropping.\n");
- priv->net_dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- break;
- }
-
- switch (WLAN_FC_GET_TYPE
- (le16_to_cpu(header->frame_ctl))) {
-
- case IEEE80211_FTYPE_MGMT:
- ipw_handle_mgmt_packet(priv, rxb,
- &stats);
- break;
-
- case IEEE80211_FTYPE_CTL:
- break;
-
- case IEEE80211_FTYPE_DATA:
- if (unlikely(!network_packet ||
- is_duplicate_packet(priv,
- header)))
- {
- IPW_DEBUG_DROP("Dropping: "
- "%pM, "
- "%pM, "
- "%pM\n",
- header->addr1,
- header->addr2,
- header->addr3);
- break;
- }
-
- ipw_handle_data_packet(priv, rxb,
- &stats);
-
- break;
- }
- break;
- }
-
- case RX_HOST_NOTIFICATION_TYPE:{
- IPW_DEBUG_RX
- ("Notification: subtype=%02X flags=%02X size=%d\n",
- pkt->u.notification.subtype,
- pkt->u.notification.flags,
- le16_to_cpu(pkt->u.notification.size));
- ipw_rx_notification(priv, &pkt->u.notification);
- break;
- }
-
- default:
- IPW_DEBUG_RX("Bad Rx packet of type %d\n",
- pkt->header.message_type);
- break;
- }
-
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, rxb->dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- list_add_tail(&rxb->list, &priv->rxq->rx_used);
-
- i = (i + 1) % RX_QUEUE_SIZE;
-
- /* If there are a lot of unsued frames, restock the Rx queue
- * so the ucode won't assert */
- if (fill_rx) {
- priv->rxq->read = i;
- ipw_rx_queue_replenish(priv);
- }
- }
-
- /* Backtrack one entry */
- priv->rxq->read = i;
- ipw_rx_queue_restock(priv);
-}
-
-#define DEFAULT_RTS_THRESHOLD 2304U
-#define MIN_RTS_THRESHOLD 1U
-#define MAX_RTS_THRESHOLD 2304U
-#define DEFAULT_BEACON_INTERVAL 100U
-#define DEFAULT_SHORT_RETRY_LIMIT 7U
-#define DEFAULT_LONG_RETRY_LIMIT 4U
-
-/*
- * ipw_sw_reset
- * @option: options to control different reset behaviour
- * 0 = reset everything except the 'disable' module_param
- * 1 = reset everything and print out driver info (for probe only)
- * 2 = reset everything
- */
-static int ipw_sw_reset(struct ipw_priv *priv, int option)
-{
- int band, modulation;
- int old_mode = priv->ieee->iw_mode;
-
- /* Initialize module parameter values here */
- priv->config = 0;
-
- /* We default to disabling the LED code as right now it causes
- * too many systems to lock up... */
- if (!led_support)
- priv->config |= CFG_NO_LED;
-
- if (associate)
- priv->config |= CFG_ASSOCIATE;
- else
- IPW_DEBUG_INFO("Auto associate disabled.\n");
-
- if (auto_create)
- priv->config |= CFG_ADHOC_CREATE;
- else
- IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
-
- priv->config &= ~CFG_STATIC_ESSID;
- priv->essid_len = 0;
- memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-
- if (disable && option) {
- priv->status |= STATUS_RF_KILL_SW;
- IPW_DEBUG_INFO("Radio disabled.\n");
- }
-
- if (default_channel != 0) {
- priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = default_channel;
- IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel);
- /* TODO: Validate that provided channel is in range */
- }
-#ifdef CONFIG_IPW2200_QOS
- ipw_qos_init(priv, qos_enable, qos_burst_enable,
- burst_duration_CCK, burst_duration_OFDM);
-#endif /* CONFIG_IPW2200_QOS */
-
- switch (network_mode) {
- case 1:
- priv->ieee->iw_mode = IW_MODE_ADHOC;
- priv->net_dev->type = ARPHRD_ETHER;
-
- break;
-#ifdef CONFIG_IPW2200_MONITOR
- case 2:
- priv->ieee->iw_mode = IW_MODE_MONITOR;
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
- break;
-#endif
- default:
- case 0:
- priv->net_dev->type = ARPHRD_ETHER;
- priv->ieee->iw_mode = IW_MODE_INFRA;
- break;
- }
-
- if (hwcrypto) {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 0;
- priv->ieee->host_decrypt = 0;
- priv->ieee->host_mc_decrypt = 0;
- }
- IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off");
-
- /* IPW2200/2915 is abled to do hardware fragmentation. */
- priv->ieee->host_open_frag = 0;
-
- if ((priv->pci_dev->device == 0x4223) ||
- (priv->pci_dev->device == 0x4224)) {
- if (option == 1)
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2915ABG Network "
- "Connection\n");
- priv->ieee->abg_true = 1;
- band = LIBIPW_52GHZ_BAND | LIBIPW_24GHZ_BAND;
- modulation = LIBIPW_OFDM_MODULATION |
- LIBIPW_CCK_MODULATION;
- priv->adapter = IPW_2915ABG;
- priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
- } else {
- if (option == 1)
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2200BG Network "
- "Connection\n");
-
- priv->ieee->abg_true = 0;
- band = LIBIPW_24GHZ_BAND;
- modulation = LIBIPW_OFDM_MODULATION |
- LIBIPW_CCK_MODULATION;
- priv->adapter = IPW_2200BG;
- priv->ieee->mode = IEEE_G | IEEE_B;
- }
-
- priv->ieee->freq_band = band;
- priv->ieee->modulation = modulation;
-
- priv->rates_mask = LIBIPW_DEFAULT_RATES_MASK;
-
- priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
- priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
-
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
- priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
- priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
-
- /* If power management is turned on, default to AC mode */
- priv->power_mode = IPW_POWER_AC;
- priv->tx_power = IPW_TX_POWER_DEFAULT;
-
- return old_mode == priv->ieee->iw_mode;
-}
-
-/*
- * This file defines the Wireless Extension handlers. It does not
- * define any methods of hardware manipulation and relies on the
- * functions defined in ipw_main to provide the HW interaction.
- *
- * The exception to this is the use of the ipw_get_ordinal()
- * function used to poll the hardware vs. making unnecessary calls.
- *
- */
-
-static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
-{
- if (channel == 0) {
- IPW_DEBUG_INFO("Setting channel to ANY (0)\n");
- priv->config &= ~CFG_STATIC_CHANNEL;
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- return 0;
- }
-
- priv->config |= CFG_STATIC_CHANNEL;
-
- if (priv->channel == channel) {
- IPW_DEBUG_INFO("Request to set channel to current value (%d)\n",
- channel);
- return 0;
- }
-
- IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel);
- priv->channel = channel;
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- int i;
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan abort triggered due to "
- "channel change.\n");
- ipw_abort_scan(priv);
- }
-
- for (i = 1000; i && (priv->status & STATUS_SCANNING); i--)
- udelay(10);
-
- if (priv->status & STATUS_SCANNING)
- IPW_DEBUG_SCAN("Still scanning...\n");
- else
- IPW_DEBUG_SCAN("Took %dms to abort current scan\n",
- 1000 - i);
-
- return 0;
- }
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- return 0;
-}
-
-static int ipw_wx_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct iw_freq *fwrq = &wrqu->freq;
- int ret = 0, i;
- u8 channel, flags;
- int band;
-
- if (fwrq->m == 0) {
- IPW_DEBUG_WX("SET Freq/Channel -> any\n");
- mutex_lock(&priv->mutex);
- ret = ipw_set_channel(priv, 0);
- mutex_unlock(&priv->mutex);
- return ret;
- }
- /* if setting by freq convert to channel */
- if (fwrq->e == 1) {
- channel = libipw_freq_to_channel(priv->ieee, fwrq->m);
- if (channel == 0)
- return -EINVAL;
- } else
- channel = fwrq->m;
-
- if (!(band = libipw_is_valid_channel(priv->ieee, channel)))
- return -EINVAL;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- i = libipw_channel_to_index(priv->ieee, channel);
- if (i == -1)
- return -EINVAL;
-
- flags = (band == LIBIPW_24GHZ_BAND) ?
- geo->bg[i].flags : geo->a[i].flags;
- if (flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n");
- return -EINVAL;
- }
- }
-
- IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
- mutex_lock(&priv->mutex);
- ret = ipw_set_channel(priv, channel);
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static int ipw_wx_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- wrqu->freq.e = 0;
-
- /* If we are associated, trying to associate, or have a statically
- * configured CHANNEL then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_CHANNEL ||
- priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) {
- int i;
-
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- wrqu->freq.e = 1;
-
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000;
- break;
-
- case LIBIPW_24GHZ_BAND:
- wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000;
- break;
-
- default:
- BUG();
- }
- } else
- wrqu->freq.m = 0;
-
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
- return 0;
-}
-
-static int ipw_wx_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
-
- switch (wrqu->mode) {
-#ifdef CONFIG_IPW2200_MONITOR
- case IW_MODE_MONITOR:
-#endif
- case IW_MODE_ADHOC:
- case IW_MODE_INFRA:
- break;
- case IW_MODE_AUTO:
- wrqu->mode = IW_MODE_INFRA;
- break;
- default:
- return -EINVAL;
- }
- if (wrqu->mode == priv->ieee->iw_mode)
- return 0;
-
- mutex_lock(&priv->mutex);
-
- ipw_sw_reset(priv, 0);
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- priv->net_dev->type = ARPHRD_ETHER;
-
- if (wrqu->mode == IW_MODE_MONITOR)
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Free the existing firmware and reset the fw_loaded
- * flag so ipw_load() will bring in the new firmware */
- free_firmware();
-
- priv->ieee->iw_mode = wrqu->mode;
-
- schedule_work(&priv->adapter_restart);
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->mode = priv->ieee->iw_mode;
- IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-/* Values are in microsecond */
-static const s32 timeout_duration[] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-
-static const s32 period_duration[] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
-static int ipw_wx_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_range *range = (struct iw_range *)extra;
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int i = 0, j;
-
- wrqu->data.length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- /* 54Mbs == ~27 Mb/s real (802.11g) */
- range->throughput = 27 * 1000 * 1000;
-
- range->max_qual.qual = 100;
- /* TODO: Find real max RSSI and stick here */
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
-
- range->avg_qual.qual = 70;
- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
- range->avg_qual.level = 0; /* FIXME to real average level */
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
- mutex_lock(&priv->mutex);
- range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
-
- for (i = 0; i < range->num_bitrates; i++)
- range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) *
- 500000;
-
- range->max_rts = DEFAULT_RTS_THRESHOLD;
- range->min_frag = MIN_FRAG_THRESHOLD;
- range->max_frag = MAX_FRAG_THRESHOLD;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- range->max_encoding_tokens = WEP_KEYS;
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
- i = 0;
- if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
- for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) {
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->bg[j].flags & LIBIPW_CH_PASSIVE_ONLY))
- continue;
-
- range->freq[i].i = geo->bg[j].channel;
- range->freq[i].m = geo->bg[j].freq * 100000;
- range->freq[i].e = 1;
- i++;
- }
- }
-
- if (priv->ieee->mode & IEEE_A) {
- for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) {
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->a[j].flags & LIBIPW_CH_PASSIVE_ONLY))
- continue;
-
- range->freq[i].i = geo->a[j].channel;
- range->freq[i].m = geo->a[j].freq * 100000;
- range->freq[i].e = 1;
- i++;
- }
- }
-
- range->num_channels = i;
- range->num_frequency = i;
-
- mutex_unlock(&priv->mutex);
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE;
-
- IPW_DEBUG_WX("GET Range\n");
- return 0;
-}
-
-static int ipw_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- return -EINVAL;
- mutex_lock(&priv->mutex);
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
- is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
- /* we disable mandatory BSSID association */
- IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
- priv->config &= ~CFG_STATIC_BSSID;
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- priv->config |= CFG_STATIC_BSSID;
- if (ether_addr_equal(priv->bssid, wrqu->ap_addr.sa_data)) {
- IPW_DEBUG_WX("BSSID set to current BSSID.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n",
- wrqu->ap_addr.sa_data);
-
- memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured BSSID then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_BSSID ||
- priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
- } else
- eth_zero_addr(wrqu->ap_addr.sa_data);
-
- IPW_DEBUG_WX("Getting WAP BSSID: %pM\n",
- wrqu->ap_addr.sa_data);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int length;
-
- mutex_lock(&priv->mutex);
-
- if (!wrqu->essid.flags)
- {
- IPW_DEBUG_WX("Setting ESSID to ANY\n");
- ipw_disassociate(priv);
- priv->config &= ~CFG_STATIC_ESSID;
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
-
- priv->config |= CFG_STATIC_ESSID;
-
- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)
- && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) {
- IPW_DEBUG_WX("ESSID set to current ESSID.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, extra, length);
-
- priv->essid_len = length;
- memcpy(priv->essid, extra, priv->essid_len);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured ESSID then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_ESSID ||
- priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_WX("Getting essid: '%*pE'\n",
- priv->essid_len, priv->essid);
- memcpy(extra, priv->essid, priv->essid_len);
- wrqu->essid.length = priv->essid_len;
- wrqu->essid.flags = 1; /* active */
- } else {
- IPW_DEBUG_WX("Getting essid: ANY\n");
- wrqu->essid.length = 0;
- wrqu->essid.flags = 0; /* active */
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
- if (wrqu->data.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
- mutex_lock(&priv->mutex);
- wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
- IPW_DEBUG_TRACE("<<\n");
- mutex_unlock(&priv->mutex);
- return 0;
-
-}
-
-static int ipw_wx_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- IPW_DEBUG_WX("Getting nick\n");
- mutex_lock(&priv->mutex);
- wrqu->data.length = strlen(priv->nick);
- memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value);
- IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value);
- mutex_lock(&priv->mutex);
-
- if (wrqu->sens.fixed == 0)
- {
- priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
- priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
- goto out;
- }
- if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) ||
- (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) {
- err = -EINVAL;
- goto out;
- }
-
- priv->roaming_threshold = wrqu->sens.value;
- priv->disassociate_threshold = 3*wrqu->sens.value;
- out:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->sens.fixed = 1;
- wrqu->sens.value = priv->roaming_threshold;
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET roaming threshold -> %s %d\n",
- wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
-
- return 0;
-}
-
-static int ipw_wx_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /* TODO: We should use semaphores or locks for access to priv */
- struct ipw_priv *priv = libipw_priv(dev);
- u32 target_rate = wrqu->bitrate.value;
- u32 fixed, mask;
-
- /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */
- /* value = X, fixed = 1 means only rate X */
- /* value = X, fixed = 0 means all rates lower equal X */
-
- if (target_rate == -1) {
- fixed = 0;
- mask = LIBIPW_DEFAULT_RATES_MASK;
- /* Now we should reassociate */
- goto apply;
- }
-
- mask = 0;
- fixed = wrqu->bitrate.fixed;
-
- if (target_rate == 1000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_1MB_MASK;
- if (target_rate == 1000000)
- goto apply;
-
- if (target_rate == 2000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_2MB_MASK;
- if (target_rate == 2000000)
- goto apply;
-
- if (target_rate == 5500000 || !fixed)
- mask |= LIBIPW_CCK_RATE_5MB_MASK;
- if (target_rate == 5500000)
- goto apply;
-
- if (target_rate == 6000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_6MB_MASK;
- if (target_rate == 6000000)
- goto apply;
-
- if (target_rate == 9000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_9MB_MASK;
- if (target_rate == 9000000)
- goto apply;
-
- if (target_rate == 11000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_11MB_MASK;
- if (target_rate == 11000000)
- goto apply;
-
- if (target_rate == 12000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_12MB_MASK;
- if (target_rate == 12000000)
- goto apply;
-
- if (target_rate == 18000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_18MB_MASK;
- if (target_rate == 18000000)
- goto apply;
-
- if (target_rate == 24000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_24MB_MASK;
- if (target_rate == 24000000)
- goto apply;
-
- if (target_rate == 36000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_36MB_MASK;
- if (target_rate == 36000000)
- goto apply;
-
- if (target_rate == 48000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_48MB_MASK;
- if (target_rate == 48000000)
- goto apply;
-
- if (target_rate == 54000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_54MB_MASK;
- if (target_rate == 54000000)
- goto apply;
-
- IPW_DEBUG_WX("invalid rate specified, returning error\n");
- return -EINVAL;
-
- apply:
- IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n",
- mask, fixed ? "fixed" : "sub-rates");
- mutex_lock(&priv->mutex);
- if (mask == LIBIPW_DEFAULT_RATES_MASK) {
- priv->config &= ~CFG_FIXED_RATE;
- ipw_set_fixed_rate(priv, priv->ieee->mode);
- } else
- priv->config |= CFG_FIXED_RATE;
-
- if (priv->rates_mask == mask) {
- IPW_DEBUG_WX("Mask set to current mask.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- priv->rates_mask = mask;
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->bitrate.value = priv->last_rate;
- wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0;
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
- return 0;
-}
-
-static int ipw_wx_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (wrqu->rts.disabled || !wrqu->rts.fixed)
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
- else {
- if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
- wrqu->rts.value > MAX_RTS_THRESHOLD) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
- priv->rts_threshold = wrqu->rts.value;
- }
-
- ipw_send_rts_threshold(priv, priv->rts_threshold);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET RTS Threshold -> %d\n", priv->rts_threshold);
- return 0;
-}
-
-static int ipw_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->rts.value = priv->rts_threshold;
- wrqu->rts.fixed = 0; /* no auto select */
- wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET RTS Threshold -> %d\n", wrqu->rts.value);
- return 0;
-}
-
-static int ipw_wx_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->mutex);
- if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) {
- err = -EINPROGRESS;
- goto out;
- }
-
- if (!wrqu->power.fixed)
- wrqu->power.value = IPW_TX_POWER_DEFAULT;
-
- if (wrqu->power.flags != IW_TXPOW_DBM) {
- err = -EINVAL;
- goto out;
- }
-
- if ((wrqu->power.value > IPW_TX_POWER_MAX) ||
- (wrqu->power.value < IPW_TX_POWER_MIN)) {
- err = -EINVAL;
- goto out;
- }
-
- priv->tx_power = wrqu->power.value;
- err = ipw_set_tx_power(priv);
- out:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->power.value = priv->tx_power;
- wrqu->power.fixed = 1;
- wrqu->power.flags = IW_TXPOW_DBM;
- wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET TX Power -> %s %d\n",
- wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
-
- return 0;
-}
-
-static int ipw_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (wrqu->frag.disabled || !wrqu->frag.fixed)
- priv->ieee->fts = DEFAULT_FTS;
- else {
- if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- priv->ieee->fts = wrqu->frag.value & ~0x1;
- }
-
- ipw_send_frag_threshold(priv, wrqu->frag.value);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET Frag Threshold -> %d\n", wrqu->frag.value);
- return 0;
-}
-
-static int ipw_wx_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->frag.value = priv->ieee->fts;
- wrqu->frag.fixed = 0; /* no auto select */
- wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
-
- return 0;
-}
-
-static int ipw_wx_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
- return -EINVAL;
-
- if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
- return 0;
-
- if (wrqu->retry.value < 0 || wrqu->retry.value >= 255)
- return -EINVAL;
-
- mutex_lock(&priv->mutex);
- if (wrqu->retry.flags & IW_RETRY_SHORT)
- priv->short_retry_limit = (u8) wrqu->retry.value;
- else if (wrqu->retry.flags & IW_RETRY_LONG)
- priv->long_retry_limit = (u8) wrqu->retry.value;
- else {
- priv->short_retry_limit = (u8) wrqu->retry.value;
- priv->long_retry_limit = (u8) wrqu->retry.value;
- }
-
- ipw_send_retry_limit(priv, priv->short_retry_limit,
- priv->long_retry_limit);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n",
- priv->short_retry_limit, priv->long_retry_limit);
- return 0;
-}
-
-static int ipw_wx_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- mutex_lock(&priv->mutex);
- wrqu->retry.disabled = 0;
-
- if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- wrqu->retry.value = priv->long_retry_limit;
- } else if (wrqu->retry.flags & IW_RETRY_SHORT) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
- wrqu->retry.value = priv->short_retry_limit;
- } else {
- wrqu->retry.flags = IW_RETRY_LIMIT;
- wrqu->retry.value = priv->short_retry_limit;
- }
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET retry -> %d\n", wrqu->retry.value);
-
- return 0;
-}
-
-static int ipw_wx_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_scan_req *req = (struct iw_scan_req *)extra;
- struct delayed_work *work = NULL;
-
- mutex_lock(&priv->mutex);
-
- priv->user_requested_scan = 1;
-
- if (wrqu->data.length == sizeof(struct iw_scan_req)) {
- if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- int len = min((int)req->essid_len,
- (int)sizeof(priv->direct_scan_ssid));
- memcpy(priv->direct_scan_ssid, req->essid, len);
- priv->direct_scan_ssid_len = len;
- work = &priv->request_direct_scan;
- } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
- work = &priv->request_passive_scan;
- }
- } else {
- /* Normal active broadcast scan */
- work = &priv->request_scan;
- }
-
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("Start scan\n");
-
- schedule_delayed_work(work, 0);
-
- return 0;
-}
-
-static int ipw_wx_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
-}
-
-static int ipw_wx_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int ret;
- u32 cap = priv->capability;
-
- mutex_lock(&priv->mutex);
- ret = libipw_wx_set_encode(priv->ieee, info, wrqu, key);
-
- /* In IBSS mode, we need to notify the firmware to update
- * the beacon info after we changed the capability. */
- if (cap != priv->capability &&
- priv->ieee->iw_mode == IW_MODE_ADHOC &&
- priv->status & STATUS_ASSOCIATED)
- ipw_disassociate(priv);
-
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static int ipw_wx_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err;
- mutex_lock(&priv->mutex);
- if (wrqu->power.disabled) {
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
- IPW_DEBUG_WX("SET Power Management Mode -> off\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitly state all */
- break;
- default: /* Otherwise we don't support it */
- IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
- wrqu->power.flags);
- mutex_unlock(&priv->mutex);
- return -EOPNOTSUPP;
- }
-
- /* If the user hasn't specified a power management mode yet, default
- * to BATTERY */
- if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC)
- priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
- else
- priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
-
- err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
-
- IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- wrqu->power.disabled = 1;
- else
- wrqu->power.disabled = 0;
-
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
-
- return 0;
-}
-
-static int ipw_wx_set_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- int err;
-
- mutex_lock(&priv->mutex);
- if ((mode < 1) || (mode > IPW_POWER_LIMIT))
- mode = IPW_POWER_AC;
-
- if (IPW_POWER_LEVEL(priv->power_mode) != mode) {
- err = ipw_send_power_mode(priv, mode);
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
- priv->power_mode = IPW_POWER_ENABLED | mode;
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#define MAX_WX_STRING 80
-static int ipw_wx_get_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int level = IPW_POWER_LEVEL(priv->power_mode);
- char *p = extra;
-
- p += scnprintf(p, MAX_WX_STRING, "Power save level: %d ", level);
-
- switch (level) {
- case IPW_POWER_AC:
- p += scnprintf(p, MAX_WX_STRING - (p - extra), "(AC)");
- break;
- case IPW_POWER_BATTERY:
- p += scnprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)");
- break;
- default:
- p += scnprintf(p, MAX_WX_STRING - (p - extra),
- "(Timeout %dms, Period %dms)",
- timeout_duration[level - 1] / 1000,
- period_duration[level - 1] / 1000);
- }
-
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- p += scnprintf(p, MAX_WX_STRING - (p - extra), " OFF");
-
- wrqu->data.length = p - extra + 1;
-
- return 0;
-}
-
-static int ipw_wx_set_wireless_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- u8 band = 0, modulation = 0;
-
- if (mode == 0 || mode & ~IEEE_MODE_MASK) {
- IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
- return -EINVAL;
- }
- mutex_lock(&priv->mutex);
- if (priv->adapter == IPW_2915ABG) {
- priv->ieee->abg_true = 1;
- if (mode & IEEE_A) {
- band |= LIBIPW_52GHZ_BAND;
- modulation |= LIBIPW_OFDM_MODULATION;
- } else
- priv->ieee->abg_true = 0;
- } else {
- if (mode & IEEE_A) {
- IPW_WARNING("Attempt to set 2200BG into "
- "802.11a mode\n");
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- priv->ieee->abg_true = 0;
- }
-
- if (mode & IEEE_B) {
- band |= LIBIPW_24GHZ_BAND;
- modulation |= LIBIPW_CCK_MODULATION;
- } else
- priv->ieee->abg_true = 0;
-
- if (mode & IEEE_G) {
- band |= LIBIPW_24GHZ_BAND;
- modulation |= LIBIPW_OFDM_MODULATION;
- } else
- priv->ieee->abg_true = 0;
-
- priv->ieee->mode = mode;
- priv->ieee->freq_band = band;
- priv->ieee->modulation = modulation;
- init_supported_rates(priv, &priv->rates);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n");
- if (!ipw_disassociate(priv)) {
- ipw_send_supported_rates(priv, &priv->rates);
- ipw_associate(priv);
- }
-
- /* Update the band LEDs */
- ipw_led_band_on(priv);
-
- IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
- mode & IEEE_A ? 'a' : '.',
- mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_wireless_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- switch (priv->ieee->mode) {
- case IEEE_A:
- strncpy(extra, "802.11a (1)", MAX_WX_STRING);
- break;
- case IEEE_B:
- strncpy(extra, "802.11b (2)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_B:
- strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
- break;
- case IEEE_G:
- strncpy(extra, "802.11g (4)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_G:
- strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
- break;
- case IEEE_B | IEEE_G:
- strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_B | IEEE_G:
- strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
- break;
- default:
- strncpy(extra, "unknown", MAX_WX_STRING);
- break;
- }
- extra[MAX_WX_STRING - 1] = '\0';
-
- IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
-
- wrqu->data.length = strlen(extra) + 1;
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-static int ipw_wx_set_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- mutex_lock(&priv->mutex);
- /* Switching from SHORT -> LONG requires a disassociation */
- if (mode == 1) {
- if (!(priv->config & CFG_PREAMBLE_LONG)) {
- priv->config |= CFG_PREAMBLE_LONG;
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC
- ("[re]association triggered due to preamble change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
- }
- goto done;
- }
-
- if (mode == 0) {
- priv->config &= ~CFG_PREAMBLE_LONG;
- goto done;
- }
- mutex_unlock(&priv->mutex);
- return -EINVAL;
-
- done:
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_PREAMBLE_LONG)
- snprintf(wrqu->name, IFNAMSIZ, "long (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_MONITOR
-static int ipw_wx_set_monitor(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int *parms = (int *)extra;
- int enable = (parms[0] > 0);
- mutex_lock(&priv->mutex);
- IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
- if (enable) {
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
- schedule_work(&priv->adapter_restart);
- }
-
- ipw_set_channel(priv, parms[1]);
- } else {
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- mutex_unlock(&priv->mutex);
- return 0;
- }
- priv->net_dev->type = ARPHRD_ETHER;
- schedule_work(&priv->adapter_restart);
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#endif /* CONFIG_IPW2200_MONITOR */
-
-static int ipw_wx_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- IPW_DEBUG_WX("RESET\n");
- schedule_work(&priv->adapter_restart);
- return 0;
-}
-
-static int ipw_wx_sw_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- union iwreq_data wrqu_sec = {
- .encoding = {
- .flags = IW_ENCODE_DISABLED,
- },
- };
- int ret;
-
- IPW_DEBUG_WX("SW_RESET\n");
-
- mutex_lock(&priv->mutex);
-
- ret = ipw_sw_reset(priv, 2);
- if (!ret) {
- free_firmware();
- ipw_adapter_restart(priv);
- }
-
- /* The SW reset bit might have been toggled on by the 'disable'
- * module parameter, so take appropriate action */
- ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW);
-
- mutex_unlock(&priv->mutex);
- libipw_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
- mutex_lock(&priv->mutex);
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- /* Configuration likely changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to sw "
- "reset.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
- }
-
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-/* Rebase the WE IOCTLs to zero for the handler array */
-static iw_handler ipw_wx_handlers[] = {
- IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
- IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq),
- IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode),
- IW_HANDLER(SIOCGIWMODE, ipw_wx_get_mode),
- IW_HANDLER(SIOCSIWSENS, ipw_wx_set_sens),
- IW_HANDLER(SIOCGIWSENS, ipw_wx_get_sens),
- IW_HANDLER(SIOCGIWRANGE, ipw_wx_get_range),
- IW_HANDLER(SIOCSIWAP, ipw_wx_set_wap),
- IW_HANDLER(SIOCGIWAP, ipw_wx_get_wap),
- IW_HANDLER(SIOCSIWSCAN, ipw_wx_set_scan),
- IW_HANDLER(SIOCGIWSCAN, ipw_wx_get_scan),
- IW_HANDLER(SIOCSIWESSID, ipw_wx_set_essid),
- IW_HANDLER(SIOCGIWESSID, ipw_wx_get_essid),
- IW_HANDLER(SIOCSIWNICKN, ipw_wx_set_nick),
- IW_HANDLER(SIOCGIWNICKN, ipw_wx_get_nick),
- IW_HANDLER(SIOCSIWRATE, ipw_wx_set_rate),
- IW_HANDLER(SIOCGIWRATE, ipw_wx_get_rate),
- IW_HANDLER(SIOCSIWRTS, ipw_wx_set_rts),
- IW_HANDLER(SIOCGIWRTS, ipw_wx_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ipw_wx_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ipw_wx_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, ipw_wx_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, ipw_wx_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, ipw_wx_set_retry),
- IW_HANDLER(SIOCGIWRETRY, ipw_wx_get_retry),
- IW_HANDLER(SIOCSIWENCODE, ipw_wx_set_encode),
- IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode),
- IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power),
- IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie),
- IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie),
- IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme),
- IW_HANDLER(SIOCSIWAUTH, ipw_wx_set_auth),
- IW_HANDLER(SIOCGIWAUTH, ipw_wx_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, ipw_wx_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, ipw_wx_get_encodeext),
-};
-
-enum {
- IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV,
- IPW_PRIV_GET_POWER,
- IPW_PRIV_SET_MODE,
- IPW_PRIV_GET_MODE,
- IPW_PRIV_SET_PREAMBLE,
- IPW_PRIV_GET_PREAMBLE,
- IPW_PRIV_RESET,
- IPW_PRIV_SW_RESET,
-#ifdef CONFIG_IPW2200_MONITOR
- IPW_PRIV_SET_MONITOR,
-#endif
-};
-
-static struct iw_priv_args ipw_priv_args[] = {
- {
- .cmd = IPW_PRIV_SET_POWER,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_power"},
- {
- .cmd = IPW_PRIV_GET_POWER,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_power"},
- {
- .cmd = IPW_PRIV_SET_MODE,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_mode"},
- {
- .cmd = IPW_PRIV_GET_MODE,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_mode"},
- {
- .cmd = IPW_PRIV_SET_PREAMBLE,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_preamble"},
- {
- .cmd = IPW_PRIV_GET_PREAMBLE,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ,
- .name = "get_preamble"},
- {
- IPW_PRIV_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
- {
- IPW_PRIV_SW_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"},
-#ifdef CONFIG_IPW2200_MONITOR
- {
- IPW_PRIV_SET_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
-#endif /* CONFIG_IPW2200_MONITOR */
-};
-
-static iw_handler ipw_priv_handler[] = {
- ipw_wx_set_powermode,
- ipw_wx_get_powermode,
- ipw_wx_set_wireless_mode,
- ipw_wx_get_wireless_mode,
- ipw_wx_set_preamble,
- ipw_wx_get_preamble,
- ipw_wx_reset,
- ipw_wx_sw_reset,
-#ifdef CONFIG_IPW2200_MONITOR
- ipw_wx_set_monitor,
-#endif
-};
-
-static const struct iw_handler_def ipw_wx_handler_def = {
- .standard = ipw_wx_handlers,
- .num_standard = ARRAY_SIZE(ipw_wx_handlers),
- .num_private = ARRAY_SIZE(ipw_priv_handler),
- .num_private_args = ARRAY_SIZE(ipw_priv_args),
- .private = ipw_priv_handler,
- .private_args = ipw_priv_args,
- .get_wireless_stats = ipw_get_wireless_stats,
-};
-
-/*
- * Get wireless statistics.
- * Called by /proc/net/wireless
- * Also called by SIOCGIWSTATS
- */
-static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_statistics *wstats;
-
- wstats = &priv->wstats;
-
- /* if hw is disabled, then ipw_get_ordinal() can't be called.
- * netdev->get_wireless_stats seems to be called before fw is
- * initialized. STATUS_ASSOCIATED will only be set if the hw is up
- * and associated; if not associcated, the values are all meaningless
- * anyway, so set them all to NULL and INVALID */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->miss.beacon = 0;
- wstats->discard.retries = 0;
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
- return wstats;
- }
-
- wstats->qual.qual = priv->quality;
- wstats->qual.level = priv->exp_avg_rssi;
- wstats->qual.noise = priv->exp_avg_noise;
- wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM;
-
- wstats->miss.beacon = average_value(&priv->average_missed_beacons);
- wstats->discard.retries = priv->last_tx_failures;
- wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable;
-
-/* if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len))
- goto fail_get_ordinal;
- wstats->discard.retries += tx_retry; */
-
- return wstats;
-}
-
-/* net device stuff */
-
-static void init_sys_config(struct ipw_sys_config *sys_config)
-{
- memset(sys_config, 0, sizeof(struct ipw_sys_config));
- sys_config->bt_coexistence = 0;
- sys_config->answer_broadcast_ssid_probe = 0;
- sys_config->accept_all_data_frames = 0;
- sys_config->accept_non_directed_frames = 1;
- sys_config->exclude_unicast_unencrypted = 0;
- sys_config->disable_unicast_decryption = 1;
- sys_config->exclude_multicast_unencrypted = 0;
- sys_config->disable_multicast_decryption = 1;
- if (antenna < CFG_SYS_ANTENNA_BOTH || antenna > CFG_SYS_ANTENNA_B)
- antenna = CFG_SYS_ANTENNA_BOTH;
- sys_config->antenna_diversity = antenna;
- sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */
- sys_config->dot11g_auto_detection = 0;
- sys_config->enable_cts_to_self = 0;
- sys_config->bt_coexist_collision_thr = 0;
- sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */
- sys_config->silence_threshold = 0x1e;
-}
-
-static int ipw_net_open(struct net_device *dev)
-{
- IPW_DEBUG_INFO("dev->open\n");
- netif_start_queue(dev);
- return 0;
-}
-
-static int ipw_net_stop(struct net_device *dev)
-{
- IPW_DEBUG_INFO("dev->close\n");
- netif_stop_queue(dev);
- return 0;
-}
-
-/*
-todo:
-
-modify to send one tfd per fragment instead of using chunking. otherwise
-we need to heavily modify the libipw_skb_to_txb.
-*/
-
-static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb,
- int pri)
-{
- struct libipw_hdr_3addrqos *hdr = (struct libipw_hdr_3addrqos *)
- txb->fragments[0]->data;
- int i = 0;
- struct tfd_frame *tfd;
-#ifdef CONFIG_IPW2200_QOS
- int tx_id = ipw_get_tx_queue_number(priv, pri);
- struct clx2_tx_queue *txq = &priv->txq[tx_id];
-#else
- struct clx2_tx_queue *txq = &priv->txq[0];
-#endif
- struct clx2_queue *q = &txq->q;
- u8 id, hdr_len, unicast;
- int fc;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- goto drop;
-
- hdr_len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- unicast = !is_multicast_ether_addr(hdr->addr1);
- id = ipw_find_station(priv, hdr->addr1);
- if (id == IPW_INVALID_STATION) {
- id = ipw_add_station(priv, hdr->addr1);
- if (id == IPW_INVALID_STATION) {
- IPW_WARNING("Attempt to send data to "
- "invalid cell: %pM\n",
- hdr->addr1);
- goto drop;
- }
- }
- break;
-
- case IW_MODE_INFRA:
- default:
- unicast = !is_multicast_ether_addr(hdr->addr3);
- id = 0;
- break;
- }
-
- tfd = &txq->bd[q->first_empty];
- txq->txb[q->first_empty] = txb;
- memset(tfd, 0, sizeof(*tfd));
- tfd->u.data.station_number = id;
-
- tfd->control_flags.message_type = TX_FRAME_TYPE;
- tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
-
- tfd->u.data.cmd_id = DINO_CMD_TX;
- tfd->u.data.len = cpu_to_le16(txb->payload_size);
-
- if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK;
- else
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM;
-
- if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE)
- tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE;
-
- fc = le16_to_cpu(hdr->frame_ctl);
- hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS);
-
- memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len);
-
- if (likely(unicast))
- tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
-
- if (txb->encrypted && !priv->ieee->host_encrypt) {
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- /* XXX: ACK flag must be set for CCMP even if it
- * is a multicast/broadcast packet, because CCMP
- * group communication encrypted by GTK is
- * actually done by the AP. */
- if (!unicast)
- tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
-
- tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM;
- tfd->u.data.key_index = 0;
- tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE;
- break;
- case SEC_LEVEL_2:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP;
- tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE;
- break;
- case SEC_LEVEL_1:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx;
- if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <=
- 40)
- tfd->u.data.key_index |= DCT_WEP_KEY_64Bit;
- else
- tfd->u.data.key_index |= DCT_WEP_KEY_128Bit;
- break;
- case SEC_LEVEL_0:
- break;
- default:
- printk(KERN_ERR "Unknown security level %d\n",
- priv->ieee->sec.level);
- break;
- }
- } else
- /* No hardware encryption */
- tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP;
-
-#ifdef CONFIG_IPW2200_QOS
- if (fc & IEEE80211_STYPE_QOS_DATA)
- ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data));
-#endif /* CONFIG_IPW2200_QOS */
-
- /* payload */
- tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2),
- txb->nr_frags));
- IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n",
- txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks));
- for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) {
- IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n",
- i, le32_to_cpu(tfd->u.data.num_chunks),
- txb->fragments[i]->len - hdr_len);
- IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n",
- i, tfd->u.data.num_chunks,
- txb->fragments[i]->len - hdr_len);
- printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len,
- txb->fragments[i]->len - hdr_len);
-
- tfd->u.data.chunk_ptr[i] =
- cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
- txb->fragments[i]->data + hdr_len,
- txb->fragments[i]->len - hdr_len,
- DMA_TO_DEVICE));
- tfd->u.data.chunk_len[i] =
- cpu_to_le16(txb->fragments[i]->len - hdr_len);
- }
-
- if (i != txb->nr_frags) {
- struct sk_buff *skb;
- u16 remaining_bytes = 0;
- int j;
-
- for (j = i; j < txb->nr_frags; j++)
- remaining_bytes += txb->fragments[j]->len - hdr_len;
-
- printk(KERN_INFO "Trying to reallocate for %d bytes\n",
- remaining_bytes);
- skb = alloc_skb(remaining_bytes, GFP_ATOMIC);
- if (skb != NULL) {
- tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes);
- for (j = i; j < txb->nr_frags; j++) {
- int size = txb->fragments[j]->len - hdr_len;
-
- printk(KERN_INFO "Adding frag %d %d...\n",
- j, size);
- skb_put_data(skb,
- txb->fragments[j]->data + hdr_len,
- size);
- }
- dev_kfree_skb_any(txb->fragments[i]);
- txb->fragments[i] = skb;
- tfd->u.data.chunk_ptr[i] =
- cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
- skb->data,
- remaining_bytes,
- DMA_TO_DEVICE));
-
- le32_add_cpu(&tfd->u.data.num_chunks, 1);
- }
- }
-
- /* kick DMA */
- q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
- ipw_write32(priv, q->reg_w, q->first_empty);
-
- if (ipw_tx_queue_space(q) < q->high_mark)
- netif_stop_queue(priv->net_dev);
-
- return NETDEV_TX_OK;
-
- drop:
- IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
- libipw_txb_free(txb);
- return NETDEV_TX_OK;
-}
-
-static int ipw_net_is_queue_full(struct net_device *dev, int pri)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-#ifdef CONFIG_IPW2200_QOS
- int tx_id = ipw_get_tx_queue_number(priv, pri);
- struct clx2_tx_queue *txq = &priv->txq[tx_id];
-#else
- struct clx2_tx_queue *txq = &priv->txq[0];
-#endif /* CONFIG_IPW2200_QOS */
-
- if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark)
- return 1;
-
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
- struct libipw_txb *txb)
-{
- struct libipw_rx_stats dummystats;
- struct ieee80211_hdr *hdr;
- u8 n;
- u16 filter = priv->prom_priv->filter;
- int hdr_only = 0;
-
- if (filter & IPW_PROM_NO_TX)
- return;
-
- memset(&dummystats, 0, sizeof(dummystats));
-
- /* Filtering of fragment chains is done against the first fragment */
- hdr = (void *)txb->fragments[0]->data;
- if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_MGMT)
- return;
- if (filter & IPW_PROM_MGMT_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_CTL)
- return;
- if (filter & IPW_PROM_CTL_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_DATA)
- return;
- if (filter & IPW_PROM_DATA_HEADER_ONLY)
- hdr_only = 1;
- }
-
- for(n=0; n<txb->nr_frags; ++n) {
- struct sk_buff *src = txb->fragments[n];
- struct sk_buff *dst;
- struct ieee80211_radiotap_header *rt_hdr;
- int len;
-
- if (hdr_only) {
- hdr = (void *)src->data;
- len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
- } else
- len = src->len;
-
- dst = alloc_skb(len + sizeof(*rt_hdr) + sizeof(u16)*2, GFP_ATOMIC);
- if (!dst)
- continue;
-
- rt_hdr = skb_put(dst, sizeof(*rt_hdr));
-
- rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION;
- rt_hdr->it_pad = 0;
- rt_hdr->it_present = 0; /* after all, it's just an idea */
- rt_hdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL);
-
- *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(
- ieee80211chan2mhz(priv->channel));
- if (priv->channel > 14) /* 802.11a */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ);
- else if (priv->ieee->mode == IEEE_B) /* 802.11b */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ);
- else /* 802.11g */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_2GHZ);
-
- rt_hdr->it_len = cpu_to_le16(dst->len);
-
- skb_copy_from_linear_data(src, skb_put(dst, len), len);
-
- if (!libipw_rx(priv->prom_priv->ieee, dst, &dummystats))
- dev_kfree_skb_any(dst);
- }
-}
-#endif
-
-static netdev_tx_t ipw_net_hard_start_xmit(struct libipw_txb *txb,
- struct net_device *dev, int pri)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- unsigned long flags;
- netdev_tx_t ret;
-
- IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
- spin_lock_irqsave(&priv->lock, flags);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (rtap_iface && netif_running(priv->prom_net_dev))
- ipw_handle_promiscuous_tx(priv, txb);
-#endif
-
- ret = ipw_tx_skb(priv, txb, pri);
- if (ret == NETDEV_TX_OK)
- __ipw_led_activity_on(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return ret;
-}
-
-static void ipw_net_set_multicast_list(struct net_device *dev)
-{
-
-}
-
-static int ipw_net_set_mac_address(struct net_device *dev, void *p)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct sockaddr *addr = p;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
- mutex_lock(&priv->mutex);
- priv->config |= CFG_CUSTOM_MAC;
- memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
- printk(KERN_INFO "%s: Setting MAC to %pM\n",
- priv->net_dev->name, priv->mac_addr);
- schedule_work(&priv->adapter_restart);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static void ipw_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct ipw_priv *p = libipw_priv(dev);
- char vers[64];
- char date[32];
- u32 len;
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
-
- len = sizeof(vers);
- ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len);
- len = sizeof(date);
- ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len);
-
- snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)",
- vers, date);
- strscpy(info->bus_info, pci_name(p->pci_dev),
- sizeof(info->bus_info));
-}
-
-static u32 ipw_ethtool_get_link(struct net_device *dev)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return (priv->status & STATUS_ASSOCIATED) != 0;
-}
-
-static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
-{
- return IPW_EEPROM_IMAGE_SIZE;
-}
-
-static int ipw_ethtool_get_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 * bytes)
-{
- struct ipw_priv *p = libipw_priv(dev);
-
- if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
- return -EINVAL;
- mutex_lock(&p->mutex);
- memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len);
- mutex_unlock(&p->mutex);
- return 0;
-}
-
-static int ipw_ethtool_set_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 * bytes)
-{
- struct ipw_priv *p = libipw_priv(dev);
- int i;
-
- if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
- return -EINVAL;
- mutex_lock(&p->mutex);
- memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len);
- for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
- ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]);
- mutex_unlock(&p->mutex);
- return 0;
-}
-
-static const struct ethtool_ops ipw_ethtool_ops = {
- .get_link = ipw_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
- .get_eeprom_len = ipw_ethtool_get_eeprom_len,
- .get_eeprom = ipw_ethtool_get_eeprom,
- .set_eeprom = ipw_ethtool_set_eeprom,
-};
-
-static irqreturn_t ipw_isr(int irq, void *data)
-{
- struct ipw_priv *priv = data;
- u32 inta, inta_mask;
-
- if (!priv)
- return IRQ_NONE;
-
- spin_lock(&priv->irq_lock);
-
- if (!(priv->status & STATUS_INT_ENABLED)) {
- /* IRQ is disabled */
- goto none;
- }
-
- inta = ipw_read32(priv, IPW_INTA_RW);
- inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n");
- goto none;
- }
-
- if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) {
- /* Shared interrupt */
- goto none;
- }
-
- /* tell the device to stop sending interrupts */
- __ipw_disable_interrupts(priv);
-
- /* ack current interrupts */
- inta &= (IPW_INTA_MASK_ALL & inta_mask);
- ipw_write32(priv, IPW_INTA_RW, inta);
-
- /* Cache INTA value for our tasklet */
- priv->isr_inta = inta;
-
- tasklet_schedule(&priv->irq_tasklet);
-
- spin_unlock(&priv->irq_lock);
-
- return IRQ_HANDLED;
- none:
- spin_unlock(&priv->irq_lock);
- return IRQ_NONE;
-}
-
-static void ipw_rf_kill(void *adapter)
-{
- struct ipw_priv *priv = adapter;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- goto exit_unlock;
- }
-
- /* RF Kill is now disabled, so bring the device back up */
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
- "device\n");
-
- /* we can not do an adapter restart while inside an irq lock */
- schedule_work(&priv->adapter_restart);
- } else
- IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
- "enabled\n");
-
- exit_unlock:
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_rf_kill(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, rf_kill.work);
- mutex_lock(&priv->mutex);
- ipw_rf_kill(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_link_up(struct ipw_priv *priv)
-{
- priv->last_seq_num = -1;
- priv->last_frag_num = -1;
- priv->last_packet_time = 0;
-
- netif_carrier_on(priv->net_dev);
-
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- ipw_reset_stats(priv);
- /* Ensure the rate is updated immediately */
- priv->last_rate = ipw_get_current_rate(priv);
- ipw_gather_stats(priv);
- ipw_led_link_up(priv);
- notify_wx_assoc_event(priv);
-
- if (priv->config & CFG_BACKGROUND_SCAN)
- schedule_delayed_work(&priv->request_scan, HZ);
-}
-
-static void ipw_bg_link_up(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, link_up);
- mutex_lock(&priv->mutex);
- ipw_link_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_link_down(struct ipw_priv *priv)
-{
- ipw_led_link_down(priv);
- netif_carrier_off(priv->net_dev);
- notify_wx_assoc_event(priv);
-
- /* Cancel any queued work ... */
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->adhoc_check);
- cancel_delayed_work(&priv->gather_stats);
-
- ipw_reset_stats(priv);
-
- if (!(priv->status & STATUS_EXIT_PENDING)) {
- /* Queue up another scan... */
- schedule_delayed_work(&priv->request_scan, 0);
- } else
- cancel_delayed_work(&priv->scan_event);
-}
-
-static void ipw_bg_link_down(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, link_down);
- mutex_lock(&priv->mutex);
- ipw_link_down(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_setup_deferred_work(struct ipw_priv *priv)
-{
- init_waitqueue_head(&priv->wait_command_queue);
- init_waitqueue_head(&priv->wait_state);
-
- INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check);
- INIT_WORK(&priv->associate, ipw_bg_associate);
- INIT_WORK(&priv->disassociate, ipw_bg_disassociate);
- INIT_WORK(&priv->system_config, ipw_system_config);
- INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish);
- INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart);
- INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill);
- INIT_WORK(&priv->up, ipw_bg_up);
- INIT_WORK(&priv->down, ipw_bg_down);
- INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
- INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan);
- INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
- INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
- INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
- INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
- INIT_WORK(&priv->roam, ipw_bg_roam);
- INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check);
- INIT_WORK(&priv->link_up, ipw_bg_link_up);
- INIT_WORK(&priv->link_down, ipw_bg_link_down);
- INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on);
- INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off);
- INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off);
- INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network);
-
-#ifdef CONFIG_IPW2200_QOS
- INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate);
-#endif /* CONFIG_IPW2200_QOS */
-
- tasklet_setup(&priv->irq_tasklet, ipw_irq_tasklet);
-}
-
-static void shim__set_security(struct net_device *dev,
- struct libipw_security *sec)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int i;
- for (i = 0; i < 4; i++) {
- if (sec->flags & (1 << i)) {
- priv->ieee->sec.encode_alg[i] = sec->encode_alg[i];
- priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
- if (sec->key_sizes[i] == 0)
- priv->ieee->sec.flags &= ~(1 << i);
- else {
- memcpy(priv->ieee->sec.keys[i], sec->keys[i],
- sec->key_sizes[i]);
- priv->ieee->sec.flags |= (1 << i);
- }
- priv->status |= STATUS_SECURITY_UPDATED;
- } else if (sec->level != SEC_LEVEL_1)
- priv->ieee->sec.flags &= ~(1 << i);
- }
-
- if (sec->flags & SEC_ACTIVE_KEY) {
- priv->ieee->sec.active_key = sec->active_key;
- priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- } else
- priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
-
- if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->ieee->sec.auth_mode != sec->auth_mode)) {
- priv->ieee->sec.auth_mode = sec->auth_mode;
- priv->ieee->sec.flags |= SEC_AUTH_MODE;
- if (sec->auth_mode == WLAN_AUTH_SHARED_KEY)
- priv->capability |= CAP_SHARED_KEY;
- else
- priv->capability &= ~CAP_SHARED_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
- priv->ieee->sec.flags |= SEC_ENABLED;
- priv->ieee->sec.enabled = sec->enabled;
- priv->status |= STATUS_SECURITY_UPDATED;
- if (sec->enabled)
- priv->capability |= CAP_PRIVACY_ON;
- else
- priv->capability &= ~CAP_PRIVACY_ON;
- }
-
- if (sec->flags & SEC_ENCRYPT)
- priv->ieee->sec.encrypt = sec->encrypt;
-
- if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
- priv->ieee->sec.level = sec->level;
- priv->ieee->sec.flags |= SEC_LEVEL;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT))
- ipw_set_hwcrypto_keys(priv);
-
- /* To match current functionality of ipw2100 (which works well w/
- * various supplicants, we don't force a disassociate if the
- * privacy capability changes ... */
-#if 0
- if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) &&
- (((priv->assoc_request.capability &
- cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && !sec->enabled) ||
- (!(priv->assoc_request.capability &
- cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && sec->enabled))) {
- IPW_DEBUG_ASSOC("Disassociating due to capability "
- "change.\n");
- ipw_disassociate(priv);
- }
-#endif
-}
-
-static int init_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *rates)
-{
- /* TODO: Mask out rates based on priv->rates_mask */
-
- memset(rates, 0, sizeof(*rates));
- /* configure supported rates */
- switch (priv->ieee->freq_band) {
- case LIBIPW_52GHZ_BAND:
- rates->ieee_mode = IPW_A_MODE;
- rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_OFDM_DEFAULT_RATES_MASK);
- break;
-
- default: /* Mixed or 2.4Ghz */
- rates->ieee_mode = IPW_G_MODE;
- rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_cck_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_CCK_DEFAULT_RATES_MASK);
- if (priv->ieee->modulation & LIBIPW_OFDM_MODULATION) {
- ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_OFDM_DEFAULT_RATES_MASK);
- }
- break;
- }
-
- return 0;
-}
-
-static int ipw_config(struct ipw_priv *priv)
-{
- /* This is only called from ipw_up, which resets/reloads the firmware
- so, we don't need to first disable the card before we configure
- it */
- if (ipw_set_tx_power(priv))
- goto error;
-
- /* initialize adapter address */
- if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr))
- goto error;
-
- /* set basic system config settings */
- init_sys_config(&priv->sys_config);
-
- /* Support Bluetooth if we have BT h/w on board, and user wants to.
- * Does not support BT priority yet (don't abort or defer our Tx) */
- if (bt_coexist) {
- unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY];
-
- if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG)
- priv->sys_config.bt_coexistence
- |= CFG_BT_COEXISTENCE_SIGNAL_CHNL;
- if (bt_caps & EEPROM_SKU_CAP_BT_OOB)
- priv->sys_config.bt_coexistence
- |= CFG_BT_COEXISTENCE_OOB;
- }
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
- }
-#endif
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->sys_config.answer_broadcast_ssid_probe = 1;
- else
- priv->sys_config.answer_broadcast_ssid_probe = 0;
-
- if (ipw_send_system_config(priv))
- goto error;
-
- init_supported_rates(priv, &priv->rates);
- if (ipw_send_supported_rates(priv, &priv->rates))
- goto error;
-
- /* Set request-to-send threshold */
- if (priv->rts_threshold) {
- if (ipw_send_rts_threshold(priv, priv->rts_threshold))
- goto error;
- }
-#ifdef CONFIG_IPW2200_QOS
- IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n");
- ipw_qos_activate(priv, NULL);
-#endif /* CONFIG_IPW2200_QOS */
-
- if (ipw_set_random_seed(priv))
- goto error;
-
- /* final state transition to the RUN state */
- if (ipw_send_host_complete(priv))
- goto error;
-
- priv->status |= STATUS_INIT;
-
- ipw_led_init(priv);
- ipw_led_radio_on(priv);
- priv->notif_missed_beacons = 0;
-
- /* Set hardware WEP key if it is configured. */
- if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.level == SEC_LEVEL_1) &&
- !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
- ipw_set_hwcrypto_keys(priv);
-
- return 0;
-
- error:
- return -EIO;
-}
-
-/*
- * NOTE:
- *
- * These tables have been tested in conjunction with the
- * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters.
- *
- * Altering this values, using it on other hardware, or in geographies
- * not intended for resale of the above mentioned Intel adapters has
- * not been tested.
- *
- * Remember to update the table in README.ipw2200 when changing this
- * table.
- *
- */
-static const struct libipw_geo ipw_geos[] = {
- { /* Restricted */
- "---",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- },
-
- { /* Custom US/Canada */
- "ZZF",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 8,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Rest of World */
- "ZZD",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}},
- },
-
- { /* Custom USA & Europe & High */
- "ZZA",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149},
- {5765, 153},
- {5785, 157},
- {5805, 161},
- {5825, 165}},
- },
-
- { /* Custom NA & Europe */
- "ZZB",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Custom Japan */
- "ZZC",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 4,
- .a = {{5170, 34}, {5190, 38},
- {5210, 42}, {5230, 46}},
- },
-
- { /* Custom */
- "ZZM",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- },
-
- { /* Europe */
- "ZZE",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}},
- .a_channels = 19,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
- {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
- {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
- {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
- {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
- {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
- {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
- {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
- {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
- {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
- {5700, 140, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Custom Japan */
- "ZZJ",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY}},
- .a_channels = 4,
- .a = {{5170, 34}, {5190, 38},
- {5210, 42}, {5230, 46}},
- },
-
- { /* Rest of World */
- "ZZR",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY |
- LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* High Band */
- "ZZH",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
- {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
- .a_channels = 4,
- .a = {{5745, 149}, {5765, 153},
- {5785, 157}, {5805, 161}},
- },
-
- { /* Custom Europe */
- "ZZG",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12}, {2472, 13}},
- .a_channels = 4,
- .a = {{5180, 36}, {5200, 40},
- {5220, 44}, {5240, 48}},
- },
-
- { /* Europe */
- "ZZK",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
- {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
- .a_channels = 24,
- .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
- {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
- {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
- {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
- {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
- {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
- {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
- {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
- {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
- {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
- {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
- {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
- {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
- {5700, 140, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Europe */
- "ZZL",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
- {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
- {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
- {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- }
-};
-
-static void ipw_set_geo(struct ipw_priv *priv)
-{
- int j;
-
- for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
- if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
- ipw_geos[j].name, 3))
- break;
- }
-
- if (j == ARRAY_SIZE(ipw_geos)) {
- IPW_WARNING("SKU [%c%c%c] not recognized.\n",
- priv->eeprom[EEPROM_COUNTRY_CODE + 0],
- priv->eeprom[EEPROM_COUNTRY_CODE + 1],
- priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
- j = 0;
- }
-
- libipw_set_geo(priv->ieee, &ipw_geos[j]);
-}
-
-#define MAX_HW_RESTARTS 5
-static int ipw_up(struct ipw_priv *priv)
-{
- int rc, i;
-
- /* Age scan list entries found before suspend */
- if (priv->suspend_time) {
- libipw_networks_age(priv->ieee, priv->suspend_time);
- priv->suspend_time = 0;
- }
-
- if (priv->status & STATUS_EXIT_PENDING)
- return -EIO;
-
- if (cmdlog && !priv->cmdlog) {
- priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog),
- GFP_KERNEL);
- if (priv->cmdlog == NULL) {
- IPW_ERROR("Error allocating %d command log entries.\n",
- cmdlog);
- return -ENOMEM;
- } else {
- priv->cmdlog_len = cmdlog;
- }
- }
-
- for (i = 0; i < MAX_HW_RESTARTS; i++) {
- /* Load the microcode, firmware, and eeprom.
- * Also start the clocks. */
- rc = ipw_load(priv);
- if (rc) {
- IPW_ERROR("Unable to load firmware: %d\n", rc);
- return rc;
- }
-
- ipw_init_ordinals(priv);
- if (!(priv->config & CFG_CUSTOM_MAC))
- eeprom_parse_mac(priv, priv->mac_addr);
- eth_hw_addr_set(priv->net_dev, priv->mac_addr);
-
- ipw_set_geo(priv);
-
- if (priv->status & STATUS_RF_KILL_SW) {
- IPW_WARNING("Radio disabled by module parameter.\n");
- return 0;
- } else if (rf_kill_active(priv)) {
- IPW_WARNING("Radio Frequency Kill Switch is On:\n"
- "Kill switch must be turned off for "
- "wireless networking to work.\n");
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- return 0;
- }
-
- rc = ipw_config(priv);
- if (!rc) {
- IPW_DEBUG_INFO("Configured device on count %i\n", i);
-
- /* If configure to try and auto-associate, kick
- * off a scan. */
- schedule_delayed_work(&priv->request_scan, 0);
-
- return 0;
- }
-
- IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc);
- IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n",
- i, MAX_HW_RESTARTS);
-
- /* We had an error bringing up the hardware, so take it
- * all the way back down so we can try again */
- ipw_down(priv);
- }
-
- /* tried to restart and config the device for as long as our
- * patience could withstand */
- IPW_ERROR("Unable to initialize device after %d attempts.\n", i);
-
- return -EIO;
-}
-
-static void ipw_bg_up(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, up);
- mutex_lock(&priv->mutex);
- ipw_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_deinit(struct ipw_priv *priv)
-{
- int i;
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_INFO("Aborting scan during shutdown.\n");
- ipw_abort_scan(priv);
- }
-
- if (priv->status & STATUS_ASSOCIATED) {
- IPW_DEBUG_INFO("Disassociating during shutdown.\n");
- ipw_disassociate(priv);
- }
-
- ipw_led_shutdown(priv);
-
- /* Wait up to 1s for status to change to not scanning and not
- * associated (disassociation can take a while for a ful 802.11
- * exchange */
- for (i = 1000; i && (priv->status &
- (STATUS_DISASSOCIATING |
- STATUS_ASSOCIATED | STATUS_SCANNING)); i--)
- udelay(10);
-
- if (priv->status & (STATUS_DISASSOCIATING |
- STATUS_ASSOCIATED | STATUS_SCANNING))
- IPW_DEBUG_INFO("Still associated or scanning...\n");
- else
- IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i);
-
- /* Attempt to disable the card */
- ipw_send_card_disable(priv, 0);
-
- priv->status &= ~STATUS_INIT;
-}
-
-static void ipw_down(struct ipw_priv *priv)
-{
- int exit_pending = priv->status & STATUS_EXIT_PENDING;
-
- priv->status |= STATUS_EXIT_PENDING;
-
- if (ipw_is_init(priv))
- ipw_deinit(priv);
-
- /* Wipe out the EXIT_PENDING status bit if we are not actually
- * exiting the module */
- if (!exit_pending)
- priv->status &= ~STATUS_EXIT_PENDING;
-
- /* tell the device to stop sending interrupts */
- ipw_disable_interrupts(priv);
-
- /* Clear all bits but the RF Kill */
- priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING;
- netif_carrier_off(priv->net_dev);
-
- ipw_stop_nic(priv);
-
- ipw_led_radio_off(priv);
-}
-
-static void ipw_bg_down(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, down);
- mutex_lock(&priv->mutex);
- ipw_down(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_wdev_init(struct net_device *dev)
-{
- int i, rc = 0;
- struct ipw_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct wireless_dev *wdev = &priv->ieee->wdev;
-
- memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
-
- /* fill-out priv->ieee->bg_band */
- if (geo->bg_channels) {
- struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
-
- bg_band->band = NL80211_BAND_2GHZ;
- bg_band->n_channels = geo->bg_channels;
- bg_band->channels = kcalloc(geo->bg_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!bg_band->channels) {
- rc = -ENOMEM;
- goto out;
- }
- /* translate geo->bg to bg_band.channels */
- for (i = 0; i < geo->bg_channels; i++) {
- bg_band->channels[i].band = NL80211_BAND_2GHZ;
- bg_band->channels[i].center_freq = geo->bg[i].freq;
- bg_band->channels[i].hw_value = geo->bg[i].channel;
- bg_band->channels[i].max_power = geo->bg[i].max_power;
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- bg_band->bitrates = ipw2200_bg_rates;
- bg_band->n_bitrates = ipw2200_num_bg_rates;
-
- wdev->wiphy->bands[NL80211_BAND_2GHZ] = bg_band;
- }
-
- /* fill-out priv->ieee->a_band */
- if (geo->a_channels) {
- struct ieee80211_supported_band *a_band = &priv->ieee->a_band;
-
- a_band->band = NL80211_BAND_5GHZ;
- a_band->n_channels = geo->a_channels;
- a_band->channels = kcalloc(geo->a_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!a_band->channels) {
- rc = -ENOMEM;
- goto out;
- }
- /* translate geo->a to a_band.channels */
- for (i = 0; i < geo->a_channels; i++) {
- a_band->channels[i].band = NL80211_BAND_5GHZ;
- a_band->channels[i].center_freq = geo->a[i].freq;
- a_band->channels[i].hw_value = geo->a[i].channel;
- a_band->channels[i].max_power = geo->a[i].max_power;
- if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- a_band->bitrates = ipw2200_a_rates;
- a_band->n_bitrates = ipw2200_num_a_rates;
-
- wdev->wiphy->bands[NL80211_BAND_5GHZ] = a_band;
- }
-
- wdev->wiphy->cipher_suites = ipw_cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
-
- set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
-
- /* With that information in place, we can now register the wiphy... */
- rc = wiphy_register(wdev->wiphy);
- if (rc)
- goto out;
-
- return 0;
-out:
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- return rc;
-}
-
-/* PCI driver stuff */
-static const struct pci_device_id card_ids[] = {
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
- {PCI_VDEVICE(INTEL, 0x104f), 0},
- {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
- {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
- {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
- {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */
-
- /* required last entry */
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, card_ids);
-
-static struct attribute *ipw_sysfs_entries[] = {
- &dev_attr_rf_kill.attr,
- &dev_attr_direct_dword.attr,
- &dev_attr_indirect_byte.attr,
- &dev_attr_indirect_dword.attr,
- &dev_attr_mem_gpio_reg.attr,
- &dev_attr_command_event_reg.attr,
- &dev_attr_nic_type.attr,
- &dev_attr_status.attr,
- &dev_attr_cfg.attr,
- &dev_attr_error.attr,
- &dev_attr_event_log.attr,
- &dev_attr_cmd_log.attr,
- &dev_attr_eeprom_delay.attr,
- &dev_attr_ucode_version.attr,
- &dev_attr_rtc.attr,
- &dev_attr_scan_age.attr,
- &dev_attr_led.attr,
- &dev_attr_speed_scan.attr,
- &dev_attr_net_stats.attr,
- &dev_attr_channels.attr,
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- &dev_attr_rtap_iface.attr,
- &dev_attr_rtap_filter.attr,
-#endif
- NULL
-};
-
-static const struct attribute_group ipw_attribute_group = {
- .name = NULL, /* put in device directory */
- .attrs = ipw_sysfs_entries,
-};
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static int ipw_prom_open(struct net_device *dev)
-{
- struct ipw_prom_priv *prom_priv = libipw_priv(dev);
- struct ipw_priv *priv = prom_priv->priv;
-
- IPW_DEBUG_INFO("prom dev->open\n");
- netif_carrier_off(dev);
-
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
-
- ipw_send_system_config(priv);
- }
-
- return 0;
-}
-
-static int ipw_prom_stop(struct net_device *dev)
-{
- struct ipw_prom_priv *prom_priv = libipw_priv(dev);
- struct ipw_priv *priv = prom_priv->priv;
-
- IPW_DEBUG_INFO("prom dev->stop\n");
-
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- priv->sys_config.accept_all_data_frames = 0;
- priv->sys_config.accept_non_directed_frames = 0;
- priv->sys_config.accept_all_mgmt_bcpr = 0;
- priv->sys_config.accept_all_mgmt_frames = 0;
-
- ipw_send_system_config(priv);
- }
-
- return 0;
-}
-
-static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- IPW_DEBUG_INFO("prom dev->xmit\n");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops ipw_prom_netdev_ops = {
- .ndo_open = ipw_prom_open,
- .ndo_stop = ipw_prom_stop,
- .ndo_start_xmit = ipw_prom_hard_start_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ipw_prom_alloc(struct ipw_priv *priv)
-{
- int rc = 0;
-
- if (priv->prom_net_dev)
- return -EPERM;
-
- priv->prom_net_dev = alloc_libipw(sizeof(struct ipw_prom_priv), 1);
- if (priv->prom_net_dev == NULL)
- return -ENOMEM;
-
- priv->prom_priv = libipw_priv(priv->prom_net_dev);
- priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev);
- priv->prom_priv->priv = priv;
-
- strcpy(priv->prom_net_dev->name, "rtap%d");
- eth_hw_addr_set(priv->prom_net_dev, priv->mac_addr);
-
- priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- priv->prom_net_dev->netdev_ops = &ipw_prom_netdev_ops;
-
- priv->prom_net_dev->min_mtu = 68;
- priv->prom_net_dev->max_mtu = LIBIPW_DATA_LEN;
-
- priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;
- SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev);
-
- rc = register_netdev(priv->prom_net_dev);
- if (rc) {
- free_libipw(priv->prom_net_dev, 1);
- priv->prom_net_dev = NULL;
- return rc;
- }
-
- return 0;
-}
-
-static void ipw_prom_free(struct ipw_priv *priv)
-{
- if (!priv->prom_net_dev)
- return;
-
- unregister_netdev(priv->prom_net_dev);
- free_libipw(priv->prom_net_dev, 1);
-
- priv->prom_net_dev = NULL;
-}
-
-#endif
-
-static const struct net_device_ops ipw_netdev_ops = {
- .ndo_open = ipw_net_open,
- .ndo_stop = ipw_net_stop,
- .ndo_set_rx_mode = ipw_net_set_multicast_list,
- .ndo_set_mac_address = ipw_net_set_mac_address,
- .ndo_start_xmit = libipw_xmit,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ipw_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err = 0;
- struct net_device *net_dev;
- void __iomem *base;
- u32 length, val;
- struct ipw_priv *priv;
- int i;
-
- net_dev = alloc_libipw(sizeof(struct ipw_priv), 0);
- if (net_dev == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- priv = libipw_priv(net_dev);
- priv->ieee = netdev_priv(net_dev);
-
- priv->net_dev = net_dev;
- priv->pci_dev = pdev;
- ipw_debug_level = debug;
- spin_lock_init(&priv->irq_lock);
- spin_lock_init(&priv->lock);
- for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
- INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
- mutex_init(&priv->mutex);
- if (pci_enable_device(pdev)) {
- err = -ENODEV;
- goto out_free_libipw;
- }
-
- pci_set_master(pdev);
-
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (!err)
- err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (err) {
- printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
- goto out_pci_disable_device;
- }
-
- pci_set_drvdata(pdev, priv);
-
- err = pci_request_regions(pdev, DRV_NAME);
- if (err)
- goto out_pci_disable_device;
-
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- length = pci_resource_len(pdev, 0);
- priv->hw_len = length;
-
- base = pci_ioremap_bar(pdev, 0);
- if (!base) {
- err = -ENODEV;
- goto out_pci_release_regions;
- }
-
- priv->hw_base = base;
- IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length);
- IPW_DEBUG_INFO("pci_resource_base = %p\n", base);
-
- ipw_setup_deferred_work(priv);
-
- ipw_sw_reset(priv, 1);
-
- err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv);
- if (err) {
- IPW_ERROR("Error allocating IRQ %d\n", pdev->irq);
- goto out_iounmap;
- }
-
- SET_NETDEV_DEV(net_dev, &pdev->dev);
-
- mutex_lock(&priv->mutex);
-
- priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
- priv->ieee->set_security = shim__set_security;
- priv->ieee->is_queue_full = ipw_net_is_queue_full;
-
-#ifdef CONFIG_IPW2200_QOS
- priv->ieee->is_qos_active = ipw_is_qos_active;
- priv->ieee->handle_probe_response = ipw_handle_beacon;
- priv->ieee->handle_beacon = ipw_handle_probe_response;
- priv->ieee->handle_assoc_response = ipw_handle_assoc_response;
-#endif /* CONFIG_IPW2200_QOS */
-
- priv->ieee->perfect_rssi = -20;
- priv->ieee->worst_rssi = -85;
-
- net_dev->netdev_ops = &ipw_netdev_ops;
- priv->wireless_data.spy_data = &priv->ieee->spy_data;
- net_dev->wireless_data = &priv->wireless_data;
- net_dev->wireless_handlers = &ipw_wx_handler_def;
- net_dev->ethtool_ops = &ipw_ethtool_ops;
-
- net_dev->min_mtu = 68;
- net_dev->max_mtu = LIBIPW_DATA_LEN;
-
- err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
- if (err) {
- IPW_ERROR("failed to create sysfs device attributes\n");
- mutex_unlock(&priv->mutex);
- goto out_release_irq;
- }
-
- if (ipw_up(priv)) {
- mutex_unlock(&priv->mutex);
- err = -EIO;
- goto out_remove_sysfs;
- }
-
- mutex_unlock(&priv->mutex);
-
- err = ipw_wdev_init(net_dev);
- if (err) {
- IPW_ERROR("failed to register wireless device\n");
- goto out_remove_sysfs;
- }
-
- err = register_netdev(net_dev);
- if (err) {
- IPW_ERROR("failed to register network device\n");
- goto out_unregister_wiphy;
- }
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (rtap_iface) {
- err = ipw_prom_alloc(priv);
- if (err) {
- IPW_ERROR("Failed to register promiscuous network "
- "device (error %d).\n", err);
- unregister_netdev(priv->net_dev);
- goto out_unregister_wiphy;
- }
- }
-#endif
-
- printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg "
- "channels, %d 802.11a channels)\n",
- priv->ieee->geo.name, priv->ieee->geo.bg_channels,
- priv->ieee->geo.a_channels);
-
- return 0;
-
- out_unregister_wiphy:
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- out_remove_sysfs:
- sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
- out_release_irq:
- free_irq(pdev->irq, priv);
- out_iounmap:
- iounmap(priv->hw_base);
- out_pci_release_regions:
- pci_release_regions(pdev);
- out_pci_disable_device:
- pci_disable_device(pdev);
- out_free_libipw:
- free_libipw(priv->net_dev, 0);
- out:
- return err;
-}
-
-static void ipw_pci_remove(struct pci_dev *pdev)
-{
- struct ipw_priv *priv = pci_get_drvdata(pdev);
- struct list_head *p, *q;
- int i;
-
- if (!priv)
- return;
-
- mutex_lock(&priv->mutex);
-
- priv->status |= STATUS_EXIT_PENDING;
- ipw_down(priv);
- sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
-
- mutex_unlock(&priv->mutex);
-
- unregister_netdev(priv->net_dev);
-
- if (priv->rxq) {
- ipw_rx_queue_free(priv, priv->rxq);
- priv->rxq = NULL;
- }
- ipw_tx_queue_free(priv);
-
- if (priv->cmdlog) {
- kfree(priv->cmdlog);
- priv->cmdlog = NULL;
- }
-
- /* make sure all works are inactive */
- cancel_delayed_work_sync(&priv->adhoc_check);
- cancel_work_sync(&priv->associate);
- cancel_work_sync(&priv->disassociate);
- cancel_work_sync(&priv->system_config);
- cancel_work_sync(&priv->rx_replenish);
- cancel_work_sync(&priv->adapter_restart);
- cancel_delayed_work_sync(&priv->rf_kill);
- cancel_work_sync(&priv->up);
- cancel_work_sync(&priv->down);
- cancel_delayed_work_sync(&priv->request_scan);
- cancel_delayed_work_sync(&priv->request_direct_scan);
- cancel_delayed_work_sync(&priv->request_passive_scan);
- cancel_delayed_work_sync(&priv->scan_event);
- cancel_delayed_work_sync(&priv->gather_stats);
- cancel_work_sync(&priv->abort_scan);
- cancel_work_sync(&priv->roam);
- cancel_delayed_work_sync(&priv->scan_check);
- cancel_work_sync(&priv->link_up);
- cancel_work_sync(&priv->link_down);
- cancel_delayed_work_sync(&priv->led_link_on);
- cancel_delayed_work_sync(&priv->led_link_off);
- cancel_delayed_work_sync(&priv->led_act_off);
- cancel_work_sync(&priv->merge_networks);
-
- /* Free MAC hash list for ADHOC */
- for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) {
- list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
- list_del(p);
- kfree(list_entry(p, struct ipw_ibss_seq, list));
- }
- }
-
- kfree(priv->error);
- priv->error = NULL;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- ipw_prom_free(priv);
-#endif
-
- free_irq(pdev->irq, priv);
- iounmap(priv->hw_base);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- /* wiphy_unregister needs to be here, before free_libipw */
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- free_libipw(priv->net_dev, 0);
- free_firmware();
-}
-
-static int __maybe_unused ipw_pci_suspend(struct device *dev_d)
-{
- struct ipw_priv *priv = dev_get_drvdata(dev_d);
- struct net_device *dev = priv->net_dev;
-
- printk(KERN_INFO "%s: Going into suspend...\n", dev->name);
-
- /* Take down the device; powers it off, etc. */
- ipw_down(priv);
-
- /* Remove the PRESENT state of the device */
- netif_device_detach(dev);
-
- priv->suspend_at = ktime_get_boottime_seconds();
-
- return 0;
-}
-
-static int __maybe_unused ipw_pci_resume(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct ipw_priv *priv = pci_get_drvdata(pdev);
- struct net_device *dev = priv->net_dev;
- u32 val;
-
- printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
-
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
- * from interfering with C3 CPU state. pci_restore_state won't help
- * here since it only restores the first 64 bytes pci config header.
- */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- /* Set the device back into the PRESENT state; this will also wake
- * the queue of needed */
- netif_device_attach(dev);
-
- priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at;
-
- /* Bring the device back up */
- schedule_work(&priv->up);
-
- return 0;
-}
-
-static void ipw_pci_shutdown(struct pci_dev *pdev)
-{
- struct ipw_priv *priv = pci_get_drvdata(pdev);
-
- /* Take down the device; powers it off, etc. */
- ipw_down(priv);
-
- pci_disable_device(pdev);
-}
-
-static SIMPLE_DEV_PM_OPS(ipw_pci_pm_ops, ipw_pci_suspend, ipw_pci_resume);
-
-/* driver initialization stuff */
-static struct pci_driver ipw_driver = {
- .name = DRV_NAME,
- .id_table = card_ids,
- .probe = ipw_pci_probe,
- .remove = ipw_pci_remove,
- .driver.pm = &ipw_pci_pm_ops,
- .shutdown = ipw_pci_shutdown,
-};
-
-static int __init ipw_init(void)
-{
- int ret;
-
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-
- ret = pci_register_driver(&ipw_driver);
- if (ret) {
- IPW_ERROR("Unable to initialize PCI module\n");
- return ret;
- }
-
- ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level);
- if (ret) {
- IPW_ERROR("Unable to create driver sysfs file\n");
- pci_unregister_driver(&ipw_driver);
- return ret;
- }
-
- return ret;
-}
-
-static void __exit ipw_exit(void)
-{
- driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level);
- pci_unregister_driver(&ipw_driver);
-}
-
-module_param(disable, int, 0444);
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-
-module_param(associate, int, 0444);
-MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
-
-module_param(auto_create, int, 0444);
-MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
-
-module_param_named(led, led_support, int, 0444);
-MODULE_PARM_DESC(led, "enable led control on some systems (default 1 on)");
-
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
-
-module_param_named(channel, default_channel, int, 0444);
-MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-module_param(rtap_iface, int, 0444);
-MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)");
-#endif
-
-#ifdef CONFIG_IPW2200_QOS
-module_param(qos_enable, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionalities");
-
-module_param(qos_burst_enable, int, 0444);
-MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode");
-
-module_param(qos_no_ack_mask, int, 0444);
-MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack");
-
-module_param(burst_duration_CCK, int, 0444);
-MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value");
-
-module_param(burst_duration_OFDM, int, 0444);
-MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
-#endif /* CONFIG_IPW2200_QOS */
-
-#ifdef CONFIG_IPW2200_MONITOR
-module_param_named(mode, network_mode, int, 0444);
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
-#else
-module_param_named(mode, network_mode, int, 0444);
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
-#endif
-
-module_param(bt_coexist, int, 0444);
-MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)");
-
-module_param(hwcrypto, int, 0444);
-MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)");
-
-module_param(cmdlog, int, 0444);
-MODULE_PARM_DESC(cmdlog,
- "allocate a ring buffer for logging firmware commands");
-
-module_param(roaming, int, 0444);
-MODULE_PARM_DESC(roaming, "enable roaming support (default on)");
-
-module_param(antenna, int, 0444);
-MODULE_PARM_DESC(antenna, "select antenna 1=Main, 3=Aux, default 0 [both], 2=slow_diversity (choose the one with lower background noise)");
-
-module_exit(ipw_exit);
-module_init(ipw_init);
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h
deleted file mode 100644
index 8ebf09121e173..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h
+++ /dev/null
@@ -1,1984 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#ifndef __ipw2200_h__
-#define __ipw2200_h__
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/firmware.h>
-#include <linux/wireless.h>
-#include <linux/jiffies.h>
-#include <asm/io.h>
-
-#include <net/lib80211.h>
-#include <net/ieee80211_radiotap.h>
-
-#define DRV_NAME "ipw2200"
-
-#include <linux/workqueue.h>
-
-#include "libipw.h"
-
-/* Authentication and Association States */
-enum connection_manager_assoc_states {
- CMAS_INIT = 0,
- CMAS_TX_AUTH_SEQ_1,
- CMAS_RX_AUTH_SEQ_2,
- CMAS_AUTH_SEQ_1_PASS,
- CMAS_AUTH_SEQ_1_FAIL,
- CMAS_TX_AUTH_SEQ_3,
- CMAS_RX_AUTH_SEQ_4,
- CMAS_AUTH_SEQ_2_PASS,
- CMAS_AUTH_SEQ_2_FAIL,
- CMAS_AUTHENTICATED,
- CMAS_TX_ASSOC,
- CMAS_RX_ASSOC_RESP,
- CMAS_ASSOCIATED,
- CMAS_LAST
-};
-
-#define IPW_WAIT (1<<0)
-#define IPW_QUIET (1<<1)
-#define IPW_ROAMING (1<<2)
-
-#define IPW_POWER_MODE_CAM 0x00 //(always on)
-#define IPW_POWER_INDEX_1 0x01
-#define IPW_POWER_INDEX_2 0x02
-#define IPW_POWER_INDEX_3 0x03
-#define IPW_POWER_INDEX_4 0x04
-#define IPW_POWER_INDEX_5 0x05
-#define IPW_POWER_AC 0x06
-#define IPW_POWER_BATTERY 0x07
-#define IPW_POWER_LIMIT 0x07
-#define IPW_POWER_MASK 0x0F
-#define IPW_POWER_ENABLED 0x10
-#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
-
-#define IPW_CMD_HOST_COMPLETE 2
-#define IPW_CMD_POWER_DOWN 4
-#define IPW_CMD_SYSTEM_CONFIG 6
-#define IPW_CMD_MULTICAST_ADDRESS 7
-#define IPW_CMD_SSID 8
-#define IPW_CMD_ADAPTER_ADDRESS 11
-#define IPW_CMD_PORT_TYPE 12
-#define IPW_CMD_RTS_THRESHOLD 15
-#define IPW_CMD_FRAG_THRESHOLD 16
-#define IPW_CMD_POWER_MODE 17
-#define IPW_CMD_WEP_KEY 18
-#define IPW_CMD_TGI_TX_KEY 19
-#define IPW_CMD_SCAN_REQUEST 20
-#define IPW_CMD_ASSOCIATE 21
-#define IPW_CMD_SUPPORTED_RATES 22
-#define IPW_CMD_SCAN_ABORT 23
-#define IPW_CMD_TX_FLUSH 24
-#define IPW_CMD_QOS_PARAMETERS 25
-#define IPW_CMD_SCAN_REQUEST_EXT 26
-#define IPW_CMD_DINO_CONFIG 30
-#define IPW_CMD_RSN_CAPABILITIES 31
-#define IPW_CMD_RX_KEY 32
-#define IPW_CMD_CARD_DISABLE 33
-#define IPW_CMD_SEED_NUMBER 34
-#define IPW_CMD_TX_POWER 35
-#define IPW_CMD_COUNTRY_INFO 36
-#define IPW_CMD_AIRONET_INFO 37
-#define IPW_CMD_AP_TX_POWER 38
-#define IPW_CMD_CCKM_INFO 39
-#define IPW_CMD_CCX_VER_INFO 40
-#define IPW_CMD_SET_CALIBRATION 41
-#define IPW_CMD_SENSITIVITY_CALIB 42
-#define IPW_CMD_RETRY_LIMIT 51
-#define IPW_CMD_IPW_PRE_POWER_DOWN 58
-#define IPW_CMD_VAP_BEACON_TEMPLATE 60
-#define IPW_CMD_VAP_DTIM_PERIOD 61
-#define IPW_CMD_EXT_SUPPORTED_RATES 62
-#define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT 63
-#define IPW_CMD_VAP_QUIET_INTERVALS 64
-#define IPW_CMD_VAP_CHANNEL_SWITCH 65
-#define IPW_CMD_VAP_MANDATORY_CHANNELS 66
-#define IPW_CMD_VAP_CELL_PWR_LIMIT 67
-#define IPW_CMD_VAP_CF_PARAM_SET 68
-#define IPW_CMD_VAP_SET_BEACONING_STATE 69
-#define IPW_CMD_MEASUREMENT 80
-#define IPW_CMD_POWER_CAPABILITY 81
-#define IPW_CMD_SUPPORTED_CHANNELS 82
-#define IPW_CMD_TPC_REPORT 83
-#define IPW_CMD_WME_INFO 84
-#define IPW_CMD_PRODUCTION_COMMAND 85
-#define IPW_CMD_LINKSYS_EOU_INFO 90
-
-#define RFD_SIZE 4
-#define NUM_TFD_CHUNKS 6
-
-#define TX_QUEUE_SIZE 32
-#define RX_QUEUE_SIZE 32
-
-#define DINO_CMD_WEP_KEY 0x08
-#define DINO_CMD_TX 0x0B
-#define DCT_ANTENNA_A 0x01
-#define DCT_ANTENNA_B 0x02
-
-#define IPW_A_MODE 0
-#define IPW_B_MODE 1
-#define IPW_G_MODE 2
-
-/*
- * TX Queue Flag Definitions
- */
-
-/* tx wep key definition */
-#define DCT_WEP_KEY_NOT_IMMIDIATE 0x00
-#define DCT_WEP_KEY_64Bit 0x40
-#define DCT_WEP_KEY_128Bit 0x80
-#define DCT_WEP_KEY_128bitIV 0xC0
-#define DCT_WEP_KEY_SIZE_MASK 0xC0
-
-#define DCT_WEP_KEY_INDEX_MASK 0x0F
-#define DCT_WEP_INDEX_USE_IMMEDIATE 0x20
-
-/* abort attempt if mgmt frame is rx'd */
-#define DCT_FLAG_ABORT_MGMT 0x01
-
-/* require CTS */
-#define DCT_FLAG_CTS_REQUIRED 0x02
-
-/* use short preamble */
-#define DCT_FLAG_LONG_PREAMBLE 0x00
-#define DCT_FLAG_SHORT_PREAMBLE 0x04
-
-/* RTS/CTS first */
-#define DCT_FLAG_RTS_REQD 0x08
-
-/* dont calculate duration field */
-#define DCT_FLAG_DUR_SET 0x10
-
-/* even if MAC WEP set (allows pre-encrypt) */
-#define DCT_FLAG_NO_WEP 0x20
-
-/* overwrite TSF field */
-#define DCT_FLAG_TSF_REQD 0x40
-
-/* ACK rx is expected to follow */
-#define DCT_FLAG_ACK_REQD 0x80
-
-/* TX flags extension */
-#define DCT_FLAG_EXT_MODE_CCK 0x01
-#define DCT_FLAG_EXT_MODE_OFDM 0x00
-
-#define DCT_FLAG_EXT_SECURITY_WEP 0x00
-#define DCT_FLAG_EXT_SECURITY_NO DCT_FLAG_EXT_SECURITY_WEP
-#define DCT_FLAG_EXT_SECURITY_CKIP 0x04
-#define DCT_FLAG_EXT_SECURITY_CCM 0x08
-#define DCT_FLAG_EXT_SECURITY_TKIP 0x0C
-#define DCT_FLAG_EXT_SECURITY_MASK 0x0C
-
-#define DCT_FLAG_EXT_QOS_ENABLED 0x10
-
-#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS 0x00
-#define DCT_FLAG_EXT_HC_SIFS 0x20
-#define DCT_FLAG_EXT_HC_PIFS 0x40
-
-#define TX_RX_TYPE_MASK 0xFF
-#define TX_FRAME_TYPE 0x00
-#define TX_HOST_COMMAND_TYPE 0x01
-#define RX_FRAME_TYPE 0x09
-#define RX_HOST_NOTIFICATION_TYPE 0x03
-#define RX_HOST_CMD_RESPONSE_TYPE 0x04
-#define RX_TX_FRAME_RESPONSE_TYPE 0x05
-#define TFD_NEED_IRQ_MASK 0x04
-
-#define HOST_CMD_DINO_CONFIG 30
-
-#define HOST_NOTIFICATION_STATUS_ASSOCIATED 10
-#define HOST_NOTIFICATION_STATUS_AUTHENTICATE 11
-#define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT 12
-#define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED 13
-#define HOST_NOTIFICATION_STATUS_FRAG_LENGTH 14
-#define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION 15
-#define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE 16
-#define HOST_NOTIFICATION_STATUS_BEACON_STATE 17
-#define HOST_NOTIFICATION_STATUS_TGI_TX_KEY 18
-#define HOST_NOTIFICATION_TX_STATUS 19
-#define HOST_NOTIFICATION_CALIB_KEEP_RESULTS 20
-#define HOST_NOTIFICATION_MEASUREMENT_STARTED 21
-#define HOST_NOTIFICATION_MEASUREMENT_ENDED 22
-#define HOST_NOTIFICATION_CHANNEL_SWITCHED 23
-#define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD 24
-#define HOST_NOTIFICATION_NOISE_STATS 25
-#define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED 30
-#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31
-
-#define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1
-#define IPW_MB_SCAN_CANCEL_THRESHOLD 3
-#define IPW_MB_ROAMING_THRESHOLD_MIN 1
-#define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8
-#define IPW_MB_ROAMING_THRESHOLD_MAX 30
-#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 3*IPW_MB_ROAMING_THRESHOLD_DEFAULT
-#define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300
-
-#define MACADRR_BYTE_LEN 6
-
-#define DCR_TYPE_AP 0x01
-#define DCR_TYPE_WLAP 0x02
-#define DCR_TYPE_MU_ESS 0x03
-#define DCR_TYPE_MU_IBSS 0x04
-#define DCR_TYPE_MU_PIBSS 0x05
-#define DCR_TYPE_SNIFFER 0x06
-#define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS
-
-/* QoS definitions */
-
-#define CW_MIN_OFDM 15
-#define CW_MAX_OFDM 1023
-#define CW_MIN_CCK 31
-#define CW_MAX_CCK 1023
-
-#define QOS_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX2_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
-#define QOS_TX3_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/4 - 1)
-
-#define QOS_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX2_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
-#define QOS_TX3_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/4 - 1)
-
-#define QOS_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define QOS_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define QOS_TX2_CW_MAX_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX3_CW_MAX_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
-
-#define QOS_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define QOS_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define QOS_TX2_CW_MAX_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX3_CW_MAX_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
-
-#define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX2_AIFS (2 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX3_AIFS (2 - QOS_AIFSN_MIN_VALUE)
-
-#define QOS_TX0_ACM 0
-#define QOS_TX1_ACM 0
-#define QOS_TX2_ACM 0
-#define QOS_TX3_ACM 0
-
-#define QOS_TX0_TXOP_LIMIT_CCK 0
-#define QOS_TX1_TXOP_LIMIT_CCK 0
-#define QOS_TX2_TXOP_LIMIT_CCK cpu_to_le16(6016)
-#define QOS_TX3_TXOP_LIMIT_CCK cpu_to_le16(3264)
-
-#define QOS_TX0_TXOP_LIMIT_OFDM 0
-#define QOS_TX1_TXOP_LIMIT_OFDM 0
-#define QOS_TX2_TXOP_LIMIT_OFDM cpu_to_le16(3008)
-#define QOS_TX3_TXOP_LIMIT_OFDM cpu_to_le16(1504)
-
-#define DEF_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX2_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX3_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-
-#define DEF_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX2_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX3_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-
-#define DEF_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX2_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX3_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-
-#define DEF_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX2_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX3_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-
-#define DEF_TX0_AIFS 0
-#define DEF_TX1_AIFS 0
-#define DEF_TX2_AIFS 0
-#define DEF_TX3_AIFS 0
-
-#define DEF_TX0_ACM 0
-#define DEF_TX1_ACM 0
-#define DEF_TX2_ACM 0
-#define DEF_TX3_ACM 0
-
-#define DEF_TX0_TXOP_LIMIT_CCK 0
-#define DEF_TX1_TXOP_LIMIT_CCK 0
-#define DEF_TX2_TXOP_LIMIT_CCK 0
-#define DEF_TX3_TXOP_LIMIT_CCK 0
-
-#define DEF_TX0_TXOP_LIMIT_OFDM 0
-#define DEF_TX1_TXOP_LIMIT_OFDM 0
-#define DEF_TX2_TXOP_LIMIT_OFDM 0
-#define DEF_TX3_TXOP_LIMIT_OFDM 0
-
-#define QOS_QOS_SETS 3
-#define QOS_PARAM_SET_ACTIVE 0
-#define QOS_PARAM_SET_DEF_CCK 1
-#define QOS_PARAM_SET_DEF_OFDM 2
-
-#define CTRL_QOS_NO_ACK (0x0020)
-
-#define IPW_TX_QUEUE_1 1
-#define IPW_TX_QUEUE_2 2
-#define IPW_TX_QUEUE_3 3
-#define IPW_TX_QUEUE_4 4
-
-/* QoS sturctures */
-struct ipw_qos_info {
- int qos_enable;
- struct libipw_qos_parameters *def_qos_parm_OFDM;
- struct libipw_qos_parameters *def_qos_parm_CCK;
- u32 burst_duration_CCK;
- u32 burst_duration_OFDM;
- u16 qos_no_ack_mask;
- int burst_enable;
-};
-
-/**************************************************************/
-/**
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues
- */
-struct clx2_queue {
- int n_bd; /**< number of BDs in this queue */
- int first_empty; /**< 1-st empty entry (index) */
- int last_used; /**< last used entry (index) */
- u32 reg_w; /**< 'write' reg (queue head), addr in domain 1 */
- u32 reg_r; /**< 'read' reg (queue tail), addr in domain 1 */
- dma_addr_t dma_addr; /**< physical addr for BD's */
- int low_mark; /**< low watermark, resume queue if free space more than this */
- int high_mark; /**< high watermark, stop queue if free space less than this */
-} __packed; /* XXX */
-
-struct machdr32 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- u8 addr4[MACADRR_BYTE_LEN];
- __le16 qos_ctrl;
-} __packed;
-
-struct machdr30 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- u8 addr4[MACADRR_BYTE_LEN];
-} __packed;
-
-struct machdr26 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- __le16 qos_ctrl;
-} __packed;
-
-struct machdr24 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
-} __packed;
-
-// TX TFD with 32 byte MAC Header
-struct tx_tfd_32 {
- struct machdr32 mchdr; // 32
- __le32 uivplaceholder[2]; // 8
-} __packed;
-
-// TX TFD with 30 byte MAC Header
-struct tx_tfd_30 {
- struct machdr30 mchdr; // 30
- u8 reserved[2]; // 2
- __le32 uivplaceholder[2]; // 8
-} __packed;
-
-// tx tfd with 26 byte mac header
-struct tx_tfd_26 {
- struct machdr26 mchdr; // 26
- u8 reserved1[2]; // 2
- __le32 uivplaceholder[2]; // 8
- u8 reserved2[4]; // 4
-} __packed;
-
-// tx tfd with 24 byte mac header
-struct tx_tfd_24 {
- struct machdr24 mchdr; // 24
- __le32 uivplaceholder[2]; // 8
- u8 reserved[8]; // 8
-} __packed;
-
-#define DCT_WEP_KEY_FIELD_LENGTH 16
-
-struct tfd_command {
- u8 index;
- u8 length;
- __le16 reserved;
- u8 payload[];
-} __packed;
-
-struct tfd_data {
- /* Header */
- __le32 work_area_ptr;
- u8 station_number; /* 0 for BSS */
- u8 reserved1;
- __le16 reserved2;
-
- /* Tx Parameters */
- u8 cmd_id;
- u8 seq_num;
- __le16 len;
- u8 priority;
- u8 tx_flags;
- u8 tx_flags_ext;
- u8 key_index;
- u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH];
- u8 rate;
- u8 antenna;
- __le16 next_packet_duration;
- __le16 next_frag_len;
- __le16 back_off_counter; //////txop;
- u8 retrylimit;
- __le16 cwcurrent;
- u8 reserved3;
-
- /* 802.11 MAC Header */
- union {
- struct tx_tfd_24 tfd_24;
- struct tx_tfd_26 tfd_26;
- struct tx_tfd_30 tfd_30;
- struct tx_tfd_32 tfd_32;
- } tfd;
-
- /* Payload DMA info */
- __le32 num_chunks;
- __le32 chunk_ptr[NUM_TFD_CHUNKS];
- __le16 chunk_len[NUM_TFD_CHUNKS];
-} __packed;
-
-struct txrx_control_flags {
- u8 message_type;
- u8 rx_seq_num;
- u8 control_bits;
- u8 reserved;
-} __packed;
-
-#define TFD_SIZE 128
-#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags))
-
-struct tfd_frame {
- struct txrx_control_flags control_flags;
- union {
- struct tfd_data data;
- struct tfd_command cmd;
- u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
- } u;
-} __packed;
-
-typedef void destructor_func(const void *);
-
-/**
- * Tx Queue for DMA. Queue consists of circular buffer of
- * BD's and required locking structures.
- */
-struct clx2_tx_queue {
- struct clx2_queue q;
- struct tfd_frame *bd;
- struct libipw_txb **txb;
-};
-
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 32
-#define RX_LOW_WATERMARK 8
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
-
-// Used for passing to driver number of successes and failures per rate
-struct rate_histogram {
- union {
- __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
- __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
- __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
- } success;
- union {
- __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
- __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
- __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
- } failed;
-} __packed;
-
-/* statistics command response */
-struct ipw_cmd_stats {
- u8 cmd_id;
- u8 seq_num;
- __le16 good_sfd;
- __le16 bad_plcp;
- __le16 wrong_bssid;
- __le16 valid_mpdu;
- __le16 bad_mac_header;
- __le16 reserved_frame_types;
- __le16 rx_ina;
- __le16 bad_crc32;
- __le16 invalid_cts;
- __le16 invalid_acks;
- __le16 long_distance_ina_fina;
- __le16 dsp_silence_unreachable;
- __le16 accumulated_rssi;
- __le16 rx_ovfl_frame_tossed;
- __le16 rssi_silence_threshold;
- __le16 rx_ovfl_frame_supplied;
- __le16 last_rx_frame_signal;
- __le16 last_rx_frame_noise;
- __le16 rx_autodetec_no_ofdm;
- __le16 rx_autodetec_no_barker;
- __le16 reserved;
-} __packed;
-
-struct notif_channel_result {
- u8 channel_num;
- struct ipw_cmd_stats stats;
- u8 uReserved;
-} __packed;
-
-#define SCAN_COMPLETED_STATUS_COMPLETE 1
-#define SCAN_COMPLETED_STATUS_ABORTED 2
-
-struct notif_scan_complete {
- u8 scan_type;
- u8 num_channels;
- u8 status;
- u8 reserved;
-} __packed;
-
-struct notif_frag_length {
- __le16 frag_length;
- __le16 reserved;
-} __packed;
-
-struct notif_beacon_state {
- __le32 state;
- __le32 number;
-} __packed;
-
-struct notif_tgi_tx_key {
- u8 key_state;
- u8 security_type;
- u8 station_index;
- u8 reserved;
-} __packed;
-
-#define SILENCE_OVER_THRESH (1)
-#define SILENCE_UNDER_THRESH (2)
-
-struct notif_link_deterioration {
- struct ipw_cmd_stats stats;
- u8 rate;
- u8 modulation;
- struct rate_histogram histogram;
- u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */
- __le16 silence_count;
-} __packed;
-
-struct notif_association {
- u8 state;
-} __packed;
-
-struct notif_authenticate {
- u8 state;
- struct machdr24 addr;
- __le16 status;
-} __packed;
-
-struct notif_calibration {
- u8 data[104];
-} __packed;
-
-struct notif_noise {
- __le32 value;
-} __packed;
-
-struct ipw_rx_notification {
- u8 reserved[8];
- u8 subtype;
- u8 flags;
- __le16 size;
- union {
- struct notif_association assoc;
- struct notif_authenticate auth;
- struct notif_channel_result channel_result;
- struct notif_scan_complete scan_complete;
- struct notif_frag_length frag_len;
- struct notif_beacon_state beacon_state;
- struct notif_tgi_tx_key tgi_tx_key;
- struct notif_link_deterioration link_deterioration;
- struct notif_calibration calibration;
- struct notif_noise noise;
- DECLARE_FLEX_ARRAY(u8, raw);
- } u;
-} __packed;
-
-struct ipw_rx_frame {
- __le32 reserved1;
- u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER
- u8 received_channel; // The channel that this frame was received on.
- // Note that for .11b this does not have to be
- // the same as the channel that it was sent.
- // Filled by LMAC
- u8 frameStatus;
- u8 rate;
- u8 rssi;
- u8 agc;
- u8 rssi_dbm;
- __le16 signal;
- __le16 noise;
- u8 antennaAndPhy;
- u8 control; // control bit should be on in bg
- u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate
- // is identical)
- u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen
- __le16 length;
- u8 data[];
-} __packed;
-
-struct ipw_rx_header {
- u8 message_type;
- u8 rx_seq_num;
- u8 control_bits;
- u8 reserved;
-} __packed;
-
-struct ipw_rx_packet {
- struct ipw_rx_header header;
- union {
- struct ipw_rx_frame frame;
- struct ipw_rx_notification notification;
- } u;
-} __packed;
-
-#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
-#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \
- sizeof(struct ipw_rx_frame))
-
-struct ipw_rx_mem_buffer {
- dma_addr_t dma_addr;
- struct sk_buff *skb;
- struct list_head list;
-}; /* Not transferred over network, so not __packed */
-
-struct ipw_rx_queue {
- struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
- struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE];
- u32 processed; /* Internal index to last handled Rx packet */
- u32 read; /* Shared index to newest available Rx buffer */
- u32 write; /* Shared index to oldest written Rx packet */
- u32 free_count; /* Number of pre-allocated buffers in rx_free */
- /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */
- struct list_head rx_free; /* Own an SKBs */
- struct list_head rx_used; /* No SKB allocated */
- spinlock_t lock;
-}; /* Not transferred over network, so not __packed */
-
-struct alive_command_responce {
- u8 alive_command;
- u8 sequence_number;
- __le16 software_revision;
- u8 device_identifier;
- u8 reserved1[5];
- __le16 reserved2;
- __le16 reserved3;
- __le16 clock_settle_time;
- __le16 powerup_settle_time;
- __le16 reserved4;
- u8 time_stamp[5]; /* month, day, year, hours, minutes */
- u8 ucode_valid;
-} __packed;
-
-#define IPW_MAX_RATES 12
-
-struct ipw_rates {
- u8 num_rates;
- u8 rates[IPW_MAX_RATES];
-} __packed;
-
-struct command_block {
- unsigned int control;
- u32 source_addr;
- u32 dest_addr;
- unsigned int status;
-} __packed;
-
-#define CB_NUMBER_OF_ELEMENTS_SMALL 64
-struct fw_image_desc {
- unsigned long last_cb_index;
- unsigned long current_cb_index;
- struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL];
- void *v_addr;
- unsigned long p_addr;
- unsigned long len;
-};
-
-struct ipw_sys_config {
- u8 bt_coexistence;
- u8 reserved1;
- u8 answer_broadcast_ssid_probe;
- u8 accept_all_data_frames;
- u8 accept_non_directed_frames;
- u8 exclude_unicast_unencrypted;
- u8 disable_unicast_decryption;
- u8 exclude_multicast_unencrypted;
- u8 disable_multicast_decryption;
- u8 antenna_diversity;
- u8 pass_crc_to_host;
- u8 dot11g_auto_detection;
- u8 enable_cts_to_self;
- u8 enable_multicast_filtering;
- u8 bt_coexist_collision_thr;
- u8 silence_threshold;
- u8 accept_all_mgmt_bcpr;
- u8 accept_all_mgmt_frames;
- u8 pass_noise_stats_to_host;
- u8 reserved3;
-} __packed;
-
-struct ipw_multicast_addr {
- u8 num_of_multicast_addresses;
- u8 reserved[3];
- u8 mac1[6];
- u8 mac2[6];
- u8 mac3[6];
- u8 mac4[6];
-} __packed;
-
-#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */
-#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */
-
-#define DCW_WEP_KEY_SEC_TYPE_WEP 0x00
-#define DCW_WEP_KEY_SEC_TYPE_CCM 0x20
-#define DCW_WEP_KEY_SEC_TYPE_TKIP 0x30
-
-#define DCW_WEP_KEY_INVALID_SIZE 0x00 /* 0 = Invalid key */
-#define DCW_WEP_KEY64Bit_SIZE 0x05 /* 64-bit encryption */
-#define DCW_WEP_KEY128Bit_SIZE 0x0D /* 128-bit encryption */
-#define DCW_CCM_KEY128Bit_SIZE 0x10 /* 128-bit key */
-//#define DCW_WEP_KEY128BitIV_SIZE 0x10 /* 128-bit key and 128-bit IV */
-
-struct ipw_wep_key {
- u8 cmd_id;
- u8 seq_num;
- u8 key_index;
- u8 key_size;
- u8 key[16];
-} __packed;
-
-struct ipw_tgi_tx_key {
- u8 key_id;
- u8 security_type;
- u8 station_index;
- u8 flags;
- u8 key[16];
- __le32 tx_counter[2];
-} __packed;
-
-#define IPW_SCAN_CHANNELS 54
-
-struct ipw_scan_request {
- u8 scan_type;
- __le16 dwell_time;
- u8 channels_list[IPW_SCAN_CHANNELS];
- u8 channels_reserved[3];
-} __packed;
-
-enum {
- IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN,
- IPW_SCAN_ACTIVE_DIRECT_SCAN,
- IPW_SCAN_ACTIVE_BROADCAST_SCAN,
- IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN,
- IPW_SCAN_TYPES
-};
-
-struct ipw_scan_request_ext {
- __le32 full_scan_index;
- u8 channels_list[IPW_SCAN_CHANNELS];
- u8 scan_type[IPW_SCAN_CHANNELS / 2];
- u8 reserved;
- __le16 dwell_time[IPW_SCAN_TYPES];
-} __packed;
-
-static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
-{
- if (index % 2)
- return scan->scan_type[index / 2] & 0x0F;
- else
- return (scan->scan_type[index / 2] & 0xF0) >> 4;
-}
-
-static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan,
- u8 index, u8 scan_type)
-{
- if (index % 2)
- scan->scan_type[index / 2] =
- (scan->scan_type[index / 2] & 0xF0) | (scan_type & 0x0F);
- else
- scan->scan_type[index / 2] =
- (scan->scan_type[index / 2] & 0x0F) |
- ((scan_type & 0x0F) << 4);
-}
-
-struct ipw_associate {
- u8 channel;
-#ifdef __LITTLE_ENDIAN_BITFIELD
- u8 auth_type:4, auth_key:4;
-#else
- u8 auth_key:4, auth_type:4;
-#endif
- u8 assoc_type;
- u8 reserved;
- __le16 policy_support;
- u8 preamble_length;
- u8 ieee_mode;
- u8 bssid[ETH_ALEN];
- __le32 assoc_tsf_msw;
- __le32 assoc_tsf_lsw;
- __le16 capability;
- __le16 listen_interval;
- __le16 beacon_interval;
- u8 dest[ETH_ALEN];
- __le16 atim_window;
- u8 smr;
- u8 reserved1;
- __le16 reserved2;
-} __packed;
-
-struct ipw_supported_rates {
- u8 ieee_mode;
- u8 num_rates;
- u8 purpose;
- u8 reserved;
- u8 supported_rates[IPW_MAX_RATES];
-} __packed;
-
-struct ipw_rts_threshold {
- __le16 rts_threshold;
- __le16 reserved;
-} __packed;
-
-struct ipw_frag_threshold {
- __le16 frag_threshold;
- __le16 reserved;
-} __packed;
-
-struct ipw_retry_limit {
- u8 short_retry_limit;
- u8 long_retry_limit;
- __le16 reserved;
-} __packed;
-
-struct ipw_dino_config {
- __le32 dino_config_addr;
- __le16 dino_config_size;
- u8 dino_response;
- u8 reserved;
-} __packed;
-
-struct ipw_aironet_info {
- u8 id;
- u8 length;
- __le16 reserved;
-} __packed;
-
-struct ipw_rx_key {
- u8 station_index;
- u8 key_type;
- u8 key_id;
- u8 key_flag;
- u8 key[16];
- u8 station_address[6];
- u8 key_index;
- u8 reserved;
-} __packed;
-
-struct ipw_country_channel_info {
- u8 first_channel;
- u8 no_channels;
- s8 max_tx_power;
-} __packed;
-
-struct ipw_country_info {
- u8 id;
- u8 length;
- u8 country_str[IEEE80211_COUNTRY_STRING_LEN];
- struct ipw_country_channel_info groups[7];
-} __packed;
-
-struct ipw_channel_tx_power {
- u8 channel_number;
- s8 tx_power;
-} __packed;
-
-#define SCAN_ASSOCIATED_INTERVAL (HZ)
-#define SCAN_INTERVAL (HZ / 10)
-#define MAX_A_CHANNELS 37
-#define MAX_B_CHANNELS 14
-
-struct ipw_tx_power {
- u8 num_channels;
- u8 ieee_mode;
- struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
-} __packed;
-
-struct ipw_rsn_capabilities {
- u8 id;
- u8 length;
- __le16 version;
-} __packed;
-
-struct ipw_sensitivity_calib {
- __le16 beacon_rssi_raw;
- __le16 reserved;
-} __packed;
-
-/**
- * Host command structure.
- *
- * On input, the following fields should be filled:
- * - cmd
- * - len
- * - status_len
- * - param (if needed)
- *
- * On output,
- * - \a status contains status;
- * - \a param filled with status parameters.
- */
-struct ipw_cmd { /* XXX */
- u32 cmd; /**< Host command */
- u32 status;/**< Status */
- u32 status_len;
- /**< How many 32 bit parameters in the status */
- u32 len; /**< incoming parameters length, bytes */
- /**
- * command parameters.
- * There should be enough space for incoming and
- * outcoming parameters.
- * Incoming parameters listed 1-st, followed by outcoming params.
- * nParams=(len+3)/4+status_len
- */
- u32 param[];
-} __packed;
-
-#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */
-
-#define STATUS_INT_ENABLED (1<<1)
-#define STATUS_RF_KILL_HW (1<<2)
-#define STATUS_RF_KILL_SW (1<<3)
-#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
-
-#define STATUS_INIT (1<<5)
-#define STATUS_AUTH (1<<6)
-#define STATUS_ASSOCIATED (1<<7)
-#define STATUS_STATE_MASK (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED)
-
-#define STATUS_ASSOCIATING (1<<8)
-#define STATUS_DISASSOCIATING (1<<9)
-#define STATUS_ROAMING (1<<10)
-#define STATUS_EXIT_PENDING (1<<11)
-#define STATUS_DISASSOC_PENDING (1<<12)
-#define STATUS_STATE_PENDING (1<<13)
-
-#define STATUS_DIRECT_SCAN_PENDING (1<<19)
-#define STATUS_SCAN_PENDING (1<<20)
-#define STATUS_SCANNING (1<<21)
-#define STATUS_SCAN_ABORTING (1<<22)
-#define STATUS_SCAN_FORCED (1<<23)
-
-#define STATUS_LED_LINK_ON (1<<24)
-#define STATUS_LED_ACT_ON (1<<25)
-
-#define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */
-#define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */
-#define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */
-
-#define STATUS_SECURITY_UPDATED (1<<31) /* Security sync needed */
-
-#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
-#define CFG_CUSTOM_MAC (1<<3)
-#define CFG_PREAMBLE_LONG (1<<4)
-#define CFG_ADHOC_PERSIST (1<<5)
-#define CFG_ASSOCIATE (1<<6)
-#define CFG_FIXED_RATE (1<<7)
-#define CFG_ADHOC_CREATE (1<<8)
-#define CFG_NO_LED (1<<9)
-#define CFG_BACKGROUND_SCAN (1<<10)
-#define CFG_SPEED_SCAN (1<<11)
-#define CFG_NET_STATS (1<<12)
-
-#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
-
-#define MAX_STATIONS 32
-#define IPW_INVALID_STATION (0xff)
-
-struct ipw_station_entry {
- u8 mac_addr[ETH_ALEN];
- u8 reserved;
- u8 support_mode;
-};
-
-#define AVG_ENTRIES 8
-struct average {
- s16 entries[AVG_ENTRIES];
- u8 pos;
- u8 init;
- s32 sum;
-};
-
-#define MAX_SPEED_SCAN 100
-#define IPW_IBSS_MAC_HASH_SIZE 31
-
-struct ipw_ibss_seq {
- u8 mac[ETH_ALEN];
- u16 seq_num;
- u16 frag_num;
- unsigned long packet_time;
- struct list_head list;
-};
-
-struct ipw_error_elem { /* XXX */
- u32 desc;
- u32 time;
- u32 blink1;
- u32 blink2;
- u32 link1;
- u32 link2;
- u32 data;
-};
-
-struct ipw_event { /* XXX */
- u32 event;
- u32 time;
- u32 data;
-} __packed;
-
-struct ipw_fw_error { /* XXX */
- unsigned long jiffies;
- u32 status;
- u32 config;
- u32 elem_len;
- u32 log_len;
- struct ipw_event *log;
- struct ipw_error_elem elem[];
-} __packed;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-
-enum ipw_prom_filter {
- IPW_PROM_CTL_HEADER_ONLY = (1 << 0),
- IPW_PROM_MGMT_HEADER_ONLY = (1 << 1),
- IPW_PROM_DATA_HEADER_ONLY = (1 << 2),
- IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */
- IPW_PROM_NO_TX = (1 << 4),
- IPW_PROM_NO_RX = (1 << 5),
- IPW_PROM_NO_CTL = (1 << 6),
- IPW_PROM_NO_MGMT = (1 << 7),
- IPW_PROM_NO_DATA = (1 << 8),
-};
-
-struct ipw_priv;
-struct ipw_prom_priv {
- struct ipw_priv *priv;
- struct libipw_device *ieee;
- enum ipw_prom_filter filter;
- int tx_packets;
- int rx_packets;
-};
-#endif
-
-#if defined(CONFIG_IPW2200_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS)
-/* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE
- *
- * When sent to us via the simulated Rx interface in sysfs, the entire
- * structure is provided regardless of any bits unset.
- */
-struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
- u64 rt_tsf; /* TSF */ /* XXX */
- u8 rt_flags; /* radiotap packet flags */
- u8 rt_rate; /* rate in 500kb/s */
- __le16 rt_channel; /* channel in mhz */
- __le16 rt_chbitmask; /* channel bitfield */
- s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
- s8 rt_dbmnoise;
- u8 rt_antenna; /* antenna number */
- u8 payload[]; /* payload... */
-} __packed;
-#endif
-
-struct ipw_priv {
- /* ieee device used by generic ieee processing code */
- struct libipw_device *ieee;
-
- spinlock_t lock;
- spinlock_t irq_lock;
- struct mutex mutex;
-
- /* basic pci-network driver stuff */
- struct pci_dev *pci_dev;
- struct net_device *net_dev;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- /* Promiscuous mode */
- struct ipw_prom_priv *prom_priv;
- struct net_device *prom_net_dev;
-#endif
-
- /* pci hardware address support */
- void __iomem *hw_base;
- unsigned long hw_len;
-
- struct fw_image_desc sram_desc;
-
- /* result of ucode download */
- struct alive_command_responce dino_alive;
-
- wait_queue_head_t wait_command_queue;
- wait_queue_head_t wait_state;
-
- /* Rx and Tx DMA processing queues */
- struct ipw_rx_queue *rxq;
- struct clx2_tx_queue txq_cmd;
- struct clx2_tx_queue txq[4];
- u32 status;
- u32 config;
- u32 capability;
-
- struct average average_missed_beacons;
- s16 exp_avg_rssi;
- s16 exp_avg_noise;
- u32 port_type;
- int rx_bufs_min; /**< minimum number of bufs in Rx queue */
- int rx_pend_max; /**< maximum pending buffers for one IRQ */
- u32 hcmd_seq; /**< sequence number for hcmd */
- u32 disassociate_threshold;
- u32 roaming_threshold;
-
- struct ipw_associate assoc_request;
- struct libipw_network *assoc_network;
-
- unsigned long ts_scan_abort;
- struct ipw_supported_rates rates;
- struct ipw_rates phy[3]; /**< PHY restrictions, per band */
- struct ipw_rates supp; /**< software defined */
- struct ipw_rates extended; /**< use for corresp. IE, AP only */
-
- struct notif_link_deterioration last_link_deterioration; /** for statistics */
- struct ipw_cmd *hcmd; /**< host command currently executed */
-
- wait_queue_head_t hcmd_wq; /**< host command waits for execution */
- u32 tsf_bcn[2]; /**< TSF from latest beacon */
-
- struct notif_calibration calib; /**< last calibration */
-
- /* ordinal interface with firmware */
- u32 table0_addr;
- u32 table0_len;
- u32 table1_addr;
- u32 table1_len;
- u32 table2_addr;
- u32 table2_len;
-
- /* context information */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
- u8 nick[IW_ESSID_MAX_SIZE];
- u16 rates_mask;
- u8 channel;
- struct ipw_sys_config sys_config;
- u32 power_mode;
- u8 bssid[ETH_ALEN];
- u16 rts_threshold;
- u8 mac_addr[ETH_ALEN];
- u8 num_stations;
- u8 stations[MAX_STATIONS][ETH_ALEN];
- u8 short_retry_limit;
- u8 long_retry_limit;
-
- u32 notif_missed_beacons;
-
- /* Statistics and counters normalized with each association */
- u32 last_missed_beacons;
- u32 last_tx_packets;
- u32 last_rx_packets;
- u32 last_tx_failures;
- u32 last_rx_err;
- u32 last_rate;
-
- u32 missed_adhoc_beacons;
- u32 missed_beacons;
- u32 rx_packets;
- u32 tx_packets;
- u32 quality;
-
- u8 speed_scan[MAX_SPEED_SCAN];
- u8 speed_scan_pos;
-
- u16 last_seq_num;
- u16 last_frag_num;
- unsigned long last_packet_time;
- struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE];
-
- /* eeprom */
- u8 eeprom[0x100]; /* 256 bytes of eeprom */
- u8 country[4];
- int eeprom_delay;
-
- struct iw_statistics wstats;
-
- struct iw_public_data wireless_data;
-
- int user_requested_scan;
- u8 direct_scan_ssid[IW_ESSID_MAX_SIZE];
- u8 direct_scan_ssid_len;
-
- struct delayed_work adhoc_check;
- struct work_struct associate;
- struct work_struct disassociate;
- struct work_struct system_config;
- struct work_struct rx_replenish;
- struct delayed_work request_scan;
- struct delayed_work request_direct_scan;
- struct delayed_work request_passive_scan;
- struct delayed_work scan_event;
- struct work_struct adapter_restart;
- struct delayed_work rf_kill;
- struct work_struct up;
- struct work_struct down;
- struct delayed_work gather_stats;
- struct work_struct abort_scan;
- struct work_struct roam;
- struct delayed_work scan_check;
- struct work_struct link_up;
- struct work_struct link_down;
-
- struct tasklet_struct irq_tasklet;
-
- /* LED related variables and work_struct */
- u8 nic_type;
- u32 led_activity_on;
- u32 led_activity_off;
- u32 led_association_on;
- u32 led_association_off;
- u32 led_ofdm_on;
- u32 led_ofdm_off;
-
- struct delayed_work led_link_on;
- struct delayed_work led_link_off;
- struct delayed_work led_act_off;
- struct work_struct merge_networks;
-
- struct ipw_cmd_log *cmdlog;
- int cmdlog_len;
- int cmdlog_pos;
-
-#define IPW_2200BG 1
-#define IPW_2915ABG 2
- u8 adapter;
-
- s8 tx_power;
-
- /* Track time in suspend using CLOCK_BOOTTIME */
- time64_t suspend_at;
- time64_t suspend_time;
-
-#ifdef CONFIG_PM
- u32 pm_state[16];
-#endif
-
- struct ipw_fw_error *error;
-
- /* network state */
-
- /* Used to pass the current INTA value from ISR to Tasklet */
- u32 isr_inta;
-
- /* QoS */
- struct ipw_qos_info qos_data;
- struct work_struct qos_activate;
- /*********************************/
-
- /* debugging info */
- u32 indirect_dword;
- u32 direct_dword;
- u32 indirect_byte;
-}; /*ipw_priv */
-
-/* debug macros */
-
-/* Debug and printf string expansion helpers for printing bitfields */
-#define BIT_FMT8 "%c%c%c%c-%c%c%c%c"
-#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8
-#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16
-
-#define BITC(x,y) (((x>>y)&1)?'1':'0')
-#define BIT_ARG8(x) \
-BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\
-BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0)
-
-#define BIT_ARG16(x) \
-BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\
-BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\
-BIT_ARG8(x)
-
-#define BIT_ARG32(x) \
-BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\
-BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\
-BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\
-BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\
-BIT_ARG16(x)
-
-
-#define IPW_DEBUG(level, fmt, args...) \
-do { if (ipw_debug_level & (level)) \
- printk(KERN_DEBUG DRV_NAME": %s " fmt, __func__ , ## args); } while (0)
-
-#ifdef CONFIG_IPW2200_DEBUG
-#define IPW_LL_DEBUG(level, fmt, args...) \
-do { if (ipw_debug_level & (level)) \
- printk(KERN_DEBUG DRV_NAME": %s " fmt, __func__ , ## args); } while (0)
-#else
-#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0)
-#endif /* CONFIG_IPW2200_DEBUG */
-
-/*
- * To use the debug system;
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define IPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a IPW_xxxx_DEBUG() macro definition for your
- * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ipw/debug_level
- *
- * you simply need to add your entry to the ipw_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/ipw then you do not have
- * CONFIG_IPW2200_DEBUG defined in your kernel configuration
- *
- */
-
-#define IPW_DL_ERROR (1<<0)
-#define IPW_DL_WARNING (1<<1)
-#define IPW_DL_INFO (1<<2)
-#define IPW_DL_WX (1<<3)
-#define IPW_DL_HOST_COMMAND (1<<5)
-#define IPW_DL_STATE (1<<6)
-
-#define IPW_DL_NOTIF (1<<10)
-#define IPW_DL_SCAN (1<<11)
-#define IPW_DL_ASSOC (1<<12)
-#define IPW_DL_DROP (1<<13)
-#define IPW_DL_IOCTL (1<<14)
-
-#define IPW_DL_MANAGE (1<<15)
-#define IPW_DL_FW (1<<16)
-#define IPW_DL_RF_KILL (1<<17)
-#define IPW_DL_FW_ERRORS (1<<18)
-
-#define IPW_DL_LED (1<<19)
-
-#define IPW_DL_ORD (1<<20)
-
-#define IPW_DL_FRAG (1<<21)
-#define IPW_DL_WEP (1<<22)
-#define IPW_DL_TX (1<<23)
-#define IPW_DL_RX (1<<24)
-#define IPW_DL_ISR (1<<25)
-#define IPW_DL_FW_INFO (1<<26)
-#define IPW_DL_IO (1<<27)
-#define IPW_DL_TRACE (1<<28)
-
-#define IPW_DL_STATS (1<<29)
-#define IPW_DL_MERGE (1<<30)
-#define IPW_DL_QOS (1<<31)
-
-#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
-#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_INFO(f, a...) IPW_DEBUG(IPW_DL_INFO, f, ## a)
-
-#define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a)
-#define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a)
-#define IPW_DEBUG_TRACE(f, a...) IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a)
-#define IPW_DEBUG_RX(f, a...) IPW_LL_DEBUG(IPW_DL_RX, f, ## a)
-#define IPW_DEBUG_TX(f, a...) IPW_LL_DEBUG(IPW_DL_TX, f, ## a)
-#define IPW_DEBUG_ISR(f, a...) IPW_LL_DEBUG(IPW_DL_ISR, f, ## a)
-#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
-#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a)
-#define IPW_DEBUG_WEP(f, a...) IPW_LL_DEBUG(IPW_DL_WEP, f, ## a)
-#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
-#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a)
-#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a)
-#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
-#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
-#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a)
-#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a)
-#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a)
-#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
-#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a)
-#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a)
-#define IPW_DEBUG_QOS(f, a...) IPW_LL_DEBUG(IPW_DL_QOS, f, ## a)
-
-#include <linux/ctype.h>
-
-/*
-* Register bit definitions
-*/
-
-#define IPW_INTA_RW 0x00000008
-#define IPW_INTA_MASK_R 0x0000000C
-#define IPW_INDIRECT_ADDR 0x00000010
-#define IPW_INDIRECT_DATA 0x00000014
-#define IPW_AUTOINC_ADDR 0x00000018
-#define IPW_AUTOINC_DATA 0x0000001C
-#define IPW_RESET_REG 0x00000020
-#define IPW_GP_CNTRL_RW 0x00000024
-
-#define IPW_READ_INT_REGISTER 0xFF4
-
-#define IPW_GP_CNTRL_BIT_INIT_DONE 0x00000004
-
-#define IPW_REGISTER_DOMAIN1_END 0x00001000
-#define IPW_SRAM_READ_INT_REGISTER 0x00000ff4
-
-#define IPW_SHARED_LOWER_BOUND 0x00000200
-#define IPW_INTERRUPT_AREA_LOWER_BOUND 0x00000f80
-
-#define IPW_NIC_SRAM_LOWER_BOUND 0x00000000
-#define IPW_NIC_SRAM_UPPER_BOUND 0x00030000
-
-#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
-#define IPW_GP_CNTRL_BIT_CLOCK_READY 0x00000001
-#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
-
-/*
- * RESET Register Bit Indexes
- */
-#define CBD_RESET_REG_PRINCETON_RESET (1<<0)
-#define IPW_START_STANDBY (1<<2)
-#define IPW_ACTIVITY_LED (1<<4)
-#define IPW_ASSOCIATED_LED (1<<5)
-#define IPW_OFDM_LED (1<<6)
-#define IPW_RESET_REG_SW_RESET (1<<7)
-#define IPW_RESET_REG_MASTER_DISABLED (1<<8)
-#define IPW_RESET_REG_STOP_MASTER (1<<9)
-#define IPW_GATE_ODMA (1<<25)
-#define IPW_GATE_IDMA (1<<26)
-#define IPW_ARC_KESHET_CONFIG (1<<27)
-#define IPW_GATE_ADMA (1<<29)
-
-#define IPW_CSR_CIS_UPPER_BOUND 0x00000200
-#define IPW_DOMAIN_0_END 0x1000
-#define CLX_MEM_BAR_SIZE 0x1000
-
-/* Dino/baseband control registers bits */
-
-#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */
-#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */
-#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */
-#define IPW_BASEBAND_CONTROL_STATUS 0X00200000
-#define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004
-#define IPW_BASEBAND_RX_FIFO_READ 0X00200004
-#define IPW_BASEBAND_CONTROL_STORE 0X00200010
-
-#define IPW_INTERNAL_CMD_EVENT 0X00300004
-#define IPW_BASEBAND_POWER_DOWN 0x00000001
-
-#define IPW_MEM_HALT_AND_RESET 0x003000e0
-
-/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */
-#define IPW_BIT_HALT_RESET_ON 0x80000000
-#define IPW_BIT_HALT_RESET_OFF 0x00000000
-
-#define CB_LAST_VALID 0x20000000
-#define CB_INT_ENABLED 0x40000000
-#define CB_VALID 0x80000000
-#define CB_SRC_LE 0x08000000
-#define CB_DEST_LE 0x04000000
-#define CB_SRC_AUTOINC 0x00800000
-#define CB_SRC_IO_GATED 0x00400000
-#define CB_DEST_AUTOINC 0x00080000
-#define CB_SRC_SIZE_LONG 0x00200000
-#define CB_DEST_SIZE_LONG 0x00020000
-
-/* DMA DEFINES */
-
-#define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000
-#define DMA_CB_STOP_AND_ABORT 0x00000C00
-#define DMA_CB_START 0x00000100
-
-#define IPW_SHARED_SRAM_SIZE 0x00030000
-#define IPW_SHARED_SRAM_DMA_CONTROL 0x00027000
-#define CB_MAX_LENGTH 0x1FFF
-
-#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
-#define IPW_EEPROM_IMAGE_SIZE 0x100
-
-/* DMA defs */
-#define IPW_DMA_I_CURRENT_CB 0x003000D0
-#define IPW_DMA_O_CURRENT_CB 0x003000D4
-#define IPW_DMA_I_DMA_CONTROL 0x003000A4
-#define IPW_DMA_I_CB_BASE 0x003000A0
-
-#define IPW_TX_CMD_QUEUE_BD_BASE 0x00000200
-#define IPW_TX_CMD_QUEUE_BD_SIZE 0x00000204
-#define IPW_TX_QUEUE_0_BD_BASE 0x00000208
-#define IPW_TX_QUEUE_0_BD_SIZE (0x0000020C)
-#define IPW_TX_QUEUE_1_BD_BASE 0x00000210
-#define IPW_TX_QUEUE_1_BD_SIZE 0x00000214
-#define IPW_TX_QUEUE_2_BD_BASE 0x00000218
-#define IPW_TX_QUEUE_2_BD_SIZE (0x0000021C)
-#define IPW_TX_QUEUE_3_BD_BASE 0x00000220
-#define IPW_TX_QUEUE_3_BD_SIZE 0x00000224
-#define IPW_RX_BD_BASE 0x00000240
-#define IPW_RX_BD_SIZE 0x00000244
-#define IPW_RFDS_TABLE_LOWER 0x00000500
-
-#define IPW_TX_CMD_QUEUE_READ_INDEX 0x00000280
-#define IPW_TX_QUEUE_0_READ_INDEX 0x00000284
-#define IPW_TX_QUEUE_1_READ_INDEX 0x00000288
-#define IPW_TX_QUEUE_2_READ_INDEX (0x0000028C)
-#define IPW_TX_QUEUE_3_READ_INDEX 0x00000290
-#define IPW_RX_READ_INDEX (0x000002A0)
-
-#define IPW_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80)
-#define IPW_TX_QUEUE_0_WRITE_INDEX (0x00000F84)
-#define IPW_TX_QUEUE_1_WRITE_INDEX (0x00000F88)
-#define IPW_TX_QUEUE_2_WRITE_INDEX (0x00000F8C)
-#define IPW_TX_QUEUE_3_WRITE_INDEX (0x00000F90)
-#define IPW_RX_WRITE_INDEX (0x00000FA0)
-
-/*
- * EEPROM Related Definitions
- */
-
-#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814)
-#define IPW_EEPROM_DATA_SRAM_SIZE (IPW_SHARED_LOWER_BOUND + 0x818)
-#define IPW_EEPROM_LOAD_DISABLE (IPW_SHARED_LOWER_BOUND + 0x81C)
-#define IPW_EEPROM_DATA (IPW_SHARED_LOWER_BOUND + 0x820)
-#define IPW_EEPROM_UPPER_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x9E0)
-
-#define IPW_STATION_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0xA0C)
-#define IPW_STATION_TABLE_UPPER (IPW_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_REQUEST_ATIM (IPW_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_ATIM_SENT (IPW_SHARED_LOWER_BOUND + 0xB10)
-#define IPW_WHO_IS_AWAKE (IPW_SHARED_LOWER_BOUND + 0xB14)
-#define IPW_DURING_ATIM_WINDOW (IPW_SHARED_LOWER_BOUND + 0xB18)
-
-#define MSB 1
-#define LSB 0
-#define WORD_TO_BYTE(_word) ((_word) * sizeof(u16))
-
-#define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \
- ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) )
-
-/* EEPROM access by BYTE */
-#define EEPROM_PME_CAPABILITY (GET_EEPROM_ADDR(0x09,MSB)) /* 1 byte */
-#define EEPROM_MAC_ADDRESS (GET_EEPROM_ADDR(0x21,LSB)) /* 6 byte */
-#define EEPROM_VERSION (GET_EEPROM_ADDR(0x24,MSB)) /* 1 byte */
-#define EEPROM_NIC_TYPE (GET_EEPROM_ADDR(0x25,LSB)) /* 1 byte */
-#define EEPROM_SKU_CAPABILITY (GET_EEPROM_ADDR(0x25,MSB)) /* 1 byte */
-#define EEPROM_COUNTRY_CODE (GET_EEPROM_ADDR(0x26,LSB)) /* 3 bytes */
-#define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB)) /* 2 bytes */
-#define EEPROM_IBSS_CHANNELS_A (GET_EEPROM_ADDR(0x29,MSB)) /* 5 bytes */
-#define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */
-#define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */
-
-/* NIC type as found in the one byte EEPROM_NIC_TYPE offset */
-#define EEPROM_NIC_TYPE_0 0
-#define EEPROM_NIC_TYPE_1 1
-#define EEPROM_NIC_TYPE_2 2
-#define EEPROM_NIC_TYPE_3 3
-#define EEPROM_NIC_TYPE_4 4
-
-/* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */
-#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */
-#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */
-#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */
-
-#define FW_MEM_REG_LOWER_BOUND 0x00300000
-#define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40)
-#define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04)
-#define EEPROM_BIT_SK (1<<0)
-#define EEPROM_BIT_CS (1<<1)
-#define EEPROM_BIT_DI (1<<2)
-#define EEPROM_BIT_DO (1<<4)
-
-#define EEPROM_CMD_READ 0x2
-
-/* Interrupts masks */
-#define IPW_INTA_NONE 0x00000000
-
-#define IPW_INTA_BIT_RX_TRANSFER 0x00000002
-#define IPW_INTA_BIT_STATUS_CHANGE 0x00000010
-#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020
-
-//Inta Bits for CF
-#define IPW_INTA_BIT_TX_CMD_QUEUE 0x00000800
-#define IPW_INTA_BIT_TX_QUEUE_1 0x00001000
-#define IPW_INTA_BIT_TX_QUEUE_2 0x00002000
-#define IPW_INTA_BIT_TX_QUEUE_3 0x00004000
-#define IPW_INTA_BIT_TX_QUEUE_4 0x00008000
-
-#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000
-
-#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000
-#define IPW_INTA_BIT_POWER_DOWN 0x00200000
-
-#define IPW_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000
-#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000
-#define IPW_INTA_BIT_RF_KILL_DONE 0x04000000
-#define IPW_INTA_BIT_FATAL_ERROR 0x40000000
-#define IPW_INTA_BIT_PARITY_ERROR 0x80000000
-
-/* Interrupts enabled at init time. */
-#define IPW_INTA_MASK_ALL \
- (IPW_INTA_BIT_TX_QUEUE_1 | \
- IPW_INTA_BIT_TX_QUEUE_2 | \
- IPW_INTA_BIT_TX_QUEUE_3 | \
- IPW_INTA_BIT_TX_QUEUE_4 | \
- IPW_INTA_BIT_TX_CMD_QUEUE | \
- IPW_INTA_BIT_RX_TRANSFER | \
- IPW_INTA_BIT_FATAL_ERROR | \
- IPW_INTA_BIT_PARITY_ERROR | \
- IPW_INTA_BIT_STATUS_CHANGE | \
- IPW_INTA_BIT_FW_INITIALIZATION_DONE | \
- IPW_INTA_BIT_BEACON_PERIOD_EXPIRED | \
- IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
- IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN | \
- IPW_INTA_BIT_POWER_DOWN | \
- IPW_INTA_BIT_RF_KILL_DONE )
-
-/* FW event log definitions */
-#define EVENT_ELEM_SIZE (3 * sizeof(u32))
-#define EVENT_START_OFFSET (1 * sizeof(u32) + 2 * sizeof(u16))
-
-/* FW error log definitions */
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-
-/* TX power level (dbm) */
-#define IPW_TX_POWER_MIN -12
-#define IPW_TX_POWER_MAX 20
-#define IPW_TX_POWER_DEFAULT IPW_TX_POWER_MAX
-
-enum {
- IPW_FW_ERROR_OK = 0,
- IPW_FW_ERROR_FAIL,
- IPW_FW_ERROR_MEMORY_UNDERFLOW,
- IPW_FW_ERROR_MEMORY_OVERFLOW,
- IPW_FW_ERROR_BAD_PARAM,
- IPW_FW_ERROR_BAD_CHECKSUM,
- IPW_FW_ERROR_NMI_INTERRUPT,
- IPW_FW_ERROR_BAD_DATABASE,
- IPW_FW_ERROR_ALLOC_FAIL,
- IPW_FW_ERROR_DMA_UNDERRUN,
- IPW_FW_ERROR_DMA_STATUS,
- IPW_FW_ERROR_DINO_ERROR,
- IPW_FW_ERROR_EEPROM_ERROR,
- IPW_FW_ERROR_SYSASSERT,
- IPW_FW_ERROR_FATAL_ERROR
-};
-
-#define AUTH_OPEN 0
-#define AUTH_SHARED_KEY 1
-#define AUTH_LEAP 2
-#define AUTH_IGNORE 3
-
-#define HC_ASSOCIATE 0
-#define HC_REASSOCIATE 1
-#define HC_DISASSOCIATE 2
-#define HC_IBSS_START 3
-#define HC_IBSS_RECONF 4
-#define HC_DISASSOC_QUIET 5
-
-#define HC_QOS_SUPPORT_ASSOC cpu_to_le16(0x01)
-
-#define IPW_RATE_CAPABILITIES 1
-#define IPW_RATE_CONNECT 0
-
-/*
- * Rate values and masks
- */
-#define IPW_TX_RATE_1MB 0x0A
-#define IPW_TX_RATE_2MB 0x14
-#define IPW_TX_RATE_5MB 0x37
-#define IPW_TX_RATE_6MB 0x0D
-#define IPW_TX_RATE_9MB 0x0F
-#define IPW_TX_RATE_11MB 0x6E
-#define IPW_TX_RATE_12MB 0x05
-#define IPW_TX_RATE_18MB 0x07
-#define IPW_TX_RATE_24MB 0x09
-#define IPW_TX_RATE_36MB 0x0B
-#define IPW_TX_RATE_48MB 0x01
-#define IPW_TX_RATE_54MB 0x03
-
-#define IPW_ORD_TABLE_ID_MASK 0x0000FF00
-#define IPW_ORD_TABLE_VALUE_MASK 0x000000FF
-
-#define IPW_ORD_TABLE_0_MASK 0x0000F000
-#define IPW_ORD_TABLE_1_MASK 0x0000F100
-#define IPW_ORD_TABLE_2_MASK 0x0000F200
-#define IPW_ORD_TABLE_3_MASK 0x0000F300
-#define IPW_ORD_TABLE_4_MASK 0x0000F400
-#define IPW_ORD_TABLE_5_MASK 0x0000F500
-#define IPW_ORD_TABLE_6_MASK 0x0000F600
-#define IPW_ORD_TABLE_7_MASK 0x0000F700
-
-/*
- * Table 0 Entries (all entries are 32 bits)
- */
-enum {
- IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1,
- IPW_ORD_STAT_FRAG_TRESHOLD,
- IPW_ORD_STAT_RTS_THRESHOLD,
- IPW_ORD_STAT_TX_HOST_REQUESTS,
- IPW_ORD_STAT_TX_HOST_COMPLETE,
- IPW_ORD_STAT_TX_DIR_DATA,
- IPW_ORD_STAT_TX_DIR_DATA_B_1,
- IPW_ORD_STAT_TX_DIR_DATA_B_2,
- IPW_ORD_STAT_TX_DIR_DATA_B_5_5,
- IPW_ORD_STAT_TX_DIR_DATA_B_11,
- /* Hole */
-
- IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19,
- IPW_ORD_STAT_TX_DIR_DATA_G_2,
- IPW_ORD_STAT_TX_DIR_DATA_G_5_5,
- IPW_ORD_STAT_TX_DIR_DATA_G_6,
- IPW_ORD_STAT_TX_DIR_DATA_G_9,
- IPW_ORD_STAT_TX_DIR_DATA_G_11,
- IPW_ORD_STAT_TX_DIR_DATA_G_12,
- IPW_ORD_STAT_TX_DIR_DATA_G_18,
- IPW_ORD_STAT_TX_DIR_DATA_G_24,
- IPW_ORD_STAT_TX_DIR_DATA_G_36,
- IPW_ORD_STAT_TX_DIR_DATA_G_48,
- IPW_ORD_STAT_TX_DIR_DATA_G_54,
- IPW_ORD_STAT_TX_NON_DIR_DATA,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_1,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_2,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_11,
- /* Hole */
-
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_2,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_6,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_9,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_11,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_12,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_18,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_24,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_36,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_48,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_54,
- IPW_ORD_STAT_TX_RETRY,
- IPW_ORD_STAT_TX_FAILURE,
- IPW_ORD_STAT_RX_ERR_CRC,
- IPW_ORD_STAT_RX_ERR_ICV,
- IPW_ORD_STAT_RX_NO_BUFFER,
- IPW_ORD_STAT_FULL_SCANS,
- IPW_ORD_STAT_PARTIAL_SCANS,
- IPW_ORD_STAT_TGH_ABORTED_SCANS,
- IPW_ORD_STAT_TX_TOTAL_BYTES,
- IPW_ORD_STAT_CURR_RSSI_RAW,
- IPW_ORD_STAT_RX_BEACON,
- IPW_ORD_STAT_MISSED_BEACONS,
- IPW_ORD_TABLE_0_LAST
-};
-
-#define IPW_RSSI_TO_DBM 112
-
-/* Table 1 Entries
- */
-enum {
- IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1,
-};
-
-/*
- * Table 2 Entries
- *
- * FW_VERSION: 16 byte string
- * FW_DATE: 16 byte string (only 14 bytes used)
- * UCODE_VERSION: 4 byte version code
- * UCODE_DATE: 5 bytes code code
- * ADDAPTER_MAC: 6 byte MAC address
- * RTC: 4 byte clock
- */
-enum {
- IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1,
- IPW_ORD_STAT_FW_DATE,
- IPW_ORD_STAT_UCODE_VERSION,
- IPW_ORD_STAT_UCODE_DATE,
- IPW_ORD_STAT_ADAPTER_MAC,
- IPW_ORD_STAT_RTC,
- IPW_ORD_TABLE_2_LAST
-};
-
-/* Table 3 */
-enum {
- IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0,
- IPW_ORD_STAT_TX_PACKET_FAILURE,
- IPW_ORD_STAT_TX_PACKET_SUCCESS,
- IPW_ORD_STAT_TX_PACKET_ABORTED,
- IPW_ORD_TABLE_3_LAST
-};
-
-/* Table 4 */
-enum {
- IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK
-};
-
-/* Table 5 */
-enum {
- IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK,
- IPW_ORD_STAT_AP_ASSNS,
- IPW_ORD_STAT_ROAM,
- IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS,
- IPW_ORD_STAT_ROAM_CAUSE_UNASSOC,
- IPW_ORD_STAT_ROAM_CAUSE_RSSI,
- IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY,
- IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE,
- IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX,
- IPW_ORD_STAT_LINK_UP,
- IPW_ORD_STAT_LINK_DOWN,
- IPW_ORD_ANTENNA_DIVERSITY,
- IPW_ORD_CURR_FREQ,
- IPW_ORD_TABLE_5_LAST
-};
-
-/* Table 6 */
-enum {
- IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK,
- IPW_ORD_CURR_BSSID,
- IPW_ORD_CURR_SSID,
- IPW_ORD_TABLE_6_LAST
-};
-
-/* Table 7 */
-enum {
- IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK,
- IPW_ORD_STAT_PERCENT_TX_RETRIES,
- IPW_ORD_STAT_PERCENT_LINK_QUALITY,
- IPW_ORD_STAT_CURR_RSSI_DBM,
- IPW_ORD_TABLE_7_LAST
-};
-
-#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410)
-#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414)
-#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500)
-#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180)
-#define IPW_ORDINALS_TABLE_1 (IPW_SHARED_LOWER_BOUND + 0x184)
-#define IPW_ORDINALS_TABLE_2 (IPW_SHARED_LOWER_BOUND + 0x188)
-#define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C)
-
-struct ipw_fixed_rate {
- __le16 tx_rates;
- __le16 reserved;
-} __packed;
-
-#define IPW_INDIRECT_ADDR_MASK (~0x3ul)
-
-struct host_cmd {
- u8 cmd;
- u8 len;
- u16 reserved;
- const u32 *param;
-} __packed; /* XXX */
-
-struct cmdlog_host_cmd {
- u8 cmd;
- u8 len;
- __le16 reserved;
- char param[124];
-} __packed;
-
-struct ipw_cmd_log {
- unsigned long jiffies;
- int retcode;
- struct cmdlog_host_cmd cmd;
-};
-
-/* SysConfig command parameters ... */
-/* bt_coexistence param */
-#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */
-#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */
-#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */
-#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */
-#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */
-
-/* clear-to-send to self param */
-#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x00
-#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x01
-#define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN
-
-/* Antenna diversity param (h/w can select best antenna, based on signal) */
-#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */
-#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */
-#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */
-#define CFG_SYS_ANTENNA_SLOW_DIV 0x02 /* consider background noise */
-
-#define IPW_MAX_CONFIG_RETRIES 10
-
-#endif /* __ipw2200_h__ */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h
deleted file mode 100644
index bec7bc2737488..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw.h
+++ /dev/null
@@ -1,1001 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
- * remains copyright by the original authors
- *
- * Portions of the merged code are based on Host AP (software wireless
- * LAN access point) driver for Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <[email protected]>
- * Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <[email protected]>
- * Copyright (c) 2004-2005, Intel Corporation
- *
- * API Version History
- * 1.0.x -- Initial version
- * 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs,
- * various structure changes, and crypto API init method
- */
-#ifndef LIBIPW_H
-#define LIBIPW_H
-#include <linux/if_ether.h> /* ETH_ALEN */
-#include <linux/kernel.h> /* ARRAY_SIZE */
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-
-#include <net/lib80211.h>
-#include <net/cfg80211.h>
-
-#define LIBIPW_VERSION "git-1.1.13"
-
-#define LIBIPW_DATA_LEN 2304
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
- 6.2.1.1.2.
-
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-
-#define LIBIPW_1ADDR_LEN 10
-#define LIBIPW_2ADDR_LEN 16
-#define LIBIPW_3ADDR_LEN 24
-#define LIBIPW_4ADDR_LEN 30
-#define LIBIPW_FCS_LEN 4
-#define LIBIPW_HLEN (LIBIPW_4ADDR_LEN)
-#define LIBIPW_FRAME_LEN (LIBIPW_DATA_LEN + LIBIPW_HLEN)
-
-#define MIN_FRAG_THRESHOLD 256U
-#define MAX_FRAG_THRESHOLD 2346U
-
-/* QOS control */
-#define LIBIPW_QCTL_TID 0x000F
-
-/* debug macros */
-
-#ifdef CONFIG_LIBIPW_DEBUG
-extern u32 libipw_debug_level;
-#define LIBIPW_DEBUG(level, fmt, args...) \
-do { if (libipw_debug_level & (level)) \
- printk(KERN_DEBUG "libipw: %s " fmt, __func__ , ## args); } while (0)
-#else
-#define LIBIPW_DEBUG(level, fmt, args...) do {} while (0)
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-/*
- * To use the debug system:
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define LIBIPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a LIBIPW_xxxx_DEBUG() macro definition for your
- * classification, or use LIBIPW_DEBUG(LIBIPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ieee80211/debug_level
- *
- * you simply need to add your entry to the libipw_debug_level array.
- *
- * If you do not see debug_level in /proc/net/ieee80211 then you do not have
- * CONFIG_LIBIPW_DEBUG defined in your kernel configuration
- *
- */
-
-#define LIBIPW_DL_INFO (1<<0)
-#define LIBIPW_DL_WX (1<<1)
-#define LIBIPW_DL_SCAN (1<<2)
-#define LIBIPW_DL_STATE (1<<3)
-#define LIBIPW_DL_MGMT (1<<4)
-#define LIBIPW_DL_FRAG (1<<5)
-#define LIBIPW_DL_DROP (1<<7)
-
-#define LIBIPW_DL_TX (1<<8)
-#define LIBIPW_DL_RX (1<<9)
-#define LIBIPW_DL_QOS (1<<31)
-
-#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "libipw: " f, ## a)
-#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "libipw: " f, ## a)
-#define LIBIPW_DEBUG_INFO(f, a...) LIBIPW_DEBUG(LIBIPW_DL_INFO, f, ## a)
-
-#define LIBIPW_DEBUG_WX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_WX, f, ## a)
-#define LIBIPW_DEBUG_SCAN(f, a...) LIBIPW_DEBUG(LIBIPW_DL_SCAN, f, ## a)
-#define LIBIPW_DEBUG_STATE(f, a...) LIBIPW_DEBUG(LIBIPW_DL_STATE, f, ## a)
-#define LIBIPW_DEBUG_MGMT(f, a...) LIBIPW_DEBUG(LIBIPW_DL_MGMT, f, ## a)
-#define LIBIPW_DEBUG_FRAG(f, a...) LIBIPW_DEBUG(LIBIPW_DL_FRAG, f, ## a)
-#define LIBIPW_DEBUG_DROP(f, a...) LIBIPW_DEBUG(LIBIPW_DL_DROP, f, ## a)
-#define LIBIPW_DEBUG_TX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_TX, f, ## a)
-#define LIBIPW_DEBUG_RX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_RX, f, ## a)
-#define LIBIPW_DEBUG_QOS(f, a...) LIBIPW_DEBUG(LIBIPW_DL_QOS, f, ## a)
-#include <linux/netdevice.h>
-#include <linux/if_arp.h> /* ARPHRD_ETHER */
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY /* enable iwspy support */
-#endif
-#include <net/iw_handler.h> /* new driver API */
-
-#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
-#endif
-
-/* IEEE 802.11 defines */
-
-#define P80211_OUI_LEN 3
-
-struct libipw_snap_hdr {
-
- u8 dsap; /* always 0xAA */
- u8 ssap; /* always 0xAA */
- u8 ctrl; /* always 0x03 */
- u8 oui[P80211_OUI_LEN]; /* organizational universal id */
-
-} __packed;
-
-#define SNAP_SIZE sizeof(struct libipw_snap_hdr)
-
-#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
-#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
-#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
-
-#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
-#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-
-#define LIBIPW_STATMASK_SIGNAL (1<<0)
-#define LIBIPW_STATMASK_RSSI (1<<1)
-#define LIBIPW_STATMASK_NOISE (1<<2)
-#define LIBIPW_STATMASK_RATE (1<<3)
-#define LIBIPW_STATMASK_WEMASK 0x7
-
-#define LIBIPW_CCK_MODULATION (1<<0)
-#define LIBIPW_OFDM_MODULATION (1<<1)
-
-#define LIBIPW_24GHZ_BAND (1<<0)
-#define LIBIPW_52GHZ_BAND (1<<1)
-
-#define LIBIPW_CCK_RATE_1MB 0x02
-#define LIBIPW_CCK_RATE_2MB 0x04
-#define LIBIPW_CCK_RATE_5MB 0x0B
-#define LIBIPW_CCK_RATE_11MB 0x16
-#define LIBIPW_OFDM_RATE_6MB 0x0C
-#define LIBIPW_OFDM_RATE_9MB 0x12
-#define LIBIPW_OFDM_RATE_12MB 0x18
-#define LIBIPW_OFDM_RATE_18MB 0x24
-#define LIBIPW_OFDM_RATE_24MB 0x30
-#define LIBIPW_OFDM_RATE_36MB 0x48
-#define LIBIPW_OFDM_RATE_48MB 0x60
-#define LIBIPW_OFDM_RATE_54MB 0x6C
-#define LIBIPW_BASIC_RATE_MASK 0x80
-
-#define LIBIPW_CCK_RATE_1MB_MASK (1<<0)
-#define LIBIPW_CCK_RATE_2MB_MASK (1<<1)
-#define LIBIPW_CCK_RATE_5MB_MASK (1<<2)
-#define LIBIPW_CCK_RATE_11MB_MASK (1<<3)
-#define LIBIPW_OFDM_RATE_6MB_MASK (1<<4)
-#define LIBIPW_OFDM_RATE_9MB_MASK (1<<5)
-#define LIBIPW_OFDM_RATE_12MB_MASK (1<<6)
-#define LIBIPW_OFDM_RATE_18MB_MASK (1<<7)
-#define LIBIPW_OFDM_RATE_24MB_MASK (1<<8)
-#define LIBIPW_OFDM_RATE_36MB_MASK (1<<9)
-#define LIBIPW_OFDM_RATE_48MB_MASK (1<<10)
-#define LIBIPW_OFDM_RATE_54MB_MASK (1<<11)
-
-#define LIBIPW_CCK_RATES_MASK 0x0000000F
-#define LIBIPW_CCK_BASIC_RATES_MASK (LIBIPW_CCK_RATE_1MB_MASK | \
- LIBIPW_CCK_RATE_2MB_MASK)
-#define LIBIPW_CCK_DEFAULT_RATES_MASK (LIBIPW_CCK_BASIC_RATES_MASK | \
- LIBIPW_CCK_RATE_5MB_MASK | \
- LIBIPW_CCK_RATE_11MB_MASK)
-
-#define LIBIPW_OFDM_RATES_MASK 0x00000FF0
-#define LIBIPW_OFDM_BASIC_RATES_MASK (LIBIPW_OFDM_RATE_6MB_MASK | \
- LIBIPW_OFDM_RATE_12MB_MASK | \
- LIBIPW_OFDM_RATE_24MB_MASK)
-#define LIBIPW_OFDM_DEFAULT_RATES_MASK (LIBIPW_OFDM_BASIC_RATES_MASK | \
- LIBIPW_OFDM_RATE_9MB_MASK | \
- LIBIPW_OFDM_RATE_18MB_MASK | \
- LIBIPW_OFDM_RATE_36MB_MASK | \
- LIBIPW_OFDM_RATE_48MB_MASK | \
- LIBIPW_OFDM_RATE_54MB_MASK)
-#define LIBIPW_DEFAULT_RATES_MASK (LIBIPW_OFDM_DEFAULT_RATES_MASK | \
- LIBIPW_CCK_DEFAULT_RATES_MASK)
-
-#define LIBIPW_NUM_OFDM_RATES 8
-#define LIBIPW_NUM_CCK_RATES 4
-#define LIBIPW_OFDM_SHIFT_MASK_A 4
-
-/* NOTE: This data is for statistical purposes; not all hardware provides this
- * information for frames received.
- * For libipw_rx_mgt, you need to set at least the 'len' parameter.
- */
-struct libipw_rx_stats {
- u32 mac_time;
- s8 rssi;
- u8 signal;
- u8 noise;
- u16 rate; /* in 100 kbps */
- u8 received_channel;
- u8 control;
- u8 mask;
- u8 freq;
- u16 len;
- u64 tsf;
- u32 beacon_time;
-};
-
-/* IEEE 802.11 requires that STA supports concurrent reception of at least
- * three fragmented frames. This define can be increased to support more
- * concurrent frames, but it should be noted that each entry can consume about
- * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
-#define LIBIPW_FRAG_CACHE_LEN 4
-
-struct libipw_frag_entry {
- unsigned long first_frag_time;
- unsigned int seq;
- unsigned int last_frag;
- struct sk_buff *skb;
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
-};
-
-struct libipw_stats {
- unsigned int tx_unicast_frames;
- unsigned int tx_multicast_frames;
- unsigned int tx_fragments;
- unsigned int tx_unicast_octets;
- unsigned int tx_multicast_octets;
- unsigned int tx_deferred_transmissions;
- unsigned int tx_single_retry_frames;
- unsigned int tx_multiple_retry_frames;
- unsigned int tx_retry_limit_exceeded;
- unsigned int tx_discards;
- unsigned int rx_unicast_frames;
- unsigned int rx_multicast_frames;
- unsigned int rx_fragments;
- unsigned int rx_unicast_octets;
- unsigned int rx_multicast_octets;
- unsigned int rx_fcs_errors;
- unsigned int rx_discards_no_buffer;
- unsigned int tx_discards_wrong_sa;
- unsigned int rx_discards_undecryptable;
- unsigned int rx_message_in_msg_fragments;
- unsigned int rx_message_in_bad_msg_fragments;
-};
-
-struct libipw_device;
-
-#define SEC_KEY_1 (1<<0)
-#define SEC_KEY_2 (1<<1)
-#define SEC_KEY_3 (1<<2)
-#define SEC_KEY_4 (1<<3)
-#define SEC_ACTIVE_KEY (1<<4)
-#define SEC_AUTH_MODE (1<<5)
-#define SEC_UNICAST_GROUP (1<<6)
-#define SEC_LEVEL (1<<7)
-#define SEC_ENABLED (1<<8)
-#define SEC_ENCRYPT (1<<9)
-
-#define SEC_LEVEL_0 0 /* None */
-#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
-#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
-#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
-#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
-
-#define SEC_ALG_NONE 0
-#define SEC_ALG_WEP 1
-#define SEC_ALG_TKIP 2
-#define SEC_ALG_CCMP 3
-
-#define WEP_KEYS 4
-#define WEP_KEY_LEN 13
-#define SCM_KEY_LEN 32
-#define SCM_TEMPORAL_KEY_LENGTH 16
-
-struct libipw_security {
- u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1;
- u8 auth_mode;
- u8 encode_alg[WEP_KEYS];
- u8 key_sizes[WEP_KEYS];
- u8 keys[WEP_KEYS][SCM_KEY_LEN];
- u8 level;
- u16 flags;
-} __packed;
-
-/*
-
- 802.11 data frame from AP
-
- ,-------------------------------------------------------------------.
-Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- |------|------|---------|---------|---------|------|---------|------|
-Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
- | | tion | (BSSID) | | | ence | data | |
- `-------------------------------------------------------------------'
-
-Total: 28-2340 bytes
-
-*/
-
-#define BEACON_PROBE_SSID_ID_POSITION 12
-
-struct libipw_hdr_1addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_2addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_3addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_4addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_3addrqos {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[0];
- __le16 qos_ctl;
-} __packed;
-
-struct libipw_info_element {
- u8 id;
- u8 len;
- u8 data[];
-} __packed;
-
-/*
- * These are the data types that can make up management packets
- *
- u16 auth_algorithm;
- u16 auth_sequence;
- u16 beacon_interval;
- u16 capability;
- u8 current_ap[ETH_ALEN];
- u16 listen_interval;
- struct {
- u16 association_id:14, reserved:2;
- } __packed;
- u32 time_stamp[2];
- u16 reason;
- u16 status;
-*/
-
-struct libipw_auth {
- struct libipw_hdr_3addr header;
- __le16 algorithm;
- __le16 transaction;
- __le16 status;
- /* challenge */
- u8 variable[];
-} __packed;
-
-struct libipw_channel_switch {
- u8 id;
- u8 len;
- u8 mode;
- u8 channel;
- u8 count;
-} __packed;
-
-struct libipw_action {
- struct libipw_hdr_3addr header;
- u8 category;
- u8 action;
- union {
- struct libipw_action_exchange {
- u8 token;
- } exchange;
- struct libipw_channel_switch channel_switch;
-
- } format;
-} __packed;
-
-struct libipw_disassoc {
- struct libipw_hdr_3addr header;
- __le16 reason;
-} __packed;
-
-/* Alias deauth for disassoc */
-#define libipw_deauth libipw_disassoc
-
-struct libipw_probe_request {
- struct libipw_hdr_3addr header;
- /* SSID, supported rates */
- u8 variable[];
-} __packed;
-
-struct libipw_probe_response {
- struct libipw_hdr_3addr header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- /* SSID, supported rates, FH params, DS params,
- * CF params, IBSS params, TIM (if beacon), RSN */
- u8 variable[];
-} __packed;
-
-/* Alias beacon for probe_response */
-#define libipw_beacon libipw_probe_response
-
-struct libipw_assoc_request {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- /* SSID, supported rates, RSN */
- u8 variable[];
-} __packed;
-
-struct libipw_reassoc_request {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- u8 current_ap[ETH_ALEN];
- u8 variable[];
-} __packed;
-
-struct libipw_assoc_response {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 status;
- __le16 aid;
- /* supported rates */
- u8 variable[];
-} __packed;
-
-struct libipw_txb {
- u8 nr_frags;
- u8 encrypted;
- u8 rts_included;
- u8 reserved;
- u16 frag_size;
- u16 payload_size;
- struct sk_buff *fragments[];
-};
-
-/* SWEEP TABLE ENTRIES NUMBER */
-#define MAX_SWEEP_TAB_ENTRIES 42
-#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
-/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
- * only use 8, and then use extended rates for the remaining supported
- * rates. Other APs, however, stick all of their supported rates on the
- * main rates information element... */
-#define MAX_RATES_LENGTH ((u8)12)
-#define MAX_RATES_EX_LENGTH ((u8)16)
-#define MAX_NETWORK_COUNT 128
-
-#define CRC_LENGTH 4U
-
-#define MAX_WPA_IE_LEN 64
-
-#define NETWORK_HAS_OFDM (1<<1)
-#define NETWORK_HAS_CCK (1<<2)
-
-/* QoS structure */
-#define NETWORK_HAS_QOS_PARAMETERS (1<<3)
-#define NETWORK_HAS_QOS_INFORMATION (1<<4)
-#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \
- NETWORK_HAS_QOS_INFORMATION)
-
-/* 802.11h */
-#define NETWORK_HAS_POWER_CONSTRAINT (1<<5)
-#define NETWORK_HAS_CSA (1<<6)
-#define NETWORK_HAS_QUIET (1<<7)
-#define NETWORK_HAS_IBSS_DFS (1<<8)
-#define NETWORK_HAS_TPC_REPORT (1<<9)
-
-#define NETWORK_HAS_ERP_VALUE (1<<10)
-
-#define QOS_QUEUE_NUM 4
-#define QOS_OUI_LEN 3
-#define QOS_OUI_TYPE 2
-#define QOS_ELEMENT_ID 221
-#define QOS_OUI_INFO_SUB_TYPE 0
-#define QOS_OUI_PARAM_SUB_TYPE 1
-#define QOS_VERSION_1 1
-#define QOS_AIFSN_MIN_VALUE 2
-
-struct libipw_qos_information_element {
- u8 elementID;
- u8 length;
- u8 qui[QOS_OUI_LEN];
- u8 qui_type;
- u8 qui_subtype;
- u8 version;
- u8 ac_info;
-} __packed;
-
-struct libipw_qos_ac_parameter {
- u8 aci_aifsn;
- u8 ecw_min_max;
- __le16 tx_op_limit;
-} __packed;
-
-struct libipw_qos_parameter_info {
- struct libipw_qos_information_element info_element;
- u8 reserved;
- struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __packed;
-
-struct libipw_qos_parameters {
- __le16 cw_min[QOS_QUEUE_NUM];
- __le16 cw_max[QOS_QUEUE_NUM];
- u8 aifs[QOS_QUEUE_NUM];
- u8 flag[QOS_QUEUE_NUM];
- __le16 tx_op_limit[QOS_QUEUE_NUM];
-} __packed;
-
-struct libipw_qos_data {
- struct libipw_qos_parameters parameters;
- int active;
- int supported;
- u8 param_count;
- u8 old_param_count;
-};
-
-struct libipw_tim_parameters {
- u8 tim_count;
- u8 tim_period;
-} __packed;
-
-/*******************************************************/
-
-struct libipw_tpc_report {
- u8 transmit_power;
- u8 link_margin;
-} __packed;
-
-struct libipw_channel_map {
- u8 channel;
- u8 map;
-} __packed;
-
-struct libipw_ibss_dfs {
- struct libipw_info_element ie;
- u8 owner[ETH_ALEN];
- u8 recovery_interval;
- struct libipw_channel_map channel_map[];
-};
-
-struct libipw_csa {
- u8 mode;
- u8 channel;
- u8 count;
-} __packed;
-
-struct libipw_quiet {
- u8 count;
- u8 period;
- u8 duration;
- u8 offset;
-} __packed;
-
-struct libipw_network {
- /* These entries are used to identify a unique network */
- u8 bssid[ETH_ALEN];
- u8 channel;
- /* Ensure null-terminated for any debug msgs */
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
-
- struct libipw_qos_data qos_data;
-
- /* These are network statistics */
- struct libipw_rx_stats stats;
- u16 capability;
- u8 rates[MAX_RATES_LENGTH];
- u8 rates_len;
- u8 rates_ex[MAX_RATES_EX_LENGTH];
- u8 rates_ex_len;
- unsigned long last_scanned;
- u8 mode;
- u32 flags;
- u32 last_associate;
- u32 time_stamp[2];
- u16 beacon_interval;
- u16 listen_interval;
- u16 atim_window;
- u8 erp_value;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
- struct libipw_tim_parameters tim;
-
- /* 802.11h info */
-
- /* Power Constraint - mandatory if spctrm mgmt required */
- u8 power_constraint;
-
- /* TPC Report - mandatory if spctrm mgmt required */
- struct libipw_tpc_report tpc_report;
-
- /* Channel Switch Announcement - optional if spctrm mgmt required */
- struct libipw_csa csa;
-
- /* Quiet - optional if spctrm mgmt required */
- struct libipw_quiet quiet;
-
- struct list_head list;
-};
-
-enum libipw_state {
- LIBIPW_UNINITIALIZED = 0,
- LIBIPW_INITIALIZED,
- LIBIPW_ASSOCIATING,
- LIBIPW_ASSOCIATED,
- LIBIPW_AUTHENTICATING,
- LIBIPW_AUTHENTICATED,
- LIBIPW_SHUTDOWN
-};
-
-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
-#define DEFAULT_FTS 2346
-
-#define CFG_LIBIPW_RESERVE_FCS (1<<0)
-#define CFG_LIBIPW_COMPUTE_FCS (1<<1)
-#define CFG_LIBIPW_RTS (1<<2)
-
-#define LIBIPW_24GHZ_MIN_CHANNEL 1
-#define LIBIPW_24GHZ_MAX_CHANNEL 14
-#define LIBIPW_24GHZ_CHANNELS (LIBIPW_24GHZ_MAX_CHANNEL - \
- LIBIPW_24GHZ_MIN_CHANNEL + 1)
-
-#define LIBIPW_52GHZ_MIN_CHANNEL 34
-#define LIBIPW_52GHZ_MAX_CHANNEL 165
-#define LIBIPW_52GHZ_CHANNELS (LIBIPW_52GHZ_MAX_CHANNEL - \
- LIBIPW_52GHZ_MIN_CHANNEL + 1)
-
-enum {
- LIBIPW_CH_PASSIVE_ONLY = (1 << 0),
- LIBIPW_CH_80211H_RULES = (1 << 1),
- LIBIPW_CH_B_ONLY = (1 << 2),
- LIBIPW_CH_NO_IBSS = (1 << 3),
- LIBIPW_CH_UNIFORM_SPREADING = (1 << 4),
- LIBIPW_CH_RADAR_DETECT = (1 << 5),
- LIBIPW_CH_INVALID = (1 << 6),
-};
-
-struct libipw_channel {
- u32 freq; /* in MHz */
- u8 channel;
- u8 flags;
- u8 max_power; /* in dBm */
-};
-
-struct libipw_geo {
- u8 name[4];
- u8 bg_channels;
- u8 a_channels;
- struct libipw_channel bg[LIBIPW_24GHZ_CHANNELS];
- struct libipw_channel a[LIBIPW_52GHZ_CHANNELS];
-};
-
-struct libipw_device {
- struct net_device *dev;
- struct wireless_dev wdev;
- struct libipw_security sec;
-
- /* Bookkeeping structures */
- struct libipw_stats ieee_stats;
-
- struct libipw_geo geo;
- struct ieee80211_supported_band bg_band;
- struct ieee80211_supported_band a_band;
-
- /* Probe / Beacon management */
- struct list_head network_free_list;
- struct list_head network_list;
- struct libipw_network *networks[MAX_NETWORK_COUNT];
- int scans;
- int scan_age;
-
- int iw_mode; /* operating mode (IW_MODE_*) */
- struct iw_spy_data spy_data; /* iwspy support */
-
- spinlock_t lock;
-
- int tx_headroom; /* Set to size of any additional room needed at front
- * of allocated Tx SKBs */
- u32 config;
-
- /* WEP and other encryption related settings at the device level */
- int open_wep; /* Set to 1 to allow unencrypted frames */
-
- /* If the host performs {en,de}cryption, then set to 1 */
- int host_encrypt;
- int host_encrypt_msdu;
- int host_decrypt;
- /* host performs multicast decryption */
- int host_mc_decrypt;
-
- /* host should strip IV and ICV from protected frames */
- /* meaningful only when hardware decryption is being used */
- int host_strip_iv_icv;
-
- int host_open_frag;
- int ieee802_1x; /* is IEEE 802.1X used */
-
- /* WPA data */
- int wpa_enabled;
- int drop_unencrypted;
- int privacy_invoked;
- size_t wpa_ie_len;
- u8 *wpa_ie;
-
- struct lib80211_crypt_info crypt_info;
-
- int bcrx_sta_key; /* use individual keys to override default keys even
- * with RX of broad/multicast frames */
-
- /* Fragmentation structures */
- struct libipw_frag_entry frag_cache[LIBIPW_FRAG_CACHE_LEN];
- unsigned int frag_next_idx;
- u16 fts; /* Fragmentation Threshold */
- u16 rts; /* RTS threshold */
-
- /* Association info */
- u8 bssid[ETH_ALEN];
-
- enum libipw_state state;
-
- int mode; /* A, B, G */
- int modulation; /* CCK, OFDM */
- int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */
- int abg_true; /* ABG flag */
-
- int perfect_rssi;
- int worst_rssi;
-
- u16 prev_seq_ctl; /* used to drop duplicate frames */
-
- /* Callback functions */
- void (*set_security) (struct net_device * dev,
- struct libipw_security * sec);
- netdev_tx_t (*hard_start_xmit) (struct libipw_txb * txb,
- struct net_device * dev, int pri);
- int (*is_queue_full) (struct net_device * dev, int pri);
-
- int (*handle_management) (struct net_device * dev,
- struct libipw_network * network, u16 type);
- int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
-
- /* Typical STA methods */
- int (*handle_auth) (struct net_device * dev,
- struct libipw_auth * auth);
- int (*handle_deauth) (struct net_device * dev,
- struct libipw_deauth * auth);
- int (*handle_action) (struct net_device * dev,
- struct libipw_action * action,
- struct libipw_rx_stats * stats);
- int (*handle_disassoc) (struct net_device * dev,
- struct libipw_disassoc * assoc);
- int (*handle_beacon) (struct net_device * dev,
- struct libipw_beacon * beacon,
- struct libipw_network * network);
- int (*handle_probe_response) (struct net_device * dev,
- struct libipw_probe_response * resp,
- struct libipw_network * network);
- int (*handle_probe_request) (struct net_device * dev,
- struct libipw_probe_request * req,
- struct libipw_rx_stats * stats);
- int (*handle_assoc_response) (struct net_device * dev,
- struct libipw_assoc_response * resp,
- struct libipw_network * network);
-
- /* Typical AP methods */
- int (*handle_assoc_request) (struct net_device * dev);
- int (*handle_reassoc_request) (struct net_device * dev,
- struct libipw_reassoc_request * req);
-
- /* This must be the last item so that it points to the data
- * allocated beyond this structure by alloc_libipw */
- u8 priv[];
-};
-
-#define IEEE_A (1<<0)
-#define IEEE_B (1<<1)
-#define IEEE_G (1<<2)
-#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
-
-static inline void *libipw_priv(struct net_device *dev)
-{
- return ((struct libipw_device *)netdev_priv(dev))->priv;
-}
-
-static inline int libipw_is_valid_mode(struct libipw_device *ieee,
- int mode)
-{
- /*
- * It is possible for both access points and our device to support
- * combinations of modes, so as long as there is one valid combination
- * of ap/device supported modes, then return success
- *
- */
- if ((mode & IEEE_A) &&
- (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
- (ieee->freq_band & LIBIPW_52GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_G) &&
- (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
- (ieee->freq_band & LIBIPW_24GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_B) &&
- (ieee->modulation & LIBIPW_CCK_MODULATION) &&
- (ieee->freq_band & LIBIPW_24GHZ_BAND))
- return 1;
-
- return 0;
-}
-
-static inline int libipw_get_hdrlen(u16 fc)
-{
- int hdrlen = LIBIPW_3ADDR_LEN;
- u16 stype = WLAN_FC_GET_STYPE(fc);
-
- switch (WLAN_FC_GET_TYPE(fc)) {
- case IEEE80211_FTYPE_DATA:
- if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = LIBIPW_4ADDR_LEN;
- if (stype & IEEE80211_STYPE_QOS_DATA)
- hdrlen += 2;
- break;
- case IEEE80211_FTYPE_CTL:
- switch (WLAN_FC_GET_STYPE(fc)) {
- case IEEE80211_STYPE_CTS:
- case IEEE80211_STYPE_ACK:
- hdrlen = LIBIPW_1ADDR_LEN;
- break;
- default:
- hdrlen = LIBIPW_2ADDR_LEN;
- break;
- }
- break;
- }
-
- return hdrlen;
-}
-
-static inline u8 *libipw_get_payload(struct ieee80211_hdr *hdr)
-{
- switch (libipw_get_hdrlen(le16_to_cpu(hdr->frame_control))) {
- case LIBIPW_1ADDR_LEN:
- return ((struct libipw_hdr_1addr *)hdr)->payload;
- case LIBIPW_2ADDR_LEN:
- return ((struct libipw_hdr_2addr *)hdr)->payload;
- case LIBIPW_3ADDR_LEN:
- return ((struct libipw_hdr_3addr *)hdr)->payload;
- case LIBIPW_4ADDR_LEN:
- return ((struct libipw_hdr_4addr *)hdr)->payload;
- }
- return NULL;
-}
-
-static inline int libipw_is_ofdm_rate(u8 rate)
-{
- switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
- case LIBIPW_OFDM_RATE_6MB:
- case LIBIPW_OFDM_RATE_9MB:
- case LIBIPW_OFDM_RATE_12MB:
- case LIBIPW_OFDM_RATE_18MB:
- case LIBIPW_OFDM_RATE_24MB:
- case LIBIPW_OFDM_RATE_36MB:
- case LIBIPW_OFDM_RATE_48MB:
- case LIBIPW_OFDM_RATE_54MB:
- return 1;
- }
- return 0;
-}
-
-static inline int libipw_is_cck_rate(u8 rate)
-{
- switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
- case LIBIPW_CCK_RATE_1MB:
- case LIBIPW_CCK_RATE_2MB:
- case LIBIPW_CCK_RATE_5MB:
- case LIBIPW_CCK_RATE_11MB:
- return 1;
- }
- return 0;
-}
-
-/* libipw.c */
-void free_libipw(struct net_device *dev, int monitor);
-struct net_device *alloc_libipw(int sizeof_priv, int monitor);
-
-void libipw_networks_age(struct libipw_device *ieee, unsigned long age_secs);
-
-int libipw_set_encryption(struct libipw_device *ieee);
-
-/* libipw_tx.c */
-netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev);
-void libipw_txb_free(struct libipw_txb *);
-
-/* libipw_rx.c */
-void libipw_rx_any(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *stats);
-int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats);
-/* make sure to set stats->len */
-void libipw_rx_mgt(struct libipw_device *ieee, struct libipw_hdr_4addr *header,
- struct libipw_rx_stats *stats);
-
-/* libipw_geo.c */
-const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee);
-void libipw_set_geo(struct libipw_device *ieee, const struct libipw_geo *geo);
-
-int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel);
-int libipw_channel_to_index(struct libipw_device *ieee, u8 channel);
-u8 libipw_freq_to_channel(struct libipw_device *ieee, u32 freq);
-u8 libipw_get_channel_flags(struct libipw_device *ieee, u8 channel);
-const struct libipw_channel *libipw_get_channel(struct libipw_device *ieee,
- u8 channel);
-u32 libipw_channel_to_freq(struct libipw_device *ieee, u8 channel);
-
-/* libipw_wx.c */
-int libipw_wx_get_scan(struct libipw_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-int libipw_wx_set_encode(struct libipw_device *ieee,
- struct iw_request_info *info, union iwreq_data *wrqu,
- char *key);
-int libipw_wx_get_encode(struct libipw_device *ieee,
- struct iw_request_info *info, union iwreq_data *wrqu,
- char *key);
-int libipw_wx_set_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-int libipw_wx_get_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-static inline void libipw_increment_scans(struct libipw_device *ieee)
-{
- ieee->scans++;
-}
-
-static inline int libipw_get_scans(struct libipw_device *ieee)
-{
- return ieee->scans;
-}
-
-#endif /* LIBIPW_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
deleted file mode 100644
index f2ae3f8f2f5cb..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2005 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-
-#include "libipw.h"
-
-int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- /* NOTE: If G mode is currently supported but
- * this is a B only channel, we don't see it
- * as valid. */
- if ((ieee->geo.bg[i].channel == channel) &&
- !(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) &&
- (!(ieee->mode & IEEE_G) ||
- !(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY)))
- return LIBIPW_24GHZ_BAND;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if ((ieee->geo.a[i].channel == channel) &&
- !(ieee->geo.a[i].flags & LIBIPW_CH_INVALID))
- return LIBIPW_52GHZ_BAND;
-
- return 0;
-}
-
-int libipw_channel_to_index(struct libipw_device *ieee, u8 channel)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return -1;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- if (ieee->geo.bg[i].channel == channel)
- return i;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if (ieee->geo.a[i].channel == channel)
- return i;
-
- return -1;
-}
-
-u32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel)
-{
- const struct libipw_channel * ch;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- ch = libipw_get_channel(ieee, channel);
- if (!ch->channel)
- return 0;
- return ch->freq;
-}
-
-u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- freq /= 100000;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- if (ieee->geo.bg[i].freq == freq)
- return ieee->geo.bg[i].channel;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if (ieee->geo.a[i].freq == freq)
- return ieee->geo.a[i].channel;
-
- return 0;
-}
-
-void libipw_set_geo(struct libipw_device *ieee,
- const struct libipw_geo *geo)
-{
- memcpy(ieee->geo.name, geo->name, 3);
- ieee->geo.name[3] = '\0';
- ieee->geo.bg_channels = geo->bg_channels;
- ieee->geo.a_channels = geo->a_channels;
- memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
- sizeof(struct libipw_channel));
- memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
- sizeof(struct libipw_channel));
-}
-
-const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee)
-{
- return &ieee->geo;
-}
-
-u8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel)
-{
- int index = libipw_channel_to_index(ieee, channel);
-
- if (index == -1)
- return LIBIPW_CH_INVALID;
-
- if (channel <= LIBIPW_24GHZ_CHANNELS)
- return ieee->geo.bg[index].flags;
-
- return ieee->geo.a[index].flags;
-}
-
-static const struct libipw_channel bad_channel = {
- .channel = 0,
- .flags = LIBIPW_CH_INVALID,
- .max_power = 0,
-};
-
-const struct libipw_channel *libipw_get_channel(struct libipw_device
- *ieee, u8 channel)
-{
- int index = libipw_channel_to_index(ieee, channel);
-
- if (index == -1)
- return &bad_channel;
-
- if (channel <= LIBIPW_24GHZ_CHANNELS)
- return &ieee->geo.bg[index];
-
- return &ieee->geo.a[index];
-}
-
-EXPORT_SYMBOL(libipw_get_channel);
-EXPORT_SYMBOL(libipw_get_channel_flags);
-EXPORT_SYMBOL(libipw_is_valid_channel);
-EXPORT_SYMBOL(libipw_freq_to_channel);
-EXPORT_SYMBOL(libipw_channel_to_freq);
-EXPORT_SYMBOL(libipw_channel_to_index);
-EXPORT_SYMBOL(libipw_set_geo);
-EXPORT_SYMBOL(libipw_get_geo);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
deleted file mode 100644
index 43bab92a4148f..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c
+++ /dev/null
@@ -1,297 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*******************************************************************************
-
- Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
-
- Portions of this file are based on the WEP enablement code provided by the
- Host AP project hostap-drivers v0.1.3
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <[email protected]>
- Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <net/net_namespace.h>
-#include <net/arp.h>
-
-#include "libipw.h"
-
-#define DRV_DESCRIPTION "802.11 data/management/control stack"
-#define DRV_NAME "libipw"
-#define DRV_PROCNAME "ieee80211"
-#define DRV_VERSION LIBIPW_VERSION
-#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <[email protected]>"
-
-MODULE_VERSION(DRV_VERSION);
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-
-static struct cfg80211_ops libipw_config_ops = { };
-static void *libipw_wiphy_privid = &libipw_wiphy_privid;
-
-static int libipw_networks_allocate(struct libipw_device *ieee)
-{
- int i, j;
-
- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
- ieee->networks[i] = kzalloc(sizeof(struct libipw_network),
- GFP_KERNEL);
- if (!ieee->networks[i]) {
- LIBIPW_ERROR("Out of memory allocating beacons\n");
- for (j = 0; j < i; j++)
- kfree(ieee->networks[j]);
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-
-static inline void libipw_networks_free(struct libipw_device *ieee)
-{
- int i;
-
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- kfree(ieee->networks[i]);
-}
-
-void libipw_networks_age(struct libipw_device *ieee,
- unsigned long age_secs)
-{
- struct libipw_network *network = NULL;
- unsigned long flags;
- unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
-
- spin_lock_irqsave(&ieee->lock, flags);
- list_for_each_entry(network, &ieee->network_list, list) {
- network->last_scanned -= age_jiffies;
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-EXPORT_SYMBOL(libipw_networks_age);
-
-static void libipw_networks_initialize(struct libipw_device *ieee)
-{
- int i;
-
- INIT_LIST_HEAD(&ieee->network_free_list);
- INIT_LIST_HEAD(&ieee->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- list_add_tail(&ieee->networks[i]->list,
- &ieee->network_free_list);
-}
-
-struct net_device *alloc_libipw(int sizeof_priv, int monitor)
-{
- struct libipw_device *ieee;
- struct net_device *dev;
- int err;
-
- LIBIPW_DEBUG_INFO("Initializing...\n");
-
- dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
- if (!dev)
- goto failed;
-
- ieee = netdev_priv(dev);
-
- ieee->dev = dev;
-
- if (!monitor) {
- ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
- if (!ieee->wdev.wiphy) {
- LIBIPW_ERROR("Unable to allocate wiphy.\n");
- goto failed_free_netdev;
- }
-
- ieee->dev->ieee80211_ptr = &ieee->wdev;
- ieee->wdev.iftype = NL80211_IFTYPE_STATION;
-
- /* Fill-out wiphy structure bits we know... Not enough info
- here to call set_wiphy_dev or set MAC address or channel info
- -- have to do that in ->ndo_init... */
- ieee->wdev.wiphy->privid = libipw_wiphy_privid;
-
- ieee->wdev.wiphy->max_scan_ssids = 1;
- ieee->wdev.wiphy->max_scan_ie_len = 0;
- ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
- | BIT(NL80211_IFTYPE_ADHOC);
- }
-
- err = libipw_networks_allocate(ieee);
- if (err) {
- LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
- goto failed_free_wiphy;
- }
- libipw_networks_initialize(ieee);
-
- /* Default fragmentation threshold is maximum payload size */
- ieee->fts = DEFAULT_FTS;
- ieee->rts = DEFAULT_FTS;
- ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
- ieee->open_wep = 1;
-
- /* Default to enabling full open WEP with host based encrypt/decrypt */
- ieee->host_encrypt = 1;
- ieee->host_decrypt = 1;
- ieee->host_mc_decrypt = 1;
-
- /* Host fragmentation in Open mode. Default is enabled.
- * Note: host fragmentation is always enabled if host encryption
- * is enabled. For cards can do hardware encryption, they must do
- * hardware fragmentation as well. So we don't need a variable
- * like host_enc_frag. */
- ieee->host_open_frag = 1;
- ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
-
- spin_lock_init(&ieee->lock);
-
- lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
-
- ieee->wpa_enabled = 0;
- ieee->drop_unencrypted = 0;
- ieee->privacy_invoked = 0;
-
- return dev;
-
-failed_free_wiphy:
- if (!monitor)
- wiphy_free(ieee->wdev.wiphy);
-failed_free_netdev:
- free_netdev(dev);
-failed:
- return NULL;
-}
-EXPORT_SYMBOL(alloc_libipw);
-
-void free_libipw(struct net_device *dev, int monitor)
-{
- struct libipw_device *ieee = netdev_priv(dev);
-
- lib80211_crypt_info_free(&ieee->crypt_info);
-
- libipw_networks_free(ieee);
-
- /* free cfg80211 resources */
- if (!monitor)
- wiphy_free(ieee->wdev.wiphy);
-
- free_netdev(dev);
-}
-EXPORT_SYMBOL(free_libipw);
-
-#ifdef CONFIG_LIBIPW_DEBUG
-
-static int debug = 0;
-u32 libipw_debug_level = 0;
-EXPORT_SYMBOL_GPL(libipw_debug_level);
-static struct proc_dir_entry *libipw_proc = NULL;
-
-static int debug_level_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "0x%08X\n", libipw_debug_level);
- return 0;
-}
-
-static int debug_level_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_level_proc_show, NULL);
-}
-
-static ssize_t debug_level_proc_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *pos)
-{
- char buf[] = "0x00000000\n";
- size_t len = min(sizeof(buf) - 1, count);
- unsigned long val;
-
- if (copy_from_user(buf, buffer, len))
- return count;
- buf[len] = 0;
- if (sscanf(buf, "%li", &val) != 1)
- printk(KERN_INFO DRV_NAME
- ": %s is not in hex or decimal form.\n", buf);
- else
- libipw_debug_level = val;
-
- return strnlen(buf, len);
-}
-
-static const struct proc_ops debug_level_proc_ops = {
- .proc_open = debug_level_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = single_release,
- .proc_write = debug_level_proc_write,
-};
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-static int __init libipw_init(void)
-{
-#ifdef CONFIG_LIBIPW_DEBUG
- struct proc_dir_entry *e;
-
- libipw_debug_level = debug;
- libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
- if (libipw_proc == NULL) {
- LIBIPW_ERROR("Unable to create " DRV_PROCNAME
- " proc directory\n");
- return -EIO;
- }
- e = proc_create("debug_level", 0644, libipw_proc,
- &debug_level_proc_ops);
- if (!e) {
- remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
- libipw_proc = NULL;
- return -EIO;
- }
-#endif /* CONFIG_LIBIPW_DEBUG */
-
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-
- return 0;
-}
-
-static void __exit libipw_exit(void)
-{
-#ifdef CONFIG_LIBIPW_DEBUG
- if (libipw_proc) {
- remove_proc_entry("debug_level", libipw_proc);
- remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
- libipw_proc = NULL;
- }
-#endif /* CONFIG_LIBIPW_DEBUG */
-}
-
-#ifdef CONFIG_LIBIPW_DEBUG
-#include <linux/moduleparam.h>
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-module_exit(libipw_exit);
-module_init(libipw_init);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
deleted file mode 100644
index 48d6870bbf4e2..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
+++ /dev/null
@@ -1,1737 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Original code based Host AP (software wireless LAN access point) driver
- * for Intersil Prism2/2.5/3 - hostap.o module, common routines
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <[email protected]>
- * Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
- * Copyright (c) 2004-2005, Intel Corporation
- */
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/gfp.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <linux/ctype.h>
-
-#include <net/lib80211.h>
-
-#include "libipw.h"
-
-static void libipw_monitor_rx(struct libipw_device *ieee,
- struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
-
- skb->dev = ieee->dev;
- skb_reset_mac_header(skb);
- skb_pull(skb, libipw_get_hdrlen(fc));
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_80211_RAW);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-}
-
-/* Called only as a tasklet (software IRQ) */
-static struct libipw_frag_entry *libipw_frag_cache_find(struct
- libipw_device
- *ieee,
- unsigned int seq,
- unsigned int frag,
- u8 * src,
- u8 * dst)
-{
- struct libipw_frag_entry *entry;
- int i;
-
- for (i = 0; i < LIBIPW_FRAG_CACHE_LEN; i++) {
- entry = &ieee->frag_cache[i];
- if (entry->skb != NULL &&
- time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
- LIBIPW_DEBUG_FRAG("expiring fragment cache entry "
- "seq=%u last_frag=%u\n",
- entry->seq, entry->last_frag);
- dev_kfree_skb_any(entry->skb);
- entry->skb = NULL;
- }
-
- if (entry->skb != NULL && entry->seq == seq &&
- (entry->last_frag + 1 == frag || frag == -1) &&
- ether_addr_equal(entry->src_addr, src) &&
- ether_addr_equal(entry->dst_addr, dst))
- return entry;
- }
-
- return NULL;
-}
-
-/* Called only as a tasklet (software IRQ) */
-static struct sk_buff *libipw_frag_cache_get(struct libipw_device *ieee,
- struct libipw_hdr_4addr *hdr)
-{
- struct sk_buff *skb = NULL;
- u16 sc;
- unsigned int frag, seq;
- struct libipw_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctl);
- frag = WLAN_GET_SEQ_FRAG(sc);
- seq = WLAN_GET_SEQ_SEQ(sc);
-
- if (frag == 0) {
- /* Reserve enough space to fit maximum frame length */
- skb = dev_alloc_skb(ieee->dev->mtu +
- sizeof(struct libipw_hdr_4addr) +
- 8 /* LLC */ +
- 2 /* alignment */ +
- 8 /* WEP */ + ETH_ALEN /* WDS */ );
- if (skb == NULL)
- return NULL;
-
- entry = &ieee->frag_cache[ieee->frag_next_idx];
- ieee->frag_next_idx++;
- if (ieee->frag_next_idx >= LIBIPW_FRAG_CACHE_LEN)
- ieee->frag_next_idx = 0;
-
- if (entry->skb != NULL)
- dev_kfree_skb_any(entry->skb);
-
- entry->first_frag_time = jiffies;
- entry->seq = seq;
- entry->last_frag = frag;
- entry->skb = skb;
- memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
- } else {
- /* received a fragment of a frame for which the head fragment
- * should have already been received */
- entry = libipw_frag_cache_find(ieee, seq, frag, hdr->addr2,
- hdr->addr1);
- if (entry != NULL) {
- entry->last_frag = frag;
- skb = entry->skb;
- }
- }
-
- return skb;
-}
-
-/* Called only as a tasklet (software IRQ) */
-static int libipw_frag_cache_invalidate(struct libipw_device *ieee,
- struct libipw_hdr_4addr *hdr)
-{
- u16 sc;
- unsigned int seq;
- struct libipw_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctl);
- seq = WLAN_GET_SEQ_SEQ(sc);
-
- entry = libipw_frag_cache_find(ieee, seq, -1, hdr->addr2,
- hdr->addr1);
-
- if (entry == NULL) {
- LIBIPW_DEBUG_FRAG("could not invalidate fragment cache "
- "entry (seq=%u)\n", seq);
- return -1;
- }
-
- entry->skb = NULL;
- return 0;
-}
-
-#ifdef NOT_YET
-/* libipw_rx_frame_mgtmt
- *
- * Responsible for handling management control frames
- *
- * Called by libipw_rx */
-static int
-libipw_rx_frame_mgmt(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats, u16 type,
- u16 stype)
-{
- if (ieee->iw_mode == IW_MODE_MASTER) {
- printk(KERN_DEBUG "%s: Master mode not yet supported.\n",
- ieee->dev->name);
- return 0;
-/*
- hostap_update_sta_ps(ieee, (struct hostap_libipw_hdr_4addr *)
- skb->data);*/
- }
-
- if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {
- if (stype == WLAN_FC_STYPE_BEACON &&
- ieee->iw_mode == IW_MODE_MASTER) {
- struct sk_buff *skb2;
- /* Process beacon frames also in kernel driver to
- * update STA(AP) table statistics */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2)
- hostap_rx(skb2->dev, skb2, rx_stats);
- }
-
- /* send management frames to the user space daemon for
- * processing */
- ieee->apdevstats.rx_packets++;
- ieee->apdevstats.rx_bytes += skb->len;
- prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
- return 0;
- }
-
- if (ieee->iw_mode == IW_MODE_MASTER) {
- if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
- printk(KERN_DEBUG "%s: unknown management frame "
- "(type=0x%02x, stype=0x%02x) dropped\n",
- skb->dev->name, type, stype);
- return -1;
- }
-
- hostap_rx(skb->dev, skb, rx_stats);
- return 0;
- }
-
- printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
- "received in non-Host AP mode\n", skb->dev->name);
- return -1;
-}
-#endif
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char libipw_rfc1042_header[] =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char libipw_bridge_tunnel_header[] =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-/* Called by libipw_rx_frame_decrypt */
-static int libipw_is_eapol_frame(struct libipw_device *ieee,
- struct sk_buff *skb)
-{
- struct net_device *dev = ieee->dev;
- u16 fc, ethertype;
- struct libipw_hdr_3addr *hdr;
- u8 *pos;
-
- if (skb->len < 24)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
-
- /* check that the frame is unicast frame to us */
- if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr) &&
- ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- /* ToDS frame with own addr BSSID and DA */
- } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- /* FromDS frame with own addr as DA */
- } else
- return 0;
-
- if (skb->len < 24 + 8)
- return 0;
-
- /* check for port access entity Ethernet type */
- pos = skb->data + 24;
- ethertype = (pos[6] << 8) | pos[7];
- if (ethertype == ETH_P_PAE)
- return 1;
-
- return 0;
-}
-
-/* Called only as a tasklet (software IRQ), by libipw_rx */
-static int
-libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct libipw_hdr_3addr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- LIBIPW_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
- hdr->addr2, res);
- if (res == -2)
- LIBIPW_DEBUG_DROP("Decryption failed ICV "
- "mismatch (key %d)\n",
- skb->data[hdrlen + 3] >> 6);
- ieee->ieee_stats.rx_discards_undecryptable++;
- return -1;
- }
-
- return res;
-}
-
-/* Called only as a tasklet (software IRQ), by libipw_rx */
-static int
-libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee,
- struct sk_buff *skb, int keyidx,
- struct lib80211_crypt_data *crypt)
-{
- struct libipw_hdr_3addr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2,
- keyidx);
- return -1;
- }
-
- return 0;
-}
-
-/* All received frames are sent to this function. @skb contains the frame in
- * IEEE 802.11 format, i.e., in the format it was sent over air.
- * This function is called only as a tasklet (software IRQ). */
-int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats)
-{
- struct net_device *dev = ieee->dev;
- struct libipw_hdr_4addr *hdr;
- size_t hdrlen;
- u16 fc, type, stype, sc;
- unsigned int frag;
- u8 *payload;
- u16 ethertype;
-#ifdef NOT_YET
- struct net_device *wds = NULL;
- struct sk_buff *skb2 = NULL;
- struct net_device *wds = NULL;
- int frame_authorized = 0;
- int from_assoc_ap = 0;
- void *sta = NULL;
-#endif
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
- struct lib80211_crypt_data *crypt = NULL;
- int keyidx = 0;
- int can_be_decrypted = 0;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- if (skb->len < 10) {
- printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
- goto rx_dropped;
- }
-
- fc = le16_to_cpu(hdr->frame_ctl);
- type = WLAN_FC_GET_TYPE(fc);
- stype = WLAN_FC_GET_STYPE(fc);
- sc = le16_to_cpu(hdr->seq_ctl);
- frag = WLAN_GET_SEQ_FRAG(sc);
- hdrlen = libipw_get_hdrlen(fc);
-
- if (skb->len < hdrlen) {
- printk(KERN_INFO "%s: invalid SKB length %d\n",
- dev->name, skb->len);
- goto rx_dropped;
- }
-
- /* Put this code here so that we avoid duplicating it in all
- * Rx paths. - Jean II */
-#ifdef CONFIG_WIRELESS_EXT
-#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
- /* If spy monitoring on */
- if (ieee->spy_data.spy_number > 0) {
- struct iw_quality wstats;
-
- wstats.updated = 0;
- if (rx_stats->mask & LIBIPW_STATMASK_RSSI) {
- wstats.level = rx_stats->signal;
- wstats.updated |= IW_QUAL_LEVEL_UPDATED;
- } else
- wstats.updated |= IW_QUAL_LEVEL_INVALID;
-
- if (rx_stats->mask & LIBIPW_STATMASK_NOISE) {
- wstats.noise = rx_stats->noise;
- wstats.updated |= IW_QUAL_NOISE_UPDATED;
- } else
- wstats.updated |= IW_QUAL_NOISE_INVALID;
-
- if (rx_stats->mask & LIBIPW_STATMASK_SIGNAL) {
- wstats.qual = rx_stats->signal;
- wstats.updated |= IW_QUAL_QUAL_UPDATED;
- } else
- wstats.updated |= IW_QUAL_QUAL_INVALID;
-
- /* Update spy records */
- wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
- }
-#endif /* IW_WIRELESS_SPY */
-#endif /* CONFIG_WIRELESS_EXT */
-
-#ifdef NOT_YET
- hostap_update_rx_stats(local->ap, hdr, rx_stats);
-#endif
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- libipw_monitor_rx(ieee, skb, rx_stats);
- return 1;
- }
-
- can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
- is_broadcast_ether_addr(hdr->addr2)) ?
- ieee->host_mc_decrypt : ieee->host_decrypt;
-
- if (can_be_decrypted) {
- if (skb->len >= hdrlen + 3) {
- /* Top two-bits of byte 3 are the key index */
- keyidx = skb->data[hdrlen + 3] >> 6;
- }
-
- /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx
- * is only allowed 2-bits of storage, no value of keyidx can
- * be provided via above code that would result in keyidx
- * being out of range */
- crypt = ieee->crypt_info.crypt[keyidx];
-
-#ifdef NOT_YET
- sta = NULL;
-
- /* Use station specific key to override default keys if the
- * receiver address is a unicast address ("individual RA"). If
- * bcrx_sta_key parameter is set, station specific key is used
- * even with broad/multicast targets (this is against IEEE
- * 802.11, but makes it easier to use different keys with
- * stations that do not support WEP key mapping). */
-
- if (is_unicast_ether_addr(hdr->addr1) || local->bcrx_sta_key)
- (void)hostap_handle_sta_crypto(local, hdr, &crypt,
- &sta);
-#endif
-
- /* allow NULL decrypt to indicate an station specific override
- * for default encryption */
- if (crypt && (crypt->ops == NULL ||
- crypt->ops->decrypt_mpdu == NULL))
- crypt = NULL;
-
- if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
- /* This seems to be triggered by some (multicast?)
- * frames from other than current BSS, so just drop the
- * frames silently instead of filling system log with
- * these reports. */
- LIBIPW_DEBUG_DROP("Decryption failed (not set)"
- " (SA=%pM)\n", hdr->addr2);
- ieee->ieee_stats.rx_discards_undecryptable++;
- goto rx_dropped;
- }
- }
-#ifdef NOT_YET
- if (type != WLAN_FC_TYPE_DATA) {
- if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
- fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
- (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
- printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from %pM\n", dev->name, hdr->addr2);
- /* TODO: could inform hostapd about this so that it
- * could send auth failure report */
- goto rx_dropped;
- }
-
- if (libipw_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
- goto rx_dropped;
- else
- goto rx_exit;
- }
-#endif
- /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */
- if (sc == ieee->prev_seq_ctl)
- goto rx_dropped;
- else
- ieee->prev_seq_ctl = sc;
-
- /* Data frame - extract src/dst addresses */
- if (skb->len < LIBIPW_3ADDR_LEN)
- goto rx_dropped;
-
- switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_FROMDS:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr3, ETH_ALEN);
- break;
- case IEEE80211_FCTL_TODS:
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- if (skb->len < LIBIPW_4ADDR_LEN)
- goto rx_dropped;
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr4, ETH_ALEN);
- break;
- default:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- }
-
-#ifdef NOT_YET
- if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
- goto rx_dropped;
- if (wds) {
- skb->dev = dev = wds;
- stats = hostap_get_stats(dev);
- }
-
- if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
- (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS && ieee->stadev &&
- ether_addr_equal(hdr->addr2, ieee->assoc_ap_addr)) {
- /* Frame from BSSID of the AP for which we are a client */
- skb->dev = dev = ieee->stadev;
- stats = hostap_get_stats(dev);
- from_assoc_ap = 1;
- }
-#endif
-
-#ifdef NOT_YET
- if ((ieee->iw_mode == IW_MODE_MASTER ||
- ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
- switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
- wds != NULL)) {
- case AP_RX_CONTINUE_NOT_AUTHORIZED:
- frame_authorized = 0;
- break;
- case AP_RX_CONTINUE:
- frame_authorized = 1;
- break;
- case AP_RX_DROP:
- goto rx_dropped;
- case AP_RX_EXIT:
- goto rx_exit;
- }
- }
-#endif
-
- /* Nullfunc frames may have PS-bit set, so they must be passed to
- * hostap_handle_sta_rx() before being dropped here. */
-
- stype &= ~IEEE80211_STYPE_QOS_DATA;
-
- if (stype != IEEE80211_STYPE_DATA &&
- stype != IEEE80211_STYPE_DATA_CFACK &&
- stype != IEEE80211_STYPE_DATA_CFPOLL &&
- stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
- if (stype != IEEE80211_STYPE_NULLFUNC)
- LIBIPW_DEBUG_DROP("RX: dropped data frame "
- "with no data (type=0x%02x, "
- "subtype=0x%02x, len=%d)\n",
- type, stype, skb->len);
- goto rx_dropped;
- }
-
- /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
-
- if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- (keyidx = libipw_rx_frame_decrypt(ieee, skb, crypt)) < 0)
- goto rx_dropped;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
-
- /* skb: hdr + (possibly fragmented) plaintext payload */
- // PR: FIXME: hostap has additional conditions in the "if" below:
- // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
- int flen;
- struct sk_buff *frag_skb = libipw_frag_cache_get(ieee, hdr);
- LIBIPW_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
-
- if (!frag_skb) {
- LIBIPW_DEBUG(LIBIPW_DL_RX | LIBIPW_DL_FRAG,
- "Rx cannot get skb from fragment "
- "cache (morefrag=%d seq=%u frag=%u)\n",
- (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
- WLAN_GET_SEQ_SEQ(sc), frag);
- goto rx_dropped;
- }
-
- flen = skb->len;
- if (frag != 0)
- flen -= hdrlen;
-
- if (frag_skb->tail + flen > frag_skb->end) {
- printk(KERN_WARNING "%s: host decrypted and "
- "reassembled frame did not fit skb\n",
- dev->name);
- libipw_frag_cache_invalidate(ieee, hdr);
- goto rx_dropped;
- }
-
- if (frag == 0) {
- /* copy first fragment (including full headers) into
- * beginning of the fragment cache skb */
- skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
- } else {
- /* append frame payload to the end of the fragment
- * cache skb */
- skb_copy_from_linear_data_offset(skb, hdrlen,
- skb_put(frag_skb, flen), flen);
- }
- dev_kfree_skb_any(skb);
- skb = NULL;
-
- if (fc & IEEE80211_FCTL_MOREFRAGS) {
- /* more fragments expected - leave the skb in fragment
- * cache for now; it will be delivered to upper layers
- * after all fragments have been received */
- goto rx_exit;
- }
-
- /* this was the last fragment and the frame will be
- * delivered, so remove skb from fragment cache */
- skb = frag_skb;
- hdr = (struct libipw_hdr_4addr *)skb->data;
- libipw_frag_cache_invalidate(ieee, hdr);
- }
-
- /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
- * encrypted/authenticated */
- if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- libipw_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
- goto rx_dropped;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
- if ( /*ieee->ieee802_1x && */
- libipw_is_eapol_frame(ieee, skb)) {
- /* pass unencrypted EAPOL frames even if encryption is
- * configured */
- } else {
- LIBIPW_DEBUG_DROP("encryption configured, but RX "
- "frame not encrypted (SA=%pM)\n",
- hdr->addr2);
- goto rx_dropped;
- }
- }
-
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
- !libipw_is_eapol_frame(ieee, skb)) {
- LIBIPW_DEBUG_DROP("dropped unencrypted RX data "
- "frame from %pM (drop_unencrypted=1)\n",
- hdr->addr2);
- goto rx_dropped;
- }
-
- /* If the frame was decrypted in hardware, we may need to strip off
- * any security data (IV, ICV, etc) that was left behind */
- if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
- ieee->host_strip_iv_icv) {
- int trimlen = 0;
-
- /* Top two-bits of byte 3 are the key index */
- if (skb->len >= hdrlen + 3)
- keyidx = skb->data[hdrlen + 3] >> 6;
-
- /* To strip off any security data which appears before the
- * payload, we simply increase hdrlen (as the header gets
- * chopped off immediately below). For the security data which
- * appears after the payload, we use skb_trim. */
-
- switch (ieee->sec.encode_alg[keyidx]) {
- case SEC_ALG_WEP:
- /* 4 byte IV */
- hdrlen += 4;
- /* 4 byte ICV */
- trimlen = 4;
- break;
- case SEC_ALG_TKIP:
- /* 4 byte IV, 4 byte ExtIV */
- hdrlen += 8;
- /* 8 byte MIC, 4 byte ICV */
- trimlen = 12;
- break;
- case SEC_ALG_CCMP:
- /* 8 byte CCMP header */
- hdrlen += 8;
- /* 8 byte MIC */
- trimlen = 8;
- break;
- }
-
- if (skb->len < trimlen)
- goto rx_dropped;
-
- __skb_trim(skb, skb->len - trimlen);
-
- if (skb->len < hdrlen)
- goto rx_dropped;
- }
-
- /* skb: hdr + (possible reassembled) full plaintext payload */
-
- payload = skb->data + hdrlen;
- ethertype = (payload[6] << 8) | payload[7];
-
-#ifdef NOT_YET
- /* If IEEE 802.1X is used, check whether the port is authorized to send
- * the received frame. */
- if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
- if (ethertype == ETH_P_PAE) {
- printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
- dev->name);
- if (ieee->hostapd && ieee->apdev) {
- /* Send IEEE 802.1X frames to the user
- * space daemon for processing */
- prism2_rx_80211(ieee->apdev, skb, rx_stats,
- PRISM2_RX_MGMT);
- ieee->apdevstats.rx_packets++;
- ieee->apdevstats.rx_bytes += skb->len;
- goto rx_exit;
- }
- } else if (!frame_authorized) {
- printk(KERN_DEBUG "%s: dropped frame from "
- "unauthorized port (IEEE 802.1X): "
- "ethertype=0x%04x\n", dev->name, ethertype);
- goto rx_dropped;
- }
- }
-#endif
-
- /* convert hdr + possible LLC headers into Ethernet header */
- if (skb->len - hdrlen >= 8 &&
- ((memcmp(payload, libipw_rfc1042_header, SNAP_SIZE) == 0 &&
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- memcmp(payload, libipw_bridge_tunnel_header, SNAP_SIZE) == 0)) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation and
- * replace EtherType */
- skb_pull(skb, hdrlen + SNAP_SIZE);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- } else {
- __be16 len;
- /* Leave Ethernet header part of hdr and full payload */
- skb_pull(skb, hdrlen);
- len = htons(skb->len);
- memcpy(skb_push(skb, 2), &len, 2);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- }
-
-#ifdef NOT_YET
- if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
- /* Non-standard frame: get addr4 from its bogus location after
- * the payload */
- skb_copy_to_linear_data_offset(skb, ETH_ALEN,
- skb->data + skb->len - ETH_ALEN,
- ETH_ALEN);
- skb_trim(skb, skb->len - ETH_ALEN);
- }
-#endif
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
-
-#ifdef NOT_YET
- if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
- if (is_multicast_ether_addr(dst)) {
- /* copy multicast frame both to the higher layers and
- * to the wireless media */
- ieee->ap->bridged_multicast++;
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- printk(KERN_DEBUG "%s: skb_clone failed for "
- "multicast frame\n", dev->name);
- } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
- /* send frame directly to the associated STA using
- * wireless media and not passing to higher layers */
- ieee->ap->bridged_unicast++;
- skb2 = skb;
- skb = NULL;
- }
- }
-
- if (skb2 != NULL) {
- /* send to wireless media */
- skb2->dev = dev;
- skb2->protocol = htons(ETH_P_802_3);
- skb_reset_mac_header(skb2);
- skb_reset_network_header(skb2);
- /* skb2->network_header += ETH_HLEN; */
- dev_queue_xmit(skb2);
- }
-#endif
-
- if (skb) {
- skb->protocol = eth_type_trans(skb, dev);
- memset(skb->cb, 0, sizeof(skb->cb));
- skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
- if (netif_rx(skb) == NET_RX_DROP) {
- /* netif_rx always succeeds, but it might drop
- * the packet. If it drops the packet, we log that
- * in our stats. */
- LIBIPW_DEBUG_DROP
- ("RX: netif_rx dropped the packet\n");
- dev->stats.rx_dropped++;
- }
- }
-
- rx_exit:
-#ifdef NOT_YET
- if (sta)
- hostap_handle_sta_release(sta);
-#endif
- return 1;
-
- rx_dropped:
- dev->stats.rx_dropped++;
-
- /* Returning 0 indicates to caller that we have not handled the SKB--
- * so it is still allocated and can be used again by underlying
- * hardware as a DMA target */
- return 0;
-}
-
-/* Filter out unrelated packets, call libipw_rx[_mgt]
- * This function takes over the skb, it should not be used again after calling
- * this function. */
-void libipw_rx_any(struct libipw_device *ieee,
- struct sk_buff *skb, struct libipw_rx_stats *stats)
-{
- struct libipw_hdr_4addr *hdr;
- int is_packet_for_us;
- u16 fc;
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- if (!libipw_rx(ieee, skb, stats))
- dev_kfree_skb_irq(skb);
- return;
- }
-
- if (skb->len < sizeof(struct ieee80211_hdr))
- goto drop_free;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
-
- if ((fc & IEEE80211_FCTL_VERS) != 0)
- goto drop_free;
-
- switch (fc & IEEE80211_FCTL_FTYPE) {
- case IEEE80211_FTYPE_MGMT:
- if (skb->len < sizeof(struct libipw_hdr_3addr))
- goto drop_free;
- libipw_rx_mgt(ieee, hdr, stats);
- dev_kfree_skb_irq(skb);
- return;
- case IEEE80211_FTYPE_DATA:
- break;
- case IEEE80211_FTYPE_CTL:
- return;
- default:
- return;
- }
-
- is_packet_for_us = 0;
- switch (ieee->iw_mode) {
- case IW_MODE_ADHOC:
- /* our BSS and not from/to DS */
- if (ether_addr_equal(hdr->addr3, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
- /* promisc: get all */
- if (ieee->dev->flags & IFF_PROMISC)
- is_packet_for_us = 1;
- /* to us */
- else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- /* mcast */
- else if (is_multicast_ether_addr(hdr->addr1))
- is_packet_for_us = 1;
- }
- break;
- case IW_MODE_INFRA:
- /* our BSS (== from our AP) and from DS */
- if (ether_addr_equal(hdr->addr2, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
- /* promisc: get all */
- if (ieee->dev->flags & IFF_PROMISC)
- is_packet_for_us = 1;
- /* to us */
- else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- /* mcast */
- else if (is_multicast_ether_addr(hdr->addr1)) {
- /* not our own packet bcasted from AP */
- if (!ether_addr_equal(hdr->addr3, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- }
- }
- break;
- default:
- /* ? */
- break;
- }
-
- if (is_packet_for_us)
- if (!libipw_rx(ieee, skb, stats))
- dev_kfree_skb_irq(skb);
- return;
-
-drop_free:
- dev_kfree_skb_irq(skb);
- ieee->dev->stats.rx_dropped++;
-}
-
-#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
-
-static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
-
-/*
-* Make the structure we read from the beacon packet to have
-* the right values
-*/
-static int libipw_verify_qos_info(struct libipw_qos_information_element
- *info_element, int sub_type)
-{
- if (info_element->elementID != QOS_ELEMENT_ID)
- return -1;
- if (info_element->qui_subtype != sub_type)
- return -1;
- if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
- return -1;
- if (info_element->qui_type != QOS_OUI_TYPE)
- return -1;
- if (info_element->version != QOS_VERSION_1)
- return -1;
-
- return 0;
-}
-
-/*
- * Parse a QoS parameter element
- */
-static int libipw_read_qos_param_element(
- struct libipw_qos_parameter_info *element_param,
- struct libipw_info_element *info_element)
-{
- size_t size = sizeof(*element_param);
-
- if (!element_param || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_param, info_element, size);
- return libipw_verify_qos_info(&element_param->info_element,
- QOS_OUI_PARAM_SUB_TYPE);
-}
-
-/*
- * Parse a QoS information element
- */
-static int libipw_read_qos_info_element(
- struct libipw_qos_information_element *element_info,
- struct libipw_info_element *info_element)
-{
- size_t size = sizeof(struct libipw_qos_information_element) - 2;
-
- if (!element_info || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_info, info_element, size);
- return libipw_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE);
-}
-
-/*
- * Write QoS parameters from the ac parameters.
- */
-static void libipw_qos_convert_ac_to_parameters(struct
- libipw_qos_parameter_info
- *param_elm, struct
- libipw_qos_parameters
- *qos_param)
-{
- int i;
- struct libipw_qos_ac_parameter *ac_params;
- u32 txop;
- u8 cw_min;
- u8 cw_max;
-
- for (i = 0; i < QOS_QUEUE_NUM; i++) {
- ac_params = &(param_elm->ac_params_record[i]);
-
- qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F;
- qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2;
-
- cw_min = ac_params->ecw_min_max & 0x0F;
- qos_param->cw_min[i] = cpu_to_le16((1 << cw_min) - 1);
-
- cw_max = (ac_params->ecw_min_max & 0xF0) >> 4;
- qos_param->cw_max[i] = cpu_to_le16((1 << cw_max) - 1);
-
- qos_param->flag[i] =
- (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
-
- txop = le16_to_cpu(ac_params->tx_op_limit) * 32;
- qos_param->tx_op_limit[i] = cpu_to_le16(txop);
- }
-}
-
-/*
- * we have a generic data element which it may contain QoS information or
- * parameters element. check the information element length to decide
- * which type to read
- */
-static int libipw_parse_qos_info_param_IE(struct libipw_info_element
- *info_element,
- struct libipw_network *network)
-{
- int rc = 0;
- struct libipw_qos_parameters *qos_param = NULL;
- struct libipw_qos_information_element qos_info_element;
-
- rc = libipw_read_qos_info_element(&qos_info_element, info_element);
-
- if (rc == 0) {
- network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
- network->flags |= NETWORK_HAS_QOS_INFORMATION;
- } else {
- struct libipw_qos_parameter_info param_element;
-
- rc = libipw_read_qos_param_element(&param_element,
- info_element);
- if (rc == 0) {
- qos_param = &(network->qos_data.parameters);
- libipw_qos_convert_ac_to_parameters(&param_element,
- qos_param);
- network->flags |= NETWORK_HAS_QOS_PARAMETERS;
- network->qos_data.param_count =
- param_element.info_element.ac_info & 0x0F;
- }
- }
-
- if (rc == 0) {
- LIBIPW_DEBUG_QOS("QoS is supported\n");
- network->qos_data.supported = 1;
- }
- return rc;
-}
-
-#ifdef CONFIG_LIBIPW_DEBUG
-#define MFIE_STRING(x) case WLAN_EID_ ##x: return #x
-
-static const char *get_info_element_string(u16 id)
-{
- switch (id) {
- MFIE_STRING(SSID);
- MFIE_STRING(SUPP_RATES);
- MFIE_STRING(FH_PARAMS);
- MFIE_STRING(DS_PARAMS);
- MFIE_STRING(CF_PARAMS);
- MFIE_STRING(TIM);
- MFIE_STRING(IBSS_PARAMS);
- MFIE_STRING(COUNTRY);
- MFIE_STRING(REQUEST);
- MFIE_STRING(CHALLENGE);
- MFIE_STRING(PWR_CONSTRAINT);
- MFIE_STRING(PWR_CAPABILITY);
- MFIE_STRING(TPC_REQUEST);
- MFIE_STRING(TPC_REPORT);
- MFIE_STRING(SUPPORTED_CHANNELS);
- MFIE_STRING(CHANNEL_SWITCH);
- MFIE_STRING(MEASURE_REQUEST);
- MFIE_STRING(MEASURE_REPORT);
- MFIE_STRING(QUIET);
- MFIE_STRING(IBSS_DFS);
- MFIE_STRING(ERP_INFO);
- MFIE_STRING(RSN);
- MFIE_STRING(EXT_SUPP_RATES);
- MFIE_STRING(VENDOR_SPECIFIC);
- MFIE_STRING(QOS_PARAMETER);
- default:
- return "UNKNOWN";
- }
-}
-#endif
-
-static int libipw_parse_info_param(struct libipw_info_element
- *info_element, u16 length,
- struct libipw_network *network)
-{
- u8 i;
-#ifdef CONFIG_LIBIPW_DEBUG
- char rates_str[64];
- char *p;
-#endif
-
- while (length >= sizeof(*info_element)) {
- if (sizeof(*info_element) + info_element->len > length) {
- LIBIPW_DEBUG_MGMT("Info elem: parse failed: "
- "info_element->len + 2 > left : "
- "info_element->len+2=%zd left=%d, id=%d.\n",
- info_element->len +
- sizeof(*info_element),
- length, info_element->id);
- /* We stop processing but don't return an error here
- * because some misbehaviour APs break this rule. ie.
- * Orinoco AP1000. */
- break;
- }
-
- switch (info_element->id) {
- case WLAN_EID_SSID:
- network->ssid_len = min(info_element->len,
- (u8) IW_ESSID_MAX_SIZE);
- memcpy(network->ssid, info_element->data,
- network->ssid_len);
- if (network->ssid_len < IW_ESSID_MAX_SIZE)
- memset(network->ssid + network->ssid_len, 0,
- IW_ESSID_MAX_SIZE - network->ssid_len);
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%*pE' len=%d.\n",
- network->ssid_len, network->ssid,
- network->ssid_len);
- break;
-
- case WLAN_EID_SUPP_RATES:
-#ifdef CONFIG_LIBIPW_DEBUG
- p = rates_str;
-#endif
- network->rates_len = min(info_element->len,
- MAX_RATES_LENGTH);
- for (i = 0; i < network->rates_len; i++) {
- network->rates[i] = info_element->data[i];
-#ifdef CONFIG_LIBIPW_DEBUG
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates[i]);
-#endif
- if (libipw_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- LIBIPW_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
- }
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n",
- rates_str, network->rates_len);
- break;
-
- case WLAN_EID_EXT_SUPP_RATES:
-#ifdef CONFIG_LIBIPW_DEBUG
- p = rates_str;
-#endif
- network->rates_ex_len = min(info_element->len,
- MAX_RATES_EX_LENGTH);
- for (i = 0; i < network->rates_ex_len; i++) {
- network->rates_ex[i] = info_element->data[i];
-#ifdef CONFIG_LIBIPW_DEBUG
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates_ex[i]);
-#endif
- if (libipw_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- LIBIPW_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
- }
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n",
- rates_str, network->rates_ex_len);
- break;
-
- case WLAN_EID_DS_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n",
- info_element->data[0]);
- network->channel = info_element->data[0];
- break;
-
- case WLAN_EID_FH_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n");
- break;
-
- case WLAN_EID_CF_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n");
- break;
-
- case WLAN_EID_TIM:
- network->tim.tim_count = info_element->data[0];
- network->tim.tim_period = info_element->data[1];
- LIBIPW_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n");
- break;
-
- case WLAN_EID_ERP_INFO:
- network->erp_value = info_element->data[0];
- network->flags |= NETWORK_HAS_ERP_VALUE;
- LIBIPW_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
- network->erp_value);
- break;
-
- case WLAN_EID_IBSS_PARAMS:
- network->atim_window = info_element->data[0];
- LIBIPW_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n",
- network->atim_window);
- break;
-
- case WLAN_EID_CHALLENGE:
- LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
- break;
-
- case WLAN_EID_VENDOR_SPECIFIC:
- LIBIPW_DEBUG_MGMT("WLAN_EID_VENDOR_SPECIFIC: %d bytes\n",
- info_element->len);
- if (!libipw_parse_qos_info_param_IE(info_element,
- network))
- break;
-
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x50 &&
- info_element->data[2] == 0xf2 &&
- info_element->data[3] == 0x01) {
- network->wpa_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->wpa_ie, info_element,
- network->wpa_ie_len);
- }
- break;
-
- case WLAN_EID_RSN:
- LIBIPW_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n",
- info_element->len);
- network->rsn_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->rsn_ie, info_element,
- network->rsn_ie_len);
- break;
-
- case WLAN_EID_QOS_PARAMETER:
- printk(KERN_ERR
- "QoS Error need to parse QOS_PARAMETER IE\n");
- break;
- /* 802.11h */
- case WLAN_EID_PWR_CONSTRAINT:
- network->power_constraint = info_element->data[0];
- network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
- break;
-
- case WLAN_EID_CHANNEL_SWITCH:
- network->power_constraint = info_element->data[0];
- network->flags |= NETWORK_HAS_CSA;
- break;
-
- case WLAN_EID_QUIET:
- network->quiet.count = info_element->data[0];
- network->quiet.period = info_element->data[1];
- network->quiet.duration = info_element->data[2];
- network->quiet.offset = info_element->data[3];
- network->flags |= NETWORK_HAS_QUIET;
- break;
-
- case WLAN_EID_IBSS_DFS:
- network->flags |= NETWORK_HAS_IBSS_DFS;
- break;
-
- case WLAN_EID_TPC_REPORT:
- network->tpc_report.transmit_power =
- info_element->data[0];
- network->tpc_report.link_margin = info_element->data[1];
- network->flags |= NETWORK_HAS_TPC_REPORT;
- break;
-
- default:
- LIBIPW_DEBUG_MGMT
- ("Unsupported info element: %s (%d)\n",
- get_info_element_string(info_element->id),
- info_element->id);
- break;
- }
-
- length -= sizeof(*info_element) + info_element->len;
- info_element =
- (struct libipw_info_element *)&info_element->
- data[info_element->len];
- }
-
- return 0;
-}
-
-static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response
- *frame, struct libipw_rx_stats *stats)
-{
- struct libipw_network network_resp = { };
- struct libipw_network *network = &network_resp;
- struct net_device *dev = ieee->dev;
-
- network->flags = 0;
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- network->qos_data.param_count = 0;
- network->qos_data.old_param_count = 0;
-
- //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
- network->atim_window = le16_to_cpu(frame->aid);
- network->listen_interval = le16_to_cpu(frame->status);
- memcpy(network->bssid, frame->header.addr3, ETH_ALEN);
- network->capability = le16_to_cpu(frame->capability);
- network->last_scanned = jiffies;
- network->rates_len = network->rates_ex_len = 0;
- network->last_associate = 0;
- network->ssid_len = 0;
- network->erp_value =
- (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0;
-
- if (stats->freq == LIBIPW_52GHZ_BAND) {
- /* for A band (No DS info) */
- network->channel = stats->received_channel;
- } else
- network->flags |= NETWORK_HAS_CCK;
-
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-
- if (libipw_parse_info_param((void *)frame->variable,
- stats->len - sizeof(*frame), network))
- return 1;
-
- network->mode = 0;
- if (stats->freq == LIBIPW_52GHZ_BAND)
- network->mode = IEEE_A;
- else {
- if (network->flags & NETWORK_HAS_OFDM)
- network->mode |= IEEE_G;
- if (network->flags & NETWORK_HAS_CCK)
- network->mode |= IEEE_B;
- }
-
- memcpy(&network->stats, stats, sizeof(network->stats));
-
- if (ieee->handle_assoc_response != NULL)
- ieee->handle_assoc_response(dev, frame, network);
-
- return 0;
-}
-
-/***************************************************/
-
-static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_response
- *beacon,
- struct libipw_network *network,
- struct libipw_rx_stats *stats)
-{
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- network->qos_data.param_count = 0;
- network->qos_data.old_param_count = 0;
-
- /* Pull out fixed field data */
- memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
- network->capability = le16_to_cpu(beacon->capability);
- network->last_scanned = jiffies;
- network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
- network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
- network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
- /* Where to pull this? beacon->listen_interval; */
- network->listen_interval = 0x0A;
- network->rates_len = network->rates_ex_len = 0;
- network->last_associate = 0;
- network->ssid_len = 0;
- network->flags = 0;
- network->atim_window = 0;
- network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
- 0x3 : 0x0;
-
- if (stats->freq == LIBIPW_52GHZ_BAND) {
- /* for A band (No DS info) */
- network->channel = stats->received_channel;
- } else
- network->flags |= NETWORK_HAS_CCK;
-
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-
- if (libipw_parse_info_param((void *)beacon->variable,
- stats->len - sizeof(*beacon), network))
- return 1;
-
- network->mode = 0;
- if (stats->freq == LIBIPW_52GHZ_BAND)
- network->mode = IEEE_A;
- else {
- if (network->flags & NETWORK_HAS_OFDM)
- network->mode |= IEEE_G;
- if (network->flags & NETWORK_HAS_CCK)
- network->mode |= IEEE_B;
- }
-
- if (network->mode == 0) {
- LIBIPW_DEBUG_SCAN("Filtered out '%*pE (%pM)' network.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 1;
- }
-
- memcpy(&network->stats, stats, sizeof(network->stats));
-
- return 0;
-}
-
-static inline int is_same_network(struct libipw_network *src,
- struct libipw_network *dst)
-{
- /* A network is only a duplicate if the channel, BSSID, and ESSID
- * all match. We treat all <hidden> with the same BSSID and channel
- * as one network */
- return ((src->ssid_len == dst->ssid_len) &&
- (src->channel == dst->channel) &&
- ether_addr_equal_64bits(src->bssid, dst->bssid) &&
- !memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
-static void update_network(struct libipw_network *dst,
- struct libipw_network *src)
-{
- int qos_active;
- u8 old_param;
-
- /* We only update the statistics if they were created by receiving
- * the network information on the actual channel the network is on.
- *
- * This keeps beacons received on neighbor channels from bringing
- * down the signal level of an AP. */
- if (dst->channel == src->stats.received_channel)
- memcpy(&dst->stats, &src->stats,
- sizeof(struct libipw_rx_stats));
- else
- LIBIPW_DEBUG_SCAN("Network %pM info received "
- "off channel (%d vs. %d)\n", src->bssid,
- dst->channel, src->stats.received_channel);
-
- dst->capability = src->capability;
- memcpy(dst->rates, src->rates, src->rates_len);
- dst->rates_len = src->rates_len;
- memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
- dst->rates_ex_len = src->rates_ex_len;
-
- dst->mode = src->mode;
- dst->flags = src->flags;
- dst->time_stamp[0] = src->time_stamp[0];
- dst->time_stamp[1] = src->time_stamp[1];
-
- dst->beacon_interval = src->beacon_interval;
- dst->listen_interval = src->listen_interval;
- dst->atim_window = src->atim_window;
- dst->erp_value = src->erp_value;
- dst->tim = src->tim;
-
- memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
- dst->wpa_ie_len = src->wpa_ie_len;
- memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
- dst->rsn_ie_len = src->rsn_ie_len;
-
- dst->last_scanned = jiffies;
- qos_active = src->qos_data.active;
- old_param = dst->qos_data.old_param_count;
- if (dst->flags & NETWORK_HAS_QOS_MASK)
- memcpy(&dst->qos_data, &src->qos_data,
- sizeof(struct libipw_qos_data));
- else {
- dst->qos_data.supported = src->qos_data.supported;
- dst->qos_data.param_count = src->qos_data.param_count;
- }
-
- if (dst->qos_data.supported == 1) {
- if (dst->ssid_len)
- LIBIPW_DEBUG_QOS
- ("QoS the network %s is QoS supported\n",
- dst->ssid);
- else
- LIBIPW_DEBUG_QOS
- ("QoS the network is QoS supported\n");
- }
- dst->qos_data.active = qos_active;
- dst->qos_data.old_param_count = old_param;
-
- /* dst->last_associate is not overwritten */
-}
-
-static inline int is_beacon(__le16 fc)
-{
- return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
-}
-
-static void libipw_process_probe_response(struct libipw_device
- *ieee, struct
- libipw_probe_response
- *beacon, struct libipw_rx_stats
- *stats)
-{
- struct net_device *dev = ieee->dev;
- struct libipw_network network = { };
- struct libipw_network *target;
- struct libipw_network *oldest = NULL;
-#ifdef CONFIG_LIBIPW_DEBUG
- struct libipw_info_element *info_element = (void *)beacon->variable;
-#endif
- unsigned long flags;
-
- LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
- info_element->len, info_element->data,
- beacon->header.addr3,
- (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xc)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xb)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xa)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x9)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x8)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x7)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x6)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x5)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x4)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x3)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x2)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
-
- if (libipw_network_init(ieee, beacon, &network, stats)) {
- LIBIPW_DEBUG_SCAN("Dropped '%*pE' (%pM) via %s.\n",
- info_element->len, info_element->data,
- beacon->header.addr3,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
- return;
- }
-
- /* The network parsed correctly -- so now we scan our known networks
- * to see if we can find it in our list.
- *
- * NOTE: This search is definitely not optimized. Once its doing
- * the "right thing" we'll optimize it for efficiency if
- * necessary */
-
- /* Search for this entry in the list and update it if it is
- * already there. */
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(target, &ieee->network_list, list) {
- if (is_same_network(target, &network))
- break;
-
- if ((oldest == NULL) ||
- time_before(target->last_scanned, oldest->last_scanned))
- oldest = target;
- }
-
- /* If we didn't find a match, then get a new network slot to initialize
- * with this beacon's information */
- if (&target->list == &ieee->network_list) {
- if (list_empty(&ieee->network_free_list)) {
- /* If there are no more slots, expire the oldest */
- list_del(&oldest->list);
- target = oldest;
- LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
- target->ssid_len, target->ssid,
- target->bssid);
- } else {
- /* Otherwise just pull from the free list */
- target = list_entry(ieee->network_free_list.next,
- struct libipw_network, list);
- list_del(ieee->network_free_list.next);
- }
-
-#ifdef CONFIG_LIBIPW_DEBUG
- LIBIPW_DEBUG_SCAN("Adding '%*pE' (%pM) via %s.\n",
- network.ssid_len, network.ssid,
- network.bssid,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
-#endif
- memcpy(target, &network, sizeof(*target));
- list_add_tail(&target->list, &ieee->network_list);
- } else {
- LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
- target->ssid_len, target->ssid,
- target->bssid,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
- update_network(target, &network);
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- if (is_beacon(beacon->header.frame_ctl)) {
- if (ieee->handle_beacon != NULL)
- ieee->handle_beacon(dev, beacon, target);
- } else {
- if (ieee->handle_probe_response != NULL)
- ieee->handle_probe_response(dev, beacon, target);
- }
-}
-
-void libipw_rx_mgt(struct libipw_device *ieee,
- struct libipw_hdr_4addr *header,
- struct libipw_rx_stats *stats)
-{
- switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) {
- case IEEE80211_STYPE_ASSOC_RESP:
- LIBIPW_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- libipw_handle_assoc_resp(ieee,
- (struct libipw_assoc_response *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_REASSOC_RESP:
- LIBIPW_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- break;
-
- case IEEE80211_STYPE_PROBE_REQ:
- LIBIPW_DEBUG_MGMT("received auth (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- if (ieee->handle_probe_request != NULL)
- ieee->handle_probe_request(ieee->dev,
- (struct
- libipw_probe_request *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_PROBE_RESP:
- LIBIPW_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_SCAN("Probe response\n");
- libipw_process_probe_response(ieee,
- (struct
- libipw_probe_response *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_BEACON:
- LIBIPW_DEBUG_MGMT("received BEACON (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_SCAN("Beacon\n");
- libipw_process_probe_response(ieee,
- (struct
- libipw_probe_response *)
- header, stats);
- break;
- case IEEE80211_STYPE_AUTH:
-
- LIBIPW_DEBUG_MGMT("received auth (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- if (ieee->handle_auth != NULL)
- ieee->handle_auth(ieee->dev,
- (struct libipw_auth *)header);
- break;
-
- case IEEE80211_STYPE_DISASSOC:
- if (ieee->handle_disassoc != NULL)
- ieee->handle_disassoc(ieee->dev,
- (struct libipw_disassoc *)
- header);
- break;
-
- case IEEE80211_STYPE_ACTION:
- LIBIPW_DEBUG_MGMT("ACTION\n");
- if (ieee->handle_action)
- ieee->handle_action(ieee->dev,
- (struct libipw_action *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_REASSOC_REQ:
- LIBIPW_DEBUG_MGMT("received reassoc (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- LIBIPW_DEBUG_MGMT("%s: LIBIPW_REASSOC_REQ received\n",
- ieee->dev->name);
- if (ieee->handle_reassoc_request != NULL)
- ieee->handle_reassoc_request(ieee->dev,
- (struct libipw_reassoc_request *)
- header);
- break;
-
- case IEEE80211_STYPE_ASSOC_REQ:
- LIBIPW_DEBUG_MGMT("received assoc (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- LIBIPW_DEBUG_MGMT("%s: LIBIPW_ASSOC_REQ received\n",
- ieee->dev->name);
- if (ieee->handle_assoc_request != NULL)
- ieee->handle_assoc_request(ieee->dev);
- break;
-
- case IEEE80211_STYPE_DEAUTH:
- LIBIPW_DEBUG_MGMT("DEAUTH\n");
- if (ieee->handle_deauth != NULL)
- ieee->handle_deauth(ieee->dev,
- (struct libipw_deauth *)
- header);
- break;
- default:
- LIBIPW_DEBUG_MGMT("received UNKNOWN (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_MGMT("%s: Unknown management packet: %d\n",
- ieee->dev->name,
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- break;
- }
-}
-
-EXPORT_SYMBOL_GPL(libipw_rx_any);
-EXPORT_SYMBOL(libipw_rx_mgt);
-EXPORT_SYMBOL(libipw_rx);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
deleted file mode 100644
index 4aec1fce1ae29..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
+++ /dev/null
@@ -1,519 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-
-#include "libipw.h"
-
-/*
-
-802.11 Data Frame
-
- ,-------------------------------------------------------------------.
-Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- |------|------|---------|---------|---------|------|---------|------|
-Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
- | | tion | (BSSID) | | | ence | data | |
- `--------------------------------------------------| |------'
-Total: 28 non-data bytes `----.----'
- |
- .- 'Frame data' expands, if WEP enabled, to <----------'
- |
- V
- ,-----------------------.
-Bytes | 4 | 0-2296 | 4 |
- |-----|-----------|-----|
-Desc. | IV | Encrypted | ICV |
- | | Packet | |
- `-----| |-----'
- `-----.-----'
- |
- .- 'Encrypted Packet' expands to
- |
- V
- ,---------------------------------------------------.
-Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
- |------|------|---------|----------|------|---------|
-Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
- | DSAP | SSAP | | | | Packet |
- | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
- `----------------------------------------------------
-Total: 8 non-data bytes
-
-802.3 Ethernet Data Frame
-
- ,-----------------------------------------.
-Bytes | 6 | 6 | 2 | Variable | 4 |
- |-------|-------|------|-----------|------|
-Desc. | Dest. | Source| Type | IP Packet | fcs |
- | MAC | MAC | | | |
- `-----------------------------------------'
-Total: 18 non-data bytes
-
-In the event that fragmentation is required, the incoming payload is split into
-N parts of size ieee->fts. The first fragment contains the SNAP header and the
-remaining packets are just data.
-
-If encryption is enabled, each fragment payload size is reduced by enough space
-to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
-So if you have 1500 bytes of payload with ieee->fts set to 500 without
-encryption it will take 3 frames. With WEP it will take 4 frames as the
-payload of each frame is reduced to 492 bytes.
-
-* SKB visualization
-*
-* ,- skb->data
-* |
-* | ETHERNET HEADER ,-<-- PAYLOAD
-* | | 14 bytes from skb->data
-* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
-* | | | |
-* |,-Dest.--. ,--Src.---. | | |
-* | 6 bytes| | 6 bytes | | | |
-* v | | | | | |
-* 0 | v 1 | v | v 2
-* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
-* ^ | ^ | ^ |
-* | | | | | |
-* | | | | `T' <---- 2 bytes for Type
-* | | | |
-* | | '---SNAP--' <-------- 6 bytes for SNAP
-* | |
-* `-IV--' <-------------------- 4 bytes for IV (WEP)
-*
-* SNAP HEADER
-*
-*/
-
-static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
-static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
-
-static int libipw_copy_snap(u8 * data, __be16 h_proto)
-{
- struct libipw_snap_hdr *snap;
- u8 *oui;
-
- snap = (struct libipw_snap_hdr *)data;
- snap->dsap = 0xaa;
- snap->ssap = 0xaa;
- snap->ctrl = 0x03;
-
- if (h_proto == htons(ETH_P_AARP) || h_proto == htons(ETH_P_IPX))
- oui = P802_1H_OUI;
- else
- oui = RFC1042_OUI;
- snap->oui[0] = oui[0];
- snap->oui[1] = oui[1];
- snap->oui[2] = oui[2];
-
- memcpy(data + SNAP_SIZE, &h_proto, sizeof(u16));
-
- return SNAP_SIZE + sizeof(u16);
-}
-
-static int libipw_encrypt_fragment(struct libipw_device *ieee,
- struct sk_buff *frag, int hdr_len)
-{
- struct lib80211_crypt_data *crypt =
- ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- int res;
-
- if (crypt == NULL)
- return -1;
-
- /* To encrypt, frame format is:
- * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
- atomic_inc(&crypt->refcnt);
- res = 0;
- if (crypt->ops && crypt->ops->encrypt_mpdu)
- res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
-
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
- ieee->dev->name, frag->len);
- ieee->ieee_stats.tx_discards++;
- return -1;
- }
-
- return 0;
-}
-
-void libipw_txb_free(struct libipw_txb *txb)
-{
- int i;
- if (unlikely(!txb))
- return;
- for (i = 0; i < txb->nr_frags; i++)
- if (txb->fragments[i])
- dev_kfree_skb_any(txb->fragments[i]);
- kfree(txb);
-}
-
-static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size,
- int headroom, gfp_t gfp_mask)
-{
- struct libipw_txb *txb;
- int i;
-
- txb = kmalloc(struct_size(txb, fragments, nr_frags), gfp_mask);
- if (!txb)
- return NULL;
-
- memset(txb, 0, sizeof(struct libipw_txb));
- txb->nr_frags = nr_frags;
- txb->frag_size = txb_size;
-
- for (i = 0; i < nr_frags; i++) {
- txb->fragments[i] = __dev_alloc_skb(txb_size + headroom,
- gfp_mask);
- if (unlikely(!txb->fragments[i])) {
- i--;
- break;
- }
- skb_reserve(txb->fragments[i], headroom);
- }
- if (unlikely(i != nr_frags)) {
- while (i >= 0)
- dev_kfree_skb_any(txb->fragments[i--]);
- kfree(txb);
- return NULL;
- }
- return txb;
-}
-
-static int libipw_classify(struct sk_buff *skb)
-{
- struct ethhdr *eth;
- struct iphdr *ip;
-
- eth = (struct ethhdr *)skb->data;
- if (eth->h_proto != htons(ETH_P_IP))
- return 0;
-
- ip = ip_hdr(skb);
- switch (ip->tos & 0xfc) {
- case 0x20:
- return 2;
- case 0x40:
- return 1;
- case 0x60:
- return 3;
- case 0x80:
- return 4;
- case 0xa0:
- return 5;
- case 0xc0:
- return 6;
- case 0xe0:
- return 7;
- default:
- return 0;
- }
-}
-
-/* Incoming skb is converted to a txb which consists of
- * a block of 802.11 fragment packets (stored as skbs) */
-netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct libipw_device *ieee = netdev_priv(dev);
- struct libipw_txb *txb = NULL;
- struct libipw_hdr_3addrqos *frag_hdr;
- int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
- rts_required;
- unsigned long flags;
- int encrypt, host_encrypt, host_encrypt_msdu;
- __be16 ether_type;
- int bytes, fc, hdr_len;
- struct sk_buff *skb_frag;
- struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */
- .duration_id = 0,
- .seq_ctl = 0,
- .qos_ctl = 0
- };
- u8 dest[ETH_ALEN], src[ETH_ALEN];
- struct lib80211_crypt_data *crypt;
- int priority = skb->priority;
- int snapped = 0;
-
- if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority))
- return NETDEV_TX_BUSY;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- /* If there is no driver handler to take the TXB, dont' bother
- * creating it... */
- if (!ieee->hard_start_xmit) {
- printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
- goto success;
- }
-
- if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
- printk(KERN_WARNING "%s: skb too small (%d).\n",
- ieee->dev->name, skb->len);
- goto success;
- }
-
- ether_type = ((struct ethhdr *)skb->data)->h_proto;
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
-
- encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) &&
- ieee->sec.encrypt;
-
- host_encrypt = ieee->host_encrypt && encrypt && crypt;
- host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
-
- if (!encrypt && ieee->ieee802_1x &&
- ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
- dev->stats.tx_dropped++;
- goto success;
- }
-
- /* Save source and destination addresses */
- skb_copy_from_linear_data(skb, dest, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
-
- if (host_encrypt)
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
- IEEE80211_FCTL_PROTECTED;
- else
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
-
- if (ieee->iw_mode == IW_MODE_INFRA) {
- fc |= IEEE80211_FCTL_TODS;
- /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
- memcpy(header.addr1, ieee->bssid, ETH_ALEN);
- memcpy(header.addr2, src, ETH_ALEN);
- memcpy(header.addr3, dest, ETH_ALEN);
- } else if (ieee->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
- memcpy(header.addr1, dest, ETH_ALEN);
- memcpy(header.addr2, src, ETH_ALEN);
- memcpy(header.addr3, ieee->bssid, ETH_ALEN);
- }
- hdr_len = LIBIPW_3ADDR_LEN;
-
- if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
- fc |= IEEE80211_STYPE_QOS_DATA;
- hdr_len += 2;
-
- skb->priority = libipw_classify(skb);
- header.qos_ctl |= cpu_to_le16(skb->priority & LIBIPW_QCTL_TID);
- }
- header.frame_ctl = cpu_to_le16(fc);
-
- /* Advance the SKB to the start of the payload */
- skb_pull(skb, sizeof(struct ethhdr));
-
- /* Determine total amount of storage required for TXB packets */
- bytes = skb->len + SNAP_SIZE + sizeof(u16);
-
- /* Encrypt msdu first on the whole data packet. */
- if ((host_encrypt || host_encrypt_msdu) &&
- crypt && crypt->ops && crypt->ops->encrypt_msdu) {
- int res = 0;
- int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
- crypt->ops->extra_msdu_postfix_len;
- struct sk_buff *skb_new = dev_alloc_skb(len);
-
- if (unlikely(!skb_new))
- goto failed;
-
- skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
- skb_put_data(skb_new, &header, hdr_len);
- snapped = 1;
- libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
- ether_type);
- skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
- res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
- if (res < 0) {
- LIBIPW_ERROR("msdu encryption failed\n");
- dev_kfree_skb_any(skb_new);
- goto failed;
- }
- dev_kfree_skb_any(skb);
- skb = skb_new;
- bytes += crypt->ops->extra_msdu_prefix_len +
- crypt->ops->extra_msdu_postfix_len;
- skb_pull(skb, hdr_len);
- }
-
- if (host_encrypt || ieee->host_open_frag) {
- /* Determine fragmentation size based on destination (multicast
- * and broadcast are not fragmented) */
- if (is_multicast_ether_addr(dest) ||
- is_broadcast_ether_addr(dest))
- frag_size = MAX_FRAG_THRESHOLD;
- else
- frag_size = ieee->fts;
-
- /* Determine amount of payload per fragment. Regardless of if
- * this stack is providing the full 802.11 header, one will
- * eventually be affixed to this fragment -- so we must account
- * for it when determining the amount of payload space. */
- bytes_per_frag = frag_size - hdr_len;
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- bytes_per_frag -= LIBIPW_FCS_LEN;
-
- /* Each fragment may need to have room for encryption
- * pre/postfix */
- if (host_encrypt && crypt && crypt->ops)
- bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_mpdu_postfix_len;
-
- /* Number of fragments is the total
- * bytes_per_frag / payload_per_fragment */
- nr_frags = bytes / bytes_per_frag;
- bytes_last_frag = bytes % bytes_per_frag;
- if (bytes_last_frag)
- nr_frags++;
- else
- bytes_last_frag = bytes_per_frag;
- } else {
- nr_frags = 1;
- bytes_per_frag = bytes_last_frag = bytes;
- frag_size = bytes + hdr_len;
- }
-
- rts_required = (frag_size > ieee->rts
- && ieee->config & CFG_LIBIPW_RTS);
- if (rts_required)
- nr_frags++;
-
- /* When we allocate the TXB we allocate enough space for the reserve
- * and full fragment bytes (bytes_per_frag doesn't include prefix,
- * postfix, header, FCS, etc.) */
- txb = libipw_alloc_txb(nr_frags, frag_size,
- ieee->tx_headroom, GFP_ATOMIC);
- if (unlikely(!txb)) {
- printk(KERN_WARNING "%s: Could not allocate TXB\n",
- ieee->dev->name);
- goto failed;
- }
- txb->encrypted = encrypt;
- if (host_encrypt)
- txb->payload_size = frag_size * (nr_frags - 1) +
- bytes_last_frag;
- else
- txb->payload_size = bytes;
-
- if (rts_required) {
- skb_frag = txb->fragments[0];
- frag_hdr = skb_put(skb_frag, hdr_len);
-
- /*
- * Set header frame_ctl to the RTS.
- */
- header.frame_ctl =
- cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
- memcpy(frag_hdr, &header, hdr_len);
-
- /*
- * Restore header frame_ctl to the original data setting.
- */
- header.frame_ctl = cpu_to_le16(fc);
-
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- skb_put(skb_frag, 4);
-
- txb->rts_included = 1;
- i = 1;
- } else
- i = 0;
-
- for (; i < nr_frags; i++) {
- skb_frag = txb->fragments[i];
-
- if (host_encrypt)
- skb_reserve(skb_frag,
- crypt->ops->extra_mpdu_prefix_len);
-
- frag_hdr = skb_put_data(skb_frag, &header, hdr_len);
-
- /* If this is not the last fragment, then add the MOREFRAGS
- * bit to the frame control */
- if (i != nr_frags - 1) {
- frag_hdr->frame_ctl =
- cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
- bytes = bytes_per_frag;
- } else {
- /* The last fragment takes the remaining length */
- bytes = bytes_last_frag;
- }
-
- if (i == 0 && !snapped) {
- libipw_copy_snap(skb_put
- (skb_frag, SNAP_SIZE + sizeof(u16)),
- ether_type);
- bytes -= SNAP_SIZE + sizeof(u16);
- }
-
- skb_copy_from_linear_data(skb, skb_put(skb_frag, bytes), bytes);
-
- /* Advance the SKB... */
- skb_pull(skb, bytes);
-
- /* Encryption routine will move the header forward in order
- * to insert the IV between the header and the payload */
- if (host_encrypt)
- libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
-
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- skb_put(skb_frag, 4);
- }
-
- success:
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- dev_kfree_skb_any(skb);
-
- if (txb) {
- netdev_tx_t ret = (*ieee->hard_start_xmit)(txb, dev, priority);
- if (ret == NETDEV_TX_OK) {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += txb->payload_size;
- return NETDEV_TX_OK;
- }
-
- libipw_txb_free(txb);
- }
-
- return NETDEV_TX_OK;
-
- failed:
- spin_unlock_irqrestore(&ieee->lock, flags);
- netif_stop_queue(dev);
- dev->stats.tx_errors++;
- return NETDEV_TX_BUSY;
-}
-EXPORT_SYMBOL(libipw_xmit);
-
-EXPORT_SYMBOL(libipw_txb_free);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
deleted file mode 100644
index 903de34028efb..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
+++ /dev/null
@@ -1,726 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
-
- Portions of this file are based on the WEP enablement code provided by the
- Host AP project hostap-drivers v0.1.3
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <[email protected]>
- Copyright (c) 2002-2003, Jouni Malinen <[email protected]>
-
-
- Contact Information:
- Intel Linux Wireless <[email protected]>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#include <linux/hardirq.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/jiffies.h>
-
-#include <net/lib80211.h>
-#include <linux/wireless.h>
-
-#include "libipw.h"
-
-static const char *libipw_modes[] = {
- "?", "a", "b", "ab", "g", "ag", "bg", "abg"
-};
-
-static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
-{
- unsigned long end = jiffies;
-
- if (end >= start)
- return jiffies_to_msecs(end - start);
-
- return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
-}
-
-#define MAX_CUSTOM_LEN 64
-static char *libipw_translate_scan(struct libipw_device *ieee,
- char *start, char *stop,
- struct libipw_network *network,
- struct iw_request_info *info)
-{
- char custom[MAX_CUSTOM_LEN];
- char *p;
- struct iw_event iwe;
- int i, j;
- char *current_val; /* For rates */
- u8 rate;
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
-
- /* Remaining entries will be displayed in the order we provide them */
-
- /* Add the ESSID */
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- iwe.u.data.length = min(network->ssid_len, (u8) 32);
- start = iwe_stream_add_point(info, start, stop,
- &iwe, network->ssid);
-
- /* Add the protocol name */
- iwe.cmd = SIOCGIWNAME;
- snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
- libipw_modes[network->mode]);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (network->capability & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
-
- start = iwe_stream_add_event(info, start, stop,
- &iwe, IW_EV_UINT_LEN);
- }
-
- /* Add channel and frequency */
- /* Note : userspace automatically computes channel using iwrange */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel);
- iwe.u.freq.e = 6;
- iwe.u.freq.i = 0;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (network->capability & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- start = iwe_stream_add_point(info, start, stop,
- &iwe, network->ssid);
-
- /* Add basic and extended rates */
- /* Rate : stuffing multiple values in a single event require a bit
- * more of magic - Jean II */
- current_val = start + iwe_stream_lcp_len(info);
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 0, j = 0; i < network->rates_len;) {
- if (j < network->rates_ex_len &&
- ((network->rates_ex[j] & 0x7F) <
- (network->rates[i] & 0x7F)))
- rate = network->rates_ex[j++] & 0x7F;
- else
- rate = network->rates[i++] & 0x7F;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- for (; j < network->rates_ex_len; j++) {
- rate = network->rates_ex[j] & 0x7F;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any rate */
- if ((current_val - start) > iwe_stream_lcp_len(info))
- start = current_val;
-
- /* Add quality statistics */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED;
-
- if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) {
- iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
- IW_QUAL_LEVEL_INVALID;
- iwe.u.qual.qual = 0;
- } else {
- if (ieee->perfect_rssi == ieee->worst_rssi)
- iwe.u.qual.qual = 100;
- else
- iwe.u.qual.qual =
- (100 *
- (ieee->perfect_rssi - ieee->worst_rssi) *
- (ieee->perfect_rssi - ieee->worst_rssi) -
- (ieee->perfect_rssi - network->stats.rssi) *
- (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
- 62 * (ieee->perfect_rssi -
- network->stats.rssi))) /
- ((ieee->perfect_rssi -
- ieee->worst_rssi) * (ieee->perfect_rssi -
- ieee->worst_rssi));
- if (iwe.u.qual.qual > 100)
- iwe.u.qual.qual = 100;
- else if (iwe.u.qual.qual < 1)
- iwe.u.qual.qual = 0;
- }
-
- if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) {
- iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
- iwe.u.qual.noise = 0;
- } else {
- iwe.u.qual.noise = network->stats.noise;
- }
-
- if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) {
- iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
- iwe.u.qual.level = 0;
- } else {
- iwe.u.qual.level = network->stats.signal;
- }
-
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-
- iwe.cmd = IWEVCUSTOM;
- p = custom;
-
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- memset(&iwe, 0, sizeof(iwe));
- if (network->wpa_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, network->wpa_ie, network->wpa_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->wpa_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- if (network->rsn_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, network->rsn_ie, network->rsn_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->rsn_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
- " Last beacon: %ums ago",
- elapsed_jiffies_msecs(network->last_scanned));
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- /* Add spectrum management information */
- iwe.cmd = -1;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
-
- if (libipw_get_channel_flags(ieee, network->channel) &
- LIBIPW_CH_INVALID) {
- iwe.cmd = IWEVCUSTOM;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
- }
-
- if (libipw_get_channel_flags(ieee, network->channel) &
- LIBIPW_CH_RADAR_DETECT) {
- iwe.cmd = IWEVCUSTOM;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
- }
-
- if (iwe.cmd == IWEVCUSTOM) {
- iwe.u.data.length = p - custom;
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
- }
-
- return start;
-}
-
-#define SCAN_ITEM_SIZE 128
-
-int libipw_wx_get_scan(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct libipw_network *network;
- unsigned long flags;
- int err = 0;
-
- char *ev = extra;
- char *stop = ev + wrqu->data.length;
- int i = 0;
-
- LIBIPW_DEBUG_WX("Getting scan\n");
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(network, &ieee->network_list, list) {
- i++;
- if (stop - ev < SCAN_ITEM_SIZE) {
- err = -E2BIG;
- break;
- }
-
- if (ieee->scan_age == 0 ||
- time_after(network->last_scanned + ieee->scan_age, jiffies))
- ev = libipw_translate_scan(ieee, ev, stop, network,
- info);
- else {
- LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n",
- network->ssid_len, network->ssid,
- network->bssid,
- elapsed_jiffies_msecs(
- network->last_scanned));
- }
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- wrqu->data.length = ev - extra;
- wrqu->data.flags = 0;
-
- LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i);
-
- return err;
-}
-
-int libipw_wx_set_encode(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &(wrqu->encoding);
- struct net_device *dev = ieee->dev;
- struct libipw_security sec = {
- .flags = 0
- };
- int i, key, key_provided, len;
- struct lib80211_crypt_data **crypt;
- int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
-
- LIBIPW_DEBUG_WX("SET_ENCODE\n");
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > WEP_KEYS)
- return -EINVAL;
- key--;
- key_provided = 1;
- } else {
- key_provided = 0;
- key = ieee->crypt_info.tx_keyidx;
- }
-
- LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
- "provided" : "default");
-
- crypt = &ieee->crypt_info.crypt[key];
-
- if (erq->flags & IW_ENCODE_DISABLED) {
- if (key_provided && *crypt) {
- LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
- key);
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- } else
- LIBIPW_DEBUG_WX("Disabling encryption.\n");
-
- /* Check all the keys to see if any are still configured,
- * and if no key index was provided, de-init them all */
- for (i = 0; i < WEP_KEYS; i++) {
- if (ieee->crypt_info.crypt[i] != NULL) {
- if (key_provided)
- break;
- lib80211_crypt_delayed_deinit(&ieee->crypt_info,
- &ieee->crypt_info.crypt[i]);
- }
- }
-
- if (i == WEP_KEYS) {
- sec.enabled = 0;
- sec.encrypt = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
- }
-
- goto done;
- }
-
- sec.enabled = 1;
- sec.encrypt = 1;
- sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
-
- if (*crypt != NULL && (*crypt)->ops != NULL &&
- strcmp((*crypt)->ops->name, "WEP") != 0) {
- /* changing to use WEP; deinit previously used algorithm
- * on this key */
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- }
-
- if (*crypt == NULL && host_crypto) {
- struct lib80211_crypt_data *new_crypt;
-
- /* take WEP into use */
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL)
- return -ENOMEM;
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- if (!new_crypt->ops) {
- request_module("lib80211_crypt_wep");
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- }
-
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(key);
-
- if (!new_crypt->ops || !new_crypt->priv) {
- kfree(new_crypt);
- new_crypt = NULL;
-
- printk(KERN_WARNING "%s: could not initialize WEP: "
- "load module lib80211_crypt_wep\n", dev->name);
- return -EOPNOTSUPP;
- }
- *crypt = new_crypt;
- }
-
- /* If a new key was provided, set it up */
- if (erq->length > 0) {
- len = erq->length <= 5 ? 5 : 13;
- memcpy(sec.keys[key], keybuf, erq->length);
- if (len > erq->length)
- memset(sec.keys[key] + erq->length, 0,
- len - erq->length);
- LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n",
- key, len, sec.keys[key],
- erq->length, len);
- sec.key_sizes[key] = len;
- if (*crypt)
- (*crypt)->ops->set_key(sec.keys[key], len, NULL,
- (*crypt)->priv);
- sec.flags |= (1 << key);
- /* This ensures a key will be activated if no key is
- * explicitly set */
- if (key == sec.active_key)
- sec.flags |= SEC_ACTIVE_KEY;
-
- } else {
- if (host_crypto) {
- len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
- NULL, (*crypt)->priv);
- if (len == 0) {
- /* Set a default key of all 0 */
- LIBIPW_DEBUG_WX("Setting key %d to all "
- "zero.\n", key);
- memset(sec.keys[key], 0, 13);
- (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
- (*crypt)->priv);
- sec.key_sizes[key] = 13;
- sec.flags |= (1 << key);
- }
- }
- /* No key data - just set the default TX key index */
- if (key_provided) {
- LIBIPW_DEBUG_WX("Setting key %d to default Tx "
- "key.\n", key);
- ieee->crypt_info.tx_keyidx = key;
- sec.active_key = key;
- sec.flags |= SEC_ACTIVE_KEY;
- }
- }
- if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
- ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
- sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
- WLAN_AUTH_SHARED_KEY;
- sec.flags |= SEC_AUTH_MODE;
- LIBIPW_DEBUG_WX("Auth: %s\n",
- sec.auth_mode == WLAN_AUTH_OPEN ?
- "OPEN" : "SHARED KEY");
- }
-
- /* For now we just support WEP, so only set that security level...
- * TODO: When WPA is added this is one place that needs to change */
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
- sec.encode_alg[key] = SEC_ALG_WEP;
-
- done:
- if (ieee->set_security)
- ieee->set_security(dev, &sec);
-
- return 0;
-}
-
-int libipw_wx_get_encode(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &(wrqu->encoding);
- int len, key;
- struct libipw_security *sec = &ieee->sec;
-
- LIBIPW_DEBUG_WX("GET_ENCODE\n");
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > WEP_KEYS)
- return -EINVAL;
- key--;
- } else
- key = ieee->crypt_info.tx_keyidx;
-
- erq->flags = key + 1;
-
- if (!sec->enabled) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- len = sec->key_sizes[key];
- memcpy(keybuf, sec->keys[key], len);
-
- erq->length = len;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (ieee->open_wep)
- erq->flags |= IW_ENCODE_OPEN;
- else
- erq->flags |= IW_ENCODE_RESTRICTED;
-
- return 0;
-}
-
-int libipw_wx_set_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct net_device *dev = ieee->dev;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int i, idx, ret = 0;
- int group_key = 0;
- const char *alg, *module;
- struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
-
- struct libipw_security sec = {
- .flags = 0,
- };
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
- return -EINVAL;
- idx--;
- } else
- idx = ieee->crypt_info.tx_keyidx;
-
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
- crypt = &ieee->crypt_info.crypt[idx];
- group_key = 1;
- } else {
- /* some Cisco APs use idx>0 for unicast in dynamic WEP */
- if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
- return -EINVAL;
- if (ieee->iw_mode == IW_MODE_INFRA)
- crypt = &ieee->crypt_info.crypt[idx];
- else
- return -EINVAL;
- }
-
- sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
- if ((encoding->flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- for (i = 0; i < WEP_KEYS; i++)
- if (ieee->crypt_info.crypt[i] != NULL)
- break;
-
- if (i == WEP_KEYS) {
- sec.enabled = 0;
- sec.encrypt = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_LEVEL;
- }
- goto done;
- }
-
- sec.enabled = 1;
- sec.encrypt = 1;
-
- if (group_key ? !ieee->host_mc_decrypt :
- !(ieee->host_encrypt || ieee->host_decrypt ||
- ieee->host_encrypt_msdu))
- goto skip_host_crypt;
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_WEP:
- alg = "WEP";
- module = "lib80211_crypt_wep";
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = "TKIP";
- module = "lib80211_crypt_tkip";
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = "CCMP";
- module = "lib80211_crypt_ccmp";
- break;
- default:
- LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
- dev->name, ext->alg);
- ret = -EINVAL;
- goto done;
- }
-
- ops = lib80211_get_crypto_ops(alg);
- if (ops == NULL) {
- request_module(module);
- ops = lib80211_get_crypto_ops(alg);
- }
- if (ops == NULL) {
- LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
- dev->name, ext->alg);
- ret = -EINVAL;
- goto done;
- }
-
- if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
- if (new_crypt == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- new_crypt->ops = ops;
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(idx);
- if (new_crypt->priv == NULL) {
- kfree(new_crypt);
- ret = -EINVAL;
- goto done;
- }
- *crypt = new_crypt;
- }
-
- if (ext->key_len > 0 && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
- (*crypt)->priv) < 0) {
- LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name);
- ret = -EINVAL;
- goto done;
- }
-
- skip_host_crypt:
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- ieee->crypt_info.tx_keyidx = idx;
- sec.active_key = idx;
- sec.flags |= SEC_ACTIVE_KEY;
- }
-
- if (ext->alg != IW_ENCODE_ALG_NONE) {
- int key_len = clamp_val(ext->key_len, 0, SCM_KEY_LEN);
-
- memcpy(sec.keys[idx], ext->key, key_len);
- sec.key_sizes[idx] = key_len;
- sec.flags |= (1 << idx);
- if (ext->alg == IW_ENCODE_ALG_WEP) {
- sec.encode_alg[idx] = SEC_ALG_WEP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
- sec.encode_alg[idx] = SEC_ALG_TKIP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_2;
- } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
- sec.encode_alg[idx] = SEC_ALG_CCMP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_3;
- }
- /* Don't set sec level for group keys. */
- if (group_key)
- sec.flags &= ~SEC_LEVEL;
- }
- done:
- if (ieee->set_security)
- ieee->set_security(dev, &sec);
-
- return ret;
-}
-
-int libipw_wx_get_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- struct libipw_security *sec = &ieee->sec;
- int idx, max_key_len;
-
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
- return -EINVAL;
- idx--;
- } else
- idx = ieee->crypt_info.tx_keyidx;
-
- if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
- ext->alg != IW_ENCODE_ALG_WEP)
- if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
- return -EINVAL;
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- if (!sec->enabled) {
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- encoding->flags |= IW_ENCODE_DISABLED;
- } else {
- if (sec->encode_alg[idx] == SEC_ALG_WEP)
- ext->alg = IW_ENCODE_ALG_WEP;
- else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
- ext->alg = IW_ENCODE_ALG_TKIP;
- else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
- ext->alg = IW_ENCODE_ALG_CCMP;
- else
- return -EINVAL;
-
- ext->key_len = sec->key_sizes[idx];
- memcpy(ext->key, sec->keys[idx], ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- if (ext->key_len &&
- (ext->alg == IW_ENCODE_ALG_TKIP ||
- ext->alg == IW_ENCODE_ALG_CCMP))
- ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
-
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(libipw_wx_set_encodeext);
-EXPORT_SYMBOL(libipw_wx_get_encodeext);
-
-EXPORT_SYMBOL(libipw_wx_get_scan);
-EXPORT_SYMBOL(libipw_wx_set_encode);
-EXPORT_SYMBOL(libipw_wx_get_encode);
--
2.39.2

2023-10-23 13:45:47

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 00/10] Remove obsolete and orphaned wifi drivers

Arnd Bergmann <[email protected]> writes:

> From: Arnd Bergmann <[email protected]>
>
> As discussed previously, a lot of the older wifi drivers are likely
> entirely unused, Though we can't know for sure.
>
> As suggested by both Greg and Jakub, let's remove the ones that look
> are most likely to have no users left and also get in the way of the
> wext cleanup. If anyone is still using any of these, we can revert the
> driver removal individually.
>
> I would suggest merging these for net-next after 6.7-rc1 is out

Why net-next? I want to take these to wireless-next to avoid any
conflicts with other wireless patches.

We could take these to wireless-next after we submit the last new
features (-next) pull request to v6.7, so most likely already next week.
So if anyone has any problems with these speak up now.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2023-10-23 14:21:09

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH 00/10] Remove obsolete and orphaned wifi drivers

On Mon, Oct 23, 2023, at 15:45, Kalle Valo wrote:
> Arnd Bergmann <[email protected]> writes:
>
>> From: Arnd Bergmann <[email protected]>
>>
>> As discussed previously, a lot of the older wifi drivers are likely
>> entirely unused, Though we can't know for sure.
>>
>> As suggested by both Greg and Jakub, let's remove the ones that look
>> are most likely to have no users left and also get in the way of the
>> wext cleanup. If anyone is still using any of these, we can revert the
>> driver removal individually.
>>
>> I would suggest merging these for net-next after 6.7-rc1 is out
>
> Why net-next? I want to take these to wireless-next to avoid any
> conflicts with other wireless patches.

My mistake, I actually rebased them on top of wireless-next before
sending out the patches, I just forgot update the text I had
already written a week earlier.

> We could take these to wireless-next after we submit the last new
> features (-next) pull request to v6.7, so most likely already next week.
> So if anyone has any problems with these speak up now.

Sounds good to me, thanks!

Arnd

2023-10-23 14:39:36

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers

Arnd Bergmann <[email protected]> writes:

> From: Arnd Bergmann <[email protected]>
>
> These two drivers were used for the earliest "Centrino" branded Intel
> laptops during the late 32-bit Pentium-M era, roughly 2003 to 2005, which
> probably makes it the most modern platform that still uses the wireless
> extension interface instead of cfg80211. Unlike the other drivers that
> are suggested for removal, this one is still officially maintained.
>
> According to Johannes Berg, there was an effort to finish the move away
> from wext in the past, but the last evidence of this that I could find
> is from commit a3caa99e6c68f ("libipw: initiate cfg80211 API conversion
> (v2)") in 2009.
>
> Link: https://lore.kernel.org/all/[email protected]/
> Cc: Stanislav Yakovlev <[email protected]>
> Cc: Linux Wireless <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> I'm not convinced this should be in the same set of drivers as the
> rest, since this is clearly less obsolete than the other hardware
> that I would remove support for.

I am inclined to remove this one as well, it's just so old.

This patch didn't make it to the list, I guess it was too big. But it's
available from the pending branch:

https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/commit/?h=pending&id=81ba6b51c3a640b277274701407bbf557f12edac

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2023-10-23 14:43:27

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 00/10] Remove obsolete and orphaned wifi drivers

"Arnd Bergmann" <[email protected]> writes:

> On Mon, Oct 23, 2023, at 15:45, Kalle Valo wrote:
>> Arnd Bergmann <[email protected]> writes:
>>
>>> From: Arnd Bergmann <[email protected]>
>>>
>>> As discussed previously, a lot of the older wifi drivers are likely
>>> entirely unused, Though we can't know for sure.
>>>
>>> As suggested by both Greg and Jakub, let's remove the ones that look
>>> are most likely to have no users left and also get in the way of the
>>> wext cleanup. If anyone is still using any of these, we can revert the
>>> driver removal individually.
>>>
>>> I would suggest merging these for net-next after 6.7-rc1 is out
>>
>> Why net-next? I want to take these to wireless-next to avoid any
>> conflicts with other wireless patches.
>
> My mistake, I actually rebased them on top of wireless-next before
> sending out the patches, I just forgot update the text I had
> already written a week earlier.

Ah, good that we are on the same page then :)

>> We could take these to wireless-next after we submit the last new
>> features (-next) pull request to v6.7, so most likely already next week.
>> So if anyone has any problems with these speak up now.
>
> Sounds good to me, thanks!

Thanks for the patches! I applied them to our pending branch for some
build testing, there were few conflicts I guess due to recent cleanup
patches but obviously easy to fix :)

https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/log/?h=pending

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2023-10-23 19:40:45

by Frank Schäfer

[permalink] [raw]
Subject: Re: [PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers

Am 23.10.23 um 15:19 schrieb Arnd Bergmann:
> From: Arnd Bergmann <[email protected]>
>
> These two drivers were used for the earliest "Centrino" branded Intel
> laptops during the late 32-bit Pentium-M era, roughly 2003 to 2005, which
> probably makes it the most modern platform that still uses the wireless
> extension interface instead of cfg80211. Unlike the other drivers that
> are suggested for removal, this one is still officially maintained.
>
> According to Johannes Berg, there was an effort to finish the move away
> from wext in the past, but the last evidence of this that I could find
> is from commit a3caa99e6c68f ("libipw: initiate cfg80211 API conversion
> (v2)") in 2009.
>
> Link: https://lore.kernel.org/all/[email protected]/
> Cc: Stanislav Yakovlev <[email protected]>
> Cc: Linux Wireless <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> I'm not convinced this should be in the same set of drivers as the
> rest, since this is clearly less obsolete than the other hardware
> that I would remove support for.
> ---

FYI, I'm still using this driver in my old diagnostic laptop.
I din't test recent kernels (yet), but the only issue I noticed over the
years is that I can't connect to hidden networks (IIRC that never worked).

So I personally would be happy if the driver could remain for a while.
But I don't care too much. If noone else uses it and/or it is too hard
to maintain - R.I.P.

2023-10-23 23:44:23

by Stefan Lippers-Hollmann

[permalink] [raw]
Subject: Re: [PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers

Hi

On 2023-10-23, Arnd Bergmann wrote:
> From: Arnd Bergmann <[email protected]>
>
> These two drivers were used for the earliest "Centrino" branded Intel
> laptops during the late 32-bit Pentium-M era, roughly 2003 to 2005, which
> probably makes it the most modern platform that still uses the wireless
> extension interface instead of cfg80211. Unlike the other drivers that
> are suggested for removal, this one is still officially maintained.
>
> According to Johannes Berg, there was an effort to finish the move away
> from wext in the past, but the last evidence of this that I could find
> is from commit a3caa99e6c68f ("libipw: initiate cfg80211 API conversion
> (v2)") in 2009.
>
> Link: https://lore.kernel.org/all/[email protected]/
> Cc: Stanislav Yakovlev <[email protected]>
> Cc: Linux Wireless <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> I'm not convinced this should be in the same set of drivers as the
> rest, since this is clearly less obsolete than the other hardware
> that I would remove support for.

These have indeed been very common back in the day, I'm still using
a 2003-vintage 1.5 GHz Pentium-M 'Banias' Acer Travelmate 292LMi
notebook using ipw2200 (and have two spare ipw2200 mini-PCI cards).
Works still fine using v6.5.8-rc1 and WPA2PSK/ CCMP (sadly it does
not do WPA3) and I do use it semi-regularly (running the latest
stable- or stable-rc kernel of the day).

While it would be nice to replace it with an ath5k based card (to
get WPA3 support), the card isn't that easy to reach in the notebook,
so it would be sad to see this go.

Host/Kernel/OS "acer-292lmi" running Linux 6.5.8-rc1 i686 [ Debian GNU/Linux trixie/sid ]
System Acer TravelMate 290
CPU Info Intel Pentium M 1024 KB cache flags( sse2 ) clocked at [ 1400.000 MHz ]
Videocard Advanced Micro Devices, [AMD/ATI] RV350/M10 / RV360/M11 [Mobility Radeon 9600 (PRO) / 9700] X.Org 1.23.2.1 [ [email protected] ]
Network cards Realtek RTL-8100/8101L/8139 PCI Fast Ethernet Adapter, at port: a000
Intel PRO/Wireless 2200BG [Calexico2] Network Connection
Processes 131 | Uptime 3:16 | Memory 125.2/493.1MB | HDD IC25N060ATMR04-0 Size 60GB (67%used) | GLX Renderer llvmpipe (LLVM 16.0.6, 128 bits) | GLX Version Yes

Yes, this is an old and slow system, but it's there, functional and
I rarely need a mobile notebook (my desktops are more current and
64 bit capable).

02:02.0 Network controller [0280]: Intel Corporation PRO/Wireless 2200BG [Calexico2] Network Connection [8086:4220] (rev 05)
Subsystem: Intel Corporation WM3B2200BG Mini-PCI Card [8086:2701]
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 128 (750ns min, 6000ns max)
Interrupt: pin A routed to IRQ 10
Region 0: Memory at d0000000 (32-bit, non-prefetchable) [size=4K]
Capabilities: [dc] Power Management version 2
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=1 PME-
Kernel driver in use: ipw2200
Kernel modules: ipw2200

[ 0.000000] Linux version 6.5.8-rc1 ([email protected]) (gcc-13 (Debian 13.2.0-5) 13.2.0, GNU ld (GNU Binutils for Debian) 2.41) #1 SMP PREEMPT_DYNAMIC 6.5-13 (2023-10-17)
...
[ 23.886128] lib80211: common routines for IEEE802.11 drivers
[ 23.886133] lib80211_crypt: registered algorithm 'NULL'
[ 24.051575] libipw: 802.11 data/management/control stack, git-1.1.13
[ 24.051586] libipw: Copyright (C) 2004-2005 Intel Corporation <[email protected]>
...
[ 24.735203] ipw2200: Intel(R) PRO/Wireless 2200/2915 Network Driver, 1.2.2kmprq
[ 24.735221] ipw2200: Copyright(c) 2003-2006 Intel Corporation
[ 24.735825] ipw2200: Detected Intel PRO/Wireless 2200BG Network Connection
...
[ 25.007359] ipw2200: Detected geography ZZE (13 802.11bg channels, 19 802.11a channels)
...
[ 27.027578] ipw2200 0000:02:02.0 wlp2s2: renamed from eth0
...
[ 29.571384] NET: Registered PF_PACKET protocol family
...
[ 42.603676] warning: `wpa_supplicant' uses wireless extensions which will stop working for Wi-Fi 7 hardware; use nl80211
[ 44.196736] lib80211_crypt: registered algorithm 'CCMP'

# iwconfig wlp2s2
wlp2s2 IEEE 802.11 ESSID:"xxx"
Mode:Managed Frequency:2.412 GHz Access Point: xx:xx:xx:xx:xx:xx
Bit Rate:54 Mb/s Tx-Power=20 dBm Sensitivity=8/0
Retry limit:7 RTS thr:off Fragment thr:off
Encryption key:xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx Security mode:open
Power Management:off
Link Quality=0/100 Signal level=-28 dBm Noise level=-89 dBm
Rx invalid nwid:0 Rx invalid crypt:6 Rx invalid frag:0
Tx excessive retries:0 Invalid misc:0 Missed beacon:100

# wpa_cli status
Selected interface 'wlp2s2'
bssid=xx:xx:xx:xx:xx:xx
freq=0
ssid=xxx
id=1
id_str=xxx
mode=station
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=172.22.2.1
address=xx:xx:xx:xx:xx:xx
uuid=xxx

(performance against a wifi6 (ipq8071a AP isn't that great, but it works)

$ iperf3 -c 172.21.4.1
Connecting to host 172.21.4.1, port 5201
[ 5] local 172.22.2.1 port 45288 connected to 172.21.4.1 port 5201
[ ID] Interval Transfer Bitrate Retr Cwnd
[ 5] 0.00-1.00 sec 1.97 MBytes 16.6 Mbits/sec 0 110 KBytes
[ 5] 1.00-2.00 sec 1.74 MBytes 14.6 Mbits/sec 0 163 KBytes
[ 5] 2.00-3.00 sec 1.68 MBytes 14.1 Mbits/sec 0 163 KBytes
[ 5] 3.00-4.00 sec 1.68 MBytes 14.1 Mbits/sec 0 163 KBytes
[ 5] 4.00-5.00 sec 1.86 MBytes 15.6 Mbits/sec 0 163 KBytes
[ 5] 5.00-6.00 sec 1.49 MBytes 12.5 Mbits/sec 0 163 KBytes
[ 5] 6.00-7.00 sec 1.86 MBytes 15.6 Mbits/sec 0 163 KBytes
[ 5] 7.00-8.00 sec 1.93 MBytes 16.2 Mbits/sec 0 228 KBytes
[ 5] 8.00-9.00 sec 1.49 MBytes 12.5 Mbits/sec 0 228 KBytes
[ 5] 9.00-10.00 sec 1.99 MBytes 16.7 Mbits/sec 0 228 KBytes
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.00 sec 17.7 MBytes 14.8 Mbits/sec 0 sender
[ 5] 0.00-10.13 sec 17.2 MBytes 14.3 Mbits/sec receiver

iperf Done.

$ iperf3 -c 172.21.4.1 --reverse
Connecting to host 172.21.4.1, port 5201
Reverse mode, remote host 172.21.4.1 is sending
[ 5] local 172.22.2.1 port 52246 connected to 172.21.4.1 port 5201
[ ID] Interval Transfer Bitrate
[ 5] 0.00-1.04 sec 1.88 MBytes 15.1 Mbits/sec
[ 5] 1.04-2.04 sec 1.75 MBytes 14.8 Mbits/sec
[ 5] 2.04-3.03 sec 1.62 MBytes 13.7 Mbits/sec
[ 5] 3.03-4.05 sec 1.75 MBytes 14.5 Mbits/sec
[ 5] 4.05-5.03 sec 1.75 MBytes 14.9 Mbits/sec
[ 5] 5.03-6.06 sec 1.88 MBytes 15.3 Mbits/sec
[ 5] 6.06-7.05 sec 1.75 MBytes 14.8 Mbits/sec
[ 5] 7.05-8.01 sec 1.75 MBytes 15.3 Mbits/sec
[ 5] 8.01-9.03 sec 1.88 MBytes 15.4 Mbits/sec
[ 5] 9.03-10.02 sec 1.75 MBytes 14.8 Mbits/sec
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval Transfer Bitrate Retr
[ 5] 0.00-10.46 sec 21.4 MBytes 17.1 Mbits/sec 0 sender
[ 5] 0.00-10.02 sec 17.8 MBytes 14.9 Mbits/sec receiver

iperf Done.

While I'll cope if ipw2200 goes away (giving me the impetus to replace
the ipw2200 card with ath5k - or at least to use an ar5212/ar2414 ath5k
or bcm4306/2 b43 32 bit PCMCIA/ cardbus card (inconvenient, with the
antenna sticking out) until then), these have been so ubiquitous in
their days that there will be quite a few surviving specimens around
(and this one is actually still in semi-regular use with current
kernels/ userland, not daily, but 2-3+ times a month, mostly for
isolated firstboot configuration of various networking gear).

Regards
Stefan Lippers-Hollmann

2023-10-25 22:48:32

by Philipp Hortmann

[permalink] [raw]
Subject: Re: [PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers

On 10/26/23 00:27, Witold Baryluk wrote:
> I might be interested in modernizing the driver, but I have no idea how
> much effort it would be (in terms of changed fraction of code). 20k LOC
> is neither small or big, and not obvious (a lot of it would be
> unchanged), if it is a week of work, or months of work.

Hi Witold,

I am trying to do this with rtl8192e.
One possibility is to take the following patch series as a starting point:
https://yhbt.net/lore/all/[email protected]/

For me as a beginner and hobbyist this is a huge task. I am happy when I
can finish it until next summer.

In case of questions feel free to ask.

Bye Philipp

2023-10-26 09:49:40

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers

Philipp Hortmann <[email protected]> writes:

> On 10/26/23 00:27, Witold Baryluk wrote:
>> I might be interested in modernizing the driver, but I have no idea
>> how much effort it would be (in terms of changed fraction of code).
>> 20k LOC is neither small or big, and not obvious (a lot of it would
>> be unchanged), if it is a week of work, or months of work.
>
> Hi Witold,
>
> I am trying to do this with rtl8192e.
> One possibility is to take the following patch series as a starting point:
> https://yhbt.net/lore/all/[email protected]/
>
> For me as a beginner and hobbyist this is a huge task. I am happy when
> I can finish it until next summer.

We also have some docs available:

https://docs.kernel.org/driver-api/80211/

And I also recommend looking at our hwsim driver as that gives a good
idea how a simple mac80211 driver works:

https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git/tree/drivers/net/wireless/virtual/mac80211_hwsim.c

And you can even tinker the driver and run tests without needing any
real hardware:

https://docs.kernel.org/networking/mac80211_hwsim/mac80211_hwsim.html

And if there are any questions about mac80211 or anything wireless
related please send them to linux-wireless. Usually someone will answer
as long the question is well formulated.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2023-10-26 09:51:36

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers

On Thu, 2023-10-26 at 12:49 +0300, Kalle Valo wrote:
> Philipp Hortmann <[email protected]> writes:
>
> > On 10/26/23 00:27, Witold Baryluk wrote:
> > > I might be interested in modernizing the driver, but I have no idea
> > > how much effort it would be (in terms of changed fraction of code).
> > > 20k LOC is neither small or big, and not obvious (a lot of it would
> > > be unchanged), if it is a week of work, or months of work.
> >
> > Hi Witold,
> >
> > I am trying to do this with rtl8192e.
> > One possibility is to take the following patch series as a starting point:
> > https://yhbt.net/lore/all/[email protected]/
> >
> > For me as a beginner and hobbyist this is a huge task. I am happy when
> > I can finish it until next summer.
>
> We also have some docs available:
>
> https://docs.kernel.org/driver-api/80211/
>
> And I also recommend looking at our hwsim driver as that gives a good
> idea how a simple mac80211 driver works:
>

FWIW, I don't think this can be ported to mac80211 - only cfg80211. It's
a fullMAC device.

johannes

2023-10-30 16:56:10

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 00/10] Remove obsolete and orphaned wifi drivers

John Paul Adrian Glaubitz <[email protected]> writes:

> There is some non-x86 hardware like the Amiga that still uses
> PCMCIA-style networking cards on machines like the A600 and A1200. So,
> unless these drivers are actually causing problems, I would rather not
> see them go yet.

There is a cost maintaining these drivers so I would like to see more
information in the report, at least:

* exact driver and hardware used

* last kernel version tested

* kernel log messages from a successful case

Here's a good example:

https://lore.kernel.org/linux-wireless/20231024014302.0a0b79b0@mir/

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2023-10-31 09:08:15

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 00/10] Remove obsolete and orphaned wifi drivers

Arnd Bergmann <[email protected]> writes:

> From: Arnd Bergmann <[email protected]>
>
> As discussed previously, a lot of the older wifi drivers are likely
> entirely unused, Though we can't know for sure.
>
> As suggested by both Greg and Jakub, let's remove the ones that look
> are most likely to have no users left and also get in the way of the
> wext cleanup. If anyone is still using any of these, we can revert the
> driver removal individually.
>
> I would suggest merging these for net-next after 6.7-rc1 is out, to give
> them the maximum amount of time for users to speak up before a release
> comes out.
>
> This kills off all pcmcia wifi drivers, and all wext users in
> drivers/net/wireless, but not the ps3-gelic-wireless driver in
> drivers/net/ethernet, or the staging drivers.
>
> In staging, rtl8192u was already removed in the meantime, while rtl8712
> and rtl8192e are apparently still used. I have not been able to find
> out whether ks7010 is still in use.
>
> Arnd
>
> Link: https://lore.kernel.org/lkml/[email protected]/
>
>
> Arnd Bergmann (10):
> wifi: libertas: drop 16-bit PCMCIA support
> wifi: atmel: remove wext style at76c50x drivers
> wifi: remove orphaned cisco/aironet driver
> wifi: remove obsolete hostap driver
> wifi: remove orphaned zd1201 driver
> wifi: remove orphaned orinoco driver
> wifi: remove orphaned ray_cs driver
> wifi: remove orphaned wl3501 driver
> wifi: remove orphaned rndis_wlan driver
> [RFC] wifi: remove ipw2100/ipw2200 drivers

I manually applied these 9 to wireless-next:

4b478bf6bdd8 wifi: libertas: drop 16-bit PCMCIA support
77e49bec6414 wifi: atmel: remove wext style at76c50x drivers
6853c70ba5ed wifi: remove orphaned cisco/aironet driver
d0172d5f7576 wifi: remove obsolete hostap driver
757a46c2a7a9 wifi: remove orphaned zd1201 driver
1535d5962d79 wifi: remove orphaned orinoco driver
6b9dbaff83d6 wifi: remove orphaned ray_cs driver
238349207cd3 wifi: remove orphaned wl3501 driver
bec95598b24a wifi: remove orphaned rndis_wlan driver

I dropped this patch as we got several reports about people using the
driver:

[RFC] wifi: remove ipw2100/ipw2200 drivers

The patches are queued for v6.8. Arnd, thanks a lot for cleaning this
up!

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches