Kalle Valo says: ==================== wireless-next patches for v6.8 The first features pull request for v6.8. Not so big in number of commits but we removed quite a few ancient drivers: libertas 16-bit PCMCIA support, atmel, hostap, zd1201, orinoco, ray_cs, wl3501 and rndis_wlan. Major changes: cfg80211/mac80211 - extend support for scanning while Multi-Link Operation (MLO) connected * tag 'wireless-next-2023-11-27' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next: (68 commits) wifi: nl80211: Documentation update for NL80211_CMD_PORT_AUTHORIZED event wifi: mac80211: Extend support for scanning while MLO connected wifi: cfg80211: Extend support for scanning while MLO connected wifi: ieee80211: fix PV1 frame control field name rfkill: return ENOTTY on invalid ioctl MAINTAINERS: update iwlwifi maintainers wifi: rtw89: 8922a: read efuse content from physical map wifi: rtw89: 8922a: read efuse content via efuse map struct from logic map wifi: rtw89: 8852c: read RX gain offset from efuse for 6GHz channels wifi: rtw89: mac: add to access efuse for WiFi 7 chips wifi: rtw89: mac: use mac_gen pointer to access about efuse wifi: rtw89: 8922a: add 8922A basic chip info wifi: rtlwifi: drop unused const_amdpci_aspm wifi: mwifiex: mwifiex_process_sleep_confirm_resp(): remove unused priv variable wifi: rtw89: regd: update regulatory map to R65-R44 wifi: rtw89: regd: handle policy of 6 GHz according to BIOS wifi: rtw89: acpi: process 6 GHz band policy from DSM wifi: rtlwifi: simplify rtl_action_proc() and rtl_tx_agg_start() wifi: rtw89: pci: update interrupt mitigation register for 8922AE wifi: rtw89: pci: correct interrupt mitigation register for 8852CE ... ====================
Unified · Split
| @@ -10,7 +10,6 @@ Contents: · 9 unmodified lines | ||
| 10 | 10 | |
| 11 | 11 | intel/ipw2100 |
| 12 | 12 | intel/ipw2200 |
| 13 | − ray_cs | |
| 14 | 13 | |
| 15 | 14 | .. only:: subproject and html |
| 16 | 15 | |
| @@ -1,165 +0,0 @@ | ||
| 1 | −.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | − | |
| 3 | −.. include:: <isonum.txt> | |
| 4 | − | |
| 5 | −========================= | |
| 6 | −Raylink wireless LAN card | |
| 7 | −========================= | |
| 8 | − | |
| 9 | −September 21, 1999 | |
| 10 | − | |
| 11 | −Copyright |copy| 1998 Corey Thomas (corey@world.std.com) | |
| 12 | − | |
| 13 | −This file is the documentation for the Raylink Wireless LAN card driver for | |
| 14 | −Linux. The Raylink wireless LAN card is a PCMCIA card which provides IEEE | |
| 15 | −802.11 compatible wireless network connectivity at 1 and 2 megabits/second. | |
| 16 | −See http://www.raytheon.com/micro/raylink/ for more information on the Raylink | |
| 17 | −card. This driver is in early development and does have bugs. See the known | |
| 18 | −bugs and limitations at the end of this document for more information. | |
| 19 | −This driver also works with WebGear's Aviator 2.4 and Aviator Pro | |
| 20 | −wireless LAN cards. | |
| 21 | − | |
| 22 | −As of kernel 2.3.18, the ray_cs driver is part of the Linux kernel | |
| 23 | −source. My web page for the development of ray_cs is at | |
| 24 | −http://web.ralinktech.com/ralink/Home/Support/Linux.html | |
| 25 | −and I can be emailed at corey@world.std.com | |
| 26 | − | |
| 27 | −The kernel driver is based on ray_cs-1.62.tgz | |
| 28 | − | |
| 29 | −The driver at my web page is intended to be used as an add on to | |
| 30 | −David Hinds pcmcia package. All the command line parameters are | |
| 31 | −available when compiled as a module. When built into the kernel, only | |
| 32 | −the essid= string parameter is available via the kernel command line. | |
| 33 | −This will change after the method of sorting out parameters for all | |
| 34 | −the PCMCIA drivers is agreed upon. If you must have a built in driver | |
| 35 | −with nondefault parameters, they can be edited in | |
| 36 | −/usr/src/linux/drivers/net/pcmcia/ray_cs.c. Searching for module_param | |
| 37 | −will find them all. | |
| 38 | − | |
| 39 | −Information on card services is available at: | |
| 40 | − | |
| 41 | − http://pcmcia-cs.sourceforge.net/ | |
| 42 | − | |
| 43 | − | |
| 44 | −Card services user programs are still required for PCMCIA devices. | |
| 45 | −pcmcia-cs-3.1.1 or greater is required for the kernel version of | |
| 46 | −the driver. | |
| 47 | − | |
| 48 | −Currently, ray_cs is not part of David Hinds card services package, | |
| 49 | −so the following magic is required. | |
| 50 | − | |
| 51 | −At the end of the /etc/pcmcia/config.opts file, add the line: | |
| 52 | −source ./ray_cs.opts | |
| 53 | −This will make card services read the ray_cs.opts file | |
| 54 | −when starting. Create the file /etc/pcmcia/ray_cs.opts containing the | |
| 55 | −following:: | |
| 56 | − | |
| 57 | − #### start of /etc/pcmcia/ray_cs.opts ################### | |
| 58 | − # Configuration options for Raylink Wireless LAN PCMCIA card | |
| 59 | − device "ray_cs" | |
| 60 | − class "network" module "misc/ray_cs" | |
| 61 | − | |
| 62 | − card "RayLink PC Card WLAN Adapter" | |
| 63 | − manfid 0x01a6, 0x0000 | |
| 64 | − bind "ray_cs" | |
| 65 | − | |
| 66 | − module "misc/ray_cs" opts "" | |
| 67 | − #### end of /etc/pcmcia/ray_cs.opts ##################### | |
| 68 | − | |
| 69 | − | |
| 70 | −To join an existing network with | |
| 71 | −different parameters, contact the network administrator for the | |
| 72 | −configuration information, and edit /etc/pcmcia/ray_cs.opts. | |
| 73 | −Add the parameters below between the empty quotes. | |
| 74 | − | |
| 75 | −Parameters for ray_cs driver which may be specified in ray_cs.opts: | |
| 76 | − | |
| 77 | −=============== =============== ============================================= | |
| 78 | −bc integer 0 = normal mode (802.11 timing), | |
| 79 | − 1 = slow down inter frame timing to allow | |
| 80 | − operation with older breezecom access | |
| 81 | − points. | |
| 82 | − | |
| 83 | −beacon_period integer beacon period in Kilo-microseconds, | |
| 84 | − | |
| 85 | − legal values = must be integer multiple | |
| 86 | − of hop dwell | |
| 87 | − | |
| 88 | − default = 256 | |
| 89 | − | |
| 90 | −country integer 1 = USA (default), | |
| 91 | − 2 = Europe, | |
| 92 | − 3 = Japan, | |
| 93 | − 4 = Korea, | |
| 94 | − 5 = Spain, | |
| 95 | − 6 = France, | |
| 96 | − 7 = Israel, | |
| 97 | − 8 = Australia | |
| 98 | − | |
| 99 | −essid string ESS ID - network name to join | |
| 100 | − | |
| 101 | − string with maximum length of 32 chars | |
| 102 | − default value = "ADHOC_ESSID" | |
| 103 | − | |
| 104 | −hop_dwell integer hop dwell time in Kilo-microseconds | |
| 105 | − | |
| 106 | − legal values = 16,32,64,128(default),256 | |
| 107 | − | |
| 108 | −irq_mask integer linux standard 16 bit value 1bit/IRQ | |
| 109 | − | |
| 110 | − lsb is IRQ 0, bit 1 is IRQ 1 etc. | |
| 111 | − Used to restrict choice of IRQ's to use. | |
| 112 | − Recommended method for controlling | |
| 113 | − interrupts is in /etc/pcmcia/config.opts | |
| 114 | − | |
| 115 | −net_type integer 0 (default) = adhoc network, | |
| 116 | − 1 = infrastructure | |
| 117 | − | |
| 118 | −phy_addr string string containing new MAC address in | |
| 119 | − hex, must start with x eg | |
| 120 | − x00008f123456 | |
| 121 | − | |
| 122 | −psm integer 0 = continuously active, | |
| 123 | − 1 = power save mode (not useful yet) | |
| 124 | − | |
| 125 | −pc_debug integer (0-5) larger values for more verbose | |
| 126 | − logging. Replaces ray_debug. | |
| 127 | − | |
| 128 | −ray_debug integer Replaced with pc_debug | |
| 129 | − | |
| 130 | −ray_mem_speed integer defaults to 500 | |
| 131 | − | |
| 132 | −sniffer integer 0 = not sniffer (default), | |
| 133 | − 1 = sniffer which can be used to record all | |
| 134 | − network traffic using tcpdump or similar, | |
| 135 | − but no normal network use is allowed. | |
| 136 | − | |
| 137 | −translate integer 0 = no translation (encapsulate frames), | |
| 138 | − 1 = translation (RFC1042/802.1) | |
| 139 | −=============== =============== ============================================= | |
| 140 | − | |
| 141 | −More on sniffer mode: | |
| 142 | − | |
| 143 | −tcpdump does not understand 802.11 headers, so it can't | |
| 144 | −interpret the contents, but it can record to a file. This is only | |
| 145 | −useful for debugging 802.11 lowlevel protocols that are not visible to | |
| 146 | −linux. If you want to watch ftp xfers, or do similar things, you | |
| 147 | −don't need to use sniffer mode. Also, some packet types are never | |
| 148 | −sent up by the card, so you will never see them (ack, rts, cts, probe | |
| 149 | −etc.) There is a simple program (showcap) included in the ray_cs | |
| 150 | −package which parses the 802.11 headers. | |
| 151 | − | |
| 152 | −Known Problems and missing features | |
| 153 | − | |
| 154 | − Does not work with non x86 | |
| 155 | − | |
| 156 | − Does not work with SMP | |
| 157 | − | |
| 158 | − Support for defragmenting frames is not yet debugged, and in | |
| 159 | − fact is known to not work. I have never encountered a net set | |
| 160 | − up to fragment, but still, it should be fixed. | |
| 161 | − | |
| 162 | − The ioctl support is incomplete. The hardware address cannot be set | |
| 163 | − using ifconfig yet. If a different hardware address is needed, it may | |
| 164 | − be set using the phy_addr parameter in ray_cs.opts. This requires | |
| 165 | − a card insertion to take effect. | |
| @@ -2405,7 +2405,6 @@ F: drivers/memory/atmel* · 2404 unmodified lines | ||
| 2405 | 2405 | F: drivers/watchdog/sama5d4_wdt.c |
| 2406 | 2406 | F: include/soc/at91/ |
| 2407 | 2407 | X: drivers/input/touchscreen/atmel_mxt_ts.c |
| 2408 | −X: drivers/net/wireless/atmel/ | |
| 2409 | 2408 | N: at91 |
| 2410 | 2409 | N: atmel |
| 2411 | 2410 | |
| @@ -3309,13 +3308,6 @@ T: git git://github.com/ndyer/linux.git · 897 unmodified lines | ||
| 3309 | 3308 | F: Documentation/devicetree/bindings/input/atmel,maxtouch.yaml |
| 3310 | 3309 | F: drivers/input/touchscreen/atmel_mxt_ts.c |
| 3311 | 3310 | |
| 3312 | −ATMEL WIRELESS DRIVER | |
| 3313 | −L: linux-wireless@vger.kernel.org | |
| 3314 | −S: Orphan | |
| 3315 | −W: http://www.thekelleys.org.uk/atmel | |
| 3316 | −W: http://atmelwlandriver.sourceforge.net/ | |
| 3317 | −F: drivers/net/wireless/atmel/atmel* | |
| 3318 | − | |
| 3319 | 3311 | ATOMIC INFRASTRUCTURE |
| 3320 | 3312 | M: Will Deacon <will@kernel.org> |
| 3321 | 3313 | M: Peter Zijlstra <peterz@infradead.org> |
| @@ -9709,11 +9701,6 @@ S: Maintained · 6387 unmodified lines | ||
| 9709 | 9701 | F: Documentation/devicetree/bindings/iio/pressure/honeywell,mprls0025pa.yaml |
| 9710 | 9702 | F: drivers/iio/pressure/mprls0025pa.c |
| 9711 | 9703 | |
| 9712 | −HOST AP DRIVER | |
| 9713 | −L: linux-wireless@vger.kernel.org | |
| 9714 | −S: Obsolete | |
| 9715 | −F: drivers/net/wireless/intersil/hostap/ | |
| 9716 | − | |
| 9717 | 9704 | HP BIOSCFG DRIVER |
| 9718 | 9705 | M: Jorge Lopez <jorge.lopez2@hp.com> |
| 9719 | 9706 | L: platform-driver-x86@vger.kernel.org |
| @@ -11017,6 +11004,7 @@ F: drivers/net/wireless/intel/iwlegacy/ · 1297 unmodified lines | ||
| 11017 | 11004 | |
| 11018 | 11005 | INTEL WIRELESS WIFI LINK (iwlwifi) |
| 11019 | 11006 | M: Gregory Greenman <gregory.greenman@intel.com> |
| 11007 | +M: Miri Korenblit <miriam.rachel.korenblit@intel.com> | |
| 11020 | 11008 | L: linux-wireless@vger.kernel.org |
| 11021 | 11009 | S: Supported |
| 11022 | 11010 | W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi |
| @@ -16269,13 +16257,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/hubcap/linux.git · 5246 unmodified lines | ||
| 16269 | 16257 | F: Documentation/filesystems/orangefs.rst |
| 16270 | 16258 | F: fs/orangefs/ |
| 16271 | 16259 | |
| 16272 | −ORINOCO DRIVER | |
| 16273 | −L: linux-wireless@vger.kernel.org | |
| 16274 | −S: Orphan | |
| 16275 | −W: https://wireless.wiki.kernel.org/en/users/Drivers/orinoco | |
| 16276 | −W: http://www.nongnu.org/orinoco/ | |
| 16277 | −F: drivers/net/wireless/intersil/orinoco/ | |
| 16278 | − | |
| 16279 | 16260 | OV2659 OMNIVISION SENSOR DRIVER |
| 16280 | 16261 | M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com> |
| 16281 | 16262 | L: linux-media@vger.kernel.org |
| @@ -18169,11 +18150,6 @@ F: drivers/ras/ · 1887 unmodified lines | ||
| 18169 | 18150 | F: include/linux/ras.h |
| 18170 | 18151 | F: include/ras/ras_event.h |
| 18171 | 18152 | |
| 18172 | −RAYLINK/WEBGEAR 802.11 WIRELESS LAN DRIVER | |
| 18173 | −L: linux-wireless@vger.kernel.org | |
| 18174 | −S: Orphan | |
| 18175 | −F: drivers/net/wireless/legacy/ray* | |
| 18176 | − | |
| 18177 | 18153 | RC-CORE / LIRC FRAMEWORK |
| 18178 | 18154 | M: Sean Young <sean@mess.org> |
| 18179 | 18155 | L: linux-media@vger.kernel.org |
| @@ -22680,11 +22656,6 @@ F: drivers/usb/gadget/function/*uvc* · 4500 unmodified lines | ||
| 22680 | 22656 | F: drivers/usb/gadget/legacy/webcam.c |
| 22681 | 22657 | F: include/uapi/linux/usb/g_uvc.h |
| 22682 | 22658 | |
| 22683 | −USB WIRELESS RNDIS DRIVER (rndis_wlan) | |
| 22684 | −L: linux-wireless@vger.kernel.org | |
| 22685 | −S: Orphan | |
| 22686 | −F: drivers/net/wireless/legacy/rndis_wlan.c | |
| 22687 | − | |
| 22688 | 22659 | USB XHCI DRIVER |
| 22689 | 22660 | M: Mathias Nyman <mathias.nyman@intel.com> |
| 22690 | 22661 | L: linux-usb@vger.kernel.org |
| @@ -22692,12 +22663,6 @@ S: Supported · 1 unmodified line | ||
| 22692 | 22663 | F: drivers/usb/host/pci-quirks* |
| 22693 | 22664 | F: drivers/usb/host/xhci* |
| 22694 | 22665 | |
| 22695 | −USB ZD1201 DRIVER | |
| 22696 | −L: linux-wireless@vger.kernel.org | |
| 22697 | −S: Orphan | |
| 22698 | −W: http://linux-lc100020.sourceforge.net | |
| 22699 | −F: drivers/net/wireless/zydas/zd1201.* | |
| 22700 | − | |
| 22701 | 22666 | USER DATAGRAM PROTOCOL (UDP) |
| 22702 | 22667 | M: Willem de Bruijn <willemdebruijn.kernel@gmail.com> |
| 22703 | 22668 | S: Maintained |
| @@ -23499,11 +23464,6 @@ M: Miloslav Trmac <mitr@volny.cz> · 795 unmodified lines | ||
| 23499 | 23464 | S: Maintained |
| 23500 | 23465 | F: drivers/input/misc/wistron_btns.c |
| 23501 | 23466 | |
| 23502 | −WL3501 WIRELESS PCMCIA CARD DRIVER | |
| 23503 | −L: linux-wireless@vger.kernel.org | |
| 23504 | −S: Orphan | |
| 23505 | −F: drivers/net/wireless/legacy/wl3501* | |
| 23506 | − | |
| 23507 | 23467 | WMI BINARY MOF DRIVER |
| 23508 | 23468 | M: Armin Wolf <W_Armin@gmx.de> |
| 23509 | 23469 | R: Thomas Weißschuh <linux@weissschuh.net> |
| @@ -22,7 +22,6 @@ source "drivers/net/wireless/admtek/Kconfig" · 21 unmodified lines | ||
| 22 | 22 | source "drivers/net/wireless/ath/Kconfig" |
| 23 | 23 | source "drivers/net/wireless/atmel/Kconfig" |
| 24 | 24 | source "drivers/net/wireless/broadcom/Kconfig" |
| 25 | −source "drivers/net/wireless/cisco/Kconfig" | |
| 26 | 25 | source "drivers/net/wireless/intel/Kconfig" |
| 27 | 26 | source "drivers/net/wireless/intersil/Kconfig" |
| 28 | 27 | source "drivers/net/wireless/marvell/Kconfig" |
| @@ -38,8 +37,6 @@ source "drivers/net/wireless/ti/Kconfig" · 9 unmodified lines | ||
| 38 | 37 | source "drivers/net/wireless/zydas/Kconfig" |
| 39 | 38 | source "drivers/net/wireless/quantenna/Kconfig" |
| 40 | 39 | |
| 41 | −source "drivers/net/wireless/legacy/Kconfig" | |
| 42 | − | |
| 43 | 40 | source "drivers/net/wireless/virtual/Kconfig" |
| 44 | 41 | |
| 45 | 42 | endif # WLAN |
| @@ -7,7 +7,6 @@ obj-$(CONFIG_WLAN_VENDOR_ADMTEK) += admtek/ · 6 unmodified lines | ||
| 7 | 7 | obj-$(CONFIG_WLAN_VENDOR_ATH) += ath/ |
| 8 | 8 | obj-$(CONFIG_WLAN_VENDOR_ATMEL) += atmel/ |
| 9 | 9 | obj-$(CONFIG_WLAN_VENDOR_BROADCOM) += broadcom/ |
| 10 | −obj-$(CONFIG_WLAN_VENDOR_CISCO) += cisco/ | |
| 11 | 10 | obj-$(CONFIG_WLAN_VENDOR_INTEL) += intel/ |
| 12 | 11 | obj-$(CONFIG_WLAN_VENDOR_INTERSIL) += intersil/ |
| 13 | 12 | obj-$(CONFIG_WLAN_VENDOR_MARVELL) += marvell/ |
| @@ -23,5 +22,4 @@ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ · 9 unmodified lines | ||
| 23 | 22 | obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ |
| 24 | 23 | obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ |
| 25 | 24 | |
| 26 | −obj-$(CONFIG_WLAN) += legacy/ | |
| 27 | 25 | obj-$(CONFIG_WLAN) += virtual/ |
| @@ -12,41 +12,6 @@ config WLAN_VENDOR_ATMEL · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | if WLAN_VENDOR_ATMEL |
| 14 | 14 | |
| 15 | −config ATMEL | |
| 16 | − tristate "Atmel at76c50x chipset 802.11b support" | |
| 17 | − depends on CFG80211 && (PCI || PCMCIA) && HAS_IOPORT | |
| 18 | − select WIRELESS_EXT | |
| 19 | − select WEXT_PRIV | |
| 20 | − select FW_LOADER | |
| 21 | − select CRC32 | |
| 22 | − help | |
| 23 | − A driver 802.11b wireless cards based on the Atmel fast-vnet | |
| 24 | − chips. This driver supports standard Linux wireless extensions. | |
| 25 | − | |
| 26 | − Many cards based on this chipset do not have flash memory | |
| 27 | − and need their firmware loaded at start-up. If yours is | |
| 28 | − one of these, you will need to provide a firmware image | |
| 29 | − to be loaded into the card by the driver. The Atmel | |
| 30 | − firmware package can be downloaded from | |
| 31 | − <http://www.thekelleys.org.uk/atmel> | |
| 32 | − | |
| 33 | −config PCI_ATMEL | |
| 34 | − tristate "Atmel at76c506 PCI cards" | |
| 35 | − depends on ATMEL && PCI | |
| 36 | − help | |
| 37 | − Enable support for PCI and mini-PCI cards containing the | |
| 38 | − Atmel at76c506 chip. | |
| 39 | − | |
| 40 | −config PCMCIA_ATMEL | |
| 41 | − tristate "Atmel at76c502/at76c504 PCMCIA cards" | |
| 42 | − depends on ATMEL && PCMCIA | |
| 43 | − select WIRELESS_EXT | |
| 44 | − select FW_LOADER | |
| 45 | − select CRC32 | |
| 46 | − help | |
| 47 | − Enable support for PCMCIA cards containing the | |
| 48 | − Atmel at76c502 and at76c504 chips. | |
| 49 | − | |
| 50 | 15 | config AT76C50X_USB |
| 51 | 16 | tristate "Atmel at76c503/at76c505/at76c505a USB cards" |
| 52 | 17 | depends on MAC80211 && USB |
| @@ -1,6 +1,2 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | −obj-$(CONFIG_ATMEL) += atmel.o | |
| 3 | −obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o | |
| 4 | −obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o | |
| 5 | − | |
| 6 | 2 | obj-$(CONFIG_AT76C50X_USB) += at76c50x-usb.o |
| @@ -1,4452 +0,0 @@ | ||
| 1 | −/*** -*- linux-c -*- ********************************************************** | |
| 2 | − | |
| 3 | − Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | |
| 4 | − | |
| 5 | − Copyright 2000-2001 ATMEL Corporation. | |
| 6 | − Copyright 2003-2004 Simon Kelley. | |
| 7 | − | |
| 8 | − This code was developed from version 2.1.1 of the Atmel drivers, | |
| 9 | − released by Atmel corp. under the GPL in December 2002. It also | |
| 10 | − includes code from the Linux aironet drivers (C) Benjamin Reed, | |
| 11 | − and the Linux PCMCIA package, (C) David Hinds and the Linux wireless | |
| 12 | − extensions, (C) Jean Tourrilhes. | |
| 13 | − | |
| 14 | − The firmware module for reading the MAC address of the card comes from | |
| 15 | − net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright | |
| 16 | − by him. net.russotto.AtmelMACFW is used under the GPL license version 2. | |
| 17 | − This file contains the module in binary form and, under the terms | |
| 18 | − of the GPL, in source form. The source is located at the end of the file. | |
| 19 | − | |
| 20 | − This program is free software; you can redistribute it and/or modify | |
| 21 | − it under the terms of the GNU General Public License as published by | |
| 22 | − the Free Software Foundation; either version 2 of the License, or | |
| 23 | − (at your option) any later version. | |
| 24 | − | |
| 25 | − This software is distributed in the hope that it will be useful, | |
| 26 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 27 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 28 | − GNU General Public License for more details. | |
| 29 | − | |
| 30 | − You should have received a copy of the GNU General Public License | |
| 31 | − along with Atmel wireless lan drivers; if not, see | |
| 32 | − <http://www.gnu.org/licenses/>. | |
| 33 | − | |
| 34 | − For all queries about this code, please contact the current author, | |
| 35 | − Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. | |
| 36 | − | |
| 37 | − Credit is due to HP UK and Cambridge Online Systems Ltd for supplying | |
| 38 | − hardware used during development of this driver. | |
| 39 | − | |
| 40 | −******************************************************************************/ | |
| 41 | − | |
| 42 | −#include <linux/interrupt.h> | |
| 43 | − | |
| 44 | −#include <linux/kernel.h> | |
| 45 | −#include <linux/ptrace.h> | |
| 46 | −#include <linux/slab.h> | |
| 47 | −#include <linux/string.h> | |
| 48 | −#include <linux/timer.h> | |
| 49 | −#include <asm/byteorder.h> | |
| 50 | −#include <asm/io.h> | |
| 51 | −#include <linux/uaccess.h> | |
| 52 | −#include <linux/module.h> | |
| 53 | −#include <linux/netdevice.h> | |
| 54 | −#include <linux/etherdevice.h> | |
| 55 | −#include <linux/skbuff.h> | |
| 56 | −#include <linux/if_arp.h> | |
| 57 | −#include <linux/ioport.h> | |
| 58 | −#include <linux/fcntl.h> | |
| 59 | −#include <linux/delay.h> | |
| 60 | −#include <linux/wireless.h> | |
| 61 | −#include <net/iw_handler.h> | |
| 62 | −#include <linux/crc32.h> | |
| 63 | −#include <linux/proc_fs.h> | |
| 64 | −#include <linux/seq_file.h> | |
| 65 | −#include <linux/device.h> | |
| 66 | −#include <linux/moduleparam.h> | |
| 67 | −#include <linux/firmware.h> | |
| 68 | −#include <linux/jiffies.h> | |
| 69 | −#include <net/cfg80211.h> | |
| 70 | −#include "atmel.h" | |
| 71 | − | |
| 72 | −#define DRIVER_MAJOR 0 | |
| 73 | −#define DRIVER_MINOR 98 | |
| 74 | − | |
| 75 | −MODULE_AUTHOR("Simon Kelley"); | |
| 76 | −MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); | |
| 77 | −MODULE_LICENSE("GPL"); | |
| 78 | − | |
| 79 | −/* The name of the firmware file to be loaded | |
| 80 | − over-rides any automatic selection */ | |
| 81 | −static char *firmware = NULL; | |
| 82 | −module_param(firmware, charp, 0); | |
| 83 | − | |
| 84 | −/* table of firmware file names */ | |
| 85 | −static struct { | |
| 86 | − AtmelFWType fw_type; | |
| 87 | − const char *fw_file; | |
| 88 | − const char *fw_file_ext; | |
| 89 | −} fw_table[] = { | |
| 90 | − { ATMEL_FW_TYPE_502, "atmel_at76c502", "bin" }, | |
| 91 | − { ATMEL_FW_TYPE_502D, "atmel_at76c502d", "bin" }, | |
| 92 | − { ATMEL_FW_TYPE_502E, "atmel_at76c502e", "bin" }, | |
| 93 | − { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" }, | |
| 94 | − { ATMEL_FW_TYPE_504, "atmel_at76c504", "bin" }, | |
| 95 | − { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" }, | |
| 96 | − { ATMEL_FW_TYPE_504A_2958, "atmel_at76c504a_2958", "bin" }, | |
| 97 | − { ATMEL_FW_TYPE_506, "atmel_at76c506", "bin" }, | |
| 98 | − { ATMEL_FW_TYPE_NONE, NULL, NULL } | |
| 99 | −}; | |
| 100 | −MODULE_FIRMWARE("atmel_at76c502-wpa.bin"); | |
| 101 | −MODULE_FIRMWARE("atmel_at76c502.bin"); | |
| 102 | −MODULE_FIRMWARE("atmel_at76c502d-wpa.bin"); | |
| 103 | −MODULE_FIRMWARE("atmel_at76c502d.bin"); | |
| 104 | −MODULE_FIRMWARE("atmel_at76c502e-wpa.bin"); | |
| 105 | −MODULE_FIRMWARE("atmel_at76c502e.bin"); | |
| 106 | −MODULE_FIRMWARE("atmel_at76c502_3com-wpa.bin"); | |
| 107 | −MODULE_FIRMWARE("atmel_at76c502_3com.bin"); | |
| 108 | −MODULE_FIRMWARE("atmel_at76c504-wpa.bin"); | |
| 109 | −MODULE_FIRMWARE("atmel_at76c504.bin"); | |
| 110 | −MODULE_FIRMWARE("atmel_at76c504_2958-wpa.bin"); | |
| 111 | −MODULE_FIRMWARE("atmel_at76c504_2958.bin"); | |
| 112 | −MODULE_FIRMWARE("atmel_at76c504a_2958-wpa.bin"); | |
| 113 | −MODULE_FIRMWARE("atmel_at76c504a_2958.bin"); | |
| 114 | −MODULE_FIRMWARE("atmel_at76c506-wpa.bin"); | |
| 115 | −MODULE_FIRMWARE("atmel_at76c506.bin"); | |
| 116 | − | |
| 117 | −#define MAX_SSID_LENGTH 32 | |
| 118 | −#define MGMT_JIFFIES (256 * HZ / 100) | |
| 119 | − | |
| 120 | −#define MAX_BSS_ENTRIES 64 | |
| 121 | − | |
| 122 | −/* registers */ | |
| 123 | −#define GCR 0x00 /* (SIR0) General Configuration Register */ | |
| 124 | −#define BSR 0x02 /* (SIR1) Bank Switching Select Register */ | |
| 125 | −#define AR 0x04 | |
| 126 | −#define DR 0x08 | |
| 127 | −#define MR1 0x12 /* Mirror Register 1 */ | |
| 128 | −#define MR2 0x14 /* Mirror Register 2 */ | |
| 129 | −#define MR3 0x16 /* Mirror Register 3 */ | |
| 130 | −#define MR4 0x18 /* Mirror Register 4 */ | |
| 131 | − | |
| 132 | −#define GPR1 0x0c | |
| 133 | −#define GPR2 0x0e | |
| 134 | −#define GPR3 0x10 | |
| 135 | −/* | |
| 136 | − * Constants for the GCR register. | |
| 137 | − */ | |
| 138 | −#define GCR_REMAP 0x0400 /* Remap internal SRAM to 0 */ | |
| 139 | −#define GCR_SWRES 0x0080 /* BIU reset (ARM and PAI are NOT reset) */ | |
| 140 | −#define GCR_CORES 0x0060 /* Core Reset (ARM and PAI are reset) */ | |
| 141 | −#define GCR_ENINT 0x0002 /* Enable Interrupts */ | |
| 142 | −#define GCR_ACKINT 0x0008 /* Acknowledge Interrupts */ | |
| 143 | − | |
| 144 | −#define BSS_SRAM 0x0200 /* AMBA module selection --> SRAM */ | |
| 145 | −#define BSS_IRAM 0x0100 /* AMBA module selection --> IRAM */ | |
| 146 | −/* | |
| 147 | − *Constants for the MR registers. | |
| 148 | − */ | |
| 149 | −#define MAC_INIT_COMPLETE 0x0001 /* MAC init has been completed */ | |
| 150 | −#define MAC_BOOT_COMPLETE 0x0010 /* MAC boot has been completed */ | |
| 151 | −#define MAC_INIT_OK 0x0002 /* MAC boot has been completed */ | |
| 152 | − | |
| 153 | −#define MIB_MAX_DATA_BYTES 212 | |
| 154 | −#define MIB_HEADER_SIZE 4 /* first four fields */ | |
| 155 | − | |
| 156 | −struct get_set_mib { | |
| 157 | − u8 type; | |
| 158 | − u8 size; | |
| 159 | − u8 index; | |
| 160 | − u8 reserved; | |
| 161 | − u8 data[MIB_MAX_DATA_BYTES]; | |
| 162 | −}; | |
| 163 | − | |
| 164 | −struct rx_desc { | |
| 165 | − u32 Next; | |
| 166 | − u16 MsduPos; | |
| 167 | − u16 MsduSize; | |
| 168 | − | |
| 169 | − u8 State; | |
| 170 | − u8 Status; | |
| 171 | − u8 Rate; | |
| 172 | − u8 Rssi; | |
| 173 | − u8 LinkQuality; | |
| 174 | − u8 PreambleType; | |
| 175 | − u16 Duration; | |
| 176 | − u32 RxTime; | |
| 177 | −}; | |
| 178 | − | |
| 179 | −#define RX_DESC_FLAG_VALID 0x80 | |
| 180 | −#define RX_DESC_FLAG_CONSUMED 0x40 | |
| 181 | −#define RX_DESC_FLAG_IDLE 0x00 | |
| 182 | − | |
| 183 | −#define RX_STATUS_SUCCESS 0x00 | |
| 184 | − | |
| 185 | −#define RX_DESC_MSDU_POS_OFFSET 4 | |
| 186 | −#define RX_DESC_MSDU_SIZE_OFFSET 6 | |
| 187 | −#define RX_DESC_FLAGS_OFFSET 8 | |
| 188 | −#define RX_DESC_STATUS_OFFSET 9 | |
| 189 | −#define RX_DESC_RSSI_OFFSET 11 | |
| 190 | −#define RX_DESC_LINK_QUALITY_OFFSET 12 | |
| 191 | −#define RX_DESC_PREAMBLE_TYPE_OFFSET 13 | |
| 192 | −#define RX_DESC_DURATION_OFFSET 14 | |
| 193 | −#define RX_DESC_RX_TIME_OFFSET 16 | |
| 194 | − | |
| 195 | −struct tx_desc { | |
| 196 | − u32 NextDescriptor; | |
| 197 | − u16 TxStartOfFrame; | |
| 198 | − u16 TxLength; | |
| 199 | − | |
| 200 | − u8 TxState; | |
| 201 | − u8 TxStatus; | |
| 202 | − u8 RetryCount; | |
| 203 | − | |
| 204 | − u8 TxRate; | |
| 205 | − | |
| 206 | − u8 KeyIndex; | |
| 207 | − u8 ChiperType; | |
| 208 | − u8 ChipreLength; | |
| 209 | − u8 Reserved1; | |
| 210 | − | |
| 211 | − u8 Reserved; | |
| 212 | − u8 PacketType; | |
| 213 | − u16 HostTxLength; | |
| 214 | −}; | |
| 215 | − | |
| 216 | −#define TX_DESC_NEXT_OFFSET 0 | |
| 217 | −#define TX_DESC_POS_OFFSET 4 | |
| 218 | −#define TX_DESC_SIZE_OFFSET 6 | |
| 219 | −#define TX_DESC_FLAGS_OFFSET 8 | |
| 220 | −#define TX_DESC_STATUS_OFFSET 9 | |
| 221 | −#define TX_DESC_RETRY_OFFSET 10 | |
| 222 | −#define TX_DESC_RATE_OFFSET 11 | |
| 223 | −#define TX_DESC_KEY_INDEX_OFFSET 12 | |
| 224 | −#define TX_DESC_CIPHER_TYPE_OFFSET 13 | |
| 225 | −#define TX_DESC_CIPHER_LENGTH_OFFSET 14 | |
| 226 | −#define TX_DESC_PACKET_TYPE_OFFSET 17 | |
| 227 | −#define TX_DESC_HOST_LENGTH_OFFSET 18 | |
| 228 | − | |
| 229 | −/* | |
| 230 | − * Host-MAC interface | |
| 231 | − */ | |
| 232 | − | |
| 233 | −#define TX_STATUS_SUCCESS 0x00 | |
| 234 | − | |
| 235 | −#define TX_FIRM_OWN 0x80 | |
| 236 | −#define TX_DONE 0x40 | |
| 237 | − | |
| 238 | −#define TX_ERROR 0x01 | |
| 239 | − | |
| 240 | −#define TX_PACKET_TYPE_DATA 0x01 | |
| 241 | −#define TX_PACKET_TYPE_MGMT 0x02 | |
| 242 | − | |
| 243 | −#define ISR_EMPTY 0x00 /* no bits set in ISR */ | |
| 244 | −#define ISR_TxCOMPLETE 0x01 /* packet transmitted */ | |
| 245 | −#define ISR_RxCOMPLETE 0x02 /* packet received */ | |
| 246 | −#define ISR_RxFRAMELOST 0x04 /* Rx Frame lost */ | |
| 247 | −#define ISR_FATAL_ERROR 0x08 /* Fatal error */ | |
| 248 | −#define ISR_COMMAND_COMPLETE 0x10 /* command completed */ | |
| 249 | −#define ISR_OUT_OF_RANGE 0x20 /* command completed */ | |
| 250 | −#define ISR_IBSS_MERGE 0x40 /* (4.1.2.30): IBSS merge */ | |
| 251 | −#define ISR_GENERIC_IRQ 0x80 | |
| 252 | − | |
| 253 | −#define Local_Mib_Type 0x01 | |
| 254 | −#define Mac_Address_Mib_Type 0x02 | |
| 255 | −#define Mac_Mib_Type 0x03 | |
| 256 | −#define Statistics_Mib_Type 0x04 | |
| 257 | −#define Mac_Mgmt_Mib_Type 0x05 | |
| 258 | −#define Mac_Wep_Mib_Type 0x06 | |
| 259 | −#define Phy_Mib_Type 0x07 | |
| 260 | −#define Multi_Domain_MIB 0x08 | |
| 261 | − | |
| 262 | −#define MAC_MGMT_MIB_CUR_BSSID_POS 14 | |
| 263 | −#define MAC_MIB_FRAG_THRESHOLD_POS 8 | |
| 264 | −#define MAC_MIB_RTS_THRESHOLD_POS 10 | |
| 265 | −#define MAC_MIB_SHORT_RETRY_POS 16 | |
| 266 | −#define MAC_MIB_LONG_RETRY_POS 17 | |
| 267 | −#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 | |
| 268 | −#define MAC_MGMT_MIB_BEACON_PER_POS 0 | |
| 269 | −#define MAC_MGMT_MIB_STATION_ID_POS 6 | |
| 270 | −#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 | |
| 271 | −#define MAC_MGMT_MIB_CUR_BSSID_POS 14 | |
| 272 | −#define MAC_MGMT_MIB_PS_MODE_POS 53 | |
| 273 | −#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 | |
| 274 | −#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 | |
| 275 | −#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 | |
| 276 | −#define PHY_MIB_CHANNEL_POS 14 | |
| 277 | −#define PHY_MIB_RATE_SET_POS 20 | |
| 278 | −#define PHY_MIB_REG_DOMAIN_POS 26 | |
| 279 | −#define LOCAL_MIB_AUTO_TX_RATE_POS 3 | |
| 280 | −#define LOCAL_MIB_SSID_SIZE 5 | |
| 281 | −#define LOCAL_MIB_TX_PROMISCUOUS_POS 6 | |
| 282 | −#define LOCAL_MIB_TX_MGMT_RATE_POS 7 | |
| 283 | −#define LOCAL_MIB_TX_CONTROL_RATE_POS 8 | |
| 284 | −#define LOCAL_MIB_PREAMBLE_TYPE 9 | |
| 285 | −#define MAC_ADDR_MIB_MAC_ADDR_POS 0 | |
| 286 | − | |
| 287 | −#define CMD_Set_MIB_Vars 0x01 | |
| 288 | −#define CMD_Get_MIB_Vars 0x02 | |
| 289 | −#define CMD_Scan 0x03 | |
| 290 | −#define CMD_Join 0x04 | |
| 291 | −#define CMD_Start 0x05 | |
| 292 | −#define CMD_EnableRadio 0x06 | |
| 293 | −#define CMD_DisableRadio 0x07 | |
| 294 | −#define CMD_SiteSurvey 0x0B | |
| 295 | − | |
| 296 | −#define CMD_STATUS_IDLE 0x00 | |
| 297 | −#define CMD_STATUS_COMPLETE 0x01 | |
| 298 | −#define CMD_STATUS_UNKNOWN 0x02 | |
| 299 | −#define CMD_STATUS_INVALID_PARAMETER 0x03 | |
| 300 | −#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 | |
| 301 | −#define CMD_STATUS_TIME_OUT 0x07 | |
| 302 | −#define CMD_STATUS_IN_PROGRESS 0x08 | |
| 303 | −#define CMD_STATUS_REJECTED_RADIO_OFF 0x09 | |
| 304 | −#define CMD_STATUS_HOST_ERROR 0xFF | |
| 305 | −#define CMD_STATUS_BUSY 0xFE | |
| 306 | − | |
| 307 | −#define CMD_BLOCK_COMMAND_OFFSET 0 | |
| 308 | −#define CMD_BLOCK_STATUS_OFFSET 1 | |
| 309 | −#define CMD_BLOCK_PARAMETERS_OFFSET 4 | |
| 310 | − | |
| 311 | −#define SCAN_OPTIONS_SITE_SURVEY 0x80 | |
| 312 | − | |
| 313 | −#define MGMT_FRAME_BODY_OFFSET 24 | |
| 314 | −#define MAX_AUTHENTICATION_RETRIES 3 | |
| 315 | −#define MAX_ASSOCIATION_RETRIES 3 | |
| 316 | − | |
| 317 | −#define AUTHENTICATION_RESPONSE_TIME_OUT 1000 | |
| 318 | − | |
| 319 | −#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ | |
| 320 | −#define LOOP_RETRY_LIMIT 500000 | |
| 321 | − | |
| 322 | −#define ACTIVE_MODE 1 | |
| 323 | −#define PS_MODE 2 | |
| 324 | − | |
| 325 | −#define MAX_ENCRYPTION_KEYS 4 | |
| 326 | −#define MAX_ENCRYPTION_KEY_SIZE 40 | |
| 327 | − | |
| 328 | −/* | |
| 329 | − * 802.11 related definitions | |
| 330 | − */ | |
| 331 | − | |
| 332 | −/* | |
| 333 | − * Regulatory Domains | |
| 334 | − */ | |
| 335 | − | |
| 336 | −#define REG_DOMAIN_FCC 0x10 /* Channels 1-11 USA */ | |
| 337 | −#define REG_DOMAIN_DOC 0x20 /* Channel 1-11 Canada */ | |
| 338 | −#define REG_DOMAIN_ETSI 0x30 /* Channel 1-13 Europe (ex Spain/France) */ | |
| 339 | −#define REG_DOMAIN_SPAIN 0x31 /* Channel 10-11 Spain */ | |
| 340 | −#define REG_DOMAIN_FRANCE 0x32 /* Channel 10-13 France */ | |
| 341 | −#define REG_DOMAIN_MKK 0x40 /* Channel 14 Japan */ | |
| 342 | −#define REG_DOMAIN_MKK1 0x41 /* Channel 1-14 Japan(MKK1) */ | |
| 343 | −#define REG_DOMAIN_ISRAEL 0x50 /* Channel 3-9 ISRAEL */ | |
| 344 | − | |
| 345 | −#define BSS_TYPE_AD_HOC 1 | |
| 346 | −#define BSS_TYPE_INFRASTRUCTURE 2 | |
| 347 | − | |
| 348 | −#define SCAN_TYPE_ACTIVE 0 | |
| 349 | −#define SCAN_TYPE_PASSIVE 1 | |
| 350 | − | |
| 351 | −#define LONG_PREAMBLE 0 | |
| 352 | −#define SHORT_PREAMBLE 1 | |
| 353 | −#define AUTO_PREAMBLE 2 | |
| 354 | − | |
| 355 | −#define DATA_FRAME_WS_HEADER_SIZE 30 | |
| 356 | − | |
| 357 | −/* promiscuous mode control */ | |
| 358 | −#define PROM_MODE_OFF 0x0 | |
| 359 | −#define PROM_MODE_UNKNOWN 0x1 | |
| 360 | −#define PROM_MODE_CRC_FAILED 0x2 | |
| 361 | −#define PROM_MODE_DUPLICATED 0x4 | |
| 362 | −#define PROM_MODE_MGMT 0x8 | |
| 363 | −#define PROM_MODE_CTRL 0x10 | |
| 364 | −#define PROM_MODE_BAD_PROTOCOL 0x20 | |
| 365 | − | |
| 366 | −#define IFACE_INT_STATUS_OFFSET 0 | |
| 367 | −#define IFACE_INT_MASK_OFFSET 1 | |
| 368 | −#define IFACE_LOCKOUT_HOST_OFFSET 2 | |
| 369 | −#define IFACE_LOCKOUT_MAC_OFFSET 3 | |
| 370 | −#define IFACE_FUNC_CTRL_OFFSET 28 | |
| 371 | −#define IFACE_MAC_STAT_OFFSET 30 | |
| 372 | −#define IFACE_GENERIC_INT_TYPE_OFFSET 32 | |
| 373 | − | |
| 374 | −#define CIPHER_SUITE_NONE 0 | |
| 375 | −#define CIPHER_SUITE_WEP_64 1 | |
| 376 | −#define CIPHER_SUITE_TKIP 2 | |
| 377 | −#define CIPHER_SUITE_AES 3 | |
| 378 | −#define CIPHER_SUITE_CCX 4 | |
| 379 | −#define CIPHER_SUITE_WEP_128 5 | |
| 380 | − | |
| 381 | −/* | |
| 382 | − * IFACE MACROS & definitions | |
| 383 | − */ | |
| 384 | − | |
| 385 | −/* | |
| 386 | − * FuncCtrl field: | |
| 387 | − */ | |
| 388 | −#define FUNC_CTRL_TxENABLE 0x10 | |
| 389 | −#define FUNC_CTRL_RxENABLE 0x20 | |
| 390 | −#define FUNC_CTRL_INIT_COMPLETE 0x01 | |
| 391 | − | |
| 392 | −/* A stub firmware image which reads the MAC address from NVRAM on the card. | |
| 393 | − For copyright information and source see the end of this file. */ | |
| 394 | −static u8 mac_reader[] = { | |
| 395 | − 0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea, | |
| 396 | − 0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea, | |
| 397 | − 0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, | |
| 398 | − 0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5, | |
| 399 | − 0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5, | |
| 400 | − 0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1, | |
| 401 | − 0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb, | |
| 402 | − 0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb, | |
| 403 | − 0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5, | |
| 404 | − 0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea, | |
| 405 | − 0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, | |
| 406 | − 0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, | |
| 407 | − 0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, | |
| 408 | − 0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, | |
| 409 | − 0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2, | |
| 410 | − 0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3, | |
| 411 | − 0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, | |
| 412 | − 0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5, | |
| 413 | − 0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5, | |
| 414 | − 0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5, | |
| 415 | − 0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3, | |
| 416 | − 0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5, | |
| 417 | − 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, | |
| 418 | − 0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, | |
| 419 | − 0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5, | |
| 420 | − 0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1, | |
| 421 | − 0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2, | |
| 422 | − 0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb, | |
| 423 | − 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb, | |
| 424 | − 0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb, | |
| 425 | − 0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3, | |
| 426 | − 0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5, | |
| 427 | − 0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3, | |
| 428 | − 0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a, | |
| 429 | − 0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5, | |
| 430 | − 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3, | |
| 431 | − 0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3, | |
| 432 | − 0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3, | |
| 433 | − 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2, | |
| 434 | − 0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb, | |
| 435 | − 0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02, | |
| 436 | − 0x00, 0x01, 0x00, 0x02 | |
| 437 | −}; | |
| 438 | − | |
| 439 | −struct atmel_private { | |
| 440 | − void *card; /* Bus dependent structure varies for PCcard */ | |
| 441 | − int (*present_callback)(void *); /* And callback which uses it */ | |
| 442 | − char firmware_id[32]; | |
| 443 | − AtmelFWType firmware_type; | |
| 444 | − u8 *firmware; | |
| 445 | − int firmware_length; | |
| 446 | − struct timer_list management_timer; | |
| 447 | − struct net_device *dev; | |
| 448 | − struct device *sys_dev; | |
| 449 | − struct iw_statistics wstats; | |
| 450 | − spinlock_t irqlock, timerlock; /* spinlocks */ | |
| 451 | − enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; | |
| 452 | − enum { | |
| 453 | − CARD_TYPE_PARALLEL_FLASH, | |
| 454 | − CARD_TYPE_SPI_FLASH, | |
| 455 | − CARD_TYPE_EEPROM | |
| 456 | − } card_type; | |
| 457 | − int do_rx_crc; /* If we need to CRC incoming packets */ | |
| 458 | − int probe_crc; /* set if we don't yet know */ | |
| 459 | − int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ | |
| 460 | − u16 rx_desc_head; | |
| 461 | − u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; | |
| 462 | − u16 tx_free_mem, tx_buff_head, tx_buff_tail; | |
| 463 | − | |
| 464 | − u16 frag_seq, frag_len, frag_no; | |
| 465 | − u8 frag_source[6]; | |
| 466 | − | |
| 467 | − u8 wep_is_on, default_key, exclude_unencrypted, encryption_level; | |
| 468 | − u8 group_cipher_suite, pairwise_cipher_suite; | |
| 469 | − u8 wep_keys[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; | |
| 470 | − int wep_key_len[MAX_ENCRYPTION_KEYS]; | |
| 471 | − int use_wpa, radio_on_broken; /* firmware dependent stuff. */ | |
| 472 | − | |
| 473 | − u16 host_info_base; | |
| 474 | − struct host_info_struct { | |
| 475 | − /* NB this is matched to the hardware, don't change. */ | |
| 476 | − u8 volatile int_status; | |
| 477 | − u8 volatile int_mask; | |
| 478 | − u8 volatile lockout_host; | |
| 479 | − u8 volatile lockout_mac; | |
| 480 | − | |
| 481 | − u16 tx_buff_pos; | |
| 482 | − u16 tx_buff_size; | |
| 483 | − u16 tx_desc_pos; | |
| 484 | − u16 tx_desc_count; | |
| 485 | − | |
| 486 | − u16 rx_buff_pos; | |
| 487 | − u16 rx_buff_size; | |
| 488 | − u16 rx_desc_pos; | |
| 489 | − u16 rx_desc_count; | |
| 490 | − | |
| 491 | − u16 build_version; | |
| 492 | − u16 command_pos; | |
| 493 | − | |
| 494 | − u16 major_version; | |
| 495 | − u16 minor_version; | |
| 496 | − | |
| 497 | − u16 func_ctrl; | |
| 498 | − u16 mac_status; | |
| 499 | − u16 generic_IRQ_type; | |
| 500 | − u8 reserved[2]; | |
| 501 | − } host_info; | |
| 502 | − | |
| 503 | − enum { | |
| 504 | − STATION_STATE_SCANNING, | |
| 505 | − STATION_STATE_JOINNING, | |
| 506 | − STATION_STATE_AUTHENTICATING, | |
| 507 | − STATION_STATE_ASSOCIATING, | |
| 508 | − STATION_STATE_READY, | |
| 509 | − STATION_STATE_REASSOCIATING, | |
| 510 | − STATION_STATE_DOWN, | |
| 511 | − STATION_STATE_MGMT_ERROR | |
| 512 | − } station_state; | |
| 513 | − | |
| 514 | − int operating_mode, power_mode; | |
| 515 | − unsigned long last_qual; | |
| 516 | − int beacons_this_sec; | |
| 517 | − int channel; | |
| 518 | − int reg_domain, config_reg_domain; | |
| 519 | − int tx_rate; | |
| 520 | − int auto_tx_rate; | |
| 521 | − int rts_threshold; | |
| 522 | − int frag_threshold; | |
| 523 | − int long_retry, short_retry; | |
| 524 | − int preamble; | |
| 525 | − int default_beacon_period, beacon_period, listen_interval; | |
| 526 | − int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; | |
| 527 | − int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; | |
| 528 | − enum { | |
| 529 | − SITE_SURVEY_IDLE, | |
| 530 | − SITE_SURVEY_IN_PROGRESS, | |
| 531 | − SITE_SURVEY_COMPLETED | |
| 532 | − } site_survey_state; | |
| 533 | − unsigned long last_survey; | |
| 534 | − | |
| 535 | − int station_was_associated, station_is_associated; | |
| 536 | − int fast_scan; | |
| 537 | − | |
| 538 | − struct bss_info { | |
| 539 | − int channel; | |
| 540 | − int SSIDsize; | |
| 541 | − int RSSI; | |
| 542 | − int UsingWEP; | |
| 543 | − int preamble; | |
| 544 | − int beacon_period; | |
| 545 | − int BSStype; | |
| 546 | − u8 BSSID[6]; | |
| 547 | − u8 SSID[MAX_SSID_LENGTH]; | |
| 548 | − } BSSinfo[MAX_BSS_ENTRIES]; | |
| 549 | − int BSS_list_entries, current_BSS; | |
| 550 | − int connect_to_any_BSS; | |
| 551 | − int SSID_size, new_SSID_size; | |
| 552 | − u8 CurrentBSSID[6], BSSID[6]; | |
| 553 | − u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; | |
| 554 | − u64 last_beacon_timestamp; | |
| 555 | − u8 rx_buf[MAX_WIRELESS_BODY]; | |
| 556 | −}; | |
| 557 | − | |
| 558 | −static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16}; | |
| 559 | − | |
| 560 | −static const struct { | |
| 561 | − int reg_domain; | |
| 562 | − int min, max; | |
| 563 | − char *name; | |
| 564 | −} channel_table[] = { { REG_DOMAIN_FCC, 1, 11, "USA" }, | |
| 565 | − { REG_DOMAIN_DOC, 1, 11, "Canada" }, | |
| 566 | − { REG_DOMAIN_ETSI, 1, 13, "Europe" }, | |
| 567 | − { REG_DOMAIN_SPAIN, 10, 11, "Spain" }, | |
| 568 | − { REG_DOMAIN_FRANCE, 10, 13, "France" }, | |
| 569 | − { REG_DOMAIN_MKK, 14, 14, "MKK" }, | |
| 570 | − { REG_DOMAIN_MKK1, 1, 14, "MKK1" }, | |
| 571 | − { REG_DOMAIN_ISRAEL, 3, 9, "Israel"} }; | |
| 572 | − | |
| 573 | −static void build_wpa_mib(struct atmel_private *priv); | |
| 574 | −static void atmel_copy_to_card(struct net_device *dev, u16 dest, | |
| 575 | − const unsigned char *src, u16 len); | |
| 576 | −static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, | |
| 577 | − u16 src, u16 len); | |
| 578 | −static void atmel_set_gcr(struct net_device *dev, u16 mask); | |
| 579 | −static void atmel_clear_gcr(struct net_device *dev, u16 mask); | |
| 580 | −static int atmel_lock_mac(struct atmel_private *priv); | |
| 581 | −static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); | |
| 582 | −static void atmel_command_irq(struct atmel_private *priv); | |
| 583 | −static int atmel_validate_channel(struct atmel_private *priv, int channel); | |
| 584 | −static void atmel_management_frame(struct atmel_private *priv, | |
| 585 | − struct ieee80211_hdr *header, | |
| 586 | − u16 frame_len, u8 rssi); | |
| 587 | −static void atmel_management_timer(struct timer_list *t); | |
| 588 | −static void atmel_send_command(struct atmel_private *priv, int command, | |
| 589 | − void *cmd, int cmd_size); | |
| 590 | −static int atmel_send_command_wait(struct atmel_private *priv, int command, | |
| 591 | − void *cmd, int cmd_size); | |
| 592 | −static void atmel_transmit_management_frame(struct atmel_private *priv, | |
| 593 | − struct ieee80211_hdr *header, | |
| 594 | − u8 *body, int body_len); | |
| 595 | − | |
| 596 | −static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); | |
| 597 | −static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, | |
| 598 | − u8 data); | |
| 599 | −static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, | |
| 600 | − u16 data); | |
| 601 | −static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, | |
| 602 | − const u8 *data, int data_len); | |
| 603 | −static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, | |
| 604 | − u8 *data, int data_len); | |
| 605 | −static void atmel_scan(struct atmel_private *priv, int specific_ssid); | |
| 606 | −static void atmel_join_bss(struct atmel_private *priv, int bss_index); | |
| 607 | −static void atmel_smooth_qual(struct atmel_private *priv); | |
| 608 | −static void atmel_writeAR(struct net_device *dev, u16 data); | |
| 609 | −static int probe_atmel_card(struct net_device *dev); | |
| 610 | −static int reset_atmel_card(struct net_device *dev); | |
| 611 | −static void atmel_enter_state(struct atmel_private *priv, int new_state); | |
| 612 | −int atmel_open (struct net_device *dev); | |
| 613 | − | |
| 614 | −static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) | |
| 615 | −{ | |
| 616 | − return priv->host_info_base + offset; | |
| 617 | −} | |
| 618 | − | |
| 619 | −static inline u16 atmel_co(struct atmel_private *priv, u16 offset) | |
| 620 | −{ | |
| 621 | − return priv->host_info.command_pos + offset; | |
| 622 | −} | |
| 623 | − | |
| 624 | −static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) | |
| 625 | −{ | |
| 626 | − return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; | |
| 627 | −} | |
| 628 | − | |
| 629 | −static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) | |
| 630 | −{ | |
| 631 | − return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; | |
| 632 | −} | |
| 633 | − | |
| 634 | −static inline u8 atmel_read8(struct net_device *dev, u16 offset) | |
| 635 | −{ | |
| 636 | − return inb(dev->base_addr + offset); | |
| 637 | −} | |
| 638 | − | |
| 639 | −static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) | |
| 640 | −{ | |
| 641 | − outb(data, dev->base_addr + offset); | |
| 642 | −} | |
| 643 | − | |
| 644 | −static inline u16 atmel_read16(struct net_device *dev, u16 offset) | |
| 645 | −{ | |
| 646 | − return inw(dev->base_addr + offset); | |
| 647 | −} | |
| 648 | − | |
| 649 | −static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) | |
| 650 | −{ | |
| 651 | − outw(data, dev->base_addr + offset); | |
| 652 | −} | |
| 653 | − | |
| 654 | −static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) | |
| 655 | −{ | |
| 656 | − atmel_writeAR(priv->dev, pos); | |
| 657 | − return atmel_read8(priv->dev, DR); | |
| 658 | −} | |
| 659 | − | |
| 660 | −static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) | |
| 661 | −{ | |
| 662 | − atmel_writeAR(priv->dev, pos); | |
| 663 | − atmel_write8(priv->dev, DR, data); | |
| 664 | −} | |
| 665 | − | |
| 666 | −static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) | |
| 667 | −{ | |
| 668 | − atmel_writeAR(priv->dev, pos); | |
| 669 | − return atmel_read16(priv->dev, DR); | |
| 670 | −} | |
| 671 | − | |
| 672 | −static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) | |
| 673 | −{ | |
| 674 | − atmel_writeAR(priv->dev, pos); | |
| 675 | − atmel_write16(priv->dev, DR, data); | |
| 676 | −} | |
| 677 | − | |
| 678 | −static const struct iw_handler_def atmel_handler_def; | |
| 679 | − | |
| 680 | −static void tx_done_irq(struct atmel_private *priv) | |
| 681 | −{ | |
| 682 | − int i; | |
| 683 | − | |
| 684 | − for (i = 0; | |
| 685 | − atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && | |
| 686 | − i < priv->host_info.tx_desc_count; | |
| 687 | − i++) { | |
| 688 | − u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); | |
| 689 | − u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); | |
| 690 | − u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); | |
| 691 | − | |
| 692 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); | |
| 693 | − | |
| 694 | − priv->tx_free_mem += msdu_size; | |
| 695 | − priv->tx_desc_free++; | |
| 696 | − | |
| 697 | − if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) | |
| 698 | − priv->tx_buff_head = 0; | |
| 699 | − else | |
| 700 | − priv->tx_buff_head += msdu_size; | |
| 701 | − | |
| 702 | − if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) | |
| 703 | − priv->tx_desc_head++ ; | |
| 704 | − else | |
| 705 | − priv->tx_desc_head = 0; | |
| 706 | − | |
| 707 | − if (type == TX_PACKET_TYPE_DATA) { | |
| 708 | − if (status == TX_STATUS_SUCCESS) | |
| 709 | − priv->dev->stats.tx_packets++; | |
| 710 | − else | |
| 711 | − priv->dev->stats.tx_errors++; | |
| 712 | − netif_wake_queue(priv->dev); | |
| 713 | − } | |
| 714 | − } | |
| 715 | −} | |
| 716 | − | |
| 717 | −static u16 find_tx_buff(struct atmel_private *priv, u16 len) | |
| 718 | −{ | |
| 719 | − u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; | |
| 720 | − | |
| 721 | − if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) | |
| 722 | − return 0; | |
| 723 | − | |
| 724 | − if (bottom_free >= len) | |
| 725 | − return priv->host_info.tx_buff_pos + priv->tx_buff_tail; | |
| 726 | − | |
| 727 | − if (priv->tx_free_mem - bottom_free >= len) { | |
| 728 | − priv->tx_buff_tail = 0; | |
| 729 | − return priv->host_info.tx_buff_pos; | |
| 730 | − } | |
| 731 | − | |
| 732 | − return 0; | |
| 733 | −} | |
| 734 | − | |
| 735 | −static void tx_update_descriptor(struct atmel_private *priv, int is_bcast, | |
| 736 | − u16 len, u16 buff, u8 type) | |
| 737 | −{ | |
| 738 | − atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); | |
| 739 | − atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); | |
| 740 | − if (!priv->use_wpa) | |
| 741 | − atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); | |
| 742 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); | |
| 743 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); | |
| 744 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); | |
| 745 | − if (priv->use_wpa) { | |
| 746 | − int cipher_type, cipher_length; | |
| 747 | − if (is_bcast) { | |
| 748 | − cipher_type = priv->group_cipher_suite; | |
| 749 | − if (cipher_type == CIPHER_SUITE_WEP_64 || | |
| 750 | − cipher_type == CIPHER_SUITE_WEP_128) | |
| 751 | − cipher_length = 8; | |
| 752 | − else if (cipher_type == CIPHER_SUITE_TKIP) | |
| 753 | − cipher_length = 12; | |
| 754 | − else if (priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_64 || | |
| 755 | − priv->pairwise_cipher_suite == CIPHER_SUITE_WEP_128) { | |
| 756 | − cipher_type = priv->pairwise_cipher_suite; | |
| 757 | − cipher_length = 8; | |
| 758 | − } else { | |
| 759 | − cipher_type = CIPHER_SUITE_NONE; | |
| 760 | − cipher_length = 0; | |
| 761 | − } | |
| 762 | − } else { | |
| 763 | − cipher_type = priv->pairwise_cipher_suite; | |
| 764 | − if (cipher_type == CIPHER_SUITE_WEP_64 || | |
| 765 | − cipher_type == CIPHER_SUITE_WEP_128) | |
| 766 | − cipher_length = 8; | |
| 767 | − else if (cipher_type == CIPHER_SUITE_TKIP) | |
| 768 | − cipher_length = 12; | |
| 769 | − else if (priv->group_cipher_suite == CIPHER_SUITE_WEP_64 || | |
| 770 | − priv->group_cipher_suite == CIPHER_SUITE_WEP_128) { | |
| 771 | − cipher_type = priv->group_cipher_suite; | |
| 772 | − cipher_length = 8; | |
| 773 | − } else { | |
| 774 | − cipher_type = CIPHER_SUITE_NONE; | |
| 775 | − cipher_length = 0; | |
| 776 | − } | |
| 777 | − } | |
| 778 | − | |
| 779 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_TYPE_OFFSET, priv->tx_desc_tail), | |
| 780 | − cipher_type); | |
| 781 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_CIPHER_LENGTH_OFFSET, priv->tx_desc_tail), | |
| 782 | − cipher_length); | |
| 783 | − } | |
| 784 | − atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); | |
| 785 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); | |
| 786 | − if (priv->tx_desc_previous != priv->tx_desc_tail) | |
| 787 | − atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); | |
| 788 | − priv->tx_desc_previous = priv->tx_desc_tail; | |
| 789 | − if (priv->tx_desc_tail < (priv->host_info.tx_desc_count - 1)) | |
| 790 | − priv->tx_desc_tail++; | |
| 791 | − else | |
| 792 | − priv->tx_desc_tail = 0; | |
| 793 | − priv->tx_desc_free--; | |
| 794 | − priv->tx_free_mem -= len; | |
| 795 | −} | |
| 796 | − | |
| 797 | −static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) | |
| 798 | −{ | |
| 799 | − struct atmel_private *priv = netdev_priv(dev); | |
| 800 | − struct ieee80211_hdr header; | |
| 801 | − unsigned long flags; | |
| 802 | − u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; | |
| 803 | − | |
| 804 | − if (priv->card && priv->present_callback && | |
| 805 | − !(*priv->present_callback)(priv->card)) { | |
| 806 | − dev->stats.tx_errors++; | |
| 807 | − dev_kfree_skb(skb); | |
| 808 | − return NETDEV_TX_OK; | |
| 809 | − } | |
| 810 | − | |
| 811 | − if (priv->station_state != STATION_STATE_READY) { | |
| 812 | − dev->stats.tx_errors++; | |
| 813 | − dev_kfree_skb(skb); | |
| 814 | − return NETDEV_TX_OK; | |
| 815 | − } | |
| 816 | − | |
| 817 | − /* first ensure the timer func cannot run */ | |
| 818 | − spin_lock_bh(&priv->timerlock); | |
| 819 | − /* then stop the hardware ISR */ | |
| 820 | − spin_lock_irqsave(&priv->irqlock, flags); | |
| 821 | − /* nb doing the above in the opposite order will deadlock */ | |
| 822 | − | |
| 823 | − /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the | |
| 824 | − 12 first bytes (containing DA/SA) and put them in the appropriate | |
| 825 | − fields of the Wireless Header. Thus the packet length is then the | |
| 826 | − initial + 18 (+30-12) */ | |
| 827 | − | |
| 828 | − if (!(buff = find_tx_buff(priv, len + 18))) { | |
| 829 | − dev->stats.tx_dropped++; | |
| 830 | − spin_unlock_irqrestore(&priv->irqlock, flags); | |
| 831 | − spin_unlock_bh(&priv->timerlock); | |
| 832 | − netif_stop_queue(dev); | |
| 833 | − return NETDEV_TX_BUSY; | |
| 834 | − } | |
| 835 | − | |
| 836 | − frame_ctl = IEEE80211_FTYPE_DATA; | |
| 837 | − header.duration_id = 0; | |
| 838 | − header.seq_ctrl = 0; | |
| 839 | − if (priv->wep_is_on) | |
| 840 | − frame_ctl |= IEEE80211_FCTL_PROTECTED; | |
| 841 | − if (priv->operating_mode == IW_MODE_ADHOC) { | |
| 842 | − skb_copy_from_linear_data(skb, &header.addr1, ETH_ALEN); | |
| 843 | − memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); | |
| 844 | − memcpy(&header.addr3, priv->BSSID, ETH_ALEN); | |
| 845 | − } else { | |
| 846 | − frame_ctl |= IEEE80211_FCTL_TODS; | |
| 847 | − memcpy(&header.addr1, priv->CurrentBSSID, ETH_ALEN); | |
| 848 | − memcpy(&header.addr2, dev->dev_addr, ETH_ALEN); | |
| 849 | − skb_copy_from_linear_data(skb, &header.addr3, ETH_ALEN); | |
| 850 | − } | |
| 851 | − | |
| 852 | − if (priv->use_wpa) | |
| 853 | − memcpy(&header.addr4, rfc1042_header, ETH_ALEN); | |
| 854 | − | |
| 855 | − header.frame_control = cpu_to_le16(frame_ctl); | |
| 856 | − /* Copy the wireless header into the card */ | |
| 857 | − atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); | |
| 858 | − /* Copy the packet sans its 802.3 header addresses which have been replaced */ | |
| 859 | − atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); | |
| 860 | − priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; | |
| 861 | − | |
| 862 | − /* low bit of first byte of destination tells us if broadcast */ | |
| 863 | − tx_update_descriptor(priv, *(skb->data) & 0x01, len + 18, buff, TX_PACKET_TYPE_DATA); | |
| 864 | − dev->stats.tx_bytes += len; | |
| 865 | − | |
| 866 | − spin_unlock_irqrestore(&priv->irqlock, flags); | |
| 867 | − spin_unlock_bh(&priv->timerlock); | |
| 868 | − dev_kfree_skb(skb); | |
| 869 | − | |
| 870 | − return NETDEV_TX_OK; | |
| 871 | −} | |
| 872 | − | |
| 873 | −static void atmel_transmit_management_frame(struct atmel_private *priv, | |
| 874 | − struct ieee80211_hdr *header, | |
| 875 | − u8 *body, int body_len) | |
| 876 | −{ | |
| 877 | − u16 buff; | |
| 878 | − int len = MGMT_FRAME_BODY_OFFSET + body_len; | |
| 879 | − | |
| 880 | − if (!(buff = find_tx_buff(priv, len))) | |
| 881 | − return; | |
| 882 | − | |
| 883 | − atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); | |
| 884 | − atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); | |
| 885 | − priv->tx_buff_tail += len; | |
| 886 | − tx_update_descriptor(priv, header->addr1[0] & 0x01, len, buff, TX_PACKET_TYPE_MGMT); | |
| 887 | −} | |
| 888 | − | |
| 889 | −static void fast_rx_path(struct atmel_private *priv, | |
| 890 | − struct ieee80211_hdr *header, | |
| 891 | − u16 msdu_size, u16 rx_packet_loc, u32 crc) | |
| 892 | −{ | |
| 893 | − /* fast path: unfragmented packet copy directly into skbuf */ | |
| 894 | − u8 mac4[6]; | |
| 895 | − struct sk_buff *skb; | |
| 896 | − unsigned char *skbp; | |
| 897 | − | |
| 898 | − /* get the final, mac 4 header field, this tells us encapsulation */ | |
| 899 | − atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); | |
| 900 | − msdu_size -= 6; | |
| 901 | − | |
| 902 | − if (priv->do_rx_crc) { | |
| 903 | − crc = crc32_le(crc, mac4, 6); | |
| 904 | − msdu_size -= 4; | |
| 905 | − } | |
| 906 | − | |
| 907 | − if (!(skb = dev_alloc_skb(msdu_size + 14))) { | |
| 908 | − priv->dev->stats.rx_dropped++; | |
| 909 | − return; | |
| 910 | − } | |
| 911 | − | |
| 912 | − skb_reserve(skb, 2); | |
| 913 | − skbp = skb_put(skb, msdu_size + 12); | |
| 914 | − atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); | |
| 915 | − | |
| 916 | − if (priv->do_rx_crc) { | |
| 917 | − u32 netcrc; | |
| 918 | − crc = crc32_le(crc, skbp + 12, msdu_size); | |
| 919 | − atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); | |
| 920 | − if ((crc ^ 0xffffffff) != netcrc) { | |
| 921 | − priv->dev->stats.rx_crc_errors++; | |
| 922 | − dev_kfree_skb(skb); | |
| 923 | − return; | |
| 924 | − } | |
| 925 | − } | |
| 926 | − | |
| 927 | − memcpy(skbp, header->addr1, ETH_ALEN); /* destination address */ | |
| 928 | − if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) | |
| 929 | − memcpy(&skbp[ETH_ALEN], header->addr3, ETH_ALEN); | |
| 930 | − else | |
| 931 | − memcpy(&skbp[ETH_ALEN], header->addr2, ETH_ALEN); /* source address */ | |
| 932 | − | |
| 933 | − skb->protocol = eth_type_trans(skb, priv->dev); | |
| 934 | − skb->ip_summed = CHECKSUM_NONE; | |
| 935 | − netif_rx(skb); | |
| 936 | − priv->dev->stats.rx_bytes += 12 + msdu_size; | |
| 937 | − priv->dev->stats.rx_packets++; | |
| 938 | −} | |
| 939 | − | |
| 940 | −/* Test to see if the packet in card memory at packet_loc has a valid CRC | |
| 941 | − It doesn't matter that this is slow: it is only used to proble the first few | |
| 942 | − packets. */ | |
| 943 | −static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) | |
| 944 | −{ | |
| 945 | − int i = msdu_size - 4; | |
| 946 | − u32 netcrc, crc = 0xffffffff; | |
| 947 | − | |
| 948 | − if (msdu_size < 4) | |
| 949 | − return 0; | |
| 950 | − | |
| 951 | − atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); | |
| 952 | − | |
| 953 | − atmel_writeAR(priv->dev, packet_loc); | |
| 954 | − while (i--) { | |
| 955 | − u8 octet = atmel_read8(priv->dev, DR); | |
| 956 | − crc = crc32_le(crc, &octet, 1); | |
| 957 | − } | |
| 958 | − | |
| 959 | − return (crc ^ 0xffffffff) == netcrc; | |
| 960 | −} | |
| 961 | − | |
| 962 | −static void frag_rx_path(struct atmel_private *priv, | |
| 963 | − struct ieee80211_hdr *header, | |
| 964 | − u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, | |
| 965 | − u8 frag_no, int more_frags) | |
| 966 | −{ | |
| 967 | − u8 mac4[ETH_ALEN]; | |
| 968 | − u8 source[ETH_ALEN]; | |
| 969 | − struct sk_buff *skb; | |
| 970 | − | |
| 971 | − if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) | |
| 972 | − memcpy(source, header->addr3, ETH_ALEN); | |
| 973 | − else | |
| 974 | − memcpy(source, header->addr2, ETH_ALEN); | |
| 975 | − | |
| 976 | − rx_packet_loc += 24; /* skip header */ | |
| 977 | − | |
| 978 | − if (priv->do_rx_crc) | |
| 979 | − msdu_size -= 4; | |
| 980 | − | |
| 981 | − if (frag_no == 0) { /* first fragment */ | |
| 982 | − atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, ETH_ALEN); | |
| 983 | − msdu_size -= ETH_ALEN; | |
| 984 | − rx_packet_loc += ETH_ALEN; | |
| 985 | − | |
| 986 | − if (priv->do_rx_crc) | |
| 987 | − crc = crc32_le(crc, mac4, 6); | |
| 988 | − | |
| 989 | − priv->frag_seq = seq_no; | |
| 990 | − priv->frag_no = 1; | |
| 991 | − priv->frag_len = msdu_size; | |
| 992 | − memcpy(priv->frag_source, source, ETH_ALEN); | |
| 993 | − memcpy(&priv->rx_buf[ETH_ALEN], source, ETH_ALEN); | |
| 994 | − memcpy(priv->rx_buf, header->addr1, ETH_ALEN); | |
| 995 | − | |
| 996 | − atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); | |
| 997 | − | |
| 998 | − if (priv->do_rx_crc) { | |
| 999 | − u32 netcrc; | |
| 1000 | − crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); | |
| 1001 | − atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); | |
| 1002 | − if ((crc ^ 0xffffffff) != netcrc) { | |
| 1003 | − priv->dev->stats.rx_crc_errors++; | |
| 1004 | − eth_broadcast_addr(priv->frag_source); | |
| 1005 | − } | |
| 1006 | − } | |
| 1007 | − | |
| 1008 | − } else if (priv->frag_no == frag_no && | |
| 1009 | − priv->frag_seq == seq_no && | |
| 1010 | − memcmp(priv->frag_source, source, ETH_ALEN) == 0) { | |
| 1011 | − | |
| 1012 | − atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], | |
| 1013 | − rx_packet_loc, msdu_size); | |
| 1014 | − if (priv->do_rx_crc) { | |
| 1015 | − u32 netcrc; | |
| 1016 | − crc = crc32_le(crc, | |
| 1017 | − &priv->rx_buf[12 + priv->frag_len], | |
| 1018 | − msdu_size); | |
| 1019 | − atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); | |
| 1020 | − if ((crc ^ 0xffffffff) != netcrc) { | |
| 1021 | − priv->dev->stats.rx_crc_errors++; | |
| 1022 | − eth_broadcast_addr(priv->frag_source); | |
| 1023 | − more_frags = 1; /* don't send broken assembly */ | |
| 1024 | − } | |
| 1025 | − } | |
| 1026 | − | |
| 1027 | − priv->frag_len += msdu_size; | |
| 1028 | − priv->frag_no++; | |
| 1029 | − | |
| 1030 | − if (!more_frags) { /* last one */ | |
| 1031 | − eth_broadcast_addr(priv->frag_source); | |
| 1032 | − if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { | |
| 1033 | − priv->dev->stats.rx_dropped++; | |
| 1034 | − } else { | |
| 1035 | − skb_reserve(skb, 2); | |
| 1036 | − skb_put_data(skb, priv->rx_buf, | |
| 1037 | − priv->frag_len + 12); | |
| 1038 | − skb->protocol = eth_type_trans(skb, priv->dev); | |
| 1039 | − skb->ip_summed = CHECKSUM_NONE; | |
| 1040 | − netif_rx(skb); | |
| 1041 | − priv->dev->stats.rx_bytes += priv->frag_len + 12; | |
| 1042 | − priv->dev->stats.rx_packets++; | |
| 1043 | − } | |
| 1044 | − } | |
| 1045 | − } else | |
| 1046 | − priv->wstats.discard.fragment++; | |
| 1047 | −} | |
| 1048 | − | |
| 1049 | −static void rx_done_irq(struct atmel_private *priv) | |
| 1050 | −{ | |
| 1051 | − int i; | |
| 1052 | − struct ieee80211_hdr header; | |
| 1053 | − | |
| 1054 | − for (i = 0; | |
| 1055 | − atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && | |
| 1056 | − i < priv->host_info.rx_desc_count; | |
| 1057 | − i++) { | |
| 1058 | − | |
| 1059 | − u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; | |
| 1060 | − u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); | |
| 1061 | − u32 crc = 0xffffffff; | |
| 1062 | − | |
| 1063 | − if (status != RX_STATUS_SUCCESS) { | |
| 1064 | − if (status == 0xc1) /* determined by experiment */ | |
| 1065 | − priv->wstats.discard.nwid++; | |
| 1066 | − else | |
| 1067 | − priv->dev->stats.rx_errors++; | |
| 1068 | − goto next; | |
| 1069 | − } | |
| 1070 | − | |
| 1071 | − msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); | |
| 1072 | − rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); | |
| 1073 | − | |
| 1074 | − if (msdu_size < 30) { | |
| 1075 | − priv->dev->stats.rx_errors++; | |
| 1076 | − goto next; | |
| 1077 | − } | |
| 1078 | − | |
| 1079 | − /* Get header as far as end of seq_ctrl */ | |
| 1080 | − atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); | |
| 1081 | − frame_ctl = le16_to_cpu(header.frame_control); | |
| 1082 | − seq_control = le16_to_cpu(header.seq_ctrl); | |
| 1083 | − | |
| 1084 | − /* probe for CRC use here if needed once five packets have | |
| 1085 | − arrived with the same crc status, we assume we know what's | |
| 1086 | − happening and stop probing */ | |
| 1087 | − if (priv->probe_crc) { | |
| 1088 | − if (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED)) { | |
| 1089 | − priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); | |
| 1090 | − } else { | |
| 1091 | − priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); | |
| 1092 | − } | |
| 1093 | − if (priv->do_rx_crc) { | |
| 1094 | − if (priv->crc_ok_cnt++ > 5) | |
| 1095 | − priv->probe_crc = 0; | |
| 1096 | − } else { | |
| 1097 | − if (priv->crc_ko_cnt++ > 5) | |
| 1098 | − priv->probe_crc = 0; | |
| 1099 | − } | |
| 1100 | − } | |
| 1101 | − | |
| 1102 | − /* don't CRC header when WEP in use */ | |
| 1103 | − if (priv->do_rx_crc && (!priv->wep_is_on || !(frame_ctl & IEEE80211_FCTL_PROTECTED))) { | |
| 1104 | − crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); | |
| 1105 | − } | |
| 1106 | − msdu_size -= 24; /* header */ | |
| 1107 | − | |
| 1108 | − if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { | |
| 1109 | − int more_fragments = frame_ctl & IEEE80211_FCTL_MOREFRAGS; | |
| 1110 | − u8 packet_fragment_no = seq_control & IEEE80211_SCTL_FRAG; | |
| 1111 | − u16 packet_sequence_no = (seq_control & IEEE80211_SCTL_SEQ) >> 4; | |
| 1112 | − | |
| 1113 | − if (!more_fragments && packet_fragment_no == 0) { | |
| 1114 | − fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); | |
| 1115 | − } else { | |
| 1116 | − frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, | |
| 1117 | − packet_sequence_no, packet_fragment_no, more_fragments); | |
| 1118 | − } | |
| 1119 | − } | |
| 1120 | − | |
| 1121 | − if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { | |
| 1122 | − /* copy rest of packet into buffer */ | |
| 1123 | − atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); | |
| 1124 | − | |
| 1125 | − /* we use the same buffer for frag reassembly and control packets */ | |
| 1126 | − eth_broadcast_addr(priv->frag_source); | |
| 1127 | − | |
| 1128 | − if (priv->do_rx_crc) { | |
| 1129 | − /* last 4 octets is crc */ | |
| 1130 | − msdu_size -= 4; | |
| 1131 | − crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); | |
| 1132 | − if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { | |
| 1133 | − priv->dev->stats.rx_crc_errors++; | |
| 1134 | − goto next; | |
| 1135 | − } | |
| 1136 | − } | |
| 1137 | − | |
| 1138 | − atmel_management_frame(priv, &header, msdu_size, | |
| 1139 | − atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); | |
| 1140 | − } | |
| 1141 | − | |
| 1142 | −next: | |
| 1143 | − /* release descriptor */ | |
| 1144 | − atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); | |
| 1145 | − | |
| 1146 | − if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) | |
| 1147 | − priv->rx_desc_head++; | |
| 1148 | − else | |
| 1149 | − priv->rx_desc_head = 0; | |
| 1150 | − } | |
| 1151 | −} | |
| 1152 | − | |
| 1153 | −static irqreturn_t service_interrupt(int irq, void *dev_id) | |
| 1154 | −{ | |
| 1155 | − struct net_device *dev = (struct net_device *) dev_id; | |
| 1156 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1157 | − u8 isr; | |
| 1158 | − int i = -1; | |
| 1159 | − static const u8 irq_order[] = { | |
| 1160 | − ISR_OUT_OF_RANGE, | |
| 1161 | − ISR_RxCOMPLETE, | |
| 1162 | − ISR_TxCOMPLETE, | |
| 1163 | − ISR_RxFRAMELOST, | |
| 1164 | − ISR_FATAL_ERROR, | |
| 1165 | − ISR_COMMAND_COMPLETE, | |
| 1166 | − ISR_IBSS_MERGE, | |
| 1167 | − ISR_GENERIC_IRQ | |
| 1168 | − }; | |
| 1169 | − | |
| 1170 | − if (priv->card && priv->present_callback && | |
| 1171 | − !(*priv->present_callback)(priv->card)) | |
| 1172 | − return IRQ_HANDLED; | |
| 1173 | − | |
| 1174 | − /* In this state upper-level code assumes it can mess with | |
| 1175 | − the card unhampered by interrupts which may change register state. | |
| 1176 | − Note that even though the card shouldn't generate interrupts | |
| 1177 | − the inturrupt line may be shared. This allows card setup | |
| 1178 | − to go on without disabling interrupts for a long time. */ | |
| 1179 | − if (priv->station_state == STATION_STATE_DOWN) | |
| 1180 | − return IRQ_NONE; | |
| 1181 | − | |
| 1182 | − atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ | |
| 1183 | − | |
| 1184 | − while (1) { | |
| 1185 | − if (!atmel_lock_mac(priv)) { | |
| 1186 | − /* failed to contact card */ | |
| 1187 | − printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); | |
| 1188 | − return IRQ_HANDLED; | |
| 1189 | − } | |
| 1190 | − | |
| 1191 | − isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); | |
| 1192 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | |
| 1193 | − | |
| 1194 | − if (!isr) { | |
| 1195 | − atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ | |
| 1196 | − return i == -1 ? IRQ_NONE : IRQ_HANDLED; | |
| 1197 | − } | |
| 1198 | − | |
| 1199 | − atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ | |
| 1200 | − | |
| 1201 | − for (i = 0; i < ARRAY_SIZE(irq_order); i++) | |
| 1202 | − if (isr & irq_order[i]) | |
| 1203 | − break; | |
| 1204 | − | |
| 1205 | − if (!atmel_lock_mac(priv)) { | |
| 1206 | − /* failed to contact card */ | |
| 1207 | − printk(KERN_ALERT "%s: failed to contact MAC.\n", dev->name); | |
| 1208 | − return IRQ_HANDLED; | |
| 1209 | − } | |
| 1210 | − | |
| 1211 | − isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); | |
| 1212 | − isr ^= irq_order[i]; | |
| 1213 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); | |
| 1214 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | |
| 1215 | − | |
| 1216 | − switch (irq_order[i]) { | |
| 1217 | − | |
| 1218 | − case ISR_OUT_OF_RANGE: | |
| 1219 | − if (priv->operating_mode == IW_MODE_INFRA && | |
| 1220 | − priv->station_state == STATION_STATE_READY) { | |
| 1221 | − priv->station_is_associated = 0; | |
| 1222 | − atmel_scan(priv, 1); | |
| 1223 | − } | |
| 1224 | − break; | |
| 1225 | − | |
| 1226 | − case ISR_RxFRAMELOST: | |
| 1227 | − priv->wstats.discard.misc++; | |
| 1228 | − fallthrough; | |
| 1229 | − case ISR_RxCOMPLETE: | |
| 1230 | − rx_done_irq(priv); | |
| 1231 | − break; | |
| 1232 | − | |
| 1233 | − case ISR_TxCOMPLETE: | |
| 1234 | − tx_done_irq(priv); | |
| 1235 | − break; | |
| 1236 | − | |
| 1237 | − case ISR_FATAL_ERROR: | |
| 1238 | − printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); | |
| 1239 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 1240 | − break; | |
| 1241 | − | |
| 1242 | − case ISR_COMMAND_COMPLETE: | |
| 1243 | − atmel_command_irq(priv); | |
| 1244 | − break; | |
| 1245 | − | |
| 1246 | − case ISR_IBSS_MERGE: | |
| 1247 | − atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, | |
| 1248 | − priv->CurrentBSSID, 6); | |
| 1249 | − /* The WPA stuff cares about the current AP address */ | |
| 1250 | − if (priv->use_wpa) | |
| 1251 | − build_wpa_mib(priv); | |
| 1252 | − break; | |
| 1253 | − case ISR_GENERIC_IRQ: | |
| 1254 | − printk(KERN_INFO "%s: Generic_irq received.\n", dev->name); | |
| 1255 | − break; | |
| 1256 | − } | |
| 1257 | − } | |
| 1258 | −} | |
| 1259 | − | |
| 1260 | −static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev) | |
| 1261 | −{ | |
| 1262 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1263 | − | |
| 1264 | − /* update the link quality here in case we are seeing no beacons | |
| 1265 | − at all to drive the process */ | |
| 1266 | − atmel_smooth_qual(priv); | |
| 1267 | − | |
| 1268 | − priv->wstats.status = priv->station_state; | |
| 1269 | − | |
| 1270 | − if (priv->operating_mode == IW_MODE_INFRA) { | |
| 1271 | − if (priv->station_state != STATION_STATE_READY) { | |
| 1272 | − priv->wstats.qual.qual = 0; | |
| 1273 | − priv->wstats.qual.level = 0; | |
| 1274 | − priv->wstats.qual.updated = (IW_QUAL_QUAL_INVALID | |
| 1275 | − | IW_QUAL_LEVEL_INVALID); | |
| 1276 | − } | |
| 1277 | − priv->wstats.qual.noise = 0; | |
| 1278 | − priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID; | |
| 1279 | − } else { | |
| 1280 | − /* Quality levels cannot be determined in ad-hoc mode, | |
| 1281 | − because we can 'hear' more that one remote station. */ | |
| 1282 | − priv->wstats.qual.qual = 0; | |
| 1283 | − priv->wstats.qual.level = 0; | |
| 1284 | − priv->wstats.qual.noise = 0; | |
| 1285 | − priv->wstats.qual.updated = IW_QUAL_QUAL_INVALID | |
| 1286 | − | IW_QUAL_LEVEL_INVALID | |
| 1287 | − | IW_QUAL_NOISE_INVALID; | |
| 1288 | − priv->wstats.miss.beacon = 0; | |
| 1289 | − } | |
| 1290 | − | |
| 1291 | − return &priv->wstats; | |
| 1292 | −} | |
| 1293 | − | |
| 1294 | −static int atmel_set_mac_address(struct net_device *dev, void *p) | |
| 1295 | −{ | |
| 1296 | − struct sockaddr *addr = p; | |
| 1297 | − | |
| 1298 | − eth_hw_addr_set(dev, addr->sa_data); | |
| 1299 | − return atmel_open(dev); | |
| 1300 | −} | |
| 1301 | − | |
| 1302 | −EXPORT_SYMBOL(atmel_open); | |
| 1303 | − | |
| 1304 | −int atmel_open(struct net_device *dev) | |
| 1305 | −{ | |
| 1306 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1307 | − int i, channel, err; | |
| 1308 | − | |
| 1309 | − /* any scheduled timer is no longer needed and might screw things up.. */ | |
| 1310 | − del_timer_sync(&priv->management_timer); | |
| 1311 | − | |
| 1312 | − /* Interrupts will not touch the card once in this state... */ | |
| 1313 | − priv->station_state = STATION_STATE_DOWN; | |
| 1314 | − | |
| 1315 | − if (priv->new_SSID_size) { | |
| 1316 | − memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); | |
| 1317 | − priv->SSID_size = priv->new_SSID_size; | |
| 1318 | − priv->new_SSID_size = 0; | |
| 1319 | − } | |
| 1320 | − priv->BSS_list_entries = 0; | |
| 1321 | − | |
| 1322 | − priv->AuthenticationRequestRetryCnt = 0; | |
| 1323 | − priv->AssociationRequestRetryCnt = 0; | |
| 1324 | − priv->ReAssociationRequestRetryCnt = 0; | |
| 1325 | − priv->CurrentAuthentTransactionSeqNum = 0x0001; | |
| 1326 | − priv->ExpectedAuthentTransactionSeqNum = 0x0002; | |
| 1327 | − | |
| 1328 | − priv->site_survey_state = SITE_SURVEY_IDLE; | |
| 1329 | − priv->station_is_associated = 0; | |
| 1330 | − | |
| 1331 | − err = reset_atmel_card(dev); | |
| 1332 | − if (err) | |
| 1333 | − return err; | |
| 1334 | − | |
| 1335 | − if (priv->config_reg_domain) { | |
| 1336 | − priv->reg_domain = priv->config_reg_domain; | |
| 1337 | − atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS, priv->reg_domain); | |
| 1338 | − } else { | |
| 1339 | − priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); | |
| 1340 | − for (i = 0; i < ARRAY_SIZE(channel_table); i++) | |
| 1341 | − if (priv->reg_domain == channel_table[i].reg_domain) | |
| 1342 | − break; | |
| 1343 | − if (i == ARRAY_SIZE(channel_table)) { | |
| 1344 | − priv->reg_domain = REG_DOMAIN_MKK1; | |
| 1345 | − printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); | |
| 1346 | − } | |
| 1347 | − } | |
| 1348 | − | |
| 1349 | − if ((channel = atmel_validate_channel(priv, priv->channel))) | |
| 1350 | − priv->channel = channel; | |
| 1351 | − | |
| 1352 | − /* this moves station_state on.... */ | |
| 1353 | − atmel_scan(priv, 1); | |
| 1354 | − | |
| 1355 | − atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ | |
| 1356 | − return 0; | |
| 1357 | −} | |
| 1358 | − | |
| 1359 | −static int atmel_close(struct net_device *dev) | |
| 1360 | −{ | |
| 1361 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1362 | − | |
| 1363 | − /* Send event to userspace that we are disassociating */ | |
| 1364 | − if (priv->station_state == STATION_STATE_READY) { | |
| 1365 | − union iwreq_data wrqu; | |
| 1366 | − | |
| 1367 | − wrqu.data.length = 0; | |
| 1368 | − wrqu.data.flags = 0; | |
| 1369 | − wrqu.ap_addr.sa_family = ARPHRD_ETHER; | |
| 1370 | − eth_zero_addr(wrqu.ap_addr.sa_data); | |
| 1371 | − wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | |
| 1372 | − } | |
| 1373 | − | |
| 1374 | − atmel_enter_state(priv, STATION_STATE_DOWN); | |
| 1375 | − | |
| 1376 | − if (priv->bus_type == BUS_TYPE_PCCARD) | |
| 1377 | − atmel_write16(dev, GCR, 0x0060); | |
| 1378 | − atmel_write16(dev, GCR, 0x0040); | |
| 1379 | − return 0; | |
| 1380 | −} | |
| 1381 | − | |
| 1382 | −static int atmel_validate_channel(struct atmel_private *priv, int channel) | |
| 1383 | −{ | |
| 1384 | − /* check that channel is OK, if so return zero, | |
| 1385 | − else return suitable default channel */ | |
| 1386 | − int i; | |
| 1387 | − | |
| 1388 | − for (i = 0; i < ARRAY_SIZE(channel_table); i++) | |
| 1389 | − if (priv->reg_domain == channel_table[i].reg_domain) { | |
| 1390 | − if (channel >= channel_table[i].min && | |
| 1391 | − channel <= channel_table[i].max) | |
| 1392 | − return 0; | |
| 1393 | − else | |
| 1394 | − return channel_table[i].min; | |
| 1395 | − } | |
| 1396 | − return 0; | |
| 1397 | −} | |
| 1398 | − | |
| 1399 | −#ifdef CONFIG_PROC_FS | |
| 1400 | −static int atmel_proc_show(struct seq_file *m, void *v) | |
| 1401 | −{ | |
| 1402 | − struct atmel_private *priv = m->private; | |
| 1403 | − int i; | |
| 1404 | − char *s, *r, *c; | |
| 1405 | − | |
| 1406 | − seq_printf(m, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); | |
| 1407 | − | |
| 1408 | − if (priv->station_state != STATION_STATE_DOWN) { | |
| 1409 | − seq_printf(m, | |
| 1410 | − "Firmware version:\t%d.%d build %d\n" | |
| 1411 | − "Firmware location:\t", | |
| 1412 | − priv->host_info.major_version, | |
| 1413 | − priv->host_info.minor_version, | |
| 1414 | − priv->host_info.build_version); | |
| 1415 | − | |
| 1416 | − if (priv->card_type != CARD_TYPE_EEPROM) | |
| 1417 | − seq_puts(m, "on card\n"); | |
| 1418 | − else if (priv->firmware) | |
| 1419 | − seq_printf(m, "%s loaded by host\n", priv->firmware_id); | |
| 1420 | − else | |
| 1421 | − seq_printf(m, "%s loaded by hotplug\n", priv->firmware_id); | |
| 1422 | − | |
| 1423 | − switch (priv->card_type) { | |
| 1424 | − case CARD_TYPE_PARALLEL_FLASH: | |
| 1425 | − c = "Parallel flash"; | |
| 1426 | − break; | |
| 1427 | − case CARD_TYPE_SPI_FLASH: | |
| 1428 | − c = "SPI flash\n"; | |
| 1429 | − break; | |
| 1430 | − case CARD_TYPE_EEPROM: | |
| 1431 | − c = "EEPROM"; | |
| 1432 | − break; | |
| 1433 | − default: | |
| 1434 | − c = "<unknown>"; | |
| 1435 | − } | |
| 1436 | − | |
| 1437 | − r = "<unknown>"; | |
| 1438 | − for (i = 0; i < ARRAY_SIZE(channel_table); i++) | |
| 1439 | − if (priv->reg_domain == channel_table[i].reg_domain) | |
| 1440 | − r = channel_table[i].name; | |
| 1441 | − | |
| 1442 | − seq_printf(m, "MAC memory type:\t%s\n", c); | |
| 1443 | − seq_printf(m, "Regulatory domain:\t%s\n", r); | |
| 1444 | − seq_printf(m, "Host CRC checking:\t%s\n", | |
| 1445 | − priv->do_rx_crc ? "On" : "Off"); | |
| 1446 | − seq_printf(m, "WPA-capable firmware:\t%s\n", | |
| 1447 | − priv->use_wpa ? "Yes" : "No"); | |
| 1448 | − } | |
| 1449 | − | |
| 1450 | − switch (priv->station_state) { | |
| 1451 | − case STATION_STATE_SCANNING: | |
| 1452 | − s = "Scanning"; | |
| 1453 | − break; | |
| 1454 | − case STATION_STATE_JOINNING: | |
| 1455 | − s = "Joining"; | |
| 1456 | − break; | |
| 1457 | − case STATION_STATE_AUTHENTICATING: | |
| 1458 | − s = "Authenticating"; | |
| 1459 | − break; | |
| 1460 | − case STATION_STATE_ASSOCIATING: | |
| 1461 | − s = "Associating"; | |
| 1462 | − break; | |
| 1463 | − case STATION_STATE_READY: | |
| 1464 | − s = "Ready"; | |
| 1465 | − break; | |
| 1466 | − case STATION_STATE_REASSOCIATING: | |
| 1467 | − s = "Reassociating"; | |
| 1468 | − break; | |
| 1469 | − case STATION_STATE_MGMT_ERROR: | |
| 1470 | − s = "Management error"; | |
| 1471 | − break; | |
| 1472 | − case STATION_STATE_DOWN: | |
| 1473 | − s = "Down"; | |
| 1474 | − break; | |
| 1475 | − default: | |
| 1476 | − s = "<unknown>"; | |
| 1477 | − } | |
| 1478 | − | |
| 1479 | − seq_printf(m, "Current state:\t\t%s\n", s); | |
| 1480 | − return 0; | |
| 1481 | −} | |
| 1482 | −#endif | |
| 1483 | − | |
| 1484 | −static const struct net_device_ops atmel_netdev_ops = { | |
| 1485 | − .ndo_open = atmel_open, | |
| 1486 | − .ndo_stop = atmel_close, | |
| 1487 | − .ndo_set_mac_address = atmel_set_mac_address, | |
| 1488 | − .ndo_start_xmit = start_tx, | |
| 1489 | − .ndo_validate_addr = eth_validate_addr, | |
| 1490 | −}; | |
| 1491 | − | |
| 1492 | −struct net_device *init_atmel_card(unsigned short irq, unsigned long port, | |
| 1493 | − const AtmelFWType fw_type, | |
| 1494 | − struct device *sys_dev, | |
| 1495 | − int (*card_present)(void *), void *card) | |
| 1496 | −{ | |
| 1497 | − struct net_device *dev; | |
| 1498 | − struct atmel_private *priv; | |
| 1499 | − int rc; | |
| 1500 | − | |
| 1501 | − /* Create the network device object. */ | |
| 1502 | − dev = alloc_etherdev(sizeof(*priv)); | |
| 1503 | − if (!dev) | |
| 1504 | − return NULL; | |
| 1505 | − | |
| 1506 | − if (dev_alloc_name(dev, dev->name) < 0) { | |
| 1507 | − printk(KERN_ERR "atmel: Couldn't get name!\n"); | |
| 1508 | − goto err_out_free; | |
| 1509 | − } | |
| 1510 | − | |
| 1511 | − priv = netdev_priv(dev); | |
| 1512 | − priv->dev = dev; | |
| 1513 | − priv->sys_dev = sys_dev; | |
| 1514 | − priv->present_callback = card_present; | |
| 1515 | − priv->card = card; | |
| 1516 | − priv->firmware = NULL; | |
| 1517 | − priv->firmware_type = fw_type; | |
| 1518 | − if (firmware) /* module parameter */ | |
| 1519 | − strscpy(priv->firmware_id, firmware, sizeof(priv->firmware_id)); | |
| 1520 | − priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; | |
| 1521 | − priv->station_state = STATION_STATE_DOWN; | |
| 1522 | − priv->do_rx_crc = 0; | |
| 1523 | − /* For PCMCIA cards, some chips need CRC, some don't | |
| 1524 | − so we have to probe. */ | |
| 1525 | − if (priv->bus_type == BUS_TYPE_PCCARD) { | |
| 1526 | − priv->probe_crc = 1; | |
| 1527 | − priv->crc_ok_cnt = priv->crc_ko_cnt = 0; | |
| 1528 | − } else | |
| 1529 | − priv->probe_crc = 0; | |
| 1530 | − priv->last_qual = jiffies; | |
| 1531 | − priv->last_beacon_timestamp = 0; | |
| 1532 | − memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); | |
| 1533 | − eth_zero_addr(priv->BSSID); | |
| 1534 | − priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ | |
| 1535 | − priv->station_was_associated = 0; | |
| 1536 | − | |
| 1537 | − priv->last_survey = jiffies; | |
| 1538 | − priv->preamble = LONG_PREAMBLE; | |
| 1539 | − priv->operating_mode = IW_MODE_INFRA; | |
| 1540 | − priv->connect_to_any_BSS = 0; | |
| 1541 | − priv->config_reg_domain = 0; | |
| 1542 | − priv->reg_domain = 0; | |
| 1543 | − priv->tx_rate = 3; | |
| 1544 | − priv->auto_tx_rate = 1; | |
| 1545 | − priv->channel = 4; | |
| 1546 | − priv->power_mode = 0; | |
| 1547 | − priv->SSID[0] = '\0'; | |
| 1548 | − priv->SSID_size = 0; | |
| 1549 | − priv->new_SSID_size = 0; | |
| 1550 | − priv->frag_threshold = 2346; | |
| 1551 | − priv->rts_threshold = 2347; | |
| 1552 | − priv->short_retry = 7; | |
| 1553 | − priv->long_retry = 4; | |
| 1554 | − | |
| 1555 | − priv->wep_is_on = 0; | |
| 1556 | − priv->default_key = 0; | |
| 1557 | − priv->encryption_level = 0; | |
| 1558 | − priv->exclude_unencrypted = 0; | |
| 1559 | − priv->group_cipher_suite = priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | |
| 1560 | − priv->use_wpa = 0; | |
| 1561 | − memset(priv->wep_keys, 0, sizeof(priv->wep_keys)); | |
| 1562 | − memset(priv->wep_key_len, 0, sizeof(priv->wep_key_len)); | |
| 1563 | − | |
| 1564 | − priv->default_beacon_period = priv->beacon_period = 100; | |
| 1565 | − priv->listen_interval = 1; | |
| 1566 | − | |
| 1567 | − timer_setup(&priv->management_timer, atmel_management_timer, 0); | |
| 1568 | − spin_lock_init(&priv->irqlock); | |
| 1569 | − spin_lock_init(&priv->timerlock); | |
| 1570 | − | |
| 1571 | − dev->netdev_ops = &atmel_netdev_ops; | |
| 1572 | − dev->wireless_handlers = &atmel_handler_def; | |
| 1573 | − dev->irq = irq; | |
| 1574 | − dev->base_addr = port; | |
| 1575 | − | |
| 1576 | − /* MTU range: 68 - 2312 */ | |
| 1577 | − dev->min_mtu = 68; | |
| 1578 | − dev->max_mtu = MAX_WIRELESS_BODY - ETH_FCS_LEN; | |
| 1579 | − | |
| 1580 | − SET_NETDEV_DEV(dev, sys_dev); | |
| 1581 | − | |
| 1582 | − if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) { | |
| 1583 | − printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc); | |
| 1584 | − goto err_out_free; | |
| 1585 | − } | |
| 1586 | − | |
| 1587 | − if (!request_region(dev->base_addr, 32, | |
| 1588 | − priv->bus_type == BUS_TYPE_PCCARD ? "atmel_cs" : "atmel_pci")) { | |
| 1589 | − goto err_out_irq; | |
| 1590 | − } | |
| 1591 | − | |
| 1592 | − if (register_netdev(dev)) | |
| 1593 | − goto err_out_res; | |
| 1594 | − | |
| 1595 | − if (!probe_atmel_card(dev)) { | |
| 1596 | − unregister_netdev(dev); | |
| 1597 | − goto err_out_res; | |
| 1598 | − } | |
| 1599 | − | |
| 1600 | − netif_carrier_off(dev); | |
| 1601 | − | |
| 1602 | − if (!proc_create_single_data("driver/atmel", 0, NULL, atmel_proc_show, | |
| 1603 | − priv)) | |
| 1604 | − printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); | |
| 1605 | − | |
| 1606 | − printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", | |
| 1607 | − dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); | |
| 1608 | − | |
| 1609 | − return dev; | |
| 1610 | − | |
| 1611 | −err_out_res: | |
| 1612 | − release_region(dev->base_addr, 32); | |
| 1613 | −err_out_irq: | |
| 1614 | − free_irq(dev->irq, dev); | |
| 1615 | −err_out_free: | |
| 1616 | − free_netdev(dev); | |
| 1617 | − return NULL; | |
| 1618 | −} | |
| 1619 | − | |
| 1620 | −EXPORT_SYMBOL(init_atmel_card); | |
| 1621 | − | |
| 1622 | −void stop_atmel_card(struct net_device *dev) | |
| 1623 | −{ | |
| 1624 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1625 | − | |
| 1626 | − /* put a brick on it... */ | |
| 1627 | − if (priv->bus_type == BUS_TYPE_PCCARD) | |
| 1628 | − atmel_write16(dev, GCR, 0x0060); | |
| 1629 | − atmel_write16(dev, GCR, 0x0040); | |
| 1630 | − | |
| 1631 | − del_timer_sync(&priv->management_timer); | |
| 1632 | − unregister_netdev(dev); | |
| 1633 | − remove_proc_entry("driver/atmel", NULL); | |
| 1634 | − free_irq(dev->irq, dev); | |
| 1635 | − kfree(priv->firmware); | |
| 1636 | − release_region(dev->base_addr, 32); | |
| 1637 | − free_netdev(dev); | |
| 1638 | −} | |
| 1639 | − | |
| 1640 | −EXPORT_SYMBOL(stop_atmel_card); | |
| 1641 | − | |
| 1642 | −static int atmel_set_essid(struct net_device *dev, | |
| 1643 | − struct iw_request_info *info, | |
| 1644 | − union iwreq_data *wrqu, | |
| 1645 | − char *extra) | |
| 1646 | −{ | |
| 1647 | − struct iw_point *dwrq = &wrqu->essid; | |
| 1648 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1649 | − | |
| 1650 | − /* Check if we asked for `any' */ | |
| 1651 | − if (dwrq->flags == 0) { | |
| 1652 | − priv->connect_to_any_BSS = 1; | |
| 1653 | − } else { | |
| 1654 | − int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | |
| 1655 | − | |
| 1656 | − priv->connect_to_any_BSS = 0; | |
| 1657 | − | |
| 1658 | − /* Check the size of the string */ | |
| 1659 | − if (dwrq->length > MAX_SSID_LENGTH) | |
| 1660 | − return -E2BIG; | |
| 1661 | − if (index != 0) | |
| 1662 | − return -EINVAL; | |
| 1663 | − | |
| 1664 | − memcpy(priv->new_SSID, extra, dwrq->length); | |
| 1665 | − priv->new_SSID_size = dwrq->length; | |
| 1666 | − } | |
| 1667 | − | |
| 1668 | − return -EINPROGRESS; | |
| 1669 | −} | |
| 1670 | − | |
| 1671 | −static int atmel_get_essid(struct net_device *dev, | |
| 1672 | − struct iw_request_info *info, | |
| 1673 | − union iwreq_data *wrqu, | |
| 1674 | − char *extra) | |
| 1675 | −{ | |
| 1676 | − struct iw_point *dwrq = &wrqu->essid; | |
| 1677 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1678 | − | |
| 1679 | − /* Get the current SSID */ | |
| 1680 | − if (priv->new_SSID_size != 0) { | |
| 1681 | − memcpy(extra, priv->new_SSID, priv->new_SSID_size); | |
| 1682 | − dwrq->length = priv->new_SSID_size; | |
| 1683 | − } else { | |
| 1684 | − memcpy(extra, priv->SSID, priv->SSID_size); | |
| 1685 | − dwrq->length = priv->SSID_size; | |
| 1686 | − } | |
| 1687 | − | |
| 1688 | − dwrq->flags = !priv->connect_to_any_BSS; /* active */ | |
| 1689 | − | |
| 1690 | − return 0; | |
| 1691 | −} | |
| 1692 | − | |
| 1693 | −static int atmel_get_wap(struct net_device *dev, | |
| 1694 | − struct iw_request_info *info, | |
| 1695 | − union iwreq_data *wrqu, | |
| 1696 | − char *extra) | |
| 1697 | −{ | |
| 1698 | − struct sockaddr *awrq = &wrqu->ap_addr; | |
| 1699 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1700 | − memcpy(awrq->sa_data, priv->CurrentBSSID, ETH_ALEN); | |
| 1701 | − awrq->sa_family = ARPHRD_ETHER; | |
| 1702 | − | |
| 1703 | − return 0; | |
| 1704 | −} | |
| 1705 | − | |
| 1706 | −static int atmel_set_encode(struct net_device *dev, | |
| 1707 | − struct iw_request_info *info, | |
| 1708 | − union iwreq_data *wrqu, | |
| 1709 | − char *extra) | |
| 1710 | −{ | |
| 1711 | − struct iw_point *dwrq = &wrqu->encoding; | |
| 1712 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1713 | − | |
| 1714 | − /* Basic checking: do we have a key to set ? | |
| 1715 | − * Note : with the new API, it's impossible to get a NULL pointer. | |
| 1716 | − * Therefore, we need to check a key size == 0 instead. | |
| 1717 | − * New version of iwconfig properly set the IW_ENCODE_NOKEY flag | |
| 1718 | − * when no key is present (only change flags), but older versions | |
| 1719 | − * don't do it. - Jean II */ | |
| 1720 | − if (dwrq->length > 0) { | |
| 1721 | − int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | |
| 1722 | − int current_index = priv->default_key; | |
| 1723 | − /* Check the size of the key */ | |
| 1724 | − if (dwrq->length > 13) { | |
| 1725 | − return -EINVAL; | |
| 1726 | − } | |
| 1727 | − /* Check the index (none -> use current) */ | |
| 1728 | − if (index < 0 || index >= 4) | |
| 1729 | − index = current_index; | |
| 1730 | − else | |
| 1731 | − priv->default_key = index; | |
| 1732 | − /* Set the length */ | |
| 1733 | − if (dwrq->length > 5) | |
| 1734 | − priv->wep_key_len[index] = 13; | |
| 1735 | − else | |
| 1736 | − if (dwrq->length > 0) | |
| 1737 | − priv->wep_key_len[index] = 5; | |
| 1738 | − else | |
| 1739 | − /* Disable the key */ | |
| 1740 | − priv->wep_key_len[index] = 0; | |
| 1741 | − /* Check if the key is not marked as invalid */ | |
| 1742 | − if (!(dwrq->flags & IW_ENCODE_NOKEY)) { | |
| 1743 | − /* Cleanup */ | |
| 1744 | − memset(priv->wep_keys[index], 0, 13); | |
| 1745 | − /* Copy the key in the driver */ | |
| 1746 | − memcpy(priv->wep_keys[index], extra, dwrq->length); | |
| 1747 | − } | |
| 1748 | − /* WE specify that if a valid key is set, encryption | |
| 1749 | − * should be enabled (user may turn it off later) | |
| 1750 | − * This is also how "iwconfig ethX key on" works */ | |
| 1751 | − if (index == current_index && | |
| 1752 | − priv->wep_key_len[index] > 0) { | |
| 1753 | − priv->wep_is_on = 1; | |
| 1754 | − priv->exclude_unencrypted = 1; | |
| 1755 | − if (priv->wep_key_len[index] > 5) { | |
| 1756 | − priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | |
| 1757 | − priv->encryption_level = 2; | |
| 1758 | − } else { | |
| 1759 | − priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | |
| 1760 | − priv->encryption_level = 1; | |
| 1761 | − } | |
| 1762 | − } | |
| 1763 | − } else { | |
| 1764 | − /* Do we want to just set the transmit key index ? */ | |
| 1765 | − int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | |
| 1766 | − if (index >= 0 && index < 4) { | |
| 1767 | − priv->default_key = index; | |
| 1768 | − } else | |
| 1769 | − /* Don't complain if only change the mode */ | |
| 1770 | − if (!(dwrq->flags & IW_ENCODE_MODE)) | |
| 1771 | − return -EINVAL; | |
| 1772 | − } | |
| 1773 | − /* Read the flags */ | |
| 1774 | − if (dwrq->flags & IW_ENCODE_DISABLED) { | |
| 1775 | − priv->wep_is_on = 0; | |
| 1776 | − priv->encryption_level = 0; | |
| 1777 | − priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | |
| 1778 | − } else { | |
| 1779 | − priv->wep_is_on = 1; | |
| 1780 | − if (priv->wep_key_len[priv->default_key] > 5) { | |
| 1781 | − priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | |
| 1782 | − priv->encryption_level = 2; | |
| 1783 | − } else { | |
| 1784 | − priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | |
| 1785 | − priv->encryption_level = 1; | |
| 1786 | − } | |
| 1787 | − } | |
| 1788 | − if (dwrq->flags & IW_ENCODE_RESTRICTED) | |
| 1789 | − priv->exclude_unencrypted = 1; | |
| 1790 | − if (dwrq->flags & IW_ENCODE_OPEN) | |
| 1791 | − priv->exclude_unencrypted = 0; | |
| 1792 | − | |
| 1793 | − return -EINPROGRESS; /* Call commit handler */ | |
| 1794 | −} | |
| 1795 | − | |
| 1796 | −static int atmel_get_encode(struct net_device *dev, | |
| 1797 | − struct iw_request_info *info, | |
| 1798 | − union iwreq_data *wrqu, | |
| 1799 | − char *extra) | |
| 1800 | −{ | |
| 1801 | − struct iw_point *dwrq = &wrqu->encoding; | |
| 1802 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1803 | − int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | |
| 1804 | − | |
| 1805 | − if (!priv->wep_is_on) | |
| 1806 | − dwrq->flags = IW_ENCODE_DISABLED; | |
| 1807 | − else { | |
| 1808 | − if (priv->exclude_unencrypted) | |
| 1809 | − dwrq->flags = IW_ENCODE_RESTRICTED; | |
| 1810 | − else | |
| 1811 | − dwrq->flags = IW_ENCODE_OPEN; | |
| 1812 | − } | |
| 1813 | − /* Which key do we want ? -1 -> tx index */ | |
| 1814 | − if (index < 0 || index >= 4) | |
| 1815 | − index = priv->default_key; | |
| 1816 | − dwrq->flags |= index + 1; | |
| 1817 | − /* Copy the key to the user buffer */ | |
| 1818 | − dwrq->length = priv->wep_key_len[index]; | |
| 1819 | − if (dwrq->length > 16) { | |
| 1820 | − dwrq->length = 0; | |
| 1821 | − } else { | |
| 1822 | − memset(extra, 0, 16); | |
| 1823 | − memcpy(extra, priv->wep_keys[index], dwrq->length); | |
| 1824 | − } | |
| 1825 | − | |
| 1826 | − return 0; | |
| 1827 | −} | |
| 1828 | − | |
| 1829 | −static int atmel_set_encodeext(struct net_device *dev, | |
| 1830 | − struct iw_request_info *info, | |
| 1831 | − union iwreq_data *wrqu, | |
| 1832 | − char *extra) | |
| 1833 | −{ | |
| 1834 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1835 | − struct iw_point *encoding = &wrqu->encoding; | |
| 1836 | − struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | |
| 1837 | − int idx, key_len, alg = ext->alg, set_key = 1; | |
| 1838 | − | |
| 1839 | − /* Determine and validate the key index */ | |
| 1840 | − idx = encoding->flags & IW_ENCODE_INDEX; | |
| 1841 | − if (idx) { | |
| 1842 | − if (idx < 1 || idx > 4) | |
| 1843 | − return -EINVAL; | |
| 1844 | − idx--; | |
| 1845 | − } else | |
| 1846 | − idx = priv->default_key; | |
| 1847 | − | |
| 1848 | − if (encoding->flags & IW_ENCODE_DISABLED) | |
| 1849 | − alg = IW_ENCODE_ALG_NONE; | |
| 1850 | − | |
| 1851 | − if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | |
| 1852 | − priv->default_key = idx; | |
| 1853 | − set_key = ext->key_len > 0 ? 1 : 0; | |
| 1854 | − } | |
| 1855 | − | |
| 1856 | − if (set_key) { | |
| 1857 | − /* Set the requested key first */ | |
| 1858 | − switch (alg) { | |
| 1859 | − case IW_ENCODE_ALG_NONE: | |
| 1860 | − priv->wep_is_on = 0; | |
| 1861 | − priv->encryption_level = 0; | |
| 1862 | − priv->pairwise_cipher_suite = CIPHER_SUITE_NONE; | |
| 1863 | − break; | |
| 1864 | − case IW_ENCODE_ALG_WEP: | |
| 1865 | − if (ext->key_len > 5) { | |
| 1866 | − priv->wep_key_len[idx] = 13; | |
| 1867 | − priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_128; | |
| 1868 | − priv->encryption_level = 2; | |
| 1869 | − } else if (ext->key_len > 0) { | |
| 1870 | − priv->wep_key_len[idx] = 5; | |
| 1871 | − priv->pairwise_cipher_suite = CIPHER_SUITE_WEP_64; | |
| 1872 | − priv->encryption_level = 1; | |
| 1873 | − } else { | |
| 1874 | − return -EINVAL; | |
| 1875 | − } | |
| 1876 | − priv->wep_is_on = 1; | |
| 1877 | − memset(priv->wep_keys[idx], 0, 13); | |
| 1878 | − key_len = min ((int)ext->key_len, priv->wep_key_len[idx]); | |
| 1879 | − memcpy(priv->wep_keys[idx], ext->key, key_len); | |
| 1880 | − break; | |
| 1881 | − default: | |
| 1882 | − return -EINVAL; | |
| 1883 | − } | |
| 1884 | − } | |
| 1885 | − | |
| 1886 | − return -EINPROGRESS; | |
| 1887 | −} | |
| 1888 | − | |
| 1889 | −static int atmel_get_encodeext(struct net_device *dev, | |
| 1890 | − struct iw_request_info *info, | |
| 1891 | − union iwreq_data *wrqu, | |
| 1892 | − char *extra) | |
| 1893 | −{ | |
| 1894 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1895 | − struct iw_point *encoding = &wrqu->encoding; | |
| 1896 | − struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | |
| 1897 | − int idx, max_key_len; | |
| 1898 | − | |
| 1899 | − max_key_len = encoding->length - sizeof(*ext); | |
| 1900 | − if (max_key_len < 0) | |
| 1901 | − return -EINVAL; | |
| 1902 | − | |
| 1903 | − idx = encoding->flags & IW_ENCODE_INDEX; | |
| 1904 | − if (idx) { | |
| 1905 | − if (idx < 1 || idx > 4) | |
| 1906 | − return -EINVAL; | |
| 1907 | − idx--; | |
| 1908 | − } else | |
| 1909 | − idx = priv->default_key; | |
| 1910 | − | |
| 1911 | − encoding->flags = idx + 1; | |
| 1912 | − memset(ext, 0, sizeof(*ext)); | |
| 1913 | − | |
| 1914 | − if (!priv->wep_is_on) { | |
| 1915 | − ext->alg = IW_ENCODE_ALG_NONE; | |
| 1916 | − ext->key_len = 0; | |
| 1917 | − encoding->flags |= IW_ENCODE_DISABLED; | |
| 1918 | − } else { | |
| 1919 | − if (priv->encryption_level > 0) | |
| 1920 | − ext->alg = IW_ENCODE_ALG_WEP; | |
| 1921 | − else | |
| 1922 | − return -EINVAL; | |
| 1923 | − | |
| 1924 | − ext->key_len = priv->wep_key_len[idx]; | |
| 1925 | − memcpy(ext->key, priv->wep_keys[idx], ext->key_len); | |
| 1926 | − encoding->flags |= IW_ENCODE_ENABLED; | |
| 1927 | − } | |
| 1928 | − | |
| 1929 | − return 0; | |
| 1930 | −} | |
| 1931 | − | |
| 1932 | −static int atmel_set_auth(struct net_device *dev, | |
| 1933 | − struct iw_request_info *info, | |
| 1934 | − union iwreq_data *wrqu, char *extra) | |
| 1935 | −{ | |
| 1936 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1937 | − struct iw_param *param = &wrqu->param; | |
| 1938 | − | |
| 1939 | − switch (param->flags & IW_AUTH_INDEX) { | |
| 1940 | − case IW_AUTH_WPA_VERSION: | |
| 1941 | − case IW_AUTH_CIPHER_PAIRWISE: | |
| 1942 | − case IW_AUTH_CIPHER_GROUP: | |
| 1943 | − case IW_AUTH_KEY_MGMT: | |
| 1944 | − case IW_AUTH_RX_UNENCRYPTED_EAPOL: | |
| 1945 | − case IW_AUTH_PRIVACY_INVOKED: | |
| 1946 | − /* | |
| 1947 | − * atmel does not use these parameters | |
| 1948 | − */ | |
| 1949 | − break; | |
| 1950 | − | |
| 1951 | − case IW_AUTH_DROP_UNENCRYPTED: | |
| 1952 | − priv->exclude_unencrypted = param->value ? 1 : 0; | |
| 1953 | − break; | |
| 1954 | − | |
| 1955 | − case IW_AUTH_80211_AUTH_ALG: { | |
| 1956 | − if (param->value & IW_AUTH_ALG_SHARED_KEY) { | |
| 1957 | − priv->exclude_unencrypted = 1; | |
| 1958 | − } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { | |
| 1959 | − priv->exclude_unencrypted = 0; | |
| 1960 | − } else | |
| 1961 | − return -EINVAL; | |
| 1962 | − break; | |
| 1963 | − } | |
| 1964 | − | |
| 1965 | − case IW_AUTH_WPA_ENABLED: | |
| 1966 | − /* Silently accept disable of WPA */ | |
| 1967 | − if (param->value > 0) | |
| 1968 | − return -EOPNOTSUPP; | |
| 1969 | − break; | |
| 1970 | − | |
| 1971 | − default: | |
| 1972 | − return -EOPNOTSUPP; | |
| 1973 | − } | |
| 1974 | − return -EINPROGRESS; | |
| 1975 | −} | |
| 1976 | − | |
| 1977 | −static int atmel_get_auth(struct net_device *dev, | |
| 1978 | − struct iw_request_info *info, | |
| 1979 | − union iwreq_data *wrqu, char *extra) | |
| 1980 | −{ | |
| 1981 | − struct atmel_private *priv = netdev_priv(dev); | |
| 1982 | − struct iw_param *param = &wrqu->param; | |
| 1983 | − | |
| 1984 | − switch (param->flags & IW_AUTH_INDEX) { | |
| 1985 | − case IW_AUTH_DROP_UNENCRYPTED: | |
| 1986 | − param->value = priv->exclude_unencrypted; | |
| 1987 | − break; | |
| 1988 | − | |
| 1989 | − case IW_AUTH_80211_AUTH_ALG: | |
| 1990 | − if (priv->exclude_unencrypted == 1) | |
| 1991 | − param->value = IW_AUTH_ALG_SHARED_KEY; | |
| 1992 | − else | |
| 1993 | − param->value = IW_AUTH_ALG_OPEN_SYSTEM; | |
| 1994 | − break; | |
| 1995 | − | |
| 1996 | − case IW_AUTH_WPA_ENABLED: | |
| 1997 | − param->value = 0; | |
| 1998 | − break; | |
| 1999 | − | |
| 2000 | − default: | |
| 2001 | − return -EOPNOTSUPP; | |
| 2002 | − } | |
| 2003 | − return 0; | |
| 2004 | −} | |
| 2005 | − | |
| 2006 | − | |
| 2007 | −static int atmel_get_name(struct net_device *dev, | |
| 2008 | − struct iw_request_info *info, | |
| 2009 | − union iwreq_data *wrqu, | |
| 2010 | − char *extra) | |
| 2011 | −{ | |
| 2012 | − strcpy(wrqu->name, "IEEE 802.11-DS"); | |
| 2013 | − return 0; | |
| 2014 | −} | |
| 2015 | − | |
| 2016 | −static int atmel_set_rate(struct net_device *dev, | |
| 2017 | − struct iw_request_info *info, | |
| 2018 | − union iwreq_data *wrqu, | |
| 2019 | − char *extra) | |
| 2020 | −{ | |
| 2021 | − struct iw_param *vwrq = &wrqu->bitrate; | |
| 2022 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2023 | − | |
| 2024 | − if (vwrq->fixed == 0) { | |
| 2025 | − priv->tx_rate = 3; | |
| 2026 | − priv->auto_tx_rate = 1; | |
| 2027 | − } else { | |
| 2028 | − priv->auto_tx_rate = 0; | |
| 2029 | − | |
| 2030 | − /* Which type of value ? */ | |
| 2031 | − if ((vwrq->value < 4) && (vwrq->value >= 0)) { | |
| 2032 | − /* Setting by rate index */ | |
| 2033 | − priv->tx_rate = vwrq->value; | |
| 2034 | − } else { | |
| 2035 | − /* Setting by frequency value */ | |
| 2036 | − switch (vwrq->value) { | |
| 2037 | − case 1000000: | |
| 2038 | − priv->tx_rate = 0; | |
| 2039 | − break; | |
| 2040 | − case 2000000: | |
| 2041 | − priv->tx_rate = 1; | |
| 2042 | − break; | |
| 2043 | − case 5500000: | |
| 2044 | − priv->tx_rate = 2; | |
| 2045 | − break; | |
| 2046 | − case 11000000: | |
| 2047 | − priv->tx_rate = 3; | |
| 2048 | − break; | |
| 2049 | − default: | |
| 2050 | − return -EINVAL; | |
| 2051 | − } | |
| 2052 | − } | |
| 2053 | − } | |
| 2054 | − | |
| 2055 | − return -EINPROGRESS; | |
| 2056 | −} | |
| 2057 | − | |
| 2058 | −static int atmel_set_mode(struct net_device *dev, | |
| 2059 | − struct iw_request_info *info, | |
| 2060 | − union iwreq_data *wrqu, | |
| 2061 | − char *extra) | |
| 2062 | −{ | |
| 2063 | − __u32 *uwrq = &wrqu->mode; | |
| 2064 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2065 | − | |
| 2066 | − if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) | |
| 2067 | − return -EINVAL; | |
| 2068 | − | |
| 2069 | − priv->operating_mode = *uwrq; | |
| 2070 | − return -EINPROGRESS; | |
| 2071 | −} | |
| 2072 | − | |
| 2073 | −static int atmel_get_mode(struct net_device *dev, | |
| 2074 | − struct iw_request_info *info, | |
| 2075 | − union iwreq_data *wrqu, | |
| 2076 | − char *extra) | |
| 2077 | −{ | |
| 2078 | − __u32 *uwrq = &wrqu->mode; | |
| 2079 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2080 | − | |
| 2081 | − *uwrq = priv->operating_mode; | |
| 2082 | − return 0; | |
| 2083 | −} | |
| 2084 | − | |
| 2085 | −static int atmel_get_rate(struct net_device *dev, | |
| 2086 | − struct iw_request_info *info, | |
| 2087 | − union iwreq_data *wrqu, | |
| 2088 | − char *extra) | |
| 2089 | −{ | |
| 2090 | − struct iw_param *vwrq = &wrqu->bitrate; | |
| 2091 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2092 | − | |
| 2093 | − if (priv->auto_tx_rate) { | |
| 2094 | − vwrq->fixed = 0; | |
| 2095 | − vwrq->value = 11000000; | |
| 2096 | − } else { | |
| 2097 | − vwrq->fixed = 1; | |
| 2098 | − switch (priv->tx_rate) { | |
| 2099 | − case 0: | |
| 2100 | − vwrq->value = 1000000; | |
| 2101 | − break; | |
| 2102 | − case 1: | |
| 2103 | − vwrq->value = 2000000; | |
| 2104 | − break; | |
| 2105 | − case 2: | |
| 2106 | − vwrq->value = 5500000; | |
| 2107 | − break; | |
| 2108 | − case 3: | |
| 2109 | − vwrq->value = 11000000; | |
| 2110 | − break; | |
| 2111 | − } | |
| 2112 | − } | |
| 2113 | − return 0; | |
| 2114 | −} | |
| 2115 | − | |
| 2116 | −static int atmel_set_power(struct net_device *dev, | |
| 2117 | − struct iw_request_info *info, | |
| 2118 | − union iwreq_data *wrqu, | |
| 2119 | − char *extra) | |
| 2120 | −{ | |
| 2121 | − struct iw_param *vwrq = &wrqu->power; | |
| 2122 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2123 | − priv->power_mode = vwrq->disabled ? 0 : 1; | |
| 2124 | − return -EINPROGRESS; | |
| 2125 | −} | |
| 2126 | − | |
| 2127 | −static int atmel_get_power(struct net_device *dev, | |
| 2128 | − struct iw_request_info *info, | |
| 2129 | − union iwreq_data *wrqu, | |
| 2130 | − char *extra) | |
| 2131 | −{ | |
| 2132 | − struct iw_param *vwrq = &wrqu->power; | |
| 2133 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2134 | − vwrq->disabled = priv->power_mode ? 0 : 1; | |
| 2135 | − vwrq->flags = IW_POWER_ON; | |
| 2136 | − return 0; | |
| 2137 | −} | |
| 2138 | − | |
| 2139 | −static int atmel_set_retry(struct net_device *dev, | |
| 2140 | − struct iw_request_info *info, | |
| 2141 | − union iwreq_data *wrqu, | |
| 2142 | − char *extra) | |
| 2143 | −{ | |
| 2144 | − struct iw_param *vwrq = &wrqu->retry; | |
| 2145 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2146 | − | |
| 2147 | − if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { | |
| 2148 | − if (vwrq->flags & IW_RETRY_LONG) | |
| 2149 | − priv->long_retry = vwrq->value; | |
| 2150 | − else if (vwrq->flags & IW_RETRY_SHORT) | |
| 2151 | − priv->short_retry = vwrq->value; | |
| 2152 | − else { | |
| 2153 | − /* No modifier : set both */ | |
| 2154 | − priv->long_retry = vwrq->value; | |
| 2155 | − priv->short_retry = vwrq->value; | |
| 2156 | − } | |
| 2157 | − return -EINPROGRESS; | |
| 2158 | − } | |
| 2159 | − | |
| 2160 | − return -EINVAL; | |
| 2161 | −} | |
| 2162 | − | |
| 2163 | −static int atmel_get_retry(struct net_device *dev, | |
| 2164 | − struct iw_request_info *info, | |
| 2165 | − union iwreq_data *wrqu, | |
| 2166 | − char *extra) | |
| 2167 | −{ | |
| 2168 | − struct iw_param *vwrq = &wrqu->retry; | |
| 2169 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2170 | − | |
| 2171 | − vwrq->disabled = 0; /* Can't be disabled */ | |
| 2172 | − | |
| 2173 | − /* Note : by default, display the short retry number */ | |
| 2174 | − if (vwrq->flags & IW_RETRY_LONG) { | |
| 2175 | − vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; | |
| 2176 | − vwrq->value = priv->long_retry; | |
| 2177 | − } else { | |
| 2178 | − vwrq->flags = IW_RETRY_LIMIT; | |
| 2179 | − vwrq->value = priv->short_retry; | |
| 2180 | − if (priv->long_retry != priv->short_retry) | |
| 2181 | − vwrq->flags |= IW_RETRY_SHORT; | |
| 2182 | − } | |
| 2183 | − | |
| 2184 | − return 0; | |
| 2185 | −} | |
| 2186 | − | |
| 2187 | −static int atmel_set_rts(struct net_device *dev, | |
| 2188 | − struct iw_request_info *info, | |
| 2189 | − union iwreq_data *wrqu, | |
| 2190 | − char *extra) | |
| 2191 | −{ | |
| 2192 | − struct iw_param *vwrq = &wrqu->rts; | |
| 2193 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2194 | − int rthr = vwrq->value; | |
| 2195 | − | |
| 2196 | − if (vwrq->disabled) | |
| 2197 | − rthr = 2347; | |
| 2198 | − if ((rthr < 0) || (rthr > 2347)) { | |
| 2199 | − return -EINVAL; | |
| 2200 | − } | |
| 2201 | − priv->rts_threshold = rthr; | |
| 2202 | − | |
| 2203 | − return -EINPROGRESS; /* Call commit handler */ | |
| 2204 | −} | |
| 2205 | − | |
| 2206 | −static int atmel_get_rts(struct net_device *dev, | |
| 2207 | − struct iw_request_info *info, | |
| 2208 | − union iwreq_data *wrqu, | |
| 2209 | − char *extra) | |
| 2210 | −{ | |
| 2211 | − struct iw_param *vwrq = &wrqu->rts; | |
| 2212 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2213 | − | |
| 2214 | − vwrq->value = priv->rts_threshold; | |
| 2215 | − vwrq->disabled = (vwrq->value >= 2347); | |
| 2216 | − vwrq->fixed = 1; | |
| 2217 | − | |
| 2218 | − return 0; | |
| 2219 | −} | |
| 2220 | − | |
| 2221 | −static int atmel_set_frag(struct net_device *dev, | |
| 2222 | − struct iw_request_info *info, | |
| 2223 | − union iwreq_data *wrqu, | |
| 2224 | − char *extra) | |
| 2225 | −{ | |
| 2226 | − struct iw_param *vwrq = &wrqu->frag; | |
| 2227 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2228 | − int fthr = vwrq->value; | |
| 2229 | − | |
| 2230 | − if (vwrq->disabled) | |
| 2231 | − fthr = 2346; | |
| 2232 | − if ((fthr < 256) || (fthr > 2346)) { | |
| 2233 | − return -EINVAL; | |
| 2234 | − } | |
| 2235 | − fthr &= ~0x1; /* Get an even value - is it really needed ??? */ | |
| 2236 | − priv->frag_threshold = fthr; | |
| 2237 | − | |
| 2238 | − return -EINPROGRESS; /* Call commit handler */ | |
| 2239 | −} | |
| 2240 | − | |
| 2241 | −static int atmel_get_frag(struct net_device *dev, | |
| 2242 | − struct iw_request_info *info, | |
| 2243 | − union iwreq_data *wrqu, | |
| 2244 | − char *extra) | |
| 2245 | −{ | |
| 2246 | − struct iw_param *vwrq = &wrqu->frag; | |
| 2247 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2248 | − | |
| 2249 | − vwrq->value = priv->frag_threshold; | |
| 2250 | − vwrq->disabled = (vwrq->value >= 2346); | |
| 2251 | − vwrq->fixed = 1; | |
| 2252 | − | |
| 2253 | − return 0; | |
| 2254 | −} | |
| 2255 | − | |
| 2256 | −static int atmel_set_freq(struct net_device *dev, | |
| 2257 | − struct iw_request_info *info, | |
| 2258 | − union iwreq_data *wrqu, | |
| 2259 | − char *extra) | |
| 2260 | −{ | |
| 2261 | − struct iw_freq *fwrq = &wrqu->freq; | |
| 2262 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2263 | − int rc = -EINPROGRESS; /* Call commit handler */ | |
| 2264 | − | |
| 2265 | − /* If setting by frequency, convert to a channel */ | |
| 2266 | − if (fwrq->e == 1) { | |
| 2267 | − int f = fwrq->m / 100000; | |
| 2268 | − | |
| 2269 | − /* Hack to fall through... */ | |
| 2270 | − fwrq->e = 0; | |
| 2271 | − fwrq->m = ieee80211_frequency_to_channel(f); | |
| 2272 | − } | |
| 2273 | − /* Setting by channel number */ | |
| 2274 | − if (fwrq->m < 0 || fwrq->m > 1000 || fwrq->e > 0) | |
| 2275 | − rc = -EOPNOTSUPP; | |
| 2276 | − else { | |
| 2277 | − int channel = fwrq->m; | |
| 2278 | − if (atmel_validate_channel(priv, channel) == 0) { | |
| 2279 | − priv->channel = channel; | |
| 2280 | − } else { | |
| 2281 | − rc = -EINVAL; | |
| 2282 | − } | |
| 2283 | − } | |
| 2284 | − return rc; | |
| 2285 | −} | |
| 2286 | − | |
| 2287 | −static int atmel_get_freq(struct net_device *dev, | |
| 2288 | − struct iw_request_info *info, | |
| 2289 | − union iwreq_data *wrqu, | |
| 2290 | − char *extra) | |
| 2291 | −{ | |
| 2292 | − struct iw_freq *fwrq = &wrqu->freq; | |
| 2293 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2294 | − | |
| 2295 | − fwrq->m = priv->channel; | |
| 2296 | − fwrq->e = 0; | |
| 2297 | − return 0; | |
| 2298 | −} | |
| 2299 | − | |
| 2300 | −static int atmel_set_scan(struct net_device *dev, | |
| 2301 | − struct iw_request_info *info, | |
| 2302 | − union iwreq_data *dwrq, | |
| 2303 | − char *extra) | |
| 2304 | −{ | |
| 2305 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2306 | − unsigned long flags; | |
| 2307 | − | |
| 2308 | − /* Note : you may have realised that, as this is a SET operation, | |
| 2309 | − * this is privileged and therefore a normal user can't | |
| 2310 | − * perform scanning. | |
| 2311 | − * This is not an error, while the device perform scanning, | |
| 2312 | − * traffic doesn't flow, so it's a perfect DoS... | |
| 2313 | − * Jean II */ | |
| 2314 | − | |
| 2315 | − if (priv->station_state == STATION_STATE_DOWN) | |
| 2316 | − return -EAGAIN; | |
| 2317 | − | |
| 2318 | − /* Timeout old surveys. */ | |
| 2319 | − if (time_after(jiffies, priv->last_survey + 20 * HZ)) | |
| 2320 | − priv->site_survey_state = SITE_SURVEY_IDLE; | |
| 2321 | − priv->last_survey = jiffies; | |
| 2322 | − | |
| 2323 | − /* Initiate a scan command */ | |
| 2324 | − if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) | |
| 2325 | − return -EBUSY; | |
| 2326 | − | |
| 2327 | − del_timer_sync(&priv->management_timer); | |
| 2328 | − spin_lock_irqsave(&priv->irqlock, flags); | |
| 2329 | − | |
| 2330 | − priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; | |
| 2331 | − priv->fast_scan = 0; | |
| 2332 | − atmel_scan(priv, 0); | |
| 2333 | − spin_unlock_irqrestore(&priv->irqlock, flags); | |
| 2334 | − | |
| 2335 | − return 0; | |
| 2336 | −} | |
| 2337 | − | |
| 2338 | −static int atmel_get_scan(struct net_device *dev, | |
| 2339 | − struct iw_request_info *info, | |
| 2340 | − union iwreq_data *wrqu, | |
| 2341 | − char *extra) | |
| 2342 | −{ | |
| 2343 | − struct iw_point *dwrq = &wrqu->data; | |
| 2344 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2345 | − int i; | |
| 2346 | − char *current_ev = extra; | |
| 2347 | − struct iw_event iwe; | |
| 2348 | − | |
| 2349 | − if (priv->site_survey_state != SITE_SURVEY_COMPLETED) | |
| 2350 | − return -EAGAIN; | |
| 2351 | − | |
| 2352 | − for (i = 0; i < priv->BSS_list_entries; i++) { | |
| 2353 | − iwe.cmd = SIOCGIWAP; | |
| 2354 | − iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | |
| 2355 | − memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, ETH_ALEN); | |
| 2356 | − current_ev = iwe_stream_add_event(info, current_ev, | |
| 2357 | − extra + IW_SCAN_MAX_DATA, | |
| 2358 | − &iwe, IW_EV_ADDR_LEN); | |
| 2359 | − | |
| 2360 | − iwe.u.data.length = priv->BSSinfo[i].SSIDsize; | |
| 2361 | − if (iwe.u.data.length > 32) | |
| 2362 | − iwe.u.data.length = 32; | |
| 2363 | − iwe.cmd = SIOCGIWESSID; | |
| 2364 | − iwe.u.data.flags = 1; | |
| 2365 | − current_ev = iwe_stream_add_point(info, current_ev, | |
| 2366 | − extra + IW_SCAN_MAX_DATA, | |
| 2367 | − &iwe, priv->BSSinfo[i].SSID); | |
| 2368 | − | |
| 2369 | − iwe.cmd = SIOCGIWMODE; | |
| 2370 | − iwe.u.mode = priv->BSSinfo[i].BSStype; | |
| 2371 | − current_ev = iwe_stream_add_event(info, current_ev, | |
| 2372 | − extra + IW_SCAN_MAX_DATA, | |
| 2373 | − &iwe, IW_EV_UINT_LEN); | |
| 2374 | − | |
| 2375 | − iwe.cmd = SIOCGIWFREQ; | |
| 2376 | − iwe.u.freq.m = priv->BSSinfo[i].channel; | |
| 2377 | − iwe.u.freq.e = 0; | |
| 2378 | − current_ev = iwe_stream_add_event(info, current_ev, | |
| 2379 | − extra + IW_SCAN_MAX_DATA, | |
| 2380 | − &iwe, IW_EV_FREQ_LEN); | |
| 2381 | − | |
| 2382 | − /* Add quality statistics */ | |
| 2383 | − iwe.cmd = IWEVQUAL; | |
| 2384 | − iwe.u.qual.level = priv->BSSinfo[i].RSSI; | |
| 2385 | − iwe.u.qual.qual = iwe.u.qual.level; | |
| 2386 | − /* iwe.u.qual.noise = SOMETHING */ | |
| 2387 | − current_ev = iwe_stream_add_event(info, current_ev, | |
| 2388 | − extra + IW_SCAN_MAX_DATA, | |
| 2389 | − &iwe, IW_EV_QUAL_LEN); | |
| 2390 | − | |
| 2391 | − | |
| 2392 | − iwe.cmd = SIOCGIWENCODE; | |
| 2393 | − if (priv->BSSinfo[i].UsingWEP) | |
| 2394 | − iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | |
| 2395 | − else | |
| 2396 | − iwe.u.data.flags = IW_ENCODE_DISABLED; | |
| 2397 | − iwe.u.data.length = 0; | |
| 2398 | − current_ev = iwe_stream_add_point(info, current_ev, | |
| 2399 | − extra + IW_SCAN_MAX_DATA, | |
| 2400 | − &iwe, NULL); | |
| 2401 | − } | |
| 2402 | − | |
| 2403 | − /* Length of data */ | |
| 2404 | − dwrq->length = (current_ev - extra); | |
| 2405 | − dwrq->flags = 0; | |
| 2406 | − | |
| 2407 | − return 0; | |
| 2408 | −} | |
| 2409 | − | |
| 2410 | −static int atmel_get_range(struct net_device *dev, | |
| 2411 | − struct iw_request_info *info, | |
| 2412 | − union iwreq_data *wrqu, | |
| 2413 | − char *extra) | |
| 2414 | −{ | |
| 2415 | − struct iw_point *dwrq = &wrqu->data; | |
| 2416 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2417 | − struct iw_range *range = (struct iw_range *) extra; | |
| 2418 | − int k, i, j; | |
| 2419 | − | |
| 2420 | − dwrq->length = sizeof(struct iw_range); | |
| 2421 | − memset(range, 0, sizeof(struct iw_range)); | |
| 2422 | − range->min_nwid = 0x0000; | |
| 2423 | − range->max_nwid = 0x0000; | |
| 2424 | − range->num_channels = 0; | |
| 2425 | − for (j = 0; j < ARRAY_SIZE(channel_table); j++) | |
| 2426 | − if (priv->reg_domain == channel_table[j].reg_domain) { | |
| 2427 | − range->num_channels = channel_table[j].max - channel_table[j].min + 1; | |
| 2428 | − break; | |
| 2429 | − } | |
| 2430 | − if (range->num_channels != 0) { | |
| 2431 | − for (k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { | |
| 2432 | − range->freq[k].i = i; /* List index */ | |
| 2433 | − | |
| 2434 | − /* Values in MHz -> * 10^5 * 10 */ | |
| 2435 | − range->freq[k].m = 100000 * | |
| 2436 | − ieee80211_channel_to_frequency(i, NL80211_BAND_2GHZ); | |
| 2437 | − range->freq[k++].e = 1; | |
| 2438 | − } | |
| 2439 | − range->num_frequency = k; | |
| 2440 | − } | |
| 2441 | − | |
| 2442 | − range->max_qual.qual = 100; | |
| 2443 | − range->max_qual.level = 100; | |
| 2444 | − range->max_qual.noise = 0; | |
| 2445 | − range->max_qual.updated = IW_QUAL_NOISE_INVALID; | |
| 2446 | − | |
| 2447 | − range->avg_qual.qual = 50; | |
| 2448 | − range->avg_qual.level = 50; | |
| 2449 | − range->avg_qual.noise = 0; | |
| 2450 | − range->avg_qual.updated = IW_QUAL_NOISE_INVALID; | |
| 2451 | − | |
| 2452 | − range->sensitivity = 0; | |
| 2453 | − | |
| 2454 | − range->bitrate[0] = 1000000; | |
| 2455 | − range->bitrate[1] = 2000000; | |
| 2456 | − range->bitrate[2] = 5500000; | |
| 2457 | − range->bitrate[3] = 11000000; | |
| 2458 | − range->num_bitrates = 4; | |
| 2459 | − | |
| 2460 | − range->min_rts = 0; | |
| 2461 | − range->max_rts = 2347; | |
| 2462 | − range->min_frag = 256; | |
| 2463 | − range->max_frag = 2346; | |
| 2464 | − | |
| 2465 | − range->encoding_size[0] = 5; | |
| 2466 | − range->encoding_size[1] = 13; | |
| 2467 | − range->num_encoding_sizes = 2; | |
| 2468 | − range->max_encoding_tokens = 4; | |
| 2469 | − | |
| 2470 | − range->pmp_flags = IW_POWER_ON; | |
| 2471 | − range->pmt_flags = IW_POWER_ON; | |
| 2472 | − range->pm_capa = 0; | |
| 2473 | − | |
| 2474 | − range->we_version_source = WIRELESS_EXT; | |
| 2475 | − range->we_version_compiled = WIRELESS_EXT; | |
| 2476 | − range->retry_capa = IW_RETRY_LIMIT ; | |
| 2477 | − range->retry_flags = IW_RETRY_LIMIT; | |
| 2478 | − range->r_time_flags = 0; | |
| 2479 | − range->min_retry = 1; | |
| 2480 | − range->max_retry = 65535; | |
| 2481 | − | |
| 2482 | − return 0; | |
| 2483 | −} | |
| 2484 | − | |
| 2485 | −static int atmel_set_wap(struct net_device *dev, | |
| 2486 | − struct iw_request_info *info, | |
| 2487 | − union iwreq_data *wrqu, | |
| 2488 | − char *extra) | |
| 2489 | −{ | |
| 2490 | − struct sockaddr *awrq = &wrqu->ap_addr; | |
| 2491 | − struct atmel_private *priv = netdev_priv(dev); | |
| 2492 | − int i; | |
| 2493 | − static const u8 any[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | |
| 2494 | − static const u8 off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
| 2495 | − unsigned long flags; | |
| 2496 | − | |
| 2497 | − if (awrq->sa_family != ARPHRD_ETHER) | |
| 2498 | − return -EINVAL; | |
| 2499 | − | |
| 2500 | − if (!memcmp(any, awrq->sa_data, 6) || | |
| 2501 | − !memcmp(off, awrq->sa_data, 6)) { | |
| 2502 | − del_timer_sync(&priv->management_timer); | |
| 2503 | − spin_lock_irqsave(&priv->irqlock, flags); | |
| 2504 | − atmel_scan(priv, 1); | |
| 2505 | − spin_unlock_irqrestore(&priv->irqlock, flags); | |
| 2506 | − return 0; | |
| 2507 | − } | |
| 2508 | − | |
| 2509 | − for (i = 0; i < priv->BSS_list_entries; i++) { | |
| 2510 | − if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { | |
| 2511 | − if (!priv->wep_is_on && priv->BSSinfo[i].UsingWEP) { | |
| 2512 | − return -EINVAL; | |
| 2513 | − } else if (priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) { | |
| 2514 | − return -EINVAL; | |
| 2515 | − } else { | |
| 2516 | − del_timer_sync(&priv->management_timer); | |
| 2517 | − spin_lock_irqsave(&priv->irqlock, flags); | |
| 2518 | − atmel_join_bss(priv, i); | |
| 2519 | − spin_unlock_irqrestore(&priv->irqlock, flags); | |
| 2520 | − return 0; | |
| 2521 | − } | |
| 2522 | − } | |
| 2523 | − } | |
| 2524 | − | |
| 2525 | − return -EINVAL; | |
| 2526 | −} | |
| 2527 | − | |
| 2528 | −static int atmel_config_commit(struct net_device *dev, | |
| 2529 | − struct iw_request_info *info, /* NULL */ | |
| 2530 | − union iwreq_data *zwrq, /* NULL */ | |
| 2531 | − char *extra) /* NULL */ | |
| 2532 | −{ | |
| 2533 | − return atmel_open(dev); | |
| 2534 | −} | |
| 2535 | − | |
| 2536 | −static const iw_handler atmel_handler[] = | |
| 2537 | −{ | |
| 2538 | − IW_HANDLER(SIOCSIWCOMMIT, atmel_config_commit), | |
| 2539 | − IW_HANDLER(SIOCGIWNAME, atmel_get_name), | |
| 2540 | − IW_HANDLER(SIOCSIWFREQ, atmel_set_freq), | |
| 2541 | − IW_HANDLER(SIOCGIWFREQ, atmel_get_freq), | |
| 2542 | − IW_HANDLER(SIOCSIWMODE, atmel_set_mode), | |
| 2543 | − IW_HANDLER(SIOCGIWMODE, atmel_get_mode), | |
| 2544 | − IW_HANDLER(SIOCGIWRANGE, atmel_get_range), | |
| 2545 | − IW_HANDLER(SIOCSIWAP, atmel_set_wap), | |
| 2546 | − IW_HANDLER(SIOCGIWAP, atmel_get_wap), | |
| 2547 | − IW_HANDLER(SIOCSIWSCAN, atmel_set_scan), | |
| 2548 | − IW_HANDLER(SIOCGIWSCAN, atmel_get_scan), | |
| 2549 | − IW_HANDLER(SIOCSIWESSID, atmel_set_essid), | |
| 2550 | − IW_HANDLER(SIOCGIWESSID, atmel_get_essid), | |
| 2551 | − IW_HANDLER(SIOCSIWRATE, atmel_set_rate), | |
| 2552 | − IW_HANDLER(SIOCGIWRATE, atmel_get_rate), | |
| 2553 | − IW_HANDLER(SIOCSIWRTS, atmel_set_rts), | |
| 2554 | − IW_HANDLER(SIOCGIWRTS, atmel_get_rts), | |
| 2555 | − IW_HANDLER(SIOCSIWFRAG, atmel_set_frag), | |
| 2556 | − IW_HANDLER(SIOCGIWFRAG, atmel_get_frag), | |
| 2557 | − IW_HANDLER(SIOCSIWRETRY, atmel_set_retry), | |
| 2558 | − IW_HANDLER(SIOCGIWRETRY, atmel_get_retry), | |
| 2559 | − IW_HANDLER(SIOCSIWENCODE, atmel_set_encode), | |
| 2560 | − IW_HANDLER(SIOCGIWENCODE, atmel_get_encode), | |
| 2561 | − IW_HANDLER(SIOCSIWPOWER, atmel_set_power), | |
| 2562 | − IW_HANDLER(SIOCGIWPOWER, atmel_get_power), | |
| 2563 | − IW_HANDLER(SIOCSIWAUTH, atmel_set_auth), | |
| 2564 | − IW_HANDLER(SIOCGIWAUTH, atmel_get_auth), | |
| 2565 | − IW_HANDLER(SIOCSIWENCODEEXT, atmel_set_encodeext), | |
| 2566 | − IW_HANDLER(SIOCGIWENCODEEXT, atmel_get_encodeext), | |
| 2567 | −}; | |
| 2568 | − | |
| 2569 | −static const iw_handler atmel_private_handler[] = | |
| 2570 | −{ | |
| 2571 | − NULL, /* SIOCIWFIRSTPRIV */ | |
| 2572 | −}; | |
| 2573 | − | |
| 2574 | −struct atmel_priv_ioctl { | |
| 2575 | − char id[32]; | |
| 2576 | − unsigned char __user *data; | |
| 2577 | − unsigned short len; | |
| 2578 | −}; | |
| 2579 | − | |
| 2580 | −#define ATMELFWL SIOCIWFIRSTPRIV | |
| 2581 | −#define ATMELIDIFC ATMELFWL + 1 | |
| 2582 | −#define ATMELRD ATMELFWL + 2 | |
| 2583 | −#define ATMELMAGIC 0x51807 | |
| 2584 | −#define REGDOMAINSZ 20 | |
| 2585 | − | |
| 2586 | −static const struct iw_priv_args atmel_private_args[] = { | |
| 2587 | − { | |
| 2588 | − .cmd = ATMELFWL, | |
| 2589 | − .set_args = IW_PRIV_TYPE_BYTE | |
| 2590 | − | IW_PRIV_SIZE_FIXED | |
| 2591 | − | sizeof(struct atmel_priv_ioctl), | |
| 2592 | − .get_args = IW_PRIV_TYPE_NONE, | |
| 2593 | − .name = "atmelfwl" | |
| 2594 | − }, { | |
| 2595 | − .cmd = ATMELIDIFC, | |
| 2596 | − .set_args = IW_PRIV_TYPE_NONE, | |
| 2597 | − .get_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | |
| 2598 | − .name = "atmelidifc" | |
| 2599 | − }, { | |
| 2600 | − .cmd = ATMELRD, | |
| 2601 | − .set_args = IW_PRIV_TYPE_CHAR | REGDOMAINSZ, | |
| 2602 | − .get_args = IW_PRIV_TYPE_NONE, | |
| 2603 | − .name = "regdomain" | |
| 2604 | − }, | |
| 2605 | −}; | |
| 2606 | − | |
| 2607 | −static const struct iw_handler_def atmel_handler_def = { | |
| 2608 | − .num_standard = ARRAY_SIZE(atmel_handler), | |
| 2609 | − .num_private = ARRAY_SIZE(atmel_private_handler), | |
| 2610 | − .num_private_args = ARRAY_SIZE(atmel_private_args), | |
| 2611 | − .standard = atmel_handler, | |
| 2612 | − .private = atmel_private_handler, | |
| 2613 | − .private_args = (struct iw_priv_args *) atmel_private_args, | |
| 2614 | − .get_wireless_stats = atmel_get_wireless_stats | |
| 2615 | −}; | |
| 2616 | − | |
| 2617 | −struct auth_body { | |
| 2618 | − __le16 alg; | |
| 2619 | − __le16 trans_seq; | |
| 2620 | − __le16 status; | |
| 2621 | − u8 el_id; | |
| 2622 | − u8 chall_text_len; | |
| 2623 | − u8 chall_text[253]; | |
| 2624 | −}; | |
| 2625 | − | |
| 2626 | −static void atmel_enter_state(struct atmel_private *priv, int new_state) | |
| 2627 | −{ | |
| 2628 | − int old_state = priv->station_state; | |
| 2629 | − | |
| 2630 | − if (new_state == old_state) | |
| 2631 | − return; | |
| 2632 | − | |
| 2633 | − priv->station_state = new_state; | |
| 2634 | − | |
| 2635 | − if (new_state == STATION_STATE_READY) { | |
| 2636 | − netif_start_queue(priv->dev); | |
| 2637 | − netif_carrier_on(priv->dev); | |
| 2638 | − } | |
| 2639 | − | |
| 2640 | − if (old_state == STATION_STATE_READY) { | |
| 2641 | − netif_carrier_off(priv->dev); | |
| 2642 | − if (netif_running(priv->dev)) | |
| 2643 | − netif_stop_queue(priv->dev); | |
| 2644 | − priv->last_beacon_timestamp = 0; | |
| 2645 | − } | |
| 2646 | −} | |
| 2647 | − | |
| 2648 | −static void atmel_scan(struct atmel_private *priv, int specific_ssid) | |
| 2649 | −{ | |
| 2650 | − struct { | |
| 2651 | − u8 BSSID[ETH_ALEN]; | |
| 2652 | − u8 SSID[MAX_SSID_LENGTH]; | |
| 2653 | − u8 scan_type; | |
| 2654 | − u8 channel; | |
| 2655 | − __le16 BSS_type; | |
| 2656 | − __le16 min_channel_time; | |
| 2657 | − __le16 max_channel_time; | |
| 2658 | − u8 options; | |
| 2659 | − u8 SSID_size; | |
| 2660 | − } cmd; | |
| 2661 | − | |
| 2662 | − eth_broadcast_addr(cmd.BSSID); | |
| 2663 | − | |
| 2664 | − if (priv->fast_scan) { | |
| 2665 | − cmd.SSID_size = priv->SSID_size; | |
| 2666 | − memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | |
| 2667 | − cmd.min_channel_time = cpu_to_le16(10); | |
| 2668 | − cmd.max_channel_time = cpu_to_le16(50); | |
| 2669 | − } else { | |
| 2670 | − priv->BSS_list_entries = 0; | |
| 2671 | − cmd.SSID_size = 0; | |
| 2672 | − cmd.min_channel_time = cpu_to_le16(10); | |
| 2673 | − cmd.max_channel_time = cpu_to_le16(120); | |
| 2674 | − } | |
| 2675 | − | |
| 2676 | − cmd.options = 0; | |
| 2677 | − | |
| 2678 | − if (!specific_ssid) | |
| 2679 | − cmd.options |= SCAN_OPTIONS_SITE_SURVEY; | |
| 2680 | − | |
| 2681 | − cmd.channel = (priv->channel & 0x7f); | |
| 2682 | − cmd.scan_type = SCAN_TYPE_ACTIVE; | |
| 2683 | − cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? | |
| 2684 | − BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); | |
| 2685 | − | |
| 2686 | − atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); | |
| 2687 | − | |
| 2688 | − /* This must come after all hardware access to avoid being messed up | |
| 2689 | − by stuff happening in interrupt context after we leave STATE_DOWN */ | |
| 2690 | − atmel_enter_state(priv, STATION_STATE_SCANNING); | |
| 2691 | −} | |
| 2692 | − | |
| 2693 | −static void join(struct atmel_private *priv, int type) | |
| 2694 | −{ | |
| 2695 | − struct { | |
| 2696 | − u8 BSSID[6]; | |
| 2697 | − u8 SSID[MAX_SSID_LENGTH]; | |
| 2698 | − u8 BSS_type; /* this is a short in a scan command - weird */ | |
| 2699 | − u8 channel; | |
| 2700 | − __le16 timeout; | |
| 2701 | − u8 SSID_size; | |
| 2702 | − u8 reserved; | |
| 2703 | − } cmd; | |
| 2704 | − | |
| 2705 | − cmd.SSID_size = priv->SSID_size; | |
| 2706 | − memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | |
| 2707 | − memcpy(cmd.BSSID, priv->CurrentBSSID, ETH_ALEN); | |
| 2708 | − cmd.channel = (priv->channel & 0x7f); | |
| 2709 | − cmd.BSS_type = type; | |
| 2710 | − cmd.timeout = cpu_to_le16(2000); | |
| 2711 | − | |
| 2712 | − atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); | |
| 2713 | −} | |
| 2714 | − | |
| 2715 | −static void start(struct atmel_private *priv, int type) | |
| 2716 | −{ | |
| 2717 | − struct { | |
| 2718 | − u8 BSSID[6]; | |
| 2719 | − u8 SSID[MAX_SSID_LENGTH]; | |
| 2720 | − u8 BSS_type; | |
| 2721 | − u8 channel; | |
| 2722 | − u8 SSID_size; | |
| 2723 | − u8 reserved[3]; | |
| 2724 | − } cmd; | |
| 2725 | − | |
| 2726 | − cmd.SSID_size = priv->SSID_size; | |
| 2727 | − memcpy(cmd.SSID, priv->SSID, priv->SSID_size); | |
| 2728 | − memcpy(cmd.BSSID, priv->BSSID, ETH_ALEN); | |
| 2729 | − cmd.BSS_type = type; | |
| 2730 | − cmd.channel = (priv->channel & 0x7f); | |
| 2731 | − | |
| 2732 | − atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); | |
| 2733 | −} | |
| 2734 | − | |
| 2735 | −static void handle_beacon_probe(struct atmel_private *priv, u16 capability, | |
| 2736 | − u8 channel) | |
| 2737 | −{ | |
| 2738 | − int rejoin = 0; | |
| 2739 | − int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? | |
| 2740 | − SHORT_PREAMBLE : LONG_PREAMBLE; | |
| 2741 | − | |
| 2742 | − if (priv->preamble != new) { | |
| 2743 | − priv->preamble = new; | |
| 2744 | − rejoin = 1; | |
| 2745 | − atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); | |
| 2746 | − } | |
| 2747 | − | |
| 2748 | − if (priv->channel != channel) { | |
| 2749 | − priv->channel = channel; | |
| 2750 | − rejoin = 1; | |
| 2751 | − atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); | |
| 2752 | − } | |
| 2753 | − | |
| 2754 | − if (rejoin) { | |
| 2755 | − priv->station_is_associated = 0; | |
| 2756 | − atmel_enter_state(priv, STATION_STATE_JOINNING); | |
| 2757 | − | |
| 2758 | − if (priv->operating_mode == IW_MODE_INFRA) | |
| 2759 | − join(priv, BSS_TYPE_INFRASTRUCTURE); | |
| 2760 | − else | |
| 2761 | − join(priv, BSS_TYPE_AD_HOC); | |
| 2762 | − } | |
| 2763 | −} | |
| 2764 | − | |
| 2765 | −static void send_authentication_request(struct atmel_private *priv, u16 system, | |
| 2766 | − u8 *challenge, int challenge_len) | |
| 2767 | −{ | |
| 2768 | − struct ieee80211_hdr header; | |
| 2769 | − struct auth_body auth; | |
| 2770 | − | |
| 2771 | − header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); | |
| 2772 | − header.duration_id = cpu_to_le16(0x8000); | |
| 2773 | − header.seq_ctrl = 0; | |
| 2774 | − memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); | |
| 2775 | − memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); | |
| 2776 | − memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); | |
| 2777 | − | |
| 2778 | − if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) | |
| 2779 | − /* no WEP for authentication frames with TrSeqNo 1 */ | |
| 2780 | − header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | |
| 2781 | − | |
| 2782 | − auth.alg = cpu_to_le16(system); | |
| 2783 | − | |
| 2784 | − auth.status = 0; | |
| 2785 | − auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); | |
| 2786 | − priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; | |
| 2787 | − priv->CurrentAuthentTransactionSeqNum += 2; | |
| 2788 | − | |
| 2789 | − if (challenge_len != 0) { | |
| 2790 | − auth.el_id = 16; /* challenge_text */ | |
| 2791 | − auth.chall_text_len = challenge_len; | |
| 2792 | − memcpy(auth.chall_text, challenge, challenge_len); | |
| 2793 | − atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); | |
| 2794 | − } else { | |
| 2795 | − atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); | |
| 2796 | − } | |
| 2797 | −} | |
| 2798 | − | |
| 2799 | −static void send_association_request(struct atmel_private *priv, int is_reassoc) | |
| 2800 | −{ | |
| 2801 | − u8 *ssid_el_p; | |
| 2802 | − int bodysize; | |
| 2803 | − struct ieee80211_hdr header; | |
| 2804 | − struct ass_req_format { | |
| 2805 | − __le16 capability; | |
| 2806 | − __le16 listen_interval; | |
| 2807 | − u8 ap[ETH_ALEN]; /* nothing after here directly accessible */ | |
| 2808 | − u8 ssid_el_id; | |
| 2809 | − u8 ssid_len; | |
| 2810 | − u8 ssid[MAX_SSID_LENGTH]; | |
| 2811 | − u8 sup_rates_el_id; | |
| 2812 | − u8 sup_rates_len; | |
| 2813 | − u8 rates[4]; | |
| 2814 | − } body; | |
| 2815 | − | |
| 2816 | − header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | |
| 2817 | − (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); | |
| 2818 | − header.duration_id = cpu_to_le16(0x8000); | |
| 2819 | − header.seq_ctrl = 0; | |
| 2820 | − | |
| 2821 | − memcpy(header.addr1, priv->CurrentBSSID, ETH_ALEN); | |
| 2822 | − memcpy(header.addr2, priv->dev->dev_addr, ETH_ALEN); | |
| 2823 | − memcpy(header.addr3, priv->CurrentBSSID, ETH_ALEN); | |
| 2824 | − | |
| 2825 | − body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS); | |
| 2826 | − if (priv->wep_is_on) | |
| 2827 | − body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); | |
| 2828 | − if (priv->preamble == SHORT_PREAMBLE) | |
| 2829 | − body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); | |
| 2830 | − | |
| 2831 | − body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); | |
| 2832 | − | |
| 2833 | − /* current AP address - only in reassoc frame */ | |
| 2834 | − if (is_reassoc) { | |
| 2835 | − memcpy(body.ap, priv->CurrentBSSID, ETH_ALEN); | |
| 2836 | − ssid_el_p = &body.ssid_el_id; | |
| 2837 | − bodysize = 18 + priv->SSID_size; | |
| 2838 | − } else { | |
| 2839 | − ssid_el_p = &body.ap[0]; | |
| 2840 | − bodysize = 12 + priv->SSID_size; | |
| 2841 | − } | |
| 2842 | − | |
| 2843 | − ssid_el_p[0] = WLAN_EID_SSID; | |
| 2844 | − ssid_el_p[1] = priv->SSID_size; | |
| 2845 | − memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); | |
| 2846 | − ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; | |
| 2847 | − ssid_el_p[3 + priv->SSID_size] = 4; /* len of supported rates */ | |
| 2848 | − memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); | |
| 2849 | − | |
| 2850 | − atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); | |
| 2851 | −} | |
| 2852 | − | |
| 2853 | −static int is_frame_from_current_bss(struct atmel_private *priv, | |
| 2854 | − struct ieee80211_hdr *header) | |
| 2855 | −{ | |
| 2856 | − if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) | |
| 2857 | − return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; | |
| 2858 | − else | |
| 2859 | − return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; | |
| 2860 | −} | |
| 2861 | − | |
| 2862 | −static int retrieve_bss(struct atmel_private *priv) | |
| 2863 | −{ | |
| 2864 | − int i; | |
| 2865 | − int max_rssi = -128; | |
| 2866 | − int max_index = -1; | |
| 2867 | − | |
| 2868 | − if (priv->BSS_list_entries == 0) | |
| 2869 | − return -1; | |
| 2870 | − | |
| 2871 | − if (priv->connect_to_any_BSS) { | |
| 2872 | − /* Select a BSS with the max-RSSI but of the same type and of | |
| 2873 | − the same WEP mode and that it is not marked as 'bad' (i.e. | |
| 2874 | − we had previously failed to connect to this BSS with the | |
| 2875 | − settings that we currently use) */ | |
| 2876 | − priv->current_BSS = 0; | |
| 2877 | − for (i = 0; i < priv->BSS_list_entries; i++) { | |
| 2878 | − if (priv->operating_mode == priv->BSSinfo[i].BSStype && | |
| 2879 | − ((!priv->wep_is_on && !priv->BSSinfo[i].UsingWEP) || | |
| 2880 | − (priv->wep_is_on && priv->BSSinfo[i].UsingWEP)) && | |
| 2881 | − !(priv->BSSinfo[i].channel & 0x80)) { | |
| 2882 | − max_rssi = priv->BSSinfo[i].RSSI; | |
| 2883 | − priv->current_BSS = max_index = i; | |
| 2884 | − } | |
| 2885 | − } | |
| 2886 | − return max_index; | |
| 2887 | − } | |
| 2888 | − | |
| 2889 | − for (i = 0; i < priv->BSS_list_entries; i++) { | |
| 2890 | − if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && | |
| 2891 | − memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && | |
| 2892 | − priv->operating_mode == priv->BSSinfo[i].BSStype && | |
| 2893 | − atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { | |
| 2894 | − if (priv->BSSinfo[i].RSSI >= max_rssi) { | |
| 2895 | − max_rssi = priv->BSSinfo[i].RSSI; | |
| 2896 | − max_index = i; | |
| 2897 | − } | |
| 2898 | − } | |
| 2899 | − } | |
| 2900 | − return max_index; | |
| 2901 | −} | |
| 2902 | − | |
| 2903 | −static void store_bss_info(struct atmel_private *priv, | |
| 2904 | − struct ieee80211_hdr *header, u16 capability, | |
| 2905 | − u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, | |
| 2906 | − u8 *ssid, int is_beacon) | |
| 2907 | −{ | |
| 2908 | − u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3; | |
| 2909 | − int i, index; | |
| 2910 | − | |
| 2911 | − for (index = -1, i = 0; i < priv->BSS_list_entries; i++) | |
| 2912 | − if (memcmp(bss, priv->BSSinfo[i].BSSID, ETH_ALEN) == 0) | |
| 2913 | − index = i; | |
| 2914 | − | |
| 2915 | − /* If we process a probe and an entry from this BSS exists | |
| 2916 | − we will update the BSS entry with the info from this BSS. | |
| 2917 | − If we process a beacon we will only update RSSI */ | |
| 2918 | − | |
| 2919 | − if (index == -1) { | |
| 2920 | − if (priv->BSS_list_entries == MAX_BSS_ENTRIES) | |
| 2921 | − return; | |
| 2922 | − index = priv->BSS_list_entries++; | |
| 2923 | − memcpy(priv->BSSinfo[index].BSSID, bss, ETH_ALEN); | |
| 2924 | − priv->BSSinfo[index].RSSI = rssi; | |
| 2925 | − } else { | |
| 2926 | − if (rssi > priv->BSSinfo[index].RSSI) | |
| 2927 | − priv->BSSinfo[index].RSSI = rssi; | |
| 2928 | − if (is_beacon) | |
| 2929 | − return; | |
| 2930 | − } | |
| 2931 | − | |
| 2932 | − priv->BSSinfo[index].channel = channel; | |
| 2933 | − priv->BSSinfo[index].beacon_period = beacon_period; | |
| 2934 | − priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY; | |
| 2935 | − memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); | |
| 2936 | − priv->BSSinfo[index].SSIDsize = ssid_len; | |
| 2937 | − | |
| 2938 | − if (capability & WLAN_CAPABILITY_IBSS) | |
| 2939 | − priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; | |
| 2940 | − else if (capability & WLAN_CAPABILITY_ESS) | |
| 2941 | − priv->BSSinfo[index].BSStype = IW_MODE_INFRA; | |
| 2942 | − | |
| 2943 | − priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? | |
| 2944 | − SHORT_PREAMBLE : LONG_PREAMBLE; | |
| 2945 | −} | |
| 2946 | − | |
| 2947 | −static void authenticate(struct atmel_private *priv, u16 frame_len) | |
| 2948 | −{ | |
| 2949 | − struct auth_body *auth = (struct auth_body *)priv->rx_buf; | |
| 2950 | − u16 status = le16_to_cpu(auth->status); | |
| 2951 | − u16 trans_seq_no = le16_to_cpu(auth->trans_seq); | |
| 2952 | − u16 system = le16_to_cpu(auth->alg); | |
| 2953 | − | |
| 2954 | − if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) { | |
| 2955 | − /* no WEP */ | |
| 2956 | − if (priv->station_was_associated) { | |
| 2957 | − atmel_enter_state(priv, STATION_STATE_REASSOCIATING); | |
| 2958 | − send_association_request(priv, 1); | |
| 2959 | − return; | |
| 2960 | − } else { | |
| 2961 | − atmel_enter_state(priv, STATION_STATE_ASSOCIATING); | |
| 2962 | − send_association_request(priv, 0); | |
| 2963 | − return; | |
| 2964 | − } | |
| 2965 | − } | |
| 2966 | − | |
| 2967 | − if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) { | |
| 2968 | − int should_associate = 0; | |
| 2969 | − /* WEP */ | |
| 2970 | − if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) | |
| 2971 | − return; | |
| 2972 | − | |
| 2973 | − if (system == WLAN_AUTH_OPEN) { | |
| 2974 | − if (trans_seq_no == 0x0002) { | |
| 2975 | − should_associate = 1; | |
| 2976 | − } | |
| 2977 | − } else if (system == WLAN_AUTH_SHARED_KEY) { | |
| 2978 | − if (trans_seq_no == 0x0002 && | |
| 2979 | − auth->el_id == WLAN_EID_CHALLENGE) { | |
| 2980 | − send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); | |
| 2981 | − return; | |
| 2982 | − } else if (trans_seq_no == 0x0004) { | |
| 2983 | − should_associate = 1; | |
| 2984 | − } | |
| 2985 | − } | |
| 2986 | − | |
| 2987 | − if (should_associate) { | |
| 2988 | − if (priv->station_was_associated) { | |
| 2989 | − atmel_enter_state(priv, STATION_STATE_REASSOCIATING); | |
| 2990 | − send_association_request(priv, 1); | |
| 2991 | − return; | |
| 2992 | − } else { | |
| 2993 | − atmel_enter_state(priv, STATION_STATE_ASSOCIATING); | |
| 2994 | − send_association_request(priv, 0); | |
| 2995 | − return; | |
| 2996 | − } | |
| 2997 | − } | |
| 2998 | − } | |
| 2999 | − | |
| 3000 | − if (status == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { | |
| 3001 | − /* Flip back and forth between WEP auth modes until the max | |
| 3002 | − * authentication tries has been exceeded. | |
| 3003 | − */ | |
| 3004 | − if (system == WLAN_AUTH_OPEN) { | |
| 3005 | − priv->CurrentAuthentTransactionSeqNum = 0x001; | |
| 3006 | − priv->exclude_unencrypted = 1; | |
| 3007 | − send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0); | |
| 3008 | − return; | |
| 3009 | − } else if (system == WLAN_AUTH_SHARED_KEY | |
| 3010 | − && priv->wep_is_on) { | |
| 3011 | − priv->CurrentAuthentTransactionSeqNum = 0x001; | |
| 3012 | − priv->exclude_unencrypted = 0; | |
| 3013 | − send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0); | |
| 3014 | − return; | |
| 3015 | − } else if (priv->connect_to_any_BSS) { | |
| 3016 | − int bss_index; | |
| 3017 | − | |
| 3018 | − priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | |
| 3019 | − | |
| 3020 | − if ((bss_index = retrieve_bss(priv)) != -1) { | |
| 3021 | − atmel_join_bss(priv, bss_index); | |
| 3022 | − return; | |
| 3023 | − } | |
| 3024 | − } | |
| 3025 | − } | |
| 3026 | − | |
| 3027 | − priv->AuthenticationRequestRetryCnt = 0; | |
| 3028 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 3029 | − priv->station_is_associated = 0; | |
| 3030 | −} | |
| 3031 | − | |
| 3032 | −static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) | |
| 3033 | −{ | |
| 3034 | − struct ass_resp_format { | |
| 3035 | − __le16 capability; | |
| 3036 | − __le16 status; | |
| 3037 | − __le16 ass_id; | |
| 3038 | − u8 el_id; | |
| 3039 | − u8 length; | |
| 3040 | − u8 rates[4]; | |
| 3041 | − } *ass_resp = (struct ass_resp_format *)priv->rx_buf; | |
| 3042 | − | |
| 3043 | − u16 status = le16_to_cpu(ass_resp->status); | |
| 3044 | − u16 ass_id = le16_to_cpu(ass_resp->ass_id); | |
| 3045 | − u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; | |
| 3046 | − | |
| 3047 | − union iwreq_data wrqu; | |
| 3048 | − | |
| 3049 | − if (frame_len < 8 + rates_len) | |
| 3050 | − return; | |
| 3051 | − | |
| 3052 | − if (status == WLAN_STATUS_SUCCESS) { | |
| 3053 | − if (subtype == IEEE80211_STYPE_ASSOC_RESP) | |
| 3054 | − priv->AssociationRequestRetryCnt = 0; | |
| 3055 | − else | |
| 3056 | − priv->ReAssociationRequestRetryCnt = 0; | |
| 3057 | − | |
| 3058 | − atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | |
| 3059 | − MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); | |
| 3060 | − atmel_set_mib(priv, Phy_Mib_Type, | |
| 3061 | − PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); | |
| 3062 | − if (priv->power_mode == 0) { | |
| 3063 | − priv->listen_interval = 1; | |
| 3064 | − atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, | |
| 3065 | − MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | |
| 3066 | − atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | |
| 3067 | − MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | |
| 3068 | − } else { | |
| 3069 | − priv->listen_interval = 2; | |
| 3070 | − atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, | |
| 3071 | − MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); | |
| 3072 | − atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | |
| 3073 | − MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); | |
| 3074 | − } | |
| 3075 | − | |
| 3076 | − priv->station_is_associated = 1; | |
| 3077 | − priv->station_was_associated = 1; | |
| 3078 | − atmel_enter_state(priv, STATION_STATE_READY); | |
| 3079 | − | |
| 3080 | − /* Send association event to userspace */ | |
| 3081 | − wrqu.data.length = 0; | |
| 3082 | − wrqu.data.flags = 0; | |
| 3083 | − memcpy(wrqu.ap_addr.sa_data, priv->CurrentBSSID, ETH_ALEN); | |
| 3084 | − wrqu.ap_addr.sa_family = ARPHRD_ETHER; | |
| 3085 | − wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | |
| 3086 | − | |
| 3087 | − return; | |
| 3088 | − } | |
| 3089 | − | |
| 3090 | − if (subtype == IEEE80211_STYPE_ASSOC_RESP && | |
| 3091 | − status != WLAN_STATUS_ASSOC_DENIED_RATES && | |
| 3092 | − status != WLAN_STATUS_CAPS_UNSUPPORTED && | |
| 3093 | − priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { | |
| 3094 | − mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | |
| 3095 | − priv->AssociationRequestRetryCnt++; | |
| 3096 | − send_association_request(priv, 0); | |
| 3097 | − return; | |
| 3098 | − } | |
| 3099 | − | |
| 3100 | − if (subtype == IEEE80211_STYPE_REASSOC_RESP && | |
| 3101 | − status != WLAN_STATUS_ASSOC_DENIED_RATES && | |
| 3102 | − status != WLAN_STATUS_CAPS_UNSUPPORTED && | |
| 3103 | − priv->ReAssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { | |
| 3104 | − mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | |
| 3105 | − priv->ReAssociationRequestRetryCnt++; | |
| 3106 | − send_association_request(priv, 1); | |
| 3107 | − return; | |
| 3108 | − } | |
| 3109 | − | |
| 3110 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 3111 | − priv->station_is_associated = 0; | |
| 3112 | − | |
| 3113 | − if (priv->connect_to_any_BSS) { | |
| 3114 | − int bss_index; | |
| 3115 | − priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | |
| 3116 | − | |
| 3117 | − if ((bss_index = retrieve_bss(priv)) != -1) | |
| 3118 | − atmel_join_bss(priv, bss_index); | |
| 3119 | − } | |
| 3120 | −} | |
| 3121 | − | |
| 3122 | −static void atmel_join_bss(struct atmel_private *priv, int bss_index) | |
| 3123 | −{ | |
| 3124 | − struct bss_info *bss = &priv->BSSinfo[bss_index]; | |
| 3125 | − | |
| 3126 | − memcpy(priv->CurrentBSSID, bss->BSSID, ETH_ALEN); | |
| 3127 | − memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); | |
| 3128 | − | |
| 3129 | − /* The WPA stuff cares about the current AP address */ | |
| 3130 | − if (priv->use_wpa) | |
| 3131 | − build_wpa_mib(priv); | |
| 3132 | − | |
| 3133 | − /* When switching to AdHoc turn OFF Power Save if needed */ | |
| 3134 | − | |
| 3135 | − if (bss->BSStype == IW_MODE_ADHOC && | |
| 3136 | − priv->operating_mode != IW_MODE_ADHOC && | |
| 3137 | − priv->power_mode) { | |
| 3138 | − priv->power_mode = 0; | |
| 3139 | − priv->listen_interval = 1; | |
| 3140 | − atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, | |
| 3141 | − MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | |
| 3142 | − atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, | |
| 3143 | − MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | |
| 3144 | − } | |
| 3145 | − | |
| 3146 | − priv->operating_mode = bss->BSStype; | |
| 3147 | − priv->channel = bss->channel & 0x7f; | |
| 3148 | − priv->beacon_period = bss->beacon_period; | |
| 3149 | − | |
| 3150 | − if (priv->preamble != bss->preamble) { | |
| 3151 | − priv->preamble = bss->preamble; | |
| 3152 | − atmel_set_mib8(priv, Local_Mib_Type, | |
| 3153 | − LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); | |
| 3154 | − } | |
| 3155 | − | |
| 3156 | − if (!priv->wep_is_on && bss->UsingWEP) { | |
| 3157 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 3158 | − priv->station_is_associated = 0; | |
| 3159 | − return; | |
| 3160 | − } | |
| 3161 | − | |
| 3162 | − if (priv->wep_is_on && !bss->UsingWEP) { | |
| 3163 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 3164 | − priv->station_is_associated = 0; | |
| 3165 | − return; | |
| 3166 | − } | |
| 3167 | − | |
| 3168 | − atmel_enter_state(priv, STATION_STATE_JOINNING); | |
| 3169 | − | |
| 3170 | − if (priv->operating_mode == IW_MODE_INFRA) | |
| 3171 | − join(priv, BSS_TYPE_INFRASTRUCTURE); | |
| 3172 | − else | |
| 3173 | − join(priv, BSS_TYPE_AD_HOC); | |
| 3174 | −} | |
| 3175 | − | |
| 3176 | −static void restart_search(struct atmel_private *priv) | |
| 3177 | −{ | |
| 3178 | − int bss_index; | |
| 3179 | − | |
| 3180 | − if (!priv->connect_to_any_BSS) { | |
| 3181 | − atmel_scan(priv, 1); | |
| 3182 | − } else { | |
| 3183 | − priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; | |
| 3184 | − | |
| 3185 | − if ((bss_index = retrieve_bss(priv)) != -1) | |
| 3186 | − atmel_join_bss(priv, bss_index); | |
| 3187 | − else | |
| 3188 | − atmel_scan(priv, 0); | |
| 3189 | − } | |
| 3190 | −} | |
| 3191 | − | |
| 3192 | −static void smooth_rssi(struct atmel_private *priv, u8 rssi) | |
| 3193 | −{ | |
| 3194 | − u8 old = priv->wstats.qual.level; | |
| 3195 | − u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */ | |
| 3196 | − | |
| 3197 | − switch (priv->firmware_type) { | |
| 3198 | − case ATMEL_FW_TYPE_502E: | |
| 3199 | − max_rssi = 63; /* 502-rmfd-reve max by experiment */ | |
| 3200 | − break; | |
| 3201 | − default: | |
| 3202 | − break; | |
| 3203 | − } | |
| 3204 | − | |
| 3205 | − rssi = rssi * 100 / max_rssi; | |
| 3206 | − if ((rssi + old) % 2) | |
| 3207 | − priv->wstats.qual.level = (rssi + old) / 2 + 1; | |
| 3208 | − else | |
| 3209 | − priv->wstats.qual.level = (rssi + old) / 2; | |
| 3210 | − priv->wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED; | |
| 3211 | − priv->wstats.qual.updated &= ~IW_QUAL_LEVEL_INVALID; | |
| 3212 | −} | |
| 3213 | − | |
| 3214 | −static void atmel_smooth_qual(struct atmel_private *priv) | |
| 3215 | −{ | |
| 3216 | − unsigned long time_diff = (jiffies - priv->last_qual) / HZ; | |
| 3217 | − while (time_diff--) { | |
| 3218 | − priv->last_qual += HZ; | |
| 3219 | − priv->wstats.qual.qual = priv->wstats.qual.qual / 2; | |
| 3220 | − priv->wstats.qual.qual += | |
| 3221 | − priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; | |
| 3222 | − priv->beacons_this_sec = 0; | |
| 3223 | − } | |
| 3224 | − priv->wstats.qual.updated |= IW_QUAL_QUAL_UPDATED; | |
| 3225 | − priv->wstats.qual.updated &= ~IW_QUAL_QUAL_INVALID; | |
| 3226 | −} | |
| 3227 | − | |
| 3228 | −/* deals with incoming management frames. */ | |
| 3229 | −static void atmel_management_frame(struct atmel_private *priv, | |
| 3230 | − struct ieee80211_hdr *header, | |
| 3231 | − u16 frame_len, u8 rssi) | |
| 3232 | −{ | |
| 3233 | − u16 subtype; | |
| 3234 | − | |
| 3235 | − subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; | |
| 3236 | − switch (subtype) { | |
| 3237 | − case IEEE80211_STYPE_BEACON: | |
| 3238 | − case IEEE80211_STYPE_PROBE_RESP: | |
| 3239 | − | |
| 3240 | − /* beacon frame has multiple variable-length fields - | |
| 3241 | − never let an engineer loose with a data structure design. */ | |
| 3242 | − { | |
| 3243 | − struct beacon_format { | |
| 3244 | − __le64 timestamp; | |
| 3245 | − __le16 interval; | |
| 3246 | − __le16 capability; | |
| 3247 | − u8 ssid_el_id; | |
| 3248 | − u8 ssid_length; | |
| 3249 | − /* ssid here */ | |
| 3250 | − u8 rates_el_id; | |
| 3251 | − u8 rates_length; | |
| 3252 | − /* rates here */ | |
| 3253 | − u8 ds_el_id; | |
| 3254 | − u8 ds_length; | |
| 3255 | − /* ds here */ | |
| 3256 | − } *beacon = (struct beacon_format *)priv->rx_buf; | |
| 3257 | − | |
| 3258 | − u8 channel, rates_length, ssid_length; | |
| 3259 | − u64 timestamp = le64_to_cpu(beacon->timestamp); | |
| 3260 | − u16 beacon_interval = le16_to_cpu(beacon->interval); | |
| 3261 | − u16 capability = le16_to_cpu(beacon->capability); | |
| 3262 | − u8 *beaconp = priv->rx_buf; | |
| 3263 | − ssid_length = beacon->ssid_length; | |
| 3264 | − /* this blows chunks. */ | |
| 3265 | − if (frame_len < 14 || frame_len < ssid_length + 15) | |
| 3266 | − return; | |
| 3267 | − rates_length = beaconp[beacon->ssid_length + 15]; | |
| 3268 | − if (frame_len < ssid_length + rates_length + 18) | |
| 3269 | − return; | |
| 3270 | − if (ssid_length > MAX_SSID_LENGTH) | |
| 3271 | − return; | |
| 3272 | − channel = beaconp[ssid_length + rates_length + 18]; | |
| 3273 | − | |
| 3274 | − if (priv->station_state == STATION_STATE_READY) { | |
| 3275 | − smooth_rssi(priv, rssi); | |
| 3276 | − if (is_frame_from_current_bss(priv, header)) { | |
| 3277 | − priv->beacons_this_sec++; | |
| 3278 | − atmel_smooth_qual(priv); | |
| 3279 | − if (priv->last_beacon_timestamp) { | |
| 3280 | − /* Note truncate this to 32 bits - kernel can't divide a long */ | |
| 3281 | − u32 beacon_delay = timestamp - priv->last_beacon_timestamp; | |
| 3282 | − int beacons = beacon_delay / (beacon_interval * 1000); | |
| 3283 | − if (beacons > 1) | |
| 3284 | − priv->wstats.miss.beacon += beacons - 1; | |
| 3285 | − } | |
| 3286 | − priv->last_beacon_timestamp = timestamp; | |
| 3287 | − handle_beacon_probe(priv, capability, channel); | |
| 3288 | − } | |
| 3289 | − } | |
| 3290 | − | |
| 3291 | − if (priv->station_state == STATION_STATE_SCANNING) | |
| 3292 | − store_bss_info(priv, header, capability, | |
| 3293 | − beacon_interval, channel, rssi, | |
| 3294 | − ssid_length, | |
| 3295 | − &beacon->rates_el_id, | |
| 3296 | − subtype == IEEE80211_STYPE_BEACON); | |
| 3297 | − } | |
| 3298 | − break; | |
| 3299 | − | |
| 3300 | − case IEEE80211_STYPE_AUTH: | |
| 3301 | − | |
| 3302 | − if (priv->station_state == STATION_STATE_AUTHENTICATING) | |
| 3303 | − authenticate(priv, frame_len); | |
| 3304 | − | |
| 3305 | − break; | |
| 3306 | − | |
| 3307 | − case IEEE80211_STYPE_ASSOC_RESP: | |
| 3308 | − case IEEE80211_STYPE_REASSOC_RESP: | |
| 3309 | − | |
| 3310 | − if (priv->station_state == STATION_STATE_ASSOCIATING || | |
| 3311 | − priv->station_state == STATION_STATE_REASSOCIATING) | |
| 3312 | − associate(priv, frame_len, subtype); | |
| 3313 | − | |
| 3314 | − break; | |
| 3315 | − | |
| 3316 | − case IEEE80211_STYPE_DISASSOC: | |
| 3317 | − if (priv->station_is_associated && | |
| 3318 | − priv->operating_mode == IW_MODE_INFRA && | |
| 3319 | − is_frame_from_current_bss(priv, header)) { | |
| 3320 | − priv->station_was_associated = 0; | |
| 3321 | − priv->station_is_associated = 0; | |
| 3322 | − | |
| 3323 | − atmel_enter_state(priv, STATION_STATE_JOINNING); | |
| 3324 | − join(priv, BSS_TYPE_INFRASTRUCTURE); | |
| 3325 | − } | |
| 3326 | − | |
| 3327 | − break; | |
| 3328 | − | |
| 3329 | − case IEEE80211_STYPE_DEAUTH: | |
| 3330 | − if (priv->operating_mode == IW_MODE_INFRA && | |
| 3331 | − is_frame_from_current_bss(priv, header)) { | |
| 3332 | − priv->station_was_associated = 0; | |
| 3333 | − | |
| 3334 | − atmel_enter_state(priv, STATION_STATE_JOINNING); | |
| 3335 | − join(priv, BSS_TYPE_INFRASTRUCTURE); | |
| 3336 | − } | |
| 3337 | − | |
| 3338 | − break; | |
| 3339 | − } | |
| 3340 | −} | |
| 3341 | − | |
| 3342 | −/* run when timer expires */ | |
| 3343 | −static void atmel_management_timer(struct timer_list *t) | |
| 3344 | −{ | |
| 3345 | − struct atmel_private *priv = from_timer(priv, t, management_timer); | |
| 3346 | − unsigned long flags; | |
| 3347 | − | |
| 3348 | − /* Check if the card has been yanked. */ | |
| 3349 | − if (priv->card && priv->present_callback && | |
| 3350 | − !(*priv->present_callback)(priv->card)) | |
| 3351 | − return; | |
| 3352 | − | |
| 3353 | − spin_lock_irqsave(&priv->irqlock, flags); | |
| 3354 | − | |
| 3355 | − switch (priv->station_state) { | |
| 3356 | − | |
| 3357 | − case STATION_STATE_AUTHENTICATING: | |
| 3358 | − if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { | |
| 3359 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 3360 | − priv->station_is_associated = 0; | |
| 3361 | − priv->AuthenticationRequestRetryCnt = 0; | |
| 3362 | − restart_search(priv); | |
| 3363 | − } else { | |
| 3364 | − int auth = WLAN_AUTH_OPEN; | |
| 3365 | − priv->AuthenticationRequestRetryCnt++; | |
| 3366 | − priv->CurrentAuthentTransactionSeqNum = 0x0001; | |
| 3367 | − mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | |
| 3368 | − if (priv->wep_is_on && priv->exclude_unencrypted) | |
| 3369 | − auth = WLAN_AUTH_SHARED_KEY; | |
| 3370 | − send_authentication_request(priv, auth, NULL, 0); | |
| 3371 | − } | |
| 3372 | − break; | |
| 3373 | − | |
| 3374 | − case STATION_STATE_ASSOCIATING: | |
| 3375 | − if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { | |
| 3376 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 3377 | − priv->station_is_associated = 0; | |
| 3378 | − priv->AssociationRequestRetryCnt = 0; | |
| 3379 | − restart_search(priv); | |
| 3380 | − } else { | |
| 3381 | − priv->AssociationRequestRetryCnt++; | |
| 3382 | − mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | |
| 3383 | − send_association_request(priv, 0); | |
| 3384 | − } | |
| 3385 | − break; | |
| 3386 | − | |
| 3387 | − case STATION_STATE_REASSOCIATING: | |
| 3388 | − if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { | |
| 3389 | − atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); | |
| 3390 | − priv->station_is_associated = 0; | |
| 3391 | − priv->ReAssociationRequestRetryCnt = 0; | |
| 3392 | − restart_search(priv); | |
| 3393 | − } else { | |
| 3394 | − priv->ReAssociationRequestRetryCnt++; | |
| 3395 | − mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | |
| 3396 | − send_association_request(priv, 1); | |
| 3397 | − } | |
| 3398 | − break; | |
| 3399 | − | |
| 3400 | − default: | |
| 3401 | − break; | |
| 3402 | − } | |
| 3403 | − | |
| 3404 | − spin_unlock_irqrestore(&priv->irqlock, flags); | |
| 3405 | −} | |
| 3406 | − | |
| 3407 | −static void atmel_command_irq(struct atmel_private *priv) | |
| 3408 | −{ | |
| 3409 | − u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); | |
| 3410 | − u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); | |
| 3411 | − int fast_scan; | |
| 3412 | − union iwreq_data wrqu; | |
| 3413 | − | |
| 3414 | − if (status == CMD_STATUS_IDLE || | |
| 3415 | − status == CMD_STATUS_IN_PROGRESS) | |
| 3416 | − return; | |
| 3417 | − | |
| 3418 | − switch (command) { | |
| 3419 | − case CMD_Start: | |
| 3420 | − if (status == CMD_STATUS_COMPLETE) { | |
| 3421 | − priv->station_was_associated = priv->station_is_associated; | |
| 3422 | − atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, | |
| 3423 | − (u8 *)priv->CurrentBSSID, 6); | |
| 3424 | − atmel_enter_state(priv, STATION_STATE_READY); | |
| 3425 | − } | |
| 3426 | − break; | |
| 3427 | − | |
| 3428 | − case CMD_Scan: | |
| 3429 | − fast_scan = priv->fast_scan; | |
| 3430 | − priv->fast_scan = 0; | |
| 3431 | − | |
| 3432 | − if (status != CMD_STATUS_COMPLETE) { | |
| 3433 | − atmel_scan(priv, 1); | |
| 3434 | − } else { | |
| 3435 | − int bss_index = retrieve_bss(priv); | |
| 3436 | − int notify_scan_complete = 1; | |
| 3437 | − if (bss_index != -1) { | |
| 3438 | − atmel_join_bss(priv, bss_index); | |
| 3439 | − } else if (priv->operating_mode == IW_MODE_ADHOC && | |
| 3440 | − priv->SSID_size != 0) { | |
| 3441 | − start(priv, BSS_TYPE_AD_HOC); | |
| 3442 | − } else { | |
| 3443 | − priv->fast_scan = !fast_scan; | |
| 3444 | − atmel_scan(priv, 1); | |
| 3445 | − notify_scan_complete = 0; | |
| 3446 | − } | |
| 3447 | − priv->site_survey_state = SITE_SURVEY_COMPLETED; | |
| 3448 | − if (notify_scan_complete) { | |
| 3449 | − wrqu.data.length = 0; | |
| 3450 | − wrqu.data.flags = 0; | |
| 3451 | − wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); | |
| 3452 | − } | |
| 3453 | − } | |
| 3454 | − break; | |
| 3455 | − | |
| 3456 | − case CMD_SiteSurvey: | |
| 3457 | − priv->fast_scan = 0; | |
| 3458 | − | |
| 3459 | − if (status != CMD_STATUS_COMPLETE) | |
| 3460 | − return; | |
| 3461 | − | |
| 3462 | − priv->site_survey_state = SITE_SURVEY_COMPLETED; | |
| 3463 | − if (priv->station_is_associated) { | |
| 3464 | − atmel_enter_state(priv, STATION_STATE_READY); | |
| 3465 | − wrqu.data.length = 0; | |
| 3466 | − wrqu.data.flags = 0; | |
| 3467 | − wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL); | |
| 3468 | − } else { | |
| 3469 | − atmel_scan(priv, 1); | |
| 3470 | − } | |
| 3471 | − break; | |
| 3472 | − | |
| 3473 | − case CMD_Join: | |
| 3474 | − if (status == CMD_STATUS_COMPLETE) { | |
| 3475 | − if (priv->operating_mode == IW_MODE_ADHOC) { | |
| 3476 | − priv->station_was_associated = priv->station_is_associated; | |
| 3477 | − atmel_enter_state(priv, STATION_STATE_READY); | |
| 3478 | − } else { | |
| 3479 | − int auth = WLAN_AUTH_OPEN; | |
| 3480 | − priv->AuthenticationRequestRetryCnt = 0; | |
| 3481 | − atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); | |
| 3482 | − | |
| 3483 | − mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); | |
| 3484 | − priv->CurrentAuthentTransactionSeqNum = 0x0001; | |
| 3485 | − if (priv->wep_is_on && priv->exclude_unencrypted) | |
| 3486 | − auth = WLAN_AUTH_SHARED_KEY; | |
| 3487 | − send_authentication_request(priv, auth, NULL, 0); | |
| 3488 | − } | |
| 3489 | − return; | |
| 3490 | − } | |
| 3491 | − | |
| 3492 | − atmel_scan(priv, 1); | |
| 3493 | − } | |
| 3494 | −} | |
| 3495 | − | |
| 3496 | −static int atmel_wakeup_firmware(struct atmel_private *priv) | |
| 3497 | −{ | |
| 3498 | − struct host_info_struct *iface = &priv->host_info; | |
| 3499 | − u16 mr1, mr3; | |
| 3500 | − int i; | |
| 3501 | − | |
| 3502 | − if (priv->card_type == CARD_TYPE_SPI_FLASH) | |
| 3503 | − atmel_set_gcr(priv->dev, GCR_REMAP); | |
| 3504 | − | |
| 3505 | − /* wake up on-board processor */ | |
| 3506 | − atmel_clear_gcr(priv->dev, 0x0040); | |
| 3507 | − atmel_write16(priv->dev, BSR, BSS_SRAM); | |
| 3508 | − | |
| 3509 | − if (priv->card_type == CARD_TYPE_SPI_FLASH) | |
| 3510 | − mdelay(100); | |
| 3511 | − | |
| 3512 | − /* and wait for it */ | |
| 3513 | − for (i = LOOP_RETRY_LIMIT; i; i--) { | |
| 3514 | − mr1 = atmel_read16(priv->dev, MR1); | |
| 3515 | − mr3 = atmel_read16(priv->dev, MR3); | |
| 3516 | − | |
| 3517 | − if (mr3 & MAC_BOOT_COMPLETE) | |
| 3518 | − break; | |
| 3519 | − if (mr1 & MAC_BOOT_COMPLETE && | |
| 3520 | − priv->bus_type == BUS_TYPE_PCCARD) | |
| 3521 | − break; | |
| 3522 | − } | |
| 3523 | − | |
| 3524 | − if (i == 0) { | |
| 3525 | − printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); | |
| 3526 | − return -EIO; | |
| 3527 | − } | |
| 3528 | − | |
| 3529 | − if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { | |
| 3530 | − printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); | |
| 3531 | − return -ENODEV; | |
| 3532 | − } | |
| 3533 | − | |
| 3534 | − /* now check for completion of MAC initialization through | |
| 3535 | − the FunCtrl field of the IFACE, poll MR1 to detect completion of | |
| 3536 | − MAC initialization, check completion status, set interrupt mask, | |
| 3537 | − enables interrupts and calls Tx and Rx initialization functions */ | |
| 3538 | − | |
| 3539 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); | |
| 3540 | − | |
| 3541 | − for (i = LOOP_RETRY_LIMIT; i; i--) { | |
| 3542 | − mr1 = atmel_read16(priv->dev, MR1); | |
| 3543 | − mr3 = atmel_read16(priv->dev, MR3); | |
| 3544 | − | |
| 3545 | − if (mr3 & MAC_INIT_COMPLETE) | |
| 3546 | − break; | |
| 3547 | − if (mr1 & MAC_INIT_COMPLETE && | |
| 3548 | − priv->bus_type == BUS_TYPE_PCCARD) | |
| 3549 | − break; | |
| 3550 | − } | |
| 3551 | − | |
| 3552 | − if (i == 0) { | |
| 3553 | − printk(KERN_ALERT "%s: MAC failed to initialise.\n", | |
| 3554 | − priv->dev->name); | |
| 3555 | − return -EIO; | |
| 3556 | − } | |
| 3557 | − | |
| 3558 | − /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ | |
| 3559 | − if ((mr3 & MAC_INIT_COMPLETE) && | |
| 3560 | − !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { | |
| 3561 | − printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); | |
| 3562 | − return -EIO; | |
| 3563 | − } | |
| 3564 | − if ((mr1 & MAC_INIT_COMPLETE) && | |
| 3565 | − !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { | |
| 3566 | − printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); | |
| 3567 | − return -EIO; | |
| 3568 | − } | |
| 3569 | − | |
| 3570 | − atmel_copy_to_host(priv->dev, (unsigned char *)iface, | |
| 3571 | − priv->host_info_base, sizeof(*iface)); | |
| 3572 | − | |
| 3573 | − iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); | |
| 3574 | − iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); | |
| 3575 | − iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); | |
| 3576 | − iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); | |
| 3577 | − iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); | |
| 3578 | − iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); | |
| 3579 | − iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); | |
| 3580 | − iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); | |
| 3581 | − iface->build_version = le16_to_cpu(iface->build_version); | |
| 3582 | − iface->command_pos = le16_to_cpu(iface->command_pos); | |
| 3583 | − iface->major_version = le16_to_cpu(iface->major_version); | |
| 3584 | − iface->minor_version = le16_to_cpu(iface->minor_version); | |
| 3585 | − iface->func_ctrl = le16_to_cpu(iface->func_ctrl); | |
| 3586 | − iface->mac_status = le16_to_cpu(iface->mac_status); | |
| 3587 | − | |
| 3588 | − return 0; | |
| 3589 | −} | |
| 3590 | − | |
| 3591 | −/* determine type of memory and MAC address */ | |
| 3592 | −static int probe_atmel_card(struct net_device *dev) | |
| 3593 | −{ | |
| 3594 | − int rc = 0; | |
| 3595 | − struct atmel_private *priv = netdev_priv(dev); | |
| 3596 | − u8 addr[ETH_ALEN] = {}; | |
| 3597 | − | |
| 3598 | − /* reset pccard */ | |
| 3599 | − if (priv->bus_type == BUS_TYPE_PCCARD) | |
| 3600 | − atmel_write16(dev, GCR, 0x0060); | |
| 3601 | − | |
| 3602 | − atmel_write16(dev, GCR, 0x0040); | |
| 3603 | − msleep(500); | |
| 3604 | − | |
| 3605 | − if (atmel_read16(dev, MR2) == 0) { | |
| 3606 | − /* No stored firmware so load a small stub which just | |
| 3607 | − tells us the MAC address */ | |
| 3608 | − int i; | |
| 3609 | − priv->card_type = CARD_TYPE_EEPROM; | |
| 3610 | − atmel_write16(dev, BSR, BSS_IRAM); | |
| 3611 | − atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); | |
| 3612 | − atmel_set_gcr(dev, GCR_REMAP); | |
| 3613 | − atmel_clear_gcr(priv->dev, 0x0040); | |
| 3614 | − atmel_write16(dev, BSR, BSS_SRAM); | |
| 3615 | − for (i = LOOP_RETRY_LIMIT; i; i--) | |
| 3616 | − if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) | |
| 3617 | − break; | |
| 3618 | − if (i == 0) { | |
| 3619 | − printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); | |
| 3620 | − } else { | |
| 3621 | − | |
| 3622 | − atmel_copy_to_host(dev, addr, atmel_read16(dev, MR2), 6); | |
| 3623 | − eth_hw_addr_set(dev, addr); | |
| 3624 | − /* got address, now squash it again until the network | |
| 3625 | − interface is opened */ | |
| 3626 | − if (priv->bus_type == BUS_TYPE_PCCARD) | |
| 3627 | − atmel_write16(dev, GCR, 0x0060); | |
| 3628 | − atmel_write16(dev, GCR, 0x0040); | |
| 3629 | − rc = 1; | |
| 3630 | − } | |
| 3631 | − } else if (atmel_read16(dev, MR4) == 0) { | |
| 3632 | − /* Mac address easy in this case. */ | |
| 3633 | − priv->card_type = CARD_TYPE_PARALLEL_FLASH; | |
| 3634 | − atmel_write16(dev, BSR, 1); | |
| 3635 | − atmel_copy_to_host(dev, addr, 0xc000, 6); | |
| 3636 | − eth_hw_addr_set(dev, addr); | |
| 3637 | − atmel_write16(dev, BSR, 0x200); | |
| 3638 | − rc = 1; | |
| 3639 | − } else { | |
| 3640 | − /* Standard firmware in flash, boot it up and ask | |
| 3641 | − for the Mac Address */ | |
| 3642 | − priv->card_type = CARD_TYPE_SPI_FLASH; | |
| 3643 | − if (atmel_wakeup_firmware(priv) == 0) { | |
| 3644 | − atmel_get_mib(priv, Mac_Address_Mib_Type, 0, addr, 6); | |
| 3645 | − eth_hw_addr_set(dev, addr); | |
| 3646 | − | |
| 3647 | − /* got address, now squash it again until the network | |
| 3648 | − interface is opened */ | |
| 3649 | − if (priv->bus_type == BUS_TYPE_PCCARD) | |
| 3650 | − atmel_write16(dev, GCR, 0x0060); | |
| 3651 | − atmel_write16(dev, GCR, 0x0040); | |
| 3652 | − rc = 1; | |
| 3653 | − } | |
| 3654 | − } | |
| 3655 | − | |
| 3656 | − if (rc) { | |
| 3657 | − if (dev->dev_addr[0] == 0xFF) { | |
| 3658 | − static const u8 default_mac[] = { | |
| 3659 | − 0x00, 0x04, 0x25, 0x00, 0x00, 0x00 | |
| 3660 | − }; | |
| 3661 | − printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); | |
| 3662 | − eth_hw_addr_set(dev, default_mac); | |
| 3663 | − } | |
| 3664 | − } | |
| 3665 | − | |
| 3666 | − return rc; | |
| 3667 | −} | |
| 3668 | − | |
| 3669 | −/* Move the encyption information on the MIB structure. | |
| 3670 | − This routine is for the pre-WPA firmware: later firmware has | |
| 3671 | − a different format MIB and a different routine. */ | |
| 3672 | −static void build_wep_mib(struct atmel_private *priv) | |
| 3673 | −{ | |
| 3674 | − struct { /* NB this is matched to the hardware, don't change. */ | |
| 3675 | − u8 wep_is_on; | |
| 3676 | − u8 default_key; /* 0..3 */ | |
| 3677 | − u8 reserved; | |
| 3678 | − u8 exclude_unencrypted; | |
| 3679 | − | |
| 3680 | − u32 WEPICV_error_count; | |
| 3681 | − u32 WEP_excluded_count; | |
| 3682 | − | |
| 3683 | − u8 wep_keys[MAX_ENCRYPTION_KEYS][13]; | |
| 3684 | − u8 encryption_level; /* 0, 1, 2 */ | |
| 3685 | − u8 reserved2[3]; | |
| 3686 | − } mib; | |
| 3687 | − int i; | |
| 3688 | − | |
| 3689 | − mib.wep_is_on = priv->wep_is_on; | |
| 3690 | − if (priv->wep_is_on) { | |
| 3691 | − if (priv->wep_key_len[priv->default_key] > 5) | |
| 3692 | − mib.encryption_level = 2; | |
| 3693 | − else | |
| 3694 | − mib.encryption_level = 1; | |
| 3695 | − } else { | |
| 3696 | − mib.encryption_level = 0; | |
| 3697 | − } | |
| 3698 | − | |
| 3699 | − mib.default_key = priv->default_key; | |
| 3700 | − mib.exclude_unencrypted = priv->exclude_unencrypted; | |
| 3701 | − | |
| 3702 | − for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) | |
| 3703 | − memcpy(mib.wep_keys[i], priv->wep_keys[i], 13); | |
| 3704 | − | |
| 3705 | − atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); | |
| 3706 | −} | |
| 3707 | − | |
| 3708 | −static void build_wpa_mib(struct atmel_private *priv) | |
| 3709 | −{ | |
| 3710 | − /* This is for the later (WPA enabled) firmware. */ | |
| 3711 | − | |
| 3712 | − struct { /* NB this is matched to the hardware, don't change. */ | |
| 3713 | − u8 cipher_default_key_value[MAX_ENCRYPTION_KEYS][MAX_ENCRYPTION_KEY_SIZE]; | |
| 3714 | − u8 receiver_address[ETH_ALEN]; | |
| 3715 | − u8 wep_is_on; | |
| 3716 | − u8 default_key; /* 0..3 */ | |
| 3717 | − u8 group_key; | |
| 3718 | − u8 exclude_unencrypted; | |
| 3719 | − u8 encryption_type; | |
| 3720 | − u8 reserved; | |
| 3721 | − | |
| 3722 | − u32 WEPICV_error_count; | |
| 3723 | − u32 WEP_excluded_count; | |
| 3724 | − | |
| 3725 | − u8 key_RSC[4][8]; | |
| 3726 | − } mib; | |
| 3727 | − | |
| 3728 | − int i; | |
| 3729 | − | |
| 3730 | − mib.wep_is_on = priv->wep_is_on; | |
| 3731 | − mib.exclude_unencrypted = priv->exclude_unencrypted; | |
| 3732 | − memcpy(mib.receiver_address, priv->CurrentBSSID, ETH_ALEN); | |
| 3733 | − | |
| 3734 | − /* zero all the keys before adding in valid ones. */ | |
| 3735 | − memset(mib.cipher_default_key_value, 0, sizeof(mib.cipher_default_key_value)); | |
| 3736 | − | |
| 3737 | − if (priv->wep_is_on) { | |
| 3738 | − /* There's a comment in the Atmel code to the effect that this | |
| 3739 | − is only valid when still using WEP, it may need to be set to | |
| 3740 | − something to use WPA */ | |
| 3741 | − memset(mib.key_RSC, 0, sizeof(mib.key_RSC)); | |
| 3742 | − | |
| 3743 | − mib.default_key = mib.group_key = 255; | |
| 3744 | − for (i = 0; i < MAX_ENCRYPTION_KEYS; i++) { | |
| 3745 | − if (priv->wep_key_len[i] > 0) { | |
| 3746 | − memcpy(mib.cipher_default_key_value[i], priv->wep_keys[i], MAX_ENCRYPTION_KEY_SIZE); | |
| 3747 | − if (i == priv->default_key) { | |
| 3748 | − mib.default_key = i; | |
| 3749 | − mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 7; | |
| 3750 | − mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->pairwise_cipher_suite; | |
| 3751 | − } else { | |
| 3752 | − mib.group_key = i; | |
| 3753 | − priv->group_cipher_suite = priv->pairwise_cipher_suite; | |
| 3754 | − mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1; | |
| 3755 | − mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite; | |
| 3756 | − } | |
| 3757 | − } | |
| 3758 | − } | |
| 3759 | − if (mib.default_key == 255) | |
| 3760 | − mib.default_key = mib.group_key != 255 ? mib.group_key : 0; | |
| 3761 | − if (mib.group_key == 255) | |
| 3762 | − mib.group_key = mib.default_key; | |
| 3763 | − | |
| 3764 | − } | |
| 3765 | − | |
| 3766 | − atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&mib, sizeof(mib)); | |
| 3767 | −} | |
| 3768 | − | |
| 3769 | −static int reset_atmel_card(struct net_device *dev) | |
| 3770 | −{ | |
| 3771 | − /* do everything necessary to wake up the hardware, including | |
| 3772 | − waiting for the lightning strike and throwing the knife switch.... | |
| 3773 | − | |
| 3774 | − set all the Mib values which matter in the card to match | |
| 3775 | − their settings in the atmel_private structure. Some of these | |
| 3776 | − can be altered on the fly, but many (WEP, infrastructure or ad-hoc) | |
| 3777 | − can only be changed by tearing down the world and coming back through | |
| 3778 | − here. | |
| 3779 | − | |
| 3780 | − This routine is also responsible for initialising some | |
| 3781 | − hardware-specific fields in the atmel_private structure, | |
| 3782 | − including a copy of the firmware's hostinfo structure | |
| 3783 | − which is the route into the rest of the firmware datastructures. */ | |
| 3784 | − | |
| 3785 | − struct atmel_private *priv = netdev_priv(dev); | |
| 3786 | − u8 configuration; | |
| 3787 | − int old_state = priv->station_state; | |
| 3788 | − int err = 0; | |
| 3789 | − | |
| 3790 | − /* data to add to the firmware names, in priority order | |
| 3791 | − this implemenents firmware versioning */ | |
| 3792 | − | |
| 3793 | − static char *firmware_modifier[] = { | |
| 3794 | − "-wpa", | |
| 3795 | − "", | |
| 3796 | − NULL | |
| 3797 | − }; | |
| 3798 | − | |
| 3799 | − /* reset pccard */ | |
| 3800 | − if (priv->bus_type == BUS_TYPE_PCCARD) | |
| 3801 | − atmel_write16(priv->dev, GCR, 0x0060); | |
| 3802 | − | |
| 3803 | − /* stop card , disable interrupts */ | |
| 3804 | − atmel_write16(priv->dev, GCR, 0x0040); | |
| 3805 | − | |
| 3806 | − if (priv->card_type == CARD_TYPE_EEPROM) { | |
| 3807 | − /* copy in firmware if needed */ | |
| 3808 | − const struct firmware *fw_entry = NULL; | |
| 3809 | − const unsigned char *fw; | |
| 3810 | − int len = priv->firmware_length; | |
| 3811 | − if (!(fw = priv->firmware)) { | |
| 3812 | − if (priv->firmware_type == ATMEL_FW_TYPE_NONE) { | |
| 3813 | − if (strlen(priv->firmware_id) == 0) { | |
| 3814 | − printk(KERN_INFO | |
| 3815 | − "%s: card type is unknown: assuming at76c502 firmware is OK.\n", | |
| 3816 | − dev->name); | |
| 3817 | − printk(KERN_INFO | |
| 3818 | − "%s: if not, use the firmware= module parameter.\n", | |
| 3819 | − dev->name); | |
| 3820 | − strcpy(priv->firmware_id, "atmel_at76c502.bin"); | |
| 3821 | − } | |
| 3822 | − err = request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev); | |
| 3823 | − if (err != 0) { | |
| 3824 | − printk(KERN_ALERT | |
| 3825 | − "%s: firmware %s is missing, cannot continue.\n", | |
| 3826 | − dev->name, priv->firmware_id); | |
| 3827 | − return err; | |
| 3828 | − } | |
| 3829 | − } else { | |
| 3830 | − int fw_index = 0; | |
| 3831 | − int success = 0; | |
| 3832 | − | |
| 3833 | − /* get firmware filename entry based on firmware type ID */ | |
| 3834 | − while (fw_table[fw_index].fw_type != priv->firmware_type | |
| 3835 | − && fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) | |
| 3836 | − fw_index++; | |
| 3837 | − | |
| 3838 | − /* construct the actual firmware file name */ | |
| 3839 | − if (fw_table[fw_index].fw_type != ATMEL_FW_TYPE_NONE) { | |
| 3840 | − int i; | |
| 3841 | − for (i = 0; firmware_modifier[i]; i++) { | |
| 3842 | − snprintf(priv->firmware_id, 32, "%s%s.%s", fw_table[fw_index].fw_file, | |
| 3843 | − firmware_modifier[i], fw_table[fw_index].fw_file_ext); | |
| 3844 | − priv->firmware_id[31] = '\0'; | |
| 3845 | − if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) == 0) { | |
| 3846 | − success = 1; | |
| 3847 | − break; | |
| 3848 | − } | |
| 3849 | − } | |
| 3850 | − } | |
| 3851 | − if (!success) { | |
| 3852 | − printk(KERN_ALERT | |
| 3853 | − "%s: firmware %s is missing, cannot start.\n", | |
| 3854 | − dev->name, priv->firmware_id); | |
| 3855 | − priv->firmware_id[0] = '\0'; | |
| 3856 | − return -ENOENT; | |
| 3857 | − } | |
| 3858 | − } | |
| 3859 | − | |
| 3860 | − fw = fw_entry->data; | |
| 3861 | − len = fw_entry->size; | |
| 3862 | − } | |
| 3863 | − | |
| 3864 | − if (len <= 0x6000) { | |
| 3865 | − atmel_write16(priv->dev, BSR, BSS_IRAM); | |
| 3866 | − atmel_copy_to_card(priv->dev, 0, fw, len); | |
| 3867 | − atmel_set_gcr(priv->dev, GCR_REMAP); | |
| 3868 | − } else { | |
| 3869 | − /* Remap */ | |
| 3870 | − atmel_set_gcr(priv->dev, GCR_REMAP); | |
| 3871 | − atmel_write16(priv->dev, BSR, BSS_IRAM); | |
| 3872 | − atmel_copy_to_card(priv->dev, 0, fw, 0x6000); | |
| 3873 | − atmel_write16(priv->dev, BSR, 0x2ff); | |
| 3874 | − atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); | |
| 3875 | − } | |
| 3876 | − | |
| 3877 | − release_firmware(fw_entry); | |
| 3878 | − } | |
| 3879 | − | |
| 3880 | − err = atmel_wakeup_firmware(priv); | |
| 3881 | − if (err != 0) | |
| 3882 | − return err; | |
| 3883 | − | |
| 3884 | − /* Check the version and set the correct flag for wpa stuff, | |
| 3885 | − old and new firmware is incompatible. | |
| 3886 | − The pre-wpa 3com firmware reports major version 5, | |
| 3887 | − the wpa 3com firmware is major version 4 and doesn't need | |
| 3888 | − the 3com broken-ness filter. */ | |
| 3889 | − priv->use_wpa = (priv->host_info.major_version == 4); | |
| 3890 | − priv->radio_on_broken = (priv->host_info.major_version == 5); | |
| 3891 | − | |
| 3892 | − /* unmask all irq sources */ | |
| 3893 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); | |
| 3894 | − | |
| 3895 | − /* int Tx system and enable Tx */ | |
| 3896 | − atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); | |
| 3897 | − atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); | |
| 3898 | − atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); | |
| 3899 | − atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); | |
| 3900 | − | |
| 3901 | − priv->tx_desc_free = priv->host_info.tx_desc_count; | |
| 3902 | − priv->tx_desc_head = 0; | |
| 3903 | − priv->tx_desc_tail = 0; | |
| 3904 | − priv->tx_desc_previous = 0; | |
| 3905 | − priv->tx_free_mem = priv->host_info.tx_buff_size; | |
| 3906 | − priv->tx_buff_head = 0; | |
| 3907 | − priv->tx_buff_tail = 0; | |
| 3908 | − | |
| 3909 | − configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); | |
| 3910 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), | |
| 3911 | − configuration | FUNC_CTRL_TxENABLE); | |
| 3912 | − | |
| 3913 | − /* init Rx system and enable */ | |
| 3914 | − priv->rx_desc_head = 0; | |
| 3915 | − | |
| 3916 | − configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); | |
| 3917 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), | |
| 3918 | − configuration | FUNC_CTRL_RxENABLE); | |
| 3919 | − | |
| 3920 | − if (!priv->radio_on_broken) { | |
| 3921 | − if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == | |
| 3922 | − CMD_STATUS_REJECTED_RADIO_OFF) { | |
| 3923 | − printk(KERN_INFO "%s: cannot turn the radio on.\n", | |
| 3924 | − dev->name); | |
| 3925 | − return -EIO; | |
| 3926 | − } | |
| 3927 | − } | |
| 3928 | − | |
| 3929 | − /* set up enough MIB values to run. */ | |
| 3930 | − atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); | |
| 3931 | − atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); | |
| 3932 | − atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); | |
| 3933 | − atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); | |
| 3934 | − atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); | |
| 3935 | − atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); | |
| 3936 | − atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); | |
| 3937 | − atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, | |
| 3938 | − priv->dev->dev_addr, 6); | |
| 3939 | − atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); | |
| 3940 | − atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); | |
| 3941 | − atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); | |
| 3942 | − atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); | |
| 3943 | − atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep_is_on); | |
| 3944 | − if (priv->use_wpa) | |
| 3945 | − build_wpa_mib(priv); | |
| 3946 | − else | |
| 3947 | − build_wep_mib(priv); | |
| 3948 | − | |
| 3949 | − if (old_state == STATION_STATE_READY) { | |
| 3950 | − union iwreq_data wrqu; | |
| 3951 | − | |
| 3952 | − wrqu.data.length = 0; | |
| 3953 | − wrqu.data.flags = 0; | |
| 3954 | − wrqu.ap_addr.sa_family = ARPHRD_ETHER; | |
| 3955 | − eth_zero_addr(wrqu.ap_addr.sa_data); | |
| 3956 | − wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); | |
| 3957 | − } | |
| 3958 | − | |
| 3959 | − return 0; | |
| 3960 | −} | |
| 3961 | − | |
| 3962 | −static void atmel_send_command(struct atmel_private *priv, int command, | |
| 3963 | − void *cmd, int cmd_size) | |
| 3964 | −{ | |
| 3965 | − if (cmd) | |
| 3966 | − atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), | |
| 3967 | − cmd, cmd_size); | |
| 3968 | − | |
| 3969 | − atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); | |
| 3970 | − atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); | |
| 3971 | −} | |
| 3972 | − | |
| 3973 | −static int atmel_send_command_wait(struct atmel_private *priv, int command, | |
| 3974 | − void *cmd, int cmd_size) | |
| 3975 | −{ | |
| 3976 | − int i, status; | |
| 3977 | − | |
| 3978 | − atmel_send_command(priv, command, cmd, cmd_size); | |
| 3979 | − | |
| 3980 | − for (i = 5000; i; i--) { | |
| 3981 | − status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); | |
| 3982 | − if (status != CMD_STATUS_IDLE && | |
| 3983 | − status != CMD_STATUS_IN_PROGRESS) | |
| 3984 | − break; | |
| 3985 | − udelay(20); | |
| 3986 | − } | |
| 3987 | − | |
| 3988 | − if (i == 0) { | |
| 3989 | − printk(KERN_ALERT "%s: failed to contact MAC.\n", priv->dev->name); | |
| 3990 | − status = CMD_STATUS_HOST_ERROR; | |
| 3991 | − } else { | |
| 3992 | − if (command != CMD_EnableRadio) | |
| 3993 | − status = CMD_STATUS_COMPLETE; | |
| 3994 | − } | |
| 3995 | − | |
| 3996 | − return status; | |
| 3997 | −} | |
| 3998 | − | |
| 3999 | −static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) | |
| 4000 | −{ | |
| 4001 | − struct get_set_mib m; | |
| 4002 | − m.type = type; | |
| 4003 | − m.size = 1; | |
| 4004 | − m.index = index; | |
| 4005 | − | |
| 4006 | − atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + 1); | |
| 4007 | − return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE)); | |
| 4008 | −} | |
| 4009 | − | |
| 4010 | −static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) | |
| 4011 | −{ | |
| 4012 | − struct get_set_mib m; | |
| 4013 | − m.type = type; | |
| 4014 | − m.size = 1; | |
| 4015 | − m.index = index; | |
| 4016 | − m.data[0] = data; | |
| 4017 | − | |
| 4018 | − atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 1); | |
| 4019 | −} | |
| 4020 | − | |
| 4021 | −static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, | |
| 4022 | − u16 data) | |
| 4023 | −{ | |
| 4024 | − struct get_set_mib m; | |
| 4025 | − m.type = type; | |
| 4026 | − m.size = 2; | |
| 4027 | − m.index = index; | |
| 4028 | − m.data[0] = data; | |
| 4029 | − m.data[1] = data >> 8; | |
| 4030 | − | |
| 4031 | − atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + 2); | |
| 4032 | −} | |
| 4033 | − | |
| 4034 | −static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, | |
| 4035 | − const u8 *data, int data_len) | |
| 4036 | −{ | |
| 4037 | − struct get_set_mib m; | |
| 4038 | − m.type = type; | |
| 4039 | − m.size = data_len; | |
| 4040 | − m.index = index; | |
| 4041 | − | |
| 4042 | − if (data_len > MIB_MAX_DATA_BYTES) | |
| 4043 | − printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); | |
| 4044 | − | |
| 4045 | − memcpy(m.data, data, data_len); | |
| 4046 | − atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); | |
| 4047 | −} | |
| 4048 | − | |
| 4049 | −static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, | |
| 4050 | − u8 *data, int data_len) | |
| 4051 | −{ | |
| 4052 | − struct get_set_mib m; | |
| 4053 | − m.type = type; | |
| 4054 | − m.size = data_len; | |
| 4055 | − m.index = index; | |
| 4056 | − | |
| 4057 | − if (data_len > MIB_MAX_DATA_BYTES) | |
| 4058 | − printk(KERN_ALERT "%s: MIB buffer too small.\n", priv->dev->name); | |
| 4059 | − | |
| 4060 | − atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, MIB_HEADER_SIZE + data_len); | |
| 4061 | − atmel_copy_to_host(priv->dev, data, | |
| 4062 | − atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + MIB_HEADER_SIZE), data_len); | |
| 4063 | −} | |
| 4064 | − | |
| 4065 | −static void atmel_writeAR(struct net_device *dev, u16 data) | |
| 4066 | −{ | |
| 4067 | − int i; | |
| 4068 | − outw(data, dev->base_addr + AR); | |
| 4069 | − /* Address register appears to need some convincing..... */ | |
| 4070 | − for (i = 0; data != inw(dev->base_addr + AR) && i < 10; i++) | |
| 4071 | − outw(data, dev->base_addr + AR); | |
| 4072 | −} | |
| 4073 | − | |
| 4074 | −static void atmel_copy_to_card(struct net_device *dev, u16 dest, | |
| 4075 | − const unsigned char *src, u16 len) | |
| 4076 | −{ | |
| 4077 | − int i; | |
| 4078 | − atmel_writeAR(dev, dest); | |
| 4079 | − if (dest % 2) { | |
| 4080 | − atmel_write8(dev, DR, *src); | |
| 4081 | − src++; len--; | |
| 4082 | − } | |
| 4083 | − for (i = len; i > 1 ; i -= 2) { | |
| 4084 | − u8 lb = *src++; | |
| 4085 | − u8 hb = *src++; | |
| 4086 | − atmel_write16(dev, DR, lb | (hb << 8)); | |
| 4087 | − } | |
| 4088 | − if (i) | |
| 4089 | − atmel_write8(dev, DR, *src); | |
| 4090 | −} | |
| 4091 | − | |
| 4092 | −static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, | |
| 4093 | − u16 src, u16 len) | |
| 4094 | −{ | |
| 4095 | − int i; | |
| 4096 | − atmel_writeAR(dev, src); | |
| 4097 | − if (src % 2) { | |
| 4098 | − *dest = atmel_read8(dev, DR); | |
| 4099 | − dest++; len--; | |
| 4100 | − } | |
| 4101 | − for (i = len; i > 1 ; i -= 2) { | |
| 4102 | − u16 hw = atmel_read16(dev, DR); | |
| 4103 | − *dest++ = hw; | |
| 4104 | − *dest++ = hw >> 8; | |
| 4105 | − } | |
| 4106 | − if (i) | |
| 4107 | − *dest = atmel_read8(dev, DR); | |
| 4108 | −} | |
| 4109 | − | |
| 4110 | −static void atmel_set_gcr(struct net_device *dev, u16 mask) | |
| 4111 | −{ | |
| 4112 | − outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); | |
| 4113 | −} | |
| 4114 | − | |
| 4115 | −static void atmel_clear_gcr(struct net_device *dev, u16 mask) | |
| 4116 | −{ | |
| 4117 | − outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); | |
| 4118 | −} | |
| 4119 | − | |
| 4120 | −static int atmel_lock_mac(struct atmel_private *priv) | |
| 4121 | −{ | |
| 4122 | − int i, j = 20; | |
| 4123 | − retry: | |
| 4124 | − for (i = 5000; i; i--) { | |
| 4125 | − if (!atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) | |
| 4126 | − break; | |
| 4127 | − udelay(20); | |
| 4128 | − } | |
| 4129 | − | |
| 4130 | − if (!i) | |
| 4131 | − return 0; /* timed out */ | |
| 4132 | − | |
| 4133 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); | |
| 4134 | − if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { | |
| 4135 | − atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); | |
| 4136 | − if (!j--) | |
| 4137 | − return 0; /* timed out */ | |
| 4138 | − goto retry; | |
| 4139 | − } | |
| 4140 | − | |
| 4141 | − return 1; | |
| 4142 | −} | |
| 4143 | − | |
| 4144 | −static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) | |
| 4145 | −{ | |
| 4146 | − atmel_writeAR(priv->dev, pos); | |
| 4147 | − atmel_write16(priv->dev, DR, data); /* card is little-endian */ | |
| 4148 | − atmel_write16(priv->dev, DR, data >> 16); | |
| 4149 | −} | |
| 4150 | − | |
| 4151 | −/***************************************************************************/ | |
| 4152 | −/* There follows the source form of the MAC address reading firmware */ | |
| 4153 | −/***************************************************************************/ | |
| 4154 | −#if 0 | |
| 4155 | − | |
| 4156 | −/* Copyright 2003 Matthew T. Russotto */ | |
| 4157 | −/* But derived from the Atmel 76C502 firmware written by Atmel and */ | |
| 4158 | −/* included in "atmel wireless lan drivers" package */ | |
| 4159 | −/* | |
| 4160 | − This file is part of net.russotto.AtmelMACFW, hereto referred to | |
| 4161 | − as AtmelMACFW | |
| 4162 | − | |
| 4163 | − AtmelMACFW is free software; you can redistribute it and/or modify | |
| 4164 | − it under the terms of the GNU General Public License version 2 | |
| 4165 | − as published by the Free Software Foundation. | |
| 4166 | − | |
| 4167 | − AtmelMACFW is distributed in the hope that it will be useful, | |
| 4168 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 4169 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 4170 | − GNU General Public License for more details. | |
| 4171 | − | |
| 4172 | − You should have received a copy of the GNU General Public License | |
| 4173 | − along with AtmelMACFW; if not, see <http://www.gnu.org/licenses/>. | |
| 4174 | − | |
| 4175 | −****************************************************************************/ | |
| 4176 | −/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ | |
| 4177 | −/* It will probably work on the 76C504 and 76C502 RFMD_3COM */ | |
| 4178 | −/* It only works on SPI EEPROM versions of the card. */ | |
| 4179 | − | |
| 4180 | −/* This firmware initializes the SPI controller and clock, reads the MAC */ | |
| 4181 | −/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ | |
| 4182 | −/* address in MR2, and sets MR3 to 0x10 to indicate it is done */ | |
| 4183 | −/* It also puts a complete copy of the EEPROM in SRAM with the offset in */ | |
| 4184 | −/* MR4, for investigational purposes (maybe we can determine chip type */ | |
| 4185 | −/* from that?) */ | |
| 4186 | − | |
| 4187 | − .org 0 | |
| 4188 | − .set MRBASE, 0x8000000 | |
| 4189 | − .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ | |
| 4190 | − .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ | |
| 4191 | − .set SRAM_BASE, 0x02000000 | |
| 4192 | − .set SP_BASE, 0x0F300000 | |
| 4193 | − .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ | |
| 4194 | − .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ | |
| 4195 | − .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ | |
| 4196 | − .set STACK_BASE, 0x5600 | |
| 4197 | − .set SP_SR, 0x10 | |
| 4198 | − .set SP_TDRE, 2 /* status register bit -- TDR empty */ | |
| 4199 | − .set SP_RDRF, 1 /* status register bit -- RDR full */ | |
| 4200 | − .set SP_SWRST, 0x80 | |
| 4201 | − .set SP_SPIEN, 0x1 | |
| 4202 | − .set SP_CR, 0 /* control register */ | |
| 4203 | − .set SP_MR, 4 /* mode register */ | |
| 4204 | − .set SP_RDR, 0x08 /* Read Data Register */ | |
| 4205 | − .set SP_TDR, 0x0C /* Transmit Data Register */ | |
| 4206 | − .set SP_CSR0, 0x30 /* chip select registers */ | |
| 4207 | − .set SP_CSR1, 0x34 | |
| 4208 | − .set SP_CSR2, 0x38 | |
| 4209 | − .set SP_CSR3, 0x3C | |
| 4210 | − .set NVRAM_CMD_RDSR, 5 /* read status register */ | |
| 4211 | − .set NVRAM_CMD_READ, 3 /* read data */ | |
| 4212 | − .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ | |
| 4213 | − .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the | |
| 4214 | − serial output, since SO is normally high. But it | |
| 4215 | − does cause 8 clock cycles and thus 8 bits to be | |
| 4216 | − clocked in to the chip. See Atmel's SPI | |
| 4217 | − controller (e.g. AT91M55800) timing and 4K | |
| 4218 | − SPI EEPROM manuals */ | |
| 4219 | − | |
| 4220 | − .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ | |
| 4221 | − .set NVRAM_IMAGE, 0x02000200 | |
| 4222 | − .set NVRAM_LENGTH, 0x0200 | |
| 4223 | − .set MAC_ADDRESS_MIB, SRAM_BASE | |
| 4224 | − .set MAC_ADDRESS_LENGTH, 6 | |
| 4225 | − .set MAC_BOOT_FLAG, 0x10 | |
| 4226 | − .set MR1, 0 | |
| 4227 | − .set MR2, 4 | |
| 4228 | − .set MR3, 8 | |
| 4229 | − .set MR4, 0xC | |
| 4230 | −RESET_VECTOR: | |
| 4231 | − b RESET_HANDLER | |
| 4232 | −UNDEF_VECTOR: | |
| 4233 | − b HALT1 | |
| 4234 | −SWI_VECTOR: | |
| 4235 | − b HALT1 | |
| 4236 | −IABORT_VECTOR: | |
| 4237 | − b HALT1 | |
| 4238 | −DABORT_VECTOR: | |
| 4239 | −RESERVED_VECTOR: | |
| 4240 | − b HALT1 | |
| 4241 | −IRQ_VECTOR: | |
| 4242 | − b HALT1 | |
| 4243 | −FIQ_VECTOR: | |
| 4244 | − b HALT1 | |
| 4245 | −HALT1: b HALT1 | |
| 4246 | −RESET_HANDLER: | |
| 4247 | − mov r0, #CPSR_INITIAL | |
| 4248 | − msr CPSR_c, r0 /* This is probably unnecessary */ | |
| 4249 | − | |
| 4250 | −/* I'm guessing this is initializing clock generator electronics for SPI */ | |
| 4251 | − ldr r0, =SPI_CGEN_BASE | |
| 4252 | − mov r1, #0 | |
| 4253 | − mov r1, r1, lsl #3 | |
| 4254 | − orr r1, r1, #0 | |
| 4255 | − str r1, [r0] | |
| 4256 | − ldr r1, [r0, #28] | |
| 4257 | − bic r1, r1, #16 | |
| 4258 | − str r1, [r0, #28] | |
| 4259 | − mov r1, #1 | |
| 4260 | − str r1, [r0, #8] | |
| 4261 | − | |
| 4262 | − ldr r0, =MRBASE | |
| 4263 | − mov r1, #0 | |
| 4264 | − strh r1, [r0, #MR1] | |
| 4265 | − strh r1, [r0, #MR2] | |
| 4266 | − strh r1, [r0, #MR3] | |
| 4267 | − strh r1, [r0, #MR4] | |
| 4268 | − | |
| 4269 | − mov sp, #STACK_BASE | |
| 4270 | − bl SP_INIT | |
| 4271 | − mov r0, #10 | |
| 4272 | − bl DELAY9 | |
| 4273 | − bl GET_MAC_ADDR | |
| 4274 | − bl GET_WHOLE_NVRAM | |
| 4275 | − ldr r0, =MRBASE | |
| 4276 | − ldr r1, =MAC_ADDRESS_MIB | |
| 4277 | − strh r1, [r0, #MR2] | |
| 4278 | − ldr r1, =NVRAM_IMAGE | |
| 4279 | − strh r1, [r0, #MR4] | |
| 4280 | − mov r1, #MAC_BOOT_FLAG | |
| 4281 | − strh r1, [r0, #MR3] | |
| 4282 | −HALT2: b HALT2 | |
| 4283 | −.func Get_Whole_NVRAM, GET_WHOLE_NVRAM | |
| 4284 | −GET_WHOLE_NVRAM: | |
| 4285 | − stmdb sp!, {lr} | |
| 4286 | − mov r2, #0 /* 0th bytes of NVRAM */ | |
| 4287 | − mov r3, #NVRAM_LENGTH | |
| 4288 | − mov r1, #0 /* not used in routine */ | |
| 4289 | − ldr r0, =NVRAM_IMAGE | |
| 4290 | − bl NVRAM_XFER | |
| 4291 | − ldmia sp!, {lr} | |
| 4292 | − bx lr | |
| 4293 | −.endfunc | |
| 4294 | − | |
| 4295 | −.func Get_MAC_Addr, GET_MAC_ADDR | |
| 4296 | −GET_MAC_ADDR: | |
| 4297 | − stmdb sp!, {lr} | |
| 4298 | − mov r2, #0x120 /* address of MAC Address within NVRAM */ | |
| 4299 | − mov r3, #MAC_ADDRESS_LENGTH | |
| 4300 | − mov r1, #0 /* not used in routine */ | |
| 4301 | − ldr r0, =MAC_ADDRESS_MIB | |
| 4302 | − bl NVRAM_XFER | |
| 4303 | − ldmia sp!, {lr} | |
| 4304 | − bx lr | |
| 4305 | −.endfunc | |
| 4306 | −.ltorg | |
| 4307 | −.func Delay9, DELAY9 | |
| 4308 | −DELAY9: | |
| 4309 | − adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ | |
| 4310 | −DELAYLOOP: | |
| 4311 | − beq DELAY9_done | |
| 4312 | − subs r0, r0, #1 | |
| 4313 | − b DELAYLOOP | |
| 4314 | −DELAY9_done: | |
| 4315 | − bx lr | |
| 4316 | −.endfunc | |
| 4317 | − | |
| 4318 | −.func SP_Init, SP_INIT | |
| 4319 | −SP_INIT: | |
| 4320 | − mov r1, #SP_SWRST | |
| 4321 | − ldr r0, =SP_BASE | |
| 4322 | − str r1, [r0, #SP_CR] /* reset the SPI */ | |
| 4323 | − mov r1, #0 | |
| 4324 | − str r1, [r0, #SP_CR] /* release SPI from reset state */ | |
| 4325 | − mov r1, #SP_SPIEN | |
| 4326 | − str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ | |
| 4327 | − str r1, [r0, #SP_CR] /* enable the SPI */ | |
| 4328 | − | |
| 4329 | −/* My guess would be this turns on the SPI clock */ | |
| 4330 | − ldr r3, =SPI_CGEN_BASE | |
| 4331 | − ldr r1, [r3, #28] | |
| 4332 | − orr r1, r1, #0x2000 | |
| 4333 | − str r1, [r3, #28] | |
| 4334 | − | |
| 4335 | − ldr r1, =0x2000c01 | |
| 4336 | − str r1, [r0, #SP_CSR0] | |
| 4337 | − ldr r1, =0x2000201 | |
| 4338 | − str r1, [r0, #SP_CSR1] | |
| 4339 | − str r1, [r0, #SP_CSR2] | |
| 4340 | − str r1, [r0, #SP_CSR3] | |
| 4341 | − ldr r1, [r0, #SP_SR] | |
| 4342 | − ldr r0, [r0, #SP_RDR] | |
| 4343 | − bx lr | |
| 4344 | −.endfunc | |
| 4345 | −.func NVRAM_Init, NVRAM_INIT | |
| 4346 | −NVRAM_INIT: | |
| 4347 | − ldr r1, =SP_BASE | |
| 4348 | − ldr r0, [r1, #SP_RDR] | |
| 4349 | − mov r0, #NVRAM_CMD_RDSR | |
| 4350 | − str r0, [r1, #SP_TDR] | |
| 4351 | −SP_loop1: | |
| 4352 | − ldr r0, [r1, #SP_SR] | |
| 4353 | − tst r0, #SP_TDRE | |
| 4354 | − beq SP_loop1 | |
| 4355 | − | |
| 4356 | − mov r0, #SPI_8CLOCKS | |
| 4357 | − str r0, [r1, #SP_TDR] | |
| 4358 | −SP_loop2: | |
| 4359 | − ldr r0, [r1, #SP_SR] | |
| 4360 | − tst r0, #SP_TDRE | |
| 4361 | − beq SP_loop2 | |
| 4362 | − | |
| 4363 | − ldr r0, [r1, #SP_RDR] | |
| 4364 | −SP_loop3: | |
| 4365 | − ldr r0, [r1, #SP_SR] | |
| 4366 | − tst r0, #SP_RDRF | |
| 4367 | − beq SP_loop3 | |
| 4368 | − | |
| 4369 | − ldr r0, [r1, #SP_RDR] | |
| 4370 | − and r0, r0, #255 | |
| 4371 | − bx lr | |
| 4372 | −.endfunc | |
| 4373 | − | |
| 4374 | −.func NVRAM_Xfer, NVRAM_XFER | |
| 4375 | − /* r0 = dest address */ | |
| 4376 | − /* r1 = not used */ | |
| 4377 | − /* r2 = src address within NVRAM */ | |
| 4378 | − /* r3 = length */ | |
| 4379 | −NVRAM_XFER: | |
| 4380 | − stmdb sp!, {r4, r5, lr} | |
| 4381 | − mov r5, r0 /* save r0 (dest address) */ | |
| 4382 | − mov r4, r3 /* save r3 (length) */ | |
| 4383 | − mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ | |
| 4384 | − and r0, r0, #8 | |
| 4385 | − add r0, r0, #NVRAM_CMD_READ | |
| 4386 | − ldr r1, =NVRAM_SCRATCH | |
| 4387 | − strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ | |
| 4388 | − strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ | |
| 4389 | −_local1: | |
| 4390 | − bl NVRAM_INIT | |
| 4391 | − tst r0, #NVRAM_SR_RDY | |
| 4392 | − bne _local1 | |
| 4393 | − mov r0, #20 | |
| 4394 | − bl DELAY9 | |
| 4395 | − mov r2, r4 /* length */ | |
| 4396 | − mov r1, r5 /* dest address */ | |
| 4397 | − mov r0, #2 /* bytes to transfer in command */ | |
| 4398 | − bl NVRAM_XFER2 | |
| 4399 | − ldmia sp!, {r4, r5, lr} | |
| 4400 | − bx lr | |
| 4401 | −.endfunc | |
| 4402 | − | |
| 4403 | −.func NVRAM_Xfer2, NVRAM_XFER2 | |
| 4404 | −NVRAM_XFER2: | |
| 4405 | − stmdb sp!, {r4, r5, r6, lr} | |
| 4406 | − ldr r4, =SP_BASE | |
| 4407 | − mov r3, #0 | |
| 4408 | − cmp r0, #0 | |
| 4409 | − bls _local2 | |
| 4410 | − ldr r5, =NVRAM_SCRATCH | |
| 4411 | −_local4: | |
| 4412 | − ldrb r6, [r5, r3] | |
| 4413 | − str r6, [r4, #SP_TDR] | |
| 4414 | −_local3: | |
| 4415 | − ldr r6, [r4, #SP_SR] | |
| 4416 | − tst r6, #SP_TDRE | |
| 4417 | − beq _local3 | |
| 4418 | − add r3, r3, #1 | |
| 4419 | − cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ | |
| 4420 | − blo _local4 | |
| 4421 | −_local2: | |
| 4422 | − mov r3, #SPI_8CLOCKS | |
| 4423 | − str r3, [r4, #SP_TDR] | |
| 4424 | − ldr r0, [r4, #SP_RDR] | |
| 4425 | −_local5: | |
| 4426 | − ldr r0, [r4, #SP_SR] | |
| 4427 | − tst r0, #SP_RDRF | |
| 4428 | − beq _local5 | |
| 4429 | − ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ | |
| 4430 | − mov r0, #0 | |
| 4431 | − cmp r2, #0 /* r2 is # of bytes to copy in */ | |
| 4432 | − bls _local6 | |
| 4433 | −_local7: | |
| 4434 | − ldr r5, [r4, #SP_SR] | |
| 4435 | − tst r5, #SP_TDRE | |
| 4436 | − beq _local7 | |
| 4437 | − str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ | |
| 4438 | −_local8: | |
| 4439 | − ldr r5, [r4, #SP_SR] | |
| 4440 | − tst r5, #SP_RDRF | |
| 4441 | − beq _local8 | |
| 4442 | − ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ | |
| 4443 | − strb r5, [r1], #1 /* postindexed */ | |
| 4444 | − add r0, r0, #1 | |
| 4445 | − cmp r0, r2 | |
| 4446 | − blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ | |
| 4447 | −_local6: | |
| 4448 | − mov r0, #200 | |
| 4449 | − bl DELAY9 | |
| 4450 | − ldmia sp!, {r4, r5, r6, lr} | |
| 4451 | − bx lr | |
| 4452 | −#endif | |
| @@ -1,31 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0-or-later */ | |
| 2 | −/*** -*- linux-c -*- ********************************************************** | |
| 3 | − | |
| 4 | − Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | |
| 5 | − | |
| 6 | − Copyright 2005 Dan Williams and Red Hat, Inc. | |
| 7 | − | |
| 8 | − | |
| 9 | −******************************************************************************/ | |
| 10 | − | |
| 11 | −#ifndef _ATMEL_H | |
| 12 | −#define _ATMEL_H | |
| 13 | − | |
| 14 | −typedef enum { | |
| 15 | − ATMEL_FW_TYPE_NONE = 0, | |
| 16 | − ATMEL_FW_TYPE_502, | |
| 17 | − ATMEL_FW_TYPE_502D, | |
| 18 | − ATMEL_FW_TYPE_502E, | |
| 19 | − ATMEL_FW_TYPE_502_3COM, | |
| 20 | − ATMEL_FW_TYPE_504, | |
| 21 | − ATMEL_FW_TYPE_504_2958, | |
| 22 | − ATMEL_FW_TYPE_504A_2958, | |
| 23 | − ATMEL_FW_TYPE_506 | |
| 24 | −} AtmelFWType; | |
| 25 | − | |
| 26 | −struct net_device *init_atmel_card(unsigned short, unsigned long, const AtmelFWType, struct device *, | |
| 27 | − int (*present_func)(void *), void * ); | |
| 28 | −void stop_atmel_card( struct net_device *); | |
| 29 | −int atmel_open( struct net_device * ); | |
| 30 | − | |
| 31 | −#endif | |
| @@ -1,292 +0,0 @@ | ||
| 1 | −/*** -*- linux-c -*- ********************************************************** | |
| 2 | − | |
| 3 | − Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | |
| 4 | − | |
| 5 | − Copyright 2000-2001 ATMEL Corporation. | |
| 6 | − Copyright 2003 Simon Kelley. | |
| 7 | − | |
| 8 | − This code was developed from version 2.1.1 of the Atmel drivers, | |
| 9 | − released by Atmel corp. under the GPL in December 2002. It also | |
| 10 | − includes code from the Linux aironet drivers (C) Benjamin Reed, | |
| 11 | − and the Linux PCMCIA package, (C) David Hinds. | |
| 12 | − | |
| 13 | − For all queries about this code, please contact the current author, | |
| 14 | − Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation. | |
| 15 | − | |
| 16 | − This program is free software; you can redistribute it and/or modify | |
| 17 | − it under the terms of the GNU General Public License as published by | |
| 18 | − the Free Software Foundation; either version 2 of the License, or | |
| 19 | − (at your option) any later version. | |
| 20 | − | |
| 21 | − This software is distributed in the hope that it will be useful, | |
| 22 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 23 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 24 | − GNU General Public License for more details. | |
| 25 | − | |
| 26 | − You should have received a copy of the GNU General Public License | |
| 27 | − along with Atmel wireless lan drivers; if not, see | |
| 28 | − <http://www.gnu.org/licenses/>. | |
| 29 | − | |
| 30 | −******************************************************************************/ | |
| 31 | − | |
| 32 | −#ifdef __IN_PCMCIA_PACKAGE__ | |
| 33 | −#include <pcmcia/k_compat.h> | |
| 34 | −#endif | |
| 35 | −#include <linux/kernel.h> | |
| 36 | −#include <linux/module.h> | |
| 37 | −#include <linux/ptrace.h> | |
| 38 | −#include <linux/slab.h> | |
| 39 | −#include <linux/string.h> | |
| 40 | −#include <linux/netdevice.h> | |
| 41 | −#include <linux/moduleparam.h> | |
| 42 | −#include <linux/device.h> | |
| 43 | − | |
| 44 | −#include <pcmcia/cistpl.h> | |
| 45 | −#include <pcmcia/cisreg.h> | |
| 46 | −#include <pcmcia/ds.h> | |
| 47 | −#include <pcmcia/ciscode.h> | |
| 48 | − | |
| 49 | −#include <asm/io.h> | |
| 50 | −#include <linux/wireless.h> | |
| 51 | − | |
| 52 | −#include "atmel.h" | |
| 53 | − | |
| 54 | − | |
| 55 | −/*====================================================================*/ | |
| 56 | − | |
| 57 | −MODULE_AUTHOR("Simon Kelley"); | |
| 58 | −MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); | |
| 59 | −MODULE_LICENSE("GPL"); | |
| 60 | − | |
| 61 | −/*====================================================================*/ | |
| 62 | − | |
| 63 | −static int atmel_config(struct pcmcia_device *link); | |
| 64 | −static void atmel_release(struct pcmcia_device *link); | |
| 65 | − | |
| 66 | −static void atmel_detach(struct pcmcia_device *p_dev); | |
| 67 | − | |
| 68 | −struct local_info { | |
| 69 | − struct net_device *eth_dev; | |
| 70 | −}; | |
| 71 | − | |
| 72 | −static int atmel_probe(struct pcmcia_device *p_dev) | |
| 73 | −{ | |
| 74 | − struct local_info *local; | |
| 75 | − int ret; | |
| 76 | − | |
| 77 | − dev_dbg(&p_dev->dev, "atmel_attach()\n"); | |
| 78 | − | |
| 79 | − /* Allocate space for private device-specific data */ | |
| 80 | − local = kzalloc(sizeof(*local), GFP_KERNEL); | |
| 81 | − if (!local) | |
| 82 | − return -ENOMEM; | |
| 83 | − | |
| 84 | − p_dev->priv = local; | |
| 85 | − | |
| 86 | − ret = atmel_config(p_dev); | |
| 87 | − if (ret) | |
| 88 | − goto err_free_priv; | |
| 89 | − | |
| 90 | − return 0; | |
| 91 | − | |
| 92 | −err_free_priv: | |
| 93 | − kfree(p_dev->priv); | |
| 94 | − return ret; | |
| 95 | −} | |
| 96 | − | |
| 97 | −static void atmel_detach(struct pcmcia_device *link) | |
| 98 | −{ | |
| 99 | − dev_dbg(&link->dev, "atmel_detach\n"); | |
| 100 | − | |
| 101 | − atmel_release(link); | |
| 102 | − | |
| 103 | − kfree(link->priv); | |
| 104 | −} | |
| 105 | − | |
| 106 | −/* Call-back function to interrogate PCMCIA-specific information | |
| 107 | − about the current existence of the card */ | |
| 108 | −static int card_present(void *arg) | |
| 109 | −{ | |
| 110 | − struct pcmcia_device *link = (struct pcmcia_device *)arg; | |
| 111 | − | |
| 112 | − if (pcmcia_dev_present(link)) | |
| 113 | − return 1; | |
| 114 | − | |
| 115 | − return 0; | |
| 116 | −} | |
| 117 | − | |
| 118 | −static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data) | |
| 119 | −{ | |
| 120 | − if (p_dev->config_index == 0) | |
| 121 | − return -EINVAL; | |
| 122 | − | |
| 123 | − return pcmcia_request_io(p_dev); | |
| 124 | −} | |
| 125 | − | |
| 126 | −static int atmel_config(struct pcmcia_device *link) | |
| 127 | −{ | |
| 128 | − int ret; | |
| 129 | − const struct pcmcia_device_id *did; | |
| 130 | − | |
| 131 | − did = dev_get_drvdata(&link->dev); | |
| 132 | − | |
| 133 | − dev_dbg(&link->dev, "atmel_config\n"); | |
| 134 | − | |
| 135 | − link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | | |
| 136 | − CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; | |
| 137 | − | |
| 138 | − if (pcmcia_loop_config(link, atmel_config_check, NULL)) | |
| 139 | − goto failed; | |
| 140 | − | |
| 141 | − if (!link->irq) { | |
| 142 | − dev_err(&link->dev, "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); | |
| 143 | − goto failed; | |
| 144 | − } | |
| 145 | − | |
| 146 | − ret = pcmcia_enable_device(link); | |
| 147 | − if (ret) | |
| 148 | − goto failed; | |
| 149 | − | |
| 150 | − ((struct local_info *)link->priv)->eth_dev = | |
| 151 | − init_atmel_card(link->irq, | |
| 152 | − link->resource[0]->start, | |
| 153 | − did ? did->driver_info : ATMEL_FW_TYPE_NONE, | |
| 154 | − &link->dev, | |
| 155 | − card_present, | |
| 156 | − link); | |
| 157 | − if (!((struct local_info *)link->priv)->eth_dev) | |
| 158 | − goto failed; | |
| 159 | − | |
| 160 | − | |
| 161 | − return 0; | |
| 162 | − | |
| 163 | − failed: | |
| 164 | − atmel_release(link); | |
| 165 | − return -ENODEV; | |
| 166 | −} | |
| 167 | − | |
| 168 | −static void atmel_release(struct pcmcia_device *link) | |
| 169 | −{ | |
| 170 | − struct net_device *dev = ((struct local_info *)link->priv)->eth_dev; | |
| 171 | − | |
| 172 | − dev_dbg(&link->dev, "atmel_release\n"); | |
| 173 | − | |
| 174 | − if (dev) | |
| 175 | − stop_atmel_card(dev); | |
| 176 | − ((struct local_info *)link->priv)->eth_dev = NULL; | |
| 177 | − | |
| 178 | − pcmcia_disable_device(link); | |
| 179 | −} | |
| 180 | − | |
| 181 | −static int atmel_suspend(struct pcmcia_device *link) | |
| 182 | −{ | |
| 183 | − struct local_info *local = link->priv; | |
| 184 | − | |
| 185 | − netif_device_detach(local->eth_dev); | |
| 186 | − | |
| 187 | − return 0; | |
| 188 | −} | |
| 189 | − | |
| 190 | −static int atmel_resume(struct pcmcia_device *link) | |
| 191 | −{ | |
| 192 | − struct local_info *local = link->priv; | |
| 193 | − | |
| 194 | − atmel_open(local->eth_dev); | |
| 195 | − netif_device_attach(local->eth_dev); | |
| 196 | − | |
| 197 | − return 0; | |
| 198 | −} | |
| 199 | − | |
| 200 | −/*====================================================================*/ | |
| 201 | −/* We use the driver_info field to store the correct firmware type for a card. */ | |
| 202 | − | |
| 203 | −#define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \ | |
| 204 | − .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \ | |
| 205 | − PCMCIA_DEV_ID_MATCH_CARD_ID, \ | |
| 206 | − .manf_id = (manf), \ | |
| 207 | − .card_id = (card), \ | |
| 208 | − .driver_info = (kernel_ulong_t)(info), } | |
| 209 | − | |
| 210 | −#define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \ | |
| 211 | − .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \ | |
| 212 | − PCMCIA_DEV_ID_MATCH_PROD_ID2, \ | |
| 213 | − .prod_id = { (v1), (v2), NULL, NULL }, \ | |
| 214 | − .prod_id_hash = { (vh1), (vh2), 0, 0 }, \ | |
| 215 | − .driver_info = (kernel_ulong_t)(info), } | |
| 216 | − | |
| 217 | −static const struct pcmcia_device_id atmel_ids[] = { | |
| 218 | − PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM), | |
| 219 | − PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM), | |
| 220 | − PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E), | |
| 221 | − PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502), | |
| 222 | − PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E), | |
| 223 | − PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502), | |
| 224 | − PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D), | |
| 225 | − PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E), | |
| 226 | − PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958), | |
| 227 | − PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504), | |
| 228 | − PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958), | |
| 229 | − PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502), | |
| 230 | − PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E), | |
| 231 | − PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502), | |
| 232 | − PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958), | |
| 233 | − PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502), | |
| 234 | − PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D), | |
| 235 | − PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502), | |
| 236 | − PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D), | |
| 237 | − PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D), | |
| 238 | − PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E), | |
| 239 | − PCMCIA_DEVICE_NULL | |
| 240 | −}; | |
| 241 | − | |
| 242 | −MODULE_DEVICE_TABLE(pcmcia, atmel_ids); | |
| 243 | − | |
| 244 | −static struct pcmcia_driver atmel_driver = { | |
| 245 | − .owner = THIS_MODULE, | |
| 246 | − .name = "atmel_cs", | |
| 247 | − .probe = atmel_probe, | |
| 248 | − .remove = atmel_detach, | |
| 249 | − .id_table = atmel_ids, | |
| 250 | − .suspend = atmel_suspend, | |
| 251 | − .resume = atmel_resume, | |
| 252 | −}; | |
| 253 | −module_pcmcia_driver(atmel_driver); | |
| 254 | − | |
| 255 | −/* | |
| 256 | − This program is free software; you can redistribute it and/or | |
| 257 | − modify it under the terms of the GNU General Public License | |
| 258 | − as published by the Free Software Foundation; either version 2 | |
| 259 | − of the License, or (at your option) any later version. | |
| 260 | − | |
| 261 | − This program is distributed in the hope that it will be useful, | |
| 262 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 263 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 264 | − GNU General Public License for more details. | |
| 265 | − | |
| 266 | − In addition: | |
| 267 | − | |
| 268 | − Redistribution and use in source and binary forms, with or without | |
| 269 | − modification, are permitted provided that the following conditions | |
| 270 | − are met: | |
| 271 | − | |
| 272 | − 1. Redistributions of source code must retain the above copyright | |
| 273 | − notice, this list of conditions and the following disclaimer. | |
| 274 | − 2. Redistributions in binary form must reproduce the above copyright | |
| 275 | − notice, this list of conditions and the following disclaimer in the | |
| 276 | − documentation and/or other materials provided with the distribution. | |
| 277 | − 3. The name of the author may not be used to endorse or promote | |
| 278 | − products derived from this software without specific prior written | |
| 279 | − permission. | |
| 280 | − | |
| 281 | − THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 282 | − IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 283 | − WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 284 | − ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
| 285 | − INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 286 | − (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 287 | − SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 288 | − HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 289 | − STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
| 290 | − IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| 291 | − POSSIBILITY OF SUCH DAMAGE. | |
| 292 | −*/ | |
| @@ -1,65 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-or-later | |
| 2 | −/*** -*- linux-c -*- ********************************************************** | |
| 3 | − | |
| 4 | − Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. | |
| 5 | − | |
| 6 | − Copyright 2004 Simon Kelley. | |
| 7 | − | |
| 8 | − | |
| 9 | −******************************************************************************/ | |
| 10 | −#include <linux/pci.h> | |
| 11 | −#include <linux/kernel.h> | |
| 12 | −#include <linux/module.h> | |
| 13 | −#include <linux/netdevice.h> | |
| 14 | −#include "atmel.h" | |
| 15 | − | |
| 16 | −MODULE_AUTHOR("Simon Kelley"); | |
| 17 | −MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); | |
| 18 | −MODULE_LICENSE("GPL"); | |
| 19 | − | |
| 20 | −static const struct pci_device_id card_ids[] = { | |
| 21 | − { 0x1114, 0x0506, PCI_ANY_ID, PCI_ANY_ID }, | |
| 22 | − { 0, } | |
| 23 | −}; | |
| 24 | − | |
| 25 | −MODULE_DEVICE_TABLE(pci, card_ids); | |
| 26 | − | |
| 27 | −static int atmel_pci_probe(struct pci_dev *, const struct pci_device_id *); | |
| 28 | −static void atmel_pci_remove(struct pci_dev *); | |
| 29 | − | |
| 30 | −static struct pci_driver atmel_driver = { | |
| 31 | − .name = "atmel", | |
| 32 | − .id_table = card_ids, | |
| 33 | − .probe = atmel_pci_probe, | |
| 34 | − .remove = atmel_pci_remove, | |
| 35 | −}; | |
| 36 | − | |
| 37 | − | |
| 38 | −static int atmel_pci_probe(struct pci_dev *pdev, | |
| 39 | − const struct pci_device_id *pent) | |
| 40 | −{ | |
| 41 | − struct net_device *dev; | |
| 42 | − | |
| 43 | − if (pci_enable_device(pdev)) | |
| 44 | − return -ENODEV; | |
| 45 | − | |
| 46 | − pci_set_master(pdev); | |
| 47 | − | |
| 48 | − dev = init_atmel_card(pdev->irq, pdev->resource[1].start, | |
| 49 | − ATMEL_FW_TYPE_506, | |
| 50 | − &pdev->dev, NULL, NULL); | |
| 51 | − if (!dev) { | |
| 52 | − pci_disable_device(pdev); | |
| 53 | − return -ENODEV; | |
| 54 | − } | |
| 55 | − | |
| 56 | − pci_set_drvdata(pdev, dev); | |
| 57 | − return 0; | |
| 58 | −} | |
| 59 | − | |
| 60 | −static void atmel_pci_remove(struct pci_dev *pdev) | |
| 61 | −{ | |
| 62 | − stop_atmel_card(pci_get_drvdata(pdev)); | |
| 63 | −} | |
| 64 | − | |
| 65 | −module_pci_driver(atmel_driver); | |
| @@ -866,7 +866,7 @@ struct wireless_dev *brcmf_apsta_add_vif(struct wiphy *wiphy, const char *name, · 865 unmodified lines | ||
| 866 | 866 | goto fail; |
| 867 | 867 | } |
| 868 | 868 | |
| 869 | − strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); | |
| 869 | + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); | |
| 870 | 870 | err = brcmf_net_attach(ifp, true); |
| 871 | 871 | if (err) { |
| 872 | 872 | bphy_err(drvr, "Registering netdevice failed\n"); |
| @@ -2334,7 +2334,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, · 2333 unmodified lines | ||
| 2334 | 2334 | goto fail; |
| 2335 | 2335 | } |
| 2336 | 2336 | |
| 2337 | − strncpy(ifp->ndev->name, name, sizeof(ifp->ndev->name) - 1); | |
| 2337 | + strscpy(ifp->ndev->name, name, sizeof(ifp->ndev->name)); | |
| 2338 | 2338 | ifp->ndev->name_assign_type = name_assign_type; |
| 2339 | 2339 | err = brcmf_net_attach(ifp, true); |
| 2340 | 2340 | if (err) { |
| @@ -341,7 +341,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) · 340 unmodified lines | ||
| 341 | 341 | /* store the country code for passing up as a regulatory hint */ |
| 342 | 342 | wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len); |
| 343 | 343 | if (brcms_c_country_valid(ccode)) |
| 344 | − strncpy(wlc->pub->srom_ccode, ccode, ccode_len); | |
| 344 | + memcpy(wlc->pub->srom_ccode, ccode, ccode_len); | |
| 345 | 345 | |
| 346 | 346 | /* |
| 347 | 347 | * If no custom world domain is found in the SROM, use the |
| @@ -354,10 +354,10 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) · 6 unmodified lines | ||
| 354 | 354 | } |
| 355 | 355 | |
| 356 | 356 | /* save default country for exiting 11d regulatory mode */ |
| 357 | − strncpy(wlc->country_default, ccode, ccode_len); | |
| 357 | + memcpy(wlc->country_default, ccode, ccode_len); | |
| 358 | 358 | |
| 359 | 359 | /* initialize autocountry_default to driver default */ |
| 360 | − strncpy(wlc->autocountry_default, ccode, ccode_len); | |
| 360 | + memcpy(wlc->autocountry_default, ccode, ccode_len); | |
| 361 | 361 | |
| 362 | 362 | brcms_c_set_country(wlc_cm, wlc_cm->world_regd); |
| 363 | 363 | |
| @@ -584,8 +584,7 @@ struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc, · 583 unmodified lines | ||
| 584 | 584 | rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase); |
| 585 | 585 | |
| 586 | 586 | /* make a private copy of our callers name */ |
| 587 | − strncpy(di->name, name, MAXNAMEL); | |
| 588 | − di->name[MAXNAMEL - 1] = '\0'; | |
| 587 | + strscpy(di->name, name, sizeof(di->name)); | |
| 589 | 588 | |
| 590 | 589 | di->dmadev = core->dma_dev; |
| 591 | 590 | |
| @@ -5551,8 +5551,8 @@ int brcms_c_module_register(struct brcms_pub *pub, · 5550 unmodified lines | ||
| 5551 | 5551 | /* find an empty entry and just add, no duplication check! */ |
| 5552 | 5552 | for (i = 0; i < BRCMS_MAXMODULES; i++) { |
| 5553 | 5553 | if (wlc->modulecb[i].name[0] == '\0') { |
| 5554 | − strncpy(wlc->modulecb[i].name, name, | |
| 5555 | − sizeof(wlc->modulecb[i].name) - 1); | |
| 5554 | + strscpy(wlc->modulecb[i].name, name, | |
| 5555 | + sizeof(wlc->modulecb[i].name)); | |
| 5556 | 5556 | wlc->modulecb[i].hdl = hdl; |
| 5557 | 5557 | wlc->modulecb[i].down_fn = d_fn; |
| 5558 | 5558 | return 0; |
| @@ -1,59 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −config WLAN_VENDOR_CISCO | |
| 3 | − bool "Cisco devices" | |
| 4 | − default y | |
| 5 | − help | |
| 6 | − If you have a wireless card belonging to this class, say Y. | |
| 7 | − | |
| 8 | − Note that the answer to this question doesn't directly affect the | |
| 9 | − kernel: saying N will just cause the configurator to skip all the | |
| 10 | − questions about these cards. If you say Y, you will be asked for | |
| 11 | − your specific card in the following questions. | |
| 12 | − | |
| 13 | −if WLAN_VENDOR_CISCO | |
| 14 | − | |
| 15 | −config AIRO | |
| 16 | − tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" | |
| 17 | − depends on CFG80211 && (PCI || BROKEN) | |
| 18 | − select WIRELESS_EXT | |
| 19 | − select CRYPTO | |
| 20 | − select CRYPTO_SKCIPHER | |
| 21 | − select WEXT_SPY | |
| 22 | − select WEXT_PRIV | |
| 23 | − help | |
| 24 | − This is the standard Linux driver to support Cisco/Aironet ISA and | |
| 25 | − PCI 802.11 wireless cards. | |
| 26 | − It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X | |
| 27 | − - with or without encryption) as well as card before the Cisco | |
| 28 | − acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). | |
| 29 | − | |
| 30 | − This driver support both the standard Linux Wireless Extensions | |
| 31 | − and Cisco proprietary API, so both the Linux Wireless Tools and the | |
| 32 | − Cisco Linux utilities can be used to configure the card. | |
| 33 | − | |
| 34 | − The driver can be compiled as a module and will be named "airo". | |
| 35 | − | |
| 36 | −config AIRO_CS | |
| 37 | − tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" | |
| 38 | − depends on CFG80211 && PCMCIA | |
| 39 | − select WIRELESS_EXT | |
| 40 | − select WEXT_SPY | |
| 41 | − select WEXT_PRIV | |
| 42 | − select CRYPTO | |
| 43 | − select CRYPTO_AES | |
| 44 | − select CRYPTO_CTR | |
| 45 | − help | |
| 46 | − This is the standard Linux driver to support Cisco/Aironet PCMCIA | |
| 47 | − 802.11 wireless cards. This driver is the same as the Aironet | |
| 48 | − driver part of the Linux Pcmcia package. | |
| 49 | − It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X | |
| 50 | − - with or without encryption) as well as card before the Cisco | |
| 51 | − acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also | |
| 52 | − supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom | |
| 53 | − 802.11b cards. | |
| 54 | − | |
| 55 | − This driver support both the standard Linux Wireless Extensions | |
| 56 | − and Cisco proprietary API, so both the Linux Wireless Tools and the | |
| 57 | − Cisco Linux utilities can be used to configure the card. | |
| 58 | − | |
| 59 | −endif # WLAN_VENDOR_CISCO | |
| @@ -1,3 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −obj-$(CONFIG_AIRO) += airo.o | |
| 3 | −obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o | |
| @@ -1,8288 +0,0 @@ | ||
| 1 | −/*====================================================================== | |
| 2 | − | |
| 3 | − Aironet driver for 4500 and 4800 series cards | |
| 4 | − | |
| 5 | − This code is released under both the GPL version 2 and BSD licenses. | |
| 6 | − Either license may be used. The respective licenses are found at | |
| 7 | − the end of this file. | |
| 8 | − | |
| 9 | − This code was developed by Benjamin Reed <breed@users.sourceforge.net> | |
| 10 | − including portions of which come from the Aironet PC4500 | |
| 11 | − Developer's Reference Manual and used with permission. Copyright | |
| 12 | − (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use | |
| 13 | − code in the Developer's manual was granted for this driver by | |
| 14 | − Aironet. Major code contributions were received from Javier Achirica | |
| 15 | − <achirica@users.sourceforge.net> and Jean Tourrilhes <jt@hpl.hp.com>. | |
| 16 | − Code was also integrated from the Cisco Aironet driver for Linux. | |
| 17 | − Support for MPI350 cards was added by Fabrice Bellet | |
| 18 | − <fabrice@bellet.info>. | |
| 19 | − | |
| 20 | −======================================================================*/ | |
| 21 | − | |
| 22 | −#include <linux/err.h> | |
| 23 | −#include <linux/init.h> | |
| 24 | − | |
| 25 | −#include <linux/kernel.h> | |
| 26 | −#include <linux/module.h> | |
| 27 | −#include <linux/proc_fs.h> | |
| 28 | − | |
| 29 | −#include <linux/sched.h> | |
| 30 | −#include <linux/ptrace.h> | |
| 31 | −#include <linux/slab.h> | |
| 32 | −#include <linux/string.h> | |
| 33 | −#include <linux/timer.h> | |
| 34 | −#include <linux/interrupt.h> | |
| 35 | −#include <linux/in.h> | |
| 36 | −#include <linux/bitops.h> | |
| 37 | −#include <linux/scatterlist.h> | |
| 38 | −#include <linux/crypto.h> | |
| 39 | −#include <linux/io.h> | |
| 40 | −#include <asm/unaligned.h> | |
| 41 | − | |
| 42 | −#include <linux/netdevice.h> | |
| 43 | −#include <linux/etherdevice.h> | |
| 44 | −#include <linux/skbuff.h> | |
| 45 | −#include <linux/if_arp.h> | |
| 46 | −#include <linux/ioport.h> | |
| 47 | −#include <linux/pci.h> | |
| 48 | −#include <linux/uaccess.h> | |
| 49 | −#include <linux/kthread.h> | |
| 50 | −#include <linux/freezer.h> | |
| 51 | − | |
| 52 | −#include <crypto/aes.h> | |
| 53 | −#include <crypto/skcipher.h> | |
| 54 | − | |
| 55 | −#include <net/cfg80211.h> | |
| 56 | −#include <net/iw_handler.h> | |
| 57 | − | |
| 58 | −#include "airo.h" | |
| 59 | − | |
| 60 | −#define DRV_NAME "airo" | |
| 61 | − | |
| 62 | −#ifdef CONFIG_PCI | |
| 63 | −static const struct pci_device_id card_ids[] = { | |
| 64 | − { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, | |
| 65 | − { 0x14b9, 0x4500, PCI_ANY_ID, PCI_ANY_ID }, | |
| 66 | − { 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, }, | |
| 67 | − { 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, }, | |
| 68 | − { 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, }, | |
| 69 | − { 0x14b9, 0x5000, PCI_ANY_ID, PCI_ANY_ID, }, | |
| 70 | − { 0x14b9, 0xa504, PCI_ANY_ID, PCI_ANY_ID, }, | |
| 71 | − { 0, } | |
| 72 | −}; | |
| 73 | −MODULE_DEVICE_TABLE(pci, card_ids); | |
| 74 | − | |
| 75 | −static int airo_pci_probe(struct pci_dev *, const struct pci_device_id *); | |
| 76 | −static void airo_pci_remove(struct pci_dev *); | |
| 77 | −static int __maybe_unused airo_pci_suspend(struct device *dev); | |
| 78 | −static int __maybe_unused airo_pci_resume(struct device *dev); | |
| 79 | − | |
| 80 | −static SIMPLE_DEV_PM_OPS(airo_pci_pm_ops, | |
| 81 | − airo_pci_suspend, | |
| 82 | − airo_pci_resume); | |
| 83 | − | |
| 84 | −static struct pci_driver airo_driver = { | |
| 85 | − .name = DRV_NAME, | |
| 86 | − .id_table = card_ids, | |
| 87 | − .probe = airo_pci_probe, | |
| 88 | − .remove = airo_pci_remove, | |
| 89 | − .driver.pm = &airo_pci_pm_ops, | |
| 90 | −}; | |
| 91 | −#endif /* CONFIG_PCI */ | |
| 92 | − | |
| 93 | −/* Include Wireless Extension definition and check version - Jean II */ | |
| 94 | −#include <linux/wireless.h> | |
| 95 | −#define WIRELESS_SPY /* enable iwspy support */ | |
| 96 | − | |
| 97 | −#define CISCO_EXT /* enable Cisco extensions */ | |
| 98 | −#ifdef CISCO_EXT | |
| 99 | −#include <linux/delay.h> | |
| 100 | −#endif | |
| 101 | − | |
| 102 | −/* Hack to do some power saving */ | |
| 103 | −#define POWER_ON_DOWN | |
| 104 | − | |
| 105 | −/* As you can see this list is HUGH! | |
| 106 | − I really don't know what a lot of these counts are about, but they | |
| 107 | − are all here for completeness. If the IGNLABEL macro is put in | |
| 108 | − infront of the label, that statistic will not be included in the list | |
| 109 | − of statistics in the /proc filesystem */ | |
| 110 | − | |
| 111 | −#define IGNLABEL(comment) NULL | |
| 112 | −static const char *statsLabels[] = { | |
| 113 | − "RxOverrun", | |
| 114 | − IGNLABEL("RxPlcpCrcErr"), | |
| 115 | − IGNLABEL("RxPlcpFormatErr"), | |
| 116 | − IGNLABEL("RxPlcpLengthErr"), | |
| 117 | − "RxMacCrcErr", | |
| 118 | − "RxMacCrcOk", | |
| 119 | − "RxWepErr", | |
| 120 | − "RxWepOk", | |
| 121 | − "RetryLong", | |
| 122 | − "RetryShort", | |
| 123 | − "MaxRetries", | |
| 124 | − "NoAck", | |
| 125 | − "NoCts", | |
| 126 | − "RxAck", | |
| 127 | − "RxCts", | |
| 128 | − "TxAck", | |
| 129 | − "TxRts", | |
| 130 | − "TxCts", | |
| 131 | − "TxMc", | |
| 132 | − "TxBc", | |
| 133 | − "TxUcFrags", | |
| 134 | − "TxUcPackets", | |
| 135 | − "TxBeacon", | |
| 136 | − "RxBeacon", | |
| 137 | − "TxSinColl", | |
| 138 | − "TxMulColl", | |
| 139 | − "DefersNo", | |
| 140 | − "DefersProt", | |
| 141 | − "DefersEngy", | |
| 142 | − "DupFram", | |
| 143 | − "RxFragDisc", | |
| 144 | − "TxAged", | |
| 145 | − "RxAged", | |
| 146 | − "LostSync-MaxRetry", | |
| 147 | − "LostSync-MissedBeacons", | |
| 148 | − "LostSync-ArlExceeded", | |
| 149 | − "LostSync-Deauth", | |
| 150 | − "LostSync-Disassoced", | |
| 151 | − "LostSync-TsfTiming", | |
| 152 | − "HostTxMc", | |
| 153 | − "HostTxBc", | |
| 154 | − "HostTxUc", | |
| 155 | − "HostTxFail", | |
| 156 | − "HostRxMc", | |
| 157 | − "HostRxBc", | |
| 158 | − "HostRxUc", | |
| 159 | − "HostRxDiscard", | |
| 160 | − IGNLABEL("HmacTxMc"), | |
| 161 | − IGNLABEL("HmacTxBc"), | |
| 162 | − IGNLABEL("HmacTxUc"), | |
| 163 | − IGNLABEL("HmacTxFail"), | |
| 164 | − IGNLABEL("HmacRxMc"), | |
| 165 | − IGNLABEL("HmacRxBc"), | |
| 166 | − IGNLABEL("HmacRxUc"), | |
| 167 | − IGNLABEL("HmacRxDiscard"), | |
| 168 | − IGNLABEL("HmacRxAccepted"), | |
| 169 | − "SsidMismatch", | |
| 170 | − "ApMismatch", | |
| 171 | − "RatesMismatch", | |
| 172 | − "AuthReject", | |
| 173 | − "AuthTimeout", | |
| 174 | − "AssocReject", | |
| 175 | − "AssocTimeout", | |
| 176 | − IGNLABEL("ReasonOutsideTable"), | |
| 177 | − IGNLABEL("ReasonStatus1"), | |
| 178 | − IGNLABEL("ReasonStatus2"), | |
| 179 | − IGNLABEL("ReasonStatus3"), | |
| 180 | − IGNLABEL("ReasonStatus4"), | |
| 181 | − IGNLABEL("ReasonStatus5"), | |
| 182 | − IGNLABEL("ReasonStatus6"), | |
| 183 | − IGNLABEL("ReasonStatus7"), | |
| 184 | − IGNLABEL("ReasonStatus8"), | |
| 185 | − IGNLABEL("ReasonStatus9"), | |
| 186 | − IGNLABEL("ReasonStatus10"), | |
| 187 | − IGNLABEL("ReasonStatus11"), | |
| 188 | − IGNLABEL("ReasonStatus12"), | |
| 189 | − IGNLABEL("ReasonStatus13"), | |
| 190 | − IGNLABEL("ReasonStatus14"), | |
| 191 | − IGNLABEL("ReasonStatus15"), | |
| 192 | − IGNLABEL("ReasonStatus16"), | |
| 193 | − IGNLABEL("ReasonStatus17"), | |
| 194 | − IGNLABEL("ReasonStatus18"), | |
| 195 | − IGNLABEL("ReasonStatus19"), | |
| 196 | − "RxMan", | |
| 197 | − "TxMan", | |
| 198 | − "RxRefresh", | |
| 199 | − "TxRefresh", | |
| 200 | − "RxPoll", | |
| 201 | − "TxPoll", | |
| 202 | − "HostRetries", | |
| 203 | − "LostSync-HostReq", | |
| 204 | − "HostTxBytes", | |
| 205 | − "HostRxBytes", | |
| 206 | − "ElapsedUsec", | |
| 207 | − "ElapsedSec", | |
| 208 | − "LostSyncBetterAP", | |
| 209 | − "PrivacyMismatch", | |
| 210 | − "Jammed", | |
| 211 | − "DiscRxNotWepped", | |
| 212 | − "PhyEleMismatch", | |
| 213 | − (char*)-1 }; | |
| 214 | −#ifndef RUN_AT | |
| 215 | −#define RUN_AT(x) (jiffies+(x)) | |
| 216 | −#endif | |
| 217 | − | |
| 218 | − | |
| 219 | −/* These variables are for insmod, since it seems that the rates | |
| 220 | − can only be set in setup_card. Rates should be a comma separated | |
| 221 | − (no spaces) list of rates (up to 8). */ | |
| 222 | − | |
| 223 | −static int rates[8]; | |
| 224 | −static char *ssids[3]; | |
| 225 | − | |
| 226 | −static int io[4]; | |
| 227 | −static int irq[4]; | |
| 228 | − | |
| 229 | −static | |
| 230 | −int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at. | |
| 231 | − 0 means no limit. For old cards this was 4 */ | |
| 232 | − | |
| 233 | −static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */ | |
| 234 | −static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read | |
| 235 | − the bap, needed on some older cards and buses. */ | |
| 236 | −static int adhoc; | |
| 237 | − | |
| 238 | −static int probe = 1; | |
| 239 | − | |
| 240 | −static kuid_t proc_kuid; | |
| 241 | −static int proc_uid /* = 0 */; | |
| 242 | − | |
| 243 | −static kgid_t proc_kgid; | |
| 244 | −static int proc_gid /* = 0 */; | |
| 245 | − | |
| 246 | −static int airo_perm = 0555; | |
| 247 | − | |
| 248 | −static int proc_perm = 0644; | |
| 249 | − | |
| 250 | −MODULE_AUTHOR("Benjamin Reed"); | |
| 251 | −MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards. " | |
| 252 | − "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs."); | |
| 253 | −MODULE_LICENSE("Dual BSD/GPL"); | |
| 254 | −module_param_hw_array(io, int, ioport, NULL, 0); | |
| 255 | −module_param_hw_array(irq, int, irq, NULL, 0); | |
| 256 | −module_param_array(rates, int, NULL, 0); | |
| 257 | −module_param_array(ssids, charp, NULL, 0); | |
| 258 | −module_param(auto_wep, int, 0); | |
| 259 | −MODULE_PARM_DESC(auto_wep, | |
| 260 | − "If non-zero, the driver will keep looping through the authentication options until an association is made. " | |
| 261 | − "The value of auto_wep is number of the wep keys to check. " | |
| 262 | − "A value of 2 will try using the key at index 0 and index 1."); | |
| 263 | −module_param(aux_bap, int, 0); | |
| 264 | −MODULE_PARM_DESC(aux_bap, | |
| 265 | − "If non-zero, the driver will switch into a mode that seems to work better for older cards with some older buses. " | |
| 266 | − "Before switching it checks that the switch is needed."); | |
| 267 | −module_param(maxencrypt, int, 0); | |
| 268 | −MODULE_PARM_DESC(maxencrypt, | |
| 269 | − "The maximum speed that the card can do encryption. " | |
| 270 | − "Units are in 512kbs. " | |
| 271 | − "Zero (default) means there is no limit. " | |
| 272 | − "Older cards used to be limited to 2mbs (4)."); | |
| 273 | −module_param(adhoc, int, 0); | |
| 274 | −MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode."); | |
| 275 | −module_param(probe, int, 0); | |
| 276 | −MODULE_PARM_DESC(probe, "If zero, the driver won't start the card."); | |
| 277 | − | |
| 278 | −module_param(proc_uid, int, 0); | |
| 279 | −MODULE_PARM_DESC(proc_uid, "The uid that the /proc files will belong to."); | |
| 280 | −module_param(proc_gid, int, 0); | |
| 281 | −MODULE_PARM_DESC(proc_gid, "The gid that the /proc files will belong to."); | |
| 282 | −module_param(airo_perm, int, 0); | |
| 283 | −MODULE_PARM_DESC(airo_perm, "The permission bits of /proc/[driver/]aironet."); | |
| 284 | −module_param(proc_perm, int, 0); | |
| 285 | −MODULE_PARM_DESC(proc_perm, "The permission bits of the files in /proc"); | |
| 286 | − | |
| 287 | −/* This is a kind of sloppy hack to get this information to OUT4500 and | |
| 288 | − IN4500. I would be extremely interested in the situation where this | |
| 289 | − doesn't work though!!! */ | |
| 290 | −static int do8bitIO /* = 0 */; | |
| 291 | − | |
| 292 | −/* Return codes */ | |
| 293 | −#define SUCCESS 0 | |
| 294 | −#define ERROR -1 | |
| 295 | −#define NO_PACKET -2 | |
| 296 | − | |
| 297 | −/* Commands */ | |
| 298 | −#define NOP2 0x0000 | |
| 299 | −#define MAC_ENABLE 0x0001 | |
| 300 | −#define MAC_DISABLE 0x0002 | |
| 301 | −#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */ | |
| 302 | −#define CMD_SOFTRESET 0x0004 | |
| 303 | −#define HOSTSLEEP 0x0005 | |
| 304 | −#define CMD_MAGIC_PKT 0x0006 | |
| 305 | −#define CMD_SETWAKEMASK 0x0007 | |
| 306 | −#define CMD_READCFG 0x0008 | |
| 307 | −#define CMD_SETMODE 0x0009 | |
| 308 | −#define CMD_ALLOCATETX 0x000a | |
| 309 | −#define CMD_TRANSMIT 0x000b | |
| 310 | −#define CMD_DEALLOCATETX 0x000c | |
| 311 | −#define NOP 0x0010 | |
| 312 | −#define CMD_WORKAROUND 0x0011 | |
| 313 | −#define CMD_ALLOCATEAUX 0x0020 | |
| 314 | −#define CMD_ACCESS 0x0021 | |
| 315 | −#define CMD_PCIBAP 0x0022 | |
| 316 | −#define CMD_PCIAUX 0x0023 | |
| 317 | −#define CMD_ALLOCBUF 0x0028 | |
| 318 | −#define CMD_GETTLV 0x0029 | |
| 319 | −#define CMD_PUTTLV 0x002a | |
| 320 | −#define CMD_DELTLV 0x002b | |
| 321 | −#define CMD_FINDNEXTTLV 0x002c | |
| 322 | −#define CMD_PSPNODES 0x0030 | |
| 323 | −#define CMD_SETCW 0x0031 | |
| 324 | −#define CMD_SETPCF 0x0032 | |
| 325 | −#define CMD_SETPHYREG 0x003e | |
| 326 | −#define CMD_TXTEST 0x003f | |
| 327 | −#define MAC_ENABLETX 0x0101 | |
| 328 | −#define CMD_LISTBSS 0x0103 | |
| 329 | −#define CMD_SAVECFG 0x0108 | |
| 330 | −#define CMD_ENABLEAUX 0x0111 | |
| 331 | −#define CMD_WRITERID 0x0121 | |
| 332 | −#define CMD_USEPSPNODES 0x0130 | |
| 333 | −#define MAC_ENABLERX 0x0201 | |
| 334 | − | |
| 335 | −/* Command errors */ | |
| 336 | −#define ERROR_QUALIF 0x00 | |
| 337 | −#define ERROR_ILLCMD 0x01 | |
| 338 | −#define ERROR_ILLFMT 0x02 | |
| 339 | −#define ERROR_INVFID 0x03 | |
| 340 | −#define ERROR_INVRID 0x04 | |
| 341 | −#define ERROR_LARGE 0x05 | |
| 342 | −#define ERROR_NDISABL 0x06 | |
| 343 | −#define ERROR_ALLOCBSY 0x07 | |
| 344 | −#define ERROR_NORD 0x0B | |
| 345 | −#define ERROR_NOWR 0x0C | |
| 346 | −#define ERROR_INVFIDTX 0x0D | |
| 347 | −#define ERROR_TESTACT 0x0E | |
| 348 | −#define ERROR_TAGNFND 0x12 | |
| 349 | −#define ERROR_DECODE 0x20 | |
| 350 | −#define ERROR_DESCUNAV 0x21 | |
| 351 | −#define ERROR_BADLEN 0x22 | |
| 352 | −#define ERROR_MODE 0x80 | |
| 353 | −#define ERROR_HOP 0x81 | |
| 354 | −#define ERROR_BINTER 0x82 | |
| 355 | −#define ERROR_RXMODE 0x83 | |
| 356 | −#define ERROR_MACADDR 0x84 | |
| 357 | −#define ERROR_RATES 0x85 | |
| 358 | −#define ERROR_ORDER 0x86 | |
| 359 | −#define ERROR_SCAN 0x87 | |
| 360 | −#define ERROR_AUTH 0x88 | |
| 361 | −#define ERROR_PSMODE 0x89 | |
| 362 | −#define ERROR_RTYPE 0x8A | |
| 363 | −#define ERROR_DIVER 0x8B | |
| 364 | −#define ERROR_SSID 0x8C | |
| 365 | −#define ERROR_APLIST 0x8D | |
| 366 | −#define ERROR_AUTOWAKE 0x8E | |
| 367 | −#define ERROR_LEAP 0x8F | |
| 368 | − | |
| 369 | −/* Registers */ | |
| 370 | −#define COMMAND 0x00 | |
| 371 | −#define PARAM0 0x02 | |
| 372 | −#define PARAM1 0x04 | |
| 373 | −#define PARAM2 0x06 | |
| 374 | −#define STATUS 0x08 | |
| 375 | −#define RESP0 0x0a | |
| 376 | −#define RESP1 0x0c | |
| 377 | −#define RESP2 0x0e | |
| 378 | −#define LINKSTAT 0x10 | |
| 379 | −#define SELECT0 0x18 | |
| 380 | −#define OFFSET0 0x1c | |
| 381 | −#define RXFID 0x20 | |
| 382 | −#define TXALLOCFID 0x22 | |
| 383 | −#define TXCOMPLFID 0x24 | |
| 384 | −#define DATA0 0x36 | |
| 385 | −#define EVSTAT 0x30 | |
| 386 | −#define EVINTEN 0x32 | |
| 387 | −#define EVACK 0x34 | |
| 388 | −#define SWS0 0x28 | |
| 389 | −#define SWS1 0x2a | |
| 390 | −#define SWS2 0x2c | |
| 391 | −#define SWS3 0x2e | |
| 392 | −#define AUXPAGE 0x3A | |
| 393 | −#define AUXOFF 0x3C | |
| 394 | −#define AUXDATA 0x3E | |
| 395 | − | |
| 396 | −#define FID_TX 1 | |
| 397 | −#define FID_RX 2 | |
| 398 | −/* Offset into aux memory for descriptors */ | |
| 399 | −#define AUX_OFFSET 0x800 | |
| 400 | −/* Size of allocated packets */ | |
| 401 | −#define PKTSIZE 1840 | |
| 402 | −#define RIDSIZE 2048 | |
| 403 | −/* Size of the transmit queue */ | |
| 404 | −#define MAXTXQ 64 | |
| 405 | − | |
| 406 | −/* BAP selectors */ | |
| 407 | −#define BAP0 0 /* Used for receiving packets */ | |
| 408 | −#define BAP1 2 /* Used for xmiting packets and working with RIDS */ | |
| 409 | − | |
| 410 | −/* Flags */ | |
| 411 | −#define COMMAND_BUSY 0x8000 | |
| 412 | − | |
| 413 | −#define BAP_BUSY 0x8000 | |
| 414 | −#define BAP_ERR 0x4000 | |
| 415 | −#define BAP_DONE 0x2000 | |
| 416 | − | |
| 417 | −#define PROMISC 0xffff | |
| 418 | −#define NOPROMISC 0x0000 | |
| 419 | − | |
| 420 | −#define EV_CMD 0x10 | |
| 421 | −#define EV_CLEARCOMMANDBUSY 0x4000 | |
| 422 | −#define EV_RX 0x01 | |
| 423 | −#define EV_TX 0x02 | |
| 424 | −#define EV_TXEXC 0x04 | |
| 425 | −#define EV_ALLOC 0x08 | |
| 426 | −#define EV_LINK 0x80 | |
| 427 | −#define EV_AWAKE 0x100 | |
| 428 | −#define EV_TXCPY 0x400 | |
| 429 | −#define EV_UNKNOWN 0x800 | |
| 430 | −#define EV_MIC 0x1000 /* Message Integrity Check Interrupt */ | |
| 431 | −#define EV_AWAKEN 0x2000 | |
| 432 | −#define STATUS_INTS (EV_AWAKE|EV_LINK|EV_TXEXC|EV_TX|EV_TXCPY|EV_RX|EV_MIC) | |
| 433 | − | |
| 434 | −#ifdef CHECK_UNKNOWN_INTS | |
| 435 | −#define IGNORE_INTS (EV_CMD | EV_UNKNOWN) | |
| 436 | −#else | |
| 437 | −#define IGNORE_INTS (~STATUS_INTS) | |
| 438 | −#endif | |
| 439 | − | |
| 440 | −/* RID TYPES */ | |
| 441 | −#define RID_RW 0x20 | |
| 442 | − | |
| 443 | −/* The RIDs */ | |
| 444 | −#define RID_CAPABILITIES 0xFF00 | |
| 445 | −#define RID_APINFO 0xFF01 | |
| 446 | −#define RID_RADIOINFO 0xFF02 | |
| 447 | −#define RID_UNKNOWN3 0xFF03 | |
| 448 | −#define RID_RSSI 0xFF04 | |
| 449 | −#define RID_CONFIG 0xFF10 | |
| 450 | −#define RID_SSID 0xFF11 | |
| 451 | −#define RID_APLIST 0xFF12 | |
| 452 | −#define RID_DRVNAME 0xFF13 | |
| 453 | −#define RID_ETHERENCAP 0xFF14 | |
| 454 | −#define RID_WEP_TEMP 0xFF15 | |
| 455 | −#define RID_WEP_PERM 0xFF16 | |
| 456 | −#define RID_MODULATION 0xFF17 | |
| 457 | −#define RID_OPTIONS 0xFF18 | |
| 458 | −#define RID_ACTUALCONFIG 0xFF20 /*readonly*/ | |
| 459 | −#define RID_FACTORYCONFIG 0xFF21 | |
| 460 | −#define RID_UNKNOWN22 0xFF22 | |
| 461 | −#define RID_LEAPUSERNAME 0xFF23 | |
| 462 | −#define RID_LEAPPASSWORD 0xFF24 | |
| 463 | −#define RID_STATUS 0xFF50 | |
| 464 | −#define RID_BEACON_HST 0xFF51 | |
| 465 | −#define RID_BUSY_HST 0xFF52 | |
| 466 | −#define RID_RETRIES_HST 0xFF53 | |
| 467 | −#define RID_UNKNOWN54 0xFF54 | |
| 468 | −#define RID_UNKNOWN55 0xFF55 | |
| 469 | −#define RID_UNKNOWN56 0xFF56 | |
| 470 | −#define RID_MIC 0xFF57 | |
| 471 | −#define RID_STATS16 0xFF60 | |
| 472 | −#define RID_STATS16DELTA 0xFF61 | |
| 473 | −#define RID_STATS16DELTACLEAR 0xFF62 | |
| 474 | −#define RID_STATS 0xFF68 | |
| 475 | −#define RID_STATSDELTA 0xFF69 | |
| 476 | −#define RID_STATSDELTACLEAR 0xFF6A | |
| 477 | −#define RID_ECHOTEST_RID 0xFF70 | |
| 478 | −#define RID_ECHOTEST_RESULTS 0xFF71 | |
| 479 | −#define RID_BSSLISTFIRST 0xFF72 | |
| 480 | −#define RID_BSSLISTNEXT 0xFF73 | |
| 481 | −#define RID_WPA_BSSLISTFIRST 0xFF74 | |
| 482 | −#define RID_WPA_BSSLISTNEXT 0xFF75 | |
| 483 | − | |
| 484 | −typedef struct { | |
| 485 | − u16 cmd; | |
| 486 | − u16 parm0; | |
| 487 | − u16 parm1; | |
| 488 | − u16 parm2; | |
| 489 | −} Cmd; | |
| 490 | − | |
| 491 | −typedef struct { | |
| 492 | − u16 status; | |
| 493 | − u16 rsp0; | |
| 494 | − u16 rsp1; | |
| 495 | − u16 rsp2; | |
| 496 | −} Resp; | |
| 497 | − | |
| 498 | −/* | |
| 499 | − * Rids and endian-ness: The Rids will always be in cpu endian, since | |
| 500 | − * this all the patches from the big-endian guys end up doing that. | |
| 501 | − * so all rid access should use the read/writeXXXRid routines. | |
| 502 | − */ | |
| 503 | − | |
| 504 | −/* This structure came from an email sent to me from an engineer at | |
| 505 | − aironet for inclusion into this driver */ | |
| 506 | −typedef struct WepKeyRid WepKeyRid; | |
| 507 | −struct WepKeyRid { | |
| 508 | − __le16 len; | |
| 509 | − __le16 kindex; | |
| 510 | − u8 mac[ETH_ALEN]; | |
| 511 | − __le16 klen; | |
| 512 | − u8 key[16]; | |
| 513 | −} __packed; | |
| 514 | − | |
| 515 | −/* These structures are from the Aironet's PC4500 Developers Manual */ | |
| 516 | −typedef struct Ssid Ssid; | |
| 517 | −struct Ssid { | |
| 518 | − __le16 len; | |
| 519 | − u8 ssid[32]; | |
| 520 | −} __packed; | |
| 521 | − | |
| 522 | −typedef struct SsidRid SsidRid; | |
| 523 | −struct SsidRid { | |
| 524 | − __le16 len; | |
| 525 | − Ssid ssids[3]; | |
| 526 | −} __packed; | |
| 527 | − | |
| 528 | −typedef struct ModulationRid ModulationRid; | |
| 529 | −struct ModulationRid { | |
| 530 | − __le16 len; | |
| 531 | − __le16 modulation; | |
| 532 | −#define MOD_DEFAULT cpu_to_le16(0) | |
| 533 | −#define MOD_CCK cpu_to_le16(1) | |
| 534 | −#define MOD_MOK cpu_to_le16(2) | |
| 535 | −} __packed; | |
| 536 | − | |
| 537 | −typedef struct ConfigRid ConfigRid; | |
| 538 | −struct ConfigRid { | |
| 539 | − __le16 len; /* sizeof(ConfigRid) */ | |
| 540 | − __le16 opmode; /* operating mode */ | |
| 541 | −#define MODE_STA_IBSS cpu_to_le16(0) | |
| 542 | −#define MODE_STA_ESS cpu_to_le16(1) | |
| 543 | −#define MODE_AP cpu_to_le16(2) | |
| 544 | −#define MODE_AP_RPTR cpu_to_le16(3) | |
| 545 | −#define MODE_CFG_MASK cpu_to_le16(0xff) | |
| 546 | −#define MODE_ETHERNET_HOST cpu_to_le16(0<<8) /* rx payloads converted */ | |
| 547 | −#define MODE_LLC_HOST cpu_to_le16(1<<8) /* rx payloads left as is */ | |
| 548 | −#define MODE_AIRONET_EXTEND cpu_to_le16(1<<9) /* enable Aironet extensions */ | |
| 549 | −#define MODE_AP_INTERFACE cpu_to_le16(1<<10) /* enable ap interface extensions */ | |
| 550 | −#define MODE_ANTENNA_ALIGN cpu_to_le16(1<<11) /* enable antenna alignment */ | |
| 551 | −#define MODE_ETHER_LLC cpu_to_le16(1<<12) /* enable ethernet LLC */ | |
| 552 | −#define MODE_LEAF_NODE cpu_to_le16(1<<13) /* enable leaf node bridge */ | |
| 553 | −#define MODE_CF_POLLABLE cpu_to_le16(1<<14) /* enable CF pollable */ | |
| 554 | −#define MODE_MIC cpu_to_le16(1<<15) /* enable MIC */ | |
| 555 | − __le16 rmode; /* receive mode */ | |
| 556 | −#define RXMODE_BC_MC_ADDR cpu_to_le16(0) | |
| 557 | −#define RXMODE_BC_ADDR cpu_to_le16(1) /* ignore multicasts */ | |
| 558 | −#define RXMODE_ADDR cpu_to_le16(2) /* ignore multicast and broadcast */ | |
| 559 | −#define RXMODE_RFMON cpu_to_le16(3) /* wireless monitor mode */ | |
| 560 | −#define RXMODE_RFMON_ANYBSS cpu_to_le16(4) | |
| 561 | −#define RXMODE_LANMON cpu_to_le16(5) /* lan style monitor -- data packets only */ | |
| 562 | −#define RXMODE_MASK cpu_to_le16(255) | |
| 563 | −#define RXMODE_DISABLE_802_3_HEADER cpu_to_le16(1<<8) /* disables 802.3 header on rx */ | |
| 564 | −#define RXMODE_FULL_MASK (RXMODE_MASK | RXMODE_DISABLE_802_3_HEADER) | |
| 565 | −#define RXMODE_NORMALIZED_RSSI cpu_to_le16(1<<9) /* return normalized RSSI */ | |
| 566 | − __le16 fragThresh; | |
| 567 | − __le16 rtsThres; | |
| 568 | − u8 macAddr[ETH_ALEN]; | |
| 569 | − u8 rates[8]; | |
| 570 | − __le16 shortRetryLimit; | |
| 571 | − __le16 longRetryLimit; | |
| 572 | − __le16 txLifetime; /* in kusec */ | |
| 573 | − __le16 rxLifetime; /* in kusec */ | |
| 574 | − __le16 stationary; | |
| 575 | − __le16 ordering; | |
| 576 | − __le16 u16deviceType; /* for overriding device type */ | |
| 577 | − __le16 cfpRate; | |
| 578 | − __le16 cfpDuration; | |
| 579 | − __le16 _reserved1[3]; | |
| 580 | − /*---------- Scanning/Associating ----------*/ | |
| 581 | − __le16 scanMode; | |
| 582 | −#define SCANMODE_ACTIVE cpu_to_le16(0) | |
| 583 | −#define SCANMODE_PASSIVE cpu_to_le16(1) | |
| 584 | −#define SCANMODE_AIROSCAN cpu_to_le16(2) | |
| 585 | − __le16 probeDelay; /* in kusec */ | |
| 586 | − __le16 probeEnergyTimeout; /* in kusec */ | |
| 587 | − __le16 probeResponseTimeout; | |
| 588 | − __le16 beaconListenTimeout; | |
| 589 | − __le16 joinNetTimeout; | |
| 590 | − __le16 authTimeout; | |
| 591 | − __le16 authType; | |
| 592 | −#define AUTH_OPEN cpu_to_le16(0x1) | |
| 593 | −#define AUTH_ENCRYPT cpu_to_le16(0x101) | |
| 594 | −#define AUTH_SHAREDKEY cpu_to_le16(0x102) | |
| 595 | −#define AUTH_ALLOW_UNENCRYPTED cpu_to_le16(0x200) | |
| 596 | − __le16 associationTimeout; | |
| 597 | − __le16 specifiedApTimeout; | |
| 598 | − __le16 offlineScanInterval; | |
| 599 | − __le16 offlineScanDuration; | |
| 600 | − __le16 linkLossDelay; | |
| 601 | − __le16 maxBeaconLostTime; | |
| 602 | − __le16 refreshInterval; | |
| 603 | −#define DISABLE_REFRESH cpu_to_le16(0xFFFF) | |
| 604 | − __le16 _reserved1a[1]; | |
| 605 | − /*---------- Power save operation ----------*/ | |
| 606 | − __le16 powerSaveMode; | |
| 607 | −#define POWERSAVE_CAM cpu_to_le16(0) | |
| 608 | −#define POWERSAVE_PSP cpu_to_le16(1) | |
| 609 | −#define POWERSAVE_PSPCAM cpu_to_le16(2) | |
| 610 | − __le16 sleepForDtims; | |
| 611 | − __le16 listenInterval; | |
| 612 | − __le16 fastListenInterval; | |
| 613 | − __le16 listenDecay; | |
| 614 | − __le16 fastListenDelay; | |
| 615 | − __le16 _reserved2[2]; | |
| 616 | − /*---------- Ap/Ibss config items ----------*/ | |
| 617 | − __le16 beaconPeriod; | |
| 618 | − __le16 atimDuration; | |
| 619 | − __le16 hopPeriod; | |
| 620 | − __le16 channelSet; | |
| 621 | − __le16 channel; | |
| 622 | − __le16 dtimPeriod; | |
| 623 | − __le16 bridgeDistance; | |
| 624 | − __le16 radioID; | |
| 625 | − /*---------- Radio configuration ----------*/ | |
| 626 | − __le16 radioType; | |
| 627 | −#define RADIOTYPE_DEFAULT cpu_to_le16(0) | |
| 628 | −#define RADIOTYPE_802_11 cpu_to_le16(1) | |
| 629 | −#define RADIOTYPE_LEGACY cpu_to_le16(2) | |
| 630 | − u8 rxDiversity; | |
| 631 | − u8 txDiversity; | |
| 632 | − __le16 txPower; | |
| 633 | −#define TXPOWER_DEFAULT 0 | |
| 634 | − __le16 rssiThreshold; | |
| 635 | −#define RSSI_DEFAULT 0 | |
| 636 | − __le16 modulation; | |
| 637 | −#define PREAMBLE_AUTO cpu_to_le16(0) | |
| 638 | −#define PREAMBLE_LONG cpu_to_le16(1) | |
| 639 | −#define PREAMBLE_SHORT cpu_to_le16(2) | |
| 640 | − __le16 preamble; | |
| 641 | − __le16 homeProduct; | |
| 642 | − __le16 radioSpecific; | |
| 643 | − /*---------- Aironet Extensions ----------*/ | |
| 644 | − u8 nodeName[16]; | |
| 645 | − __le16 arlThreshold; | |
| 646 | − __le16 arlDecay; | |
| 647 | − __le16 arlDelay; | |
| 648 | − __le16 _reserved4[1]; | |
| 649 | − /*---------- Aironet Extensions ----------*/ | |
| 650 | − u8 magicAction; | |
| 651 | −#define MAGIC_ACTION_STSCHG 1 | |
| 652 | −#define MAGIC_ACTION_RESUME 2 | |
| 653 | −#define MAGIC_IGNORE_MCAST (1<<8) | |
| 654 | −#define MAGIC_IGNORE_BCAST (1<<9) | |
| 655 | −#define MAGIC_SWITCH_TO_PSP (0<<10) | |
| 656 | −#define MAGIC_STAY_IN_CAM (1<<10) | |
| 657 | − u8 magicControl; | |
| 658 | − __le16 autoWake; | |
| 659 | −} __packed; | |
| 660 | − | |
| 661 | −typedef struct StatusRid StatusRid; | |
| 662 | −struct StatusRid { | |
| 663 | − __le16 len; | |
| 664 | − u8 mac[ETH_ALEN]; | |
| 665 | − __le16 mode; | |
| 666 | − __le16 errorCode; | |
| 667 | − __le16 sigQuality; | |
| 668 | − __le16 SSIDlen; | |
| 669 | − char SSID[32]; | |
| 670 | − char apName[16]; | |
| 671 | − u8 bssid[4][ETH_ALEN]; | |
| 672 | − __le16 beaconPeriod; | |
| 673 | − __le16 dimPeriod; | |
| 674 | − __le16 atimDuration; | |
| 675 | − __le16 hopPeriod; | |
| 676 | − __le16 channelSet; | |
| 677 | − __le16 channel; | |
| 678 | − __le16 hopsToBackbone; | |
| 679 | − __le16 apTotalLoad; | |
| 680 | − __le16 generatedLoad; | |
| 681 | − __le16 accumulatedArl; | |
| 682 | − __le16 signalQuality; | |
| 683 | − __le16 currentXmitRate; | |
| 684 | − __le16 apDevExtensions; | |
| 685 | − __le16 normalizedSignalStrength; | |
| 686 | − __le16 shortPreamble; | |
| 687 | − u8 apIP[4]; | |
| 688 | − u8 noisePercent; /* Noise percent in last second */ | |
| 689 | − u8 noisedBm; /* Noise dBm in last second */ | |
| 690 | − u8 noiseAvePercent; /* Noise percent in last minute */ | |
| 691 | − u8 noiseAvedBm; /* Noise dBm in last minute */ | |
| 692 | − u8 noiseMaxPercent; /* Highest noise percent in last minute */ | |
| 693 | − u8 noiseMaxdBm; /* Highest noise dbm in last minute */ | |
| 694 | − __le16 load; | |
| 695 | − u8 carrier[4]; | |
| 696 | − __le16 assocStatus; | |
| 697 | −#define STAT_NOPACKETS 0 | |
| 698 | −#define STAT_NOCARRIERSET 10 | |
| 699 | −#define STAT_GOTCARRIERSET 11 | |
| 700 | −#define STAT_WRONGSSID 20 | |
| 701 | −#define STAT_BADCHANNEL 25 | |
| 702 | −#define STAT_BADBITRATES 30 | |
| 703 | −#define STAT_BADPRIVACY 35 | |
| 704 | −#define STAT_APFOUND 40 | |
| 705 | −#define STAT_APREJECTED 50 | |
| 706 | −#define STAT_AUTHENTICATING 60 | |
| 707 | −#define STAT_DEAUTHENTICATED 61 | |
| 708 | −#define STAT_AUTHTIMEOUT 62 | |
| 709 | −#define STAT_ASSOCIATING 70 | |
| 710 | −#define STAT_DEASSOCIATED 71 | |
| 711 | −#define STAT_ASSOCTIMEOUT 72 | |
| 712 | −#define STAT_NOTAIROAP 73 | |
| 713 | −#define STAT_ASSOCIATED 80 | |
| 714 | −#define STAT_LEAPING 90 | |
| 715 | −#define STAT_LEAPFAILED 91 | |
| 716 | −#define STAT_LEAPTIMEDOUT 92 | |
| 717 | −#define STAT_LEAPCOMPLETE 93 | |
| 718 | −} __packed; | |
| 719 | − | |
| 720 | −typedef struct StatsRid StatsRid; | |
| 721 | −struct StatsRid { | |
| 722 | − __le16 len; | |
| 723 | − __le16 spacer; | |
| 724 | − __le32 vals[100]; | |
| 725 | −} __packed; | |
| 726 | − | |
| 727 | −typedef struct APListRid APListRid; | |
| 728 | −struct APListRid { | |
| 729 | − __le16 len; | |
| 730 | − u8 ap[4][ETH_ALEN]; | |
| 731 | −} __packed; | |
| 732 | − | |
| 733 | −typedef struct CapabilityRid CapabilityRid; | |
| 734 | −struct CapabilityRid { | |
| 735 | − __le16 len; | |
| 736 | − char oui[3]; | |
| 737 | − char zero; | |
| 738 | − __le16 prodNum; | |
| 739 | − char manName[32]; | |
| 740 | − char prodName[16]; | |
| 741 | − char prodVer[8]; | |
| 742 | − char factoryAddr[ETH_ALEN]; | |
| 743 | − char aironetAddr[ETH_ALEN]; | |
| 744 | − __le16 radioType; | |
| 745 | − __le16 country; | |
| 746 | − char callid[ETH_ALEN]; | |
| 747 | − char supportedRates[8]; | |
| 748 | − char rxDiversity; | |
| 749 | − char txDiversity; | |
| 750 | − __le16 txPowerLevels[8]; | |
| 751 | − __le16 hardVer; | |
| 752 | − __le16 hardCap; | |
| 753 | − __le16 tempRange; | |
| 754 | − __le16 softVer; | |
| 755 | − __le16 softSubVer; | |
| 756 | − __le16 interfaceVer; | |
| 757 | − __le16 softCap; | |
| 758 | − __le16 bootBlockVer; | |
| 759 | − __le16 requiredHard; | |
| 760 | − __le16 extSoftCap; | |
| 761 | −} __packed; | |
| 762 | − | |
| 763 | −/* Only present on firmware >= 5.30.17 */ | |
| 764 | −typedef struct BSSListRidExtra BSSListRidExtra; | |
| 765 | −struct BSSListRidExtra { | |
| 766 | − __le16 unknown[4]; | |
| 767 | − u8 fixed[12]; /* WLAN management frame */ | |
| 768 | − u8 iep[624]; | |
| 769 | −} __packed; | |
| 770 | − | |
| 771 | −typedef struct BSSListRid BSSListRid; | |
| 772 | −struct BSSListRid { | |
| 773 | − __le16 len; | |
| 774 | − __le16 index; /* First is 0 and 0xffff means end of list */ | |
| 775 | −#define RADIO_FH 1 /* Frequency hopping radio type */ | |
| 776 | −#define RADIO_DS 2 /* Direct sequence radio type */ | |
| 777 | −#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */ | |
| 778 | − __le16 radioType; | |
| 779 | − u8 bssid[ETH_ALEN]; /* Mac address of the BSS */ | |
| 780 | − u8 zero; | |
| 781 | − u8 ssidLen; | |
| 782 | − u8 ssid[32]; | |
| 783 | − __le16 dBm; | |
| 784 | −#define CAP_ESS cpu_to_le16(1<<0) | |
| 785 | −#define CAP_IBSS cpu_to_le16(1<<1) | |
| 786 | −#define CAP_PRIVACY cpu_to_le16(1<<4) | |
| 787 | −#define CAP_SHORTHDR cpu_to_le16(1<<5) | |
| 788 | − __le16 cap; | |
| 789 | − __le16 beaconInterval; | |
| 790 | − u8 rates[8]; /* Same as rates for config rid */ | |
| 791 | − struct { /* For frequency hopping only */ | |
| 792 | − __le16 dwell; | |
| 793 | − u8 hopSet; | |
| 794 | − u8 hopPattern; | |
| 795 | − u8 hopIndex; | |
| 796 | − u8 fill; | |
| 797 | − } fh; | |
| 798 | − __le16 dsChannel; | |
| 799 | − __le16 atimWindow; | |
| 800 | − | |
| 801 | − /* Only present on firmware >= 5.30.17 */ | |
| 802 | − BSSListRidExtra extra; | |
| 803 | −} __packed; | |
| 804 | − | |
| 805 | −typedef struct { | |
| 806 | − BSSListRid bss; | |
| 807 | − struct list_head list; | |
| 808 | −} BSSListElement; | |
| 809 | − | |
| 810 | −typedef struct tdsRssiEntry tdsRssiEntry; | |
| 811 | −struct tdsRssiEntry { | |
| 812 | − u8 rssipct; | |
| 813 | − u8 rssidBm; | |
| 814 | −} __packed; | |
| 815 | − | |
| 816 | −typedef struct tdsRssiRid tdsRssiRid; | |
| 817 | −struct tdsRssiRid { | |
| 818 | − u16 len; | |
| 819 | − tdsRssiEntry x[256]; | |
| 820 | −} __packed; | |
| 821 | − | |
| 822 | −typedef struct MICRid MICRid; | |
| 823 | −struct MICRid { | |
| 824 | − __le16 len; | |
| 825 | − __le16 state; | |
| 826 | − __le16 multicastValid; | |
| 827 | − u8 multicast[16]; | |
| 828 | − __le16 unicastValid; | |
| 829 | − u8 unicast[16]; | |
| 830 | −} __packed; | |
| 831 | − | |
| 832 | −typedef struct MICBuffer MICBuffer; | |
| 833 | −struct MICBuffer { | |
| 834 | − __be16 typelen; | |
| 835 | − | |
| 836 | − union { | |
| 837 | − u8 snap[8]; | |
| 838 | − struct { | |
| 839 | − u8 dsap; | |
| 840 | − u8 ssap; | |
| 841 | − u8 control; | |
| 842 | − u8 orgcode[3]; | |
| 843 | − u8 fieldtype[2]; | |
| 844 | − } llc; | |
| 845 | − } u; | |
| 846 | − __be32 mic; | |
| 847 | − __be32 seq; | |
| 848 | −} __packed; | |
| 849 | − | |
| 850 | −typedef struct { | |
| 851 | − u8 da[ETH_ALEN]; | |
| 852 | − u8 sa[ETH_ALEN]; | |
| 853 | −} etherHead; | |
| 854 | − | |
| 855 | −#define TXCTL_TXOK (1<<1) /* report if tx is ok */ | |
| 856 | −#define TXCTL_TXEX (1<<2) /* report if tx fails */ | |
| 857 | −#define TXCTL_802_3 (0<<3) /* 802.3 packet */ | |
| 858 | −#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */ | |
| 859 | −#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */ | |
| 860 | −#define TXCTL_LLC (1<<4) /* payload is llc */ | |
| 861 | −#define TXCTL_RELEASE (0<<5) /* release after completion */ | |
| 862 | −#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */ | |
| 863 | − | |
| 864 | −#define BUSY_FID 0x10000 | |
| 865 | − | |
| 866 | −#ifdef CISCO_EXT | |
| 867 | −#define AIROMAGIC 0xa55a | |
| 868 | −/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */ | |
| 869 | −#ifdef SIOCIWFIRSTPRIV | |
| 870 | −#ifdef SIOCDEVPRIVATE | |
| 871 | −#define AIROOLDIOCTL SIOCDEVPRIVATE | |
| 872 | −#define AIROOLDIDIFC AIROOLDIOCTL + 1 | |
| 873 | −#endif /* SIOCDEVPRIVATE */ | |
| 874 | −#else /* SIOCIWFIRSTPRIV */ | |
| 875 | −#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE | |
| 876 | −#endif /* SIOCIWFIRSTPRIV */ | |
| 877 | −/* This may be wrong. When using the new SIOCIWFIRSTPRIV range, we probably | |
| 878 | − * should use only "GET" ioctls (last bit set to 1). "SET" ioctls are root | |
| 879 | − * only and don't return the modified struct ifreq to the application which | |
| 880 | − * is usually a problem. - Jean II */ | |
| 881 | −#define AIROIOCTL SIOCIWFIRSTPRIV | |
| 882 | −#define AIROIDIFC AIROIOCTL + 1 | |
| 883 | − | |
| 884 | −/* Ioctl constants to be used in airo_ioctl.command */ | |
| 885 | − | |
| 886 | −#define AIROGCAP 0 // Capability rid | |
| 887 | −#define AIROGCFG 1 // USED A LOT | |
| 888 | −#define AIROGSLIST 2 // System ID list | |
| 889 | −#define AIROGVLIST 3 // List of specified AP's | |
| 890 | −#define AIROGDRVNAM 4 // NOTUSED | |
| 891 | −#define AIROGEHTENC 5 // NOTUSED | |
| 892 | −#define AIROGWEPKTMP 6 | |
| 893 | −#define AIROGWEPKNV 7 | |
| 894 | −#define AIROGSTAT 8 | |
| 895 | −#define AIROGSTATSC32 9 | |
| 896 | −#define AIROGSTATSD32 10 | |
| 897 | −#define AIROGMICRID 11 | |
| 898 | −#define AIROGMICSTATS 12 | |
| 899 | −#define AIROGFLAGS 13 | |
| 900 | −#define AIROGID 14 | |
| 901 | −#define AIRORRID 15 | |
| 902 | −#define AIRORSWVERSION 17 | |
| 903 | − | |
| 904 | −/* Leave gap of 40 commands after AIROGSTATSD32 for future */ | |
| 905 | − | |
| 906 | −#define AIROPCAP AIROGSTATSD32 + 40 | |
| 907 | −#define AIROPVLIST AIROPCAP + 1 | |
| 908 | −#define AIROPSLIST AIROPVLIST + 1 | |
| 909 | −#define AIROPCFG AIROPSLIST + 1 | |
| 910 | −#define AIROPSIDS AIROPCFG + 1 | |
| 911 | −#define AIROPAPLIST AIROPSIDS + 1 | |
| 912 | −#define AIROPMACON AIROPAPLIST + 1 /* Enable mac */ | |
| 913 | −#define AIROPMACOFF AIROPMACON + 1 /* Disable mac */ | |
| 914 | −#define AIROPSTCLR AIROPMACOFF + 1 | |
| 915 | −#define AIROPWEPKEY AIROPSTCLR + 1 | |
| 916 | −#define AIROPWEPKEYNV AIROPWEPKEY + 1 | |
| 917 | −#define AIROPLEAPPWD AIROPWEPKEYNV + 1 | |
| 918 | −#define AIROPLEAPUSR AIROPLEAPPWD + 1 | |
| 919 | − | |
| 920 | −/* Flash codes */ | |
| 921 | − | |
| 922 | −#define AIROFLSHRST AIROPWEPKEYNV + 40 | |
| 923 | −#define AIROFLSHGCHR AIROFLSHRST + 1 | |
| 924 | −#define AIROFLSHSTFL AIROFLSHGCHR + 1 | |
| 925 | −#define AIROFLSHPCHR AIROFLSHSTFL + 1 | |
| 926 | −#define AIROFLPUTBUF AIROFLSHPCHR + 1 | |
| 927 | −#define AIRORESTART AIROFLPUTBUF + 1 | |
| 928 | − | |
| 929 | −#define FLASHSIZE 32768 | |
| 930 | −#define AUXMEMSIZE (256 * 1024) | |
| 931 | − | |
| 932 | −typedef struct aironet_ioctl { | |
| 933 | − unsigned short command; // What to do | |
| 934 | − unsigned short len; // Len of data | |
| 935 | − unsigned short ridnum; // rid number | |
| 936 | − unsigned char __user *data; // d-data | |
| 937 | −} aironet_ioctl; | |
| 938 | − | |
| 939 | −static const char swversion[] = "2.1"; | |
| 940 | −#endif /* CISCO_EXT */ | |
| 941 | − | |
| 942 | −#define NUM_MODULES 2 | |
| 943 | −#define MIC_MSGLEN_MAX 2400 | |
| 944 | −#define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX | |
| 945 | −#define AIRO_DEF_MTU 2312 | |
| 946 | − | |
| 947 | −typedef struct { | |
| 948 | − u32 size; // size | |
| 949 | − u8 enabled; // MIC enabled or not | |
| 950 | − u32 rxSuccess; // successful packets received | |
| 951 | − u32 rxIncorrectMIC; // pkts dropped due to incorrect MIC comparison | |
| 952 | − u32 rxNotMICed; // pkts dropped due to not being MIC'd | |
| 953 | − u32 rxMICPlummed; // pkts dropped due to not having a MIC plummed | |
| 954 | − u32 rxWrongSequence; // pkts dropped due to sequence number violation | |
| 955 | − u32 reserve[32]; | |
| 956 | −} mic_statistics; | |
| 957 | − | |
| 958 | −typedef struct { | |
| 959 | − __be32 coeff[((EMMH32_MSGLEN_MAX)+3)>>2]; | |
| 960 | − u64 accum; // accumulated mic, reduced to u32 in final() | |
| 961 | − int position; // current position (byte offset) in message | |
| 962 | − union { | |
| 963 | − u8 d8[4]; | |
| 964 | − __be32 d32; | |
| 965 | − } part; // saves partial message word across update() calls | |
| 966 | −} emmh32_context; | |
| 967 | − | |
| 968 | −typedef struct { | |
| 969 | − emmh32_context seed; // Context - the seed | |
| 970 | − u32 rx; // Received sequence number | |
| 971 | − u32 tx; // Tx sequence number | |
| 972 | − u32 window; // Start of window | |
| 973 | − u8 valid; // Flag to say if context is valid or not | |
| 974 | − u8 key[16]; | |
| 975 | −} miccntx; | |
| 976 | − | |
| 977 | −typedef struct { | |
| 978 | − miccntx mCtx; // Multicast context | |
| 979 | − miccntx uCtx; // Unicast context | |
| 980 | −} mic_module; | |
| 981 | − | |
| 982 | −typedef struct { | |
| 983 | − unsigned int rid: 16; | |
| 984 | − unsigned int len: 15; | |
| 985 | − unsigned int valid: 1; | |
| 986 | − dma_addr_t host_addr; | |
| 987 | −} Rid; | |
| 988 | − | |
| 989 | −typedef struct { | |
| 990 | − unsigned int offset: 15; | |
| 991 | − unsigned int eoc: 1; | |
| 992 | − unsigned int len: 15; | |
| 993 | − unsigned int valid: 1; | |
| 994 | − dma_addr_t host_addr; | |
| 995 | −} TxFid; | |
| 996 | − | |
| 997 | −struct rx_hdr { | |
| 998 | − __le16 status, len; | |
| 999 | − u8 rssi[2]; | |
| 1000 | − u8 rate; | |
| 1001 | − u8 freq; | |
| 1002 | − __le16 tmp[4]; | |
| 1003 | −} __packed; | |
| 1004 | − | |
| 1005 | −typedef struct { | |
| 1006 | − unsigned int ctl: 15; | |
| 1007 | − unsigned int rdy: 1; | |
| 1008 | − unsigned int len: 15; | |
| 1009 | − unsigned int valid: 1; | |
| 1010 | − dma_addr_t host_addr; | |
| 1011 | −} RxFid; | |
| 1012 | − | |
| 1013 | −/* | |
| 1014 | − * Host receive descriptor | |
| 1015 | − */ | |
| 1016 | −typedef struct { | |
| 1017 | − unsigned char __iomem *card_ram_off; /* offset into card memory of the | |
| 1018 | − desc */ | |
| 1019 | − RxFid rx_desc; /* card receive descriptor */ | |
| 1020 | − char *virtual_host_addr; /* virtual address of host receive | |
| 1021 | − buffer */ | |
| 1022 | − int pending; | |
| 1023 | −} HostRxDesc; | |
| 1024 | − | |
| 1025 | −/* | |
| 1026 | − * Host transmit descriptor | |
| 1027 | − */ | |
| 1028 | −typedef struct { | |
| 1029 | − unsigned char __iomem *card_ram_off; /* offset into card memory of the | |
| 1030 | − desc */ | |
| 1031 | − TxFid tx_desc; /* card transmit descriptor */ | |
| 1032 | − char *virtual_host_addr; /* virtual address of host receive | |
| 1033 | − buffer */ | |
| 1034 | − int pending; | |
| 1035 | −} HostTxDesc; | |
| 1036 | − | |
| 1037 | −/* | |
| 1038 | − * Host RID descriptor | |
| 1039 | − */ | |
| 1040 | −typedef struct { | |
| 1041 | − unsigned char __iomem *card_ram_off; /* offset into card memory of the | |
| 1042 | − descriptor */ | |
| 1043 | − Rid rid_desc; /* card RID descriptor */ | |
| 1044 | − char *virtual_host_addr; /* virtual address of host receive | |
| 1045 | − buffer */ | |
| 1046 | −} HostRidDesc; | |
| 1047 | − | |
| 1048 | −typedef struct { | |
| 1049 | − u16 sw0; | |
| 1050 | − u16 sw1; | |
| 1051 | − u16 status; | |
| 1052 | − u16 len; | |
| 1053 | −#define HOST_SET (1 << 0) | |
| 1054 | −#define HOST_INT_TX (1 << 1) /* Interrupt on successful TX */ | |
| 1055 | −#define HOST_INT_TXERR (1 << 2) /* Interrupt on unseccessful TX */ | |
| 1056 | −#define HOST_LCC_PAYLOAD (1 << 4) /* LLC payload, 0 = Ethertype */ | |
| 1057 | −#define HOST_DONT_RLSE (1 << 5) /* Don't release buffer when done */ | |
| 1058 | −#define HOST_DONT_RETRY (1 << 6) /* Don't retry trasmit */ | |
| 1059 | −#define HOST_CLR_AID (1 << 7) /* clear AID failure */ | |
| 1060 | −#define HOST_RTS (1 << 9) /* Force RTS use */ | |
| 1061 | −#define HOST_SHORT (1 << 10) /* Do short preamble */ | |
| 1062 | − u16 ctl; | |
| 1063 | − u16 aid; | |
| 1064 | − u16 retries; | |
| 1065 | − u16 fill; | |
| 1066 | −} TxCtlHdr; | |
| 1067 | − | |
| 1068 | −typedef struct { | |
| 1069 | − u16 ctl; | |
| 1070 | − u16 duration; | |
| 1071 | − char addr1[6]; | |
| 1072 | − char addr2[6]; | |
| 1073 | − char addr3[6]; | |
| 1074 | − u16 seq; | |
| 1075 | − char addr4[6]; | |
| 1076 | −} WifiHdr; | |
| 1077 | − | |
| 1078 | − | |
| 1079 | −typedef struct { | |
| 1080 | − TxCtlHdr ctlhdr; | |
| 1081 | − u16 fill1; | |
| 1082 | − u16 fill2; | |
| 1083 | − WifiHdr wifihdr; | |
| 1084 | − u16 gaplen; | |
| 1085 | − u16 status; | |
| 1086 | −} WifiCtlHdr; | |
| 1087 | − | |
| 1088 | −static WifiCtlHdr wifictlhdr8023 = { | |
| 1089 | − .ctlhdr = { | |
| 1090 | − .ctl = HOST_DONT_RLSE, | |
| 1091 | − } | |
| 1092 | −}; | |
| 1093 | − | |
| 1094 | −// A few details needed for WEP (Wireless Equivalent Privacy) | |
| 1095 | −#define MAX_KEY_SIZE 13 // 128 (?) bits | |
| 1096 | −#define MIN_KEY_SIZE 5 // 40 bits RC4 - WEP | |
| 1097 | −typedef struct wep_key_t { | |
| 1098 | − u16 len; | |
| 1099 | − u8 key[16]; /* 40-bit and 104-bit keys */ | |
| 1100 | −} wep_key_t; | |
| 1101 | − | |
| 1102 | −/* List of Wireless Handlers (new API) */ | |
| 1103 | −static const struct iw_handler_def airo_handler_def; | |
| 1104 | − | |
| 1105 | −static const char version[] = "airo.c 0.6 (Ben Reed & Javier Achirica)"; | |
| 1106 | − | |
| 1107 | −struct airo_info; | |
| 1108 | − | |
| 1109 | −static int get_dec_u16(char *buffer, int *start, int limit); | |
| 1110 | −static void OUT4500(struct airo_info *, u16 reg, u16 value); | |
| 1111 | −static unsigned short IN4500(struct airo_info *, u16 reg); | |
| 1112 | −static u16 setup_card(struct airo_info*, struct net_device *dev, int lock); | |
| 1113 | −static int enable_MAC(struct airo_info *ai, int lock); | |
| 1114 | −static void disable_MAC(struct airo_info *ai, int lock); | |
| 1115 | −static void enable_interrupts(struct airo_info*); | |
| 1116 | −static void disable_interrupts(struct airo_info*); | |
| 1117 | −static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp, | |
| 1118 | − bool may_sleep); | |
| 1119 | −static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap); | |
| 1120 | −static int aux_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, | |
| 1121 | − int whichbap); | |
| 1122 | −static int fast_bap_read(struct airo_info*, __le16 *pu16Dst, int bytelen, | |
| 1123 | − int whichbap); | |
| 1124 | −static int bap_write(struct airo_info*, const __le16 *pu16Src, int bytelen, | |
| 1125 | − int whichbap); | |
| 1126 | −static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd); | |
| 1127 | −static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len, int lock); | |
| 1128 | −static int PC4500_writerid(struct airo_info*, u16 rid, const void | |
| 1129 | − *pBuf, int len, int lock); | |
| 1130 | −static int do_writerid(struct airo_info*, u16 rid, const void *rid_data, | |
| 1131 | − int len, int dummy); | |
| 1132 | −static u16 transmit_allocate(struct airo_info*, int lenPayload, int raw); | |
| 1133 | −static int transmit_802_3_packet(struct airo_info*, int len, char *pPacket, | |
| 1134 | − bool may_sleep); | |
| 1135 | −static int transmit_802_11_packet(struct airo_info*, int len, char *pPacket, | |
| 1136 | − bool may_sleep); | |
| 1137 | − | |
| 1138 | −static int mpi_send_packet(struct net_device *dev); | |
| 1139 | −static void mpi_unmap_card(struct pci_dev *pci); | |
| 1140 | −static void mpi_receive_802_3(struct airo_info *ai); | |
| 1141 | −static void mpi_receive_802_11(struct airo_info *ai); | |
| 1142 | −static int waitbusy(struct airo_info *ai); | |
| 1143 | − | |
| 1144 | −static irqreturn_t airo_interrupt(int irq, void* dev_id); | |
| 1145 | −static int airo_thread(void *data); | |
| 1146 | −static void timer_func(struct net_device *dev); | |
| 1147 | −static int airo_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *, int cmd); | |
| 1148 | −static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev); | |
| 1149 | −#ifdef CISCO_EXT | |
| 1150 | −static int readrids(struct net_device *dev, aironet_ioctl *comp); | |
| 1151 | −static int writerids(struct net_device *dev, aironet_ioctl *comp); | |
| 1152 | −static int flashcard(struct net_device *dev, aironet_ioctl *comp); | |
| 1153 | −#endif /* CISCO_EXT */ | |
| 1154 | −static void micinit(struct airo_info *ai); | |
| 1155 | −static int micsetup(struct airo_info *ai); | |
| 1156 | −static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); | |
| 1157 | −static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, u16 payLen); | |
| 1158 | − | |
| 1159 | −static u8 airo_rssi_to_dbm(tdsRssiEntry *rssi_rid, u8 rssi); | |
| 1160 | −static u8 airo_dbm_to_pct(tdsRssiEntry *rssi_rid, u8 dbm); | |
| 1161 | − | |
| 1162 | −static void airo_networks_free(struct airo_info *ai); | |
| 1163 | − | |
| 1164 | −struct airo_info { | |
| 1165 | − struct net_device *dev; | |
| 1166 | − struct list_head dev_list; | |
| 1167 | − /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we | |
| 1168 | − use the high bit to mark whether it is in use. */ | |
| 1169 | −#define MAX_FIDS 6 | |
| 1170 | −#define MPI_MAX_FIDS 1 | |
| 1171 | − u32 fids[MAX_FIDS]; | |
| 1172 | − ConfigRid config; | |
| 1173 | − char keyindex; // Used with auto wep | |
| 1174 | − char defindex; // Used with auto wep | |
| 1175 | − struct proc_dir_entry *proc_entry; | |
| 1176 | − spinlock_t aux_lock; | |
| 1177 | −#define FLAG_RADIO_OFF 0 /* User disabling of MAC */ | |
| 1178 | −#define FLAG_RADIO_DOWN 1 /* ifup/ifdown disabling of MAC */ | |
| 1179 | −#define FLAG_RADIO_MASK 0x03 | |
| 1180 | −#define FLAG_ENABLED 2 | |
| 1181 | −#define FLAG_ADHOC 3 /* Needed by MIC */ | |
| 1182 | −#define FLAG_MIC_CAPABLE 4 | |
| 1183 | −#define FLAG_UPDATE_MULTI 5 | |
| 1184 | −#define FLAG_UPDATE_UNI 6 | |
| 1185 | −#define FLAG_802_11 7 | |
| 1186 | −#define FLAG_PROMISC 8 /* IFF_PROMISC 0x100 - include/linux/if.h */ | |
| 1187 | −#define FLAG_PENDING_XMIT 9 | |
| 1188 | −#define FLAG_PENDING_XMIT11 10 | |
| 1189 | −#define FLAG_MPI 11 | |
| 1190 | −#define FLAG_REGISTERED 12 | |
| 1191 | −#define FLAG_COMMIT 13 | |
| 1192 | −#define FLAG_RESET 14 | |
| 1193 | −#define FLAG_FLASHING 15 | |
| 1194 | −#define FLAG_WPA_CAPABLE 16 | |
| 1195 | − unsigned long flags; | |
| 1196 | −#define JOB_DIE 0 | |
| 1197 | −#define JOB_XMIT 1 | |
| 1198 | −#define JOB_XMIT11 2 | |
| 1199 | −#define JOB_STATS 3 | |
| 1200 | −#define JOB_PROMISC 4 | |
| 1201 | −#define JOB_MIC 5 | |
| 1202 | −#define JOB_EVENT 6 | |
| 1203 | −#define JOB_AUTOWEP 7 | |
| 1204 | −#define JOB_SCAN_RESULTS 9 | |
| 1205 | − unsigned long jobs; | |
| 1206 | − int (*bap_read)(struct airo_info*, __le16 *pu16Dst, int bytelen, | |
| 1207 | − int whichbap); | |
| 1208 | − unsigned short *flash; | |
| 1209 | − tdsRssiEntry *rssi; | |
| 1210 | − struct task_struct *list_bss_task; | |
| 1211 | − struct task_struct *airo_thread_task; | |
| 1212 | − struct semaphore sem; | |
| 1213 | − wait_queue_head_t thr_wait; | |
| 1214 | − unsigned long expires; | |
| 1215 | − struct { | |
| 1216 | − struct sk_buff *skb; | |
| 1217 | − int fid; | |
| 1218 | − } xmit, xmit11; | |
| 1219 | − struct net_device *wifidev; | |
| 1220 | − struct iw_statistics wstats; // wireless stats | |
| 1221 | − unsigned long scan_timeout; /* Time scan should be read */ | |
| 1222 | − struct iw_spy_data spy_data; | |
| 1223 | − struct iw_public_data wireless_data; | |
| 1224 | − /* MIC stuff */ | |
| 1225 | − struct crypto_sync_skcipher *tfm; | |
| 1226 | − mic_module mod[2]; | |
| 1227 | − mic_statistics micstats; | |
| 1228 | − HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors | |
| 1229 | − HostTxDesc txfids[MPI_MAX_FIDS]; | |
| 1230 | − HostRidDesc config_desc; | |
| 1231 | − unsigned long ridbus; // phys addr of config_desc | |
| 1232 | − struct sk_buff_head txq;// tx queue used by mpi350 code | |
| 1233 | − struct pci_dev *pci; | |
| 1234 | − unsigned char __iomem *pcimem; | |
| 1235 | − unsigned char __iomem *pciaux; | |
| 1236 | − unsigned char *shared; | |
| 1237 | − dma_addr_t shared_dma; | |
| 1238 | − pm_message_t power; | |
| 1239 | − SsidRid *SSID; | |
| 1240 | − APListRid APList; | |
| 1241 | −#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE | |
| 1242 | − char proc_name[IFNAMSIZ]; | |
| 1243 | − | |
| 1244 | − int wep_capable; | |
| 1245 | − int max_wep_idx; | |
| 1246 | − int last_auth; | |
| 1247 | − | |
| 1248 | − /* WPA-related stuff */ | |
| 1249 | − unsigned int bssListFirst; | |
| 1250 | − unsigned int bssListNext; | |
| 1251 | − unsigned int bssListRidLen; | |
| 1252 | − | |
| 1253 | − struct list_head network_list; | |
| 1254 | − struct list_head network_free_list; | |
| 1255 | − BSSListElement *networks; | |
| 1256 | −}; | |
| 1257 | − | |
| 1258 | −static inline int bap_read(struct airo_info *ai, __le16 *pu16Dst, int bytelen, | |
| 1259 | − int whichbap) | |
| 1260 | −{ | |
| 1261 | − return ai->bap_read(ai, pu16Dst, bytelen, whichbap); | |
| 1262 | −} | |
| 1263 | − | |
| 1264 | −static int setup_proc_entry(struct net_device *dev, | |
| 1265 | − struct airo_info *apriv); | |
| 1266 | −static int takedown_proc_entry(struct net_device *dev, | |
| 1267 | − struct airo_info *apriv); | |
| 1268 | − | |
| 1269 | −static int cmdreset(struct airo_info *ai); | |
| 1270 | −static int setflashmode(struct airo_info *ai); | |
| 1271 | −static int flashgchar(struct airo_info *ai, int matchbyte, int dwelltime); | |
| 1272 | −static int flashputbuf(struct airo_info *ai); | |
| 1273 | −static int flashrestart(struct airo_info *ai, struct net_device *dev); | |
| 1274 | − | |
| 1275 | −#define airo_print(type, name, fmt, args...) \ | |
| 1276 | − printk(type DRV_NAME "(%s): " fmt "\n", name, ##args) | |
| 1277 | − | |
| 1278 | −#define airo_print_info(name, fmt, args...) \ | |
| 1279 | − airo_print(KERN_INFO, name, fmt, ##args) | |
| 1280 | − | |
| 1281 | −#define airo_print_dbg(name, fmt, args...) \ | |
| 1282 | − airo_print(KERN_DEBUG, name, fmt, ##args) | |
| 1283 | − | |
| 1284 | −#define airo_print_warn(name, fmt, args...) \ | |
| 1285 | − airo_print(KERN_WARNING, name, fmt, ##args) | |
| 1286 | − | |
| 1287 | −#define airo_print_err(name, fmt, args...) \ | |
| 1288 | − airo_print(KERN_ERR, name, fmt, ##args) | |
| 1289 | − | |
| 1290 | −#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash) | |
| 1291 | − | |
| 1292 | −/*********************************************************************** | |
| 1293 | − * MIC ROUTINES * | |
| 1294 | − *********************************************************************** | |
| 1295 | − */ | |
| 1296 | − | |
| 1297 | −static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq); | |
| 1298 | −static void MoveWindow(miccntx *context, u32 micSeq); | |
| 1299 | −static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, | |
| 1300 | − struct crypto_sync_skcipher *tfm); | |
| 1301 | −static void emmh32_init(emmh32_context *context); | |
| 1302 | −static void emmh32_update(emmh32_context *context, u8 *pOctets, int len); | |
| 1303 | −static void emmh32_final(emmh32_context *context, u8 digest[4]); | |
| 1304 | −static int flashpchar(struct airo_info *ai, int byte, int dwelltime); | |
| 1305 | − | |
| 1306 | −static void age_mic_context(miccntx *cur, miccntx *old, u8 *key, int key_len, | |
| 1307 | − struct crypto_sync_skcipher *tfm) | |
| 1308 | −{ | |
| 1309 | − /* If the current MIC context is valid and its key is the same as | |
| 1310 | − * the MIC register, there's nothing to do. | |
| 1311 | − */ | |
| 1312 | − if (cur->valid && (memcmp(cur->key, key, key_len) == 0)) | |
| 1313 | − return; | |
| 1314 | − | |
| 1315 | − /* Age current mic Context */ | |
| 1316 | − memcpy(old, cur, sizeof(*cur)); | |
| 1317 | − | |
| 1318 | − /* Initialize new context */ | |
| 1319 | − memcpy(cur->key, key, key_len); | |
| 1320 | − cur->window = 33; /* Window always points to the middle */ | |
| 1321 | − cur->rx = 0; /* Rx Sequence numbers */ | |
| 1322 | − cur->tx = 0; /* Tx sequence numbers */ | |
| 1323 | − cur->valid = 1; /* Key is now valid */ | |
| 1324 | − | |
| 1325 | − /* Give key to mic seed */ | |
| 1326 | − emmh32_setseed(&cur->seed, key, key_len, tfm); | |
| 1327 | −} | |
| 1328 | − | |
| 1329 | −/* micinit - Initialize mic seed */ | |
| 1330 | − | |
| 1331 | −static void micinit(struct airo_info *ai) | |
| 1332 | −{ | |
| 1333 | − MICRid mic_rid; | |
| 1334 | − | |
| 1335 | − clear_bit(JOB_MIC, &ai->jobs); | |
| 1336 | − PC4500_readrid(ai, RID_MIC, &mic_rid, sizeof(mic_rid), 0); | |
| 1337 | − up(&ai->sem); | |
| 1338 | − | |
| 1339 | − ai->micstats.enabled = (le16_to_cpu(mic_rid.state) & 0x00FF) ? 1 : 0; | |
| 1340 | − if (!ai->micstats.enabled) { | |
| 1341 | − /* So next time we have a valid key and mic is enabled, we will | |
| 1342 | − * update the sequence number if the key is the same as before. | |
| 1343 | − */ | |
| 1344 | − ai->mod[0].uCtx.valid = 0; | |
| 1345 | − ai->mod[0].mCtx.valid = 0; | |
| 1346 | − return; | |
| 1347 | − } | |
| 1348 | − | |
| 1349 | − if (mic_rid.multicastValid) { | |
| 1350 | − age_mic_context(&ai->mod[0].mCtx, &ai->mod[1].mCtx, | |
| 1351 | − mic_rid.multicast, sizeof(mic_rid.multicast), | |
| 1352 | − ai->tfm); | |
| 1353 | − } | |
| 1354 | − | |
| 1355 | − if (mic_rid.unicastValid) { | |
| 1356 | − age_mic_context(&ai->mod[0].uCtx, &ai->mod[1].uCtx, | |
| 1357 | − mic_rid.unicast, sizeof(mic_rid.unicast), | |
| 1358 | − ai->tfm); | |
| 1359 | − } | |
| 1360 | −} | |
| 1361 | − | |
| 1362 | −/* micsetup - Get ready for business */ | |
| 1363 | − | |
| 1364 | −static int micsetup(struct airo_info *ai) | |
| 1365 | −{ | |
| 1366 | − int i; | |
| 1367 | − | |
| 1368 | − if (ai->tfm == NULL) | |
| 1369 | − ai->tfm = crypto_alloc_sync_skcipher("ctr(aes)", 0, 0); | |
| 1370 | − | |
| 1371 | − if (IS_ERR(ai->tfm)) { | |
| 1372 | − airo_print_err(ai->dev->name, "failed to load transform for AES"); | |
| 1373 | − ai->tfm = NULL; | |
| 1374 | − return ERROR; | |
| 1375 | − } | |
| 1376 | − | |
| 1377 | − for (i = 0; i < NUM_MODULES; i++) { | |
| 1378 | − memset(&ai->mod[i].mCtx, 0, sizeof(miccntx)); | |
| 1379 | − memset(&ai->mod[i].uCtx, 0, sizeof(miccntx)); | |
| 1380 | − } | |
| 1381 | − return SUCCESS; | |
| 1382 | −} | |
| 1383 | − | |
| 1384 | −static const u8 micsnap[] = {0xAA, 0xAA, 0x03, 0x00, 0x40, 0x96, 0x00, 0x02}; | |
| 1385 | − | |
| 1386 | −/*=========================================================================== | |
| 1387 | − * Description: Mic a packet | |
| 1388 | − * | |
| 1389 | − * Inputs: etherHead * pointer to an 802.3 frame | |
| 1390 | − * | |
| 1391 | − * Returns: BOOLEAN if successful, otherwise false. | |
| 1392 | − * PacketTxLen will be updated with the mic'd packets size. | |
| 1393 | − * | |
| 1394 | − * Caveats: It is assumed that the frame buffer will already | |
| 1395 | − * be big enough to hold the largets mic message possible. | |
| 1396 | − * (No memory allocation is done here). | |
| 1397 | − * | |
| 1398 | − * Author: sbraneky (10/15/01) | |
| 1399 | − * Merciless hacks by rwilcher (1/14/02) | |
| 1400 | − */ | |
| 1401 | − | |
| 1402 | −static int encapsulate(struct airo_info *ai, etherHead *frame, MICBuffer *mic, int payLen) | |
| 1403 | −{ | |
| 1404 | − miccntx *context; | |
| 1405 | − | |
| 1406 | − // Determine correct context | |
| 1407 | − // If not adhoc, always use unicast key | |
| 1408 | − | |
| 1409 | − if (test_bit(FLAG_ADHOC, &ai->flags) && (frame->da[0] & 0x1)) | |
| 1410 | − context = &ai->mod[0].mCtx; | |
| 1411 | − else | |
| 1412 | − context = &ai->mod[0].uCtx; | |
| 1413 | − | |
| 1414 | − if (!context->valid) | |
| 1415 | − return ERROR; | |
| 1416 | − | |
| 1417 | − mic->typelen = htons(payLen + 16); //Length of Mic'd packet | |
| 1418 | − | |
| 1419 | − memcpy(&mic->u.snap, micsnap, sizeof(micsnap)); // Add Snap | |
| 1420 | − | |
| 1421 | − // Add Tx sequence | |
| 1422 | − mic->seq = htonl(context->tx); | |
| 1423 | − context->tx += 2; | |
| 1424 | − | |
| 1425 | − emmh32_init(&context->seed); // Mic the packet | |
| 1426 | − emmh32_update(&context->seed, frame->da, ETH_ALEN * 2); // DA, SA | |
| 1427 | − emmh32_update(&context->seed, (u8*)&mic->typelen, 10); // Type/Length and Snap | |
| 1428 | − emmh32_update(&context->seed, (u8*)&mic->seq, sizeof(mic->seq)); //SEQ | |
| 1429 | − emmh32_update(&context->seed, (u8*)(frame + 1), payLen); //payload | |
| 1430 | − emmh32_final(&context->seed, (u8*)&mic->mic); | |
| 1431 | − | |
| 1432 | − /* New Type/length ?????????? */ | |
| 1433 | − mic->typelen = 0; //Let NIC know it could be an oversized packet | |
| 1434 | − return SUCCESS; | |
| 1435 | −} | |
| 1436 | − | |
| 1437 | −typedef enum { | |
| 1438 | − NONE, | |
| 1439 | − NOMIC, | |
| 1440 | − NOMICPLUMMED, | |
| 1441 | − SEQUENCE, | |
| 1442 | − INCORRECTMIC, | |
| 1443 | −} mic_error; | |
| 1444 | − | |
| 1445 | −/*=========================================================================== | |
| 1446 | − * Description: Decapsulates a MIC'd packet and returns the 802.3 packet | |
| 1447 | − * (removes the MIC stuff) if packet is a valid packet. | |
| 1448 | − * | |
| 1449 | − * Inputs: etherHead pointer to the 802.3 packet | |
| 1450 | − * | |
| 1451 | − * Returns: BOOLEAN - TRUE if packet should be dropped otherwise FALSE | |
| 1452 | − * | |
| 1453 | − * Author: sbraneky (10/15/01) | |
| 1454 | − * Merciless hacks by rwilcher (1/14/02) | |
| 1455 | − *--------------------------------------------------------------------------- | |
| 1456 | − */ | |
| 1457 | − | |
| 1458 | −static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *eth, u16 payLen) | |
| 1459 | −{ | |
| 1460 | − int i; | |
| 1461 | − u32 micSEQ; | |
| 1462 | − miccntx *context; | |
| 1463 | − u8 digest[4]; | |
| 1464 | − mic_error micError = NONE; | |
| 1465 | − | |
| 1466 | − // Check if the packet is a Mic'd packet | |
| 1467 | − | |
| 1468 | − if (!ai->micstats.enabled) { | |
| 1469 | − //No Mic set or Mic OFF but we received a MIC'd packet. | |
| 1470 | − if (memcmp ((u8*)eth + 14, micsnap, sizeof(micsnap)) == 0) { | |
| 1471 | − ai->micstats.rxMICPlummed++; | |
| 1472 | − return ERROR; | |
| 1473 | − } | |
| 1474 | − return SUCCESS; | |
| 1475 | − } | |
| 1476 | − | |
| 1477 | − if (ntohs(mic->typelen) == 0x888E) | |
| 1478 | − return SUCCESS; | |
| 1479 | − | |
| 1480 | − if (memcmp (mic->u.snap, micsnap, sizeof(micsnap)) != 0) { | |
| 1481 | − // Mic enabled but packet isn't Mic'd | |
| 1482 | − ai->micstats.rxMICPlummed++; | |
| 1483 | − return ERROR; | |
| 1484 | − } | |
| 1485 | − | |
| 1486 | − micSEQ = ntohl(mic->seq); //store SEQ as CPU order | |
| 1487 | − | |
| 1488 | − //At this point we a have a mic'd packet and mic is enabled | |
| 1489 | − //Now do the mic error checking. | |
| 1490 | − | |
| 1491 | − //Receive seq must be odd | |
| 1492 | − if ((micSEQ & 1) == 0) { | |
| 1493 | − ai->micstats.rxWrongSequence++; | |
| 1494 | − return ERROR; | |
| 1495 | − } | |
| 1496 | − | |
| 1497 | − for (i = 0; i < NUM_MODULES; i++) { | |
| 1498 | − int mcast = eth->da[0] & 1; | |
| 1499 | − //Determine proper context | |
| 1500 | − context = mcast ? &ai->mod[i].mCtx : &ai->mod[i].uCtx; | |
| 1501 | − | |
| 1502 | − //Make sure context is valid | |
| 1503 | − if (!context->valid) { | |
| 1504 | − if (i == 0) | |
| 1505 | − micError = NOMICPLUMMED; | |
| 1506 | − continue; | |
| 1507 | − } | |
| 1508 | − //DeMic it | |
| 1509 | − | |
| 1510 | − if (!mic->typelen) | |
| 1511 | − mic->typelen = htons(payLen + sizeof(MICBuffer) - 2); | |
| 1512 | − | |
| 1513 | − emmh32_init(&context->seed); | |
| 1514 | − emmh32_update(&context->seed, eth->da, ETH_ALEN*2); | |
| 1515 | − emmh32_update(&context->seed, (u8 *)&mic->typelen, sizeof(mic->typelen)+sizeof(mic->u.snap)); | |
| 1516 | − emmh32_update(&context->seed, (u8 *)&mic->seq, sizeof(mic->seq)); | |
| 1517 | − emmh32_update(&context->seed, (u8 *)(eth + 1), payLen); | |
| 1518 | − //Calculate MIC | |
| 1519 | − emmh32_final(&context->seed, digest); | |
| 1520 | − | |
| 1521 | − if (memcmp(digest, &mic->mic, 4)) { //Make sure the mics match | |
| 1522 | − //Invalid Mic | |
| 1523 | − if (i == 0) | |
| 1524 | − micError = INCORRECTMIC; | |
| 1525 | − continue; | |
| 1526 | − } | |
| 1527 | − | |
| 1528 | − //Check Sequence number if mics pass | |
| 1529 | − if (RxSeqValid(ai, context, mcast, micSEQ) == SUCCESS) { | |
| 1530 | − ai->micstats.rxSuccess++; | |
| 1531 | − return SUCCESS; | |
| 1532 | − } | |
| 1533 | − if (i == 0) | |
| 1534 | − micError = SEQUENCE; | |
| 1535 | − } | |
| 1536 | − | |
| 1537 | − // Update statistics | |
| 1538 | − switch (micError) { | |
| 1539 | − case NOMICPLUMMED: ai->micstats.rxMICPlummed++; break; | |
| 1540 | − case SEQUENCE: ai->micstats.rxWrongSequence++; break; | |
| 1541 | − case INCORRECTMIC: ai->micstats.rxIncorrectMIC++; break; | |
| 1542 | − case NONE: break; | |
| 1543 | − case NOMIC: break; | |
| 1544 | − } | |
| 1545 | − return ERROR; | |
| 1546 | −} | |
| 1547 | − | |
| 1548 | −/*=========================================================================== | |
| 1549 | − * Description: Checks the Rx Seq number to make sure it is valid | |
| 1550 | − * and hasn't already been received | |
| 1551 | − * | |
| 1552 | − * Inputs: miccntx - mic context to check seq against | |
| 1553 | − * micSeq - the Mic seq number | |
| 1554 | − * | |
| 1555 | − * Returns: TRUE if valid otherwise FALSE. | |
| 1556 | − * | |
| 1557 | − * Author: sbraneky (10/15/01) | |
| 1558 | − * Merciless hacks by rwilcher (1/14/02) | |
| 1559 | − *--------------------------------------------------------------------------- | |
| 1560 | − */ | |
| 1561 | − | |
| 1562 | −static int RxSeqValid(struct airo_info *ai, miccntx *context, int mcast, u32 micSeq) | |
| 1563 | −{ | |
| 1564 | − u32 seq, index; | |
| 1565 | − | |
| 1566 | − //Allow for the ap being rebooted - if it is then use the next | |
| 1567 | − //sequence number of the current sequence number - might go backwards | |
| 1568 | − | |
| 1569 | − if (mcast) { | |
| 1570 | − if (test_bit(FLAG_UPDATE_MULTI, &ai->flags)) { | |
| 1571 | − clear_bit (FLAG_UPDATE_MULTI, &ai->flags); | |
| 1572 | − context->window = (micSeq > 33) ? micSeq : 33; | |
| 1573 | − context->rx = 0; // Reset rx | |
| 1574 | − } | |
| 1575 | − } else if (test_bit(FLAG_UPDATE_UNI, &ai->flags)) { | |
| 1576 | − clear_bit (FLAG_UPDATE_UNI, &ai->flags); | |
| 1577 | − context->window = (micSeq > 33) ? micSeq : 33; // Move window | |
| 1578 | − context->rx = 0; // Reset rx | |
| 1579 | − } | |
| 1580 | − | |
| 1581 | − //Make sequence number relative to START of window | |
| 1582 | − seq = micSeq - (context->window - 33); | |
| 1583 | − | |
| 1584 | − //Too old of a SEQ number to check. | |
| 1585 | − if ((s32)seq < 0) | |
| 1586 | − return ERROR; | |
| 1587 | − | |
| 1588 | − if (seq > 64) { | |
| 1589 | − //Window is infinite forward | |
| 1590 | − MoveWindow(context, micSeq); | |
| 1591 | − return SUCCESS; | |
| 1592 | − } | |
| 1593 | − | |
| 1594 | − // We are in the window. Now check the context rx bit to see if it was already sent | |
| 1595 | − seq >>= 1; //divide by 2 because we only have odd numbers | |
| 1596 | − index = 1 << seq; //Get an index number | |
| 1597 | − | |
| 1598 | − if (!(context->rx & index)) { | |
| 1599 | − //micSEQ falls inside the window. | |
| 1600 | − //Add seqence number to the list of received numbers. | |
| 1601 | − context->rx |= index; | |
| 1602 | − | |
| 1603 | − MoveWindow(context, micSeq); | |
| 1604 | − | |
| 1605 | − return SUCCESS; | |
| 1606 | − } | |
| 1607 | − return ERROR; | |
| 1608 | −} | |
| 1609 | − | |
| 1610 | −static void MoveWindow(miccntx *context, u32 micSeq) | |
| 1611 | −{ | |
| 1612 | − u32 shift; | |
| 1613 | − | |
| 1614 | − //Move window if seq greater than the middle of the window | |
| 1615 | − if (micSeq > context->window) { | |
| 1616 | − shift = (micSeq - context->window) >> 1; | |
| 1617 | − | |
| 1618 | − //Shift out old | |
| 1619 | − if (shift < 32) | |
| 1620 | − context->rx >>= shift; | |
| 1621 | − else | |
| 1622 | − context->rx = 0; | |
| 1623 | − | |
| 1624 | − context->window = micSeq; //Move window | |
| 1625 | − } | |
| 1626 | −} | |
| 1627 | − | |
| 1628 | −/*==============================================*/ | |
| 1629 | −/*========== EMMH ROUTINES ====================*/ | |
| 1630 | −/*==============================================*/ | |
| 1631 | − | |
| 1632 | −/* mic accumulate */ | |
| 1633 | −#define MIC_ACCUM(val) \ | |
| 1634 | − context->accum += (u64)(val) * be32_to_cpu(context->coeff[coeff_position++]); | |
| 1635 | − | |
| 1636 | −/* expand the key to fill the MMH coefficient array */ | |
| 1637 | −static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, | |
| 1638 | − struct crypto_sync_skcipher *tfm) | |
| 1639 | −{ | |
| 1640 | − /* take the keying material, expand if necessary, truncate at 16-bytes */ | |
| 1641 | − /* run through AES counter mode to generate context->coeff[] */ | |
| 1642 | − | |
| 1643 | − SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); | |
| 1644 | − struct scatterlist sg; | |
| 1645 | − u8 iv[AES_BLOCK_SIZE] = {}; | |
| 1646 | − int ret; | |
| 1647 | − | |
| 1648 | − crypto_sync_skcipher_setkey(tfm, pkey, 16); | |
| 1649 | − | |
| 1650 | − memset(context->coeff, 0, sizeof(context->coeff)); | |
| 1651 | − sg_init_one(&sg, context->coeff, sizeof(context->coeff)); | |
| 1652 | − | |
| 1653 | − skcipher_request_set_sync_tfm(req, tfm); | |
| 1654 | − skcipher_request_set_callback(req, 0, NULL, NULL); | |
| 1655 | − skcipher_request_set_crypt(req, &sg, &sg, sizeof(context->coeff), iv); | |
| 1656 | − | |
| 1657 | − ret = crypto_skcipher_encrypt(req); | |
| 1658 | − WARN_ON_ONCE(ret); | |
| 1659 | −} | |
| 1660 | − | |
| 1661 | −/* prepare for calculation of a new mic */ | |
| 1662 | −static void emmh32_init(emmh32_context *context) | |
| 1663 | −{ | |
| 1664 | − /* prepare for new mic calculation */ | |
| 1665 | − context->accum = 0; | |
| 1666 | − context->position = 0; | |
| 1667 | −} | |
| 1668 | − | |
| 1669 | −/* add some bytes to the mic calculation */ | |
| 1670 | −static void emmh32_update(emmh32_context *context, u8 *pOctets, int len) | |
| 1671 | −{ | |
| 1672 | − int coeff_position, byte_position; | |
| 1673 | − | |
| 1674 | − if (len == 0) return; | |
| 1675 | − | |
| 1676 | − coeff_position = context->position >> 2; | |
| 1677 | − | |
| 1678 | − /* deal with partial 32-bit word left over from last update */ | |
| 1679 | − byte_position = context->position & 3; | |
| 1680 | − if (byte_position) { | |
| 1681 | − /* have a partial word in part to deal with */ | |
| 1682 | − do { | |
| 1683 | − if (len == 0) return; | |
| 1684 | − context->part.d8[byte_position++] = *pOctets++; | |
| 1685 | − context->position++; | |
| 1686 | − len--; | |
| 1687 | − } while (byte_position < 4); | |
| 1688 | − MIC_ACCUM(ntohl(context->part.d32)); | |
| 1689 | − } | |
| 1690 | − | |
| 1691 | − /* deal with full 32-bit words */ | |
| 1692 | − while (len >= 4) { | |
| 1693 | − MIC_ACCUM(ntohl(*(__be32 *)pOctets)); | |
| 1694 | − context->position += 4; | |
| 1695 | − pOctets += 4; | |
| 1696 | − len -= 4; | |
| 1697 | − } | |
| 1698 | − | |
| 1699 | − /* deal with partial 32-bit word that will be left over from this update */ | |
| 1700 | − byte_position = 0; | |
| 1701 | − while (len > 0) { | |
| 1702 | − context->part.d8[byte_position++] = *pOctets++; | |
| 1703 | − context->position++; | |
| 1704 | − len--; | |
| 1705 | − } | |
| 1706 | −} | |
| 1707 | − | |
| 1708 | −/* mask used to zero empty bytes for final partial word */ | |
| 1709 | −static u32 mask32[4] = { 0x00000000L, 0xFF000000L, 0xFFFF0000L, 0xFFFFFF00L }; | |
| 1710 | − | |
| 1711 | −/* calculate the mic */ | |
| 1712 | −static void emmh32_final(emmh32_context *context, u8 digest[4]) | |
| 1713 | −{ | |
| 1714 | − int coeff_position, byte_position; | |
| 1715 | − u32 val; | |
| 1716 | − | |
| 1717 | − u64 sum, utmp; | |
| 1718 | − s64 stmp; | |
| 1719 | − | |
| 1720 | − coeff_position = context->position >> 2; | |
| 1721 | − | |
| 1722 | − /* deal with partial 32-bit word left over from last update */ | |
| 1723 | − byte_position = context->position & 3; | |
| 1724 | − if (byte_position) { | |
| 1725 | − /* have a partial word in part to deal with */ | |
| 1726 | − val = ntohl(context->part.d32); | |
| 1727 | − MIC_ACCUM(val & mask32[byte_position]); /* zero empty bytes */ | |
| 1728 | − } | |
| 1729 | − | |
| 1730 | − /* reduce the accumulated u64 to a 32-bit MIC */ | |
| 1731 | − sum = context->accum; | |
| 1732 | − stmp = (sum & 0xffffffffLL) - ((sum >> 32) * 15); | |
| 1733 | − utmp = (stmp & 0xffffffffLL) - ((stmp >> 32) * 15); | |
| 1734 | − sum = utmp & 0xffffffffLL; | |
| 1735 | − if (utmp > 0x10000000fLL) | |
| 1736 | − sum -= 15; | |
| 1737 | − | |
| 1738 | − val = (u32)sum; | |
| 1739 | − digest[0] = (val>>24) & 0xFF; | |
| 1740 | − digest[1] = (val>>16) & 0xFF; | |
| 1741 | − digest[2] = (val>>8) & 0xFF; | |
| 1742 | − digest[3] = val & 0xFF; | |
| 1743 | −} | |
| 1744 | − | |
| 1745 | −static int readBSSListRid(struct airo_info *ai, int first, | |
| 1746 | − BSSListRid *list) | |
| 1747 | −{ | |
| 1748 | − Cmd cmd; | |
| 1749 | − Resp rsp; | |
| 1750 | − | |
| 1751 | − if (first == 1) { | |
| 1752 | − if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; | |
| 1753 | − memset(&cmd, 0, sizeof(cmd)); | |
| 1754 | − cmd.cmd = CMD_LISTBSS; | |
| 1755 | − if (down_interruptible(&ai->sem)) | |
| 1756 | − return -ERESTARTSYS; | |
| 1757 | − ai->list_bss_task = current; | |
| 1758 | − issuecommand(ai, &cmd, &rsp, true); | |
| 1759 | − up(&ai->sem); | |
| 1760 | − /* Let the command take effect */ | |
| 1761 | − schedule_timeout_uninterruptible(3 * HZ); | |
| 1762 | − ai->list_bss_task = NULL; | |
| 1763 | − } | |
| 1764 | − return PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext, | |
| 1765 | − list, ai->bssListRidLen, 1); | |
| 1766 | −} | |
| 1767 | − | |
| 1768 | −static int readWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int temp, int lock) | |
| 1769 | −{ | |
| 1770 | − return PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM, | |
| 1771 | − wkr, sizeof(*wkr), lock); | |
| 1772 | −} | |
| 1773 | − | |
| 1774 | −static int writeWepKeyRid(struct airo_info *ai, WepKeyRid *wkr, int perm, int lock) | |
| 1775 | −{ | |
| 1776 | − int rc; | |
| 1777 | − rc = PC4500_writerid(ai, RID_WEP_TEMP, wkr, sizeof(*wkr), lock); | |
| 1778 | − if (rc!=SUCCESS) | |
| 1779 | − airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); | |
| 1780 | − if (perm) { | |
| 1781 | − rc = PC4500_writerid(ai, RID_WEP_PERM, wkr, sizeof(*wkr), lock); | |
| 1782 | − if (rc!=SUCCESS) | |
| 1783 | − airo_print_err(ai->dev->name, "WEP_PERM set %x", rc); | |
| 1784 | − } | |
| 1785 | − return rc; | |
| 1786 | −} | |
| 1787 | − | |
| 1788 | −static int readSsidRid(struct airo_info*ai, SsidRid *ssidr) | |
| 1789 | −{ | |
| 1790 | − return PC4500_readrid(ai, RID_SSID, ssidr, sizeof(*ssidr), 1); | |
| 1791 | −} | |
| 1792 | − | |
| 1793 | −static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr, int lock) | |
| 1794 | −{ | |
| 1795 | − return PC4500_writerid(ai, RID_SSID, pssidr, sizeof(*pssidr), lock); | |
| 1796 | −} | |
| 1797 | − | |
| 1798 | −static int readConfigRid(struct airo_info *ai, int lock) | |
| 1799 | −{ | |
| 1800 | − int rc; | |
| 1801 | − ConfigRid cfg; | |
| 1802 | − | |
| 1803 | − if (ai->config.len) | |
| 1804 | − return SUCCESS; | |
| 1805 | − | |
| 1806 | − rc = PC4500_readrid(ai, RID_ACTUALCONFIG, &cfg, sizeof(cfg), lock); | |
| 1807 | − if (rc != SUCCESS) | |
| 1808 | − return rc; | |
| 1809 | − | |
| 1810 | − ai->config = cfg; | |
| 1811 | − return SUCCESS; | |
| 1812 | −} | |
| 1813 | − | |
| 1814 | −static inline void checkThrottle(struct airo_info *ai) | |
| 1815 | −{ | |
| 1816 | − int i; | |
| 1817 | −/* Old hardware had a limit on encryption speed */ | |
| 1818 | − if (ai->config.authType != AUTH_OPEN && maxencrypt) { | |
| 1819 | − for (i = 0; i<8; i++) { | |
| 1820 | − if (ai->config.rates[i] > maxencrypt) { | |
| 1821 | − ai->config.rates[i] = 0; | |
| 1822 | − } | |
| 1823 | − } | |
| 1824 | − } | |
| 1825 | −} | |
| 1826 | − | |
| 1827 | −static int writeConfigRid(struct airo_info *ai, int lock) | |
| 1828 | −{ | |
| 1829 | − ConfigRid cfgr; | |
| 1830 | − | |
| 1831 | − if (!test_bit (FLAG_COMMIT, &ai->flags)) | |
| 1832 | − return SUCCESS; | |
| 1833 | − | |
| 1834 | − clear_bit (FLAG_COMMIT, &ai->flags); | |
| 1835 | − clear_bit (FLAG_RESET, &ai->flags); | |
| 1836 | − checkThrottle(ai); | |
| 1837 | − cfgr = ai->config; | |
| 1838 | − | |
| 1839 | − if ((cfgr.opmode & MODE_CFG_MASK) == MODE_STA_IBSS) | |
| 1840 | − set_bit(FLAG_ADHOC, &ai->flags); | |
| 1841 | − else | |
| 1842 | − clear_bit(FLAG_ADHOC, &ai->flags); | |
| 1843 | − | |
| 1844 | − return PC4500_writerid(ai, RID_CONFIG, &cfgr, sizeof(cfgr), lock); | |
| 1845 | −} | |
| 1846 | − | |
| 1847 | −static int readStatusRid(struct airo_info *ai, StatusRid *statr, int lock) | |
| 1848 | −{ | |
| 1849 | − return PC4500_readrid(ai, RID_STATUS, statr, sizeof(*statr), lock); | |
| 1850 | −} | |
| 1851 | − | |
| 1852 | −static int writeAPListRid(struct airo_info *ai, APListRid *aplr, int lock) | |
| 1853 | −{ | |
| 1854 | − return PC4500_writerid(ai, RID_APLIST, aplr, sizeof(*aplr), lock); | |
| 1855 | −} | |
| 1856 | − | |
| 1857 | −static int readCapabilityRid(struct airo_info *ai, CapabilityRid *capr, int lock) | |
| 1858 | −{ | |
| 1859 | − return PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr), lock); | |
| 1860 | −} | |
| 1861 | − | |
| 1862 | −static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) | |
| 1863 | −{ | |
| 1864 | − return PC4500_readrid(ai, rid, sr, sizeof(*sr), lock); | |
| 1865 | −} | |
| 1866 | − | |
| 1867 | −static void try_auto_wep(struct airo_info *ai) | |
| 1868 | −{ | |
| 1869 | − if (auto_wep && !test_bit(FLAG_RADIO_DOWN, &ai->flags)) { | |
| 1870 | − ai->expires = RUN_AT(3*HZ); | |
| 1871 | − wake_up_interruptible(&ai->thr_wait); | |
| 1872 | − } | |
| 1873 | −} | |
| 1874 | − | |
| 1875 | −static int airo_open(struct net_device *dev) | |
| 1876 | −{ | |
| 1877 | − struct airo_info *ai = dev->ml_priv; | |
| 1878 | − int rc = 0; | |
| 1879 | − | |
| 1880 | − if (test_bit(FLAG_FLASHING, &ai->flags)) | |
| 1881 | − return -EIO; | |
| 1882 | − | |
| 1883 | − /* Make sure the card is configured. | |
| 1884 | − * Wireless Extensions may postpone config changes until the card | |
| 1885 | − * is open (to pipeline changes and speed-up card setup). If | |
| 1886 | − * those changes are not yet committed, do it now - Jean II */ | |
| 1887 | − if (test_bit(FLAG_COMMIT, &ai->flags)) { | |
| 1888 | − disable_MAC(ai, 1); | |
| 1889 | − writeConfigRid(ai, 1); | |
| 1890 | − } | |
| 1891 | − | |
| 1892 | − if (ai->wifidev != dev) { | |
| 1893 | − clear_bit(JOB_DIE, &ai->jobs); | |
| 1894 | − ai->airo_thread_task = kthread_run(airo_thread, dev, "%s", | |
| 1895 | − dev->name); | |
| 1896 | − if (IS_ERR(ai->airo_thread_task)) | |
| 1897 | − return (int)PTR_ERR(ai->airo_thread_task); | |
| 1898 | − | |
| 1899 | − rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED, | |
| 1900 | − dev->name, dev); | |
| 1901 | − if (rc) { | |
| 1902 | − airo_print_err(dev->name, | |
| 1903 | − "register interrupt %d failed, rc %d", | |
| 1904 | − dev->irq, rc); | |
| 1905 | − set_bit(JOB_DIE, &ai->jobs); | |
| 1906 | − kthread_stop(ai->airo_thread_task); | |
| 1907 | − return rc; | |
| 1908 | − } | |
| 1909 | − | |
| 1910 | − /* Power on the MAC controller (which may have been disabled) */ | |
| 1911 | − clear_bit(FLAG_RADIO_DOWN, &ai->flags); | |
| 1912 | − enable_interrupts(ai); | |
| 1913 | − | |
| 1914 | − try_auto_wep(ai); | |
| 1915 | − } | |
| 1916 | − enable_MAC(ai, 1); | |
| 1917 | − | |
| 1918 | − netif_start_queue(dev); | |
| 1919 | − return 0; | |
| 1920 | −} | |
| 1921 | − | |
| 1922 | −static netdev_tx_t mpi_start_xmit(struct sk_buff *skb, | |
| 1923 | − struct net_device *dev) | |
| 1924 | −{ | |
| 1925 | − int npacks, pending; | |
| 1926 | − unsigned long flags; | |
| 1927 | − struct airo_info *ai = dev->ml_priv; | |
| 1928 | − | |
| 1929 | − if (!skb) { | |
| 1930 | − airo_print_err(dev->name, "%s: skb == NULL!",__func__); | |
| 1931 | − return NETDEV_TX_OK; | |
| 1932 | − } | |
| 1933 | − if (skb_padto(skb, ETH_ZLEN)) { | |
| 1934 | − dev->stats.tx_dropped++; | |
| 1935 | − return NETDEV_TX_OK; | |
| 1936 | − } | |
| 1937 | − npacks = skb_queue_len (&ai->txq); | |
| 1938 | − | |
| 1939 | − if (npacks >= MAXTXQ - 1) { | |
| 1940 | − netif_stop_queue (dev); | |
| 1941 | − if (npacks > MAXTXQ) { | |
| 1942 | − dev->stats.tx_fifo_errors++; | |
| 1943 | − return NETDEV_TX_BUSY; | |
| 1944 | − } | |
| 1945 | − skb_queue_tail (&ai->txq, skb); | |
| 1946 | − return NETDEV_TX_OK; | |
| 1947 | − } | |
| 1948 | − | |
| 1949 | − spin_lock_irqsave(&ai->aux_lock, flags); | |
| 1950 | − skb_queue_tail (&ai->txq, skb); | |
| 1951 | − pending = test_bit(FLAG_PENDING_XMIT, &ai->flags); | |
| 1952 | − spin_unlock_irqrestore(&ai->aux_lock, flags); | |
| 1953 | − netif_wake_queue (dev); | |
| 1954 | − | |
| 1955 | − if (pending == 0) { | |
| 1956 | − set_bit(FLAG_PENDING_XMIT, &ai->flags); | |
| 1957 | − mpi_send_packet (dev); | |
| 1958 | − } | |
| 1959 | − return NETDEV_TX_OK; | |
| 1960 | −} | |
| 1961 | − | |
| 1962 | −/* | |
| 1963 | − * @mpi_send_packet | |
| 1964 | − * | |
| 1965 | − * Attempt to transmit a packet. Can be called from interrupt | |
| 1966 | − * or transmit . return number of packets we tried to send | |
| 1967 | − */ | |
| 1968 | − | |
| 1969 | −static int mpi_send_packet (struct net_device *dev) | |
| 1970 | −{ | |
| 1971 | − struct sk_buff *skb; | |
| 1972 | − unsigned char *buffer; | |
| 1973 | − s16 len; | |
| 1974 | − __le16 *payloadLen; | |
| 1975 | − struct airo_info *ai = dev->ml_priv; | |
| 1976 | − u8 *sendbuf; | |
| 1977 | − | |
| 1978 | − /* get a packet to send */ | |
| 1979 | − | |
| 1980 | − if ((skb = skb_dequeue(&ai->txq)) == NULL) { | |
| 1981 | − airo_print_err(dev->name, | |
| 1982 | − "%s: Dequeue'd zero in send_packet()", | |
| 1983 | − __func__); | |
| 1984 | − return 0; | |
| 1985 | − } | |
| 1986 | − | |
| 1987 | − /* check min length*/ | |
| 1988 | − len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | |
| 1989 | − buffer = skb->data; | |
| 1990 | − | |
| 1991 | − ai->txfids[0].tx_desc.offset = 0; | |
| 1992 | − ai->txfids[0].tx_desc.valid = 1; | |
| 1993 | − ai->txfids[0].tx_desc.eoc = 1; | |
| 1994 | − ai->txfids[0].tx_desc.len =len+sizeof(WifiHdr); | |
| 1995 | − | |
| 1996 | −/* | |
| 1997 | − * Magic, the cards firmware needs a length count (2 bytes) in the host buffer | |
| 1998 | − * right after TXFID_HDR.The TXFID_HDR contains the status short so payloadlen | |
| 1999 | − * is immediately after it. ------------------------------------------------ | |
| 2000 | − * |TXFIDHDR+STATUS|PAYLOADLEN|802.3HDR|PACKETDATA| | |
| 2001 | − * ------------------------------------------------ | |
| 2002 | − */ | |
| 2003 | − | |
| 2004 | − memcpy(ai->txfids[0].virtual_host_addr, | |
| 2005 | − (char *)&wifictlhdr8023, sizeof(wifictlhdr8023)); | |
| 2006 | − | |
| 2007 | − payloadLen = (__le16 *)(ai->txfids[0].virtual_host_addr + | |
| 2008 | − sizeof(wifictlhdr8023)); | |
| 2009 | − sendbuf = ai->txfids[0].virtual_host_addr + | |
| 2010 | − sizeof(wifictlhdr8023) + 2 ; | |
| 2011 | − | |
| 2012 | − /* | |
| 2013 | − * Firmware automatically puts 802 header on so | |
| 2014 | − * we don't need to account for it in the length | |
| 2015 | − */ | |
| 2016 | − if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && | |
| 2017 | − (ntohs(((__be16 *)buffer)[6]) != 0x888E)) { | |
| 2018 | − MICBuffer pMic; | |
| 2019 | − | |
| 2020 | − if (encapsulate(ai, (etherHead *)buffer, &pMic, len - sizeof(etherHead)) != SUCCESS) | |
| 2021 | − return ERROR; | |
| 2022 | − | |
| 2023 | − *payloadLen = cpu_to_le16(len-sizeof(etherHead)+sizeof(pMic)); | |
| 2024 | − ai->txfids[0].tx_desc.len += sizeof(pMic); | |
| 2025 | − /* copy data into airo dma buffer */ | |
| 2026 | − memcpy (sendbuf, buffer, sizeof(etherHead)); | |
| 2027 | − buffer += sizeof(etherHead); | |
| 2028 | − sendbuf += sizeof(etherHead); | |
| 2029 | − memcpy (sendbuf, &pMic, sizeof(pMic)); | |
| 2030 | − sendbuf += sizeof(pMic); | |
| 2031 | − memcpy (sendbuf, buffer, len - sizeof(etherHead)); | |
| 2032 | − } else { | |
| 2033 | − *payloadLen = cpu_to_le16(len - sizeof(etherHead)); | |
| 2034 | − | |
| 2035 | − netif_trans_update(dev); | |
| 2036 | − | |
| 2037 | − /* copy data into airo dma buffer */ | |
| 2038 | − memcpy(sendbuf, buffer, len); | |
| 2039 | − } | |
| 2040 | − | |
| 2041 | − memcpy_toio(ai->txfids[0].card_ram_off, | |
| 2042 | − &ai->txfids[0].tx_desc, sizeof(TxFid)); | |
| 2043 | − | |
| 2044 | − OUT4500(ai, EVACK, 8); | |
| 2045 | − | |
| 2046 | − dev_kfree_skb_any(skb); | |
| 2047 | − return 1; | |
| 2048 | −} | |
| 2049 | − | |
| 2050 | −static void get_tx_error(struct airo_info *ai, s32 fid) | |
| 2051 | −{ | |
| 2052 | − __le16 status; | |
| 2053 | − | |
| 2054 | − if (fid < 0) | |
| 2055 | − status = ((WifiCtlHdr *)ai->txfids[0].virtual_host_addr)->ctlhdr.status; | |
| 2056 | − else { | |
| 2057 | − if (bap_setup(ai, ai->fids[fid] & 0xffff, 4, BAP0) != SUCCESS) | |
| 2058 | − return; | |
| 2059 | − bap_read(ai, &status, 2, BAP0); | |
| 2060 | − } | |
| 2061 | − if (le16_to_cpu(status) & 2) /* Too many retries */ | |
| 2062 | − ai->dev->stats.tx_aborted_errors++; | |
| 2063 | − if (le16_to_cpu(status) & 4) /* Transmit lifetime exceeded */ | |
| 2064 | − ai->dev->stats.tx_heartbeat_errors++; | |
| 2065 | − if (le16_to_cpu(status) & 8) /* Aid fail */ | |
| 2066 | − { } | |
| 2067 | − if (le16_to_cpu(status) & 0x10) /* MAC disabled */ | |
| 2068 | − ai->dev->stats.tx_carrier_errors++; | |
| 2069 | − if (le16_to_cpu(status) & 0x20) /* Association lost */ | |
| 2070 | − { } | |
| 2071 | − /* We produce a TXDROP event only for retry or lifetime | |
| 2072 | − * exceeded, because that's the only status that really mean | |
| 2073 | − * that this particular node went away. | |
| 2074 | − * Other errors means that *we* screwed up. - Jean II */ | |
| 2075 | − if ((le16_to_cpu(status) & 2) || | |
| 2076 | − (le16_to_cpu(status) & 4)) { | |
| 2077 | − union iwreq_data wrqu; | |
| 2078 | − char junk[0x18]; | |
| 2079 | − | |
| 2080 | − /* Faster to skip over useless data than to do | |
| 2081 | − * another bap_setup(). We are at offset 0x6 and | |
| 2082 | − * need to go to 0x18 and read 6 bytes - Jean II */ | |
| 2083 | − bap_read(ai, (__le16 *) junk, 0x18, BAP0); | |
| 2084 | − | |
| 2085 | − /* Copy 802.11 dest address. | |
| 2086 | − * We use the 802.11 header because the frame may | |
| 2087 | − * not be 802.3 or may be mangled... | |
| 2088 | − * In Ad-Hoc mode, it will be the node address. | |
| 2089 | − * In managed mode, it will be most likely the AP addr | |
| 2090 | − * User space will figure out how to convert it to | |
| 2091 | − * whatever it needs (IP address or else). | |
| 2092 | − * - Jean II */ | |
| 2093 | − memcpy(wrqu.addr.sa_data, junk + 0x12, ETH_ALEN); | |
| 2094 | − wrqu.addr.sa_family = ARPHRD_ETHER; | |
| 2095 | − | |
| 2096 | − /* Send event to user space */ | |
| 2097 | − wireless_send_event(ai->dev, IWEVTXDROP, &wrqu, NULL); | |
| 2098 | − } | |
| 2099 | −} | |
| 2100 | − | |
| 2101 | −static void airo_end_xmit(struct net_device *dev, bool may_sleep) | |
| 2102 | −{ | |
| 2103 | − u16 status; | |
| 2104 | − int i; | |
| 2105 | − struct airo_info *priv = dev->ml_priv; | |
| 2106 | − struct sk_buff *skb = priv->xmit.skb; | |
| 2107 | − int fid = priv->xmit.fid; | |
| 2108 | − u32 *fids = priv->fids; | |
| 2109 | − | |
| 2110 | − clear_bit(JOB_XMIT, &priv->jobs); | |
| 2111 | − clear_bit(FLAG_PENDING_XMIT, &priv->flags); | |
| 2112 | − status = transmit_802_3_packet(priv, fids[fid], skb->data, may_sleep); | |
| 2113 | − up(&priv->sem); | |
| 2114 | − | |
| 2115 | − i = 0; | |
| 2116 | − if (status == SUCCESS) { | |
| 2117 | − netif_trans_update(dev); | |
| 2118 | − for (; i < MAX_FIDS / 2 && (priv->fids[i] & 0xffff0000); i++); | |
| 2119 | − } else { | |
| 2120 | − priv->fids[fid] &= 0xffff; | |
| 2121 | − dev->stats.tx_window_errors++; | |
| 2122 | − } | |
| 2123 | − if (i < MAX_FIDS / 2) | |
| 2124 | − netif_wake_queue(dev); | |
| 2125 | − dev_kfree_skb(skb); | |
| 2126 | −} | |
| 2127 | − | |
| 2128 | −static netdev_tx_t airo_start_xmit(struct sk_buff *skb, | |
| 2129 | − struct net_device *dev) | |
| 2130 | −{ | |
| 2131 | − s16 len; | |
| 2132 | − int i, j; | |
| 2133 | − struct airo_info *priv = dev->ml_priv; | |
| 2134 | − u32 *fids = priv->fids; | |
| 2135 | − | |
| 2136 | − if (skb == NULL) { | |
| 2137 | − airo_print_err(dev->name, "%s: skb == NULL!", __func__); | |
| 2138 | − return NETDEV_TX_OK; | |
| 2139 | − } | |
| 2140 | − if (skb_padto(skb, ETH_ZLEN)) { | |
| 2141 | − dev->stats.tx_dropped++; | |
| 2142 | − return NETDEV_TX_OK; | |
| 2143 | − } | |
| 2144 | − | |
| 2145 | − /* Find a vacant FID */ | |
| 2146 | − for (i = 0; i < MAX_FIDS / 2 && (fids[i] & 0xffff0000); i++); | |
| 2147 | − for (j = i + 1; j < MAX_FIDS / 2 && (fids[j] & 0xffff0000); j++); | |
| 2148 | − | |
| 2149 | − if (j >= MAX_FIDS / 2) { | |
| 2150 | − netif_stop_queue(dev); | |
| 2151 | − | |
| 2152 | − if (i == MAX_FIDS / 2) { | |
| 2153 | − dev->stats.tx_fifo_errors++; | |
| 2154 | − return NETDEV_TX_BUSY; | |
| 2155 | − } | |
| 2156 | − } | |
| 2157 | − /* check min length*/ | |
| 2158 | − len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | |
| 2159 | − /* Mark fid as used & save length for later */ | |
| 2160 | − fids[i] |= (len << 16); | |
| 2161 | − priv->xmit.skb = skb; | |
| 2162 | − priv->xmit.fid = i; | |
| 2163 | − if (down_trylock(&priv->sem) != 0) { | |
| 2164 | − set_bit(FLAG_PENDING_XMIT, &priv->flags); | |
| 2165 | − netif_stop_queue(dev); | |
| 2166 | − set_bit(JOB_XMIT, &priv->jobs); | |
| 2167 | − wake_up_interruptible(&priv->thr_wait); | |
| 2168 | − } else | |
| 2169 | − airo_end_xmit(dev, false); | |
| 2170 | − return NETDEV_TX_OK; | |
| 2171 | −} | |
| 2172 | − | |
| 2173 | −static void airo_end_xmit11(struct net_device *dev, bool may_sleep) | |
| 2174 | −{ | |
| 2175 | − u16 status; | |
| 2176 | − int i; | |
| 2177 | − struct airo_info *priv = dev->ml_priv; | |
| 2178 | − struct sk_buff *skb = priv->xmit11.skb; | |
| 2179 | − int fid = priv->xmit11.fid; | |
| 2180 | − u32 *fids = priv->fids; | |
| 2181 | − | |
| 2182 | − clear_bit(JOB_XMIT11, &priv->jobs); | |
| 2183 | − clear_bit(FLAG_PENDING_XMIT11, &priv->flags); | |
| 2184 | − status = transmit_802_11_packet(priv, fids[fid], skb->data, may_sleep); | |
| 2185 | − up(&priv->sem); | |
| 2186 | − | |
| 2187 | − i = MAX_FIDS / 2; | |
| 2188 | − if (status == SUCCESS) { | |
| 2189 | − netif_trans_update(dev); | |
| 2190 | − for (; i < MAX_FIDS && (priv->fids[i] & 0xffff0000); i++); | |
| 2191 | − } else { | |
| 2192 | − priv->fids[fid] &= 0xffff; | |
| 2193 | − dev->stats.tx_window_errors++; | |
| 2194 | − } | |
| 2195 | − if (i < MAX_FIDS) | |
| 2196 | − netif_wake_queue(dev); | |
| 2197 | − dev_kfree_skb(skb); | |
| 2198 | −} | |
| 2199 | − | |
| 2200 | −static netdev_tx_t airo_start_xmit11(struct sk_buff *skb, | |
| 2201 | − struct net_device *dev) | |
| 2202 | −{ | |
| 2203 | − s16 len; | |
| 2204 | − int i, j; | |
| 2205 | − struct airo_info *priv = dev->ml_priv; | |
| 2206 | − u32 *fids = priv->fids; | |
| 2207 | − | |
| 2208 | − if (test_bit(FLAG_MPI, &priv->flags)) { | |
| 2209 | − /* Not implemented yet for MPI350 */ | |
| 2210 | − netif_stop_queue(dev); | |
| 2211 | − dev_kfree_skb_any(skb); | |
| 2212 | − return NETDEV_TX_OK; | |
| 2213 | − } | |
| 2214 | − | |
| 2215 | − if (skb == NULL) { | |
| 2216 | − airo_print_err(dev->name, "%s: skb == NULL!", __func__); | |
| 2217 | − return NETDEV_TX_OK; | |
| 2218 | − } | |
| 2219 | − if (skb_padto(skb, ETH_ZLEN)) { | |
| 2220 | − dev->stats.tx_dropped++; | |
| 2221 | − return NETDEV_TX_OK; | |
| 2222 | − } | |
| 2223 | − | |
| 2224 | − /* Find a vacant FID */ | |
| 2225 | − for (i = MAX_FIDS / 2; i < MAX_FIDS && (fids[i] & 0xffff0000); i++); | |
| 2226 | − for (j = i + 1; j < MAX_FIDS && (fids[j] & 0xffff0000); j++); | |
| 2227 | − | |
| 2228 | − if (j >= MAX_FIDS) { | |
| 2229 | − netif_stop_queue(dev); | |
| 2230 | − | |
| 2231 | − if (i == MAX_FIDS) { | |
| 2232 | − dev->stats.tx_fifo_errors++; | |
| 2233 | − return NETDEV_TX_BUSY; | |
| 2234 | − } | |
| 2235 | − } | |
| 2236 | − /* check min length*/ | |
| 2237 | − len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | |
| 2238 | − /* Mark fid as used & save length for later */ | |
| 2239 | − fids[i] |= (len << 16); | |
| 2240 | − priv->xmit11.skb = skb; | |
| 2241 | − priv->xmit11.fid = i; | |
| 2242 | − if (down_trylock(&priv->sem) != 0) { | |
| 2243 | − set_bit(FLAG_PENDING_XMIT11, &priv->flags); | |
| 2244 | − netif_stop_queue(dev); | |
| 2245 | − set_bit(JOB_XMIT11, &priv->jobs); | |
| 2246 | − wake_up_interruptible(&priv->thr_wait); | |
| 2247 | − } else | |
| 2248 | − airo_end_xmit11(dev, false); | |
| 2249 | − return NETDEV_TX_OK; | |
| 2250 | −} | |
| 2251 | − | |
| 2252 | −static void airo_read_stats(struct net_device *dev) | |
| 2253 | −{ | |
| 2254 | − struct airo_info *ai = dev->ml_priv; | |
| 2255 | − StatsRid stats_rid; | |
| 2256 | − __le32 *vals = stats_rid.vals; | |
| 2257 | − | |
| 2258 | − clear_bit(JOB_STATS, &ai->jobs); | |
| 2259 | − if (ai->power.event) { | |
| 2260 | − up(&ai->sem); | |
| 2261 | − return; | |
| 2262 | − } | |
| 2263 | − readStatsRid(ai, &stats_rid, RID_STATS, 0); | |
| 2264 | − up(&ai->sem); | |
| 2265 | − | |
| 2266 | − dev->stats.rx_packets = le32_to_cpu(vals[43]) + le32_to_cpu(vals[44]) + | |
| 2267 | − le32_to_cpu(vals[45]); | |
| 2268 | − dev->stats.tx_packets = le32_to_cpu(vals[39]) + le32_to_cpu(vals[40]) + | |
| 2269 | − le32_to_cpu(vals[41]); | |
| 2270 | − dev->stats.rx_bytes = le32_to_cpu(vals[92]); | |
| 2271 | − dev->stats.tx_bytes = le32_to_cpu(vals[91]); | |
| 2272 | − dev->stats.rx_errors = le32_to_cpu(vals[0]) + le32_to_cpu(vals[2]) + | |
| 2273 | − le32_to_cpu(vals[3]) + le32_to_cpu(vals[4]); | |
| 2274 | − dev->stats.tx_errors = le32_to_cpu(vals[42]) + | |
| 2275 | − dev->stats.tx_fifo_errors; | |
| 2276 | − dev->stats.multicast = le32_to_cpu(vals[43]); | |
| 2277 | − dev->stats.collisions = le32_to_cpu(vals[89]); | |
| 2278 | − | |
| 2279 | − /* detailed rx_errors: */ | |
| 2280 | − dev->stats.rx_length_errors = le32_to_cpu(vals[3]); | |
| 2281 | − dev->stats.rx_crc_errors = le32_to_cpu(vals[4]); | |
| 2282 | − dev->stats.rx_frame_errors = le32_to_cpu(vals[2]); | |
| 2283 | − dev->stats.rx_fifo_errors = le32_to_cpu(vals[0]); | |
| 2284 | −} | |
| 2285 | − | |
| 2286 | −static struct net_device_stats *airo_get_stats(struct net_device *dev) | |
| 2287 | −{ | |
| 2288 | − struct airo_info *local = dev->ml_priv; | |
| 2289 | − | |
| 2290 | − if (!test_bit(JOB_STATS, &local->jobs)) { | |
| 2291 | − set_bit(JOB_STATS, &local->jobs); | |
| 2292 | − wake_up_interruptible(&local->thr_wait); | |
| 2293 | − } | |
| 2294 | − | |
| 2295 | − return &dev->stats; | |
| 2296 | −} | |
| 2297 | − | |
| 2298 | −static void airo_set_promisc(struct airo_info *ai, bool may_sleep) | |
| 2299 | −{ | |
| 2300 | − Cmd cmd; | |
| 2301 | − Resp rsp; | |
| 2302 | − | |
| 2303 | − memset(&cmd, 0, sizeof(cmd)); | |
| 2304 | − cmd.cmd = CMD_SETMODE; | |
| 2305 | − clear_bit(JOB_PROMISC, &ai->jobs); | |
| 2306 | − cmd.parm0=(ai->flags&IFF_PROMISC) ? PROMISC : NOPROMISC; | |
| 2307 | − issuecommand(ai, &cmd, &rsp, may_sleep); | |
| 2308 | − up(&ai->sem); | |
| 2309 | −} | |
| 2310 | − | |
| 2311 | −static void airo_set_multicast_list(struct net_device *dev) | |
| 2312 | −{ | |
| 2313 | − struct airo_info *ai = dev->ml_priv; | |
| 2314 | − | |
| 2315 | − if ((dev->flags ^ ai->flags) & IFF_PROMISC) { | |
| 2316 | − change_bit(FLAG_PROMISC, &ai->flags); | |
| 2317 | − if (down_trylock(&ai->sem) != 0) { | |
| 2318 | − set_bit(JOB_PROMISC, &ai->jobs); | |
| 2319 | − wake_up_interruptible(&ai->thr_wait); | |
| 2320 | − } else | |
| 2321 | − airo_set_promisc(ai, false); | |
| 2322 | − } | |
| 2323 | − | |
| 2324 | − if ((dev->flags&IFF_ALLMULTI) || !netdev_mc_empty(dev)) { | |
| 2325 | − /* Turn on multicast. (Should be already setup...) */ | |
| 2326 | − } | |
| 2327 | −} | |
| 2328 | − | |
| 2329 | −static int airo_set_mac_address(struct net_device *dev, void *p) | |
| 2330 | −{ | |
| 2331 | − struct airo_info *ai = dev->ml_priv; | |
| 2332 | − struct sockaddr *addr = p; | |
| 2333 | − | |
| 2334 | − readConfigRid(ai, 1); | |
| 2335 | − memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len); | |
| 2336 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 2337 | − disable_MAC(ai, 1); | |
| 2338 | − writeConfigRid (ai, 1); | |
| 2339 | − enable_MAC(ai, 1); | |
| 2340 | − dev_addr_set(ai->dev, addr->sa_data); | |
| 2341 | − if (ai->wifidev) | |
| 2342 | − dev_addr_set(ai->wifidev, addr->sa_data); | |
| 2343 | − return 0; | |
| 2344 | −} | |
| 2345 | − | |
| 2346 | −static LIST_HEAD(airo_devices); | |
| 2347 | − | |
| 2348 | −static void add_airo_dev(struct airo_info *ai) | |
| 2349 | −{ | |
| 2350 | − /* Upper layers already keep track of PCI devices, | |
| 2351 | − * so we only need to remember our non-PCI cards. */ | |
| 2352 | − if (!ai->pci) | |
| 2353 | − list_add_tail(&ai->dev_list, &airo_devices); | |
| 2354 | −} | |
| 2355 | − | |
| 2356 | −static void del_airo_dev(struct airo_info *ai) | |
| 2357 | −{ | |
| 2358 | − if (!ai->pci) | |
| 2359 | − list_del(&ai->dev_list); | |
| 2360 | −} | |
| 2361 | − | |
| 2362 | −static int airo_close(struct net_device *dev) | |
| 2363 | −{ | |
| 2364 | − struct airo_info *ai = dev->ml_priv; | |
| 2365 | − | |
| 2366 | − netif_stop_queue(dev); | |
| 2367 | − | |
| 2368 | − if (ai->wifidev != dev) { | |
| 2369 | −#ifdef POWER_ON_DOWN | |
| 2370 | − /* Shut power to the card. The idea is that the user can save | |
| 2371 | − * power when he doesn't need the card with "ifconfig down". | |
| 2372 | − * That's the method that is most friendly towards the network | |
| 2373 | − * stack (i.e. the network stack won't try to broadcast | |
| 2374 | − * anything on the interface and routes are gone. Jean II */ | |
| 2375 | − set_bit(FLAG_RADIO_DOWN, &ai->flags); | |
| 2376 | − disable_MAC(ai, 1); | |
| 2377 | −#endif | |
| 2378 | − disable_interrupts(ai); | |
| 2379 | − | |
| 2380 | − free_irq(dev->irq, dev); | |
| 2381 | − | |
| 2382 | − set_bit(JOB_DIE, &ai->jobs); | |
| 2383 | − kthread_stop(ai->airo_thread_task); | |
| 2384 | − } | |
| 2385 | − return 0; | |
| 2386 | −} | |
| 2387 | − | |
| 2388 | −void stop_airo_card(struct net_device *dev, int freeres) | |
| 2389 | −{ | |
| 2390 | − struct airo_info *ai = dev->ml_priv; | |
| 2391 | − | |
| 2392 | − set_bit(FLAG_RADIO_DOWN, &ai->flags); | |
| 2393 | − disable_MAC(ai, 1); | |
| 2394 | − disable_interrupts(ai); | |
| 2395 | − takedown_proc_entry(dev, ai); | |
| 2396 | − if (test_bit(FLAG_REGISTERED, &ai->flags)) { | |
| 2397 | − unregister_netdev(dev); | |
| 2398 | − if (ai->wifidev) { | |
| 2399 | − unregister_netdev(ai->wifidev); | |
| 2400 | − free_netdev(ai->wifidev); | |
| 2401 | − ai->wifidev = NULL; | |
| 2402 | − } | |
| 2403 | − clear_bit(FLAG_REGISTERED, &ai->flags); | |
| 2404 | − } | |
| 2405 | − /* | |
| 2406 | − * Clean out tx queue | |
| 2407 | − */ | |
| 2408 | − if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) { | |
| 2409 | − struct sk_buff *skb = NULL; | |
| 2410 | − for (;(skb = skb_dequeue(&ai->txq));) | |
| 2411 | − dev_kfree_skb(skb); | |
| 2412 | − } | |
| 2413 | − | |
| 2414 | − airo_networks_free (ai); | |
| 2415 | − | |
| 2416 | − kfree(ai->flash); | |
| 2417 | − kfree(ai->rssi); | |
| 2418 | − kfree(ai->SSID); | |
| 2419 | − if (freeres) { | |
| 2420 | − /* PCMCIA frees this stuff, so only for PCI and ISA */ | |
| 2421 | − release_region(dev->base_addr, 64); | |
| 2422 | − if (test_bit(FLAG_MPI, &ai->flags)) { | |
| 2423 | − if (ai->pci) | |
| 2424 | − mpi_unmap_card(ai->pci); | |
| 2425 | − if (ai->pcimem) | |
| 2426 | − iounmap(ai->pcimem); | |
| 2427 | − if (ai->pciaux) | |
| 2428 | − iounmap(ai->pciaux); | |
| 2429 | − dma_free_coherent(&ai->pci->dev, PCI_SHARED_LEN, | |
| 2430 | − ai->shared, ai->shared_dma); | |
| 2431 | − } | |
| 2432 | − } | |
| 2433 | − crypto_free_sync_skcipher(ai->tfm); | |
| 2434 | − del_airo_dev(ai); | |
| 2435 | − free_netdev(dev); | |
| 2436 | −} | |
| 2437 | − | |
| 2438 | −EXPORT_SYMBOL(stop_airo_card); | |
| 2439 | − | |
| 2440 | −static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr) | |
| 2441 | −{ | |
| 2442 | − memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); | |
| 2443 | − return ETH_ALEN; | |
| 2444 | −} | |
| 2445 | − | |
| 2446 | −static void mpi_unmap_card(struct pci_dev *pci) | |
| 2447 | −{ | |
| 2448 | − unsigned long mem_start = pci_resource_start(pci, 1); | |
| 2449 | − unsigned long mem_len = pci_resource_len(pci, 1); | |
| 2450 | − unsigned long aux_start = pci_resource_start(pci, 2); | |
| 2451 | − unsigned long aux_len = AUXMEMSIZE; | |
| 2452 | − | |
| 2453 | − release_mem_region(aux_start, aux_len); | |
| 2454 | − release_mem_region(mem_start, mem_len); | |
| 2455 | −} | |
| 2456 | − | |
| 2457 | −/************************************************************* | |
| 2458 | − * This routine assumes that descriptors have been setup . | |
| 2459 | − * Run at insmod time or after reset when the descriptors | |
| 2460 | − * have been initialized . Returns 0 if all is well nz | |
| 2461 | − * otherwise . Does not allocate memory but sets up card | |
| 2462 | − * using previously allocated descriptors. | |
| 2463 | − */ | |
| 2464 | −static int mpi_init_descriptors (struct airo_info *ai) | |
| 2465 | −{ | |
| 2466 | − Cmd cmd; | |
| 2467 | − Resp rsp; | |
| 2468 | − int i; | |
| 2469 | − int rc = SUCCESS; | |
| 2470 | − | |
| 2471 | − /* Alloc card RX descriptors */ | |
| 2472 | − netif_stop_queue(ai->dev); | |
| 2473 | − | |
| 2474 | − memset(&rsp, 0, sizeof(rsp)); | |
| 2475 | − memset(&cmd, 0, sizeof(cmd)); | |
| 2476 | − | |
| 2477 | − cmd.cmd = CMD_ALLOCATEAUX; | |
| 2478 | − cmd.parm0 = FID_RX; | |
| 2479 | − cmd.parm1 = (ai->rxfids[0].card_ram_off - ai->pciaux); | |
| 2480 | − cmd.parm2 = MPI_MAX_FIDS; | |
| 2481 | − rc = issuecommand(ai, &cmd, &rsp, true); | |
| 2482 | − if (rc != SUCCESS) { | |
| 2483 | − airo_print_err(ai->dev->name, "Couldn't allocate RX FID"); | |
| 2484 | − return rc; | |
| 2485 | − } | |
| 2486 | − | |
| 2487 | − for (i = 0; i<MPI_MAX_FIDS; i++) { | |
| 2488 | − memcpy_toio(ai->rxfids[i].card_ram_off, | |
| 2489 | − &ai->rxfids[i].rx_desc, sizeof(RxFid)); | |
| 2490 | − } | |
| 2491 | − | |
| 2492 | − /* Alloc card TX descriptors */ | |
| 2493 | − | |
| 2494 | − memset(&rsp, 0, sizeof(rsp)); | |
| 2495 | − memset(&cmd, 0, sizeof(cmd)); | |
| 2496 | − | |
| 2497 | − cmd.cmd = CMD_ALLOCATEAUX; | |
| 2498 | − cmd.parm0 = FID_TX; | |
| 2499 | − cmd.parm1 = (ai->txfids[0].card_ram_off - ai->pciaux); | |
| 2500 | − cmd.parm2 = MPI_MAX_FIDS; | |
| 2501 | − | |
| 2502 | − for (i = 0; i<MPI_MAX_FIDS; i++) { | |
| 2503 | − ai->txfids[i].tx_desc.valid = 1; | |
| 2504 | − memcpy_toio(ai->txfids[i].card_ram_off, | |
| 2505 | − &ai->txfids[i].tx_desc, sizeof(TxFid)); | |
| 2506 | − } | |
| 2507 | − ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ | |
| 2508 | − | |
| 2509 | − rc = issuecommand(ai, &cmd, &rsp, true); | |
| 2510 | − if (rc != SUCCESS) { | |
| 2511 | − airo_print_err(ai->dev->name, "Couldn't allocate TX FID"); | |
| 2512 | − return rc; | |
| 2513 | − } | |
| 2514 | − | |
| 2515 | − /* Alloc card Rid descriptor */ | |
| 2516 | − memset(&rsp, 0, sizeof(rsp)); | |
| 2517 | − memset(&cmd, 0, sizeof(cmd)); | |
| 2518 | − | |
| 2519 | − cmd.cmd = CMD_ALLOCATEAUX; | |
| 2520 | − cmd.parm0 = RID_RW; | |
| 2521 | − cmd.parm1 = (ai->config_desc.card_ram_off - ai->pciaux); | |
| 2522 | − cmd.parm2 = 1; /* Magic number... */ | |
| 2523 | − rc = issuecommand(ai, &cmd, &rsp, true); | |
| 2524 | − if (rc != SUCCESS) { | |
| 2525 | − airo_print_err(ai->dev->name, "Couldn't allocate RID"); | |
| 2526 | − return rc; | |
| 2527 | − } | |
| 2528 | − | |
| 2529 | − memcpy_toio(ai->config_desc.card_ram_off, | |
| 2530 | − &ai->config_desc.rid_desc, sizeof(Rid)); | |
| 2531 | − | |
| 2532 | − return rc; | |
| 2533 | −} | |
| 2534 | − | |
| 2535 | −/* | |
| 2536 | − * We are setting up three things here: | |
| 2537 | − * 1) Map AUX memory for descriptors: Rid, TxFid, or RxFid. | |
| 2538 | − * 2) Map PCI memory for issuing commands. | |
| 2539 | − * 3) Allocate memory (shared) to send and receive ethernet frames. | |
| 2540 | − */ | |
| 2541 | −static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci) | |
| 2542 | −{ | |
| 2543 | − unsigned long mem_start, mem_len, aux_start, aux_len; | |
| 2544 | − int rc = -1; | |
| 2545 | − int i; | |
| 2546 | − dma_addr_t busaddroff; | |
| 2547 | − unsigned char *vpackoff; | |
| 2548 | − unsigned char __iomem *pciaddroff; | |
| 2549 | − | |
| 2550 | − mem_start = pci_resource_start(pci, 1); | |
| 2551 | − mem_len = pci_resource_len(pci, 1); | |
| 2552 | − aux_start = pci_resource_start(pci, 2); | |
| 2553 | − aux_len = AUXMEMSIZE; | |
| 2554 | − | |
| 2555 | − if (!request_mem_region(mem_start, mem_len, DRV_NAME)) { | |
| 2556 | − airo_print_err("", "Couldn't get region %x[%x]", | |
| 2557 | − (int)mem_start, (int)mem_len); | |
| 2558 | − goto out; | |
| 2559 | − } | |
| 2560 | − if (!request_mem_region(aux_start, aux_len, DRV_NAME)) { | |
| 2561 | − airo_print_err("", "Couldn't get region %x[%x]", | |
| 2562 | − (int)aux_start, (int)aux_len); | |
| 2563 | − goto free_region1; | |
| 2564 | − } | |
| 2565 | − | |
| 2566 | − ai->pcimem = ioremap(mem_start, mem_len); | |
| 2567 | − if (!ai->pcimem) { | |
| 2568 | − airo_print_err("", "Couldn't map region %x[%x]", | |
| 2569 | − (int)mem_start, (int)mem_len); | |
| 2570 | − goto free_region2; | |
| 2571 | − } | |
| 2572 | − ai->pciaux = ioremap(aux_start, aux_len); | |
| 2573 | − if (!ai->pciaux) { | |
| 2574 | − airo_print_err("", "Couldn't map region %x[%x]", | |
| 2575 | − (int)aux_start, (int)aux_len); | |
| 2576 | − goto free_memmap; | |
| 2577 | − } | |
| 2578 | − | |
| 2579 | − /* Reserve PKTSIZE for each fid and 2K for the Rids */ | |
| 2580 | − ai->shared = dma_alloc_coherent(&pci->dev, PCI_SHARED_LEN, | |
| 2581 | − &ai->shared_dma, GFP_KERNEL); | |
| 2582 | − if (!ai->shared) { | |
| 2583 | − airo_print_err("", "Couldn't alloc_coherent %d", | |
| 2584 | − PCI_SHARED_LEN); | |
| 2585 | − goto free_auxmap; | |
| 2586 | − } | |
| 2587 | − | |
| 2588 | − /* | |
| 2589 | − * Setup descriptor RX, TX, CONFIG | |
| 2590 | − */ | |
| 2591 | − busaddroff = ai->shared_dma; | |
| 2592 | − pciaddroff = ai->pciaux + AUX_OFFSET; | |
| 2593 | − vpackoff = ai->shared; | |
| 2594 | − | |
| 2595 | − /* RX descriptor setup */ | |
| 2596 | − for (i = 0; i < MPI_MAX_FIDS; i++) { | |
| 2597 | − ai->rxfids[i].pending = 0; | |
| 2598 | − ai->rxfids[i].card_ram_off = pciaddroff; | |
| 2599 | − ai->rxfids[i].virtual_host_addr = vpackoff; | |
| 2600 | − ai->rxfids[i].rx_desc.host_addr = busaddroff; | |
| 2601 | − ai->rxfids[i].rx_desc.valid = 1; | |
| 2602 | − ai->rxfids[i].rx_desc.len = PKTSIZE; | |
| 2603 | − ai->rxfids[i].rx_desc.rdy = 0; | |
| 2604 | − | |
| 2605 | − pciaddroff += sizeof(RxFid); | |
| 2606 | − busaddroff += PKTSIZE; | |
| 2607 | − vpackoff += PKTSIZE; | |
| 2608 | − } | |
| 2609 | − | |
| 2610 | − /* TX descriptor setup */ | |
| 2611 | − for (i = 0; i < MPI_MAX_FIDS; i++) { | |
| 2612 | − ai->txfids[i].card_ram_off = pciaddroff; | |
| 2613 | − ai->txfids[i].virtual_host_addr = vpackoff; | |
| 2614 | − ai->txfids[i].tx_desc.valid = 1; | |
| 2615 | − ai->txfids[i].tx_desc.host_addr = busaddroff; | |
| 2616 | − memcpy(ai->txfids[i].virtual_host_addr, | |
| 2617 | − &wifictlhdr8023, sizeof(wifictlhdr8023)); | |
| 2618 | − | |
| 2619 | − pciaddroff += sizeof(TxFid); | |
| 2620 | − busaddroff += PKTSIZE; | |
| 2621 | − vpackoff += PKTSIZE; | |
| 2622 | − } | |
| 2623 | − ai->txfids[i-1].tx_desc.eoc = 1; /* Last descriptor has EOC set */ | |
| 2624 | − | |
| 2625 | − /* Rid descriptor setup */ | |
| 2626 | − ai->config_desc.card_ram_off = pciaddroff; | |
| 2627 | − ai->config_desc.virtual_host_addr = vpackoff; | |
| 2628 | − ai->config_desc.rid_desc.host_addr = busaddroff; | |
| 2629 | − ai->ridbus = busaddroff; | |
| 2630 | − ai->config_desc.rid_desc.rid = 0; | |
| 2631 | − ai->config_desc.rid_desc.len = RIDSIZE; | |
| 2632 | − ai->config_desc.rid_desc.valid = 1; | |
| 2633 | − pciaddroff += sizeof(Rid); | |
| 2634 | − busaddroff += RIDSIZE; | |
| 2635 | − vpackoff += RIDSIZE; | |
| 2636 | − | |
| 2637 | − /* Tell card about descriptors */ | |
| 2638 | − if (mpi_init_descriptors (ai) != SUCCESS) | |
| 2639 | − goto free_shared; | |
| 2640 | − | |
| 2641 | − return 0; | |
| 2642 | − free_shared: | |
| 2643 | − dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, | |
| 2644 | − ai->shared_dma); | |
| 2645 | − free_auxmap: | |
| 2646 | − iounmap(ai->pciaux); | |
| 2647 | − free_memmap: | |
| 2648 | − iounmap(ai->pcimem); | |
| 2649 | − free_region2: | |
| 2650 | − release_mem_region(aux_start, aux_len); | |
| 2651 | − free_region1: | |
| 2652 | − release_mem_region(mem_start, mem_len); | |
| 2653 | − out: | |
| 2654 | − return rc; | |
| 2655 | −} | |
| 2656 | − | |
| 2657 | −static const struct header_ops airo_header_ops = { | |
| 2658 | − .parse = wll_header_parse, | |
| 2659 | −}; | |
| 2660 | − | |
| 2661 | −static const struct net_device_ops airo11_netdev_ops = { | |
| 2662 | − .ndo_open = airo_open, | |
| 2663 | − .ndo_stop = airo_close, | |
| 2664 | − .ndo_start_xmit = airo_start_xmit11, | |
| 2665 | − .ndo_get_stats = airo_get_stats, | |
| 2666 | − .ndo_set_mac_address = airo_set_mac_address, | |
| 2667 | − .ndo_siocdevprivate = airo_siocdevprivate, | |
| 2668 | −}; | |
| 2669 | − | |
| 2670 | −static void wifi_setup(struct net_device *dev) | |
| 2671 | −{ | |
| 2672 | − dev->netdev_ops = &airo11_netdev_ops; | |
| 2673 | − dev->header_ops = &airo_header_ops; | |
| 2674 | − dev->wireless_handlers = &airo_handler_def; | |
| 2675 | − | |
| 2676 | − dev->type = ARPHRD_IEEE80211; | |
| 2677 | − dev->hard_header_len = ETH_HLEN; | |
| 2678 | − dev->mtu = AIRO_DEF_MTU; | |
| 2679 | − dev->min_mtu = 68; | |
| 2680 | − dev->max_mtu = MIC_MSGLEN_MAX; | |
| 2681 | − dev->addr_len = ETH_ALEN; | |
| 2682 | − dev->tx_queue_len = 100; | |
| 2683 | − | |
| 2684 | − eth_broadcast_addr(dev->broadcast); | |
| 2685 | − | |
| 2686 | − dev->flags = IFF_BROADCAST|IFF_MULTICAST; | |
| 2687 | −} | |
| 2688 | − | |
| 2689 | −static struct net_device *init_wifidev(struct airo_info *ai, | |
| 2690 | − struct net_device *ethdev) | |
| 2691 | −{ | |
| 2692 | − int err; | |
| 2693 | − struct net_device *dev = alloc_netdev(0, "wifi%d", NET_NAME_UNKNOWN, | |
| 2694 | − wifi_setup); | |
| 2695 | − if (!dev) | |
| 2696 | − return NULL; | |
| 2697 | − dev->ml_priv = ethdev->ml_priv; | |
| 2698 | − dev->irq = ethdev->irq; | |
| 2699 | − dev->base_addr = ethdev->base_addr; | |
| 2700 | − dev->wireless_data = ethdev->wireless_data; | |
| 2701 | − SET_NETDEV_DEV(dev, ethdev->dev.parent); | |
| 2702 | − eth_hw_addr_inherit(dev, ethdev); | |
| 2703 | − err = register_netdev(dev); | |
| 2704 | − if (err<0) { | |
| 2705 | − free_netdev(dev); | |
| 2706 | − return NULL; | |
| 2707 | − } | |
| 2708 | − return dev; | |
| 2709 | −} | |
| 2710 | − | |
| 2711 | −static int reset_card(struct net_device *dev, int lock) | |
| 2712 | −{ | |
| 2713 | − struct airo_info *ai = dev->ml_priv; | |
| 2714 | − | |
| 2715 | − if (lock && down_interruptible(&ai->sem)) | |
| 2716 | − return -1; | |
| 2717 | − waitbusy (ai); | |
| 2718 | − OUT4500(ai, COMMAND, CMD_SOFTRESET); | |
| 2719 | − msleep(200); | |
| 2720 | − waitbusy (ai); | |
| 2721 | − msleep(200); | |
| 2722 | − if (lock) | |
| 2723 | − up(&ai->sem); | |
| 2724 | − return 0; | |
| 2725 | −} | |
| 2726 | − | |
| 2727 | −#define AIRO_MAX_NETWORK_COUNT 64 | |
| 2728 | −static int airo_networks_allocate(struct airo_info *ai) | |
| 2729 | −{ | |
| 2730 | − if (ai->networks) | |
| 2731 | − return 0; | |
| 2732 | − | |
| 2733 | − ai->networks = kcalloc(AIRO_MAX_NETWORK_COUNT, sizeof(BSSListElement), | |
| 2734 | − GFP_KERNEL); | |
| 2735 | − if (!ai->networks) { | |
| 2736 | − airo_print_warn("", "Out of memory allocating beacons"); | |
| 2737 | − return -ENOMEM; | |
| 2738 | − } | |
| 2739 | − | |
| 2740 | − return 0; | |
| 2741 | −} | |
| 2742 | − | |
| 2743 | −static void airo_networks_free(struct airo_info *ai) | |
| 2744 | −{ | |
| 2745 | − kfree(ai->networks); | |
| 2746 | − ai->networks = NULL; | |
| 2747 | −} | |
| 2748 | − | |
| 2749 | −static void airo_networks_initialize(struct airo_info *ai) | |
| 2750 | −{ | |
| 2751 | − int i; | |
| 2752 | − | |
| 2753 | − INIT_LIST_HEAD(&ai->network_free_list); | |
| 2754 | − INIT_LIST_HEAD(&ai->network_list); | |
| 2755 | − for (i = 0; i < AIRO_MAX_NETWORK_COUNT; i++) | |
| 2756 | − list_add_tail(&ai->networks[i].list, | |
| 2757 | − &ai->network_free_list); | |
| 2758 | −} | |
| 2759 | − | |
| 2760 | −static const struct net_device_ops airo_netdev_ops = { | |
| 2761 | − .ndo_open = airo_open, | |
| 2762 | − .ndo_stop = airo_close, | |
| 2763 | − .ndo_start_xmit = airo_start_xmit, | |
| 2764 | − .ndo_get_stats = airo_get_stats, | |
| 2765 | − .ndo_set_rx_mode = airo_set_multicast_list, | |
| 2766 | − .ndo_set_mac_address = airo_set_mac_address, | |
| 2767 | − .ndo_siocdevprivate = airo_siocdevprivate, | |
| 2768 | − .ndo_validate_addr = eth_validate_addr, | |
| 2769 | −}; | |
| 2770 | − | |
| 2771 | −static const struct net_device_ops mpi_netdev_ops = { | |
| 2772 | − .ndo_open = airo_open, | |
| 2773 | − .ndo_stop = airo_close, | |
| 2774 | − .ndo_start_xmit = mpi_start_xmit, | |
| 2775 | − .ndo_get_stats = airo_get_stats, | |
| 2776 | − .ndo_set_rx_mode = airo_set_multicast_list, | |
| 2777 | − .ndo_set_mac_address = airo_set_mac_address, | |
| 2778 | − .ndo_siocdevprivate = airo_siocdevprivate, | |
| 2779 | − .ndo_validate_addr = eth_validate_addr, | |
| 2780 | −}; | |
| 2781 | − | |
| 2782 | − | |
| 2783 | −static struct net_device *_init_airo_card(unsigned short irq, int port, | |
| 2784 | − int is_pcmcia, struct pci_dev *pci, | |
| 2785 | − struct device *dmdev) | |
| 2786 | −{ | |
| 2787 | − struct net_device *dev; | |
| 2788 | − struct airo_info *ai; | |
| 2789 | − int i, rc; | |
| 2790 | − CapabilityRid cap_rid; | |
| 2791 | − | |
| 2792 | − /* Create the network device object. */ | |
| 2793 | − dev = alloc_netdev(sizeof(*ai), "", NET_NAME_UNKNOWN, ether_setup); | |
| 2794 | − if (!dev) { | |
| 2795 | − airo_print_err("", "Couldn't alloc_etherdev"); | |
| 2796 | − return NULL; | |
| 2797 | − } | |
| 2798 | − | |
| 2799 | − ai = dev->ml_priv = netdev_priv(dev); | |
| 2800 | − ai->wifidev = NULL; | |
| 2801 | − ai->flags = 1 << FLAG_RADIO_DOWN; | |
| 2802 | − ai->jobs = 0; | |
| 2803 | − ai->dev = dev; | |
| 2804 | − if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { | |
| 2805 | − airo_print_dbg("", "Found an MPI350 card"); | |
| 2806 | − set_bit(FLAG_MPI, &ai->flags); | |
| 2807 | − } | |
| 2808 | − spin_lock_init(&ai->aux_lock); | |
| 2809 | − sema_init(&ai->sem, 1); | |
| 2810 | − ai->config.len = 0; | |
| 2811 | − ai->pci = pci; | |
| 2812 | − init_waitqueue_head (&ai->thr_wait); | |
| 2813 | − ai->tfm = NULL; | |
| 2814 | − add_airo_dev(ai); | |
| 2815 | − ai->APList.len = cpu_to_le16(sizeof(struct APListRid)); | |
| 2816 | − | |
| 2817 | − if (airo_networks_allocate (ai)) | |
| 2818 | − goto err_out_free; | |
| 2819 | − airo_networks_initialize (ai); | |
| 2820 | − | |
| 2821 | − skb_queue_head_init (&ai->txq); | |
| 2822 | − | |
| 2823 | − /* The Airo-specific entries in the device structure. */ | |
| 2824 | − if (test_bit(FLAG_MPI,&ai->flags)) | |
| 2825 | − dev->netdev_ops = &mpi_netdev_ops; | |
| 2826 | − else | |
| 2827 | − dev->netdev_ops = &airo_netdev_ops; | |
| 2828 | − dev->wireless_handlers = &airo_handler_def; | |
| 2829 | − ai->wireless_data.spy_data = &ai->spy_data; | |
| 2830 | − dev->wireless_data = &ai->wireless_data; | |
| 2831 | − dev->irq = irq; | |
| 2832 | − dev->base_addr = port; | |
| 2833 | − dev->priv_flags &= ~IFF_TX_SKB_SHARING; | |
| 2834 | − dev->max_mtu = MIC_MSGLEN_MAX; | |
| 2835 | − | |
| 2836 | − SET_NETDEV_DEV(dev, dmdev); | |
| 2837 | − | |
| 2838 | − reset_card (dev, 1); | |
| 2839 | − msleep(400); | |
| 2840 | − | |
| 2841 | − if (!is_pcmcia) { | |
| 2842 | − if (!request_region(dev->base_addr, 64, DRV_NAME)) { | |
| 2843 | − rc = -EBUSY; | |
| 2844 | − airo_print_err(dev->name, "Couldn't request region"); | |
| 2845 | − goto err_out_nets; | |
| 2846 | − } | |
| 2847 | − } | |
| 2848 | − | |
| 2849 | − if (test_bit(FLAG_MPI,&ai->flags)) { | |
| 2850 | − if (mpi_map_card(ai, pci)) { | |
| 2851 | − airo_print_err("", "Could not map memory"); | |
| 2852 | − goto err_out_res; | |
| 2853 | − } | |
| 2854 | − } | |
| 2855 | − | |
| 2856 | − if (probe) { | |
| 2857 | − if (setup_card(ai, dev, 1) != SUCCESS) { | |
| 2858 | − airo_print_err(dev->name, "MAC could not be enabled"); | |
| 2859 | − rc = -EIO; | |
| 2860 | − goto err_out_map; | |
| 2861 | − } | |
| 2862 | − } else if (!test_bit(FLAG_MPI,&ai->flags)) { | |
| 2863 | − ai->bap_read = fast_bap_read; | |
| 2864 | − set_bit(FLAG_FLASHING, &ai->flags); | |
| 2865 | − } | |
| 2866 | − | |
| 2867 | − strcpy(dev->name, "eth%d"); | |
| 2868 | − rc = register_netdev(dev); | |
| 2869 | − if (rc) { | |
| 2870 | − airo_print_err(dev->name, "Couldn't register_netdev"); | |
| 2871 | − goto err_out_map; | |
| 2872 | − } | |
| 2873 | − ai->wifidev = init_wifidev(ai, dev); | |
| 2874 | − if (!ai->wifidev) | |
| 2875 | − goto err_out_reg; | |
| 2876 | − | |
| 2877 | − rc = readCapabilityRid(ai, &cap_rid, 1); | |
| 2878 | − if (rc != SUCCESS) { | |
| 2879 | − rc = -EIO; | |
| 2880 | − goto err_out_wifi; | |
| 2881 | − } | |
| 2882 | − /* WEP capability discovery */ | |
| 2883 | − ai->wep_capable = (cap_rid.softCap & cpu_to_le16(0x02)) ? 1 : 0; | |
| 2884 | − ai->max_wep_idx = (cap_rid.softCap & cpu_to_le16(0x80)) ? 3 : 0; | |
| 2885 | − | |
| 2886 | − airo_print_info(dev->name, "Firmware version %x.%x.%02d", | |
| 2887 | − ((le16_to_cpu(cap_rid.softVer) >> 8) & 0xF), | |
| 2888 | − (le16_to_cpu(cap_rid.softVer) & 0xFF), | |
| 2889 | − le16_to_cpu(cap_rid.softSubVer)); | |
| 2890 | − | |
| 2891 | − /* Test for WPA support */ | |
| 2892 | − /* Only firmware versions 5.30.17 or better can do WPA */ | |
| 2893 | − if (le16_to_cpu(cap_rid.softVer) > 0x530 | |
| 2894 | − || (le16_to_cpu(cap_rid.softVer) == 0x530 | |
| 2895 | − && le16_to_cpu(cap_rid.softSubVer) >= 17)) { | |
| 2896 | − airo_print_info(ai->dev->name, "WPA supported."); | |
| 2897 | − | |
| 2898 | − set_bit(FLAG_WPA_CAPABLE, &ai->flags); | |
| 2899 | − ai->bssListFirst = RID_WPA_BSSLISTFIRST; | |
| 2900 | − ai->bssListNext = RID_WPA_BSSLISTNEXT; | |
| 2901 | − ai->bssListRidLen = sizeof(BSSListRid); | |
| 2902 | − } else { | |
| 2903 | − airo_print_info(ai->dev->name, "WPA unsupported with firmware " | |
| 2904 | − "versions older than 5.30.17."); | |
| 2905 | − | |
| 2906 | − ai->bssListFirst = RID_BSSLISTFIRST; | |
| 2907 | − ai->bssListNext = RID_BSSLISTNEXT; | |
| 2908 | − ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra); | |
| 2909 | − } | |
| 2910 | − | |
| 2911 | − set_bit(FLAG_REGISTERED,&ai->flags); | |
| 2912 | − airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); | |
| 2913 | − | |
| 2914 | − /* Allocate the transmit buffers */ | |
| 2915 | − if (probe && !test_bit(FLAG_MPI,&ai->flags)) | |
| 2916 | − for (i = 0; i < MAX_FIDS; i++) | |
| 2917 | − ai->fids[i] = transmit_allocate(ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); | |
| 2918 | − | |
| 2919 | − if (setup_proc_entry(dev, dev->ml_priv) < 0) | |
| 2920 | − goto err_out_wifi; | |
| 2921 | − | |
| 2922 | − return dev; | |
| 2923 | − | |
| 2924 | −err_out_wifi: | |
| 2925 | − unregister_netdev(ai->wifidev); | |
| 2926 | − free_netdev(ai->wifidev); | |
| 2927 | −err_out_reg: | |
| 2928 | − unregister_netdev(dev); | |
| 2929 | −err_out_map: | |
| 2930 | − if (test_bit(FLAG_MPI,&ai->flags) && pci) { | |
| 2931 | − dma_free_coherent(&pci->dev, PCI_SHARED_LEN, ai->shared, | |
| 2932 | − ai->shared_dma); | |
| 2933 | − iounmap(ai->pciaux); | |
| 2934 | − iounmap(ai->pcimem); | |
| 2935 | − mpi_unmap_card(ai->pci); | |
| 2936 | − } | |
| 2937 | −err_out_res: | |
| 2938 | − if (!is_pcmcia) | |
| 2939 | − release_region(dev->base_addr, 64); | |
| 2940 | −err_out_nets: | |
| 2941 | − airo_networks_free(ai); | |
| 2942 | −err_out_free: | |
| 2943 | − del_airo_dev(ai); | |
| 2944 | − free_netdev(dev); | |
| 2945 | − return NULL; | |
| 2946 | −} | |
| 2947 | − | |
| 2948 | −struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, | |
| 2949 | − struct device *dmdev) | |
| 2950 | −{ | |
| 2951 | − return _init_airo_card (irq, port, is_pcmcia, NULL, dmdev); | |
| 2952 | −} | |
| 2953 | − | |
| 2954 | −EXPORT_SYMBOL(init_airo_card); | |
| 2955 | − | |
| 2956 | −static int waitbusy (struct airo_info *ai) | |
| 2957 | −{ | |
| 2958 | − int delay = 0; | |
| 2959 | − while ((IN4500(ai, COMMAND) & COMMAND_BUSY) && (delay < 10000)) { | |
| 2960 | − udelay (10); | |
| 2961 | − if ((++delay % 20) == 0) | |
| 2962 | − OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); | |
| 2963 | − } | |
| 2964 | − return delay < 10000; | |
| 2965 | −} | |
| 2966 | − | |
| 2967 | −int reset_airo_card(struct net_device *dev) | |
| 2968 | −{ | |
| 2969 | − int i; | |
| 2970 | − struct airo_info *ai = dev->ml_priv; | |
| 2971 | − | |
| 2972 | − if (reset_card (dev, 1)) | |
| 2973 | − return -1; | |
| 2974 | − | |
| 2975 | − if (setup_card(ai, dev, 1) != SUCCESS) { | |
| 2976 | − airo_print_err(dev->name, "MAC could not be enabled"); | |
| 2977 | − return -1; | |
| 2978 | − } | |
| 2979 | − airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); | |
| 2980 | − /* Allocate the transmit buffers if needed */ | |
| 2981 | − if (!test_bit(FLAG_MPI,&ai->flags)) | |
| 2982 | − for (i = 0; i < MAX_FIDS; i++) | |
| 2983 | − ai->fids[i] = transmit_allocate (ai, AIRO_DEF_MTU, i>=MAX_FIDS/2); | |
| 2984 | − | |
| 2985 | − enable_interrupts(ai); | |
| 2986 | − netif_wake_queue(dev); | |
| 2987 | − return 0; | |
| 2988 | −} | |
| 2989 | − | |
| 2990 | −EXPORT_SYMBOL(reset_airo_card); | |
| 2991 | − | |
| 2992 | −static void airo_send_event(struct net_device *dev) | |
| 2993 | −{ | |
| 2994 | − struct airo_info *ai = dev->ml_priv; | |
| 2995 | − union iwreq_data wrqu; | |
| 2996 | − StatusRid status_rid; | |
| 2997 | − | |
| 2998 | − clear_bit(JOB_EVENT, &ai->jobs); | |
| 2999 | − PC4500_readrid(ai, RID_STATUS, &status_rid, sizeof(status_rid), 0); | |
| 3000 | − up(&ai->sem); | |
| 3001 | − wrqu.data.length = 0; | |
| 3002 | − wrqu.data.flags = 0; | |
| 3003 | − memcpy(wrqu.ap_addr.sa_data, status_rid.bssid[0], ETH_ALEN); | |
| 3004 | − wrqu.ap_addr.sa_family = ARPHRD_ETHER; | |
| 3005 | − | |
| 3006 | − /* Send event to user space */ | |
| 3007 | − wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | |
| 3008 | −} | |
| 3009 | − | |
| 3010 | −static void airo_process_scan_results (struct airo_info *ai) | |
| 3011 | −{ | |
| 3012 | − union iwreq_data wrqu; | |
| 3013 | − BSSListRid bss; | |
| 3014 | − int rc; | |
| 3015 | − BSSListElement * loop_net; | |
| 3016 | − BSSListElement * tmp_net; | |
| 3017 | − | |
| 3018 | − /* Blow away current list of scan results */ | |
| 3019 | − list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) { | |
| 3020 | − list_move_tail (&loop_net->list, &ai->network_free_list); | |
| 3021 | − /* Don't blow away ->list, just BSS data */ | |
| 3022 | − memset (loop_net, 0, sizeof (loop_net->bss)); | |
| 3023 | − } | |
| 3024 | − | |
| 3025 | − /* Try to read the first entry of the scan result */ | |
| 3026 | − rc = PC4500_readrid(ai, ai->bssListFirst, &bss, ai->bssListRidLen, 0); | |
| 3027 | − if ((rc) || (bss.index == cpu_to_le16(0xffff))) { | |
| 3028 | − /* No scan results */ | |
| 3029 | − goto out; | |
| 3030 | − } | |
| 3031 | − | |
| 3032 | − /* Read and parse all entries */ | |
| 3033 | − tmp_net = NULL; | |
| 3034 | − while ((!rc) && (bss.index != cpu_to_le16(0xffff))) { | |
| 3035 | − /* Grab a network off the free list */ | |
| 3036 | − if (!list_empty(&ai->network_free_list)) { | |
| 3037 | − tmp_net = list_entry(ai->network_free_list.next, | |
| 3038 | − BSSListElement, list); | |
| 3039 | − list_del(ai->network_free_list.next); | |
| 3040 | − } | |
| 3041 | − | |
| 3042 | − if (tmp_net != NULL) { | |
| 3043 | − memcpy(tmp_net, &bss, sizeof(tmp_net->bss)); | |
| 3044 | − list_add_tail(&tmp_net->list, &ai->network_list); | |
| 3045 | − tmp_net = NULL; | |
| 3046 | − } | |
| 3047 | − | |
| 3048 | − /* Read next entry */ | |
| 3049 | − rc = PC4500_readrid(ai, ai->bssListNext, | |
| 3050 | − &bss, ai->bssListRidLen, 0); | |
| 3051 | − } | |
| 3052 | − | |
| 3053 | −out: | |
| 3054 | − /* write APList back (we cleared it in airo_set_scan) */ | |
| 3055 | − disable_MAC(ai, 2); | |
| 3056 | − writeAPListRid(ai, &ai->APList, 0); | |
| 3057 | − enable_MAC(ai, 0); | |
| 3058 | − | |
| 3059 | − ai->scan_timeout = 0; | |
| 3060 | − clear_bit(JOB_SCAN_RESULTS, &ai->jobs); | |
| 3061 | − up(&ai->sem); | |
| 3062 | − | |
| 3063 | − /* Send an empty event to user space. | |
| 3064 | − * We don't send the received data on | |
| 3065 | − * the event because it would require | |
| 3066 | − * us to do complex transcoding, and | |
| 3067 | − * we want to minimise the work done in | |
| 3068 | − * the irq handler. Use a request to | |
| 3069 | − * extract the data - Jean II */ | |
| 3070 | − wrqu.data.length = 0; | |
| 3071 | − wrqu.data.flags = 0; | |
| 3072 | − wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL); | |
| 3073 | −} | |
| 3074 | − | |
| 3075 | −static int airo_thread(void *data) | |
| 3076 | −{ | |
| 3077 | − struct net_device *dev = data; | |
| 3078 | − struct airo_info *ai = dev->ml_priv; | |
| 3079 | − int locked; | |
| 3080 | − | |
| 3081 | − set_freezable(); | |
| 3082 | − while (1) { | |
| 3083 | − /* make swsusp happy with our thread */ | |
| 3084 | − try_to_freeze(); | |
| 3085 | − | |
| 3086 | − if (test_bit(JOB_DIE, &ai->jobs)) | |
| 3087 | − break; | |
| 3088 | − | |
| 3089 | − if (ai->jobs) { | |
| 3090 | − locked = down_interruptible(&ai->sem); | |
| 3091 | − } else { | |
| 3092 | − wait_queue_entry_t wait; | |
| 3093 | − | |
| 3094 | − init_waitqueue_entry(&wait, current); | |
| 3095 | − add_wait_queue(&ai->thr_wait, &wait); | |
| 3096 | − for (;;) { | |
| 3097 | − set_current_state(TASK_INTERRUPTIBLE); | |
| 3098 | − if (ai->jobs) | |
| 3099 | − break; | |
| 3100 | − if (ai->expires || ai->scan_timeout) { | |
| 3101 | − if (ai->scan_timeout && | |
| 3102 | − time_after_eq(jiffies, ai->scan_timeout)) { | |
| 3103 | − set_bit(JOB_SCAN_RESULTS, &ai->jobs); | |
| 3104 | − break; | |
| 3105 | − } else if (ai->expires && | |
| 3106 | − time_after_eq(jiffies, ai->expires)) { | |
| 3107 | − set_bit(JOB_AUTOWEP, &ai->jobs); | |
| 3108 | − break; | |
| 3109 | − } | |
| 3110 | − if (!kthread_should_stop() && | |
| 3111 | − !freezing(current)) { | |
| 3112 | − unsigned long wake_at; | |
| 3113 | − if (!ai->expires || !ai->scan_timeout) { | |
| 3114 | − wake_at = max(ai->expires, | |
| 3115 | − ai->scan_timeout); | |
| 3116 | − } else { | |
| 3117 | − wake_at = min(ai->expires, | |
| 3118 | − ai->scan_timeout); | |
| 3119 | − } | |
| 3120 | − schedule_timeout(wake_at - jiffies); | |
| 3121 | − continue; | |
| 3122 | − } | |
| 3123 | − } else if (!kthread_should_stop() && | |
| 3124 | − !freezing(current)) { | |
| 3125 | − schedule(); | |
| 3126 | − continue; | |
| 3127 | − } | |
| 3128 | − break; | |
| 3129 | − } | |
| 3130 | − __set_current_state(TASK_RUNNING); | |
| 3131 | − remove_wait_queue(&ai->thr_wait, &wait); | |
| 3132 | − locked = 1; | |
| 3133 | − } | |
| 3134 | − | |
| 3135 | − if (locked) | |
| 3136 | − continue; | |
| 3137 | − | |
| 3138 | − if (test_bit(JOB_DIE, &ai->jobs)) { | |
| 3139 | − up(&ai->sem); | |
| 3140 | − break; | |
| 3141 | − } | |
| 3142 | − | |
| 3143 | − if (ai->power.event || test_bit(FLAG_FLASHING, &ai->flags)) { | |
| 3144 | − up(&ai->sem); | |
| 3145 | − continue; | |
| 3146 | − } | |
| 3147 | − | |
| 3148 | − if (test_bit(JOB_XMIT, &ai->jobs)) | |
| 3149 | − airo_end_xmit(dev, true); | |
| 3150 | − else if (test_bit(JOB_XMIT11, &ai->jobs)) | |
| 3151 | − airo_end_xmit11(dev, true); | |
| 3152 | − else if (test_bit(JOB_STATS, &ai->jobs)) | |
| 3153 | − airo_read_stats(dev); | |
| 3154 | − else if (test_bit(JOB_PROMISC, &ai->jobs)) | |
| 3155 | − airo_set_promisc(ai, true); | |
| 3156 | − else if (test_bit(JOB_MIC, &ai->jobs)) | |
| 3157 | − micinit(ai); | |
| 3158 | − else if (test_bit(JOB_EVENT, &ai->jobs)) | |
| 3159 | − airo_send_event(dev); | |
| 3160 | − else if (test_bit(JOB_AUTOWEP, &ai->jobs)) | |
| 3161 | − timer_func(dev); | |
| 3162 | − else if (test_bit(JOB_SCAN_RESULTS, &ai->jobs)) | |
| 3163 | − airo_process_scan_results(ai); | |
| 3164 | − else /* Shouldn't get here, but we make sure to unlock */ | |
| 3165 | − up(&ai->sem); | |
| 3166 | − } | |
| 3167 | − | |
| 3168 | − return 0; | |
| 3169 | −} | |
| 3170 | − | |
| 3171 | −static int header_len(__le16 ctl) | |
| 3172 | −{ | |
| 3173 | − u16 fc = le16_to_cpu(ctl); | |
| 3174 | − switch (fc & 0xc) { | |
| 3175 | − case 4: | |
| 3176 | − if ((fc & 0xe0) == 0xc0) | |
| 3177 | − return 10; /* one-address control packet */ | |
| 3178 | − return 16; /* two-address control packet */ | |
| 3179 | − case 8: | |
| 3180 | − if ((fc & 0x300) == 0x300) | |
| 3181 | − return 30; /* WDS packet */ | |
| 3182 | − } | |
| 3183 | − return 24; | |
| 3184 | −} | |
| 3185 | − | |
| 3186 | −static void airo_handle_cisco_mic(struct airo_info *ai) | |
| 3187 | −{ | |
| 3188 | − if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) { | |
| 3189 | − set_bit(JOB_MIC, &ai->jobs); | |
| 3190 | − wake_up_interruptible(&ai->thr_wait); | |
| 3191 | − } | |
| 3192 | −} | |
| 3193 | − | |
| 3194 | −/* Airo Status codes */ | |
| 3195 | −#define STAT_NOBEACON 0x8000 /* Loss of sync - missed beacons */ | |
| 3196 | −#define STAT_MAXRETRIES 0x8001 /* Loss of sync - max retries */ | |
| 3197 | −#define STAT_MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/ | |
| 3198 | −#define STAT_FORCELOSS 0x8003 /* Loss of sync - host request */ | |
| 3199 | −#define STAT_TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */ | |
| 3200 | −#define STAT_DEAUTH 0x8100 /* low byte is 802.11 reason code */ | |
| 3201 | −#define STAT_DISASSOC 0x8200 /* low byte is 802.11 reason code */ | |
| 3202 | −#define STAT_ASSOC_FAIL 0x8400 /* low byte is 802.11 reason code */ | |
| 3203 | −#define STAT_AUTH_FAIL 0x0300 /* low byte is 802.11 reason code */ | |
| 3204 | −#define STAT_ASSOC 0x0400 /* Associated */ | |
| 3205 | −#define STAT_REASSOC 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ | |
| 3206 | − | |
| 3207 | −static void airo_print_status(const char *devname, u16 status) | |
| 3208 | −{ | |
| 3209 | − u8 reason = status & 0xFF; | |
| 3210 | − | |
| 3211 | − switch (status & 0xFF00) { | |
| 3212 | − case STAT_NOBEACON: | |
| 3213 | − switch (status) { | |
| 3214 | − case STAT_NOBEACON: | |
| 3215 | − airo_print_dbg(devname, "link lost (missed beacons)"); | |
| 3216 | − break; | |
| 3217 | − case STAT_MAXRETRIES: | |
| 3218 | − case STAT_MAXARL: | |
| 3219 | − airo_print_dbg(devname, "link lost (max retries)"); | |
| 3220 | − break; | |
| 3221 | − case STAT_FORCELOSS: | |
| 3222 | − airo_print_dbg(devname, "link lost (local choice)"); | |
| 3223 | − break; | |
| 3224 | − case STAT_TSFSYNC: | |
| 3225 | − airo_print_dbg(devname, "link lost (TSF sync lost)"); | |
| 3226 | − break; | |
| 3227 | − default: | |
| 3228 | − airo_print_dbg(devname, "unknown status %x\n", status); | |
| 3229 | − break; | |
| 3230 | − } | |
| 3231 | − break; | |
| 3232 | − case STAT_DEAUTH: | |
| 3233 | − airo_print_dbg(devname, "deauthenticated (reason: %d)", reason); | |
| 3234 | − break; | |
| 3235 | − case STAT_DISASSOC: | |
| 3236 | − airo_print_dbg(devname, "disassociated (reason: %d)", reason); | |
| 3237 | − break; | |
| 3238 | − case STAT_ASSOC_FAIL: | |
| 3239 | − airo_print_dbg(devname, "association failed (reason: %d)", | |
| 3240 | − reason); | |
| 3241 | − break; | |
| 3242 | − case STAT_AUTH_FAIL: | |
| 3243 | − airo_print_dbg(devname, "authentication failed (reason: %d)", | |
| 3244 | − reason); | |
| 3245 | − break; | |
| 3246 | − case STAT_ASSOC: | |
| 3247 | − case STAT_REASSOC: | |
| 3248 | − break; | |
| 3249 | − default: | |
| 3250 | − airo_print_dbg(devname, "unknown status %x\n", status); | |
| 3251 | − break; | |
| 3252 | − } | |
| 3253 | −} | |
| 3254 | − | |
| 3255 | −static void airo_handle_link(struct airo_info *ai) | |
| 3256 | −{ | |
| 3257 | − union iwreq_data wrqu; | |
| 3258 | − int scan_forceloss = 0; | |
| 3259 | − u16 status; | |
| 3260 | − | |
| 3261 | − /* Get new status and acknowledge the link change */ | |
| 3262 | − status = le16_to_cpu(IN4500(ai, LINKSTAT)); | |
| 3263 | − OUT4500(ai, EVACK, EV_LINK); | |
| 3264 | − | |
| 3265 | − if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0)) | |
| 3266 | − scan_forceloss = 1; | |
| 3267 | − | |
| 3268 | − airo_print_status(ai->dev->name, status); | |
| 3269 | − | |
| 3270 | − if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) { | |
| 3271 | − if (auto_wep) | |
| 3272 | − ai->expires = 0; | |
| 3273 | − if (ai->list_bss_task) | |
| 3274 | − wake_up_process(ai->list_bss_task); | |
| 3275 | − set_bit(FLAG_UPDATE_UNI, &ai->flags); | |
| 3276 | − set_bit(FLAG_UPDATE_MULTI, &ai->flags); | |
| 3277 | − | |
| 3278 | − set_bit(JOB_EVENT, &ai->jobs); | |
| 3279 | − wake_up_interruptible(&ai->thr_wait); | |
| 3280 | − | |
| 3281 | − netif_carrier_on(ai->dev); | |
| 3282 | − } else if (!scan_forceloss) { | |
| 3283 | − if (auto_wep && !ai->expires) { | |
| 3284 | − ai->expires = RUN_AT(3*HZ); | |
| 3285 | − wake_up_interruptible(&ai->thr_wait); | |
| 3286 | − } | |
| 3287 | − | |
| 3288 | − /* Send event to user space */ | |
| 3289 | − eth_zero_addr(wrqu.ap_addr.sa_data); | |
| 3290 | − wrqu.ap_addr.sa_family = ARPHRD_ETHER; | |
| 3291 | − wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL); | |
| 3292 | − netif_carrier_off(ai->dev); | |
| 3293 | − } else { | |
| 3294 | − netif_carrier_off(ai->dev); | |
| 3295 | − } | |
| 3296 | −} | |
| 3297 | − | |
| 3298 | −static void airo_handle_rx(struct airo_info *ai) | |
| 3299 | −{ | |
| 3300 | − struct sk_buff *skb = NULL; | |
| 3301 | − __le16 fc, v, *buffer, tmpbuf[4]; | |
| 3302 | − u16 len, hdrlen = 0, gap, fid; | |
| 3303 | − struct rx_hdr hdr; | |
| 3304 | − int success = 0; | |
| 3305 | − | |
| 3306 | − if (test_bit(FLAG_MPI, &ai->flags)) { | |
| 3307 | − if (test_bit(FLAG_802_11, &ai->flags)) | |
| 3308 | − mpi_receive_802_11(ai); | |
| 3309 | − else | |
| 3310 | − mpi_receive_802_3(ai); | |
| 3311 | − OUT4500(ai, EVACK, EV_RX); | |
| 3312 | − return; | |
| 3313 | − } | |
| 3314 | − | |
| 3315 | − fid = IN4500(ai, RXFID); | |
| 3316 | − | |
| 3317 | − /* Get the packet length */ | |
| 3318 | − if (test_bit(FLAG_802_11, &ai->flags)) { | |
| 3319 | − bap_setup (ai, fid, 4, BAP0); | |
| 3320 | − bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0); | |
| 3321 | − /* Bad CRC. Ignore packet */ | |
| 3322 | − if (le16_to_cpu(hdr.status) & 2) | |
| 3323 | − hdr.len = 0; | |
| 3324 | − if (ai->wifidev == NULL) | |
| 3325 | − hdr.len = 0; | |
| 3326 | − } else { | |
| 3327 | − bap_setup(ai, fid, 0x36, BAP0); | |
| 3328 | − bap_read(ai, &hdr.len, 2, BAP0); | |
| 3329 | − } | |
| 3330 | − len = le16_to_cpu(hdr.len); | |
| 3331 | − | |
| 3332 | − if (len > AIRO_DEF_MTU) { | |
| 3333 | − airo_print_err(ai->dev->name, "Bad size %d", len); | |
| 3334 | − goto done; | |
| 3335 | − } | |
| 3336 | − if (len == 0) | |
| 3337 | − goto done; | |
| 3338 | − | |
| 3339 | − if (test_bit(FLAG_802_11, &ai->flags)) { | |
| 3340 | − bap_read(ai, &fc, sizeof (fc), BAP0); | |
| 3341 | − hdrlen = header_len(fc); | |
| 3342 | − } else | |
| 3343 | − hdrlen = ETH_ALEN * 2; | |
| 3344 | − | |
| 3345 | − skb = dev_alloc_skb(len + hdrlen + 2 + 2); | |
| 3346 | − if (!skb) { | |
| 3347 | − ai->dev->stats.rx_dropped++; | |
| 3348 | − goto done; | |
| 3349 | − } | |
| 3350 | − | |
| 3351 | − skb_reserve(skb, 2); /* This way the IP header is aligned */ | |
| 3352 | − buffer = skb_put(skb, len + hdrlen); | |
| 3353 | − if (test_bit(FLAG_802_11, &ai->flags)) { | |
| 3354 | − buffer[0] = fc; | |
| 3355 | − bap_read(ai, buffer + 1, hdrlen - 2, BAP0); | |
| 3356 | − if (hdrlen == 24) | |
| 3357 | − bap_read(ai, tmpbuf, 6, BAP0); | |
| 3358 | − | |
| 3359 | − bap_read(ai, &v, sizeof(v), BAP0); | |
| 3360 | − gap = le16_to_cpu(v); | |
| 3361 | − if (gap) { | |
| 3362 | − if (gap <= 8) { | |
| 3363 | − bap_read(ai, tmpbuf, gap, BAP0); | |
| 3364 | − } else { | |
| 3365 | − airo_print_err(ai->dev->name, "gaplen too " | |
| 3366 | − "big. Problems will follow..."); | |
| 3367 | − } | |
| 3368 | − } | |
| 3369 | − bap_read(ai, buffer + hdrlen/2, len, BAP0); | |
| 3370 | − } else { | |
| 3371 | − MICBuffer micbuf; | |
| 3372 | − | |
| 3373 | − bap_read(ai, buffer, ETH_ALEN * 2, BAP0); | |
| 3374 | − if (ai->micstats.enabled) { | |
| 3375 | − bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0); | |
| 3376 | − if (ntohs(micbuf.typelen) > 0x05DC) | |
| 3377 | − bap_setup(ai, fid, 0x44, BAP0); | |
| 3378 | − else { | |
| 3379 | − if (len <= sizeof (micbuf)) { | |
| 3380 | − dev_kfree_skb_irq(skb); | |
| 3381 | − goto done; | |
| 3382 | − } | |
| 3383 | − | |
| 3384 | − len -= sizeof(micbuf); | |
| 3385 | − skb_trim(skb, len + hdrlen); | |
| 3386 | − } | |
| 3387 | − } | |
| 3388 | − | |
| 3389 | − bap_read(ai, buffer + ETH_ALEN, len, BAP0); | |
| 3390 | − if (decapsulate(ai, &micbuf, (etherHead*) buffer, len)) | |
| 3391 | − dev_kfree_skb_irq (skb); | |
| 3392 | − else | |
| 3393 | − success = 1; | |
| 3394 | − } | |
| 3395 | − | |
| 3396 | −#ifdef WIRELESS_SPY | |
| 3397 | − if (success && (ai->spy_data.spy_number > 0)) { | |
| 3398 | − char *sa; | |
| 3399 | − struct iw_quality wstats; | |
| 3400 | − | |
| 3401 | − /* Prepare spy data : addr + qual */ | |
| 3402 | − if (!test_bit(FLAG_802_11, &ai->flags)) { | |
| 3403 | − sa = (char *) buffer + 6; | |
| 3404 | − bap_setup(ai, fid, 8, BAP0); | |
| 3405 | − bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0); | |
| 3406 | − } else | |
| 3407 | − sa = (char *) buffer + 10; | |
| 3408 | − wstats.qual = hdr.rssi[0]; | |
| 3409 | − if (ai->rssi) | |
| 3410 | − wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; | |
| 3411 | − else | |
| 3412 | − wstats.level = (hdr.rssi[1] + 321) / 2; | |
| 3413 | − wstats.noise = ai->wstats.qual.noise; | |
| 3414 | − wstats.updated = IW_QUAL_LEVEL_UPDATED | |
| 3415 | − | IW_QUAL_QUAL_UPDATED | |
| 3416 | − | IW_QUAL_DBM; | |
| 3417 | − /* Update spy records */ | |
| 3418 | − wireless_spy_update(ai->dev, sa, &wstats); | |
| 3419 | − } | |
| 3420 | −#endif /* WIRELESS_SPY */ | |
| 3421 | − | |
| 3422 | −done: | |
| 3423 | − OUT4500(ai, EVACK, EV_RX); | |
| 3424 | − | |
| 3425 | − if (success) { | |
| 3426 | − if (test_bit(FLAG_802_11, &ai->flags)) { | |
| 3427 | − skb_reset_mac_header(skb); | |
| 3428 | − skb->pkt_type = PACKET_OTHERHOST; | |
| 3429 | − skb->dev = ai->wifidev; | |
| 3430 | − skb->protocol = htons(ETH_P_802_2); | |
| 3431 | − } else | |
| 3432 | − skb->protocol = eth_type_trans(skb, ai->dev); | |
| 3433 | − skb->ip_summed = CHECKSUM_NONE; | |
| 3434 | − | |
| 3435 | − netif_rx(skb); | |
| 3436 | − } | |
| 3437 | −} | |
| 3438 | − | |
| 3439 | −static void airo_handle_tx(struct airo_info *ai, u16 status) | |
| 3440 | −{ | |
| 3441 | − int i, index = -1; | |
| 3442 | − u16 fid; | |
| 3443 | − | |
| 3444 | − if (test_bit(FLAG_MPI, &ai->flags)) { | |
| 3445 | − unsigned long flags; | |
| 3446 | − | |
| 3447 | − if (status & EV_TXEXC) | |
| 3448 | − get_tx_error(ai, -1); | |
| 3449 | − | |
| 3450 | − spin_lock_irqsave(&ai->aux_lock, flags); | |
| 3451 | − if (!skb_queue_empty(&ai->txq)) { | |
| 3452 | − spin_unlock_irqrestore(&ai->aux_lock, flags); | |
| 3453 | − mpi_send_packet(ai->dev); | |
| 3454 | − } else { | |
| 3455 | − clear_bit(FLAG_PENDING_XMIT, &ai->flags); | |
| 3456 | − spin_unlock_irqrestore(&ai->aux_lock, flags); | |
| 3457 | − netif_wake_queue(ai->dev); | |
| 3458 | − } | |
| 3459 | − OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); | |
| 3460 | − return; | |
| 3461 | − } | |
| 3462 | − | |
| 3463 | − fid = IN4500(ai, TXCOMPLFID); | |
| 3464 | − | |
| 3465 | − for (i = 0; i < MAX_FIDS; i++) { | |
| 3466 | − if ((ai->fids[i] & 0xffff) == fid) | |
| 3467 | − index = i; | |
| 3468 | − } | |
| 3469 | − | |
| 3470 | − if (index != -1) { | |
| 3471 | − if (status & EV_TXEXC) | |
| 3472 | − get_tx_error(ai, index); | |
| 3473 | − | |
| 3474 | − OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC)); | |
| 3475 | − | |
| 3476 | − /* Set up to be used again */ | |
| 3477 | − ai->fids[index] &= 0xffff; | |
| 3478 | − if (index < MAX_FIDS / 2) { | |
| 3479 | − if (!test_bit(FLAG_PENDING_XMIT, &ai->flags)) | |
| 3480 | − netif_wake_queue(ai->dev); | |
| 3481 | − } else { | |
| 3482 | − if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags)) | |
| 3483 | − netif_wake_queue(ai->wifidev); | |
| 3484 | − } | |
| 3485 | − } else { | |
| 3486 | − OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); | |
| 3487 | − airo_print_err(ai->dev->name, "Unallocated FID was used to xmit"); | |
| 3488 | − } | |
| 3489 | −} | |
| 3490 | − | |
| 3491 | −static irqreturn_t airo_interrupt(int irq, void *dev_id) | |
| 3492 | −{ | |
| 3493 | − struct net_device *dev = dev_id; | |
| 3494 | − u16 status, savedInterrupts = 0; | |
| 3495 | − struct airo_info *ai = dev->ml_priv; | |
| 3496 | − int handled = 0; | |
| 3497 | − | |
| 3498 | − if (!netif_device_present(dev)) | |
| 3499 | − return IRQ_NONE; | |
| 3500 | − | |
| 3501 | − for (;;) { | |
| 3502 | − status = IN4500(ai, EVSTAT); | |
| 3503 | − if (!(status & STATUS_INTS) || (status == 0xffff)) | |
| 3504 | − break; | |
| 3505 | − | |
| 3506 | − handled = 1; | |
| 3507 | − | |
| 3508 | − if (status & EV_AWAKE) { | |
| 3509 | − OUT4500(ai, EVACK, EV_AWAKE); | |
| 3510 | − OUT4500(ai, EVACK, EV_AWAKE); | |
| 3511 | − } | |
| 3512 | − | |
| 3513 | − if (!savedInterrupts) { | |
| 3514 | − savedInterrupts = IN4500(ai, EVINTEN); | |
| 3515 | − OUT4500(ai, EVINTEN, 0); | |
| 3516 | − } | |
| 3517 | − | |
| 3518 | − if (status & EV_MIC) { | |
| 3519 | − OUT4500(ai, EVACK, EV_MIC); | |
| 3520 | − airo_handle_cisco_mic(ai); | |
| 3521 | − } | |
| 3522 | − | |
| 3523 | − if (status & EV_LINK) { | |
| 3524 | − /* Link status changed */ | |
| 3525 | − airo_handle_link(ai); | |
| 3526 | − } | |
| 3527 | − | |
| 3528 | − /* Check to see if there is something to receive */ | |
| 3529 | − if (status & EV_RX) | |
| 3530 | − airo_handle_rx(ai); | |
| 3531 | − | |
| 3532 | − /* Check to see if a packet has been transmitted */ | |
| 3533 | − if (status & (EV_TX | EV_TXCPY | EV_TXEXC)) | |
| 3534 | − airo_handle_tx(ai, status); | |
| 3535 | − | |
| 3536 | − if (status & ~STATUS_INTS & ~IGNORE_INTS) { | |
| 3537 | − airo_print_warn(ai->dev->name, "Got weird status %x", | |
| 3538 | − status & ~STATUS_INTS & ~IGNORE_INTS); | |
| 3539 | − } | |
| 3540 | − } | |
| 3541 | − | |
| 3542 | − if (savedInterrupts) | |
| 3543 | − OUT4500(ai, EVINTEN, savedInterrupts); | |
| 3544 | − | |
| 3545 | − return IRQ_RETVAL(handled); | |
| 3546 | −} | |
| 3547 | − | |
| 3548 | −/* | |
| 3549 | − * Routines to talk to the card | |
| 3550 | − */ | |
| 3551 | − | |
| 3552 | −/* | |
| 3553 | − * This was originally written for the 4500, hence the name | |
| 3554 | − * NOTE: If use with 8bit mode and SMP bad things will happen! | |
| 3555 | − * Why would some one do 8 bit IO in an SMP machine?!? | |
| 3556 | − */ | |
| 3557 | −static void OUT4500(struct airo_info *ai, u16 reg, u16 val) | |
| 3558 | −{ | |
| 3559 | − if (test_bit(FLAG_MPI,&ai->flags)) | |
| 3560 | − reg <<= 1; | |
| 3561 | − if (!do8bitIO) | |
| 3562 | − outw(val, ai->dev->base_addr + reg); | |
| 3563 | − else { | |
| 3564 | − outb(val & 0xff, ai->dev->base_addr + reg); | |
| 3565 | − outb(val >> 8, ai->dev->base_addr + reg + 1); | |
| 3566 | − } | |
| 3567 | −} | |
| 3568 | − | |
| 3569 | −static u16 IN4500(struct airo_info *ai, u16 reg) | |
| 3570 | −{ | |
| 3571 | − unsigned short rc; | |
| 3572 | − | |
| 3573 | − if (test_bit(FLAG_MPI,&ai->flags)) | |
| 3574 | − reg <<= 1; | |
| 3575 | − if (!do8bitIO) | |
| 3576 | − rc = inw(ai->dev->base_addr + reg); | |
| 3577 | − else { | |
| 3578 | − rc = inb(ai->dev->base_addr + reg); | |
| 3579 | − rc += ((int)inb(ai->dev->base_addr + reg + 1)) << 8; | |
| 3580 | − } | |
| 3581 | − return rc; | |
| 3582 | −} | |
| 3583 | − | |
| 3584 | −static int enable_MAC(struct airo_info *ai, int lock) | |
| 3585 | −{ | |
| 3586 | − int rc; | |
| 3587 | − Cmd cmd; | |
| 3588 | − Resp rsp; | |
| 3589 | − | |
| 3590 | − /* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions | |
| 3591 | − * FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down" | |
| 3592 | − * Note : we could try to use !netif_running(dev) in enable_MAC() | |
| 3593 | − * instead of this flag, but I don't trust it *within* the | |
| 3594 | − * open/close functions, and testing both flags together is | |
| 3595 | − * "cheaper" - Jean II */ | |
| 3596 | − if (ai->flags & FLAG_RADIO_MASK) return SUCCESS; | |
| 3597 | − | |
| 3598 | − if (lock && down_interruptible(&ai->sem)) | |
| 3599 | − return -ERESTARTSYS; | |
| 3600 | − | |
| 3601 | − if (!test_bit(FLAG_ENABLED, &ai->flags)) { | |
| 3602 | − memset(&cmd, 0, sizeof(cmd)); | |
| 3603 | − cmd.cmd = MAC_ENABLE; | |
| 3604 | − rc = issuecommand(ai, &cmd, &rsp, true); | |
| 3605 | − if (rc == SUCCESS) | |
| 3606 | − set_bit(FLAG_ENABLED, &ai->flags); | |
| 3607 | − } else | |
| 3608 | − rc = SUCCESS; | |
| 3609 | − | |
| 3610 | − if (lock) | |
| 3611 | − up(&ai->sem); | |
| 3612 | − | |
| 3613 | − if (rc) | |
| 3614 | − airo_print_err(ai->dev->name, "Cannot enable MAC"); | |
| 3615 | − else if ((rsp.status & 0xFF00) != 0) { | |
| 3616 | − airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, " | |
| 3617 | − "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2); | |
| 3618 | − rc = ERROR; | |
| 3619 | − } | |
| 3620 | − return rc; | |
| 3621 | −} | |
| 3622 | − | |
| 3623 | −static void disable_MAC(struct airo_info *ai, int lock) | |
| 3624 | −{ | |
| 3625 | − Cmd cmd; | |
| 3626 | − Resp rsp; | |
| 3627 | − | |
| 3628 | − if (lock == 1 && down_interruptible(&ai->sem)) | |
| 3629 | − return; | |
| 3630 | − | |
| 3631 | − if (test_bit(FLAG_ENABLED, &ai->flags)) { | |
| 3632 | − if (lock != 2) /* lock == 2 means don't disable carrier */ | |
| 3633 | − netif_carrier_off(ai->dev); | |
| 3634 | − memset(&cmd, 0, sizeof(cmd)); | |
| 3635 | − cmd.cmd = MAC_DISABLE; // disable in case already enabled | |
| 3636 | − issuecommand(ai, &cmd, &rsp, true); | |
| 3637 | − clear_bit(FLAG_ENABLED, &ai->flags); | |
| 3638 | − } | |
| 3639 | − if (lock == 1) | |
| 3640 | − up(&ai->sem); | |
| 3641 | −} | |
| 3642 | − | |
| 3643 | −static void enable_interrupts(struct airo_info *ai) | |
| 3644 | −{ | |
| 3645 | − /* Enable the interrupts */ | |
| 3646 | − OUT4500(ai, EVINTEN, STATUS_INTS); | |
| 3647 | −} | |
| 3648 | − | |
| 3649 | −static void disable_interrupts(struct airo_info *ai) | |
| 3650 | −{ | |
| 3651 | − OUT4500(ai, EVINTEN, 0); | |
| 3652 | −} | |
| 3653 | − | |
| 3654 | −static void mpi_receive_802_3(struct airo_info *ai) | |
| 3655 | −{ | |
| 3656 | − RxFid rxd; | |
| 3657 | − int len = 0; | |
| 3658 | − struct sk_buff *skb; | |
| 3659 | − char *buffer; | |
| 3660 | − int off = 0; | |
| 3661 | − MICBuffer micbuf; | |
| 3662 | − | |
| 3663 | − memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); | |
| 3664 | − /* Make sure we got something */ | |
| 3665 | − if (rxd.rdy && rxd.valid == 0) { | |
| 3666 | − len = rxd.len + 12; | |
| 3667 | − if (len < 12 || len > 2048) | |
| 3668 | − goto badrx; | |
| 3669 | − | |
| 3670 | − skb = dev_alloc_skb(len); | |
| 3671 | − if (!skb) { | |
| 3672 | − ai->dev->stats.rx_dropped++; | |
| 3673 | − goto badrx; | |
| 3674 | − } | |
| 3675 | − buffer = skb_put(skb, len); | |
| 3676 | − memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2); | |
| 3677 | − if (ai->micstats.enabled) { | |
| 3678 | − memcpy(&micbuf, | |
| 3679 | − ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2, | |
| 3680 | − sizeof(micbuf)); | |
| 3681 | − if (ntohs(micbuf.typelen) <= 0x05DC) { | |
| 3682 | − if (len <= sizeof(micbuf) + ETH_ALEN * 2) | |
| 3683 | − goto badmic; | |
| 3684 | − | |
| 3685 | − off = sizeof(micbuf); | |
| 3686 | − skb_trim (skb, len - off); | |
| 3687 | − } | |
| 3688 | − } | |
| 3689 | − memcpy(buffer + ETH_ALEN * 2, | |
| 3690 | − ai->rxfids[0].virtual_host_addr + ETH_ALEN * 2 + off, | |
| 3691 | − len - ETH_ALEN * 2 - off); | |
| 3692 | − if (decapsulate (ai, &micbuf, (etherHead*)buffer, len - off - ETH_ALEN * 2)) { | |
| 3693 | −badmic: | |
| 3694 | − dev_kfree_skb_irq (skb); | |
| 3695 | − goto badrx; | |
| 3696 | − } | |
| 3697 | −#ifdef WIRELESS_SPY | |
| 3698 | − if (ai->spy_data.spy_number > 0) { | |
| 3699 | − char *sa; | |
| 3700 | − struct iw_quality wstats; | |
| 3701 | − /* Prepare spy data : addr + qual */ | |
| 3702 | − sa = buffer + ETH_ALEN; | |
| 3703 | − wstats.qual = 0; /* XXX Where do I get that info from ??? */ | |
| 3704 | − wstats.level = 0; | |
| 3705 | − wstats.updated = 0; | |
| 3706 | − /* Update spy records */ | |
| 3707 | − wireless_spy_update(ai->dev, sa, &wstats); | |
| 3708 | − } | |
| 3709 | −#endif /* WIRELESS_SPY */ | |
| 3710 | − | |
| 3711 | − skb->ip_summed = CHECKSUM_NONE; | |
| 3712 | − skb->protocol = eth_type_trans(skb, ai->dev); | |
| 3713 | − netif_rx(skb); | |
| 3714 | − } | |
| 3715 | −badrx: | |
| 3716 | − if (rxd.valid == 0) { | |
| 3717 | − rxd.valid = 1; | |
| 3718 | − rxd.rdy = 0; | |
| 3719 | − rxd.len = PKTSIZE; | |
| 3720 | − memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); | |
| 3721 | − } | |
| 3722 | −} | |
| 3723 | − | |
| 3724 | −static void mpi_receive_802_11(struct airo_info *ai) | |
| 3725 | −{ | |
| 3726 | − RxFid rxd; | |
| 3727 | − struct sk_buff *skb = NULL; | |
| 3728 | − u16 len, hdrlen = 0; | |
| 3729 | − __le16 fc; | |
| 3730 | − struct rx_hdr hdr; | |
| 3731 | − u16 gap; | |
| 3732 | − u16 *buffer; | |
| 3733 | − char *ptr = ai->rxfids[0].virtual_host_addr + 4; | |
| 3734 | − | |
| 3735 | − memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); | |
| 3736 | − memcpy ((char *)&hdr, ptr, sizeof(hdr)); | |
| 3737 | − ptr += sizeof(hdr); | |
| 3738 | − /* Bad CRC. Ignore packet */ | |
| 3739 | − if (le16_to_cpu(hdr.status) & 2) | |
| 3740 | − hdr.len = 0; | |
| 3741 | − if (ai->wifidev == NULL) | |
| 3742 | − hdr.len = 0; | |
| 3743 | − len = le16_to_cpu(hdr.len); | |
| 3744 | − if (len > AIRO_DEF_MTU) { | |
| 3745 | − airo_print_err(ai->dev->name, "Bad size %d", len); | |
| 3746 | − goto badrx; | |
| 3747 | − } | |
| 3748 | − if (len == 0) | |
| 3749 | − goto badrx; | |
| 3750 | − | |
| 3751 | − fc = get_unaligned((__le16 *)ptr); | |
| 3752 | − hdrlen = header_len(fc); | |
| 3753 | − | |
| 3754 | − skb = dev_alloc_skb(len + hdrlen + 2); | |
| 3755 | − if (!skb) { | |
| 3756 | − ai->dev->stats.rx_dropped++; | |
| 3757 | − goto badrx; | |
| 3758 | − } | |
| 3759 | − buffer = skb_put(skb, len + hdrlen); | |
| 3760 | − memcpy ((char *)buffer, ptr, hdrlen); | |
| 3761 | − ptr += hdrlen; | |
| 3762 | − if (hdrlen == 24) | |
| 3763 | − ptr += 6; | |
| 3764 | − gap = get_unaligned_le16(ptr); | |
| 3765 | − ptr += sizeof(__le16); | |
| 3766 | − if (gap) { | |
| 3767 | − if (gap <= 8) | |
| 3768 | − ptr += gap; | |
| 3769 | − else | |
| 3770 | − airo_print_err(ai->dev->name, | |
| 3771 | − "gaplen too big. Problems will follow..."); | |
| 3772 | − } | |
| 3773 | − memcpy ((char *)buffer + hdrlen, ptr, len); | |
| 3774 | − ptr += len; | |
| 3775 | −#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | |
| 3776 | − if (ai->spy_data.spy_number > 0) { | |
| 3777 | − char *sa; | |
| 3778 | − struct iw_quality wstats; | |
| 3779 | − /* Prepare spy data : addr + qual */ | |
| 3780 | − sa = (char*)buffer + 10; | |
| 3781 | − wstats.qual = hdr.rssi[0]; | |
| 3782 | − if (ai->rssi) | |
| 3783 | − wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; | |
| 3784 | − else | |
| 3785 | − wstats.level = (hdr.rssi[1] + 321) / 2; | |
| 3786 | − wstats.noise = ai->wstats.qual.noise; | |
| 3787 | − wstats.updated = IW_QUAL_QUAL_UPDATED | |
| 3788 | − | IW_QUAL_LEVEL_UPDATED | |
| 3789 | − | IW_QUAL_DBM; | |
| 3790 | − /* Update spy records */ | |
| 3791 | − wireless_spy_update(ai->dev, sa, &wstats); | |
| 3792 | − } | |
| 3793 | −#endif /* IW_WIRELESS_SPY */ | |
| 3794 | − skb_reset_mac_header(skb); | |
| 3795 | − skb->pkt_type = PACKET_OTHERHOST; | |
| 3796 | − skb->dev = ai->wifidev; | |
| 3797 | − skb->protocol = htons(ETH_P_802_2); | |
| 3798 | − skb->ip_summed = CHECKSUM_NONE; | |
| 3799 | − netif_rx(skb); | |
| 3800 | − | |
| 3801 | −badrx: | |
| 3802 | − if (rxd.valid == 0) { | |
| 3803 | − rxd.valid = 1; | |
| 3804 | − rxd.rdy = 0; | |
| 3805 | − rxd.len = PKTSIZE; | |
| 3806 | − memcpy_toio(ai->rxfids[0].card_ram_off, &rxd, sizeof(rxd)); | |
| 3807 | − } | |
| 3808 | −} | |
| 3809 | − | |
| 3810 | −static inline void set_auth_type(struct airo_info *local, int auth_type) | |
| 3811 | −{ | |
| 3812 | − local->config.authType = auth_type; | |
| 3813 | − /* Cache the last auth type used (of AUTH_OPEN and AUTH_ENCRYPT). | |
| 3814 | − * Used by airo_set_auth() | |
| 3815 | − */ | |
| 3816 | − if (auth_type == AUTH_OPEN || auth_type == AUTH_ENCRYPT) | |
| 3817 | − local->last_auth = auth_type; | |
| 3818 | −} | |
| 3819 | − | |
| 3820 | −static int noinline_for_stack airo_readconfig(struct airo_info *ai, | |
| 3821 | − struct net_device *dev, int lock) | |
| 3822 | −{ | |
| 3823 | − int i, status; | |
| 3824 | − /* large variables, so don't inline this function, | |
| 3825 | − * maybe change to kmalloc | |
| 3826 | − */ | |
| 3827 | − tdsRssiRid rssi_rid; | |
| 3828 | − CapabilityRid cap_rid; | |
| 3829 | − | |
| 3830 | − kfree(ai->SSID); | |
| 3831 | − ai->SSID = NULL; | |
| 3832 | − // general configuration (read/modify/write) | |
| 3833 | − status = readConfigRid(ai, lock); | |
| 3834 | − if (status != SUCCESS) return ERROR; | |
| 3835 | − | |
| 3836 | − status = readCapabilityRid(ai, &cap_rid, lock); | |
| 3837 | − if (status != SUCCESS) return ERROR; | |
| 3838 | − | |
| 3839 | − status = PC4500_readrid(ai, RID_RSSI, &rssi_rid, sizeof(rssi_rid), lock); | |
| 3840 | − if (status == SUCCESS) { | |
| 3841 | − if (ai->rssi || (ai->rssi = kmalloc(512, GFP_KERNEL)) != NULL) | |
| 3842 | − memcpy(ai->rssi, (u8*)&rssi_rid + 2, 512); /* Skip RID length member */ | |
| 3843 | − } | |
| 3844 | − else { | |
| 3845 | − kfree(ai->rssi); | |
| 3846 | − ai->rssi = NULL; | |
| 3847 | − if (cap_rid.softCap & cpu_to_le16(8)) | |
| 3848 | − ai->config.rmode |= RXMODE_NORMALIZED_RSSI; | |
| 3849 | − else | |
| 3850 | − airo_print_warn(ai->dev->name, "unknown received signal " | |
| 3851 | − "level scale"); | |
| 3852 | − } | |
| 3853 | − ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; | |
| 3854 | − set_auth_type(ai, AUTH_OPEN); | |
| 3855 | − ai->config.modulation = MOD_CCK; | |
| 3856 | − | |
| 3857 | − if (le16_to_cpu(cap_rid.len) >= sizeof(cap_rid) && | |
| 3858 | − (cap_rid.extSoftCap & cpu_to_le16(1)) && | |
| 3859 | − micsetup(ai) == SUCCESS) { | |
| 3860 | − ai->config.opmode |= MODE_MIC; | |
| 3861 | − set_bit(FLAG_MIC_CAPABLE, &ai->flags); | |
| 3862 | − } | |
| 3863 | − | |
| 3864 | − /* Save off the MAC */ | |
| 3865 | − eth_hw_addr_set(dev, ai->config.macAddr); | |
| 3866 | − | |
| 3867 | − /* Check to see if there are any insmod configured | |
| 3868 | − rates to add */ | |
| 3869 | − if (rates[0]) { | |
| 3870 | − memset(ai->config.rates, 0, sizeof(ai->config.rates)); | |
| 3871 | − for (i = 0; i < 8 && rates[i]; i++) { | |
| 3872 | − ai->config.rates[i] = rates[i]; | |
| 3873 | − } | |
| 3874 | − } | |
| 3875 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 3876 | − | |
| 3877 | − return SUCCESS; | |
| 3878 | −} | |
| 3879 | − | |
| 3880 | − | |
| 3881 | −static u16 setup_card(struct airo_info *ai, struct net_device *dev, int lock) | |
| 3882 | −{ | |
| 3883 | − Cmd cmd; | |
| 3884 | − Resp rsp; | |
| 3885 | − int status; | |
| 3886 | − SsidRid mySsid; | |
| 3887 | − __le16 lastindex; | |
| 3888 | − WepKeyRid wkr; | |
| 3889 | − int rc; | |
| 3890 | − | |
| 3891 | − memset(&mySsid, 0, sizeof(mySsid)); | |
| 3892 | − kfree (ai->flash); | |
| 3893 | − ai->flash = NULL; | |
| 3894 | − | |
| 3895 | − /* The NOP is the first step in getting the card going */ | |
| 3896 | − cmd.cmd = NOP; | |
| 3897 | − cmd.parm0 = cmd.parm1 = cmd.parm2 = 0; | |
| 3898 | − if (lock && down_interruptible(&ai->sem)) | |
| 3899 | − return ERROR; | |
| 3900 | − if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { | |
| 3901 | − if (lock) | |
| 3902 | − up(&ai->sem); | |
| 3903 | − return ERROR; | |
| 3904 | − } | |
| 3905 | − disable_MAC(ai, 0); | |
| 3906 | − | |
| 3907 | − // Let's figure out if we need to use the AUX port | |
| 3908 | − if (!test_bit(FLAG_MPI,&ai->flags)) { | |
| 3909 | − cmd.cmd = CMD_ENABLEAUX; | |
| 3910 | − if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { | |
| 3911 | − if (lock) | |
| 3912 | − up(&ai->sem); | |
| 3913 | − airo_print_err(ai->dev->name, "Error checking for AUX port"); | |
| 3914 | − return ERROR; | |
| 3915 | − } | |
| 3916 | − if (!aux_bap || rsp.status & 0xff00) { | |
| 3917 | − ai->bap_read = fast_bap_read; | |
| 3918 | − airo_print_dbg(ai->dev->name, "Doing fast bap_reads"); | |
| 3919 | − } else { | |
| 3920 | − ai->bap_read = aux_bap_read; | |
| 3921 | − airo_print_dbg(ai->dev->name, "Doing AUX bap_reads"); | |
| 3922 | − } | |
| 3923 | − } | |
| 3924 | − if (lock) | |
| 3925 | − up(&ai->sem); | |
| 3926 | − if (ai->config.len == 0) { | |
| 3927 | − status = airo_readconfig(ai, dev, lock); | |
| 3928 | − if (status != SUCCESS) | |
| 3929 | − return ERROR; | |
| 3930 | − } | |
| 3931 | − | |
| 3932 | − /* Setup the SSIDs if present */ | |
| 3933 | − if (ssids[0]) { | |
| 3934 | − int i; | |
| 3935 | − for (i = 0; i < 3 && ssids[i]; i++) { | |
| 3936 | − size_t len = strlen(ssids[i]); | |
| 3937 | − if (len > 32) | |
| 3938 | − len = 32; | |
| 3939 | − mySsid.ssids[i].len = cpu_to_le16(len); | |
| 3940 | − memcpy(mySsid.ssids[i].ssid, ssids[i], len); | |
| 3941 | − } | |
| 3942 | − mySsid.len = cpu_to_le16(sizeof(mySsid)); | |
| 3943 | − } | |
| 3944 | − | |
| 3945 | − status = writeConfigRid(ai, lock); | |
| 3946 | − if (status != SUCCESS) return ERROR; | |
| 3947 | − | |
| 3948 | − /* Set up the SSID list */ | |
| 3949 | − if (ssids[0]) { | |
| 3950 | − status = writeSsidRid(ai, &mySsid, lock); | |
| 3951 | − if (status != SUCCESS) return ERROR; | |
| 3952 | − } | |
| 3953 | − | |
| 3954 | − status = enable_MAC(ai, lock); | |
| 3955 | − if (status != SUCCESS) | |
| 3956 | − return ERROR; | |
| 3957 | − | |
| 3958 | − /* Grab the initial wep key, we gotta save it for auto_wep */ | |
| 3959 | − rc = readWepKeyRid(ai, &wkr, 1, lock); | |
| 3960 | − if (rc == SUCCESS) do { | |
| 3961 | − lastindex = wkr.kindex; | |
| 3962 | − if (wkr.kindex == cpu_to_le16(0xffff)) { | |
| 3963 | − ai->defindex = wkr.mac[0]; | |
| 3964 | − } | |
| 3965 | − rc = readWepKeyRid(ai, &wkr, 0, lock); | |
| 3966 | − } while (lastindex != wkr.kindex); | |
| 3967 | − | |
| 3968 | − try_auto_wep(ai); | |
| 3969 | − | |
| 3970 | − return SUCCESS; | |
| 3971 | −} | |
| 3972 | − | |
| 3973 | −static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp, | |
| 3974 | − bool may_sleep) | |
| 3975 | −{ | |
| 3976 | − // Im really paranoid about letting it run forever! | |
| 3977 | − int max_tries = 600000; | |
| 3978 | − | |
| 3979 | − if (IN4500(ai, EVSTAT) & EV_CMD) | |
| 3980 | − OUT4500(ai, EVACK, EV_CMD); | |
| 3981 | − | |
| 3982 | − OUT4500(ai, PARAM0, pCmd->parm0); | |
| 3983 | − OUT4500(ai, PARAM1, pCmd->parm1); | |
| 3984 | − OUT4500(ai, PARAM2, pCmd->parm2); | |
| 3985 | − OUT4500(ai, COMMAND, pCmd->cmd); | |
| 3986 | − | |
| 3987 | − while (max_tries-- && (IN4500(ai, EVSTAT) & EV_CMD) == 0) { | |
| 3988 | − if ((IN4500(ai, COMMAND)) == pCmd->cmd) | |
| 3989 | − // PC4500 didn't notice command, try again | |
| 3990 | − OUT4500(ai, COMMAND, pCmd->cmd); | |
| 3991 | − if (may_sleep && (max_tries & 255) == 0) | |
| 3992 | − cond_resched(); | |
| 3993 | − } | |
| 3994 | − | |
| 3995 | − if (max_tries == -1) { | |
| 3996 | − airo_print_err(ai->dev->name, | |
| 3997 | − "Max tries exceeded when issuing command"); | |
| 3998 | − if (IN4500(ai, COMMAND) & COMMAND_BUSY) | |
| 3999 | − OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); | |
| 4000 | − return ERROR; | |
| 4001 | − } | |
| 4002 | − | |
| 4003 | − // command completed | |
| 4004 | − pRsp->status = IN4500(ai, STATUS); | |
| 4005 | − pRsp->rsp0 = IN4500(ai, RESP0); | |
| 4006 | − pRsp->rsp1 = IN4500(ai, RESP1); | |
| 4007 | − pRsp->rsp2 = IN4500(ai, RESP2); | |
| 4008 | − if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) | |
| 4009 | − airo_print_err(ai->dev->name, | |
| 4010 | − "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x", | |
| 4011 | − pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1, | |
| 4012 | − pRsp->rsp2); | |
| 4013 | − | |
| 4014 | − // clear stuck command busy if necessary | |
| 4015 | − if (IN4500(ai, COMMAND) & COMMAND_BUSY) { | |
| 4016 | − OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); | |
| 4017 | − } | |
| 4018 | − // acknowledge processing the status/response | |
| 4019 | − OUT4500(ai, EVACK, EV_CMD); | |
| 4020 | − | |
| 4021 | − return SUCCESS; | |
| 4022 | −} | |
| 4023 | − | |
| 4024 | −/* Sets up the bap to start exchange data. whichbap should | |
| 4025 | − * be one of the BAP0 or BAP1 defines. Locks should be held before | |
| 4026 | − * calling! */ | |
| 4027 | −static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap) | |
| 4028 | −{ | |
| 4029 | − int timeout = 50; | |
| 4030 | − int max_tries = 3; | |
| 4031 | − | |
| 4032 | − OUT4500(ai, SELECT0+whichbap, rid); | |
| 4033 | − OUT4500(ai, OFFSET0+whichbap, offset); | |
| 4034 | − while (1) { | |
| 4035 | − int status = IN4500(ai, OFFSET0+whichbap); | |
| 4036 | − if (status & BAP_BUSY) { | |
| 4037 | − /* This isn't really a timeout, but its kinda | |
| 4038 | − close */ | |
| 4039 | − if (timeout--) { | |
| 4040 | − continue; | |
| 4041 | − } | |
| 4042 | − } else if (status & BAP_ERR) { | |
| 4043 | − /* invalid rid or offset */ | |
| 4044 | − airo_print_err(ai->dev->name, "BAP error %x %d", | |
| 4045 | − status, whichbap); | |
| 4046 | − return ERROR; | |
| 4047 | − } else if (status & BAP_DONE) { // success | |
| 4048 | − return SUCCESS; | |
| 4049 | − } | |
| 4050 | − if (!(max_tries--)) { | |
| 4051 | − airo_print_err(ai->dev->name, | |
| 4052 | − "BAP setup error too many retries\n"); | |
| 4053 | − return ERROR; | |
| 4054 | − } | |
| 4055 | − // -- PC4500 missed it, try again | |
| 4056 | − OUT4500(ai, SELECT0+whichbap, rid); | |
| 4057 | − OUT4500(ai, OFFSET0+whichbap, offset); | |
| 4058 | − timeout = 50; | |
| 4059 | − } | |
| 4060 | −} | |
| 4061 | − | |
| 4062 | −/* should only be called by aux_bap_read. This aux function and the | |
| 4063 | − following use concepts not documented in the developers guide. I | |
| 4064 | − got them from a patch given to my by Aironet */ | |
| 4065 | −static u16 aux_setup(struct airo_info *ai, u16 page, | |
| 4066 | − u16 offset, u16 *len) | |
| 4067 | −{ | |
| 4068 | − u16 next; | |
| 4069 | − | |
| 4070 | − OUT4500(ai, AUXPAGE, page); | |
| 4071 | − OUT4500(ai, AUXOFF, 0); | |
| 4072 | − next = IN4500(ai, AUXDATA); | |
| 4073 | − *len = IN4500(ai, AUXDATA)&0xff; | |
| 4074 | − if (offset != 4) OUT4500(ai, AUXOFF, offset); | |
| 4075 | − return next; | |
| 4076 | −} | |
| 4077 | − | |
| 4078 | −/* requires call to bap_setup() first */ | |
| 4079 | −static int aux_bap_read(struct airo_info *ai, __le16 *pu16Dst, | |
| 4080 | − int bytelen, int whichbap) | |
| 4081 | −{ | |
| 4082 | − u16 len; | |
| 4083 | − u16 page; | |
| 4084 | − u16 offset; | |
| 4085 | − u16 next; | |
| 4086 | − int words; | |
| 4087 | − int i; | |
| 4088 | − unsigned long flags; | |
| 4089 | − | |
| 4090 | − spin_lock_irqsave(&ai->aux_lock, flags); | |
| 4091 | − page = IN4500(ai, SWS0+whichbap); | |
| 4092 | − offset = IN4500(ai, SWS2+whichbap); | |
| 4093 | − next = aux_setup(ai, page, offset, &len); | |
| 4094 | − words = (bytelen+1)>>1; | |
| 4095 | − | |
| 4096 | − for (i = 0; i<words;) { | |
| 4097 | − int count; | |
| 4098 | − count = (len>>1) < (words-i) ? (len>>1) : (words-i); | |
| 4099 | − if (!do8bitIO) | |
| 4100 | − insw(ai->dev->base_addr+DATA0+whichbap, | |
| 4101 | − pu16Dst+i, count); | |
| 4102 | − else | |
| 4103 | − insb(ai->dev->base_addr+DATA0+whichbap, | |
| 4104 | − pu16Dst+i, count << 1); | |
| 4105 | − i += count; | |
| 4106 | − if (i<words) { | |
| 4107 | − next = aux_setup(ai, next, 4, &len); | |
| 4108 | − } | |
| 4109 | − } | |
| 4110 | − spin_unlock_irqrestore(&ai->aux_lock, flags); | |
| 4111 | − return SUCCESS; | |
| 4112 | −} | |
| 4113 | − | |
| 4114 | − | |
| 4115 | −/* requires call to bap_setup() first */ | |
| 4116 | −static int fast_bap_read(struct airo_info *ai, __le16 *pu16Dst, | |
| 4117 | − int bytelen, int whichbap) | |
| 4118 | −{ | |
| 4119 | − bytelen = (bytelen + 1) & (~1); // round up to even value | |
| 4120 | − if (!do8bitIO) | |
| 4121 | − insw(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1); | |
| 4122 | − else | |
| 4123 | − insb(ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen); | |
| 4124 | − return SUCCESS; | |
| 4125 | −} | |
| 4126 | − | |
| 4127 | −/* requires call to bap_setup() first */ | |
| 4128 | −static int bap_write(struct airo_info *ai, const __le16 *pu16Src, | |
| 4129 | − int bytelen, int whichbap) | |
| 4130 | −{ | |
| 4131 | − bytelen = (bytelen + 1) & (~1); // round up to even value | |
| 4132 | − if (!do8bitIO) | |
| 4133 | − outsw(ai->dev->base_addr+DATA0+whichbap, | |
| 4134 | − pu16Src, bytelen>>1); | |
| 4135 | − else | |
| 4136 | − outsb(ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen); | |
| 4137 | − return SUCCESS; | |
| 4138 | −} | |
| 4139 | − | |
| 4140 | −static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd) | |
| 4141 | −{ | |
| 4142 | − Cmd cmd; /* for issuing commands */ | |
| 4143 | − Resp rsp; /* response from commands */ | |
| 4144 | − u16 status; | |
| 4145 | − | |
| 4146 | − memset(&cmd, 0, sizeof(cmd)); | |
| 4147 | − cmd.cmd = accmd; | |
| 4148 | − cmd.parm0 = rid; | |
| 4149 | − status = issuecommand(ai, &cmd, &rsp, true); | |
| 4150 | − if (status != 0) return status; | |
| 4151 | − if ((rsp.status & 0x7F00) != 0) { | |
| 4152 | − return (accmd << 8) + (rsp.rsp0 & 0xFF); | |
| 4153 | − } | |
| 4154 | − return 0; | |
| 4155 | −} | |
| 4156 | − | |
| 4157 | −/* Note, that we are using BAP1 which is also used by transmit, so | |
| 4158 | − * we must get a lock. */ | |
| 4159 | −static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, int lock) | |
| 4160 | −{ | |
| 4161 | − u16 status; | |
| 4162 | − int rc = SUCCESS; | |
| 4163 | − | |
| 4164 | − if (lock) { | |
| 4165 | − if (down_interruptible(&ai->sem)) | |
| 4166 | − return ERROR; | |
| 4167 | − } | |
| 4168 | − if (test_bit(FLAG_MPI,&ai->flags)) { | |
| 4169 | − Cmd cmd; | |
| 4170 | − Resp rsp; | |
| 4171 | − | |
| 4172 | − memset(&cmd, 0, sizeof(cmd)); | |
| 4173 | − memset(&rsp, 0, sizeof(rsp)); | |
| 4174 | − ai->config_desc.rid_desc.valid = 1; | |
| 4175 | − ai->config_desc.rid_desc.len = RIDSIZE; | |
| 4176 | − ai->config_desc.rid_desc.rid = 0; | |
| 4177 | − ai->config_desc.rid_desc.host_addr = ai->ridbus; | |
| 4178 | − | |
| 4179 | − cmd.cmd = CMD_ACCESS; | |
| 4180 | − cmd.parm0 = rid; | |
| 4181 | − | |
| 4182 | − memcpy_toio(ai->config_desc.card_ram_off, | |
| 4183 | − &ai->config_desc.rid_desc, sizeof(Rid)); | |
| 4184 | − | |
| 4185 | − rc = issuecommand(ai, &cmd, &rsp, true); | |
| 4186 | − | |
| 4187 | − if (rsp.status & 0x7f00) | |
| 4188 | − rc = rsp.rsp0; | |
| 4189 | − if (!rc) | |
| 4190 | − memcpy(pBuf, ai->config_desc.virtual_host_addr, len); | |
| 4191 | − goto done; | |
| 4192 | − } else { | |
| 4193 | − if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS))!=SUCCESS) { | |
| 4194 | − rc = status; | |
| 4195 | − goto done; | |
| 4196 | − } | |
| 4197 | − if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { | |
| 4198 | − rc = ERROR; | |
| 4199 | − goto done; | |
| 4200 | − } | |
| 4201 | − // read the rid length field | |
| 4202 | − bap_read(ai, pBuf, 2, BAP1); | |
| 4203 | − // length for remaining part of rid | |
| 4204 | − len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2; | |
| 4205 | − | |
| 4206 | − if (len <= 2) { | |
| 4207 | − airo_print_err(ai->dev->name, | |
| 4208 | − "Rid %x has a length of %d which is too short", | |
| 4209 | − (int)rid, (int)len); | |
| 4210 | − rc = ERROR; | |
| 4211 | − goto done; | |
| 4212 | − } | |
| 4213 | − // read remainder of the rid | |
| 4214 | − rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1); | |
| 4215 | − } | |
| 4216 | −done: | |
| 4217 | − if (lock) | |
| 4218 | − up(&ai->sem); | |
| 4219 | − return rc; | |
| 4220 | −} | |
| 4221 | − | |
| 4222 | −/* Note, that we are using BAP1 which is also used by transmit, so | |
| 4223 | − * make sure this isn't called when a transmit is happening */ | |
| 4224 | −static int PC4500_writerid(struct airo_info *ai, u16 rid, | |
| 4225 | − const void *pBuf, int len, int lock) | |
| 4226 | −{ | |
| 4227 | − u16 status; | |
| 4228 | − int rc = SUCCESS; | |
| 4229 | − | |
| 4230 | − *(__le16*)pBuf = cpu_to_le16((u16)len); | |
| 4231 | − | |
| 4232 | − if (lock) { | |
| 4233 | − if (down_interruptible(&ai->sem)) | |
| 4234 | − return ERROR; | |
| 4235 | − } | |
| 4236 | − if (test_bit(FLAG_MPI,&ai->flags)) { | |
| 4237 | − Cmd cmd; | |
| 4238 | − Resp rsp; | |
| 4239 | − | |
| 4240 | − if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) | |
| 4241 | − airo_print_err(ai->dev->name, | |
| 4242 | − "%s: MAC should be disabled (rid=%04x)", | |
| 4243 | − __func__, rid); | |
| 4244 | − memset(&cmd, 0, sizeof(cmd)); | |
| 4245 | − memset(&rsp, 0, sizeof(rsp)); | |
| 4246 | − | |
| 4247 | − ai->config_desc.rid_desc.valid = 1; | |
| 4248 | − ai->config_desc.rid_desc.len = *((u16 *)pBuf); | |
| 4249 | − ai->config_desc.rid_desc.rid = 0; | |
| 4250 | − | |
| 4251 | − cmd.cmd = CMD_WRITERID; | |
| 4252 | − cmd.parm0 = rid; | |
| 4253 | − | |
| 4254 | − memcpy_toio(ai->config_desc.card_ram_off, | |
| 4255 | − &ai->config_desc.rid_desc, sizeof(Rid)); | |
| 4256 | − | |
| 4257 | − if (len < 4 || len > 2047) { | |
| 4258 | − airo_print_err(ai->dev->name, "%s: len=%d", __func__, len); | |
| 4259 | − rc = -1; | |
| 4260 | − } else { | |
| 4261 | − memcpy(ai->config_desc.virtual_host_addr, | |
| 4262 | − pBuf, len); | |
| 4263 | − | |
| 4264 | − rc = issuecommand(ai, &cmd, &rsp, true); | |
| 4265 | − if ((rc & 0xff00) != 0) { | |
| 4266 | − airo_print_err(ai->dev->name, "%s: Write rid Error %d", | |
| 4267 | − __func__, rc); | |
| 4268 | − airo_print_err(ai->dev->name, "%s: Cmd=%04x", | |
| 4269 | − __func__, cmd.cmd); | |
| 4270 | − } | |
| 4271 | − | |
| 4272 | − if ((rsp.status & 0x7f00)) | |
| 4273 | − rc = rsp.rsp0; | |
| 4274 | − } | |
| 4275 | − } else { | |
| 4276 | − // --- first access so that we can write the rid data | |
| 4277 | − if ((status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) { | |
| 4278 | − rc = status; | |
| 4279 | − goto done; | |
| 4280 | − } | |
| 4281 | − // --- now write the rid data | |
| 4282 | − if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) { | |
| 4283 | − rc = ERROR; | |
| 4284 | − goto done; | |
| 4285 | − } | |
| 4286 | − bap_write(ai, pBuf, len, BAP1); | |
| 4287 | − // ---now commit the rid data | |
| 4288 | − rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS); | |
| 4289 | − } | |
| 4290 | −done: | |
| 4291 | − if (lock) | |
| 4292 | − up(&ai->sem); | |
| 4293 | − return rc; | |
| 4294 | −} | |
| 4295 | − | |
| 4296 | −/* Allocates a FID to be used for transmitting packets. We only use | |
| 4297 | − one for now. */ | |
| 4298 | −static u16 transmit_allocate(struct airo_info *ai, int lenPayload, int raw) | |
| 4299 | −{ | |
| 4300 | − unsigned int loop = 3000; | |
| 4301 | − Cmd cmd; | |
| 4302 | − Resp rsp; | |
| 4303 | − u16 txFid; | |
| 4304 | − __le16 txControl; | |
| 4305 | − | |
| 4306 | − cmd.cmd = CMD_ALLOCATETX; | |
| 4307 | − cmd.parm0 = lenPayload; | |
| 4308 | − if (down_interruptible(&ai->sem)) | |
| 4309 | − return ERROR; | |
| 4310 | − if (issuecommand(ai, &cmd, &rsp, true) != SUCCESS) { | |
| 4311 | − txFid = ERROR; | |
| 4312 | − goto done; | |
| 4313 | − } | |
| 4314 | − if ((rsp.status & 0xFF00) != 0) { | |
| 4315 | − txFid = ERROR; | |
| 4316 | − goto done; | |
| 4317 | − } | |
| 4318 | − /* wait for the allocate event/indication | |
| 4319 | − * It makes me kind of nervous that this can just sit here and spin, | |
| 4320 | − * but in practice it only loops like four times. */ | |
| 4321 | − while (((IN4500(ai, EVSTAT) & EV_ALLOC) == 0) && --loop); | |
| 4322 | − if (!loop) { | |
| 4323 | − txFid = ERROR; | |
| 4324 | − goto done; | |
| 4325 | − } | |
| 4326 | − | |
| 4327 | − // get the allocated fid and acknowledge | |
| 4328 | − txFid = IN4500(ai, TXALLOCFID); | |
| 4329 | − OUT4500(ai, EVACK, EV_ALLOC); | |
| 4330 | − | |
| 4331 | − /* The CARD is pretty cool since it converts the ethernet packet | |
| 4332 | − * into 802.11. Also note that we don't release the FID since we | |
| 4333 | − * will be using the same one over and over again. */ | |
| 4334 | − /* We only have to setup the control once since we are not | |
| 4335 | − * releasing the fid. */ | |
| 4336 | − if (raw) | |
| 4337 | − txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_11 | |
| 4338 | − | TXCTL_ETHERNET | TXCTL_NORELEASE); | |
| 4339 | − else | |
| 4340 | − txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3 | |
| 4341 | − | TXCTL_ETHERNET | TXCTL_NORELEASE); | |
| 4342 | − if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) | |
| 4343 | − txFid = ERROR; | |
| 4344 | − else | |
| 4345 | − bap_write(ai, &txControl, sizeof(txControl), BAP1); | |
| 4346 | − | |
| 4347 | −done: | |
| 4348 | − up(&ai->sem); | |
| 4349 | − | |
| 4350 | − return txFid; | |
| 4351 | −} | |
| 4352 | − | |
| 4353 | −/* In general BAP1 is dedicated to transmiting packets. However, | |
| 4354 | − since we need a BAP when accessing RIDs, we also use BAP1 for that. | |
| 4355 | − Make sure the BAP1 spinlock is held when this is called. */ | |
| 4356 | −static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket, | |
| 4357 | − bool may_sleep) | |
| 4358 | −{ | |
| 4359 | − __le16 payloadLen; | |
| 4360 | − Cmd cmd; | |
| 4361 | − Resp rsp; | |
| 4362 | − int miclen = 0; | |
| 4363 | − u16 txFid = len; | |
| 4364 | − MICBuffer pMic; | |
| 4365 | − | |
| 4366 | − len >>= 16; | |
| 4367 | − | |
| 4368 | − if (len <= ETH_ALEN * 2) { | |
| 4369 | − airo_print_warn(ai->dev->name, "Short packet %d", len); | |
| 4370 | − return ERROR; | |
| 4371 | − } | |
| 4372 | − len -= ETH_ALEN * 2; | |
| 4373 | − | |
| 4374 | − if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && | |
| 4375 | − (ntohs(((__be16 *)pPacket)[6]) != 0x888E)) { | |
| 4376 | − if (encapsulate(ai, (etherHead *)pPacket,&pMic, len) != SUCCESS) | |
| 4377 | − return ERROR; | |
| 4378 | − miclen = sizeof(pMic); | |
| 4379 | − } | |
| 4380 | − // packet is destination[6], source[6], payload[len-12] | |
| 4381 | − // write the payload length and dst/src/payload | |
| 4382 | − if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; | |
| 4383 | − /* The hardware addresses aren't counted as part of the payload, so | |
| 4384 | − * we have to subtract the 12 bytes for the addresses off */ | |
| 4385 | − payloadLen = cpu_to_le16(len + miclen); | |
| 4386 | − bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); | |
| 4387 | − bap_write(ai, (__le16*)pPacket, sizeof(etherHead), BAP1); | |
| 4388 | − if (miclen) | |
| 4389 | − bap_write(ai, (__le16*)&pMic, miclen, BAP1); | |
| 4390 | − bap_write(ai, (__le16*)(pPacket + sizeof(etherHead)), len, BAP1); | |
| 4391 | − // issue the transmit command | |
| 4392 | − memset(&cmd, 0, sizeof(cmd)); | |
| 4393 | − cmd.cmd = CMD_TRANSMIT; | |
| 4394 | − cmd.parm0 = txFid; | |
| 4395 | − if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) | |
| 4396 | − return ERROR; | |
| 4397 | − if ((rsp.status & 0xFF00) != 0) return ERROR; | |
| 4398 | − return SUCCESS; | |
| 4399 | −} | |
| 4400 | − | |
| 4401 | −static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket, | |
| 4402 | − bool may_sleep) | |
| 4403 | −{ | |
| 4404 | − __le16 fc, payloadLen; | |
| 4405 | − Cmd cmd; | |
| 4406 | − Resp rsp; | |
| 4407 | − int hdrlen; | |
| 4408 | − static u8 tail[(30-10) + 2 + 6] = {[30-10] = 6}; | |
| 4409 | − /* padding of header to full size + le16 gaplen (6) + gaplen bytes */ | |
| 4410 | − u16 txFid = len; | |
| 4411 | − len >>= 16; | |
| 4412 | − | |
| 4413 | − fc = *(__le16*)pPacket; | |
| 4414 | − hdrlen = header_len(fc); | |
| 4415 | − | |
| 4416 | − if (len < hdrlen) { | |
| 4417 | − airo_print_warn(ai->dev->name, "Short packet %d", len); | |
| 4418 | − return ERROR; | |
| 4419 | − } | |
| 4420 | − | |
| 4421 | − /* packet is 802.11 header + payload | |
| 4422 | − * write the payload length and dst/src/payload */ | |
| 4423 | − if (bap_setup(ai, txFid, 6, BAP1) != SUCCESS) return ERROR; | |
| 4424 | − /* The 802.11 header aren't counted as part of the payload, so | |
| 4425 | − * we have to subtract the header bytes off */ | |
| 4426 | − payloadLen = cpu_to_le16(len-hdrlen); | |
| 4427 | − bap_write(ai, &payloadLen, sizeof(payloadLen), BAP1); | |
| 4428 | − if (bap_setup(ai, txFid, 0x0014, BAP1) != SUCCESS) return ERROR; | |
| 4429 | − bap_write(ai, (__le16 *)pPacket, hdrlen, BAP1); | |
| 4430 | − bap_write(ai, (__le16 *)(tail + (hdrlen - 10)), 38 - hdrlen, BAP1); | |
| 4431 | − | |
| 4432 | − bap_write(ai, (__le16 *)(pPacket + hdrlen), len - hdrlen, BAP1); | |
| 4433 | − // issue the transmit command | |
| 4434 | − memset(&cmd, 0, sizeof(cmd)); | |
| 4435 | − cmd.cmd = CMD_TRANSMIT; | |
| 4436 | − cmd.parm0 = txFid; | |
| 4437 | − if (issuecommand(ai, &cmd, &rsp, may_sleep) != SUCCESS) | |
| 4438 | − return ERROR; | |
| 4439 | − if ((rsp.status & 0xFF00) != 0) return ERROR; | |
| 4440 | − return SUCCESS; | |
| 4441 | −} | |
| 4442 | − | |
| 4443 | −/* | |
| 4444 | − * This is the proc_fs routines. It is a bit messier than I would | |
| 4445 | − * like! Feel free to clean it up! | |
| 4446 | − */ | |
| 4447 | − | |
| 4448 | −static ssize_t proc_read(struct file *file, | |
| 4449 | − char __user *buffer, | |
| 4450 | − size_t len, | |
| 4451 | − loff_t *offset); | |
| 4452 | − | |
| 4453 | −static ssize_t proc_write(struct file *file, | |
| 4454 | − const char __user *buffer, | |
| 4455 | − size_t len, | |
| 4456 | − loff_t *offset); | |
| 4457 | −static int proc_close(struct inode *inode, struct file *file); | |
| 4458 | − | |
| 4459 | −static int proc_stats_open(struct inode *inode, struct file *file); | |
| 4460 | −static int proc_statsdelta_open(struct inode *inode, struct file *file); | |
| 4461 | −static int proc_status_open(struct inode *inode, struct file *file); | |
| 4462 | −static int proc_SSID_open(struct inode *inode, struct file *file); | |
| 4463 | −static int proc_APList_open(struct inode *inode, struct file *file); | |
| 4464 | −static int proc_BSSList_open(struct inode *inode, struct file *file); | |
| 4465 | −static int proc_config_open(struct inode *inode, struct file *file); | |
| 4466 | −static int proc_wepkey_open(struct inode *inode, struct file *file); | |
| 4467 | − | |
| 4468 | −static const struct proc_ops proc_statsdelta_ops = { | |
| 4469 | − .proc_read = proc_read, | |
| 4470 | − .proc_open = proc_statsdelta_open, | |
| 4471 | − .proc_release = proc_close, | |
| 4472 | − .proc_lseek = default_llseek, | |
| 4473 | −}; | |
| 4474 | − | |
| 4475 | −static const struct proc_ops proc_stats_ops = { | |
| 4476 | − .proc_read = proc_read, | |
| 4477 | − .proc_open = proc_stats_open, | |
| 4478 | − .proc_release = proc_close, | |
| 4479 | − .proc_lseek = default_llseek, | |
| 4480 | −}; | |
| 4481 | − | |
| 4482 | −static const struct proc_ops proc_status_ops = { | |
| 4483 | − .proc_read = proc_read, | |
| 4484 | − .proc_open = proc_status_open, | |
| 4485 | − .proc_release = proc_close, | |
| 4486 | − .proc_lseek = default_llseek, | |
| 4487 | −}; | |
| 4488 | − | |
| 4489 | −static const struct proc_ops proc_SSID_ops = { | |
| 4490 | − .proc_read = proc_read, | |
| 4491 | − .proc_write = proc_write, | |
| 4492 | − .proc_open = proc_SSID_open, | |
| 4493 | − .proc_release = proc_close, | |
| 4494 | − .proc_lseek = default_llseek, | |
| 4495 | −}; | |
| 4496 | − | |
| 4497 | −static const struct proc_ops proc_BSSList_ops = { | |
| 4498 | − .proc_read = proc_read, | |
| 4499 | − .proc_write = proc_write, | |
| 4500 | − .proc_open = proc_BSSList_open, | |
| 4501 | − .proc_release = proc_close, | |
| 4502 | − .proc_lseek = default_llseek, | |
| 4503 | −}; | |
| 4504 | − | |
| 4505 | −static const struct proc_ops proc_APList_ops = { | |
| 4506 | − .proc_read = proc_read, | |
| 4507 | − .proc_write = proc_write, | |
| 4508 | − .proc_open = proc_APList_open, | |
| 4509 | − .proc_release = proc_close, | |
| 4510 | − .proc_lseek = default_llseek, | |
| 4511 | −}; | |
| 4512 | − | |
| 4513 | −static const struct proc_ops proc_config_ops = { | |
| 4514 | − .proc_read = proc_read, | |
| 4515 | − .proc_write = proc_write, | |
| 4516 | − .proc_open = proc_config_open, | |
| 4517 | − .proc_release = proc_close, | |
| 4518 | − .proc_lseek = default_llseek, | |
| 4519 | −}; | |
| 4520 | − | |
| 4521 | −static const struct proc_ops proc_wepkey_ops = { | |
| 4522 | − .proc_read = proc_read, | |
| 4523 | − .proc_write = proc_write, | |
| 4524 | − .proc_open = proc_wepkey_open, | |
| 4525 | − .proc_release = proc_close, | |
| 4526 | − .proc_lseek = default_llseek, | |
| 4527 | −}; | |
| 4528 | − | |
| 4529 | −static struct proc_dir_entry *airo_entry; | |
| 4530 | − | |
| 4531 | −struct proc_data { | |
| 4532 | − int release_buffer; | |
| 4533 | − int readlen; | |
| 4534 | − char *rbuffer; | |
| 4535 | − int writelen; | |
| 4536 | − int maxwritelen; | |
| 4537 | − char *wbuffer; | |
| 4538 | − void (*on_close) (struct inode *, struct file *); | |
| 4539 | −}; | |
| 4540 | − | |
| 4541 | −static int setup_proc_entry(struct net_device *dev, | |
| 4542 | − struct airo_info *apriv) | |
| 4543 | −{ | |
| 4544 | − struct proc_dir_entry *entry; | |
| 4545 | − | |
| 4546 | − /* First setup the device directory */ | |
| 4547 | − strcpy(apriv->proc_name, dev->name); | |
| 4548 | − apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm, | |
| 4549 | − airo_entry); | |
| 4550 | − if (!apriv->proc_entry) | |
| 4551 | − return -ENOMEM; | |
| 4552 | − proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid); | |
| 4553 | − | |
| 4554 | − /* Setup the StatsDelta */ | |
| 4555 | − entry = proc_create_data("StatsDelta", 0444 & proc_perm, | |
| 4556 | − apriv->proc_entry, &proc_statsdelta_ops, dev); | |
| 4557 | − if (!entry) | |
| 4558 | − goto fail; | |
| 4559 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4560 | − | |
| 4561 | − /* Setup the Stats */ | |
| 4562 | − entry = proc_create_data("Stats", 0444 & proc_perm, | |
| 4563 | − apriv->proc_entry, &proc_stats_ops, dev); | |
| 4564 | − if (!entry) | |
| 4565 | − goto fail; | |
| 4566 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4567 | − | |
| 4568 | − /* Setup the Status */ | |
| 4569 | − entry = proc_create_data("Status", 0444 & proc_perm, | |
| 4570 | − apriv->proc_entry, &proc_status_ops, dev); | |
| 4571 | − if (!entry) | |
| 4572 | − goto fail; | |
| 4573 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4574 | − | |
| 4575 | − /* Setup the Config */ | |
| 4576 | − entry = proc_create_data("Config", proc_perm, | |
| 4577 | − apriv->proc_entry, &proc_config_ops, dev); | |
| 4578 | − if (!entry) | |
| 4579 | − goto fail; | |
| 4580 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4581 | − | |
| 4582 | − /* Setup the SSID */ | |
| 4583 | − entry = proc_create_data("SSID", proc_perm, | |
| 4584 | − apriv->proc_entry, &proc_SSID_ops, dev); | |
| 4585 | − if (!entry) | |
| 4586 | − goto fail; | |
| 4587 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4588 | − | |
| 4589 | − /* Setup the APList */ | |
| 4590 | − entry = proc_create_data("APList", proc_perm, | |
| 4591 | − apriv->proc_entry, &proc_APList_ops, dev); | |
| 4592 | − if (!entry) | |
| 4593 | − goto fail; | |
| 4594 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4595 | − | |
| 4596 | − /* Setup the BSSList */ | |
| 4597 | − entry = proc_create_data("BSSList", proc_perm, | |
| 4598 | − apriv->proc_entry, &proc_BSSList_ops, dev); | |
| 4599 | − if (!entry) | |
| 4600 | − goto fail; | |
| 4601 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4602 | − | |
| 4603 | − /* Setup the WepKey */ | |
| 4604 | − entry = proc_create_data("WepKey", proc_perm, | |
| 4605 | − apriv->proc_entry, &proc_wepkey_ops, dev); | |
| 4606 | − if (!entry) | |
| 4607 | − goto fail; | |
| 4608 | − proc_set_user(entry, proc_kuid, proc_kgid); | |
| 4609 | − return 0; | |
| 4610 | − | |
| 4611 | −fail: | |
| 4612 | − remove_proc_subtree(apriv->proc_name, airo_entry); | |
| 4613 | − return -ENOMEM; | |
| 4614 | −} | |
| 4615 | − | |
| 4616 | −static int takedown_proc_entry(struct net_device *dev, | |
| 4617 | − struct airo_info *apriv) | |
| 4618 | −{ | |
| 4619 | − remove_proc_subtree(apriv->proc_name, airo_entry); | |
| 4620 | − return 0; | |
| 4621 | −} | |
| 4622 | − | |
| 4623 | −/* | |
| 4624 | − * What we want from the proc_fs is to be able to efficiently read | |
| 4625 | − * and write the configuration. To do this, we want to read the | |
| 4626 | − * configuration when the file is opened and write it when the file is | |
| 4627 | − * closed. So basically we allocate a read buffer at open and fill it | |
| 4628 | − * with data, and allocate a write buffer and read it at close. | |
| 4629 | − */ | |
| 4630 | − | |
| 4631 | −/* | |
| 4632 | − * The read routine is generic, it relies on the preallocated rbuffer | |
| 4633 | − * to supply the data. | |
| 4634 | − */ | |
| 4635 | −static ssize_t proc_read(struct file *file, | |
| 4636 | − char __user *buffer, | |
| 4637 | − size_t len, | |
| 4638 | − loff_t *offset) | |
| 4639 | −{ | |
| 4640 | − struct proc_data *priv = file->private_data; | |
| 4641 | − | |
| 4642 | − if (!priv->rbuffer) | |
| 4643 | − return -EINVAL; | |
| 4644 | − | |
| 4645 | − return simple_read_from_buffer(buffer, len, offset, priv->rbuffer, | |
| 4646 | − priv->readlen); | |
| 4647 | −} | |
| 4648 | − | |
| 4649 | −/* | |
| 4650 | − * The write routine is generic, it fills in a preallocated rbuffer | |
| 4651 | − * to supply the data. | |
| 4652 | − */ | |
| 4653 | −static ssize_t proc_write(struct file *file, | |
| 4654 | − const char __user *buffer, | |
| 4655 | − size_t len, | |
| 4656 | − loff_t *offset) | |
| 4657 | −{ | |
| 4658 | − ssize_t ret; | |
| 4659 | − struct proc_data *priv = file->private_data; | |
| 4660 | − | |
| 4661 | − if (!priv->wbuffer) | |
| 4662 | − return -EINVAL; | |
| 4663 | − | |
| 4664 | − ret = simple_write_to_buffer(priv->wbuffer, priv->maxwritelen, offset, | |
| 4665 | − buffer, len); | |
| 4666 | − if (ret > 0) | |
| 4667 | − priv->writelen = max_t(int, priv->writelen, *offset); | |
| 4668 | − | |
| 4669 | − return ret; | |
| 4670 | −} | |
| 4671 | − | |
| 4672 | −static int proc_status_open(struct inode *inode, struct file *file) | |
| 4673 | −{ | |
| 4674 | − struct proc_data *data; | |
| 4675 | − struct net_device *dev = pde_data(inode); | |
| 4676 | − struct airo_info *apriv = dev->ml_priv; | |
| 4677 | − CapabilityRid cap_rid; | |
| 4678 | − StatusRid status_rid; | |
| 4679 | − u16 mode; | |
| 4680 | − int i; | |
| 4681 | − | |
| 4682 | − if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) | |
| 4683 | − return -ENOMEM; | |
| 4684 | − data = file->private_data; | |
| 4685 | − if ((data->rbuffer = kmalloc(2048, GFP_KERNEL)) == NULL) { | |
| 4686 | − kfree (file->private_data); | |
| 4687 | − return -ENOMEM; | |
| 4688 | − } | |
| 4689 | − | |
| 4690 | − readStatusRid(apriv, &status_rid, 1); | |
| 4691 | − readCapabilityRid(apriv, &cap_rid, 1); | |
| 4692 | − | |
| 4693 | − mode = le16_to_cpu(status_rid.mode); | |
| 4694 | − | |
| 4695 | − i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n", | |
| 4696 | − mode & 1 ? "CFG ": "", | |
| 4697 | − mode & 2 ? "ACT ": "", | |
| 4698 | − mode & 0x10 ? "SYN ": "", | |
| 4699 | − mode & 0x20 ? "LNK ": "", | |
| 4700 | − mode & 0x40 ? "LEAP ": "", | |
| 4701 | − mode & 0x80 ? "PRIV ": "", | |
| 4702 | − mode & 0x100 ? "KEY ": "", | |
| 4703 | − mode & 0x200 ? "WEP ": "", | |
| 4704 | − mode & 0x8000 ? "ERR ": ""); | |
| 4705 | − sprintf(data->rbuffer+i, "Mode: %x\n" | |
| 4706 | − "Signal Strength: %d\n" | |
| 4707 | − "Signal Quality: %d\n" | |
| 4708 | − "SSID: %-.*s\n" | |
| 4709 | − "AP: %-.16s\n" | |
| 4710 | − "Freq: %d\n" | |
| 4711 | − "BitRate: %dmbs\n" | |
| 4712 | − "Driver Version: %s\n" | |
| 4713 | − "Device: %s\nManufacturer: %s\nFirmware Version: %s\n" | |
| 4714 | − "Radio type: %x\nCountry: %x\nHardware Version: %x\n" | |
| 4715 | − "Software Version: %x\nSoftware Subversion: %x\n" | |
| 4716 | − "Boot block version: %x\n", | |
| 4717 | − le16_to_cpu(status_rid.mode), | |
| 4718 | − le16_to_cpu(status_rid.normalizedSignalStrength), | |
| 4719 | − le16_to_cpu(status_rid.signalQuality), | |
| 4720 | − le16_to_cpu(status_rid.SSIDlen), | |
| 4721 | − status_rid.SSID, | |
| 4722 | − status_rid.apName, | |
| 4723 | − le16_to_cpu(status_rid.channel), | |
| 4724 | − le16_to_cpu(status_rid.currentXmitRate) / 2, | |
| 4725 | − version, | |
| 4726 | − cap_rid.prodName, | |
| 4727 | − cap_rid.manName, | |
| 4728 | − cap_rid.prodVer, | |
| 4729 | − le16_to_cpu(cap_rid.radioType), | |
| 4730 | − le16_to_cpu(cap_rid.country), | |
| 4731 | − le16_to_cpu(cap_rid.hardVer), | |
| 4732 | − le16_to_cpu(cap_rid.softVer), | |
| 4733 | − le16_to_cpu(cap_rid.softSubVer), | |
| 4734 | − le16_to_cpu(cap_rid.bootBlockVer)); | |
| 4735 | − data->readlen = strlen(data->rbuffer); | |
| 4736 | − return 0; | |
| 4737 | −} | |
| 4738 | − | |
| 4739 | −static int proc_stats_rid_open(struct inode*, struct file*, u16); | |
| 4740 | −static int proc_statsdelta_open(struct inode *inode, | |
| 4741 | − struct file *file) | |
| 4742 | −{ | |
| 4743 | − if (file->f_mode&FMODE_WRITE) { | |
| 4744 | − return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR); | |
| 4745 | − } | |
| 4746 | − return proc_stats_rid_open(inode, file, RID_STATSDELTA); | |
| 4747 | −} | |
| 4748 | − | |
| 4749 | −static int proc_stats_open(struct inode *inode, struct file *file) | |
| 4750 | −{ | |
| 4751 | − return proc_stats_rid_open(inode, file, RID_STATS); | |
| 4752 | −} | |
| 4753 | − | |
| 4754 | −static int proc_stats_rid_open(struct inode *inode, | |
| 4755 | − struct file *file, | |
| 4756 | − u16 rid) | |
| 4757 | −{ | |
| 4758 | − struct proc_data *data; | |
| 4759 | − struct net_device *dev = pde_data(inode); | |
| 4760 | − struct airo_info *apriv = dev->ml_priv; | |
| 4761 | − StatsRid stats; | |
| 4762 | − int i, j; | |
| 4763 | − __le32 *vals = stats.vals; | |
| 4764 | − int len; | |
| 4765 | − | |
| 4766 | − if ((file->private_data = kzalloc(sizeof(struct proc_data), GFP_KERNEL)) == NULL) | |
| 4767 | − return -ENOMEM; | |
| 4768 | − data = file->private_data; | |
| 4769 | − if ((data->rbuffer = kmalloc(4096, GFP_KERNEL)) == NULL) { | |
| 4770 | − kfree (file->private_data); | |
| 4771 | − return -ENOMEM; | |
| 4772 | − } | |
| 4773 | − | |
| 4774 | − readStatsRid(apriv, &stats, rid, 1); | |
| 4775 | − len = le16_to_cpu(stats.len); | |
| 4776 | − | |
| 4777 | − j = 0; | |
| 4778 | − for (i = 0; statsLabels[i]!=(char *)-1 && i*4<len; i++) { | |
| 4779 | − if (!statsLabels[i]) continue; | |
| 4780 | − if (j+strlen(statsLabels[i])+16>4096) { | |
| 4781 | − airo_print_warn(apriv->dev->name, | |
| 4782 | − "Potentially disastrous buffer overflow averted!"); | |
| 4783 | − break; | |
| 4784 | − } | |
| 4785 | − j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], | |
| 4786 | − le32_to_cpu(vals[i])); | |
| 4787 | − } | |
| 4788 | − if (i*4 >= len) { | |
| 4789 | − airo_print_warn(apriv->dev->name, "Got a short rid"); | |
| 4790 | − } | |
| 4791 | − data->readlen = j; | |
| 4792 | − return 0; | |
| 4793 | −} | |
| 4794 | − | |
| 4795 | −static int get_dec_u16(char *buffer, int *start, int limit) | |
| 4796 | −{ | |
| 4797 | − u16 value; | |
| 4798 | − int valid = 0; | |
| 4799 | − for (value = 0; *start < limit && buffer[*start] >= '0' && | |
| 4800 | − buffer[*start] <= '9'; (*start)++) { | |
| 4801 | − valid = 1; | |
| 4802 | − value *= 10; | |
| 4803 | − value += buffer[*start] - '0'; | |
| 4804 | − } | |
| 4805 | − if (!valid) return -1; | |
| 4806 | − return value; | |
| 4807 | −} | |
| 4808 | − | |
| 4809 | −static int airo_config_commit(struct net_device *dev, | |
| 4810 | − struct iw_request_info *info, | |
| 4811 | − union iwreq_data *wrqu, | |
| 4812 | − char *extra); | |
| 4813 | − | |
| 4814 | −static inline int sniffing_mode(struct airo_info *ai) | |
| 4815 | −{ | |
| 4816 | − return (le16_to_cpu(ai->config.rmode) & le16_to_cpu(RXMODE_MASK)) >= | |
| 4817 | − le16_to_cpu(RXMODE_RFMON); | |
| 4818 | −} | |
| 4819 | − | |
| 4820 | −static void proc_config_on_close(struct inode *inode, struct file *file) | |
| 4821 | −{ | |
| 4822 | − struct proc_data *data = file->private_data; | |
| 4823 | − struct net_device *dev = pde_data(inode); | |
| 4824 | − struct airo_info *ai = dev->ml_priv; | |
| 4825 | − char *line; | |
| 4826 | − | |
| 4827 | − if (!data->writelen) return; | |
| 4828 | − | |
| 4829 | − readConfigRid(ai, 1); | |
| 4830 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4831 | − | |
| 4832 | − line = data->wbuffer; | |
| 4833 | − while (line[0]) { | |
| 4834 | −/*** Mode processing */ | |
| 4835 | − if (!strncmp(line, "Mode: ", 6)) { | |
| 4836 | − line += 6; | |
| 4837 | − if (sniffing_mode(ai)) | |
| 4838 | − set_bit (FLAG_RESET, &ai->flags); | |
| 4839 | − ai->config.rmode &= ~RXMODE_FULL_MASK; | |
| 4840 | − clear_bit (FLAG_802_11, &ai->flags); | |
| 4841 | − ai->config.opmode &= ~MODE_CFG_MASK; | |
| 4842 | − ai->config.scanMode = SCANMODE_ACTIVE; | |
| 4843 | − if (line[0] == 'a') { | |
| 4844 | − ai->config.opmode |= MODE_STA_IBSS; | |
| 4845 | − } else { | |
| 4846 | − ai->config.opmode |= MODE_STA_ESS; | |
| 4847 | − if (line[0] == 'r') { | |
| 4848 | − ai->config.rmode |= RXMODE_RFMON | RXMODE_DISABLE_802_3_HEADER; | |
| 4849 | − ai->config.scanMode = SCANMODE_PASSIVE; | |
| 4850 | − set_bit (FLAG_802_11, &ai->flags); | |
| 4851 | − } else if (line[0] == 'y') { | |
| 4852 | − ai->config.rmode |= RXMODE_RFMON_ANYBSS | RXMODE_DISABLE_802_3_HEADER; | |
| 4853 | − ai->config.scanMode = SCANMODE_PASSIVE; | |
| 4854 | − set_bit (FLAG_802_11, &ai->flags); | |
| 4855 | − } else if (line[0] == 'l') | |
| 4856 | − ai->config.rmode |= RXMODE_LANMON; | |
| 4857 | − } | |
| 4858 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4859 | − } | |
| 4860 | − | |
| 4861 | −/*** Radio status */ | |
| 4862 | − else if (!strncmp(line,"Radio: ", 7)) { | |
| 4863 | − line += 7; | |
| 4864 | − if (!strncmp(line,"off", 3)) { | |
| 4865 | − set_bit (FLAG_RADIO_OFF, &ai->flags); | |
| 4866 | − } else { | |
| 4867 | − clear_bit (FLAG_RADIO_OFF, &ai->flags); | |
| 4868 | − } | |
| 4869 | − } | |
| 4870 | −/*** NodeName processing */ | |
| 4871 | − else if (!strncmp(line, "NodeName: ", 10)) { | |
| 4872 | − int j; | |
| 4873 | − | |
| 4874 | − line += 10; | |
| 4875 | − memset(ai->config.nodeName, 0, 16); | |
| 4876 | −/* Do the name, assume a space between the mode and node name */ | |
| 4877 | − for (j = 0; j < 16 && line[j] != '\n'; j++) { | |
| 4878 | − ai->config.nodeName[j] = line[j]; | |
| 4879 | − } | |
| 4880 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4881 | − } | |
| 4882 | − | |
| 4883 | −/*** PowerMode processing */ | |
| 4884 | − else if (!strncmp(line, "PowerMode: ", 11)) { | |
| 4885 | − line += 11; | |
| 4886 | − if (!strncmp(line, "PSPCAM", 6)) { | |
| 4887 | − ai->config.powerSaveMode = POWERSAVE_PSPCAM; | |
| 4888 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4889 | − } else if (!strncmp(line, "PSP", 3)) { | |
| 4890 | − ai->config.powerSaveMode = POWERSAVE_PSP; | |
| 4891 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4892 | − } else { | |
| 4893 | − ai->config.powerSaveMode = POWERSAVE_CAM; | |
| 4894 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4895 | − } | |
| 4896 | − } else if (!strncmp(line, "DataRates: ", 11)) { | |
| 4897 | − int v, i = 0, k = 0; /* i is index into line, | |
| 4898 | − k is index to rates */ | |
| 4899 | − | |
| 4900 | − line += 11; | |
| 4901 | − while ((v = get_dec_u16(line, &i, 3))!=-1) { | |
| 4902 | − ai->config.rates[k++] = (u8)v; | |
| 4903 | − line += i + 1; | |
| 4904 | − i = 0; | |
| 4905 | − } | |
| 4906 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4907 | − } else if (!strncmp(line, "Channel: ", 9)) { | |
| 4908 | − int v, i = 0; | |
| 4909 | − line += 9; | |
| 4910 | − v = get_dec_u16(line, &i, i+3); | |
| 4911 | − if (v != -1) { | |
| 4912 | − ai->config.channelSet = cpu_to_le16(v); | |
| 4913 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4914 | − } | |
| 4915 | − } else if (!strncmp(line, "XmitPower: ", 11)) { | |
| 4916 | − int v, i = 0; | |
| 4917 | − line += 11; | |
| 4918 | − v = get_dec_u16(line, &i, i+3); | |
| 4919 | − if (v != -1) { | |
| 4920 | − ai->config.txPower = cpu_to_le16(v); | |
| 4921 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4922 | − } | |
| 4923 | − } else if (!strncmp(line, "WEP: ", 5)) { | |
| 4924 | − line += 5; | |
| 4925 | − switch(line[0]) { | |
| 4926 | − case 's': | |
| 4927 | − set_auth_type(ai, AUTH_SHAREDKEY); | |
| 4928 | − break; | |
| 4929 | − case 'e': | |
| 4930 | − set_auth_type(ai, AUTH_ENCRYPT); | |
| 4931 | − break; | |
| 4932 | − default: | |
| 4933 | − set_auth_type(ai, AUTH_OPEN); | |
| 4934 | − break; | |
| 4935 | − } | |
| 4936 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4937 | − } else if (!strncmp(line, "LongRetryLimit: ", 16)) { | |
| 4938 | − int v, i = 0; | |
| 4939 | − | |
| 4940 | − line += 16; | |
| 4941 | − v = get_dec_u16(line, &i, 3); | |
| 4942 | − v = (v<0) ? 0 : ((v>255) ? 255 : v); | |
| 4943 | − ai->config.longRetryLimit = cpu_to_le16(v); | |
| 4944 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4945 | − } else if (!strncmp(line, "ShortRetryLimit: ", 17)) { | |
| 4946 | − int v, i = 0; | |
| 4947 | − | |
| 4948 | − line += 17; | |
| 4949 | − v = get_dec_u16(line, &i, 3); | |
| 4950 | − v = (v<0) ? 0 : ((v>255) ? 255 : v); | |
| 4951 | − ai->config.shortRetryLimit = cpu_to_le16(v); | |
| 4952 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4953 | − } else if (!strncmp(line, "RTSThreshold: ", 14)) { | |
| 4954 | − int v, i = 0; | |
| 4955 | − | |
| 4956 | − line += 14; | |
| 4957 | − v = get_dec_u16(line, &i, 4); | |
| 4958 | − v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); | |
| 4959 | − ai->config.rtsThres = cpu_to_le16(v); | |
| 4960 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4961 | − } else if (!strncmp(line, "TXMSDULifetime: ", 16)) { | |
| 4962 | − int v, i = 0; | |
| 4963 | − | |
| 4964 | − line += 16; | |
| 4965 | − v = get_dec_u16(line, &i, 5); | |
| 4966 | − v = (v<0) ? 0 : v; | |
| 4967 | − ai->config.txLifetime = cpu_to_le16(v); | |
| 4968 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4969 | − } else if (!strncmp(line, "RXMSDULifetime: ", 16)) { | |
| 4970 | − int v, i = 0; | |
| 4971 | − | |
| 4972 | − line += 16; | |
| 4973 | − v = get_dec_u16(line, &i, 5); | |
| 4974 | − v = (v<0) ? 0 : v; | |
| 4975 | − ai->config.rxLifetime = cpu_to_le16(v); | |
| 4976 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4977 | − } else if (!strncmp(line, "TXDiversity: ", 13)) { | |
| 4978 | − ai->config.txDiversity = | |
| 4979 | − (line[13]=='l') ? 1 : | |
| 4980 | − ((line[13]=='r')? 2: 3); | |
| 4981 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4982 | − } else if (!strncmp(line, "RXDiversity: ", 13)) { | |
| 4983 | − ai->config.rxDiversity = | |
| 4984 | − (line[13]=='l') ? 1 : | |
| 4985 | − ((line[13]=='r')? 2: 3); | |
| 4986 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4987 | − } else if (!strncmp(line, "FragThreshold: ", 15)) { | |
| 4988 | − int v, i = 0; | |
| 4989 | − | |
| 4990 | − line += 15; | |
| 4991 | − v = get_dec_u16(line, &i, 4); | |
| 4992 | − v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); | |
| 4993 | − v = v & 0xfffe; /* Make sure its even */ | |
| 4994 | − ai->config.fragThresh = cpu_to_le16(v); | |
| 4995 | − set_bit (FLAG_COMMIT, &ai->flags); | |
| 4996 | − } else if (!strncmp(line, "Modulation: ", 12)) { | |
| 4997 | − line += 12; | |
| 4998 | − switch(*line) { | |
| 4999 | − case 'd': ai->config.modulation = MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break; | |
3289 more lines aren’t shown here.
| @@ -1,10 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −#ifndef _AIRO_H_ | |
| 3 | −#define _AIRO_H_ | |
| 4 | − | |
| 5 | −struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia, | |
| 6 | − struct device *dmdev); | |
| 7 | −int reset_airo_card(struct net_device *dev); | |
| 8 | −void stop_airo_card(struct net_device *dev, int freeres); | |
| 9 | − | |
| 10 | −#endif /* _AIRO_H_ */ | |
| @@ -1,218 +0,0 @@ | ||
| 1 | −/*====================================================================== | |
| 2 | − | |
| 3 | − Aironet driver for 4500 and 4800 series cards | |
| 4 | − | |
| 5 | − This code is released under both the GPL version 2 and BSD licenses. | |
| 6 | − Either license may be used. The respective licenses are found at | |
| 7 | − the end of this file. | |
| 8 | − | |
| 9 | − This code was developed by Benjamin Reed <breed@users.sourceforge.net> | |
| 10 | − including portions of which come from the Aironet PC4500 | |
| 11 | − Developer's Reference Manual and used with permission. Copyright | |
| 12 | − (C) 1999 Benjamin Reed. All Rights Reserved. Permission to use | |
| 13 | − code in the Developer's manual was granted for this driver by | |
| 14 | − Aironet. | |
| 15 | − | |
| 16 | − In addition this module was derived from dummy_cs. | |
| 17 | − The initial developer of dummy_cs is David A. Hinds | |
| 18 | − <dahinds@users.sourceforge.net>. Portions created by David A. Hinds | |
| 19 | − are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | |
| 20 | − | |
| 21 | −======================================================================*/ | |
| 22 | − | |
| 23 | −#ifdef __IN_PCMCIA_PACKAGE__ | |
| 24 | −#include <pcmcia/k_compat.h> | |
| 25 | −#endif | |
| 26 | −#include <linux/kernel.h> | |
| 27 | −#include <linux/module.h> | |
| 28 | −#include <linux/ptrace.h> | |
| 29 | −#include <linux/slab.h> | |
| 30 | −#include <linux/string.h> | |
| 31 | −#include <linux/timer.h> | |
| 32 | −#include <linux/netdevice.h> | |
| 33 | − | |
| 34 | −#include <pcmcia/cistpl.h> | |
| 35 | −#include <pcmcia/cisreg.h> | |
| 36 | −#include <pcmcia/ds.h> | |
| 37 | − | |
| 38 | −#include <linux/io.h> | |
| 39 | − | |
| 40 | −#include "airo.h" | |
| 41 | − | |
| 42 | − | |
| 43 | −/*====================================================================*/ | |
| 44 | − | |
| 45 | −MODULE_AUTHOR("Benjamin Reed"); | |
| 46 | −MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet " | |
| 47 | − "cards. This is the module that links the PCMCIA card " | |
| 48 | − "with the airo module."); | |
| 49 | −MODULE_LICENSE("Dual BSD/GPL"); | |
| 50 | − | |
| 51 | −/*====================================================================*/ | |
| 52 | − | |
| 53 | −static int airo_config(struct pcmcia_device *link); | |
| 54 | −static void airo_release(struct pcmcia_device *link); | |
| 55 | − | |
| 56 | −static void airo_detach(struct pcmcia_device *p_dev); | |
| 57 | − | |
| 58 | −struct local_info { | |
| 59 | − struct net_device *eth_dev; | |
| 60 | −}; | |
| 61 | − | |
| 62 | −static int airo_probe(struct pcmcia_device *p_dev) | |
| 63 | −{ | |
| 64 | − struct local_info *local; | |
| 65 | − | |
| 66 | − dev_dbg(&p_dev->dev, "airo_attach()\n"); | |
| 67 | − | |
| 68 | − /* Allocate space for private device-specific data */ | |
| 69 | − local = kzalloc(sizeof(*local), GFP_KERNEL); | |
| 70 | − if (!local) | |
| 71 | − return -ENOMEM; | |
| 72 | − | |
| 73 | − p_dev->priv = local; | |
| 74 | − | |
| 75 | − return airo_config(p_dev); | |
| 76 | −} /* airo_attach */ | |
| 77 | − | |
| 78 | −static void airo_detach(struct pcmcia_device *link) | |
| 79 | −{ | |
| 80 | − dev_dbg(&link->dev, "airo_detach\n"); | |
| 81 | − | |
| 82 | − airo_release(link); | |
| 83 | − | |
| 84 | − if (((struct local_info *)link->priv)->eth_dev) { | |
| 85 | − stop_airo_card(((struct local_info *)link->priv)->eth_dev, | |
| 86 | − 0); | |
| 87 | − } | |
| 88 | − ((struct local_info *)link->priv)->eth_dev = NULL; | |
| 89 | − | |
| 90 | − kfree(link->priv); | |
| 91 | −} /* airo_detach */ | |
| 92 | − | |
| 93 | −static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) | |
| 94 | −{ | |
| 95 | − if (p_dev->config_index == 0) | |
| 96 | − return -EINVAL; | |
| 97 | − | |
| 98 | − return pcmcia_request_io(p_dev); | |
| 99 | −} | |
| 100 | − | |
| 101 | − | |
| 102 | −static int airo_config(struct pcmcia_device *link) | |
| 103 | −{ | |
| 104 | − int ret; | |
| 105 | − | |
| 106 | − dev_dbg(&link->dev, "airo_config\n"); | |
| 107 | − | |
| 108 | − link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | | |
| 109 | − CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; | |
| 110 | − | |
| 111 | − ret = pcmcia_loop_config(link, airo_cs_config_check, NULL); | |
| 112 | − if (ret) | |
| 113 | − goto failed; | |
| 114 | − | |
| 115 | − if (!link->irq) | |
| 116 | − goto failed; | |
| 117 | − | |
| 118 | − ret = pcmcia_enable_device(link); | |
| 119 | − if (ret) | |
| 120 | − goto failed; | |
| 121 | − ((struct local_info *)link->priv)->eth_dev = | |
| 122 | − init_airo_card(link->irq, | |
| 123 | − link->resource[0]->start, 1, &link->dev); | |
| 124 | − if (!((struct local_info *)link->priv)->eth_dev) | |
| 125 | − goto failed; | |
| 126 | − | |
| 127 | − return 0; | |
| 128 | − | |
| 129 | − failed: | |
| 130 | − airo_release(link); | |
| 131 | − return -ENODEV; | |
| 132 | −} /* airo_config */ | |
| 133 | − | |
| 134 | −static void airo_release(struct pcmcia_device *link) | |
| 135 | −{ | |
| 136 | − dev_dbg(&link->dev, "airo_release\n"); | |
| 137 | − pcmcia_disable_device(link); | |
| 138 | −} | |
| 139 | − | |
| 140 | −static int airo_suspend(struct pcmcia_device *link) | |
| 141 | −{ | |
| 142 | − struct local_info *local = link->priv; | |
| 143 | − | |
| 144 | − netif_device_detach(local->eth_dev); | |
| 145 | − | |
| 146 | − return 0; | |
| 147 | −} | |
| 148 | − | |
| 149 | −static int airo_resume(struct pcmcia_device *link) | |
| 150 | −{ | |
| 151 | − struct local_info *local = link->priv; | |
| 152 | − | |
| 153 | − if (link->open) { | |
| 154 | − reset_airo_card(local->eth_dev); | |
| 155 | − netif_device_attach(local->eth_dev); | |
| 156 | − } | |
| 157 | − | |
| 158 | − return 0; | |
| 159 | −} | |
| 160 | − | |
| 161 | −static const struct pcmcia_device_id airo_ids[] = { | |
| 162 | − PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a), | |
| 163 | − PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005), | |
| 164 | − PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007), | |
| 165 | − PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007), | |
| 166 | − PCMCIA_DEVICE_NULL, | |
| 167 | −}; | |
| 168 | −MODULE_DEVICE_TABLE(pcmcia, airo_ids); | |
| 169 | − | |
| 170 | −static struct pcmcia_driver airo_driver = { | |
| 171 | − .owner = THIS_MODULE, | |
| 172 | − .name = "airo_cs", | |
| 173 | − .probe = airo_probe, | |
| 174 | − .remove = airo_detach, | |
| 175 | − .id_table = airo_ids, | |
| 176 | − .suspend = airo_suspend, | |
| 177 | − .resume = airo_resume, | |
| 178 | −}; | |
| 179 | −module_pcmcia_driver(airo_driver); | |
| 180 | − | |
| 181 | −/* | |
| 182 | − This program is free software; you can redistribute it and/or | |
| 183 | − modify it under the terms of the GNU General Public License | |
| 184 | − as published by the Free Software Foundation; either version 2 | |
| 185 | − of the License, or (at your option) any later version. | |
| 186 | − | |
| 187 | − This program is distributed in the hope that it will be useful, | |
| 188 | − but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 189 | − MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 190 | − GNU General Public License for more details. | |
| 191 | − | |
| 192 | − In addition: | |
| 193 | − | |
| 194 | − Redistribution and use in source and binary forms, with or without | |
| 195 | − modification, are permitted provided that the following conditions | |
| 196 | − are met: | |
| 197 | − | |
| 198 | − 1. Redistributions of source code must retain the above copyright | |
| 199 | − notice, this list of conditions and the following disclaimer. | |
| 200 | − 2. Redistributions in binary form must reproduce the above copyright | |
| 201 | − notice, this list of conditions and the following disclaimer in the | |
| 202 | − documentation and/or other materials provided with the distribution. | |
| 203 | − 3. The name of the author may not be used to endorse or promote | |
| 204 | − products derived from this software without specific prior written | |
| 205 | − permission. | |
| 206 | − | |
| 207 | − THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
| 208 | − IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
| 209 | − WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 210 | − ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
| 211 | − INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
| 212 | − (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 213 | − SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 214 | − HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
| 215 | − STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
| 216 | − IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| 217 | − POSSIBILITY OF SUCH DAMAGE. | |
| 218 | −*/ | |
| @@ -4231,8 +4231,6 @@ il4965_rx_handle(struct il_priv *il) · 4230 unmodified lines | ||
| 4231 | 4231 | fill_rx = 1; |
| 4232 | 4232 | |
| 4233 | 4233 | while (i != r) { |
| 4234 | − int len; | |
| 4235 | − | |
| 4236 | 4234 | rxb = rxq->queue[i]; |
| 4237 | 4235 | |
| 4238 | 4236 | /* If an RXB doesn't have a Rx queue slot associated with it, |
| @@ -4246,10 +4244,6 @@ il4965_rx_handle(struct il_priv *il) · 7 unmodified lines | ||
| 4246 | 4244 | PAGE_SIZE << il->hw_params.rx_page_order, |
| 4247 | 4245 | DMA_FROM_DEVICE); |
| 4248 | 4246 | pkt = rxb_addr(rxb); |
| 4249 | − | |
| 4250 | − len = le32_to_cpu(pkt->len_n_flags) & IL_RX_FRAME_SIZE_MSK; | |
| 4251 | − len += sizeof(u32); /* account for status word */ | |
| 4252 | − | |
| 4253 | 4247 | reclaim = il_need_reclaim(il, pkt); |
| 4254 | 4248 | |
| 4255 | 4249 | /* Based on type of command response or notification, |
| @@ -12,8 +12,6 @@ config WLAN_VENDOR_INTERSIL · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | if WLAN_VENDOR_INTERSIL |
| 14 | 14 | |
| 15 | −source "drivers/net/wireless/intersil/hostap/Kconfig" | |
| 16 | −source "drivers/net/wireless/intersil/orinoco/Kconfig" | |
| 17 | 15 | source "drivers/net/wireless/intersil/p54/Kconfig" |
| 18 | 16 | |
| 19 | 17 | endif # WLAN_VENDOR_INTERSIL |
| @@ -1,4 +1,2 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | −obj-$(CONFIG_HOSTAP) += hostap/ | |
| 3 | −obj-$(CONFIG_HERMES) += orinoco/ | |
| 4 | 2 | obj-$(CONFIG_P54_COMMON) += p54/ |
| @@ -1,95 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −config HOSTAP | |
| 3 | − tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" | |
| 4 | − select WIRELESS_EXT | |
| 5 | − select WEXT_SPY | |
| 6 | − select WEXT_PRIV | |
| 7 | − select CRYPTO | |
| 8 | − select CRYPTO_MICHAEL_MIC | |
| 9 | − select CRC32 | |
| 10 | − select LIB80211 | |
| 11 | − select LIB80211_CRYPT_WEP | |
| 12 | − select LIB80211_CRYPT_TKIP | |
| 13 | − select LIB80211_CRYPT_CCMP | |
| 14 | − help | |
| 15 | − Shared driver code for IEEE 802.11b wireless cards based on | |
| 16 | − Intersil Prism2/2.5/3 chipset. This driver supports so called | |
| 17 | − Host AP mode that allows the card to act as an IEEE 802.11 | |
| 18 | − access point. | |
| 19 | − | |
| 20 | − See <http://hostap.epitest.fi/> for more information about the | |
| 21 | − Host AP driver configuration and tools. This site includes | |
| 22 | − information and tools (hostapd and wpa_supplicant) for WPA/WPA2 | |
| 23 | − support. | |
| 24 | − | |
| 25 | − This option includes the base Host AP driver code that is shared by | |
| 26 | − different hardware models. You will also need to enable support for | |
| 27 | − PLX/PCI/CS version of the driver to actually use the driver. | |
| 28 | − | |
| 29 | − The driver can be compiled as a module and it will be called | |
| 30 | − hostap. | |
| 31 | − | |
| 32 | −config HOSTAP_FIRMWARE | |
| 33 | − bool "Support downloading firmware images with Host AP driver" | |
| 34 | − depends on HOSTAP | |
| 35 | − help | |
| 36 | − Configure Host AP driver to include support for firmware image | |
| 37 | − download. This option by itself only enables downloading to the | |
| 38 | − volatile memory, i.e. the card RAM. This option is required to | |
| 39 | − support cards that don't have firmware in flash, such as D-Link | |
| 40 | − DWL-520 rev E and D-Link DWL-650 rev P. | |
| 41 | − | |
| 42 | − Firmware image downloading needs a user space tool, prism2_srec. | |
| 43 | − It is available from http://hostap.epitest.fi/. | |
| 44 | − | |
| 45 | −config HOSTAP_FIRMWARE_NVRAM | |
| 46 | − bool "Support for non-volatile firmware download" | |
| 47 | − depends on HOSTAP_FIRMWARE | |
| 48 | − help | |
| 49 | − Allow Host AP driver to write firmware images to the non-volatile | |
| 50 | − card memory, i.e. flash memory that survives power cycling. | |
| 51 | − Enable this option if you want to be able to change card firmware | |
| 52 | − permanently. | |
| 53 | − | |
| 54 | − Firmware image downloading needs a user space tool, prism2_srec. | |
| 55 | − It is available from http://hostap.epitest.fi/. | |
| 56 | − | |
| 57 | −config HOSTAP_PLX | |
| 58 | − tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" | |
| 59 | − depends on PCI && HOSTAP && HAS_IOPORT | |
| 60 | − help | |
| 61 | − Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based | |
| 62 | − PCI adaptors. | |
| 63 | − | |
| 64 | − "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | |
| 65 | − driver and its help text includes more information about the Host AP | |
| 66 | − driver. | |
| 67 | − | |
| 68 | − The driver can be compiled as a module and will be named | |
| 69 | − hostap_plx. | |
| 70 | − | |
| 71 | −config HOSTAP_PCI | |
| 72 | − tristate "Host AP driver for Prism2.5 PCI adaptors" | |
| 73 | − depends on PCI && HOSTAP | |
| 74 | − help | |
| 75 | − Host AP driver's version for Prism2.5 PCI adaptors. | |
| 76 | − | |
| 77 | − "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | |
| 78 | − driver and its help text includes more information about the Host AP | |
| 79 | − driver. | |
| 80 | − | |
| 81 | − The driver can be compiled as a module and will be named | |
| 82 | − hostap_pci. | |
| 83 | − | |
| 84 | −config HOSTAP_CS | |
| 85 | − tristate "Host AP driver for Prism2/2.5/3 PC Cards" | |
| 86 | − depends on PCMCIA && HOSTAP | |
| 87 | − help | |
| 88 | − Host AP driver's version for Prism2/2.5/3 PC Cards. | |
| 89 | − | |
| 90 | − "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this | |
| 91 | − driver and its help text includes more information about the Host AP | |
| 92 | − driver. | |
| 93 | − | |
| 94 | − The driver can be compiled as a module and will be named | |
| 95 | − hostap_cs. | |
| @@ -1,8 +0,0 @@ | ||
| 1 | −# SPDX-License-Identifier: GPL-2.0 | |
| 2 | −hostap-y := hostap_80211_rx.o hostap_80211_tx.o hostap_ap.o hostap_info.o \ | |
| 3 | − hostap_ioctl.o hostap_main.o hostap_proc.o | |
| 4 | −obj-$(CONFIG_HOSTAP) += hostap.o | |
| 5 | − | |
| 6 | −obj-$(CONFIG_HOSTAP_CS) += hostap_cs.o | |
| 7 | −obj-$(CONFIG_HOSTAP_PLX) += hostap_plx.o | |
| 8 | −obj-$(CONFIG_HOSTAP_PCI) += hostap_pci.o | |
| @@ -1,98 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −#ifndef HOSTAP_H | |
| 3 | −#define HOSTAP_H | |
| 4 | − | |
| 5 | −#include <linux/ethtool.h> | |
| 6 | −#include <linux/kernel.h> | |
| 7 | − | |
| 8 | −#include "hostap_wlan.h" | |
| 9 | −#include "hostap_ap.h" | |
| 10 | − | |
| 11 | −static const long __maybe_unused freq_list[] = { | |
| 12 | − 2412, 2417, 2422, 2427, 2432, 2437, 2442, | |
| 13 | − 2447, 2452, 2457, 2462, 2467, 2472, 2484 | |
| 14 | −}; | |
| 15 | −#define FREQ_COUNT ARRAY_SIZE(freq_list) | |
| 16 | − | |
| 17 | −/* hostap.c */ | |
| 18 | − | |
| 19 | −extern struct proc_dir_entry *hostap_proc; | |
| 20 | − | |
| 21 | −u16 hostap_tx_callback_register(local_info_t *local, | |
| 22 | − void (*func)(struct sk_buff *, int ok, void *), | |
| 23 | − void *data); | |
| 24 | −int hostap_tx_callback_unregister(local_info_t *local, u16 idx); | |
| 25 | −int hostap_set_word(struct net_device *dev, int rid, u16 val); | |
| 26 | −int hostap_set_string(struct net_device *dev, int rid, const char *val); | |
| 27 | −u16 hostap_get_porttype(local_info_t *local); | |
| 28 | −int hostap_set_encryption(local_info_t *local); | |
| 29 | −int hostap_set_antsel(local_info_t *local); | |
| 30 | −int hostap_set_roaming(local_info_t *local); | |
| 31 | −int hostap_set_auth_algs(local_info_t *local); | |
| 32 | −void hostap_dump_rx_header(const char *name, | |
| 33 | − const struct hfa384x_rx_frame *rx); | |
| 34 | −void hostap_dump_tx_header(const char *name, | |
| 35 | − const struct hfa384x_tx_frame *tx); | |
| 36 | −extern const struct header_ops hostap_80211_ops; | |
| 37 | −int hostap_80211_get_hdrlen(__le16 fc); | |
| 38 | −struct net_device_stats *hostap_get_stats(struct net_device *dev); | |
| 39 | −void hostap_setup_dev(struct net_device *dev, local_info_t *local, | |
| 40 | − int type); | |
| 41 | −void hostap_set_multicast_list_queue(struct work_struct *work); | |
| 42 | −int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); | |
| 43 | −int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked); | |
| 44 | −void hostap_cleanup(local_info_t *local); | |
| 45 | −void hostap_cleanup_handler(void *data); | |
| 46 | −struct net_device * hostap_add_interface(struct local_info *local, | |
| 47 | − int type, int rtnl_locked, | |
| 48 | − const char *prefix, const char *name); | |
| 49 | −void hostap_remove_interface(struct net_device *dev, int rtnl_locked, | |
| 50 | − int remove_from_list); | |
| 51 | −int prism2_update_comms_qual(struct net_device *dev); | |
| 52 | −int prism2_sta_send_mgmt(local_info_t *local, u8 *dst, u16 stype, | |
| 53 | − u8 *body, size_t bodylen); | |
| 54 | −int prism2_sta_deauth(local_info_t *local, u16 reason); | |
| 55 | −int prism2_wds_add(local_info_t *local, u8 *remote_addr, | |
| 56 | − int rtnl_locked); | |
| 57 | −int prism2_wds_del(local_info_t *local, u8 *remote_addr, | |
| 58 | − int rtnl_locked, int do_not_remove); | |
| 59 | − | |
| 60 | − | |
| 61 | −/* hostap_ap.c */ | |
| 62 | − | |
| 63 | −int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac); | |
| 64 | −int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac); | |
| 65 | −void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); | |
| 66 | −int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); | |
| 67 | −void ap_control_kickall(struct ap_data *ap); | |
| 68 | −void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | |
| 69 | − struct lib80211_crypt_data ***crypt); | |
| 70 | −int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | |
| 71 | − struct iw_quality qual[], int buf_size, | |
| 72 | − int aplist); | |
| 73 | −int prism2_ap_translate_scan(struct net_device *dev, | |
| 74 | − struct iw_request_info *info, char *buffer); | |
| 75 | −int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param); | |
| 76 | − | |
| 77 | − | |
| 78 | −/* hostap_proc.c */ | |
| 79 | − | |
| 80 | −void hostap_init_proc(local_info_t *local); | |
| 81 | −void hostap_remove_proc(local_info_t *local); | |
| 82 | − | |
| 83 | − | |
| 84 | −/* hostap_info.c */ | |
| 85 | − | |
| 86 | −void hostap_info_init(local_info_t *local); | |
| 87 | −void hostap_info_process(local_info_t *local, struct sk_buff *skb); | |
| 88 | − | |
| 89 | − | |
| 90 | −/* hostap_ioctl.c */ | |
| 91 | − | |
| 92 | −extern const struct iw_handler_def hostap_iw_handler_def; | |
| 93 | −extern const struct ethtool_ops prism2_ethtool_ops; | |
| 94 | − | |
| 95 | −int hostap_siocdevprivate(struct net_device *dev, struct ifreq *ifr, | |
| 96 | − void __user *data, int cmd); | |
| 97 | − | |
| 98 | −#endif /* HOSTAP_H */ | |
| @@ -1,97 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −#ifndef HOSTAP_80211_H | |
| 3 | −#define HOSTAP_80211_H | |
| 4 | − | |
| 5 | −#include <linux/types.h> | |
| 6 | −#include <linux/skbuff.h> | |
| 7 | −#include <linux/netdevice.h> | |
| 8 | − | |
| 9 | −struct hostap_ieee80211_mgmt { | |
| 10 | − __le16 frame_control; | |
| 11 | − __le16 duration; | |
| 12 | − u8 da[6]; | |
| 13 | − u8 sa[6]; | |
| 14 | − u8 bssid[6]; | |
| 15 | − __le16 seq_ctrl; | |
| 16 | − union { | |
| 17 | − struct { | |
| 18 | − __le16 auth_alg; | |
| 19 | − __le16 auth_transaction; | |
| 20 | − __le16 status_code; | |
| 21 | − /* possibly followed by Challenge text */ | |
| 22 | − u8 variable[0]; | |
| 23 | − } __packed auth; | |
| 24 | − struct { | |
| 25 | − __le16 reason_code; | |
| 26 | − } __packed deauth; | |
| 27 | − struct { | |
| 28 | − __le16 capab_info; | |
| 29 | − __le16 listen_interval; | |
| 30 | − /* followed by SSID and Supported rates */ | |
| 31 | − u8 variable[0]; | |
| 32 | − } __packed assoc_req; | |
| 33 | − struct { | |
| 34 | − __le16 capab_info; | |
| 35 | − __le16 status_code; | |
| 36 | − __le16 aid; | |
| 37 | − /* followed by Supported rates */ | |
| 38 | − u8 variable[0]; | |
| 39 | − } __packed assoc_resp, reassoc_resp; | |
| 40 | − struct { | |
| 41 | − __le16 capab_info; | |
| 42 | − __le16 listen_interval; | |
| 43 | − u8 current_ap[6]; | |
| 44 | − /* followed by SSID and Supported rates */ | |
| 45 | − u8 variable[0]; | |
| 46 | − } __packed reassoc_req; | |
| 47 | − struct { | |
| 48 | − __le16 reason_code; | |
| 49 | − } __packed disassoc; | |
| 50 | − struct { | |
| 51 | − } __packed probe_req; | |
| 52 | − struct { | |
| 53 | − u8 timestamp[8]; | |
| 54 | − __le16 beacon_int; | |
| 55 | − __le16 capab_info; | |
| 56 | − /* followed by some of SSID, Supported rates, | |
| 57 | − * FH Params, DS Params, CF Params, IBSS Params, TIM */ | |
| 58 | − u8 variable[0]; | |
| 59 | − } __packed beacon, probe_resp; | |
| 60 | − } u; | |
| 61 | −} __packed; | |
| 62 | − | |
| 63 | − | |
| 64 | −#define IEEE80211_MGMT_HDR_LEN 24 | |
| 65 | −#define IEEE80211_DATA_HDR3_LEN 24 | |
| 66 | −#define IEEE80211_DATA_HDR4_LEN 30 | |
| 67 | − | |
| 68 | − | |
| 69 | −struct hostap_80211_rx_status { | |
| 70 | − u32 mac_time; | |
| 71 | − u8 signal; | |
| 72 | − u8 noise; | |
| 73 | − u16 rate; /* in 100 kbps */ | |
| 74 | −}; | |
| 75 | − | |
| 76 | −/* prism2_rx_80211 'type' argument */ | |
| 77 | −enum { | |
| 78 | − PRISM2_RX_MONITOR, PRISM2_RX_MGMT, PRISM2_RX_NON_ASSOC, | |
| 79 | − PRISM2_RX_NULLFUNC_ACK | |
| 80 | −}; | |
| 81 | − | |
| 82 | −int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | |
| 83 | − struct hostap_80211_rx_status *rx_stats, int type); | |
| 84 | −void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |
| 85 | − struct hostap_80211_rx_status *rx_stats); | |
| 86 | −void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | |
| 87 | − struct hostap_80211_rx_status *rx_stats); | |
| 88 | − | |
| 89 | −void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); | |
| 90 | −netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, | |
| 91 | − struct net_device *dev); | |
| 92 | −netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, | |
| 93 | − struct net_device *dev); | |
| 94 | −netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, | |
| 95 | − struct net_device *dev); | |
| 96 | − | |
| 97 | −#endif /* HOSTAP_80211_H */ | |
| @@ -1,1116 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −#include <linux/etherdevice.h> | |
| 3 | −#include <linux/slab.h> | |
| 4 | −#include <linux/export.h> | |
| 5 | −#include <net/lib80211.h> | |
| 6 | −#include <linux/if_arp.h> | |
| 7 | − | |
| 8 | −#include "hostap_80211.h" | |
| 9 | −#include "hostap.h" | |
| 10 | −#include "hostap_ap.h" | |
| 11 | − | |
| 12 | −/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | |
| 13 | −/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | |
| 14 | −static unsigned char rfc1042_header[] = | |
| 15 | −{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | |
| 16 | −/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | |
| 17 | −static unsigned char bridge_tunnel_header[] = | |
| 18 | −{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | |
| 19 | −/* No encapsulation header if EtherType < 0x600 (=length) */ | |
| 20 | − | |
| 21 | −void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, | |
| 22 | − struct hostap_80211_rx_status *rx_stats) | |
| 23 | −{ | |
| 24 | − struct ieee80211_hdr *hdr; | |
| 25 | − u16 fc; | |
| 26 | − | |
| 27 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 28 | − | |
| 29 | − printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d " | |
| 30 | − "jiffies=%ld\n", | |
| 31 | − name, rx_stats->signal, rx_stats->noise, rx_stats->rate, | |
| 32 | − skb->len, jiffies); | |
| 33 | − | |
| 34 | − if (skb->len < 2) | |
| 35 | − return; | |
| 36 | − | |
| 37 | − fc = le16_to_cpu(hdr->frame_control); | |
| 38 | − printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | |
| 39 | − fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, | |
| 40 | − (fc & IEEE80211_FCTL_STYPE) >> 4, | |
| 41 | − fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | |
| 42 | − fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | |
| 43 | − | |
| 44 | − if (skb->len < IEEE80211_DATA_HDR3_LEN) { | |
| 45 | − printk("\n"); | |
| 46 | − return; | |
| 47 | − } | |
| 48 | − | |
| 49 | − printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | |
| 50 | − le16_to_cpu(hdr->seq_ctrl)); | |
| 51 | − | |
| 52 | − printk(KERN_DEBUG " A1=%pM", hdr->addr1); | |
| 53 | − printk(" A2=%pM", hdr->addr2); | |
| 54 | − printk(" A3=%pM", hdr->addr3); | |
| 55 | − if (skb->len >= 30) | |
| 56 | − printk(" A4=%pM", hdr->addr4); | |
| 57 | − printk("\n"); | |
| 58 | −} | |
| 59 | − | |
| 60 | − | |
| 61 | −/* Send RX frame to netif with 802.11 (and possible prism) header. | |
| 62 | − * Called from hardware or software IRQ context. */ | |
| 63 | −int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, | |
| 64 | − struct hostap_80211_rx_status *rx_stats, int type) | |
| 65 | −{ | |
| 66 | − struct hostap_interface *iface; | |
| 67 | − local_info_t *local; | |
| 68 | − int hdrlen, phdrlen, head_need, tail_need; | |
| 69 | − u16 fc; | |
| 70 | − int prism_header, ret; | |
| 71 | − struct ieee80211_hdr *fhdr; | |
| 72 | − | |
| 73 | − iface = netdev_priv(dev); | |
| 74 | − local = iface->local; | |
| 75 | − | |
| 76 | − if (dev->type == ARPHRD_IEEE80211_PRISM) { | |
| 77 | − if (local->monitor_type == PRISM2_MONITOR_PRISM) { | |
| 78 | − prism_header = 1; | |
| 79 | − phdrlen = sizeof(struct linux_wlan_ng_prism_hdr); | |
| 80 | − } else { /* local->monitor_type == PRISM2_MONITOR_CAPHDR */ | |
| 81 | − prism_header = 2; | |
| 82 | − phdrlen = sizeof(struct linux_wlan_ng_cap_hdr); | |
| 83 | − } | |
| 84 | − } else if (dev->type == ARPHRD_IEEE80211_RADIOTAP) { | |
| 85 | − prism_header = 3; | |
| 86 | − phdrlen = sizeof(struct hostap_radiotap_rx); | |
| 87 | − } else { | |
| 88 | − prism_header = 0; | |
| 89 | − phdrlen = 0; | |
| 90 | − } | |
| 91 | − | |
| 92 | − fhdr = (struct ieee80211_hdr *) skb->data; | |
| 93 | − fc = le16_to_cpu(fhdr->frame_control); | |
| 94 | − | |
| 95 | − if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) { | |
| 96 | − printk(KERN_DEBUG "%s: dropped management frame with header " | |
| 97 | − "version %d\n", dev->name, fc & IEEE80211_FCTL_VERS); | |
| 98 | − dev_kfree_skb_any(skb); | |
| 99 | − return 0; | |
| 100 | − } | |
| 101 | − | |
| 102 | − hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control); | |
| 103 | − | |
| 104 | − /* check if there is enough room for extra data; if not, expand skb | |
| 105 | − * buffer to be large enough for the changes */ | |
| 106 | − head_need = phdrlen; | |
| 107 | − tail_need = 0; | |
| 108 | −#ifdef PRISM2_ADD_BOGUS_CRC | |
| 109 | − tail_need += 4; | |
| 110 | −#endif /* PRISM2_ADD_BOGUS_CRC */ | |
| 111 | − | |
| 112 | − head_need -= skb_headroom(skb); | |
| 113 | − tail_need -= skb_tailroom(skb); | |
| 114 | − | |
| 115 | − if (head_need > 0 || tail_need > 0) { | |
| 116 | − if (pskb_expand_head(skb, head_need > 0 ? head_need : 0, | |
| 117 | − tail_need > 0 ? tail_need : 0, | |
| 118 | − GFP_ATOMIC)) { | |
| 119 | − printk(KERN_DEBUG "%s: prism2_rx_80211 failed to " | |
| 120 | − "reallocate skb buffer\n", dev->name); | |
| 121 | − dev_kfree_skb_any(skb); | |
| 122 | − return 0; | |
| 123 | − } | |
| 124 | − } | |
| 125 | − | |
| 126 | − /* We now have an skb with enough head and tail room, so just insert | |
| 127 | − * the extra data */ | |
| 128 | − | |
| 129 | −#ifdef PRISM2_ADD_BOGUS_CRC | |
| 130 | − memset(skb_put(skb, 4), 0xff, 4); /* Prism2 strips CRC */ | |
| 131 | −#endif /* PRISM2_ADD_BOGUS_CRC */ | |
| 132 | − | |
| 133 | − if (prism_header == 1) { | |
| 134 | − struct linux_wlan_ng_prism_hdr *hdr; | |
| 135 | − hdr = skb_push(skb, phdrlen); | |
| 136 | − memset(hdr, 0, phdrlen); | |
| 137 | − hdr->msgcode = LWNG_CAP_DID_BASE; | |
| 138 | − hdr->msglen = sizeof(*hdr); | |
| 139 | − memcpy(hdr->devname, dev->name, sizeof(hdr->devname)); | |
| 140 | −#define LWNG_SETVAL(f,i,s,l,d) \ | |
| 141 | −hdr->f.did = LWNG_CAP_DID_BASE | (i << 12); \ | |
| 142 | −hdr->f.status = s; hdr->f.len = l; hdr->f.data = d | |
| 143 | − LWNG_SETVAL(hosttime, 1, 0, 4, jiffies); | |
| 144 | − LWNG_SETVAL(mactime, 2, 0, 4, rx_stats->mac_time); | |
| 145 | − LWNG_SETVAL(channel, 3, 1 /* no value */, 4, 0); | |
| 146 | − LWNG_SETVAL(rssi, 4, 1 /* no value */, 4, 0); | |
| 147 | − LWNG_SETVAL(sq, 5, 1 /* no value */, 4, 0); | |
| 148 | − LWNG_SETVAL(signal, 6, 0, 4, rx_stats->signal); | |
| 149 | − LWNG_SETVAL(noise, 7, 0, 4, rx_stats->noise); | |
| 150 | − LWNG_SETVAL(rate, 8, 0, 4, rx_stats->rate / 5); | |
| 151 | − LWNG_SETVAL(istx, 9, 0, 4, 0); | |
| 152 | − LWNG_SETVAL(frmlen, 10, 0, 4, skb->len - phdrlen); | |
| 153 | −#undef LWNG_SETVAL | |
| 154 | − } else if (prism_header == 2) { | |
| 155 | − struct linux_wlan_ng_cap_hdr *hdr; | |
| 156 | − hdr = skb_push(skb, phdrlen); | |
| 157 | − memset(hdr, 0, phdrlen); | |
| 158 | − hdr->version = htonl(LWNG_CAPHDR_VERSION); | |
| 159 | − hdr->length = htonl(phdrlen); | |
| 160 | − hdr->mactime = __cpu_to_be64(rx_stats->mac_time); | |
| 161 | − hdr->hosttime = __cpu_to_be64(jiffies); | |
| 162 | − hdr->phytype = htonl(4); /* dss_dot11_b */ | |
| 163 | − hdr->channel = htonl(local->channel); | |
| 164 | − hdr->datarate = htonl(rx_stats->rate); | |
| 165 | − hdr->antenna = htonl(0); /* unknown */ | |
| 166 | − hdr->priority = htonl(0); /* unknown */ | |
| 167 | − hdr->ssi_type = htonl(3); /* raw */ | |
| 168 | − hdr->ssi_signal = htonl(rx_stats->signal); | |
| 169 | − hdr->ssi_noise = htonl(rx_stats->noise); | |
| 170 | − hdr->preamble = htonl(0); /* unknown */ | |
| 171 | − hdr->encoding = htonl(1); /* cck */ | |
| 172 | − } else if (prism_header == 3) { | |
| 173 | − struct hostap_radiotap_rx *hdr; | |
| 174 | − hdr = skb_push(skb, phdrlen); | |
| 175 | − memset(hdr, 0, phdrlen); | |
| 176 | − hdr->hdr.it_len = cpu_to_le16(phdrlen); | |
| 177 | − hdr->hdr.it_present = | |
| 178 | − cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | | |
| 179 | − (1 << IEEE80211_RADIOTAP_CHANNEL) | | |
| 180 | − (1 << IEEE80211_RADIOTAP_RATE) | | |
| 181 | − (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | |
| 182 | − (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)); | |
| 183 | − hdr->tsft = cpu_to_le64(rx_stats->mac_time); | |
| 184 | − hdr->chan_freq = cpu_to_le16(freq_list[local->channel - 1]); | |
| 185 | − hdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_CCK | | |
| 186 | − IEEE80211_CHAN_2GHZ); | |
| 187 | − hdr->rate = rx_stats->rate / 5; | |
| 188 | − hdr->dbm_antsignal = rx_stats->signal; | |
| 189 | − hdr->dbm_antnoise = rx_stats->noise; | |
| 190 | − } | |
| 191 | − | |
| 192 | − ret = skb->len - phdrlen; | |
| 193 | − skb->dev = dev; | |
| 194 | − skb_reset_mac_header(skb); | |
| 195 | − skb_pull(skb, hdrlen); | |
| 196 | − if (prism_header) | |
| 197 | − skb_pull(skb, phdrlen); | |
| 198 | − skb->pkt_type = PACKET_OTHERHOST; | |
| 199 | − skb->protocol = cpu_to_be16(ETH_P_802_2); | |
| 200 | − memset(skb->cb, 0, sizeof(skb->cb)); | |
| 201 | − netif_rx(skb); | |
| 202 | − | |
| 203 | − return ret; | |
| 204 | −} | |
| 205 | − | |
| 206 | − | |
| 207 | −/* Called only as a tasklet (software IRQ) */ | |
| 208 | −static void monitor_rx(struct net_device *dev, struct sk_buff *skb, | |
| 209 | − struct hostap_80211_rx_status *rx_stats) | |
| 210 | −{ | |
| 211 | − int len; | |
| 212 | − | |
| 213 | − len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR); | |
| 214 | − dev->stats.rx_packets++; | |
| 215 | − dev->stats.rx_bytes += len; | |
| 216 | −} | |
| 217 | − | |
| 218 | − | |
| 219 | −/* Called only as a tasklet (software IRQ) */ | |
| 220 | −static struct prism2_frag_entry * | |
| 221 | −prism2_frag_cache_find(local_info_t *local, unsigned int seq, | |
| 222 | − unsigned int frag, u8 *src, u8 *dst) | |
| 223 | −{ | |
| 224 | − struct prism2_frag_entry *entry; | |
| 225 | − int i; | |
| 226 | − | |
| 227 | − for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { | |
| 228 | − entry = &local->frag_cache[i]; | |
| 229 | − if (entry->skb != NULL && | |
| 230 | − time_after(jiffies, entry->first_frag_time + 2 * HZ)) { | |
| 231 | − printk(KERN_DEBUG "%s: expiring fragment cache entry " | |
| 232 | − "seq=%u last_frag=%u\n", | |
| 233 | − local->dev->name, entry->seq, entry->last_frag); | |
| 234 | − dev_kfree_skb(entry->skb); | |
| 235 | − entry->skb = NULL; | |
| 236 | − } | |
| 237 | − | |
| 238 | − if (entry->skb != NULL && entry->seq == seq && | |
| 239 | − (entry->last_frag + 1 == frag || frag == -1) && | |
| 240 | − memcmp(entry->src_addr, src, ETH_ALEN) == 0 && | |
| 241 | − memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) | |
| 242 | − return entry; | |
| 243 | − } | |
| 244 | − | |
| 245 | − return NULL; | |
| 246 | −} | |
| 247 | − | |
| 248 | − | |
| 249 | −/* Called only as a tasklet (software IRQ) */ | |
| 250 | −static struct sk_buff * | |
| 251 | −prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr) | |
| 252 | −{ | |
| 253 | − struct sk_buff *skb = NULL; | |
| 254 | − u16 sc; | |
| 255 | − unsigned int frag, seq; | |
| 256 | − struct prism2_frag_entry *entry; | |
| 257 | − | |
| 258 | − sc = le16_to_cpu(hdr->seq_ctrl); | |
| 259 | − frag = sc & IEEE80211_SCTL_FRAG; | |
| 260 | − seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | |
| 261 | − | |
| 262 | − if (frag == 0) { | |
| 263 | − /* Reserve enough space to fit maximum frame length */ | |
| 264 | − skb = dev_alloc_skb(local->dev->mtu + | |
| 265 | − sizeof(struct ieee80211_hdr) + | |
| 266 | − 8 /* LLC */ + | |
| 267 | − 2 /* alignment */ + | |
| 268 | − 8 /* WEP */ + ETH_ALEN /* WDS */); | |
| 269 | − if (skb == NULL) | |
| 270 | − return NULL; | |
| 271 | − | |
| 272 | − entry = &local->frag_cache[local->frag_next_idx]; | |
| 273 | − local->frag_next_idx++; | |
| 274 | − if (local->frag_next_idx >= PRISM2_FRAG_CACHE_LEN) | |
| 275 | − local->frag_next_idx = 0; | |
| 276 | − | |
| 277 | − if (entry->skb != NULL) | |
| 278 | − dev_kfree_skb(entry->skb); | |
| 279 | − | |
| 280 | − entry->first_frag_time = jiffies; | |
| 281 | − entry->seq = seq; | |
| 282 | − entry->last_frag = frag; | |
| 283 | − entry->skb = skb; | |
| 284 | − memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); | |
| 285 | − memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); | |
| 286 | − } else { | |
| 287 | − /* received a fragment of a frame for which the head fragment | |
| 288 | − * should have already been received */ | |
| 289 | − entry = prism2_frag_cache_find(local, seq, frag, hdr->addr2, | |
| 290 | − hdr->addr1); | |
| 291 | − if (entry != NULL) { | |
| 292 | − entry->last_frag = frag; | |
| 293 | − skb = entry->skb; | |
| 294 | − } | |
| 295 | − } | |
| 296 | − | |
| 297 | − return skb; | |
| 298 | −} | |
| 299 | − | |
| 300 | − | |
| 301 | −/* Called only as a tasklet (software IRQ) */ | |
| 302 | −static int prism2_frag_cache_invalidate(local_info_t *local, | |
| 303 | − struct ieee80211_hdr *hdr) | |
| 304 | −{ | |
| 305 | − u16 sc; | |
| 306 | − unsigned int seq; | |
| 307 | − struct prism2_frag_entry *entry; | |
| 308 | − | |
| 309 | − sc = le16_to_cpu(hdr->seq_ctrl); | |
| 310 | − seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | |
| 311 | − | |
| 312 | − entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1); | |
| 313 | − | |
| 314 | − if (entry == NULL) { | |
| 315 | − printk(KERN_DEBUG "%s: could not invalidate fragment cache " | |
| 316 | − "entry (seq=%u)\n", | |
| 317 | − local->dev->name, seq); | |
| 318 | − return -1; | |
| 319 | − } | |
| 320 | − | |
| 321 | − entry->skb = NULL; | |
| 322 | − return 0; | |
| 323 | −} | |
| 324 | − | |
| 325 | − | |
| 326 | −static struct hostap_bss_info *__hostap_get_bss(local_info_t *local, u8 *bssid, | |
| 327 | − u8 *ssid, size_t ssid_len) | |
| 328 | −{ | |
| 329 | − struct list_head *ptr; | |
| 330 | − struct hostap_bss_info *bss; | |
| 331 | − | |
| 332 | − list_for_each(ptr, &local->bss_list) { | |
| 333 | − bss = list_entry(ptr, struct hostap_bss_info, list); | |
| 334 | − if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && | |
| 335 | − (ssid == NULL || | |
| 336 | − (ssid_len == bss->ssid_len && | |
| 337 | − memcmp(ssid, bss->ssid, ssid_len) == 0))) { | |
| 338 | − list_move(&bss->list, &local->bss_list); | |
| 339 | − return bss; | |
| 340 | − } | |
| 341 | − } | |
| 342 | − | |
| 343 | − return NULL; | |
| 344 | −} | |
| 345 | − | |
| 346 | − | |
| 347 | −static struct hostap_bss_info *__hostap_add_bss(local_info_t *local, u8 *bssid, | |
| 348 | − u8 *ssid, size_t ssid_len) | |
| 349 | −{ | |
| 350 | − struct hostap_bss_info *bss; | |
| 351 | − | |
| 352 | − if (local->num_bss_info >= HOSTAP_MAX_BSS_COUNT) { | |
| 353 | − bss = list_entry(local->bss_list.prev, | |
| 354 | − struct hostap_bss_info, list); | |
| 355 | − list_del(&bss->list); | |
| 356 | − local->num_bss_info--; | |
| 357 | − } else { | |
| 358 | − bss = kmalloc(sizeof(*bss), GFP_ATOMIC); | |
| 359 | − if (bss == NULL) | |
| 360 | − return NULL; | |
| 361 | − } | |
| 362 | − | |
| 363 | − memset(bss, 0, sizeof(*bss)); | |
| 364 | − memcpy(bss->bssid, bssid, ETH_ALEN); | |
| 365 | − memcpy(bss->ssid, ssid, ssid_len); | |
| 366 | − bss->ssid_len = ssid_len; | |
| 367 | − local->num_bss_info++; | |
| 368 | − list_add(&bss->list, &local->bss_list); | |
| 369 | − return bss; | |
| 370 | −} | |
| 371 | − | |
| 372 | − | |
| 373 | −static void __hostap_expire_bss(local_info_t *local) | |
| 374 | −{ | |
| 375 | − struct hostap_bss_info *bss; | |
| 376 | − | |
| 377 | − while (local->num_bss_info > 0) { | |
| 378 | − bss = list_entry(local->bss_list.prev, | |
| 379 | − struct hostap_bss_info, list); | |
| 380 | − if (!time_after(jiffies, bss->last_update + 60 * HZ)) | |
| 381 | − break; | |
| 382 | − | |
| 383 | − list_del(&bss->list); | |
| 384 | − local->num_bss_info--; | |
| 385 | − kfree(bss); | |
| 386 | − } | |
| 387 | −} | |
| 388 | − | |
| 389 | − | |
| 390 | −/* Both IEEE 802.11 Beacon and Probe Response frames have similar structure, so | |
| 391 | − * the same routine can be used to parse both of them. */ | |
| 392 | −static void hostap_rx_sta_beacon(local_info_t *local, struct sk_buff *skb, | |
| 393 | − int stype) | |
| 394 | −{ | |
| 395 | − struct hostap_ieee80211_mgmt *mgmt; | |
| 396 | − int left, chan = 0; | |
| 397 | − u8 *pos; | |
| 398 | − u8 *ssid = NULL, *wpa = NULL, *rsn = NULL; | |
| 399 | − size_t ssid_len = 0, wpa_len = 0, rsn_len = 0; | |
| 400 | − struct hostap_bss_info *bss; | |
| 401 | − | |
| 402 | − if (skb->len < IEEE80211_MGMT_HDR_LEN + sizeof(mgmt->u.beacon)) | |
| 403 | − return; | |
| 404 | − | |
| 405 | − mgmt = (struct hostap_ieee80211_mgmt *) skb->data; | |
| 406 | − pos = mgmt->u.beacon.variable; | |
| 407 | − left = skb->len - (pos - skb->data); | |
| 408 | − | |
| 409 | − while (left >= 2) { | |
| 410 | − if (2 + pos[1] > left) | |
| 411 | − return; /* parse failed */ | |
| 412 | − switch (*pos) { | |
| 413 | − case WLAN_EID_SSID: | |
| 414 | − ssid = pos + 2; | |
| 415 | − ssid_len = pos[1]; | |
| 416 | − break; | |
| 417 | − case WLAN_EID_VENDOR_SPECIFIC: | |
| 418 | − if (pos[1] >= 4 && | |
| 419 | − pos[2] == 0x00 && pos[3] == 0x50 && | |
| 420 | − pos[4] == 0xf2 && pos[5] == 1) { | |
| 421 | − wpa = pos; | |
| 422 | − wpa_len = pos[1] + 2; | |
| 423 | − } | |
| 424 | − break; | |
| 425 | − case WLAN_EID_RSN: | |
| 426 | − rsn = pos; | |
| 427 | − rsn_len = pos[1] + 2; | |
| 428 | − break; | |
| 429 | − case WLAN_EID_DS_PARAMS: | |
| 430 | − if (pos[1] >= 1) | |
| 431 | − chan = pos[2]; | |
| 432 | − break; | |
| 433 | − } | |
| 434 | − left -= 2 + pos[1]; | |
| 435 | − pos += 2 + pos[1]; | |
| 436 | − } | |
| 437 | − | |
| 438 | − if (wpa_len > MAX_WPA_IE_LEN) | |
| 439 | − wpa_len = MAX_WPA_IE_LEN; | |
| 440 | − if (rsn_len > MAX_WPA_IE_LEN) | |
| 441 | − rsn_len = MAX_WPA_IE_LEN; | |
| 442 | − if (ssid_len > sizeof(bss->ssid)) | |
| 443 | − ssid_len = sizeof(bss->ssid); | |
| 444 | − | |
| 445 | − spin_lock(&local->lock); | |
| 446 | − bss = __hostap_get_bss(local, mgmt->bssid, ssid, ssid_len); | |
| 447 | − if (bss == NULL) | |
| 448 | − bss = __hostap_add_bss(local, mgmt->bssid, ssid, ssid_len); | |
| 449 | − if (bss) { | |
| 450 | − bss->last_update = jiffies; | |
| 451 | − bss->count++; | |
| 452 | − bss->capab_info = le16_to_cpu(mgmt->u.beacon.capab_info); | |
| 453 | − if (wpa) { | |
| 454 | − memcpy(bss->wpa_ie, wpa, wpa_len); | |
| 455 | − bss->wpa_ie_len = wpa_len; | |
| 456 | − } else | |
| 457 | − bss->wpa_ie_len = 0; | |
| 458 | − if (rsn) { | |
| 459 | − memcpy(bss->rsn_ie, rsn, rsn_len); | |
| 460 | − bss->rsn_ie_len = rsn_len; | |
| 461 | − } else | |
| 462 | − bss->rsn_ie_len = 0; | |
| 463 | − bss->chan = chan; | |
| 464 | − } | |
| 465 | − __hostap_expire_bss(local); | |
| 466 | − spin_unlock(&local->lock); | |
| 467 | −} | |
| 468 | − | |
| 469 | − | |
| 470 | −static int | |
| 471 | −hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb, | |
| 472 | − struct hostap_80211_rx_status *rx_stats, u16 type, | |
| 473 | − u16 stype) | |
| 474 | −{ | |
| 475 | − if (local->iw_mode == IW_MODE_MASTER) | |
| 476 | − hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data); | |
| 477 | − | |
| 478 | − if (local->hostapd && type == IEEE80211_FTYPE_MGMT) { | |
| 479 | − if (stype == IEEE80211_STYPE_BEACON && | |
| 480 | − local->iw_mode == IW_MODE_MASTER) { | |
| 481 | − struct sk_buff *skb2; | |
| 482 | − /* Process beacon frames also in kernel driver to | |
| 483 | − * update STA(AP) table statistics */ | |
| 484 | − skb2 = skb_clone(skb, GFP_ATOMIC); | |
| 485 | − if (skb2) | |
| 486 | − hostap_rx(skb2->dev, skb2, rx_stats); | |
| 487 | − } | |
| 488 | − | |
| 489 | − /* send management frames to the user space daemon for | |
| 490 | − * processing */ | |
| 491 | − local->apdevstats.rx_packets++; | |
| 492 | − local->apdevstats.rx_bytes += skb->len; | |
| 493 | − if (local->apdev == NULL) | |
| 494 | − return -1; | |
| 495 | − prism2_rx_80211(local->apdev, skb, rx_stats, PRISM2_RX_MGMT); | |
| 496 | − return 0; | |
| 497 | − } | |
| 498 | − | |
| 499 | − if (local->iw_mode == IW_MODE_MASTER) { | |
| 500 | − if (type != IEEE80211_FTYPE_MGMT && | |
| 501 | − type != IEEE80211_FTYPE_CTL) { | |
| 502 | − printk(KERN_DEBUG "%s: unknown management frame " | |
| 503 | − "(type=0x%02x, stype=0x%02x) dropped\n", | |
| 504 | − skb->dev->name, type >> 2, stype >> 4); | |
| 505 | − return -1; | |
| 506 | − } | |
| 507 | − | |
| 508 | − hostap_rx(skb->dev, skb, rx_stats); | |
| 509 | − return 0; | |
| 510 | − } else if (type == IEEE80211_FTYPE_MGMT && | |
| 511 | − (stype == IEEE80211_STYPE_BEACON || | |
| 512 | − stype == IEEE80211_STYPE_PROBE_RESP)) { | |
| 513 | − hostap_rx_sta_beacon(local, skb, stype); | |
| 514 | − return -1; | |
| 515 | − } else if (type == IEEE80211_FTYPE_MGMT && | |
| 516 | − (stype == IEEE80211_STYPE_ASSOC_RESP || | |
| 517 | − stype == IEEE80211_STYPE_REASSOC_RESP)) { | |
| 518 | − /* Ignore (Re)AssocResp silently since these are not currently | |
| 519 | − * needed but are still received when WPA/RSN mode is enabled. | |
| 520 | − */ | |
| 521 | − return -1; | |
| 522 | − } else { | |
| 523 | − printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: dropped unhandled" | |
| 524 | − " management frame in non-Host AP mode (type=%d:%d)\n", | |
| 525 | − skb->dev->name, type >> 2, stype >> 4); | |
| 526 | − return -1; | |
| 527 | − } | |
| 528 | −} | |
| 529 | − | |
| 530 | − | |
| 531 | −/* Called only as a tasklet (software IRQ) */ | |
| 532 | −static struct net_device *prism2_rx_get_wds(local_info_t *local, | |
| 533 | − u8 *addr) | |
| 534 | −{ | |
| 535 | − struct hostap_interface *iface = NULL; | |
| 536 | − struct list_head *ptr; | |
| 537 | − | |
| 538 | − read_lock_bh(&local->iface_lock); | |
| 539 | − list_for_each(ptr, &local->hostap_interfaces) { | |
| 540 | − iface = list_entry(ptr, struct hostap_interface, list); | |
| 541 | − if (iface->type == HOSTAP_INTERFACE_WDS && | |
| 542 | − memcmp(iface->u.wds.remote_addr, addr, ETH_ALEN) == 0) | |
| 543 | − break; | |
| 544 | − iface = NULL; | |
| 545 | − } | |
| 546 | − read_unlock_bh(&local->iface_lock); | |
| 547 | − | |
| 548 | − return iface ? iface->dev : NULL; | |
| 549 | −} | |
| 550 | − | |
| 551 | − | |
| 552 | −static int | |
| 553 | −hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc, | |
| 554 | − struct net_device **wds) | |
| 555 | −{ | |
| 556 | − /* FIX: is this really supposed to accept WDS frames only in Master | |
| 557 | − * mode? What about Repeater or Managed with WDS frames? */ | |
| 558 | − if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != | |
| 559 | − (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS) && | |
| 560 | − (local->iw_mode != IW_MODE_MASTER || !(fc & IEEE80211_FCTL_TODS))) | |
| 561 | − return 0; /* not a WDS frame */ | |
| 562 | − | |
| 563 | − /* Possible WDS frame: either IEEE 802.11 compliant (if FromDS) | |
| 564 | − * or own non-standard frame with 4th address after payload */ | |
| 565 | − if (!ether_addr_equal(hdr->addr1, local->dev->dev_addr) && | |
| 566 | − (hdr->addr1[0] != 0xff || hdr->addr1[1] != 0xff || | |
| 567 | − hdr->addr1[2] != 0xff || hdr->addr1[3] != 0xff || | |
| 568 | − hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { | |
| 569 | − /* RA (or BSSID) is not ours - drop */ | |
| 570 | − PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with " | |
| 571 | − "not own or broadcast %s=%pM\n", | |
| 572 | − local->dev->name, | |
| 573 | − fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", | |
| 574 | − hdr->addr1); | |
| 575 | − return -1; | |
| 576 | − } | |
| 577 | − | |
| 578 | − /* check if the frame came from a registered WDS connection */ | |
| 579 | − *wds = prism2_rx_get_wds(local, hdr->addr2); | |
| 580 | − if (*wds == NULL && fc & IEEE80211_FCTL_FROMDS && | |
| 581 | − (local->iw_mode != IW_MODE_INFRA || | |
| 582 | − !(local->wds_type & HOSTAP_WDS_AP_CLIENT) || | |
| 583 | − memcmp(hdr->addr2, local->bssid, ETH_ALEN) != 0)) { | |
| 584 | − /* require that WDS link has been registered with TA or the | |
| 585 | − * frame is from current AP when using 'AP client mode' */ | |
| 586 | − PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " | |
| 587 | − "from unknown TA=%pM\n", | |
| 588 | − local->dev->name, hdr->addr2); | |
| 589 | − if (local->ap && local->ap->autom_ap_wds) | |
| 590 | − hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); | |
| 591 | − return -1; | |
| 592 | − } | |
| 593 | − | |
| 594 | − if (*wds && !(fc & IEEE80211_FCTL_FROMDS) && local->ap && | |
| 595 | − hostap_is_sta_assoc(local->ap, hdr->addr2)) { | |
| 596 | − /* STA is actually associated with us even though it has a | |
| 597 | − * registered WDS link. Assume it is in 'AP client' mode. | |
| 598 | − * Since this is a 3-addr frame, assume it is not (bogus) WDS | |
| 599 | − * frame and process it like any normal ToDS frame from | |
| 600 | − * associated STA. */ | |
| 601 | − *wds = NULL; | |
| 602 | − } | |
| 603 | − | |
| 604 | − return 0; | |
| 605 | −} | |
| 606 | − | |
| 607 | − | |
| 608 | −static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) | |
| 609 | −{ | |
| 610 | − struct net_device *dev = local->dev; | |
| 611 | − u16 fc, ethertype; | |
| 612 | − struct ieee80211_hdr *hdr; | |
| 613 | − u8 *pos; | |
| 614 | − | |
| 615 | − if (skb->len < 24) | |
| 616 | − return 0; | |
| 617 | − | |
| 618 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 619 | − fc = le16_to_cpu(hdr->frame_control); | |
| 620 | − | |
| 621 | − /* check that the frame is unicast frame to us */ | |
| 622 | − if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | |
| 623 | − IEEE80211_FCTL_TODS && | |
| 624 | − ether_addr_equal(hdr->addr1, dev->dev_addr) && | |
| 625 | − ether_addr_equal(hdr->addr3, dev->dev_addr)) { | |
| 626 | − /* ToDS frame with own addr BSSID and DA */ | |
| 627 | − } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | |
| 628 | − IEEE80211_FCTL_FROMDS && | |
| 629 | − ether_addr_equal(hdr->addr1, dev->dev_addr)) { | |
| 630 | − /* FromDS frame with own addr as DA */ | |
| 631 | − } else | |
| 632 | − return 0; | |
| 633 | − | |
| 634 | − if (skb->len < 24 + 8) | |
| 635 | − return 0; | |
| 636 | − | |
| 637 | − /* check for port access entity Ethernet type */ | |
| 638 | − pos = skb->data + 24; | |
| 639 | − ethertype = (pos[6] << 8) | pos[7]; | |
| 640 | − if (ethertype == ETH_P_PAE) | |
| 641 | − return 1; | |
| 642 | − | |
| 643 | − return 0; | |
| 644 | −} | |
| 645 | − | |
| 646 | − | |
| 647 | −/* Called only as a tasklet (software IRQ) */ | |
| 648 | −static int | |
| 649 | −hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, | |
| 650 | − struct lib80211_crypt_data *crypt) | |
| 651 | −{ | |
| 652 | − struct ieee80211_hdr *hdr; | |
| 653 | − int res, hdrlen; | |
| 654 | − | |
| 655 | − if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) | |
| 656 | − return 0; | |
| 657 | − | |
| 658 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 659 | − hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); | |
| 660 | − | |
| 661 | − if (local->tkip_countermeasures && | |
| 662 | − strcmp(crypt->ops->name, "TKIP") == 0) { | |
| 663 | − if (net_ratelimit()) { | |
| 664 | − printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | |
| 665 | − "received packet from %pM\n", | |
| 666 | − local->dev->name, hdr->addr2); | |
| 667 | − } | |
| 668 | − return -1; | |
| 669 | − } | |
| 670 | − | |
| 671 | − atomic_inc(&crypt->refcnt); | |
| 672 | − res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); | |
| 673 | − atomic_dec(&crypt->refcnt); | |
| 674 | − if (res < 0) { | |
| 675 | − printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n", | |
| 676 | − local->dev->name, hdr->addr2, res); | |
| 677 | − local->comm_tallies.rx_discards_wep_undecryptable++; | |
| 678 | − return -1; | |
| 679 | − } | |
| 680 | − | |
| 681 | − return res; | |
| 682 | −} | |
| 683 | − | |
| 684 | − | |
| 685 | −/* Called only as a tasklet (software IRQ) */ | |
| 686 | −static int | |
| 687 | −hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, | |
| 688 | − int keyidx, struct lib80211_crypt_data *crypt) | |
| 689 | −{ | |
| 690 | − struct ieee80211_hdr *hdr; | |
| 691 | − int res, hdrlen; | |
| 692 | − | |
| 693 | − if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) | |
| 694 | − return 0; | |
| 695 | − | |
| 696 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 697 | − hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); | |
| 698 | − | |
| 699 | − atomic_inc(&crypt->refcnt); | |
| 700 | − res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); | |
| 701 | − atomic_dec(&crypt->refcnt); | |
| 702 | − if (res < 0) { | |
| 703 | − printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" | |
| 704 | − " (SA=%pM keyidx=%d)\n", | |
| 705 | − local->dev->name, hdr->addr2, keyidx); | |
| 706 | − return -1; | |
| 707 | − } | |
| 708 | − | |
| 709 | − return 0; | |
| 710 | −} | |
| 711 | − | |
| 712 | − | |
| 713 | −/* All received frames are sent to this function. @skb contains the frame in | |
| 714 | − * IEEE 802.11 format, i.e., in the format it was sent over air. | |
| 715 | − * This function is called only as a tasklet (software IRQ). */ | |
| 716 | −void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, | |
| 717 | − struct hostap_80211_rx_status *rx_stats) | |
| 718 | −{ | |
| 719 | − struct hostap_interface *iface; | |
| 720 | − local_info_t *local; | |
| 721 | − struct ieee80211_hdr *hdr; | |
| 722 | − size_t hdrlen; | |
| 723 | − u16 fc, type, stype, sc; | |
| 724 | − struct net_device *wds = NULL; | |
| 725 | − unsigned int frag; | |
| 726 | − u8 *payload; | |
| 727 | − struct sk_buff *skb2 = NULL; | |
| 728 | − u16 ethertype; | |
| 729 | − int frame_authorized = 0; | |
| 730 | − int from_assoc_ap = 0; | |
| 731 | − u8 dst[ETH_ALEN]; | |
| 732 | − u8 src[ETH_ALEN]; | |
| 733 | − struct lib80211_crypt_data *crypt = NULL; | |
| 734 | − void *sta = NULL; | |
| 735 | − int keyidx = 0; | |
| 736 | − | |
| 737 | − iface = netdev_priv(dev); | |
| 738 | − local = iface->local; | |
| 739 | − iface->stats.rx_packets++; | |
| 740 | − iface->stats.rx_bytes += skb->len; | |
| 741 | − | |
| 742 | − /* dev is the master radio device; change this to be the default | |
| 743 | − * virtual interface (this may be changed to WDS device below) */ | |
| 744 | − dev = local->ddev; | |
| 745 | − iface = netdev_priv(dev); | |
| 746 | − | |
| 747 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 748 | − | |
| 749 | − if (skb->len < 10) | |
| 750 | − goto rx_dropped; | |
| 751 | − | |
| 752 | − fc = le16_to_cpu(hdr->frame_control); | |
| 753 | − type = fc & IEEE80211_FCTL_FTYPE; | |
| 754 | − stype = fc & IEEE80211_FCTL_STYPE; | |
| 755 | − sc = le16_to_cpu(hdr->seq_ctrl); | |
| 756 | − frag = sc & IEEE80211_SCTL_FRAG; | |
| 757 | − hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); | |
| 758 | − | |
| 759 | − /* Put this code here so that we avoid duplicating it in all | |
| 760 | − * Rx paths. - Jean II */ | |
| 761 | −#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */ | |
| 762 | − /* If spy monitoring on */ | |
| 763 | − if (iface->spy_data.spy_number > 0) { | |
| 764 | − struct iw_quality wstats; | |
| 765 | − wstats.level = rx_stats->signal; | |
| 766 | − wstats.noise = rx_stats->noise; | |
| 767 | − wstats.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_UPDATED | |
| 768 | − | IW_QUAL_QUAL_INVALID | IW_QUAL_DBM; | |
| 769 | − /* Update spy records */ | |
| 770 | − wireless_spy_update(dev, hdr->addr2, &wstats); | |
| 771 | − } | |
| 772 | −#endif /* IW_WIRELESS_SPY */ | |
| 773 | − hostap_update_rx_stats(local->ap, hdr, rx_stats); | |
| 774 | − | |
| 775 | − if (local->iw_mode == IW_MODE_MONITOR) { | |
| 776 | − monitor_rx(dev, skb, rx_stats); | |
| 777 | − return; | |
| 778 | − } | |
| 779 | − | |
| 780 | − if (local->host_decrypt) { | |
| 781 | − int idx = 0; | |
| 782 | − if (skb->len >= hdrlen + 3) | |
| 783 | − idx = skb->data[hdrlen + 3] >> 6; | |
| 784 | − crypt = local->crypt_info.crypt[idx]; | |
| 785 | − sta = NULL; | |
| 786 | − | |
| 787 | − /* Use station specific key to override default keys if the | |
| 788 | − * receiver address is a unicast address ("individual RA"). If | |
| 789 | − * bcrx_sta_key parameter is set, station specific key is used | |
| 790 | − * even with broad/multicast targets (this is against IEEE | |
| 791 | − * 802.11, but makes it easier to use different keys with | |
| 792 | − * stations that do not support WEP key mapping). */ | |
| 793 | − | |
| 794 | − if (!(hdr->addr1[0] & 0x01) || local->bcrx_sta_key) | |
| 795 | − (void) hostap_handle_sta_crypto(local, hdr, &crypt, | |
| 796 | − &sta); | |
| 797 | − | |
| 798 | − /* allow NULL decrypt to indicate an station specific override | |
| 799 | − * for default encryption */ | |
| 800 | − if (crypt && (crypt->ops == NULL || | |
| 801 | − crypt->ops->decrypt_mpdu == NULL)) | |
| 802 | − crypt = NULL; | |
| 803 | − | |
| 804 | − if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) { | |
| 805 | −#if 0 | |
| 806 | − /* This seems to be triggered by some (multicast?) | |
| 807 | − * frames from other than current BSS, so just drop the | |
| 808 | − * frames silently instead of filling system log with | |
| 809 | − * these reports. */ | |
| 810 | − printk(KERN_DEBUG "%s: WEP decryption failed (not set)" | |
| 811 | − " (SA=%pM)\n", | |
| 812 | − local->dev->name, hdr->addr2); | |
| 813 | −#endif | |
| 814 | − local->comm_tallies.rx_discards_wep_undecryptable++; | |
| 815 | − goto rx_dropped; | |
| 816 | − } | |
| 817 | − } | |
| 818 | − | |
| 819 | − if (type != IEEE80211_FTYPE_DATA) { | |
| 820 | − if (type == IEEE80211_FTYPE_MGMT && | |
| 821 | − stype == IEEE80211_STYPE_AUTH && | |
| 822 | − fc & IEEE80211_FCTL_PROTECTED && local->host_decrypt && | |
| 823 | − (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | |
| 824 | − { | |
| 825 | − printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " | |
| 826 | − "from %pM\n", dev->name, hdr->addr2); | |
| 827 | − /* TODO: could inform hostapd about this so that it | |
| 828 | − * could send auth failure report */ | |
| 829 | − goto rx_dropped; | |
| 830 | − } | |
| 831 | − | |
| 832 | − if (hostap_rx_frame_mgmt(local, skb, rx_stats, type, stype)) | |
| 833 | − goto rx_dropped; | |
| 834 | − else | |
| 835 | − goto rx_exit; | |
| 836 | − } | |
| 837 | − | |
| 838 | − /* Data frame - extract src/dst addresses */ | |
| 839 | − if (skb->len < IEEE80211_DATA_HDR3_LEN) | |
| 840 | − goto rx_dropped; | |
| 841 | − | |
| 842 | − switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { | |
| 843 | − case IEEE80211_FCTL_FROMDS: | |
| 844 | − memcpy(dst, hdr->addr1, ETH_ALEN); | |
| 845 | − memcpy(src, hdr->addr3, ETH_ALEN); | |
| 846 | − break; | |
| 847 | − case IEEE80211_FCTL_TODS: | |
| 848 | − memcpy(dst, hdr->addr3, ETH_ALEN); | |
| 849 | − memcpy(src, hdr->addr2, ETH_ALEN); | |
| 850 | − break; | |
| 851 | − case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: | |
| 852 | − if (skb->len < IEEE80211_DATA_HDR4_LEN) | |
| 853 | − goto rx_dropped; | |
| 854 | − memcpy(dst, hdr->addr3, ETH_ALEN); | |
| 855 | − memcpy(src, hdr->addr4, ETH_ALEN); | |
| 856 | − break; | |
| 857 | − default: | |
| 858 | − memcpy(dst, hdr->addr1, ETH_ALEN); | |
| 859 | − memcpy(src, hdr->addr2, ETH_ALEN); | |
| 860 | − break; | |
| 861 | − } | |
| 862 | − | |
| 863 | − if (hostap_rx_frame_wds(local, hdr, fc, &wds)) | |
| 864 | − goto rx_dropped; | |
| 865 | − if (wds) | |
| 866 | − skb->dev = dev = wds; | |
| 867 | − | |
| 868 | − if (local->iw_mode == IW_MODE_MASTER && !wds && | |
| 869 | − (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | |
| 870 | − IEEE80211_FCTL_FROMDS && | |
| 871 | − local->stadev && | |
| 872 | − memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { | |
| 873 | − /* Frame from BSSID of the AP for which we are a client */ | |
| 874 | − skb->dev = dev = local->stadev; | |
| 875 | − from_assoc_ap = 1; | |
| 876 | − } | |
| 877 | − | |
| 878 | − if ((local->iw_mode == IW_MODE_MASTER || | |
| 879 | − local->iw_mode == IW_MODE_REPEAT) && | |
| 880 | − !from_assoc_ap) { | |
| 881 | − switch (hostap_handle_sta_rx(local, dev, skb, rx_stats, | |
| 882 | − wds != NULL)) { | |
| 883 | − case AP_RX_CONTINUE_NOT_AUTHORIZED: | |
| 884 | − frame_authorized = 0; | |
| 885 | − break; | |
| 886 | − case AP_RX_CONTINUE: | |
| 887 | − frame_authorized = 1; | |
| 888 | − break; | |
| 889 | − case AP_RX_DROP: | |
| 890 | − goto rx_dropped; | |
| 891 | − case AP_RX_EXIT: | |
| 892 | − goto rx_exit; | |
| 893 | − } | |
| 894 | − } | |
| 895 | − | |
| 896 | − /* Nullfunc frames may have PS-bit set, so they must be passed to | |
| 897 | − * hostap_handle_sta_rx() before being dropped here. */ | |
| 898 | − if (stype != IEEE80211_STYPE_DATA && | |
| 899 | − stype != IEEE80211_STYPE_DATA_CFACK && | |
| 900 | − stype != IEEE80211_STYPE_DATA_CFPOLL && | |
| 901 | − stype != IEEE80211_STYPE_DATA_CFACKPOLL) { | |
| 902 | − if (stype != IEEE80211_STYPE_NULLFUNC) | |
| 903 | − printk(KERN_DEBUG "%s: RX: dropped data frame " | |
| 904 | − "with no data (type=0x%02x, subtype=0x%02x)\n", | |
| 905 | − dev->name, type >> 2, stype >> 4); | |
| 906 | − goto rx_dropped; | |
| 907 | − } | |
| 908 | − | |
| 909 | − /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ | |
| 910 | − | |
| 911 | − if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | |
| 912 | − (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) | |
| 913 | − goto rx_dropped; | |
| 914 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 915 | − | |
| 916 | − /* skb: hdr + (possibly fragmented) plaintext payload */ | |
| 917 | − | |
| 918 | − if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | |
| 919 | − (frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { | |
| 920 | − int flen; | |
| 921 | − struct sk_buff *frag_skb = | |
| 922 | − prism2_frag_cache_get(local, hdr); | |
| 923 | − if (!frag_skb) { | |
| 924 | − printk(KERN_DEBUG "%s: Rx cannot get skb from " | |
| 925 | − "fragment cache (morefrag=%d seq=%u frag=%u)\n", | |
| 926 | − dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0, | |
| 927 | − (sc & IEEE80211_SCTL_SEQ) >> 4, frag); | |
| 928 | − goto rx_dropped; | |
| 929 | − } | |
| 930 | − | |
| 931 | − flen = skb->len; | |
| 932 | − if (frag != 0) | |
| 933 | − flen -= hdrlen; | |
| 934 | − | |
| 935 | − if (frag_skb->tail + flen > frag_skb->end) { | |
| 936 | − printk(KERN_WARNING "%s: host decrypted and " | |
| 937 | − "reassembled frame did not fit skb\n", | |
| 938 | − dev->name); | |
| 939 | − prism2_frag_cache_invalidate(local, hdr); | |
| 940 | − goto rx_dropped; | |
| 941 | − } | |
| 942 | − | |
| 943 | − if (frag == 0) { | |
| 944 | − /* copy first fragment (including full headers) into | |
| 945 | − * beginning of the fragment cache skb */ | |
| 946 | − skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), | |
| 947 | − flen); | |
| 948 | − } else { | |
| 949 | − /* append frame payload to the end of the fragment | |
| 950 | − * cache skb */ | |
| 951 | − skb_copy_from_linear_data_offset(skb, hdrlen, | |
| 952 | − skb_put(frag_skb, | |
| 953 | − flen), flen); | |
| 954 | − } | |
| 955 | − dev_kfree_skb(skb); | |
| 956 | − skb = NULL; | |
| 957 | − | |
| 958 | − if (fc & IEEE80211_FCTL_MOREFRAGS) { | |
| 959 | − /* more fragments expected - leave the skb in fragment | |
| 960 | − * cache for now; it will be delivered to upper layers | |
| 961 | − * after all fragments have been received */ | |
| 962 | − goto rx_exit; | |
| 963 | − } | |
| 964 | − | |
| 965 | − /* this was the last fragment and the frame will be | |
| 966 | − * delivered, so remove skb from fragment cache */ | |
| 967 | − skb = frag_skb; | |
| 968 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 969 | − prism2_frag_cache_invalidate(local, hdr); | |
| 970 | − } | |
| 971 | − | |
| 972 | − /* skb: hdr + (possible reassembled) full MSDU payload; possibly still | |
| 973 | − * encrypted/authenticated */ | |
| 974 | − | |
| 975 | − if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) && | |
| 976 | − hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt)) | |
| 977 | − goto rx_dropped; | |
| 978 | − | |
| 979 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 980 | − if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) { | |
| 981 | − if (local->ieee_802_1x && | |
| 982 | − hostap_is_eapol_frame(local, skb)) { | |
| 983 | − /* pass unencrypted EAPOL frames even if encryption is | |
| 984 | − * configured */ | |
| 985 | − PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X - passing " | |
| 986 | − "unencrypted EAPOL frame\n", local->dev->name); | |
| 987 | − } else { | |
| 988 | − printk(KERN_DEBUG "%s: encryption configured, but RX " | |
| 989 | − "frame not encrypted (SA=%pM)\n", | |
| 990 | − local->dev->name, hdr->addr2); | |
| 991 | − goto rx_dropped; | |
| 992 | − } | |
| 993 | − } | |
| 994 | − | |
| 995 | − if (local->drop_unencrypted && !(fc & IEEE80211_FCTL_PROTECTED) && | |
| 996 | − !hostap_is_eapol_frame(local, skb)) { | |
| 997 | − if (net_ratelimit()) { | |
| 998 | − printk(KERN_DEBUG "%s: dropped unencrypted RX data " | |
| 999 | − "frame from %pM (drop_unencrypted=1)\n", | |
| 1000 | − dev->name, hdr->addr2); | |
| 1001 | − } | |
| 1002 | − goto rx_dropped; | |
| 1003 | − } | |
| 1004 | − | |
| 1005 | − /* skb: hdr + (possible reassembled) full plaintext payload */ | |
| 1006 | − | |
| 1007 | − payload = skb->data + hdrlen; | |
| 1008 | − ethertype = (payload[6] << 8) | payload[7]; | |
| 1009 | − | |
| 1010 | − /* If IEEE 802.1X is used, check whether the port is authorized to send | |
| 1011 | − * the received frame. */ | |
| 1012 | − if (local->ieee_802_1x && local->iw_mode == IW_MODE_MASTER) { | |
| 1013 | − if (ethertype == ETH_P_PAE) { | |
| 1014 | − PDEBUG(DEBUG_EXTRA2, "%s: RX: IEEE 802.1X frame\n", | |
| 1015 | − dev->name); | |
| 1016 | − if (local->hostapd && local->apdev) { | |
| 1017 | − /* Send IEEE 802.1X frames to the user | |
| 1018 | − * space daemon for processing */ | |
| 1019 | − prism2_rx_80211(local->apdev, skb, rx_stats, | |
| 1020 | − PRISM2_RX_MGMT); | |
| 1021 | − local->apdevstats.rx_packets++; | |
| 1022 | − local->apdevstats.rx_bytes += skb->len; | |
| 1023 | − goto rx_exit; | |
| 1024 | − } | |
| 1025 | − } else if (!frame_authorized) { | |
| 1026 | − printk(KERN_DEBUG "%s: dropped frame from " | |
| 1027 | − "unauthorized port (IEEE 802.1X): " | |
| 1028 | − "ethertype=0x%04x\n", | |
| 1029 | − dev->name, ethertype); | |
| 1030 | − goto rx_dropped; | |
| 1031 | − } | |
| 1032 | − } | |
| 1033 | − | |
| 1034 | − /* convert hdr + possible LLC headers into Ethernet header */ | |
| 1035 | − if (skb->len - hdrlen >= 8 && | |
| 1036 | − ((memcmp(payload, rfc1042_header, 6) == 0 && | |
| 1037 | − ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | |
| 1038 | − memcmp(payload, bridge_tunnel_header, 6) == 0)) { | |
| 1039 | − /* remove RFC1042 or Bridge-Tunnel encapsulation and | |
| 1040 | − * replace EtherType */ | |
| 1041 | − skb_pull(skb, hdrlen + 6); | |
| 1042 | − memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | |
| 1043 | − memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | |
| 1044 | − } else { | |
| 1045 | − __be16 len; | |
| 1046 | − /* Leave Ethernet header part of hdr and full payload */ | |
| 1047 | − skb_pull(skb, hdrlen); | |
| 1048 | − len = htons(skb->len); | |
| 1049 | − memcpy(skb_push(skb, 2), &len, 2); | |
| 1050 | − memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | |
| 1051 | − memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | |
| 1052 | − } | |
| 1053 | − | |
| 1054 | − if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == | |
| 1055 | − IEEE80211_FCTL_TODS) && | |
| 1056 | − skb->len >= ETH_HLEN + ETH_ALEN) { | |
| 1057 | − /* Non-standard frame: get addr4 from its bogus location after | |
| 1058 | − * the payload */ | |
| 1059 | − skb_copy_from_linear_data_offset(skb, skb->len - ETH_ALEN, | |
| 1060 | − skb->data + ETH_ALEN, | |
| 1061 | − ETH_ALEN); | |
| 1062 | − skb_trim(skb, skb->len - ETH_ALEN); | |
| 1063 | − } | |
| 1064 | − | |
| 1065 | − dev->stats.rx_packets++; | |
| 1066 | − dev->stats.rx_bytes += skb->len; | |
| 1067 | − | |
| 1068 | − if (local->iw_mode == IW_MODE_MASTER && !wds && | |
| 1069 | − local->ap->bridge_packets) { | |
| 1070 | − if (dst[0] & 0x01) { | |
| 1071 | − /* copy multicast frame both to the higher layers and | |
| 1072 | − * to the wireless media */ | |
| 1073 | − local->ap->bridged_multicast++; | |
| 1074 | − skb2 = skb_clone(skb, GFP_ATOMIC); | |
| 1075 | − if (skb2 == NULL) | |
| 1076 | − printk(KERN_DEBUG "%s: skb_clone failed for " | |
| 1077 | − "multicast frame\n", dev->name); | |
| 1078 | − } else if (hostap_is_sta_authorized(local->ap, dst)) { | |
| 1079 | − /* send frame directly to the associated STA using | |
| 1080 | − * wireless media and not passing to higher layers */ | |
| 1081 | − local->ap->bridged_unicast++; | |
| 1082 | − skb2 = skb; | |
| 1083 | − skb = NULL; | |
| 1084 | − } | |
| 1085 | − } | |
| 1086 | − | |
| 1087 | − if (skb2 != NULL) { | |
| 1088 | − /* send to wireless media */ | |
| 1089 | − skb2->dev = dev; | |
| 1090 | − skb2->protocol = cpu_to_be16(ETH_P_802_3); | |
| 1091 | − skb_reset_mac_header(skb2); | |
| 1092 | − skb_reset_network_header(skb2); | |
| 1093 | − /* skb2->network_header += ETH_HLEN; */ | |
| 1094 | − dev_queue_xmit(skb2); | |
| 1095 | − } | |
| 1096 | − | |
| 1097 | − if (skb) { | |
| 1098 | − skb->protocol = eth_type_trans(skb, dev); | |
| 1099 | − memset(skb->cb, 0, sizeof(skb->cb)); | |
| 1100 | − netif_rx(skb); | |
| 1101 | − } | |
| 1102 | − | |
| 1103 | − rx_exit: | |
| 1104 | − if (sta) | |
| 1105 | − hostap_handle_sta_release(sta); | |
| 1106 | − return; | |
| 1107 | − | |
| 1108 | − rx_dropped: | |
| 1109 | − dev_kfree_skb(skb); | |
| 1110 | − | |
| 1111 | − dev->stats.rx_dropped++; | |
| 1112 | − goto rx_exit; | |
| 1113 | −} | |
| 1114 | − | |
| 1115 | − | |
| 1116 | −EXPORT_SYMBOL(hostap_80211_rx); | |
| @@ -1,554 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −#include <linux/slab.h> | |
| 3 | −#include <linux/export.h> | |
| 4 | −#include <linux/etherdevice.h> | |
| 5 | − | |
| 6 | −#include "hostap_80211.h" | |
| 7 | −#include "hostap_common.h" | |
| 8 | −#include "hostap_wlan.h" | |
| 9 | −#include "hostap.h" | |
| 10 | −#include "hostap_ap.h" | |
| 11 | − | |
| 12 | −/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ | |
| 13 | −/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ | |
| 14 | −static unsigned char rfc1042_header[] = | |
| 15 | −{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | |
| 16 | −/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ | |
| 17 | −static unsigned char bridge_tunnel_header[] = | |
| 18 | −{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; | |
| 19 | −/* No encapsulation header if EtherType < 0x600 (=length) */ | |
| 20 | − | |
| 21 | −void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) | |
| 22 | −{ | |
| 23 | − struct ieee80211_hdr *hdr; | |
| 24 | − u16 fc; | |
| 25 | − | |
| 26 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 27 | − | |
| 28 | − printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n", | |
| 29 | − name, skb->len, jiffies); | |
| 30 | − | |
| 31 | − if (skb->len < 2) | |
| 32 | − return; | |
| 33 | − | |
| 34 | − fc = le16_to_cpu(hdr->frame_control); | |
| 35 | − printk(KERN_DEBUG " FC=0x%04x (type=%d:%d)%s%s", | |
| 36 | − fc, (fc & IEEE80211_FCTL_FTYPE) >> 2, | |
| 37 | − (fc & IEEE80211_FCTL_STYPE) >> 4, | |
| 38 | − fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", | |
| 39 | − fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); | |
| 40 | − | |
| 41 | − if (skb->len < IEEE80211_DATA_HDR3_LEN) { | |
| 42 | − printk("\n"); | |
| 43 | − return; | |
| 44 | − } | |
| 45 | − | |
| 46 | − printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), | |
| 47 | − le16_to_cpu(hdr->seq_ctrl)); | |
| 48 | − | |
| 49 | − printk(KERN_DEBUG " A1=%pM", hdr->addr1); | |
| 50 | − printk(" A2=%pM", hdr->addr2); | |
| 51 | − printk(" A3=%pM", hdr->addr3); | |
| 52 | − if (skb->len >= 30) | |
| 53 | − printk(" A4=%pM", hdr->addr4); | |
| 54 | − printk("\n"); | |
| 55 | −} | |
| 56 | − | |
| 57 | − | |
| 58 | −/* hard_start_xmit function for data interfaces (wlan#, wlan#wds#, wlan#sta) | |
| 59 | − * Convert Ethernet header into a suitable IEEE 802.11 header depending on | |
| 60 | − * device configuration. */ | |
| 61 | −netdev_tx_t hostap_data_start_xmit(struct sk_buff *skb, | |
| 62 | − struct net_device *dev) | |
| 63 | −{ | |
| 64 | − struct hostap_interface *iface; | |
| 65 | − local_info_t *local; | |
| 66 | − int need_headroom, need_tailroom = 0; | |
| 67 | − struct ieee80211_hdr hdr; | |
| 68 | − u16 fc, ethertype = 0; | |
| 69 | − enum { | |
| 70 | − WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME | |
| 71 | − } use_wds = WDS_NO; | |
| 72 | − u8 *encaps_data; | |
| 73 | − int hdr_len, encaps_len, skip_header_bytes; | |
| 74 | − int to_assoc_ap = 0; | |
| 75 | − struct hostap_skb_tx_data *meta; | |
| 76 | − | |
| 77 | − iface = netdev_priv(dev); | |
| 78 | − local = iface->local; | |
| 79 | − | |
| 80 | − if (skb->len < ETH_HLEN) { | |
| 81 | − printk(KERN_DEBUG "%s: hostap_data_start_xmit: short skb " | |
| 82 | − "(len=%d)\n", dev->name, skb->len); | |
| 83 | − kfree_skb(skb); | |
| 84 | − return NETDEV_TX_OK; | |
| 85 | − } | |
| 86 | − | |
| 87 | − if (local->ddev != dev) { | |
| 88 | − use_wds = (local->iw_mode == IW_MODE_MASTER && | |
| 89 | − !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? | |
| 90 | − WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; | |
| 91 | − if (dev == local->stadev) { | |
| 92 | − to_assoc_ap = 1; | |
| 93 | − use_wds = WDS_NO; | |
| 94 | − } else if (dev == local->apdev) { | |
| 95 | − printk(KERN_DEBUG "%s: prism2_tx: trying to use " | |
| 96 | − "AP device with Ethernet net dev\n", dev->name); | |
| 97 | − kfree_skb(skb); | |
| 98 | − return NETDEV_TX_OK; | |
| 99 | − } | |
| 100 | − } else { | |
| 101 | − if (local->iw_mode == IW_MODE_REPEAT) { | |
| 102 | − printk(KERN_DEBUG "%s: prism2_tx: trying to use " | |
| 103 | − "non-WDS link in Repeater mode\n", dev->name); | |
| 104 | − kfree_skb(skb); | |
| 105 | − return NETDEV_TX_OK; | |
| 106 | − } else if (local->iw_mode == IW_MODE_INFRA && | |
| 107 | − (local->wds_type & HOSTAP_WDS_AP_CLIENT) && | |
| 108 | − !ether_addr_equal(skb->data + ETH_ALEN, dev->dev_addr)) { | |
| 109 | − /* AP client mode: send frames with foreign src addr | |
| 110 | − * using 4-addr WDS frames */ | |
| 111 | − use_wds = WDS_COMPLIANT_FRAME; | |
| 112 | − } | |
| 113 | − } | |
| 114 | − | |
| 115 | − /* Incoming skb->data: dst_addr[6], src_addr[6], proto[2], payload | |
| 116 | − * ==> | |
| 117 | − * Prism2 TX frame with 802.11 header: | |
| 118 | − * txdesc (address order depending on used mode; includes dst_addr and | |
| 119 | − * src_addr), possible encapsulation (RFC1042/Bridge-Tunnel; | |
| 120 | − * proto[2], payload {, possible addr4[6]} */ | |
| 121 | − | |
| 122 | − ethertype = (skb->data[12] << 8) | skb->data[13]; | |
| 123 | − | |
| 124 | − memset(&hdr, 0, sizeof(hdr)); | |
| 125 | − | |
| 126 | − /* Length of data after IEEE 802.11 header */ | |
| 127 | − encaps_data = NULL; | |
| 128 | − encaps_len = 0; | |
| 129 | − skip_header_bytes = ETH_HLEN; | |
| 130 | − if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) { | |
| 131 | − encaps_data = bridge_tunnel_header; | |
| 132 | − encaps_len = sizeof(bridge_tunnel_header); | |
| 133 | − skip_header_bytes -= 2; | |
| 134 | − } else if (ethertype >= 0x600) { | |
| 135 | − encaps_data = rfc1042_header; | |
| 136 | − encaps_len = sizeof(rfc1042_header); | |
| 137 | − skip_header_bytes -= 2; | |
| 138 | − } | |
| 139 | − | |
| 140 | − fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; | |
| 141 | − hdr_len = IEEE80211_DATA_HDR3_LEN; | |
| 142 | − | |
| 143 | − if (use_wds != WDS_NO) { | |
| 144 | − /* Note! Prism2 station firmware has problems with sending real | |
| 145 | − * 802.11 frames with four addresses; until these problems can | |
| 146 | − * be fixed or worked around, 4-addr frames needed for WDS are | |
| 147 | − * using incompatible format: FromDS flag is not set and the | |
| 148 | − * fourth address is added after the frame payload; it is | |
| 149 | − * assumed, that the receiving station knows how to handle this | |
| 150 | − * frame format */ | |
| 151 | − | |
| 152 | − if (use_wds == WDS_COMPLIANT_FRAME) { | |
| 153 | − fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; | |
| 154 | − /* From&To DS: Addr1 = RA, Addr2 = TA, Addr3 = DA, | |
| 155 | − * Addr4 = SA */ | |
| 156 | − skb_copy_from_linear_data_offset(skb, ETH_ALEN, | |
| 157 | − &hdr.addr4, ETH_ALEN); | |
| 158 | − hdr_len += ETH_ALEN; | |
| 159 | − } else { | |
| 160 | − /* bogus 4-addr format to workaround Prism2 station | |
| 161 | − * f/w bug */ | |
| 162 | − fc |= IEEE80211_FCTL_TODS; | |
| 163 | − /* From DS: Addr1 = DA (used as RA), | |
| 164 | − * Addr2 = BSSID (used as TA), Addr3 = SA (used as DA), | |
| 165 | − */ | |
| 166 | − | |
| 167 | − /* SA from skb->data + ETH_ALEN will be added after | |
| 168 | − * frame payload; use hdr.addr4 as a temporary buffer | |
| 169 | − */ | |
| 170 | − skb_copy_from_linear_data_offset(skb, ETH_ALEN, | |
| 171 | − &hdr.addr4, ETH_ALEN); | |
| 172 | − need_tailroom += ETH_ALEN; | |
| 173 | − } | |
| 174 | − | |
| 175 | − /* send broadcast and multicast frames to broadcast RA, if | |
| 176 | − * configured; otherwise, use unicast RA of the WDS link */ | |
| 177 | − if ((local->wds_type & HOSTAP_WDS_BROADCAST_RA) && | |
| 178 | − is_multicast_ether_addr(skb->data)) | |
| 179 | − eth_broadcast_addr(hdr.addr1); | |
| 180 | − else if (iface->type == HOSTAP_INTERFACE_WDS) | |
| 181 | − memcpy(&hdr.addr1, iface->u.wds.remote_addr, | |
| 182 | − ETH_ALEN); | |
| 183 | − else | |
| 184 | − memcpy(&hdr.addr1, local->bssid, ETH_ALEN); | |
| 185 | − memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); | |
| 186 | − skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); | |
| 187 | − } else if (local->iw_mode == IW_MODE_MASTER && !to_assoc_ap) { | |
| 188 | − fc |= IEEE80211_FCTL_FROMDS; | |
| 189 | − /* From DS: Addr1 = DA, Addr2 = BSSID, Addr3 = SA */ | |
| 190 | − skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); | |
| 191 | − memcpy(&hdr.addr2, dev->dev_addr, ETH_ALEN); | |
| 192 | − skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr3, | |
| 193 | − ETH_ALEN); | |
| 194 | − } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { | |
| 195 | − fc |= IEEE80211_FCTL_TODS; | |
| 196 | − /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ | |
| 197 | − memcpy(&hdr.addr1, to_assoc_ap ? | |
| 198 | − local->assoc_ap_addr : local->bssid, ETH_ALEN); | |
| 199 | − skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, | |
| 200 | − ETH_ALEN); | |
| 201 | − skb_copy_from_linear_data(skb, &hdr.addr3, ETH_ALEN); | |
| 202 | − } else if (local->iw_mode == IW_MODE_ADHOC) { | |
| 203 | − /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */ | |
| 204 | − skb_copy_from_linear_data(skb, &hdr.addr1, ETH_ALEN); | |
| 205 | − skb_copy_from_linear_data_offset(skb, ETH_ALEN, &hdr.addr2, | |
| 206 | − ETH_ALEN); | |
| 207 | − memcpy(&hdr.addr3, local->bssid, ETH_ALEN); | |
| 208 | − } | |
| 209 | − | |
| 210 | − hdr.frame_control = cpu_to_le16(fc); | |
| 211 | − | |
| 212 | − skb_pull(skb, skip_header_bytes); | |
| 213 | − need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len; | |
| 214 | − if (skb_tailroom(skb) < need_tailroom) { | |
| 215 | − skb = skb_unshare(skb, GFP_ATOMIC); | |
| 216 | − if (skb == NULL) { | |
| 217 | − iface->stats.tx_dropped++; | |
| 218 | − return NETDEV_TX_OK; | |
| 219 | − } | |
| 220 | − if (pskb_expand_head(skb, need_headroom, need_tailroom, | |
| 221 | − GFP_ATOMIC)) { | |
| 222 | − kfree_skb(skb); | |
| 223 | − iface->stats.tx_dropped++; | |
| 224 | − return NETDEV_TX_OK; | |
| 225 | − } | |
| 226 | − } else if (skb_headroom(skb) < need_headroom) { | |
| 227 | − struct sk_buff *tmp = skb; | |
| 228 | − skb = skb_realloc_headroom(skb, need_headroom); | |
| 229 | − kfree_skb(tmp); | |
| 230 | − if (skb == NULL) { | |
| 231 | − iface->stats.tx_dropped++; | |
| 232 | − return NETDEV_TX_OK; | |
| 233 | − } | |
| 234 | − } else { | |
| 235 | − skb = skb_unshare(skb, GFP_ATOMIC); | |
| 236 | − if (skb == NULL) { | |
| 237 | − iface->stats.tx_dropped++; | |
| 238 | − return NETDEV_TX_OK; | |
| 239 | − } | |
| 240 | − } | |
| 241 | − | |
| 242 | − if (encaps_data) | |
| 243 | − memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len); | |
| 244 | − memcpy(skb_push(skb, hdr_len), &hdr, hdr_len); | |
| 245 | − if (use_wds == WDS_OWN_FRAME) { | |
| 246 | − skb_put_data(skb, &hdr.addr4, ETH_ALEN); | |
| 247 | − } | |
| 248 | − | |
| 249 | − iface->stats.tx_packets++; | |
| 250 | − iface->stats.tx_bytes += skb->len; | |
| 251 | − | |
| 252 | − skb_reset_mac_header(skb); | |
| 253 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 254 | − memset(meta, 0, sizeof(*meta)); | |
| 255 | − meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | |
| 256 | − if (use_wds) | |
| 257 | − meta->flags |= HOSTAP_TX_FLAGS_WDS; | |
| 258 | − meta->ethertype = ethertype; | |
| 259 | − meta->iface = iface; | |
| 260 | − | |
| 261 | − /* Send IEEE 802.11 encapsulated frame using the master radio device */ | |
| 262 | − skb->dev = local->dev; | |
| 263 | − dev_queue_xmit(skb); | |
| 264 | − return NETDEV_TX_OK; | |
| 265 | −} | |
| 266 | − | |
| 267 | − | |
| 268 | −/* hard_start_xmit function for hostapd wlan#ap interfaces */ | |
| 269 | −netdev_tx_t hostap_mgmt_start_xmit(struct sk_buff *skb, | |
| 270 | − struct net_device *dev) | |
| 271 | −{ | |
| 272 | − struct hostap_interface *iface; | |
| 273 | − local_info_t *local; | |
| 274 | − struct hostap_skb_tx_data *meta; | |
| 275 | − struct ieee80211_hdr *hdr; | |
| 276 | − u16 fc; | |
| 277 | − | |
| 278 | − iface = netdev_priv(dev); | |
| 279 | − local = iface->local; | |
| 280 | − | |
| 281 | − if (skb->len < 10) { | |
| 282 | − printk(KERN_DEBUG "%s: hostap_mgmt_start_xmit: short skb " | |
| 283 | − "(len=%d)\n", dev->name, skb->len); | |
| 284 | − kfree_skb(skb); | |
| 285 | − return NETDEV_TX_OK; | |
| 286 | − } | |
| 287 | − | |
| 288 | − iface->stats.tx_packets++; | |
| 289 | − iface->stats.tx_bytes += skb->len; | |
| 290 | − | |
| 291 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 292 | − memset(meta, 0, sizeof(*meta)); | |
| 293 | − meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | |
| 294 | − meta->iface = iface; | |
| 295 | − | |
| 296 | − if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) { | |
| 297 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 298 | − fc = le16_to_cpu(hdr->frame_control); | |
| 299 | − if (ieee80211_is_data(hdr->frame_control) && | |
| 300 | − (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) { | |
| 301 | − u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN + | |
| 302 | − sizeof(rfc1042_header)]; | |
| 303 | − meta->ethertype = (pos[0] << 8) | pos[1]; | |
| 304 | − } | |
| 305 | − } | |
| 306 | − | |
| 307 | − /* Send IEEE 802.11 encapsulated frame using the master radio device */ | |
| 308 | − skb->dev = local->dev; | |
| 309 | − dev_queue_xmit(skb); | |
| 310 | − return NETDEV_TX_OK; | |
| 311 | −} | |
| 312 | − | |
| 313 | − | |
| 314 | −/* Called only from software IRQ */ | |
| 315 | −static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, | |
| 316 | − struct lib80211_crypt_data *crypt) | |
| 317 | −{ | |
| 318 | − struct hostap_interface *iface; | |
| 319 | − local_info_t *local; | |
| 320 | − struct ieee80211_hdr *hdr; | |
| 321 | − int prefix_len, postfix_len, hdr_len, res; | |
| 322 | − | |
| 323 | − iface = netdev_priv(skb->dev); | |
| 324 | − local = iface->local; | |
| 325 | − | |
| 326 | − if (skb->len < IEEE80211_DATA_HDR3_LEN) { | |
| 327 | − kfree_skb(skb); | |
| 328 | − return NULL; | |
| 329 | − } | |
| 330 | − | |
| 331 | − if (local->tkip_countermeasures && | |
| 332 | − strcmp(crypt->ops->name, "TKIP") == 0) { | |
| 333 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 334 | − if (net_ratelimit()) { | |
| 335 | − printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " | |
| 336 | − "TX packet to %pM\n", | |
| 337 | − local->dev->name, hdr->addr1); | |
| 338 | − } | |
| 339 | − kfree_skb(skb); | |
| 340 | − return NULL; | |
| 341 | − } | |
| 342 | − | |
| 343 | − skb = skb_unshare(skb, GFP_ATOMIC); | |
| 344 | − if (skb == NULL) | |
| 345 | − return NULL; | |
| 346 | − | |
| 347 | − prefix_len = crypt->ops->extra_mpdu_prefix_len + | |
| 348 | − crypt->ops->extra_msdu_prefix_len; | |
| 349 | − postfix_len = crypt->ops->extra_mpdu_postfix_len + | |
| 350 | − crypt->ops->extra_msdu_postfix_len; | |
| 351 | − if ((skb_headroom(skb) < prefix_len || | |
| 352 | − skb_tailroom(skb) < postfix_len) && | |
| 353 | − pskb_expand_head(skb, prefix_len, postfix_len, GFP_ATOMIC)) { | |
| 354 | − kfree_skb(skb); | |
| 355 | − return NULL; | |
| 356 | − } | |
| 357 | − | |
| 358 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 359 | − hdr_len = hostap_80211_get_hdrlen(hdr->frame_control); | |
| 360 | − | |
| 361 | − /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so | |
| 362 | − * call both MSDU and MPDU encryption functions from here. */ | |
| 363 | − atomic_inc(&crypt->refcnt); | |
| 364 | − res = 0; | |
| 365 | − if (crypt->ops->encrypt_msdu) | |
| 366 | − res = crypt->ops->encrypt_msdu(skb, hdr_len, crypt->priv); | |
| 367 | − if (res == 0 && crypt->ops->encrypt_mpdu) | |
| 368 | − res = crypt->ops->encrypt_mpdu(skb, hdr_len, crypt->priv); | |
| 369 | − atomic_dec(&crypt->refcnt); | |
| 370 | − if (res < 0) { | |
| 371 | − kfree_skb(skb); | |
| 372 | − return NULL; | |
| 373 | − } | |
| 374 | − | |
| 375 | − return skb; | |
| 376 | −} | |
| 377 | − | |
| 378 | − | |
| 379 | −/* hard_start_xmit function for master radio interface wifi#. | |
| 380 | − * AP processing (TX rate control, power save buffering, etc.). | |
| 381 | − * Use hardware TX function to send the frame. */ | |
| 382 | −netdev_tx_t hostap_master_start_xmit(struct sk_buff *skb, | |
| 383 | − struct net_device *dev) | |
| 384 | −{ | |
| 385 | − struct hostap_interface *iface; | |
| 386 | − local_info_t *local; | |
| 387 | − netdev_tx_t ret = NETDEV_TX_BUSY; | |
| 388 | − u16 fc; | |
| 389 | − struct hostap_tx_data tx; | |
| 390 | − ap_tx_ret tx_ret; | |
| 391 | − struct hostap_skb_tx_data *meta; | |
| 392 | − int no_encrypt = 0; | |
| 393 | − struct ieee80211_hdr *hdr; | |
| 394 | − | |
| 395 | − iface = netdev_priv(dev); | |
| 396 | − local = iface->local; | |
| 397 | − | |
| 398 | − tx.skb = skb; | |
| 399 | − tx.sta_ptr = NULL; | |
| 400 | − | |
| 401 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 402 | − if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | |
| 403 | − printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | |
| 404 | − "expected 0x%08x)\n", | |
| 405 | − dev->name, meta->magic, HOSTAP_SKB_TX_DATA_MAGIC); | |
| 406 | − ret = NETDEV_TX_OK; | |
| 407 | − iface->stats.tx_dropped++; | |
| 408 | − goto fail; | |
| 409 | − } | |
| 410 | − | |
| 411 | − if (local->host_encrypt) { | |
| 412 | − /* Set crypt to default algorithm and key; will be replaced in | |
| 413 | − * AP code if STA has own alg/key */ | |
| 414 | − tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx]; | |
| 415 | − tx.host_encrypt = 1; | |
| 416 | − } else { | |
| 417 | − tx.crypt = NULL; | |
| 418 | − tx.host_encrypt = 0; | |
| 419 | − } | |
| 420 | − | |
| 421 | − if (skb->len < 24) { | |
| 422 | − printk(KERN_DEBUG "%s: hostap_master_start_xmit: short skb " | |
| 423 | − "(len=%d)\n", dev->name, skb->len); | |
| 424 | − ret = NETDEV_TX_OK; | |
| 425 | − iface->stats.tx_dropped++; | |
| 426 | − goto fail; | |
| 427 | − } | |
| 428 | − | |
| 429 | − /* FIX (?): | |
| 430 | − * Wi-Fi 802.11b test plan suggests that AP should ignore power save | |
| 431 | − * bit in authentication and (re)association frames and assume tha | |
| 432 | − * STA remains awake for the response. */ | |
| 433 | − tx_ret = hostap_handle_sta_tx(local, &tx); | |
| 434 | − skb = tx.skb; | |
| 435 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 436 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 437 | − fc = le16_to_cpu(hdr->frame_control); | |
| 438 | − switch (tx_ret) { | |
| 439 | − case AP_TX_CONTINUE: | |
| 440 | − break; | |
| 441 | − case AP_TX_CONTINUE_NOT_AUTHORIZED: | |
| 442 | − if (local->ieee_802_1x && | |
| 443 | − ieee80211_is_data(hdr->frame_control) && | |
| 444 | − meta->ethertype != ETH_P_PAE && | |
| 445 | − !(meta->flags & HOSTAP_TX_FLAGS_WDS)) { | |
| 446 | − printk(KERN_DEBUG "%s: dropped frame to unauthorized " | |
| 447 | − "port (IEEE 802.1X): ethertype=0x%04x\n", | |
| 448 | − dev->name, meta->ethertype); | |
| 449 | − hostap_dump_tx_80211(dev->name, skb); | |
| 450 | − | |
| 451 | − ret = NETDEV_TX_OK; /* drop packet */ | |
| 452 | − iface->stats.tx_dropped++; | |
| 453 | − goto fail; | |
| 454 | − } | |
| 455 | − break; | |
| 456 | − case AP_TX_DROP: | |
| 457 | − ret = NETDEV_TX_OK; /* drop packet */ | |
| 458 | − iface->stats.tx_dropped++; | |
| 459 | − goto fail; | |
| 460 | − case AP_TX_RETRY: | |
| 461 | − goto fail; | |
| 462 | − case AP_TX_BUFFERED: | |
| 463 | − /* do not free skb here, it will be freed when the | |
| 464 | − * buffered frame is sent/timed out */ | |
| 465 | − ret = NETDEV_TX_OK; | |
| 466 | − goto tx_exit; | |
| 467 | − } | |
| 468 | − | |
| 469 | − /* Request TX callback if protocol version is 2 in 802.11 header; | |
| 470 | − * this version 2 is a special case used between hostapd and kernel | |
| 471 | − * driver */ | |
| 472 | − if (((fc & IEEE80211_FCTL_VERS) == BIT(1)) && | |
| 473 | − local->ap && local->ap->tx_callback_idx && meta->tx_cb_idx == 0) { | |
| 474 | − meta->tx_cb_idx = local->ap->tx_callback_idx; | |
| 475 | − | |
| 476 | − /* remove special version from the frame header */ | |
| 477 | − fc &= ~IEEE80211_FCTL_VERS; | |
| 478 | − hdr->frame_control = cpu_to_le16(fc); | |
| 479 | − } | |
| 480 | − | |
| 481 | − if (!ieee80211_is_data(hdr->frame_control)) { | |
| 482 | − no_encrypt = 1; | |
| 483 | − tx.crypt = NULL; | |
| 484 | − } | |
| 485 | − | |
| 486 | − if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && | |
| 487 | − !(fc & IEEE80211_FCTL_PROTECTED)) { | |
| 488 | − no_encrypt = 1; | |
| 489 | − PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " | |
| 490 | − "unencrypted EAPOL frame\n", dev->name); | |
| 491 | − tx.crypt = NULL; /* no encryption for IEEE 802.1X frames */ | |
| 492 | − } | |
| 493 | − | |
| 494 | − if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) | |
| 495 | − tx.crypt = NULL; | |
| 496 | − else if ((tx.crypt || | |
| 497 | − local->crypt_info.crypt[local->crypt_info.tx_keyidx]) && | |
| 498 | − !no_encrypt) { | |
| 499 | − /* Add ISWEP flag both for firmware and host based encryption | |
| 500 | − */ | |
| 501 | − fc |= IEEE80211_FCTL_PROTECTED; | |
| 502 | − hdr->frame_control = cpu_to_le16(fc); | |
| 503 | − } else if (local->drop_unencrypted && | |
| 504 | − ieee80211_is_data(hdr->frame_control) && | |
| 505 | − meta->ethertype != ETH_P_PAE) { | |
| 506 | − if (net_ratelimit()) { | |
| 507 | − printk(KERN_DEBUG "%s: dropped unencrypted TX data " | |
| 508 | − "frame (drop_unencrypted=1)\n", dev->name); | |
| 509 | − } | |
| 510 | − iface->stats.tx_dropped++; | |
| 511 | − ret = NETDEV_TX_OK; | |
| 512 | − goto fail; | |
| 513 | − } | |
| 514 | − | |
| 515 | − if (tx.crypt) { | |
| 516 | − skb = hostap_tx_encrypt(skb, tx.crypt); | |
| 517 | − if (skb == NULL) { | |
| 518 | − printk(KERN_DEBUG "%s: TX - encryption failed\n", | |
| 519 | − dev->name); | |
| 520 | − ret = NETDEV_TX_OK; | |
| 521 | − goto fail; | |
| 522 | − } | |
| 523 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 524 | − if (meta->magic != HOSTAP_SKB_TX_DATA_MAGIC) { | |
| 525 | − printk(KERN_DEBUG "%s: invalid skb->cb magic (0x%08x, " | |
| 526 | − "expected 0x%08x) after hostap_tx_encrypt\n", | |
| 527 | − dev->name, meta->magic, | |
| 528 | − HOSTAP_SKB_TX_DATA_MAGIC); | |
| 529 | − ret = NETDEV_TX_OK; | |
| 530 | − iface->stats.tx_dropped++; | |
| 531 | − goto fail; | |
| 532 | − } | |
| 533 | − } | |
| 534 | − | |
| 535 | − if (local->func->tx == NULL || local->func->tx(skb, dev)) { | |
| 536 | − ret = NETDEV_TX_OK; | |
| 537 | − iface->stats.tx_dropped++; | |
| 538 | − } else { | |
| 539 | − ret = NETDEV_TX_OK; | |
| 540 | − iface->stats.tx_packets++; | |
| 541 | − iface->stats.tx_bytes += skb->len; | |
| 542 | − } | |
| 543 | − | |
| 544 | − fail: | |
| 545 | − if (ret == NETDEV_TX_OK && skb) | |
| 546 | − dev_kfree_skb(skb); | |
| 547 | − tx_exit: | |
| 548 | − if (tx.sta_ptr) | |
| 549 | − hostap_handle_sta_release(tx.sta_ptr); | |
| 550 | − return ret; | |
| 551 | −} | |
| 552 | − | |
| 553 | − | |
| 554 | −EXPORT_SYMBOL(hostap_master_start_xmit); | |
| @@ -1,3277 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −/* | |
| 3 | − * Intersil Prism2 driver with Host AP (software access point) support | |
| 4 | − * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | |
| 5 | − * <j@w1.fi> | |
| 6 | − * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> | |
| 7 | − * | |
| 8 | − * This file is to be included into hostap.c when S/W AP functionality is | |
| 9 | − * compiled. | |
| 10 | − * | |
| 11 | − * AP: FIX: | |
| 12 | − * - if unicast Class 2 (assoc,reassoc,disassoc) frame received from | |
| 13 | − * unauthenticated STA, send deauth. frame (8802.11: 5.5) | |
| 14 | − * - if unicast Class 3 (data with to/from DS,deauth,pspoll) frame received | |
| 15 | − * from authenticated, but unassoc STA, send disassoc frame (8802.11: 5.5) | |
| 16 | − * - if unicast Class 3 received from unauthenticated STA, send deauth. frame | |
| 17 | − * (8802.11: 5.5) | |
| 18 | − */ | |
| 19 | − | |
| 20 | −#include <linux/proc_fs.h> | |
| 21 | −#include <linux/seq_file.h> | |
| 22 | −#include <linux/delay.h> | |
| 23 | −#include <linux/random.h> | |
| 24 | −#include <linux/if_arp.h> | |
| 25 | −#include <linux/slab.h> | |
| 26 | −#include <linux/export.h> | |
| 27 | −#include <linux/moduleparam.h> | |
| 28 | −#include <linux/etherdevice.h> | |
| 29 | − | |
| 30 | −#include "hostap_wlan.h" | |
| 31 | −#include "hostap.h" | |
| 32 | −#include "hostap_ap.h" | |
| 33 | − | |
| 34 | −static int other_ap_policy[MAX_PARM_DEVICES] = { AP_OTHER_AP_SKIP_ALL, | |
| 35 | − DEF_INTS }; | |
| 36 | −module_param_array(other_ap_policy, int, NULL, 0444); | |
| 37 | −MODULE_PARM_DESC(other_ap_policy, "Other AP beacon monitoring policy (0-3)"); | |
| 38 | − | |
| 39 | −static int ap_max_inactivity[MAX_PARM_DEVICES] = { AP_MAX_INACTIVITY_SEC, | |
| 40 | − DEF_INTS }; | |
| 41 | −module_param_array(ap_max_inactivity, int, NULL, 0444); | |
| 42 | −MODULE_PARM_DESC(ap_max_inactivity, "AP timeout (in seconds) for station " | |
| 43 | − "inactivity"); | |
| 44 | − | |
| 45 | −static int ap_bridge_packets[MAX_PARM_DEVICES] = { 1, DEF_INTS }; | |
| 46 | −module_param_array(ap_bridge_packets, int, NULL, 0444); | |
| 47 | −MODULE_PARM_DESC(ap_bridge_packets, "Bridge packets directly between " | |
| 48 | − "stations"); | |
| 49 | − | |
| 50 | −static int autom_ap_wds[MAX_PARM_DEVICES] = { 0, DEF_INTS }; | |
| 51 | −module_param_array(autom_ap_wds, int, NULL, 0444); | |
| 52 | −MODULE_PARM_DESC(autom_ap_wds, "Add WDS connections to other APs " | |
| 53 | − "automatically"); | |
| 54 | − | |
| 55 | − | |
| 56 | −static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta); | |
| 57 | −static void hostap_event_expired_sta(struct net_device *dev, | |
| 58 | − struct sta_info *sta); | |
| 59 | −static void handle_add_proc_queue(struct work_struct *work); | |
| 60 | − | |
| 61 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 62 | −static void handle_wds_oper_queue(struct work_struct *work); | |
| 63 | −static void prism2_send_mgmt(struct net_device *dev, | |
| 64 | − u16 type_subtype, char *body, | |
| 65 | − int body_len, u8 *addr, u16 tx_cb_idx); | |
| 66 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 67 | − | |
| 68 | − | |
| 69 | −#if !defined(PRISM2_NO_PROCFS_DEBUG) && defined(CONFIG_PROC_FS) | |
| 70 | −static int ap_debug_proc_show(struct seq_file *m, void *v) | |
| 71 | −{ | |
| 72 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 73 | − | |
| 74 | − seq_printf(m, "BridgedUnicastFrames=%u\n", ap->bridged_unicast); | |
| 75 | − seq_printf(m, "BridgedMulticastFrames=%u\n", ap->bridged_multicast); | |
| 76 | − seq_printf(m, "max_inactivity=%u\n", ap->max_inactivity / HZ); | |
| 77 | − seq_printf(m, "bridge_packets=%u\n", ap->bridge_packets); | |
| 78 | − seq_printf(m, "nullfunc_ack=%u\n", ap->nullfunc_ack); | |
| 79 | − seq_printf(m, "autom_ap_wds=%u\n", ap->autom_ap_wds); | |
| 80 | − seq_printf(m, "auth_algs=%u\n", ap->local->auth_algs); | |
| 81 | − seq_printf(m, "tx_drop_nonassoc=%u\n", ap->tx_drop_nonassoc); | |
| 82 | − return 0; | |
| 83 | −} | |
| 84 | −#endif | |
| 85 | − | |
| 86 | −static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) | |
| 87 | −{ | |
| 88 | − sta->hnext = ap->sta_hash[STA_HASH(sta->addr)]; | |
| 89 | − ap->sta_hash[STA_HASH(sta->addr)] = sta; | |
| 90 | −} | |
| 91 | − | |
| 92 | −static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) | |
| 93 | −{ | |
| 94 | − struct sta_info *s; | |
| 95 | − | |
| 96 | − s = ap->sta_hash[STA_HASH(sta->addr)]; | |
| 97 | − if (s == NULL) return; | |
| 98 | − if (ether_addr_equal(s->addr, sta->addr)) { | |
| 99 | − ap->sta_hash[STA_HASH(sta->addr)] = s->hnext; | |
| 100 | − return; | |
| 101 | − } | |
| 102 | − | |
| 103 | − while (s->hnext != NULL && !ether_addr_equal(s->hnext->addr, sta->addr)) | |
| 104 | − s = s->hnext; | |
| 105 | − if (s->hnext != NULL) | |
| 106 | − s->hnext = s->hnext->hnext; | |
| 107 | − else | |
| 108 | − printk("AP: could not remove STA %pM from hash table\n", | |
| 109 | − sta->addr); | |
| 110 | −} | |
| 111 | − | |
| 112 | −static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) | |
| 113 | −{ | |
| 114 | − if (sta->ap && sta->local) | |
| 115 | − hostap_event_expired_sta(sta->local->dev, sta); | |
| 116 | − | |
| 117 | − if (ap->proc != NULL) { | |
| 118 | − char name[20]; | |
| 119 | − sprintf(name, "%pM", sta->addr); | |
| 120 | − remove_proc_entry(name, ap->proc); | |
| 121 | − } | |
| 122 | − | |
| 123 | − if (sta->crypt) { | |
| 124 | − sta->crypt->ops->deinit(sta->crypt->priv); | |
| 125 | − kfree(sta->crypt); | |
| 126 | − sta->crypt = NULL; | |
| 127 | − } | |
| 128 | − | |
| 129 | − skb_queue_purge(&sta->tx_buf); | |
| 130 | − | |
| 131 | − ap->num_sta--; | |
| 132 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 133 | − if (sta->aid > 0) | |
| 134 | − ap->sta_aid[sta->aid - 1] = NULL; | |
| 135 | − | |
| 136 | − if (!sta->ap) | |
| 137 | − kfree(sta->u.sta.challenge); | |
| 138 | − timer_shutdown_sync(&sta->timer); | |
| 139 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 140 | − | |
| 141 | − kfree(sta); | |
| 142 | −} | |
| 143 | − | |
| 144 | − | |
| 145 | −static void hostap_set_tim(local_info_t *local, int aid, int set) | |
| 146 | −{ | |
| 147 | − if (local->func->set_tim) | |
| 148 | − local->func->set_tim(local->dev, aid, set); | |
| 149 | −} | |
| 150 | − | |
| 151 | − | |
| 152 | −static void hostap_event_new_sta(struct net_device *dev, struct sta_info *sta) | |
| 153 | −{ | |
| 154 | − union iwreq_data wrqu; | |
| 155 | − memset(&wrqu, 0, sizeof(wrqu)); | |
| 156 | − memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); | |
| 157 | − wrqu.addr.sa_family = ARPHRD_ETHER; | |
| 158 | − wireless_send_event(dev, IWEVREGISTERED, &wrqu, NULL); | |
| 159 | −} | |
| 160 | − | |
| 161 | − | |
| 162 | −static void hostap_event_expired_sta(struct net_device *dev, | |
| 163 | − struct sta_info *sta) | |
| 164 | −{ | |
| 165 | − union iwreq_data wrqu; | |
| 166 | − memset(&wrqu, 0, sizeof(wrqu)); | |
| 167 | − memcpy(wrqu.addr.sa_data, sta->addr, ETH_ALEN); | |
| 168 | − wrqu.addr.sa_family = ARPHRD_ETHER; | |
| 169 | − wireless_send_event(dev, IWEVEXPIRED, &wrqu, NULL); | |
| 170 | −} | |
| 171 | − | |
| 172 | − | |
| 173 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 174 | − | |
| 175 | −static void ap_handle_timer(struct timer_list *t) | |
| 176 | −{ | |
| 177 | − struct sta_info *sta = from_timer(sta, t, timer); | |
| 178 | − local_info_t *local; | |
| 179 | − struct ap_data *ap; | |
| 180 | − unsigned long next_time = 0; | |
| 181 | − int was_assoc; | |
| 182 | − | |
| 183 | − if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { | |
| 184 | − PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); | |
| 185 | − return; | |
| 186 | − } | |
| 187 | − | |
| 188 | − local = sta->local; | |
| 189 | − ap = local->ap; | |
| 190 | − was_assoc = sta->flags & WLAN_STA_ASSOC; | |
| 191 | − | |
| 192 | − if (atomic_read(&sta->users) != 0) | |
| 193 | − next_time = jiffies + HZ; | |
| 194 | − else if ((sta->flags & WLAN_STA_PERM) && !(sta->flags & WLAN_STA_AUTH)) | |
| 195 | − next_time = jiffies + ap->max_inactivity; | |
| 196 | − | |
| 197 | − if (time_before(jiffies, sta->last_rx + ap->max_inactivity)) { | |
| 198 | − /* station activity detected; reset timeout state */ | |
| 199 | − sta->timeout_next = STA_NULLFUNC; | |
| 200 | − next_time = sta->last_rx + ap->max_inactivity; | |
| 201 | − } else if (sta->timeout_next == STA_DISASSOC && | |
| 202 | − !(sta->flags & WLAN_STA_PENDING_POLL)) { | |
| 203 | − /* STA ACKed data nullfunc frame poll */ | |
| 204 | − sta->timeout_next = STA_NULLFUNC; | |
| 205 | − next_time = jiffies + ap->max_inactivity; | |
| 206 | − } | |
| 207 | − | |
| 208 | − if (next_time) { | |
| 209 | − sta->timer.expires = next_time; | |
| 210 | − add_timer(&sta->timer); | |
| 211 | − return; | |
| 212 | − } | |
| 213 | − | |
| 214 | − if (sta->ap) | |
| 215 | − sta->timeout_next = STA_DEAUTH; | |
| 216 | − | |
| 217 | − if (sta->timeout_next == STA_DEAUTH && !(sta->flags & WLAN_STA_PERM)) { | |
| 218 | − spin_lock(&ap->sta_table_lock); | |
| 219 | − ap_sta_hash_del(ap, sta); | |
| 220 | − list_del(&sta->list); | |
| 221 | − spin_unlock(&ap->sta_table_lock); | |
| 222 | − sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); | |
| 223 | − } else if (sta->timeout_next == STA_DISASSOC) | |
| 224 | − sta->flags &= ~WLAN_STA_ASSOC; | |
| 225 | − | |
| 226 | − if (was_assoc && !(sta->flags & WLAN_STA_ASSOC) && !sta->ap) | |
| 227 | − hostap_event_expired_sta(local->dev, sta); | |
| 228 | − | |
| 229 | − if (sta->timeout_next == STA_DEAUTH && sta->aid > 0 && | |
| 230 | − !skb_queue_empty(&sta->tx_buf)) { | |
| 231 | − hostap_set_tim(local, sta->aid, 0); | |
| 232 | − sta->flags &= ~WLAN_STA_TIM; | |
| 233 | − } | |
| 234 | − | |
| 235 | − if (sta->ap) { | |
| 236 | − if (ap->autom_ap_wds) { | |
| 237 | − PDEBUG(DEBUG_AP, "%s: removing automatic WDS " | |
| 238 | − "connection to AP %pM\n", | |
| 239 | − local->dev->name, sta->addr); | |
| 240 | − hostap_wds_link_oper(local, sta->addr, WDS_DEL); | |
| 241 | − } | |
| 242 | − } else if (sta->timeout_next == STA_NULLFUNC) { | |
| 243 | − /* send data frame to poll STA and check whether this frame | |
| 244 | − * is ACKed */ | |
| 245 | − /* FIX: IEEE80211_STYPE_NULLFUNC would be more appropriate, but | |
| 246 | − * it is apparently not retried so TX Exc events are not | |
| 247 | − * received for it */ | |
| 248 | − sta->flags |= WLAN_STA_PENDING_POLL; | |
| 249 | − prism2_send_mgmt(local->dev, IEEE80211_FTYPE_DATA | | |
| 250 | − IEEE80211_STYPE_DATA, NULL, 0, | |
| 251 | − sta->addr, ap->tx_callback_poll); | |
| 252 | − } else { | |
| 253 | − int deauth = sta->timeout_next == STA_DEAUTH; | |
| 254 | − __le16 resp; | |
| 255 | − PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" | |
| 256 | − "(last=%lu, jiffies=%lu)\n", | |
| 257 | − local->dev->name, | |
| 258 | − deauth ? "deauthentication" : "disassociation", | |
| 259 | − sta->addr, sta->last_rx, jiffies); | |
| 260 | − | |
| 261 | − resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : | |
| 262 | − WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); | |
| 263 | − prism2_send_mgmt(local->dev, IEEE80211_FTYPE_MGMT | | |
| 264 | − (deauth ? IEEE80211_STYPE_DEAUTH : | |
| 265 | − IEEE80211_STYPE_DISASSOC), | |
| 266 | − (char *) &resp, 2, sta->addr, 0); | |
| 267 | − } | |
| 268 | − | |
| 269 | − if (sta->timeout_next == STA_DEAUTH) { | |
| 270 | − if (sta->flags & WLAN_STA_PERM) { | |
| 271 | − PDEBUG(DEBUG_AP, "%s: STA %pM" | |
| 272 | − " would have been removed, " | |
| 273 | − "but it has 'perm' flag\n", | |
| 274 | − local->dev->name, sta->addr); | |
| 275 | − } else | |
| 276 | − ap_free_sta(ap, sta); | |
| 277 | − return; | |
| 278 | − } | |
| 279 | − | |
| 280 | − if (sta->timeout_next == STA_NULLFUNC) { | |
| 281 | − sta->timeout_next = STA_DISASSOC; | |
| 282 | − sta->timer.expires = jiffies + AP_DISASSOC_DELAY; | |
| 283 | − } else { | |
| 284 | − sta->timeout_next = STA_DEAUTH; | |
| 285 | − sta->timer.expires = jiffies + AP_DEAUTH_DELAY; | |
| 286 | − } | |
| 287 | − | |
| 288 | − add_timer(&sta->timer); | |
| 289 | −} | |
| 290 | − | |
| 291 | − | |
| 292 | −void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, | |
| 293 | − int resend) | |
| 294 | −{ | |
| 295 | − u8 addr[ETH_ALEN]; | |
| 296 | − __le16 resp; | |
| 297 | − int i; | |
| 298 | − | |
| 299 | − PDEBUG(DEBUG_AP, "%s: Deauthenticate all stations\n", dev->name); | |
| 300 | − eth_broadcast_addr(addr); | |
| 301 | − | |
| 302 | − resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); | |
| 303 | − | |
| 304 | − /* deauth message sent; try to resend it few times; the message is | |
| 305 | − * broadcast, so it may be delayed until next DTIM; there is not much | |
| 306 | − * else we can do at this point since the driver is going to be shut | |
| 307 | − * down */ | |
| 308 | − for (i = 0; i < 5; i++) { | |
| 309 | − prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | |
| 310 | − IEEE80211_STYPE_DEAUTH, | |
| 311 | − (char *) &resp, 2, addr, 0); | |
| 312 | − | |
| 313 | − if (!resend || ap->num_sta <= 0) | |
| 314 | − return; | |
| 315 | − | |
| 316 | − mdelay(50); | |
| 317 | − } | |
| 318 | −} | |
| 319 | − | |
| 320 | − | |
| 321 | −static int ap_control_proc_show(struct seq_file *m, void *v) | |
| 322 | −{ | |
| 323 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 324 | − char *policy_txt; | |
| 325 | − struct mac_entry *entry; | |
| 326 | − | |
| 327 | − if (v == SEQ_START_TOKEN) { | |
| 328 | − switch (ap->mac_restrictions.policy) { | |
| 329 | − case MAC_POLICY_OPEN: | |
| 330 | − policy_txt = "open"; | |
| 331 | − break; | |
| 332 | − case MAC_POLICY_ALLOW: | |
| 333 | − policy_txt = "allow"; | |
| 334 | − break; | |
| 335 | − case MAC_POLICY_DENY: | |
| 336 | − policy_txt = "deny"; | |
| 337 | − break; | |
| 338 | − default: | |
| 339 | − policy_txt = "unknown"; | |
| 340 | − break; | |
| 341 | − } | |
| 342 | − seq_printf(m, "MAC policy: %s\n", policy_txt); | |
| 343 | − seq_printf(m, "MAC entries: %u\n", ap->mac_restrictions.entries); | |
| 344 | − seq_puts(m, "MAC list:\n"); | |
| 345 | − return 0; | |
| 346 | − } | |
| 347 | − | |
| 348 | − entry = v; | |
| 349 | − seq_printf(m, "%pM\n", entry->addr); | |
| 350 | − return 0; | |
| 351 | −} | |
| 352 | − | |
| 353 | −static void *ap_control_proc_start(struct seq_file *m, loff_t *_pos) | |
| 354 | −{ | |
| 355 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 356 | − spin_lock_bh(&ap->mac_restrictions.lock); | |
| 357 | − return seq_list_start_head(&ap->mac_restrictions.mac_list, *_pos); | |
| 358 | −} | |
| 359 | − | |
| 360 | −static void *ap_control_proc_next(struct seq_file *m, void *v, loff_t *_pos) | |
| 361 | −{ | |
| 362 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 363 | − return seq_list_next(v, &ap->mac_restrictions.mac_list, _pos); | |
| 364 | −} | |
| 365 | − | |
| 366 | −static void ap_control_proc_stop(struct seq_file *m, void *v) | |
| 367 | −{ | |
| 368 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 369 | − spin_unlock_bh(&ap->mac_restrictions.lock); | |
| 370 | −} | |
| 371 | − | |
| 372 | −static const struct seq_operations ap_control_proc_seqops = { | |
| 373 | − .start = ap_control_proc_start, | |
| 374 | − .next = ap_control_proc_next, | |
| 375 | − .stop = ap_control_proc_stop, | |
| 376 | − .show = ap_control_proc_show, | |
| 377 | −}; | |
| 378 | − | |
| 379 | −int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac) | |
| 380 | −{ | |
| 381 | − struct mac_entry *entry; | |
| 382 | − | |
| 383 | − entry = kmalloc(sizeof(struct mac_entry), GFP_KERNEL); | |
| 384 | − if (entry == NULL) | |
| 385 | − return -ENOMEM; | |
| 386 | − | |
| 387 | − memcpy(entry->addr, mac, ETH_ALEN); | |
| 388 | − | |
| 389 | − spin_lock_bh(&mac_restrictions->lock); | |
| 390 | − list_add_tail(&entry->list, &mac_restrictions->mac_list); | |
| 391 | − mac_restrictions->entries++; | |
| 392 | − spin_unlock_bh(&mac_restrictions->lock); | |
| 393 | − | |
| 394 | − return 0; | |
| 395 | −} | |
| 396 | − | |
| 397 | − | |
| 398 | −int ap_control_del_mac(struct mac_restrictions *mac_restrictions, u8 *mac) | |
| 399 | −{ | |
| 400 | − struct list_head *ptr; | |
| 401 | − struct mac_entry *entry; | |
| 402 | − | |
| 403 | − spin_lock_bh(&mac_restrictions->lock); | |
| 404 | − for (ptr = mac_restrictions->mac_list.next; | |
| 405 | − ptr != &mac_restrictions->mac_list; ptr = ptr->next) { | |
| 406 | − entry = list_entry(ptr, struct mac_entry, list); | |
| 407 | − | |
| 408 | − if (ether_addr_equal(entry->addr, mac)) { | |
| 409 | − list_del(ptr); | |
| 410 | − kfree(entry); | |
| 411 | − mac_restrictions->entries--; | |
| 412 | − spin_unlock_bh(&mac_restrictions->lock); | |
| 413 | − return 0; | |
| 414 | − } | |
| 415 | − } | |
| 416 | − spin_unlock_bh(&mac_restrictions->lock); | |
| 417 | − return -1; | |
| 418 | −} | |
| 419 | − | |
| 420 | − | |
| 421 | −static int ap_control_mac_deny(struct mac_restrictions *mac_restrictions, | |
| 422 | − u8 *mac) | |
| 423 | −{ | |
| 424 | − struct mac_entry *entry; | |
| 425 | − int found = 0; | |
| 426 | − | |
| 427 | − if (mac_restrictions->policy == MAC_POLICY_OPEN) | |
| 428 | − return 0; | |
| 429 | − | |
| 430 | − spin_lock_bh(&mac_restrictions->lock); | |
| 431 | − list_for_each_entry(entry, &mac_restrictions->mac_list, list) { | |
| 432 | − if (ether_addr_equal(entry->addr, mac)) { | |
| 433 | − found = 1; | |
| 434 | − break; | |
| 435 | − } | |
| 436 | − } | |
| 437 | − spin_unlock_bh(&mac_restrictions->lock); | |
| 438 | − | |
| 439 | − if (mac_restrictions->policy == MAC_POLICY_ALLOW) | |
| 440 | − return !found; | |
| 441 | − else | |
| 442 | − return found; | |
| 443 | −} | |
| 444 | − | |
| 445 | − | |
| 446 | −void ap_control_flush_macs(struct mac_restrictions *mac_restrictions) | |
| 447 | −{ | |
| 448 | − struct list_head *ptr, *n; | |
| 449 | − struct mac_entry *entry; | |
| 450 | − | |
| 451 | − if (mac_restrictions->entries == 0) | |
| 452 | − return; | |
| 453 | − | |
| 454 | − spin_lock_bh(&mac_restrictions->lock); | |
| 455 | − for (ptr = mac_restrictions->mac_list.next, n = ptr->next; | |
| 456 | − ptr != &mac_restrictions->mac_list; | |
| 457 | − ptr = n, n = ptr->next) { | |
| 458 | − entry = list_entry(ptr, struct mac_entry, list); | |
| 459 | − list_del(ptr); | |
| 460 | − kfree(entry); | |
| 461 | − } | |
| 462 | − mac_restrictions->entries = 0; | |
| 463 | − spin_unlock_bh(&mac_restrictions->lock); | |
| 464 | −} | |
| 465 | − | |
| 466 | − | |
| 467 | −int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac) | |
| 468 | −{ | |
| 469 | − struct sta_info *sta; | |
| 470 | − __le16 resp; | |
| 471 | − | |
| 472 | − spin_lock_bh(&ap->sta_table_lock); | |
| 473 | − sta = ap_get_sta(ap, mac); | |
| 474 | − if (sta) { | |
| 475 | − ap_sta_hash_del(ap, sta); | |
| 476 | − list_del(&sta->list); | |
| 477 | − } | |
| 478 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 479 | − | |
| 480 | − if (!sta) | |
| 481 | − return -EINVAL; | |
| 482 | − | |
| 483 | − resp = cpu_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); | |
| 484 | − prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH, | |
| 485 | − (char *) &resp, 2, sta->addr, 0); | |
| 486 | − | |
| 487 | − if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | |
| 488 | − hostap_event_expired_sta(dev, sta); | |
| 489 | − | |
| 490 | − ap_free_sta(ap, sta); | |
| 491 | − | |
| 492 | − return 0; | |
| 493 | −} | |
| 494 | − | |
| 495 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 496 | − | |
| 497 | − | |
| 498 | −void ap_control_kickall(struct ap_data *ap) | |
| 499 | −{ | |
| 500 | − struct list_head *ptr, *n; | |
| 501 | − struct sta_info *sta; | |
| 502 | − | |
| 503 | − spin_lock_bh(&ap->sta_table_lock); | |
| 504 | − for (ptr = ap->sta_list.next, n = ptr->next; ptr != &ap->sta_list; | |
| 505 | − ptr = n, n = ptr->next) { | |
| 506 | − sta = list_entry(ptr, struct sta_info, list); | |
| 507 | − ap_sta_hash_del(ap, sta); | |
| 508 | − list_del(&sta->list); | |
| 509 | − if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | |
| 510 | − hostap_event_expired_sta(sta->local->dev, sta); | |
| 511 | − ap_free_sta(ap, sta); | |
| 512 | − } | |
| 513 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 514 | −} | |
| 515 | − | |
| 516 | − | |
| 517 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 518 | − | |
| 519 | −static int prism2_ap_proc_show(struct seq_file *m, void *v) | |
| 520 | −{ | |
| 521 | − struct sta_info *sta = v; | |
| 522 | − int i; | |
| 523 | − | |
| 524 | − if (v == SEQ_START_TOKEN) { | |
| 525 | − seq_printf(m, "# BSSID CHAN SIGNAL NOISE RATE SSID FLAGS\n"); | |
| 526 | − return 0; | |
| 527 | − } | |
| 528 | − | |
| 529 | − if (!sta->ap) | |
| 530 | − return 0; | |
| 531 | − | |
| 532 | − seq_printf(m, "%pM %d %d %d %d '", | |
| 533 | − sta->addr, | |
| 534 | − sta->u.ap.channel, sta->last_rx_signal, | |
| 535 | − sta->last_rx_silence, sta->last_rx_rate); | |
| 536 | − | |
| 537 | − for (i = 0; i < sta->u.ap.ssid_len; i++) { | |
| 538 | − if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) | |
| 539 | − seq_putc(m, sta->u.ap.ssid[i]); | |
| 540 | − else | |
| 541 | − seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); | |
| 542 | − } | |
| 543 | − | |
| 544 | − seq_putc(m, '\''); | |
| 545 | − if (sta->capability & WLAN_CAPABILITY_ESS) | |
| 546 | − seq_puts(m, " [ESS]"); | |
| 547 | − if (sta->capability & WLAN_CAPABILITY_IBSS) | |
| 548 | − seq_puts(m, " [IBSS]"); | |
| 549 | − if (sta->capability & WLAN_CAPABILITY_PRIVACY) | |
| 550 | − seq_puts(m, " [WEP]"); | |
| 551 | − seq_putc(m, '\n'); | |
| 552 | − return 0; | |
| 553 | −} | |
| 554 | − | |
| 555 | −static void *prism2_ap_proc_start(struct seq_file *m, loff_t *_pos) | |
| 556 | −{ | |
| 557 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 558 | − spin_lock_bh(&ap->sta_table_lock); | |
| 559 | − return seq_list_start_head(&ap->sta_list, *_pos); | |
| 560 | −} | |
| 561 | − | |
| 562 | −static void *prism2_ap_proc_next(struct seq_file *m, void *v, loff_t *_pos) | |
| 563 | −{ | |
| 564 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 565 | − return seq_list_next(v, &ap->sta_list, _pos); | |
| 566 | −} | |
| 567 | − | |
| 568 | −static void prism2_ap_proc_stop(struct seq_file *m, void *v) | |
| 569 | −{ | |
| 570 | − struct ap_data *ap = pde_data(file_inode(m->file)); | |
| 571 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 572 | −} | |
| 573 | − | |
| 574 | −static const struct seq_operations prism2_ap_proc_seqops = { | |
| 575 | − .start = prism2_ap_proc_start, | |
| 576 | − .next = prism2_ap_proc_next, | |
| 577 | − .stop = prism2_ap_proc_stop, | |
| 578 | − .show = prism2_ap_proc_show, | |
| 579 | −}; | |
| 580 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 581 | − | |
| 582 | − | |
| 583 | −void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver) | |
| 584 | −{ | |
| 585 | − if (!ap) | |
| 586 | − return; | |
| 587 | − | |
| 588 | − if (sta_fw_ver == PRISM2_FW_VER(0,8,0)) { | |
| 589 | − PDEBUG(DEBUG_AP, "Using data::nullfunc ACK workaround - " | |
| 590 | − "firmware upgrade recommended\n"); | |
| 591 | − ap->nullfunc_ack = 1; | |
| 592 | − } else | |
| 593 | − ap->nullfunc_ack = 0; | |
| 594 | − | |
| 595 | − if (sta_fw_ver == PRISM2_FW_VER(1,4,2)) { | |
| 596 | − printk(KERN_WARNING "%s: Warning: secondary station firmware " | |
| 597 | − "version 1.4.2 does not seem to work in Host AP mode\n", | |
| 598 | − ap->local->dev->name); | |
| 599 | − } | |
| 600 | −} | |
| 601 | − | |
| 602 | − | |
| 603 | −/* Called only as a tasklet (software IRQ) */ | |
| 604 | −static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) | |
| 605 | −{ | |
| 606 | − struct ap_data *ap = data; | |
| 607 | − struct ieee80211_hdr *hdr; | |
| 608 | − | |
| 609 | − if (!ap->local->hostapd || !ap->local->apdev) { | |
| 610 | − dev_kfree_skb(skb); | |
| 611 | − return; | |
| 612 | − } | |
| 613 | − | |
| 614 | − /* Pass the TX callback frame to the hostapd; use 802.11 header version | |
| 615 | − * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */ | |
| 616 | − | |
| 617 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 618 | − hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS); | |
| 619 | − hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0)); | |
| 620 | − | |
| 621 | − skb->dev = ap->local->apdev; | |
| 622 | − skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control)); | |
| 623 | − skb->pkt_type = PACKET_OTHERHOST; | |
| 624 | − skb->protocol = cpu_to_be16(ETH_P_802_2); | |
| 625 | − memset(skb->cb, 0, sizeof(skb->cb)); | |
| 626 | − netif_rx(skb); | |
| 627 | −} | |
| 628 | − | |
| 629 | − | |
| 630 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 631 | −/* Called only as a tasklet (software IRQ) */ | |
| 632 | −static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) | |
| 633 | −{ | |
| 634 | − struct ap_data *ap = data; | |
| 635 | − struct net_device *dev = ap->local->dev; | |
| 636 | − struct ieee80211_hdr *hdr; | |
| 637 | − u16 auth_alg, auth_transaction, status; | |
| 638 | − __le16 *pos; | |
| 639 | − struct sta_info *sta = NULL; | |
| 640 | − char *txt = NULL; | |
| 641 | − | |
| 642 | − if (ap->local->hostapd) { | |
| 643 | − dev_kfree_skb(skb); | |
| 644 | − return; | |
| 645 | − } | |
| 646 | − | |
| 647 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 648 | − if (!ieee80211_is_auth(hdr->frame_control) || | |
| 649 | − skb->len < IEEE80211_MGMT_HDR_LEN + 6) { | |
| 650 | − printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid " | |
| 651 | − "frame\n", dev->name); | |
| 652 | − dev_kfree_skb(skb); | |
| 653 | − return; | |
| 654 | − } | |
| 655 | − | |
| 656 | − pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | |
| 657 | − auth_alg = le16_to_cpu(*pos++); | |
| 658 | − auth_transaction = le16_to_cpu(*pos++); | |
| 659 | − status = le16_to_cpu(*pos++); | |
| 660 | − | |
| 661 | − if (!ok) { | |
| 662 | − txt = "frame was not ACKed"; | |
| 663 | − goto done; | |
| 664 | − } | |
| 665 | − | |
| 666 | − spin_lock(&ap->sta_table_lock); | |
| 667 | − sta = ap_get_sta(ap, hdr->addr1); | |
| 668 | − if (sta) | |
| 669 | − atomic_inc(&sta->users); | |
| 670 | − spin_unlock(&ap->sta_table_lock); | |
| 671 | − | |
| 672 | − if (!sta) { | |
| 673 | − txt = "STA not found"; | |
| 674 | − goto done; | |
| 675 | − } | |
| 676 | − | |
| 677 | − if (status == WLAN_STATUS_SUCCESS && | |
| 678 | − ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || | |
| 679 | − (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { | |
| 680 | − txt = "STA authenticated"; | |
| 681 | − sta->flags |= WLAN_STA_AUTH; | |
| 682 | − sta->last_auth = jiffies; | |
| 683 | − } else if (status != WLAN_STATUS_SUCCESS) | |
| 684 | − txt = "authentication failed"; | |
| 685 | − | |
| 686 | − done: | |
| 687 | − if (sta) | |
| 688 | − atomic_dec(&sta->users); | |
| 689 | − if (txt) { | |
| 690 | − PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " | |
| 691 | − "trans#=%d status=%d - %s\n", | |
| 692 | − dev->name, hdr->addr1, | |
| 693 | − auth_alg, auth_transaction, status, txt); | |
| 694 | − } | |
| 695 | − dev_kfree_skb(skb); | |
| 696 | −} | |
| 697 | − | |
| 698 | − | |
| 699 | −/* Called only as a tasklet (software IRQ) */ | |
| 700 | −static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) | |
| 701 | −{ | |
| 702 | − struct ap_data *ap = data; | |
| 703 | − struct net_device *dev = ap->local->dev; | |
| 704 | − struct ieee80211_hdr *hdr; | |
| 705 | − u16 status; | |
| 706 | − __le16 *pos; | |
| 707 | − struct sta_info *sta = NULL; | |
| 708 | − char *txt = NULL; | |
| 709 | − | |
| 710 | − if (ap->local->hostapd) { | |
| 711 | − dev_kfree_skb(skb); | |
| 712 | − return; | |
| 713 | − } | |
| 714 | − | |
| 715 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 716 | − if ((!ieee80211_is_assoc_resp(hdr->frame_control) && | |
| 717 | − !ieee80211_is_reassoc_resp(hdr->frame_control)) || | |
| 718 | − skb->len < IEEE80211_MGMT_HDR_LEN + 4) { | |
| 719 | − printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid " | |
| 720 | − "frame\n", dev->name); | |
| 721 | − dev_kfree_skb(skb); | |
| 722 | − return; | |
| 723 | − } | |
| 724 | − | |
| 725 | − if (!ok) { | |
| 726 | − txt = "frame was not ACKed"; | |
| 727 | − goto done; | |
| 728 | − } | |
| 729 | − | |
| 730 | − spin_lock(&ap->sta_table_lock); | |
| 731 | − sta = ap_get_sta(ap, hdr->addr1); | |
| 732 | − if (sta) | |
| 733 | − atomic_inc(&sta->users); | |
| 734 | − spin_unlock(&ap->sta_table_lock); | |
| 735 | − | |
| 736 | − if (!sta) { | |
| 737 | − txt = "STA not found"; | |
| 738 | − goto done; | |
| 739 | − } | |
| 740 | − | |
| 741 | − pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | |
| 742 | − pos++; | |
| 743 | − status = le16_to_cpu(*pos++); | |
| 744 | − if (status == WLAN_STATUS_SUCCESS) { | |
| 745 | − if (!(sta->flags & WLAN_STA_ASSOC)) | |
| 746 | − hostap_event_new_sta(dev, sta); | |
| 747 | − txt = "STA associated"; | |
| 748 | − sta->flags |= WLAN_STA_ASSOC; | |
| 749 | − sta->last_assoc = jiffies; | |
| 750 | − } else | |
| 751 | − txt = "association failed"; | |
| 752 | − | |
| 753 | − done: | |
| 754 | − if (sta) | |
| 755 | − atomic_dec(&sta->users); | |
| 756 | − if (txt) { | |
| 757 | − PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", | |
| 758 | − dev->name, hdr->addr1, txt); | |
| 759 | − } | |
| 760 | − dev_kfree_skb(skb); | |
| 761 | −} | |
| 762 | − | |
| 763 | −/* Called only as a tasklet (software IRQ); TX callback for poll frames used | |
| 764 | − * in verifying whether the STA is still present. */ | |
| 765 | −static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) | |
| 766 | −{ | |
| 767 | − struct ap_data *ap = data; | |
| 768 | − struct ieee80211_hdr *hdr; | |
| 769 | − struct sta_info *sta; | |
| 770 | − | |
| 771 | − if (skb->len < 24) | |
| 772 | − goto fail; | |
| 773 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 774 | − if (ok) { | |
| 775 | − spin_lock(&ap->sta_table_lock); | |
| 776 | − sta = ap_get_sta(ap, hdr->addr1); | |
| 777 | − if (sta) | |
| 778 | − sta->flags &= ~WLAN_STA_PENDING_POLL; | |
| 779 | − spin_unlock(&ap->sta_table_lock); | |
| 780 | − } else { | |
| 781 | − PDEBUG(DEBUG_AP, | |
| 782 | − "%s: STA %pM did not ACK activity poll frame\n", | |
| 783 | − ap->local->dev->name, hdr->addr1); | |
| 784 | − } | |
| 785 | − | |
| 786 | − fail: | |
| 787 | − dev_kfree_skb(skb); | |
| 788 | −} | |
| 789 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 790 | − | |
| 791 | − | |
| 792 | −void hostap_init_data(local_info_t *local) | |
| 793 | −{ | |
| 794 | − struct ap_data *ap = local->ap; | |
| 795 | − | |
| 796 | − if (ap == NULL) { | |
| 797 | − printk(KERN_WARNING "hostap_init_data: ap == NULL\n"); | |
| 798 | − return; | |
| 799 | − } | |
| 800 | − memset(ap, 0, sizeof(struct ap_data)); | |
| 801 | − ap->local = local; | |
| 802 | − | |
| 803 | − ap->ap_policy = GET_INT_PARM(other_ap_policy, local->card_idx); | |
| 804 | − ap->bridge_packets = GET_INT_PARM(ap_bridge_packets, local->card_idx); | |
| 805 | − ap->max_inactivity = | |
| 806 | − GET_INT_PARM(ap_max_inactivity, local->card_idx) * HZ; | |
| 807 | − ap->autom_ap_wds = GET_INT_PARM(autom_ap_wds, local->card_idx); | |
| 808 | − | |
| 809 | − spin_lock_init(&ap->sta_table_lock); | |
| 810 | − INIT_LIST_HEAD(&ap->sta_list); | |
| 811 | − | |
| 812 | − /* Initialize task queue structure for AP management */ | |
| 813 | − INIT_WORK(&local->ap->add_sta_proc_queue, handle_add_proc_queue); | |
| 814 | − | |
| 815 | − ap->tx_callback_idx = | |
| 816 | − hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); | |
| 817 | − if (ap->tx_callback_idx == 0) | |
| 818 | − printk(KERN_WARNING "%s: failed to register TX callback for " | |
| 819 | − "AP\n", local->dev->name); | |
| 820 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 821 | − INIT_WORK(&local->ap->wds_oper_queue, handle_wds_oper_queue); | |
| 822 | − | |
| 823 | − ap->tx_callback_auth = | |
| 824 | − hostap_tx_callback_register(local, hostap_ap_tx_cb_auth, ap); | |
| 825 | − ap->tx_callback_assoc = | |
| 826 | − hostap_tx_callback_register(local, hostap_ap_tx_cb_assoc, ap); | |
| 827 | − ap->tx_callback_poll = | |
| 828 | − hostap_tx_callback_register(local, hostap_ap_tx_cb_poll, ap); | |
| 829 | − if (ap->tx_callback_auth == 0 || ap->tx_callback_assoc == 0 || | |
| 830 | − ap->tx_callback_poll == 0) | |
| 831 | − printk(KERN_WARNING "%s: failed to register TX callback for " | |
| 832 | − "AP\n", local->dev->name); | |
| 833 | − | |
| 834 | − spin_lock_init(&ap->mac_restrictions.lock); | |
| 835 | − INIT_LIST_HEAD(&ap->mac_restrictions.mac_list); | |
| 836 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 837 | − | |
| 838 | − ap->initialized = 1; | |
| 839 | −} | |
| 840 | − | |
| 841 | − | |
| 842 | −void hostap_init_ap_proc(local_info_t *local) | |
| 843 | −{ | |
| 844 | − struct ap_data *ap = local->ap; | |
| 845 | − | |
| 846 | − ap->proc = local->proc; | |
| 847 | − if (ap->proc == NULL) | |
| 848 | − return; | |
| 849 | − | |
| 850 | −#ifndef PRISM2_NO_PROCFS_DEBUG | |
| 851 | − proc_create_single_data("ap_debug", 0, ap->proc, ap_debug_proc_show, ap); | |
| 852 | −#endif /* PRISM2_NO_PROCFS_DEBUG */ | |
| 853 | − | |
| 854 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 855 | − proc_create_seq_data("ap_control", 0, ap->proc, &ap_control_proc_seqops, | |
| 856 | − ap); | |
| 857 | − proc_create_seq_data("ap", 0, ap->proc, &prism2_ap_proc_seqops, ap); | |
| 858 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 859 | − | |
| 860 | −} | |
| 861 | − | |
| 862 | − | |
| 863 | −void hostap_free_data(struct ap_data *ap) | |
| 864 | −{ | |
| 865 | − struct sta_info *n, *sta; | |
| 866 | − | |
| 867 | − if (ap == NULL || !ap->initialized) { | |
| 868 | − printk(KERN_DEBUG "hostap_free_data: ap has not yet been " | |
| 869 | − "initialized - skip resource freeing\n"); | |
| 870 | − return; | |
| 871 | − } | |
| 872 | − | |
| 873 | − flush_work(&ap->add_sta_proc_queue); | |
| 874 | − | |
| 875 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 876 | − flush_work(&ap->wds_oper_queue); | |
| 877 | − if (ap->crypt) | |
| 878 | − ap->crypt->deinit(ap->crypt_priv); | |
| 879 | − ap->crypt = ap->crypt_priv = NULL; | |
| 880 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 881 | − | |
| 882 | − list_for_each_entry_safe(sta, n, &ap->sta_list, list) { | |
| 883 | − ap_sta_hash_del(ap, sta); | |
| 884 | − list_del(&sta->list); | |
| 885 | − if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | |
| 886 | − hostap_event_expired_sta(sta->local->dev, sta); | |
| 887 | − ap_free_sta(ap, sta); | |
| 888 | − } | |
| 889 | − | |
| 890 | −#ifndef PRISM2_NO_PROCFS_DEBUG | |
| 891 | − if (ap->proc != NULL) { | |
| 892 | − remove_proc_entry("ap_debug", ap->proc); | |
| 893 | − } | |
| 894 | −#endif /* PRISM2_NO_PROCFS_DEBUG */ | |
| 895 | − | |
| 896 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 897 | − if (ap->proc != NULL) { | |
| 898 | − remove_proc_entry("ap", ap->proc); | |
| 899 | − remove_proc_entry("ap_control", ap->proc); | |
| 900 | − } | |
| 901 | − ap_control_flush_macs(&ap->mac_restrictions); | |
| 902 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 903 | − | |
| 904 | − ap->initialized = 0; | |
| 905 | −} | |
| 906 | − | |
| 907 | − | |
| 908 | −/* caller should have mutex for AP STA list handling */ | |
| 909 | −static struct sta_info* ap_get_sta(struct ap_data *ap, u8 *sta) | |
| 910 | −{ | |
| 911 | − struct sta_info *s; | |
| 912 | − | |
| 913 | − s = ap->sta_hash[STA_HASH(sta)]; | |
| 914 | − while (s != NULL && !ether_addr_equal(s->addr, sta)) | |
| 915 | − s = s->hnext; | |
| 916 | − return s; | |
| 917 | −} | |
| 918 | − | |
| 919 | − | |
| 920 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 921 | − | |
| 922 | −/* Called from timer handler and from scheduled AP queue handlers */ | |
| 923 | −static void prism2_send_mgmt(struct net_device *dev, | |
| 924 | − u16 type_subtype, char *body, | |
| 925 | − int body_len, u8 *addr, u16 tx_cb_idx) | |
| 926 | −{ | |
| 927 | − struct hostap_interface *iface; | |
| 928 | − local_info_t *local; | |
| 929 | − struct ieee80211_hdr *hdr; | |
| 930 | − u16 fc; | |
| 931 | − struct sk_buff *skb; | |
| 932 | − struct hostap_skb_tx_data *meta; | |
| 933 | − int hdrlen; | |
| 934 | − | |
| 935 | − iface = netdev_priv(dev); | |
| 936 | − local = iface->local; | |
| 937 | − dev = local->dev; /* always use master radio device */ | |
| 938 | − iface = netdev_priv(dev); | |
| 939 | − | |
| 940 | − if (!(dev->flags & IFF_UP)) { | |
| 941 | − PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt - device is not UP - " | |
| 942 | − "cannot send frame\n", dev->name); | |
| 943 | − return; | |
| 944 | − } | |
| 945 | − | |
| 946 | − skb = dev_alloc_skb(sizeof(*hdr) + body_len); | |
| 947 | − if (skb == NULL) { | |
| 948 | − PDEBUG(DEBUG_AP, "%s: prism2_send_mgmt failed to allocate " | |
| 949 | − "skb\n", dev->name); | |
| 950 | − return; | |
| 951 | − } | |
| 952 | − | |
| 953 | − fc = type_subtype; | |
| 954 | − hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype)); | |
| 955 | − hdr = skb_put_zero(skb, hdrlen); | |
| 956 | − if (body) | |
| 957 | − skb_put_data(skb, body, body_len); | |
| 958 | − | |
| 959 | − /* FIX: ctrl::ack sending used special HFA384X_TX_CTRL_802_11 | |
| 960 | − * tx_control instead of using local->tx_control */ | |
| 961 | − | |
| 962 | − | |
| 963 | − memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */ | |
| 964 | − if (ieee80211_is_data(hdr->frame_control)) { | |
| 965 | − fc |= IEEE80211_FCTL_FROMDS; | |
| 966 | − memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */ | |
| 967 | − memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */ | |
| 968 | − } else if (ieee80211_is_ctl(hdr->frame_control)) { | |
| 969 | − /* control:ACK does not have addr2 or addr3 */ | |
| 970 | − eth_zero_addr(hdr->addr2); | |
| 971 | − eth_zero_addr(hdr->addr3); | |
| 972 | − } else { | |
| 973 | − memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* SA */ | |
| 974 | − memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */ | |
| 975 | − } | |
| 976 | − | |
| 977 | − hdr->frame_control = cpu_to_le16(fc); | |
| 978 | − | |
| 979 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 980 | − memset(meta, 0, sizeof(*meta)); | |
| 981 | − meta->magic = HOSTAP_SKB_TX_DATA_MAGIC; | |
| 982 | − meta->iface = iface; | |
| 983 | − meta->tx_cb_idx = tx_cb_idx; | |
| 984 | − | |
| 985 | − skb->dev = dev; | |
| 986 | − skb_reset_mac_header(skb); | |
| 987 | − skb_reset_network_header(skb); | |
| 988 | − dev_queue_xmit(skb); | |
| 989 | −} | |
| 990 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 991 | − | |
| 992 | −#ifdef CONFIG_PROC_FS | |
| 993 | −static int prism2_sta_proc_show(struct seq_file *m, void *v) | |
| 994 | −{ | |
| 995 | − struct sta_info *sta = m->private; | |
| 996 | − int i; | |
| 997 | − | |
| 998 | − /* FIX: possible race condition.. the STA data could have just expired, | |
| 999 | − * but proc entry was still here so that the read could have started; | |
| 1000 | − * some locking should be done here.. */ | |
| 1001 | − | |
| 1002 | − seq_printf(m, | |
| 1003 | − "%s=%pM\nusers=%d\naid=%d\n" | |
| 1004 | − "flags=0x%04x%s%s%s%s%s%s%s\n" | |
| 1005 | − "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", | |
| 1006 | − sta->ap ? "AP" : "STA", | |
| 1007 | − sta->addr, atomic_read(&sta->users), sta->aid, | |
| 1008 | − sta->flags, | |
| 1009 | − sta->flags & WLAN_STA_AUTH ? " AUTH" : "", | |
| 1010 | − sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", | |
| 1011 | − sta->flags & WLAN_STA_PS ? " PS" : "", | |
| 1012 | − sta->flags & WLAN_STA_TIM ? " TIM" : "", | |
| 1013 | − sta->flags & WLAN_STA_PERM ? " PERM" : "", | |
| 1014 | − sta->flags & WLAN_STA_AUTHORIZED ? " AUTHORIZED" : "", | |
| 1015 | − sta->flags & WLAN_STA_PENDING_POLL ? " POLL" : "", | |
| 1016 | − sta->capability, sta->listen_interval); | |
| 1017 | − /* supported_rates: 500 kbit/s units with msb ignored */ | |
| 1018 | − for (i = 0; i < sizeof(sta->supported_rates); i++) | |
| 1019 | − if (sta->supported_rates[i] != 0) | |
| 1020 | − seq_printf(m, "%d%sMbps ", | |
| 1021 | − (sta->supported_rates[i] & 0x7f) / 2, | |
| 1022 | − sta->supported_rates[i] & 1 ? ".5" : ""); | |
| 1023 | − seq_printf(m, | |
| 1024 | − "\njiffies=%lu\nlast_auth=%lu\nlast_assoc=%lu\n" | |
| 1025 | − "last_rx=%lu\nlast_tx=%lu\nrx_packets=%lu\n" | |
| 1026 | − "tx_packets=%lu\n" | |
| 1027 | − "rx_bytes=%lu\ntx_bytes=%lu\nbuffer_count=%d\n" | |
| 1028 | − "last_rx: silence=%d dBm signal=%d dBm rate=%d%s Mbps\n" | |
| 1029 | − "tx_rate=%d\ntx[1M]=%d\ntx[2M]=%d\ntx[5.5M]=%d\n" | |
| 1030 | − "tx[11M]=%d\n" | |
| 1031 | − "rx[1M]=%d\nrx[2M]=%d\nrx[5.5M]=%d\nrx[11M]=%d\n", | |
| 1032 | − jiffies, sta->last_auth, sta->last_assoc, sta->last_rx, | |
| 1033 | − sta->last_tx, | |
| 1034 | − sta->rx_packets, sta->tx_packets, sta->rx_bytes, | |
| 1035 | − sta->tx_bytes, skb_queue_len(&sta->tx_buf), | |
| 1036 | − sta->last_rx_silence, | |
| 1037 | − sta->last_rx_signal, sta->last_rx_rate / 10, | |
| 1038 | − sta->last_rx_rate % 10 ? ".5" : "", | |
| 1039 | − sta->tx_rate, sta->tx_count[0], sta->tx_count[1], | |
| 1040 | − sta->tx_count[2], sta->tx_count[3], sta->rx_count[0], | |
| 1041 | − sta->rx_count[1], sta->rx_count[2], sta->rx_count[3]); | |
| 1042 | − if (sta->crypt && sta->crypt->ops && sta->crypt->ops->print_stats) | |
| 1043 | − sta->crypt->ops->print_stats(m, sta->crypt->priv); | |
| 1044 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 1045 | − if (sta->ap) { | |
| 1046 | − if (sta->u.ap.channel >= 0) | |
| 1047 | − seq_printf(m, "channel=%d\n", sta->u.ap.channel); | |
| 1048 | − seq_puts(m, "ssid="); | |
| 1049 | − for (i = 0; i < sta->u.ap.ssid_len; i++) { | |
| 1050 | − if (sta->u.ap.ssid[i] >= 32 && sta->u.ap.ssid[i] < 127) | |
| 1051 | − seq_putc(m, sta->u.ap.ssid[i]); | |
| 1052 | − else | |
| 1053 | − seq_printf(m, "<%02x>", sta->u.ap.ssid[i]); | |
| 1054 | − } | |
| 1055 | − seq_putc(m, '\n'); | |
| 1056 | − } | |
| 1057 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 1058 | − | |
| 1059 | − return 0; | |
| 1060 | −} | |
| 1061 | −#endif | |
| 1062 | − | |
| 1063 | −static void handle_add_proc_queue(struct work_struct *work) | |
| 1064 | −{ | |
| 1065 | − struct ap_data *ap = container_of(work, struct ap_data, | |
| 1066 | − add_sta_proc_queue); | |
| 1067 | − struct sta_info *sta; | |
| 1068 | − char name[20]; | |
| 1069 | − struct add_sta_proc_data *entry, *prev; | |
| 1070 | − | |
| 1071 | − entry = ap->add_sta_proc_entries; | |
| 1072 | − ap->add_sta_proc_entries = NULL; | |
| 1073 | − | |
| 1074 | − while (entry) { | |
| 1075 | − spin_lock_bh(&ap->sta_table_lock); | |
| 1076 | − sta = ap_get_sta(ap, entry->addr); | |
| 1077 | − if (sta) | |
| 1078 | − atomic_inc(&sta->users); | |
| 1079 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 1080 | − | |
| 1081 | − if (sta) { | |
| 1082 | − sprintf(name, "%pM", sta->addr); | |
| 1083 | − sta->proc = proc_create_single_data( | |
| 1084 | − name, 0, ap->proc, | |
| 1085 | − prism2_sta_proc_show, sta); | |
| 1086 | − | |
| 1087 | − atomic_dec(&sta->users); | |
| 1088 | − } | |
| 1089 | − | |
| 1090 | − prev = entry; | |
| 1091 | − entry = entry->next; | |
| 1092 | − kfree(prev); | |
| 1093 | − } | |
| 1094 | −} | |
| 1095 | − | |
| 1096 | − | |
| 1097 | −static struct sta_info * ap_add_sta(struct ap_data *ap, u8 *addr) | |
| 1098 | −{ | |
| 1099 | − struct sta_info *sta; | |
| 1100 | − | |
| 1101 | − sta = kzalloc(sizeof(struct sta_info), GFP_ATOMIC); | |
| 1102 | − if (sta == NULL) { | |
| 1103 | − PDEBUG(DEBUG_AP, "AP: kmalloc failed\n"); | |
| 1104 | − return NULL; | |
| 1105 | − } | |
| 1106 | − | |
| 1107 | − /* initialize STA info data */ | |
| 1108 | − sta->local = ap->local; | |
| 1109 | − skb_queue_head_init(&sta->tx_buf); | |
| 1110 | − memcpy(sta->addr, addr, ETH_ALEN); | |
| 1111 | − | |
| 1112 | − atomic_inc(&sta->users); | |
| 1113 | − spin_lock_bh(&ap->sta_table_lock); | |
| 1114 | − list_add(&sta->list, &ap->sta_list); | |
| 1115 | − ap->num_sta++; | |
| 1116 | − ap_sta_hash_add(ap, sta); | |
| 1117 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 1118 | − | |
| 1119 | − if (ap->proc) { | |
| 1120 | − struct add_sta_proc_data *entry; | |
| 1121 | − /* schedule a non-interrupt context process to add a procfs | |
| 1122 | − * entry for the STA since procfs code use GFP_KERNEL */ | |
| 1123 | − entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | |
| 1124 | − if (entry) { | |
| 1125 | − memcpy(entry->addr, sta->addr, ETH_ALEN); | |
| 1126 | − entry->next = ap->add_sta_proc_entries; | |
| 1127 | − ap->add_sta_proc_entries = entry; | |
| 1128 | − schedule_work(&ap->add_sta_proc_queue); | |
| 1129 | − } else | |
| 1130 | − printk(KERN_DEBUG "Failed to add STA proc data\n"); | |
| 1131 | − } | |
| 1132 | − | |
| 1133 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 1134 | − timer_setup(&sta->timer, ap_handle_timer, 0); | |
| 1135 | − sta->timer.expires = jiffies + ap->max_inactivity; | |
| 1136 | − if (!ap->local->hostapd) | |
| 1137 | − add_timer(&sta->timer); | |
| 1138 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 1139 | − | |
| 1140 | − return sta; | |
| 1141 | −} | |
| 1142 | − | |
| 1143 | − | |
| 1144 | −static int ap_tx_rate_ok(int rateidx, struct sta_info *sta, | |
| 1145 | − local_info_t *local) | |
| 1146 | −{ | |
| 1147 | − if (rateidx > sta->tx_max_rate || | |
| 1148 | − !(sta->tx_supp_rates & (1 << rateidx))) | |
| 1149 | − return 0; | |
| 1150 | − | |
| 1151 | − if (local->tx_rate_control != 0 && | |
| 1152 | − !(local->tx_rate_control & (1 << rateidx))) | |
| 1153 | − return 0; | |
| 1154 | − | |
| 1155 | − return 1; | |
| 1156 | −} | |
| 1157 | − | |
| 1158 | − | |
| 1159 | −static void prism2_check_tx_rates(struct sta_info *sta) | |
| 1160 | −{ | |
| 1161 | − int i; | |
| 1162 | − | |
| 1163 | − sta->tx_supp_rates = 0; | |
| 1164 | − for (i = 0; i < sizeof(sta->supported_rates); i++) { | |
| 1165 | − if ((sta->supported_rates[i] & 0x7f) == 2) | |
| 1166 | − sta->tx_supp_rates |= WLAN_RATE_1M; | |
| 1167 | − if ((sta->supported_rates[i] & 0x7f) == 4) | |
| 1168 | − sta->tx_supp_rates |= WLAN_RATE_2M; | |
| 1169 | − if ((sta->supported_rates[i] & 0x7f) == 11) | |
| 1170 | − sta->tx_supp_rates |= WLAN_RATE_5M5; | |
| 1171 | − if ((sta->supported_rates[i] & 0x7f) == 22) | |
| 1172 | − sta->tx_supp_rates |= WLAN_RATE_11M; | |
| 1173 | − } | |
| 1174 | − sta->tx_max_rate = sta->tx_rate = sta->tx_rate_idx = 0; | |
| 1175 | − if (sta->tx_supp_rates & WLAN_RATE_1M) { | |
| 1176 | − sta->tx_max_rate = 0; | |
| 1177 | − if (ap_tx_rate_ok(0, sta, sta->local)) { | |
| 1178 | − sta->tx_rate = 10; | |
| 1179 | − sta->tx_rate_idx = 0; | |
| 1180 | − } | |
| 1181 | − } | |
| 1182 | − if (sta->tx_supp_rates & WLAN_RATE_2M) { | |
| 1183 | − sta->tx_max_rate = 1; | |
| 1184 | − if (ap_tx_rate_ok(1, sta, sta->local)) { | |
| 1185 | − sta->tx_rate = 20; | |
| 1186 | − sta->tx_rate_idx = 1; | |
| 1187 | − } | |
| 1188 | − } | |
| 1189 | − if (sta->tx_supp_rates & WLAN_RATE_5M5) { | |
| 1190 | − sta->tx_max_rate = 2; | |
| 1191 | − if (ap_tx_rate_ok(2, sta, sta->local)) { | |
| 1192 | − sta->tx_rate = 55; | |
| 1193 | − sta->tx_rate_idx = 2; | |
| 1194 | − } | |
| 1195 | − } | |
| 1196 | − if (sta->tx_supp_rates & WLAN_RATE_11M) { | |
| 1197 | − sta->tx_max_rate = 3; | |
| 1198 | − if (ap_tx_rate_ok(3, sta, sta->local)) { | |
| 1199 | − sta->tx_rate = 110; | |
| 1200 | − sta->tx_rate_idx = 3; | |
| 1201 | − } | |
| 1202 | − } | |
| 1203 | −} | |
| 1204 | − | |
| 1205 | − | |
| 1206 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 1207 | − | |
| 1208 | −static void ap_crypt_init(struct ap_data *ap) | |
| 1209 | −{ | |
| 1210 | − ap->crypt = lib80211_get_crypto_ops("WEP"); | |
| 1211 | − | |
| 1212 | − if (ap->crypt) { | |
| 1213 | − if (ap->crypt->init) { | |
| 1214 | − ap->crypt_priv = ap->crypt->init(0); | |
| 1215 | − if (ap->crypt_priv == NULL) | |
| 1216 | − ap->crypt = NULL; | |
| 1217 | − else { | |
| 1218 | − u8 key[WEP_KEY_LEN]; | |
| 1219 | − get_random_bytes(key, WEP_KEY_LEN); | |
| 1220 | − ap->crypt->set_key(key, WEP_KEY_LEN, NULL, | |
| 1221 | − ap->crypt_priv); | |
| 1222 | − } | |
| 1223 | − } | |
| 1224 | − } | |
| 1225 | − | |
| 1226 | − if (ap->crypt == NULL) { | |
| 1227 | − printk(KERN_WARNING "AP could not initialize WEP: load module " | |
| 1228 | − "lib80211_crypt_wep.ko\n"); | |
| 1229 | − } | |
| 1230 | −} | |
| 1231 | − | |
| 1232 | − | |
| 1233 | −/* Generate challenge data for shared key authentication. IEEE 802.11 specifies | |
| 1234 | − * that WEP algorithm is used for generating challenge. This should be unique, | |
| 1235 | − * but otherwise there is not really need for randomness etc. Initialize WEP | |
| 1236 | − * with pseudo random key and then use increasing IV to get unique challenge | |
| 1237 | − * streams. | |
| 1238 | − * | |
| 1239 | − * Called only as a scheduled task for pending AP frames. | |
| 1240 | − */ | |
| 1241 | −static char * ap_auth_make_challenge(struct ap_data *ap) | |
| 1242 | −{ | |
| 1243 | − char *tmpbuf; | |
| 1244 | − struct sk_buff *skb; | |
| 1245 | − | |
| 1246 | − if (ap->crypt == NULL) { | |
| 1247 | − ap_crypt_init(ap); | |
| 1248 | − if (ap->crypt == NULL) | |
| 1249 | − return NULL; | |
| 1250 | − } | |
| 1251 | − | |
| 1252 | − tmpbuf = kmalloc(WLAN_AUTH_CHALLENGE_LEN, GFP_ATOMIC); | |
| 1253 | − if (tmpbuf == NULL) { | |
| 1254 | − PDEBUG(DEBUG_AP, "AP: kmalloc failed for challenge\n"); | |
| 1255 | − return NULL; | |
| 1256 | − } | |
| 1257 | − | |
| 1258 | − skb = dev_alloc_skb(WLAN_AUTH_CHALLENGE_LEN + | |
| 1259 | − ap->crypt->extra_mpdu_prefix_len + | |
| 1260 | − ap->crypt->extra_mpdu_postfix_len); | |
| 1261 | − if (skb == NULL) { | |
| 1262 | − kfree(tmpbuf); | |
| 1263 | − return NULL; | |
| 1264 | − } | |
| 1265 | − | |
| 1266 | − skb_reserve(skb, ap->crypt->extra_mpdu_prefix_len); | |
| 1267 | − skb_put_zero(skb, WLAN_AUTH_CHALLENGE_LEN); | |
| 1268 | − if (ap->crypt->encrypt_mpdu(skb, 0, ap->crypt_priv)) { | |
| 1269 | − dev_kfree_skb(skb); | |
| 1270 | − kfree(tmpbuf); | |
| 1271 | − return NULL; | |
| 1272 | − } | |
| 1273 | − | |
| 1274 | − skb_copy_from_linear_data_offset(skb, ap->crypt->extra_mpdu_prefix_len, | |
| 1275 | − tmpbuf, WLAN_AUTH_CHALLENGE_LEN); | |
| 1276 | − dev_kfree_skb(skb); | |
| 1277 | − | |
| 1278 | − return tmpbuf; | |
| 1279 | −} | |
| 1280 | − | |
| 1281 | − | |
| 1282 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1283 | −static void handle_authen(local_info_t *local, struct sk_buff *skb, | |
| 1284 | − struct hostap_80211_rx_status *rx_stats) | |
| 1285 | −{ | |
| 1286 | − struct net_device *dev = local->dev; | |
| 1287 | − struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
| 1288 | − size_t hdrlen; | |
| 1289 | − struct ap_data *ap = local->ap; | |
| 1290 | − char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL; | |
| 1291 | − int len, olen; | |
| 1292 | − u16 auth_alg, auth_transaction, status_code; | |
| 1293 | − __le16 *pos; | |
| 1294 | − u16 resp = WLAN_STATUS_SUCCESS; | |
| 1295 | − struct sta_info *sta = NULL; | |
| 1296 | − struct lib80211_crypt_data *crypt; | |
| 1297 | − char *txt = ""; | |
| 1298 | − | |
| 1299 | − len = skb->len - IEEE80211_MGMT_HDR_LEN; | |
| 1300 | − | |
| 1301 | − hdrlen = hostap_80211_get_hdrlen(hdr->frame_control); | |
| 1302 | − | |
| 1303 | − if (len < 6) { | |
| 1304 | − PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " | |
| 1305 | − "(len=%d) from %pM\n", dev->name, len, hdr->addr2); | |
| 1306 | − return; | |
| 1307 | − } | |
| 1308 | − | |
| 1309 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 1310 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 1311 | − if (sta) | |
| 1312 | − atomic_inc(&sta->users); | |
| 1313 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1314 | − | |
| 1315 | − if (sta && sta->crypt) | |
| 1316 | − crypt = sta->crypt; | |
| 1317 | − else { | |
| 1318 | − int idx = 0; | |
| 1319 | − if (skb->len >= hdrlen + 3) | |
| 1320 | − idx = skb->data[hdrlen + 3] >> 6; | |
| 1321 | − crypt = local->crypt_info.crypt[idx]; | |
| 1322 | − } | |
| 1323 | − | |
| 1324 | − pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | |
| 1325 | − auth_alg = __le16_to_cpu(*pos); | |
| 1326 | − pos++; | |
| 1327 | − auth_transaction = __le16_to_cpu(*pos); | |
| 1328 | − pos++; | |
| 1329 | − status_code = __le16_to_cpu(*pos); | |
| 1330 | − pos++; | |
| 1331 | − | |
| 1332 | − if (ether_addr_equal(dev->dev_addr, hdr->addr2) || | |
| 1333 | − ap_control_mac_deny(&ap->mac_restrictions, hdr->addr2)) { | |
| 1334 | − txt = "authentication denied"; | |
| 1335 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1336 | − goto fail; | |
| 1337 | − } | |
| 1338 | − | |
| 1339 | − if (((local->auth_algs & PRISM2_AUTH_OPEN) && | |
| 1340 | − auth_alg == WLAN_AUTH_OPEN) || | |
| 1341 | − ((local->auth_algs & PRISM2_AUTH_SHARED_KEY) && | |
| 1342 | − crypt && auth_alg == WLAN_AUTH_SHARED_KEY)) { | |
| 1343 | − } else { | |
| 1344 | − txt = "unsupported algorithm"; | |
| 1345 | − resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; | |
| 1346 | − goto fail; | |
| 1347 | − } | |
| 1348 | − | |
| 1349 | − if (len >= 8) { | |
| 1350 | − u8 *u = (u8 *) pos; | |
| 1351 | − if (*u == WLAN_EID_CHALLENGE) { | |
| 1352 | − if (*(u + 1) != WLAN_AUTH_CHALLENGE_LEN) { | |
| 1353 | − txt = "invalid challenge len"; | |
| 1354 | − resp = WLAN_STATUS_CHALLENGE_FAIL; | |
| 1355 | − goto fail; | |
| 1356 | − } | |
| 1357 | − if (len - 8 < WLAN_AUTH_CHALLENGE_LEN) { | |
| 1358 | − txt = "challenge underflow"; | |
| 1359 | − resp = WLAN_STATUS_CHALLENGE_FAIL; | |
| 1360 | − goto fail; | |
| 1361 | − } | |
| 1362 | − challenge = (char *) (u + 2); | |
| 1363 | − } | |
| 1364 | − } | |
| 1365 | − | |
| 1366 | − if (sta && sta->ap) { | |
| 1367 | − if (time_after(jiffies, sta->u.ap.last_beacon + | |
| 1368 | − (10 * sta->listen_interval * HZ) / 1024)) { | |
| 1369 | − PDEBUG(DEBUG_AP, "%s: no beacons received for a while," | |
| 1370 | − " assuming AP %pM is now STA\n", | |
| 1371 | − dev->name, sta->addr); | |
| 1372 | − sta->ap = 0; | |
| 1373 | − sta->flags = 0; | |
| 1374 | − sta->u.sta.challenge = NULL; | |
| 1375 | − } else { | |
| 1376 | − txt = "AP trying to authenticate?"; | |
| 1377 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1378 | − goto fail; | |
| 1379 | − } | |
| 1380 | − } | |
| 1381 | − | |
| 1382 | − if ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) || | |
| 1383 | − (auth_alg == WLAN_AUTH_SHARED_KEY && | |
| 1384 | − (auth_transaction == 1 || | |
| 1385 | − (auth_transaction == 3 && sta != NULL && | |
| 1386 | − sta->u.sta.challenge != NULL)))) { | |
| 1387 | − } else { | |
| 1388 | − txt = "unknown authentication transaction number"; | |
| 1389 | − resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; | |
| 1390 | − goto fail; | |
| 1391 | − } | |
| 1392 | − | |
| 1393 | − if (sta == NULL) { | |
| 1394 | − txt = "new STA"; | |
| 1395 | − | |
| 1396 | − if (local->ap->num_sta >= MAX_STA_COUNT) { | |
| 1397 | − /* FIX: might try to remove some old STAs first? */ | |
| 1398 | − txt = "no more room for new STAs"; | |
| 1399 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1400 | − goto fail; | |
| 1401 | − } | |
| 1402 | − | |
| 1403 | − sta = ap_add_sta(local->ap, hdr->addr2); | |
| 1404 | − if (sta == NULL) { | |
| 1405 | − txt = "ap_add_sta failed"; | |
| 1406 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1407 | − goto fail; | |
| 1408 | − } | |
| 1409 | − } | |
| 1410 | − | |
| 1411 | − switch (auth_alg) { | |
| 1412 | − case WLAN_AUTH_OPEN: | |
| 1413 | − txt = "authOK"; | |
| 1414 | − /* IEEE 802.11 standard is not completely clear about | |
| 1415 | − * whether STA is considered authenticated after | |
| 1416 | − * authentication OK frame has been send or after it | |
| 1417 | − * has been ACKed. In order to reduce interoperability | |
| 1418 | − * issues, mark the STA authenticated before ACK. */ | |
| 1419 | − sta->flags |= WLAN_STA_AUTH; | |
| 1420 | − break; | |
| 1421 | − | |
| 1422 | − case WLAN_AUTH_SHARED_KEY: | |
| 1423 | − if (auth_transaction == 1) { | |
| 1424 | − if (sta->u.sta.challenge == NULL) { | |
| 1425 | − sta->u.sta.challenge = | |
| 1426 | − ap_auth_make_challenge(local->ap); | |
| 1427 | − if (sta->u.sta.challenge == NULL) { | |
| 1428 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1429 | − goto fail; | |
| 1430 | − } | |
| 1431 | − } | |
| 1432 | − } else { | |
| 1433 | − if (sta->u.sta.challenge == NULL || | |
| 1434 | − challenge == NULL || | |
| 1435 | − memcmp(sta->u.sta.challenge, challenge, | |
| 1436 | − WLAN_AUTH_CHALLENGE_LEN) != 0 || | |
| 1437 | − !ieee80211_has_protected(hdr->frame_control)) { | |
| 1438 | − txt = "challenge response incorrect"; | |
| 1439 | − resp = WLAN_STATUS_CHALLENGE_FAIL; | |
| 1440 | − goto fail; | |
| 1441 | − } | |
| 1442 | − | |
| 1443 | − txt = "challenge OK - authOK"; | |
| 1444 | − /* IEEE 802.11 standard is not completely clear about | |
| 1445 | − * whether STA is considered authenticated after | |
| 1446 | − * authentication OK frame has been send or after it | |
| 1447 | − * has been ACKed. In order to reduce interoperability | |
| 1448 | − * issues, mark the STA authenticated before ACK. */ | |
| 1449 | − sta->flags |= WLAN_STA_AUTH; | |
| 1450 | − kfree(sta->u.sta.challenge); | |
| 1451 | − sta->u.sta.challenge = NULL; | |
| 1452 | − } | |
| 1453 | − break; | |
| 1454 | − } | |
| 1455 | − | |
| 1456 | − fail: | |
| 1457 | − pos = (__le16 *) body; | |
| 1458 | − *pos = cpu_to_le16(auth_alg); | |
| 1459 | − pos++; | |
| 1460 | − *pos = cpu_to_le16(auth_transaction + 1); | |
| 1461 | − pos++; | |
| 1462 | − *pos = cpu_to_le16(resp); /* status_code */ | |
| 1463 | − pos++; | |
| 1464 | − olen = 6; | |
| 1465 | − | |
| 1466 | − if (resp == WLAN_STATUS_SUCCESS && sta != NULL && | |
| 1467 | − sta->u.sta.challenge != NULL && | |
| 1468 | − auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 1) { | |
| 1469 | − u8 *tmp = (u8 *) pos; | |
| 1470 | − *tmp++ = WLAN_EID_CHALLENGE; | |
| 1471 | − *tmp++ = WLAN_AUTH_CHALLENGE_LEN; | |
| 1472 | − pos++; | |
| 1473 | − memcpy(pos, sta->u.sta.challenge, WLAN_AUTH_CHALLENGE_LEN); | |
| 1474 | − olen += 2 + WLAN_AUTH_CHALLENGE_LEN; | |
| 1475 | − } | |
| 1476 | − | |
| 1477 | − prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH, | |
| 1478 | − body, olen, hdr->addr2, ap->tx_callback_auth); | |
| 1479 | − | |
| 1480 | − if (sta) { | |
| 1481 | − sta->last_rx = jiffies; | |
| 1482 | − atomic_dec(&sta->users); | |
| 1483 | − } | |
| 1484 | − | |
| 1485 | − if (resp) { | |
| 1486 | − PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " | |
| 1487 | − "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", | |
| 1488 | − dev->name, hdr->addr2, | |
| 1489 | − auth_alg, auth_transaction, status_code, len, | |
| 1490 | − le16_to_cpu(hdr->frame_control), resp, txt); | |
| 1491 | − } | |
| 1492 | −} | |
| 1493 | − | |
| 1494 | − | |
| 1495 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1496 | −static void handle_assoc(local_info_t *local, struct sk_buff *skb, | |
| 1497 | − struct hostap_80211_rx_status *rx_stats, int reassoc) | |
| 1498 | −{ | |
| 1499 | − struct net_device *dev = local->dev; | |
| 1500 | − struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
| 1501 | − char body[12], *p, *lpos; | |
| 1502 | − int len, left; | |
| 1503 | − __le16 *pos; | |
| 1504 | − u16 resp = WLAN_STATUS_SUCCESS; | |
| 1505 | − struct sta_info *sta = NULL; | |
| 1506 | − int send_deauth = 0; | |
| 1507 | − char __always_unused *txt = ""; | |
| 1508 | − u8 prev_ap[ETH_ALEN]; | |
| 1509 | − | |
| 1510 | − left = len = skb->len - IEEE80211_MGMT_HDR_LEN; | |
| 1511 | − | |
| 1512 | − if (len < (reassoc ? 10 : 4)) { | |
| 1513 | − PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " | |
| 1514 | − "(len=%d, reassoc=%d) from %pM\n", | |
| 1515 | − dev->name, len, reassoc, hdr->addr2); | |
| 1516 | − return; | |
| 1517 | − } | |
| 1518 | − | |
| 1519 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 1520 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 1521 | − if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { | |
| 1522 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1523 | − txt = "trying to associate before authentication"; | |
| 1524 | − send_deauth = 1; | |
| 1525 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1526 | − sta = NULL; /* do not decrement sta->users */ | |
| 1527 | − goto fail; | |
| 1528 | − } | |
| 1529 | − atomic_inc(&sta->users); | |
| 1530 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1531 | − | |
| 1532 | − pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); | |
| 1533 | − sta->capability = __le16_to_cpu(*pos); | |
| 1534 | − pos++; left -= 2; | |
| 1535 | − sta->listen_interval = __le16_to_cpu(*pos); | |
| 1536 | − pos++; left -= 2; | |
| 1537 | − | |
| 1538 | − if (reassoc) { | |
| 1539 | − memcpy(prev_ap, pos, ETH_ALEN); | |
| 1540 | − pos++; pos++; pos++; left -= 6; | |
| 1541 | − } else | |
| 1542 | − eth_zero_addr(prev_ap); | |
| 1543 | − | |
| 1544 | − if (left >= 2) { | |
| 1545 | − unsigned int ileft; | |
| 1546 | − unsigned char *u = (unsigned char *) pos; | |
| 1547 | − | |
| 1548 | − if (*u == WLAN_EID_SSID) { | |
| 1549 | − u++; left--; | |
| 1550 | − ileft = *u; | |
| 1551 | − u++; left--; | |
| 1552 | − | |
| 1553 | − if (ileft > left || ileft > MAX_SSID_LEN) { | |
| 1554 | − txt = "SSID overflow"; | |
| 1555 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1556 | − goto fail; | |
| 1557 | − } | |
| 1558 | − | |
| 1559 | − if (ileft != strlen(local->essid) || | |
| 1560 | − memcmp(local->essid, u, ileft) != 0) { | |
| 1561 | − txt = "not our SSID"; | |
| 1562 | − resp = WLAN_STATUS_ASSOC_DENIED_UNSPEC; | |
| 1563 | − goto fail; | |
| 1564 | − } | |
| 1565 | − | |
| 1566 | − u += ileft; | |
| 1567 | − left -= ileft; | |
| 1568 | − } | |
| 1569 | − | |
| 1570 | − if (left >= 2 && *u == WLAN_EID_SUPP_RATES) { | |
| 1571 | − u++; left--; | |
| 1572 | − ileft = *u; | |
| 1573 | − u++; left--; | |
| 1574 | − | |
| 1575 | − if (ileft > left || ileft == 0 || | |
| 1576 | − ileft > WLAN_SUPP_RATES_MAX) { | |
| 1577 | − txt = "SUPP_RATES len error"; | |
| 1578 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1579 | − goto fail; | |
| 1580 | − } | |
| 1581 | − | |
| 1582 | − memset(sta->supported_rates, 0, | |
| 1583 | − sizeof(sta->supported_rates)); | |
| 1584 | − memcpy(sta->supported_rates, u, ileft); | |
| 1585 | − prism2_check_tx_rates(sta); | |
| 1586 | − | |
| 1587 | − u += ileft; | |
| 1588 | − left -= ileft; | |
| 1589 | − } | |
| 1590 | − | |
| 1591 | − if (left > 0) { | |
| 1592 | − PDEBUG(DEBUG_AP, "%s: assoc from %pM" | |
| 1593 | − " with extra data (%d bytes) [", | |
| 1594 | − dev->name, hdr->addr2, left); | |
| 1595 | − while (left > 0) { | |
| 1596 | − PDEBUG2(DEBUG_AP, "<%02x>", *u); | |
| 1597 | − u++; left--; | |
| 1598 | − } | |
| 1599 | − PDEBUG2(DEBUG_AP, "]\n"); | |
| 1600 | − } | |
| 1601 | − } else { | |
| 1602 | − txt = "frame underflow"; | |
| 1603 | − resp = WLAN_STATUS_UNSPECIFIED_FAILURE; | |
| 1604 | − goto fail; | |
| 1605 | − } | |
| 1606 | − | |
| 1607 | − /* get a unique AID */ | |
| 1608 | − if (sta->aid > 0) | |
| 1609 | − txt = "OK, old AID"; | |
| 1610 | − else { | |
| 1611 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 1612 | − for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++) | |
| 1613 | − if (local->ap->sta_aid[sta->aid - 1] == NULL) | |
| 1614 | − break; | |
| 1615 | − if (sta->aid > MAX_AID_TABLE_SIZE) { | |
| 1616 | − sta->aid = 0; | |
| 1617 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1618 | − resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; | |
| 1619 | − txt = "no room for more AIDs"; | |
| 1620 | − } else { | |
| 1621 | − local->ap->sta_aid[sta->aid - 1] = sta; | |
| 1622 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1623 | − txt = "OK, new AID"; | |
| 1624 | − } | |
| 1625 | − } | |
| 1626 | − | |
| 1627 | − fail: | |
| 1628 | − pos = (__le16 *) body; | |
| 1629 | − | |
| 1630 | − if (send_deauth) { | |
| 1631 | − *pos = cpu_to_le16(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); | |
| 1632 | − pos++; | |
| 1633 | − } else { | |
| 1634 | − /* FIX: CF-Pollable and CF-PollReq should be set to match the | |
| 1635 | − * values in beacons/probe responses */ | |
| 1636 | − /* FIX: how about privacy and WEP? */ | |
| 1637 | − /* capability */ | |
| 1638 | − *pos = cpu_to_le16(WLAN_CAPABILITY_ESS); | |
| 1639 | − pos++; | |
| 1640 | − | |
| 1641 | − /* status_code */ | |
| 1642 | − *pos = cpu_to_le16(resp); | |
| 1643 | − pos++; | |
| 1644 | − | |
| 1645 | − *pos = cpu_to_le16((sta && sta->aid > 0 ? sta->aid : 0) | | |
| 1646 | − BIT(14) | BIT(15)); /* AID */ | |
| 1647 | − pos++; | |
| 1648 | − | |
| 1649 | − /* Supported rates (Information element) */ | |
| 1650 | − p = (char *) pos; | |
| 1651 | − *p++ = WLAN_EID_SUPP_RATES; | |
| 1652 | − lpos = p; | |
| 1653 | − *p++ = 0; /* len */ | |
| 1654 | − if (local->tx_rate_control & WLAN_RATE_1M) { | |
| 1655 | − *p++ = local->basic_rates & WLAN_RATE_1M ? 0x82 : 0x02; | |
| 1656 | − (*lpos)++; | |
| 1657 | − } | |
| 1658 | − if (local->tx_rate_control & WLAN_RATE_2M) { | |
| 1659 | − *p++ = local->basic_rates & WLAN_RATE_2M ? 0x84 : 0x04; | |
| 1660 | − (*lpos)++; | |
| 1661 | − } | |
| 1662 | − if (local->tx_rate_control & WLAN_RATE_5M5) { | |
| 1663 | − *p++ = local->basic_rates & WLAN_RATE_5M5 ? | |
| 1664 | − 0x8b : 0x0b; | |
| 1665 | − (*lpos)++; | |
| 1666 | − } | |
| 1667 | − if (local->tx_rate_control & WLAN_RATE_11M) { | |
| 1668 | − *p++ = local->basic_rates & WLAN_RATE_11M ? | |
| 1669 | − 0x96 : 0x16; | |
| 1670 | − (*lpos)++; | |
| 1671 | − } | |
| 1672 | − pos = (__le16 *) p; | |
| 1673 | − } | |
| 1674 | − | |
| 1675 | − prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | |
| 1676 | − (send_deauth ? IEEE80211_STYPE_DEAUTH : | |
| 1677 | − (reassoc ? IEEE80211_STYPE_REASSOC_RESP : | |
| 1678 | − IEEE80211_STYPE_ASSOC_RESP)), | |
| 1679 | − body, (u8 *) pos - (u8 *) body, | |
| 1680 | − hdr->addr2, | |
| 1681 | − send_deauth ? 0 : local->ap->tx_callback_assoc); | |
| 1682 | − | |
| 1683 | − if (sta) { | |
| 1684 | − if (resp == WLAN_STATUS_SUCCESS) { | |
| 1685 | − sta->last_rx = jiffies; | |
| 1686 | − /* STA will be marked associated from TX callback, if | |
| 1687 | − * AssocResp is ACKed */ | |
| 1688 | − } | |
| 1689 | − atomic_dec(&sta->users); | |
| 1690 | − } | |
| 1691 | − | |
| 1692 | −#if 0 | |
| 1693 | − PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " | |
| 1694 | − "prev_ap=%pM) => %d(%d) (%s)\n", | |
| 1695 | − dev->name, | |
| 1696 | − hdr->addr2, | |
| 1697 | − reassoc ? "re" : "", len, | |
| 1698 | − prev_ap, | |
| 1699 | − resp, send_deauth, txt); | |
| 1700 | −#endif | |
| 1701 | −} | |
| 1702 | − | |
| 1703 | − | |
| 1704 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1705 | −static void handle_deauth(local_info_t *local, struct sk_buff *skb, | |
| 1706 | − struct hostap_80211_rx_status *rx_stats) | |
| 1707 | −{ | |
| 1708 | − struct net_device *dev = local->dev; | |
| 1709 | − struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
| 1710 | − char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN); | |
| 1711 | − int len; | |
| 1712 | − u16 reason_code; | |
| 1713 | − __le16 *pos; | |
| 1714 | − struct sta_info *sta = NULL; | |
| 1715 | − | |
| 1716 | − len = skb->len - IEEE80211_MGMT_HDR_LEN; | |
| 1717 | − | |
| 1718 | − if (len < 2) { | |
| 1719 | − printk("handle_deauth - too short payload (len=%d)\n", len); | |
| 1720 | − return; | |
| 1721 | − } | |
| 1722 | − | |
| 1723 | − pos = (__le16 *) body; | |
| 1724 | − reason_code = le16_to_cpu(*pos); | |
| 1725 | − | |
| 1726 | − PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " | |
| 1727 | − "reason_code=%d\n", dev->name, hdr->addr2, | |
| 1728 | − len, reason_code); | |
| 1729 | − | |
| 1730 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 1731 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 1732 | − if (sta != NULL) { | |
| 1733 | − if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | |
| 1734 | − hostap_event_expired_sta(local->dev, sta); | |
| 1735 | − sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); | |
| 1736 | − } | |
| 1737 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1738 | − if (sta == NULL) { | |
| 1739 | − printk("%s: deauthentication from %pM, " | |
| 1740 | − "reason_code=%d, but STA not authenticated\n", dev->name, | |
| 1741 | − hdr->addr2, reason_code); | |
| 1742 | − } | |
| 1743 | −} | |
| 1744 | − | |
| 1745 | − | |
| 1746 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1747 | −static void handle_disassoc(local_info_t *local, struct sk_buff *skb, | |
| 1748 | − struct hostap_80211_rx_status *rx_stats) | |
| 1749 | −{ | |
| 1750 | − struct net_device *dev = local->dev; | |
| 1751 | − struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
| 1752 | − char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | |
| 1753 | − int len; | |
| 1754 | − u16 reason_code; | |
| 1755 | − __le16 *pos; | |
| 1756 | − struct sta_info *sta = NULL; | |
| 1757 | − | |
| 1758 | − len = skb->len - IEEE80211_MGMT_HDR_LEN; | |
| 1759 | − | |
| 1760 | − if (len < 2) { | |
| 1761 | − printk("handle_disassoc - too short payload (len=%d)\n", len); | |
| 1762 | − return; | |
| 1763 | − } | |
| 1764 | − | |
| 1765 | − pos = (__le16 *) body; | |
| 1766 | − reason_code = le16_to_cpu(*pos); | |
| 1767 | − | |
| 1768 | − PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " | |
| 1769 | − "reason_code=%d\n", dev->name, hdr->addr2, | |
| 1770 | − len, reason_code); | |
| 1771 | − | |
| 1772 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 1773 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 1774 | − if (sta != NULL) { | |
| 1775 | − if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap) | |
| 1776 | − hostap_event_expired_sta(local->dev, sta); | |
| 1777 | − sta->flags &= ~WLAN_STA_ASSOC; | |
| 1778 | − } | |
| 1779 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1780 | − if (sta == NULL) { | |
| 1781 | − printk("%s: disassociation from %pM, " | |
| 1782 | − "reason_code=%d, but STA not authenticated\n", | |
| 1783 | − dev->name, hdr->addr2, reason_code); | |
| 1784 | − } | |
| 1785 | −} | |
| 1786 | − | |
| 1787 | − | |
| 1788 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1789 | −static void ap_handle_data_nullfunc(local_info_t *local, | |
| 1790 | − struct ieee80211_hdr *hdr) | |
| 1791 | −{ | |
| 1792 | − struct net_device *dev = local->dev; | |
| 1793 | − | |
| 1794 | − /* some STA f/w's seem to require control::ACK frame for | |
| 1795 | − * data::nullfunc, but at least Prism2 station f/w version 0.8.0 does | |
| 1796 | − * not send this.. | |
| 1797 | − * send control::ACK for the data::nullfunc */ | |
| 1798 | − | |
| 1799 | − printk(KERN_DEBUG "Sending control::ACK for data::nullfunc\n"); | |
| 1800 | − prism2_send_mgmt(dev, IEEE80211_FTYPE_CTL | IEEE80211_STYPE_ACK, | |
| 1801 | − NULL, 0, hdr->addr2, 0); | |
| 1802 | −} | |
| 1803 | − | |
| 1804 | − | |
| 1805 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1806 | −static void ap_handle_dropped_data(local_info_t *local, | |
| 1807 | − struct ieee80211_hdr *hdr) | |
| 1808 | −{ | |
| 1809 | − struct net_device *dev = local->dev; | |
| 1810 | − struct sta_info *sta; | |
| 1811 | − __le16 reason; | |
| 1812 | − | |
| 1813 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 1814 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 1815 | − if (sta) | |
| 1816 | − atomic_inc(&sta->users); | |
| 1817 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1818 | − | |
| 1819 | − if (sta != NULL && (sta->flags & WLAN_STA_ASSOC)) { | |
| 1820 | − PDEBUG(DEBUG_AP, "ap_handle_dropped_data: STA is now okay?\n"); | |
| 1821 | − atomic_dec(&sta->users); | |
| 1822 | − return; | |
| 1823 | − } | |
| 1824 | − | |
| 1825 | − reason = cpu_to_le16(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); | |
| 1826 | − prism2_send_mgmt(dev, IEEE80211_FTYPE_MGMT | | |
| 1827 | − ((sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) ? | |
| 1828 | − IEEE80211_STYPE_DEAUTH : IEEE80211_STYPE_DISASSOC), | |
| 1829 | − (char *) &reason, sizeof(reason), hdr->addr2, 0); | |
| 1830 | − | |
| 1831 | − if (sta) | |
| 1832 | − atomic_dec(&sta->users); | |
| 1833 | −} | |
| 1834 | − | |
| 1835 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 1836 | − | |
| 1837 | − | |
| 1838 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1839 | −static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta, | |
| 1840 | − struct sk_buff *skb) | |
| 1841 | −{ | |
| 1842 | − struct hostap_skb_tx_data *meta; | |
| 1843 | − | |
| 1844 | − if (!(sta->flags & WLAN_STA_PS)) { | |
| 1845 | − /* Station has moved to non-PS mode, so send all buffered | |
| 1846 | − * frames using normal device queue. */ | |
| 1847 | − dev_queue_xmit(skb); | |
| 1848 | − return; | |
| 1849 | − } | |
| 1850 | − | |
| 1851 | − /* add a flag for hostap_handle_sta_tx() to know that this skb should | |
| 1852 | − * be passed through even though STA is using PS */ | |
| 1853 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 1854 | − meta->flags |= HOSTAP_TX_FLAGS_BUFFERED_FRAME; | |
| 1855 | − if (!skb_queue_empty(&sta->tx_buf)) { | |
| 1856 | − /* indicate to STA that more frames follow */ | |
| 1857 | − meta->flags |= HOSTAP_TX_FLAGS_ADD_MOREDATA; | |
| 1858 | − } | |
| 1859 | − dev_queue_xmit(skb); | |
| 1860 | −} | |
| 1861 | − | |
| 1862 | − | |
| 1863 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1864 | −static void handle_pspoll(local_info_t *local, | |
| 1865 | − struct ieee80211_hdr *hdr, | |
| 1866 | − struct hostap_80211_rx_status *rx_stats) | |
| 1867 | −{ | |
| 1868 | − struct net_device *dev = local->dev; | |
| 1869 | − struct sta_info *sta; | |
| 1870 | − u16 aid; | |
| 1871 | − struct sk_buff *skb; | |
| 1872 | − | |
| 1873 | − PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", | |
| 1874 | − hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control)); | |
| 1875 | − | |
| 1876 | − if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { | |
| 1877 | − PDEBUG(DEBUG_AP, | |
| 1878 | − "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", | |
| 1879 | − hdr->addr1); | |
| 1880 | − return; | |
| 1881 | − } | |
| 1882 | − | |
| 1883 | − aid = le16_to_cpu(hdr->duration_id); | |
| 1884 | − if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) { | |
| 1885 | − PDEBUG(DEBUG_PS, " PSPOLL and AID[15:14] not set\n"); | |
| 1886 | − return; | |
| 1887 | − } | |
| 1888 | − aid &= ~(BIT(15) | BIT(14)); | |
| 1889 | − if (aid == 0 || aid > MAX_AID_TABLE_SIZE) { | |
| 1890 | − PDEBUG(DEBUG_PS, " invalid aid=%d\n", aid); | |
| 1891 | − return; | |
| 1892 | − } | |
| 1893 | − PDEBUG(DEBUG_PS2, " aid=%d\n", aid); | |
| 1894 | − | |
| 1895 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 1896 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 1897 | − if (sta) | |
| 1898 | − atomic_inc(&sta->users); | |
| 1899 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 1900 | − | |
| 1901 | − if (sta == NULL) { | |
| 1902 | − PDEBUG(DEBUG_PS, " STA not found\n"); | |
| 1903 | − return; | |
| 1904 | − } | |
| 1905 | − if (sta->aid != aid) { | |
| 1906 | − PDEBUG(DEBUG_PS, " received aid=%i does not match with " | |
| 1907 | − "assoc.aid=%d\n", aid, sta->aid); | |
| 1908 | − return; | |
| 1909 | − } | |
| 1910 | − | |
| 1911 | − /* FIX: todo: | |
| 1912 | − * - add timeout for buffering (clear aid in TIM vector if buffer timed | |
| 1913 | − * out (expiry time must be longer than ListenInterval for | |
| 1914 | − * the corresponding STA; "8802-11: 11.2.1.9 AP aging function" | |
| 1915 | − * - what to do, if buffered, pspolled, and sent frame is not ACKed by | |
| 1916 | − * sta; store buffer for later use and leave TIM aid bit set? use | |
| 1917 | − * TX event to check whether frame was ACKed? | |
| 1918 | − */ | |
| 1919 | − | |
| 1920 | − while ((skb = skb_dequeue(&sta->tx_buf)) != NULL) { | |
| 1921 | − /* send buffered frame .. */ | |
| 1922 | − PDEBUG(DEBUG_PS2, "Sending buffered frame to STA after PS POLL" | |
| 1923 | − " (buffer_count=%d)\n", skb_queue_len(&sta->tx_buf)); | |
| 1924 | − | |
| 1925 | − pspoll_send_buffered(local, sta, skb); | |
| 1926 | − | |
| 1927 | − if (sta->flags & WLAN_STA_PS) { | |
| 1928 | − /* send only one buffered packet per PS Poll */ | |
| 1929 | − /* FIX: should ignore further PS Polls until the | |
| 1930 | − * buffered packet that was just sent is acknowledged | |
| 1931 | − * (Tx or TxExc event) */ | |
| 1932 | − break; | |
| 1933 | − } | |
| 1934 | − } | |
| 1935 | − | |
| 1936 | − if (skb_queue_empty(&sta->tx_buf)) { | |
| 1937 | − /* try to clear aid from TIM */ | |
| 1938 | − if (!(sta->flags & WLAN_STA_TIM)) | |
| 1939 | − PDEBUG(DEBUG_PS2, "Re-unsetting TIM for aid %d\n", | |
| 1940 | − aid); | |
| 1941 | − hostap_set_tim(local, aid, 0); | |
| 1942 | − sta->flags &= ~WLAN_STA_TIM; | |
| 1943 | − } | |
| 1944 | − | |
| 1945 | − atomic_dec(&sta->users); | |
| 1946 | −} | |
| 1947 | − | |
| 1948 | − | |
| 1949 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 1950 | − | |
| 1951 | −static void handle_wds_oper_queue(struct work_struct *work) | |
| 1952 | −{ | |
| 1953 | − struct ap_data *ap = container_of(work, struct ap_data, | |
| 1954 | − wds_oper_queue); | |
| 1955 | − local_info_t *local = ap->local; | |
| 1956 | − struct wds_oper_data *entry, *prev; | |
| 1957 | − | |
| 1958 | − spin_lock_bh(&local->lock); | |
| 1959 | − entry = local->ap->wds_oper_entries; | |
| 1960 | − local->ap->wds_oper_entries = NULL; | |
| 1961 | − spin_unlock_bh(&local->lock); | |
| 1962 | − | |
| 1963 | − while (entry) { | |
| 1964 | − PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " | |
| 1965 | − "to AP %pM\n", | |
| 1966 | − local->dev->name, | |
| 1967 | − entry->type == WDS_ADD ? "adding" : "removing", | |
| 1968 | − entry->addr); | |
| 1969 | − if (entry->type == WDS_ADD) | |
| 1970 | − prism2_wds_add(local, entry->addr, 0); | |
| 1971 | − else if (entry->type == WDS_DEL) | |
| 1972 | − prism2_wds_del(local, entry->addr, 0, 1); | |
| 1973 | − | |
| 1974 | − prev = entry; | |
| 1975 | − entry = entry->next; | |
| 1976 | − kfree(prev); | |
| 1977 | − } | |
| 1978 | −} | |
| 1979 | − | |
| 1980 | − | |
| 1981 | −/* Called only as a scheduled task for pending AP frames. */ | |
| 1982 | −static void handle_beacon(local_info_t *local, struct sk_buff *skb, | |
| 1983 | − struct hostap_80211_rx_status *rx_stats) | |
| 1984 | −{ | |
| 1985 | − struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | |
| 1986 | − char *body = skb->data + IEEE80211_MGMT_HDR_LEN; | |
| 1987 | − int len, left; | |
| 1988 | − u16 beacon_int, capability; | |
| 1989 | − __le16 *pos; | |
| 1990 | − char *ssid = NULL; | |
| 1991 | − unsigned char *supp_rates = NULL; | |
| 1992 | − int ssid_len = 0, supp_rates_len = 0; | |
| 1993 | − struct sta_info *sta = NULL; | |
| 1994 | − int new_sta = 0, channel = -1; | |
| 1995 | − | |
| 1996 | − len = skb->len - IEEE80211_MGMT_HDR_LEN; | |
| 1997 | − | |
| 1998 | − if (len < 8 + 2 + 2) { | |
| 1999 | − printk(KERN_DEBUG "handle_beacon - too short payload " | |
| 2000 | − "(len=%d)\n", len); | |
| 2001 | − return; | |
| 2002 | − } | |
| 2003 | − | |
| 2004 | − pos = (__le16 *) body; | |
| 2005 | − left = len; | |
| 2006 | − | |
| 2007 | − /* Timestamp (8 octets) */ | |
| 2008 | − pos += 4; left -= 8; | |
| 2009 | − /* Beacon interval (2 octets) */ | |
| 2010 | − beacon_int = le16_to_cpu(*pos); | |
| 2011 | − pos++; left -= 2; | |
| 2012 | − /* Capability information (2 octets) */ | |
| 2013 | − capability = le16_to_cpu(*pos); | |
| 2014 | − pos++; left -= 2; | |
| 2015 | − | |
| 2016 | − if (local->ap->ap_policy != AP_OTHER_AP_EVEN_IBSS && | |
| 2017 | − capability & WLAN_CAPABILITY_IBSS) | |
| 2018 | − return; | |
| 2019 | − | |
| 2020 | − if (left >= 2) { | |
| 2021 | − unsigned int ileft; | |
| 2022 | − unsigned char *u = (unsigned char *) pos; | |
| 2023 | − | |
| 2024 | − if (*u == WLAN_EID_SSID) { | |
| 2025 | − u++; left--; | |
| 2026 | − ileft = *u; | |
| 2027 | − u++; left--; | |
| 2028 | − | |
| 2029 | − if (ileft > left || ileft > MAX_SSID_LEN) { | |
| 2030 | − PDEBUG(DEBUG_AP, "SSID: overflow\n"); | |
| 2031 | − return; | |
| 2032 | − } | |
| 2033 | − | |
| 2034 | − if (local->ap->ap_policy == AP_OTHER_AP_SAME_SSID && | |
| 2035 | − (ileft != strlen(local->essid) || | |
| 2036 | − memcmp(local->essid, u, ileft) != 0)) { | |
| 2037 | − /* not our SSID */ | |
| 2038 | − return; | |
| 2039 | − } | |
| 2040 | − | |
| 2041 | − ssid = u; | |
| 2042 | − ssid_len = ileft; | |
| 2043 | − | |
| 2044 | − u += ileft; | |
| 2045 | − left -= ileft; | |
| 2046 | − } | |
| 2047 | − | |
| 2048 | − if (*u == WLAN_EID_SUPP_RATES) { | |
| 2049 | − u++; left--; | |
| 2050 | − ileft = *u; | |
| 2051 | − u++; left--; | |
| 2052 | − | |
| 2053 | − if (ileft > left || ileft == 0 || ileft > 8) { | |
| 2054 | − PDEBUG(DEBUG_AP, " - SUPP_RATES len error\n"); | |
| 2055 | − return; | |
| 2056 | − } | |
| 2057 | − | |
| 2058 | − supp_rates = u; | |
| 2059 | − supp_rates_len = ileft; | |
| 2060 | − | |
| 2061 | − u += ileft; | |
| 2062 | − left -= ileft; | |
| 2063 | − } | |
| 2064 | − | |
| 2065 | − if (*u == WLAN_EID_DS_PARAMS) { | |
| 2066 | − u++; left--; | |
| 2067 | − ileft = *u; | |
| 2068 | − u++; left--; | |
| 2069 | − | |
| 2070 | − if (ileft > left || ileft != 1) { | |
| 2071 | − PDEBUG(DEBUG_AP, " - DS_PARAMS len error\n"); | |
| 2072 | − return; | |
| 2073 | − } | |
| 2074 | − | |
| 2075 | − channel = *u; | |
| 2076 | − | |
| 2077 | − u += ileft; | |
| 2078 | − left -= ileft; | |
| 2079 | − } | |
| 2080 | − } | |
| 2081 | − | |
| 2082 | − spin_lock_bh(&local->ap->sta_table_lock); | |
| 2083 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 2084 | − if (sta != NULL) | |
| 2085 | − atomic_inc(&sta->users); | |
| 2086 | − spin_unlock_bh(&local->ap->sta_table_lock); | |
| 2087 | − | |
| 2088 | − if (sta == NULL) { | |
| 2089 | − /* add new AP */ | |
| 2090 | − new_sta = 1; | |
| 2091 | − sta = ap_add_sta(local->ap, hdr->addr2); | |
| 2092 | − if (sta == NULL) { | |
| 2093 | − printk(KERN_INFO "prism2: kmalloc failed for AP " | |
| 2094 | − "data structure\n"); | |
| 2095 | − return; | |
| 2096 | − } | |
| 2097 | − hostap_event_new_sta(local->dev, sta); | |
| 2098 | − | |
| 2099 | − /* mark APs authentication and associated for pseudo ad-hoc | |
| 2100 | − * style communication */ | |
| 2101 | − sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | |
| 2102 | − | |
| 2103 | − if (local->ap->autom_ap_wds) { | |
| 2104 | − hostap_wds_link_oper(local, sta->addr, WDS_ADD); | |
| 2105 | − } | |
| 2106 | − } | |
| 2107 | − | |
| 2108 | − sta->ap = 1; | |
| 2109 | − if (ssid) { | |
| 2110 | − sta->u.ap.ssid_len = ssid_len; | |
| 2111 | − memcpy(sta->u.ap.ssid, ssid, ssid_len); | |
| 2112 | − sta->u.ap.ssid[ssid_len] = '\0'; | |
| 2113 | − } else { | |
| 2114 | − sta->u.ap.ssid_len = 0; | |
| 2115 | − sta->u.ap.ssid[0] = '\0'; | |
| 2116 | − } | |
| 2117 | − sta->u.ap.channel = channel; | |
| 2118 | − sta->rx_packets++; | |
| 2119 | − sta->rx_bytes += len; | |
| 2120 | − sta->u.ap.last_beacon = sta->last_rx = jiffies; | |
| 2121 | − sta->capability = capability; | |
| 2122 | − sta->listen_interval = beacon_int; | |
| 2123 | − | |
| 2124 | − atomic_dec(&sta->users); | |
| 2125 | − | |
| 2126 | − if (new_sta) { | |
| 2127 | − memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | |
| 2128 | − memcpy(sta->supported_rates, supp_rates, supp_rates_len); | |
| 2129 | − prism2_check_tx_rates(sta); | |
| 2130 | − } | |
| 2131 | −} | |
| 2132 | − | |
| 2133 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 2134 | − | |
| 2135 | − | |
| 2136 | −/* Called only as a tasklet. */ | |
| 2137 | −static void handle_ap_item(local_info_t *local, struct sk_buff *skb, | |
| 2138 | − struct hostap_80211_rx_status *rx_stats) | |
| 2139 | −{ | |
| 2140 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 2141 | − struct net_device *dev = local->dev; | |
| 2142 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 2143 | − u16 fc, type, stype; | |
| 2144 | − struct ieee80211_hdr *hdr; | |
| 2145 | − | |
| 2146 | − /* FIX: should give skb->len to handler functions and check that the | |
| 2147 | − * buffer is long enough */ | |
| 2148 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 2149 | − fc = le16_to_cpu(hdr->frame_control); | |
| 2150 | − type = fc & IEEE80211_FCTL_FTYPE; | |
| 2151 | − stype = fc & IEEE80211_FCTL_STYPE; | |
| 2152 | − | |
| 2153 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 2154 | − if (!local->hostapd && type == IEEE80211_FTYPE_DATA) { | |
| 2155 | − PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); | |
| 2156 | − | |
| 2157 | − if (!(fc & IEEE80211_FCTL_TODS) || | |
| 2158 | − (fc & IEEE80211_FCTL_FROMDS)) { | |
| 2159 | − if (stype == IEEE80211_STYPE_NULLFUNC) { | |
| 2160 | − /* no ToDS nullfunc seems to be used to check | |
| 2161 | − * AP association; so send reject message to | |
| 2162 | − * speed up re-association */ | |
| 2163 | − ap_handle_dropped_data(local, hdr); | |
| 2164 | − goto done; | |
| 2165 | − } | |
| 2166 | − PDEBUG(DEBUG_AP, " not ToDS frame (fc=0x%04x)\n", | |
| 2167 | − fc); | |
| 2168 | − goto done; | |
| 2169 | − } | |
| 2170 | − | |
| 2171 | − if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { | |
| 2172 | − PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" | |
| 2173 | − " not own MAC\n", hdr->addr1); | |
| 2174 | − goto done; | |
| 2175 | − } | |
| 2176 | − | |
| 2177 | − if (local->ap->nullfunc_ack && | |
| 2178 | − stype == IEEE80211_STYPE_NULLFUNC) | |
| 2179 | − ap_handle_data_nullfunc(local, hdr); | |
| 2180 | − else | |
| 2181 | − ap_handle_dropped_data(local, hdr); | |
| 2182 | − goto done; | |
| 2183 | − } | |
| 2184 | − | |
| 2185 | − if (type == IEEE80211_FTYPE_MGMT && stype == IEEE80211_STYPE_BEACON) { | |
| 2186 | − handle_beacon(local, skb, rx_stats); | |
| 2187 | − goto done; | |
| 2188 | − } | |
| 2189 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 2190 | − | |
| 2191 | − if (type == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL) { | |
| 2192 | − handle_pspoll(local, hdr, rx_stats); | |
| 2193 | − goto done; | |
| 2194 | − } | |
| 2195 | − | |
| 2196 | − if (local->hostapd) { | |
| 2197 | − PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " | |
| 2198 | − "subtype=0x%02x\n", type, stype); | |
| 2199 | − goto done; | |
| 2200 | − } | |
| 2201 | − | |
| 2202 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 2203 | − if (type != IEEE80211_FTYPE_MGMT) { | |
| 2204 | − PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); | |
| 2205 | − goto done; | |
| 2206 | − } | |
| 2207 | − | |
| 2208 | − if (!ether_addr_equal(hdr->addr1, dev->dev_addr)) { | |
| 2209 | − PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" | |
| 2210 | − " not own MAC\n", hdr->addr1); | |
| 2211 | − goto done; | |
| 2212 | − } | |
| 2213 | − | |
| 2214 | − if (!ether_addr_equal(hdr->addr3, dev->dev_addr)) { | |
| 2215 | − PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" | |
| 2216 | − " not own MAC\n", hdr->addr3); | |
| 2217 | − goto done; | |
| 2218 | − } | |
| 2219 | − | |
| 2220 | − switch (stype) { | |
| 2221 | − case IEEE80211_STYPE_ASSOC_REQ: | |
| 2222 | − handle_assoc(local, skb, rx_stats, 0); | |
| 2223 | − break; | |
| 2224 | − case IEEE80211_STYPE_ASSOC_RESP: | |
| 2225 | − PDEBUG(DEBUG_AP, "==> ASSOC RESP (ignored)\n"); | |
| 2226 | − break; | |
| 2227 | − case IEEE80211_STYPE_REASSOC_REQ: | |
| 2228 | − handle_assoc(local, skb, rx_stats, 1); | |
| 2229 | − break; | |
| 2230 | − case IEEE80211_STYPE_REASSOC_RESP: | |
| 2231 | − PDEBUG(DEBUG_AP, "==> REASSOC RESP (ignored)\n"); | |
| 2232 | − break; | |
| 2233 | − case IEEE80211_STYPE_ATIM: | |
| 2234 | − PDEBUG(DEBUG_AP, "==> ATIM (ignored)\n"); | |
| 2235 | − break; | |
| 2236 | − case IEEE80211_STYPE_DISASSOC: | |
| 2237 | − handle_disassoc(local, skb, rx_stats); | |
| 2238 | − break; | |
| 2239 | − case IEEE80211_STYPE_AUTH: | |
| 2240 | − handle_authen(local, skb, rx_stats); | |
| 2241 | − break; | |
| 2242 | − case IEEE80211_STYPE_DEAUTH: | |
| 2243 | − handle_deauth(local, skb, rx_stats); | |
| 2244 | − break; | |
| 2245 | − default: | |
| 2246 | − PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", | |
| 2247 | − stype >> 4); | |
| 2248 | − break; | |
| 2249 | − } | |
| 2250 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 2251 | − | |
| 2252 | − done: | |
| 2253 | − dev_kfree_skb(skb); | |
| 2254 | −} | |
| 2255 | − | |
| 2256 | − | |
| 2257 | −/* Called only as a tasklet (software IRQ) */ | |
| 2258 | −void hostap_rx(struct net_device *dev, struct sk_buff *skb, | |
| 2259 | − struct hostap_80211_rx_status *rx_stats) | |
| 2260 | −{ | |
| 2261 | − struct hostap_interface *iface; | |
| 2262 | − local_info_t *local; | |
| 2263 | − struct ieee80211_hdr *hdr; | |
| 2264 | − | |
| 2265 | − iface = netdev_priv(dev); | |
| 2266 | − local = iface->local; | |
| 2267 | − | |
| 2268 | − if (skb->len < 16) | |
| 2269 | − goto drop; | |
| 2270 | − | |
| 2271 | − dev->stats.rx_packets++; | |
| 2272 | − | |
| 2273 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 2274 | − | |
| 2275 | − if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL && | |
| 2276 | − ieee80211_is_beacon(hdr->frame_control)) | |
| 2277 | − goto drop; | |
| 2278 | − | |
| 2279 | − skb->protocol = cpu_to_be16(ETH_P_HOSTAP); | |
| 2280 | − handle_ap_item(local, skb, rx_stats); | |
| 2281 | − return; | |
| 2282 | − | |
| 2283 | − drop: | |
| 2284 | − dev_kfree_skb(skb); | |
| 2285 | −} | |
| 2286 | − | |
| 2287 | − | |
| 2288 | −/* Called only as a tasklet (software IRQ) */ | |
| 2289 | −static void schedule_packet_send(local_info_t *local, struct sta_info *sta) | |
| 2290 | −{ | |
| 2291 | − struct sk_buff *skb; | |
| 2292 | − struct ieee80211_hdr *hdr; | |
| 2293 | − struct hostap_80211_rx_status rx_stats; | |
| 2294 | − | |
| 2295 | − if (skb_queue_empty(&sta->tx_buf)) | |
| 2296 | − return; | |
| 2297 | − | |
| 2298 | − skb = dev_alloc_skb(16); | |
| 2299 | − if (skb == NULL) { | |
| 2300 | − printk(KERN_DEBUG "%s: schedule_packet_send: skb alloc " | |
| 2301 | − "failed\n", local->dev->name); | |
| 2302 | − return; | |
| 2303 | − } | |
| 2304 | − | |
| 2305 | − hdr = skb_put(skb, 16); | |
| 2306 | − | |
| 2307 | − /* Generate a fake pspoll frame to start packet delivery */ | |
| 2308 | − hdr->frame_control = cpu_to_le16( | |
| 2309 | − IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); | |
| 2310 | − memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN); | |
| 2311 | − memcpy(hdr->addr2, sta->addr, ETH_ALEN); | |
| 2312 | − hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); | |
| 2313 | − | |
| 2314 | − PDEBUG(DEBUG_PS2, | |
| 2315 | − "%s: Scheduling buffered packet delivery for STA %pM\n", | |
| 2316 | − local->dev->name, sta->addr); | |
| 2317 | − | |
| 2318 | − skb->dev = local->dev; | |
| 2319 | − | |
| 2320 | − memset(&rx_stats, 0, sizeof(rx_stats)); | |
| 2321 | − hostap_rx(local->dev, skb, &rx_stats); | |
| 2322 | −} | |
| 2323 | − | |
| 2324 | − | |
| 2325 | −int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], | |
| 2326 | − struct iw_quality qual[], int buf_size, | |
| 2327 | − int aplist) | |
| 2328 | −{ | |
| 2329 | − struct ap_data *ap = local->ap; | |
| 2330 | − struct list_head *ptr; | |
| 2331 | − int count = 0; | |
| 2332 | − | |
| 2333 | − spin_lock_bh(&ap->sta_table_lock); | |
| 2334 | − | |
| 2335 | − for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | |
| 2336 | − ptr = ptr->next) { | |
| 2337 | − struct sta_info *sta = (struct sta_info *) ptr; | |
| 2338 | − | |
| 2339 | − if (aplist && !sta->ap) | |
| 2340 | − continue; | |
| 2341 | − addr[count].sa_family = ARPHRD_ETHER; | |
| 2342 | − memcpy(addr[count].sa_data, sta->addr, ETH_ALEN); | |
| 2343 | − if (sta->last_rx_silence == 0) | |
| 2344 | − qual[count].qual = sta->last_rx_signal < 27 ? | |
| 2345 | − 0 : (sta->last_rx_signal - 27) * 92 / 127; | |
| 2346 | − else | |
| 2347 | − qual[count].qual = sta->last_rx_signal - | |
| 2348 | − sta->last_rx_silence - 35; | |
| 2349 | − qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | |
| 2350 | − qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | |
| 2351 | − qual[count].updated = sta->last_rx_updated; | |
| 2352 | − | |
| 2353 | − sta->last_rx_updated = IW_QUAL_DBM; | |
| 2354 | − | |
| 2355 | − count++; | |
| 2356 | − if (count >= buf_size) | |
| 2357 | − break; | |
| 2358 | − } | |
| 2359 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 2360 | − | |
| 2361 | − return count; | |
| 2362 | −} | |
| 2363 | − | |
| 2364 | − | |
| 2365 | −/* Translate our list of Access Points & Stations to a card independent | |
| 2366 | − * format that the Wireless Tools will understand - Jean II */ | |
| 2367 | −int prism2_ap_translate_scan(struct net_device *dev, | |
| 2368 | − struct iw_request_info *info, char *buffer) | |
| 2369 | −{ | |
| 2370 | − struct hostap_interface *iface; | |
| 2371 | − local_info_t *local; | |
| 2372 | − struct ap_data *ap; | |
| 2373 | − struct list_head *ptr; | |
| 2374 | − struct iw_event iwe; | |
| 2375 | − char *current_ev = buffer; | |
| 2376 | − char *end_buf = buffer + IW_SCAN_MAX_DATA; | |
| 2377 | −#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) | |
| 2378 | − char buf[64]; | |
| 2379 | −#endif | |
| 2380 | − | |
| 2381 | − iface = netdev_priv(dev); | |
| 2382 | − local = iface->local; | |
| 2383 | − ap = local->ap; | |
| 2384 | − | |
| 2385 | − spin_lock_bh(&ap->sta_table_lock); | |
| 2386 | − | |
| 2387 | − for (ptr = ap->sta_list.next; ptr != NULL && ptr != &ap->sta_list; | |
| 2388 | − ptr = ptr->next) { | |
| 2389 | − struct sta_info *sta = (struct sta_info *) ptr; | |
| 2390 | − | |
| 2391 | − /* First entry *MUST* be the AP MAC address */ | |
| 2392 | − memset(&iwe, 0, sizeof(iwe)); | |
| 2393 | − iwe.cmd = SIOCGIWAP; | |
| 2394 | − iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | |
| 2395 | − memcpy(iwe.u.ap_addr.sa_data, sta->addr, ETH_ALEN); | |
| 2396 | − iwe.len = IW_EV_ADDR_LEN; | |
| 2397 | − current_ev = iwe_stream_add_event(info, current_ev, end_buf, | |
| 2398 | − &iwe, IW_EV_ADDR_LEN); | |
| 2399 | − | |
| 2400 | − /* Use the mode to indicate if it's a station or | |
| 2401 | − * an Access Point */ | |
| 2402 | − memset(&iwe, 0, sizeof(iwe)); | |
| 2403 | − iwe.cmd = SIOCGIWMODE; | |
| 2404 | − if (sta->ap) | |
| 2405 | − iwe.u.mode = IW_MODE_MASTER; | |
| 2406 | − else | |
| 2407 | − iwe.u.mode = IW_MODE_INFRA; | |
| 2408 | − iwe.len = IW_EV_UINT_LEN; | |
| 2409 | − current_ev = iwe_stream_add_event(info, current_ev, end_buf, | |
| 2410 | − &iwe, IW_EV_UINT_LEN); | |
| 2411 | − | |
| 2412 | − /* Some quality */ | |
| 2413 | − memset(&iwe, 0, sizeof(iwe)); | |
| 2414 | − iwe.cmd = IWEVQUAL; | |
| 2415 | − if (sta->last_rx_silence == 0) | |
| 2416 | − iwe.u.qual.qual = sta->last_rx_signal < 27 ? | |
| 2417 | − 0 : (sta->last_rx_signal - 27) * 92 / 127; | |
| 2418 | − else | |
| 2419 | − iwe.u.qual.qual = sta->last_rx_signal - | |
| 2420 | − sta->last_rx_silence - 35; | |
| 2421 | − iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal); | |
| 2422 | − iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence); | |
| 2423 | − iwe.u.qual.updated = sta->last_rx_updated; | |
| 2424 | − iwe.len = IW_EV_QUAL_LEN; | |
| 2425 | − current_ev = iwe_stream_add_event(info, current_ev, end_buf, | |
| 2426 | − &iwe, IW_EV_QUAL_LEN); | |
| 2427 | − | |
| 2428 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 2429 | − if (sta->ap) { | |
| 2430 | − memset(&iwe, 0, sizeof(iwe)); | |
| 2431 | − iwe.cmd = SIOCGIWESSID; | |
| 2432 | − iwe.u.data.length = sta->u.ap.ssid_len; | |
| 2433 | − iwe.u.data.flags = 1; | |
| 2434 | − current_ev = iwe_stream_add_point(info, current_ev, | |
| 2435 | − end_buf, &iwe, | |
| 2436 | − sta->u.ap.ssid); | |
| 2437 | − | |
| 2438 | − memset(&iwe, 0, sizeof(iwe)); | |
| 2439 | − iwe.cmd = SIOCGIWENCODE; | |
| 2440 | − if (sta->capability & WLAN_CAPABILITY_PRIVACY) | |
| 2441 | − iwe.u.data.flags = | |
| 2442 | − IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | |
| 2443 | − else | |
| 2444 | − iwe.u.data.flags = IW_ENCODE_DISABLED; | |
| 2445 | − current_ev = iwe_stream_add_point(info, current_ev, | |
| 2446 | − end_buf, &iwe, | |
| 2447 | − sta->u.ap.ssid); | |
| 2448 | − | |
| 2449 | − if (sta->u.ap.channel > 0 && | |
| 2450 | − sta->u.ap.channel <= FREQ_COUNT) { | |
| 2451 | − memset(&iwe, 0, sizeof(iwe)); | |
| 2452 | − iwe.cmd = SIOCGIWFREQ; | |
| 2453 | − iwe.u.freq.m = freq_list[sta->u.ap.channel - 1] | |
| 2454 | − * 100000; | |
| 2455 | − iwe.u.freq.e = 1; | |
| 2456 | − current_ev = iwe_stream_add_event( | |
| 2457 | − info, current_ev, end_buf, &iwe, | |
| 2458 | − IW_EV_FREQ_LEN); | |
| 2459 | − } | |
| 2460 | − | |
| 2461 | − memset(&iwe, 0, sizeof(iwe)); | |
| 2462 | − iwe.cmd = IWEVCUSTOM; | |
| 2463 | − sprintf(buf, "beacon_interval=%d", | |
| 2464 | − sta->listen_interval); | |
| 2465 | − iwe.u.data.length = strlen(buf); | |
| 2466 | − current_ev = iwe_stream_add_point(info, current_ev, | |
| 2467 | − end_buf, &iwe, buf); | |
| 2468 | − } | |
| 2469 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 2470 | − | |
| 2471 | − sta->last_rx_updated = IW_QUAL_DBM; | |
| 2472 | − | |
| 2473 | − /* To be continued, we should make good use of IWEVCUSTOM */ | |
| 2474 | − } | |
| 2475 | − | |
| 2476 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 2477 | − | |
| 2478 | − return current_ev - buffer; | |
| 2479 | −} | |
| 2480 | − | |
| 2481 | − | |
| 2482 | −static int prism2_hostapd_add_sta(struct ap_data *ap, | |
| 2483 | − struct prism2_hostapd_param *param) | |
| 2484 | −{ | |
| 2485 | − struct sta_info *sta; | |
| 2486 | − | |
| 2487 | − spin_lock_bh(&ap->sta_table_lock); | |
| 2488 | − sta = ap_get_sta(ap, param->sta_addr); | |
| 2489 | − if (sta) | |
| 2490 | − atomic_inc(&sta->users); | |
| 2491 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 2492 | − | |
| 2493 | − if (sta == NULL) { | |
| 2494 | − sta = ap_add_sta(ap, param->sta_addr); | |
| 2495 | − if (sta == NULL) | |
| 2496 | − return -1; | |
| 2497 | − } | |
| 2498 | − | |
| 2499 | − if (!(sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | |
| 2500 | − hostap_event_new_sta(sta->local->dev, sta); | |
| 2501 | − | |
| 2502 | − sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; | |
| 2503 | − sta->last_rx = jiffies; | |
| 2504 | − sta->aid = param->u.add_sta.aid; | |
| 2505 | − sta->capability = param->u.add_sta.capability; | |
| 2506 | − sta->tx_supp_rates = param->u.add_sta.tx_supp_rates; | |
| 2507 | − if (sta->tx_supp_rates & WLAN_RATE_1M) | |
| 2508 | − sta->supported_rates[0] = 2; | |
| 2509 | − if (sta->tx_supp_rates & WLAN_RATE_2M) | |
| 2510 | − sta->supported_rates[1] = 4; | |
| 2511 | − if (sta->tx_supp_rates & WLAN_RATE_5M5) | |
| 2512 | − sta->supported_rates[2] = 11; | |
| 2513 | − if (sta->tx_supp_rates & WLAN_RATE_11M) | |
| 2514 | − sta->supported_rates[3] = 22; | |
| 2515 | − prism2_check_tx_rates(sta); | |
| 2516 | − atomic_dec(&sta->users); | |
| 2517 | − return 0; | |
| 2518 | −} | |
| 2519 | − | |
| 2520 | − | |
| 2521 | −static int prism2_hostapd_remove_sta(struct ap_data *ap, | |
| 2522 | − struct prism2_hostapd_param *param) | |
| 2523 | −{ | |
| 2524 | − struct sta_info *sta; | |
| 2525 | − | |
| 2526 | − spin_lock_bh(&ap->sta_table_lock); | |
| 2527 | − sta = ap_get_sta(ap, param->sta_addr); | |
| 2528 | − if (sta) { | |
| 2529 | − ap_sta_hash_del(ap, sta); | |
| 2530 | − list_del(&sta->list); | |
| 2531 | − } | |
| 2532 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 2533 | − | |
| 2534 | − if (!sta) | |
| 2535 | − return -ENOENT; | |
| 2536 | − | |
| 2537 | − if ((sta->flags & WLAN_STA_ASSOC) && !sta->ap && sta->local) | |
| 2538 | − hostap_event_expired_sta(sta->local->dev, sta); | |
| 2539 | − ap_free_sta(ap, sta); | |
| 2540 | − | |
| 2541 | − return 0; | |
| 2542 | −} | |
| 2543 | − | |
| 2544 | − | |
| 2545 | −static int prism2_hostapd_get_info_sta(struct ap_data *ap, | |
| 2546 | − struct prism2_hostapd_param *param) | |
| 2547 | −{ | |
| 2548 | − struct sta_info *sta; | |
| 2549 | − | |
| 2550 | − spin_lock_bh(&ap->sta_table_lock); | |
| 2551 | − sta = ap_get_sta(ap, param->sta_addr); | |
| 2552 | − if (sta) | |
| 2553 | − atomic_inc(&sta->users); | |
| 2554 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 2555 | − | |
| 2556 | − if (!sta) | |
| 2557 | − return -ENOENT; | |
| 2558 | − | |
| 2559 | − param->u.get_info_sta.inactive_sec = (jiffies - sta->last_rx) / HZ; | |
| 2560 | − | |
| 2561 | − atomic_dec(&sta->users); | |
| 2562 | − | |
| 2563 | − return 1; | |
| 2564 | −} | |
| 2565 | − | |
| 2566 | − | |
| 2567 | −static int prism2_hostapd_set_flags_sta(struct ap_data *ap, | |
| 2568 | − struct prism2_hostapd_param *param) | |
| 2569 | −{ | |
| 2570 | − struct sta_info *sta; | |
| 2571 | − | |
| 2572 | − spin_lock_bh(&ap->sta_table_lock); | |
| 2573 | − sta = ap_get_sta(ap, param->sta_addr); | |
| 2574 | − if (sta) { | |
| 2575 | − sta->flags |= param->u.set_flags_sta.flags_or; | |
| 2576 | − sta->flags &= param->u.set_flags_sta.flags_and; | |
| 2577 | − } | |
| 2578 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 2579 | − | |
| 2580 | − if (!sta) | |
| 2581 | − return -ENOENT; | |
| 2582 | − | |
| 2583 | − return 0; | |
| 2584 | −} | |
| 2585 | − | |
| 2586 | − | |
| 2587 | −static int prism2_hostapd_sta_clear_stats(struct ap_data *ap, | |
| 2588 | − struct prism2_hostapd_param *param) | |
| 2589 | −{ | |
| 2590 | − struct sta_info *sta; | |
| 2591 | − int rate; | |
| 2592 | − | |
| 2593 | − spin_lock_bh(&ap->sta_table_lock); | |
| 2594 | − sta = ap_get_sta(ap, param->sta_addr); | |
| 2595 | − if (sta) { | |
| 2596 | − sta->rx_packets = sta->tx_packets = 0; | |
| 2597 | − sta->rx_bytes = sta->tx_bytes = 0; | |
| 2598 | − for (rate = 0; rate < WLAN_RATE_COUNT; rate++) { | |
| 2599 | − sta->tx_count[rate] = 0; | |
| 2600 | − sta->rx_count[rate] = 0; | |
| 2601 | − } | |
| 2602 | − } | |
| 2603 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 2604 | − | |
| 2605 | − if (!sta) | |
| 2606 | − return -ENOENT; | |
| 2607 | − | |
| 2608 | − return 0; | |
| 2609 | −} | |
| 2610 | − | |
| 2611 | − | |
| 2612 | −int prism2_hostapd(struct ap_data *ap, struct prism2_hostapd_param *param) | |
| 2613 | −{ | |
| 2614 | − switch (param->cmd) { | |
| 2615 | − case PRISM2_HOSTAPD_FLUSH: | |
| 2616 | − ap_control_kickall(ap); | |
| 2617 | − return 0; | |
| 2618 | − case PRISM2_HOSTAPD_ADD_STA: | |
| 2619 | − return prism2_hostapd_add_sta(ap, param); | |
| 2620 | − case PRISM2_HOSTAPD_REMOVE_STA: | |
| 2621 | − return prism2_hostapd_remove_sta(ap, param); | |
| 2622 | − case PRISM2_HOSTAPD_GET_INFO_STA: | |
| 2623 | − return prism2_hostapd_get_info_sta(ap, param); | |
| 2624 | − case PRISM2_HOSTAPD_SET_FLAGS_STA: | |
| 2625 | − return prism2_hostapd_set_flags_sta(ap, param); | |
| 2626 | − case PRISM2_HOSTAPD_STA_CLEAR_STATS: | |
| 2627 | − return prism2_hostapd_sta_clear_stats(ap, param); | |
| 2628 | − default: | |
| 2629 | − printk(KERN_WARNING "prism2_hostapd: unknown cmd=%d\n", | |
| 2630 | − param->cmd); | |
| 2631 | − return -EOPNOTSUPP; | |
| 2632 | − } | |
| 2633 | −} | |
| 2634 | − | |
| 2635 | − | |
| 2636 | −/* Update station info for host-based TX rate control and return current | |
| 2637 | − * TX rate */ | |
| 2638 | −static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) | |
| 2639 | −{ | |
| 2640 | − int ret = sta->tx_rate; | |
| 2641 | − struct hostap_interface *iface; | |
| 2642 | − local_info_t *local; | |
| 2643 | − | |
| 2644 | − iface = netdev_priv(dev); | |
| 2645 | − local = iface->local; | |
| 2646 | − | |
| 2647 | − sta->tx_count[sta->tx_rate_idx]++; | |
| 2648 | − sta->tx_since_last_failure++; | |
| 2649 | − sta->tx_consecutive_exc = 0; | |
| 2650 | − if (sta->tx_since_last_failure >= WLAN_RATE_UPDATE_COUNT && | |
| 2651 | − sta->tx_rate_idx < sta->tx_max_rate) { | |
| 2652 | − /* use next higher rate */ | |
| 2653 | − int old_rate, new_rate; | |
| 2654 | − old_rate = new_rate = sta->tx_rate_idx; | |
| 2655 | − while (new_rate < sta->tx_max_rate) { | |
| 2656 | − new_rate++; | |
| 2657 | − if (ap_tx_rate_ok(new_rate, sta, local)) { | |
| 2658 | − sta->tx_rate_idx = new_rate; | |
| 2659 | − break; | |
| 2660 | − } | |
| 2661 | − } | |
| 2662 | − if (old_rate != sta->tx_rate_idx) { | |
| 2663 | − switch (sta->tx_rate_idx) { | |
| 2664 | − case 0: sta->tx_rate = 10; break; | |
| 2665 | − case 1: sta->tx_rate = 20; break; | |
| 2666 | − case 2: sta->tx_rate = 55; break; | |
| 2667 | − case 3: sta->tx_rate = 110; break; | |
| 2668 | − default: sta->tx_rate = 0; break; | |
| 2669 | − } | |
| 2670 | − PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", | |
| 2671 | − dev->name, sta->addr, sta->tx_rate); | |
| 2672 | − } | |
| 2673 | − sta->tx_since_last_failure = 0; | |
| 2674 | − } | |
| 2675 | − | |
| 2676 | − return ret; | |
| 2677 | −} | |
| 2678 | − | |
| 2679 | − | |
| 2680 | −/* Called only from software IRQ. Called for each TX frame prior possible | |
| 2681 | − * encryption and transmit. */ | |
| 2682 | −ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) | |
| 2683 | −{ | |
| 2684 | − struct sta_info *sta = NULL; | |
| 2685 | − struct sk_buff *skb = tx->skb; | |
| 2686 | − int set_tim, ret; | |
| 2687 | − struct ieee80211_hdr *hdr; | |
| 2688 | − struct hostap_skb_tx_data *meta; | |
| 2689 | − | |
| 2690 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 2691 | − ret = AP_TX_CONTINUE; | |
| 2692 | − if (local->ap == NULL || skb->len < 10 || | |
| 2693 | − meta->iface->type == HOSTAP_INTERFACE_STA) | |
| 2694 | − goto out; | |
| 2695 | − | |
| 2696 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 2697 | − | |
| 2698 | − if (hdr->addr1[0] & 0x01) { | |
| 2699 | − /* broadcast/multicast frame - no AP related processing */ | |
| 2700 | − if (local->ap->num_sta <= 0) | |
| 2701 | − ret = AP_TX_DROP; | |
| 2702 | − goto out; | |
| 2703 | − } | |
| 2704 | − | |
| 2705 | − /* unicast packet - check whether destination STA is associated */ | |
| 2706 | − spin_lock(&local->ap->sta_table_lock); | |
| 2707 | − sta = ap_get_sta(local->ap, hdr->addr1); | |
| 2708 | − if (sta) | |
| 2709 | − atomic_inc(&sta->users); | |
| 2710 | − spin_unlock(&local->ap->sta_table_lock); | |
| 2711 | − | |
| 2712 | − if (local->iw_mode == IW_MODE_MASTER && sta == NULL && | |
| 2713 | − !(meta->flags & HOSTAP_TX_FLAGS_WDS) && | |
| 2714 | − meta->iface->type != HOSTAP_INTERFACE_MASTER && | |
| 2715 | − meta->iface->type != HOSTAP_INTERFACE_AP) { | |
| 2716 | −#if 0 | |
| 2717 | − /* This can happen, e.g., when wlan0 is added to a bridge and | |
| 2718 | − * bridging code does not know which port is the correct target | |
| 2719 | − * for a unicast frame. In this case, the packet is send to all | |
| 2720 | − * ports of the bridge. Since this is a valid scenario, do not | |
| 2721 | − * print out any errors here. */ | |
| 2722 | − if (net_ratelimit()) { | |
| 2723 | − printk(KERN_DEBUG "AP: drop packet to non-associated " | |
| 2724 | − "STA %pM\n", hdr->addr1); | |
| 2725 | − } | |
| 2726 | −#endif | |
| 2727 | − local->ap->tx_drop_nonassoc++; | |
| 2728 | − ret = AP_TX_DROP; | |
| 2729 | − goto out; | |
| 2730 | − } | |
| 2731 | − | |
| 2732 | − if (sta == NULL) | |
| 2733 | − goto out; | |
| 2734 | − | |
| 2735 | − if (!(sta->flags & WLAN_STA_AUTHORIZED)) | |
| 2736 | − ret = AP_TX_CONTINUE_NOT_AUTHORIZED; | |
| 2737 | − | |
| 2738 | − /* Set tx_rate if using host-based TX rate control */ | |
| 2739 | − if (!local->fw_tx_rate_control) | |
| 2740 | − local->ap->last_tx_rate = meta->rate = | |
| 2741 | − ap_update_sta_tx_rate(sta, local->dev); | |
| 2742 | − | |
| 2743 | − if (local->iw_mode != IW_MODE_MASTER) | |
| 2744 | − goto out; | |
| 2745 | − | |
| 2746 | − if (!(sta->flags & WLAN_STA_PS)) | |
| 2747 | − goto out; | |
| 2748 | − | |
| 2749 | − if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) { | |
| 2750 | − /* indicate to STA that more frames follow */ | |
| 2751 | − hdr->frame_control |= | |
| 2752 | − cpu_to_le16(IEEE80211_FCTL_MOREDATA); | |
| 2753 | − } | |
| 2754 | − | |
| 2755 | − if (meta->flags & HOSTAP_TX_FLAGS_BUFFERED_FRAME) { | |
| 2756 | − /* packet was already buffered and now send due to | |
| 2757 | − * PS poll, so do not rebuffer it */ | |
| 2758 | − goto out; | |
| 2759 | − } | |
| 2760 | − | |
| 2761 | − if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { | |
| 2762 | − PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" | |
| 2763 | − "PS mode buffer\n", | |
| 2764 | − local->dev->name, sta->addr); | |
| 2765 | − /* Make sure that TIM is set for the station (it might not be | |
| 2766 | − * after AP wlan hw reset). */ | |
| 2767 | − /* FIX: should fix hw reset to restore bits based on STA | |
| 2768 | − * buffer state.. */ | |
| 2769 | − hostap_set_tim(local, sta->aid, 1); | |
| 2770 | − sta->flags |= WLAN_STA_TIM; | |
| 2771 | − ret = AP_TX_DROP; | |
| 2772 | − goto out; | |
| 2773 | − } | |
| 2774 | − | |
| 2775 | − /* STA in PS mode, buffer frame for later delivery */ | |
| 2776 | − set_tim = skb_queue_empty(&sta->tx_buf); | |
| 2777 | − skb_queue_tail(&sta->tx_buf, skb); | |
| 2778 | − /* FIX: could save RX time to skb and expire buffered frames after | |
| 2779 | − * some time if STA does not poll for them */ | |
| 2780 | − | |
| 2781 | − if (set_tim) { | |
| 2782 | − if (sta->flags & WLAN_STA_TIM) | |
| 2783 | − PDEBUG(DEBUG_PS2, "Re-setting TIM for aid %d\n", | |
| 2784 | − sta->aid); | |
| 2785 | − hostap_set_tim(local, sta->aid, 1); | |
| 2786 | − sta->flags |= WLAN_STA_TIM; | |
| 2787 | − } | |
| 2788 | − | |
| 2789 | − ret = AP_TX_BUFFERED; | |
| 2790 | − | |
| 2791 | − out: | |
| 2792 | − if (sta != NULL) { | |
| 2793 | − if (ret == AP_TX_CONTINUE || | |
| 2794 | − ret == AP_TX_CONTINUE_NOT_AUTHORIZED) { | |
| 2795 | − sta->tx_packets++; | |
| 2796 | − sta->tx_bytes += skb->len; | |
| 2797 | − sta->last_tx = jiffies; | |
| 2798 | − } | |
| 2799 | − | |
| 2800 | − if ((ret == AP_TX_CONTINUE || | |
| 2801 | − ret == AP_TX_CONTINUE_NOT_AUTHORIZED) && | |
| 2802 | − sta->crypt && tx->host_encrypt) { | |
| 2803 | − tx->crypt = sta->crypt; | |
| 2804 | − tx->sta_ptr = sta; /* hostap_handle_sta_release() will | |
| 2805 | − * be called to release sta info | |
| 2806 | − * later */ | |
| 2807 | − } else | |
| 2808 | − atomic_dec(&sta->users); | |
| 2809 | − } | |
| 2810 | − | |
| 2811 | − return ret; | |
| 2812 | −} | |
| 2813 | − | |
| 2814 | − | |
| 2815 | −void hostap_handle_sta_release(void *ptr) | |
| 2816 | −{ | |
| 2817 | − struct sta_info *sta = ptr; | |
| 2818 | − atomic_dec(&sta->users); | |
| 2819 | −} | |
| 2820 | − | |
| 2821 | − | |
| 2822 | −/* Called only as a tasklet (software IRQ) */ | |
| 2823 | −void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) | |
| 2824 | −{ | |
| 2825 | − struct sta_info *sta; | |
| 2826 | − struct ieee80211_hdr *hdr; | |
| 2827 | − struct hostap_skb_tx_data *meta; | |
| 2828 | − | |
| 2829 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 2830 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 2831 | − | |
| 2832 | − spin_lock(&local->ap->sta_table_lock); | |
| 2833 | − sta = ap_get_sta(local->ap, hdr->addr1); | |
| 2834 | − if (!sta) { | |
| 2835 | − spin_unlock(&local->ap->sta_table_lock); | |
| 2836 | − PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" | |
| 2837 | − " for this TX error (@%lu)\n", | |
| 2838 | − local->dev->name, hdr->addr1, jiffies); | |
| 2839 | − return; | |
| 2840 | − } | |
| 2841 | − | |
| 2842 | − sta->tx_since_last_failure = 0; | |
| 2843 | − sta->tx_consecutive_exc++; | |
| 2844 | − | |
| 2845 | − if (sta->tx_consecutive_exc >= WLAN_RATE_DECREASE_THRESHOLD && | |
| 2846 | − sta->tx_rate_idx > 0 && meta->rate <= sta->tx_rate) { | |
| 2847 | − /* use next lower rate */ | |
| 2848 | − int old, rate; | |
| 2849 | − old = rate = sta->tx_rate_idx; | |
| 2850 | − while (rate > 0) { | |
| 2851 | − rate--; | |
| 2852 | − if (ap_tx_rate_ok(rate, sta, local)) { | |
| 2853 | − sta->tx_rate_idx = rate; | |
| 2854 | − break; | |
| 2855 | − } | |
| 2856 | − } | |
| 2857 | − if (old != sta->tx_rate_idx) { | |
| 2858 | − switch (sta->tx_rate_idx) { | |
| 2859 | − case 0: sta->tx_rate = 10; break; | |
| 2860 | − case 1: sta->tx_rate = 20; break; | |
| 2861 | − case 2: sta->tx_rate = 55; break; | |
| 2862 | − case 3: sta->tx_rate = 110; break; | |
| 2863 | − default: sta->tx_rate = 0; break; | |
| 2864 | − } | |
| 2865 | − PDEBUG(DEBUG_AP, | |
| 2866 | − "%s: STA %pM TX rate lowered to %d\n", | |
| 2867 | − local->dev->name, sta->addr, sta->tx_rate); | |
| 2868 | − } | |
| 2869 | − sta->tx_consecutive_exc = 0; | |
| 2870 | − } | |
| 2871 | − spin_unlock(&local->ap->sta_table_lock); | |
| 2872 | −} | |
| 2873 | − | |
| 2874 | − | |
| 2875 | −static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, | |
| 2876 | − int pwrmgt, int type, int stype) | |
| 2877 | −{ | |
| 2878 | − if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { | |
| 2879 | − sta->flags |= WLAN_STA_PS; | |
| 2880 | − PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " | |
| 2881 | − "mode (type=0x%02X, stype=0x%02X)\n", | |
| 2882 | − sta->addr, type >> 2, stype >> 4); | |
| 2883 | − } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { | |
| 2884 | − sta->flags &= ~WLAN_STA_PS; | |
| 2885 | − PDEBUG(DEBUG_PS2, "STA %pM changed to not use " | |
| 2886 | − "PS mode (type=0x%02X, stype=0x%02X)\n", | |
| 2887 | − sta->addr, type >> 2, stype >> 4); | |
| 2888 | − if (type != IEEE80211_FTYPE_CTL || | |
| 2889 | − stype != IEEE80211_STYPE_PSPOLL) | |
| 2890 | − schedule_packet_send(local, sta); | |
| 2891 | − } | |
| 2892 | −} | |
| 2893 | − | |
| 2894 | − | |
| 2895 | −/* Called only as a tasklet (software IRQ). Called for each RX frame to update | |
| 2896 | − * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */ | |
| 2897 | −int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr) | |
| 2898 | −{ | |
| 2899 | − struct sta_info *sta; | |
| 2900 | − u16 fc; | |
| 2901 | − | |
| 2902 | − spin_lock(&local->ap->sta_table_lock); | |
| 2903 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 2904 | − if (sta) | |
| 2905 | − atomic_inc(&sta->users); | |
| 2906 | − spin_unlock(&local->ap->sta_table_lock); | |
| 2907 | − | |
| 2908 | − if (!sta) | |
| 2909 | − return -1; | |
| 2910 | − | |
| 2911 | − fc = le16_to_cpu(hdr->frame_control); | |
| 2912 | − hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, | |
| 2913 | − fc & IEEE80211_FCTL_FTYPE, | |
| 2914 | − fc & IEEE80211_FCTL_STYPE); | |
| 2915 | − | |
| 2916 | − atomic_dec(&sta->users); | |
| 2917 | − return 0; | |
| 2918 | −} | |
| 2919 | − | |
| 2920 | − | |
| 2921 | −/* Called only as a tasklet (software IRQ). Called for each RX frame after | |
| 2922 | − * getting RX header and payload from hardware. */ | |
| 2923 | −ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | |
| 2924 | − struct sk_buff *skb, | |
| 2925 | − struct hostap_80211_rx_status *rx_stats, | |
| 2926 | − int wds) | |
| 2927 | −{ | |
| 2928 | − int ret; | |
| 2929 | − struct sta_info *sta; | |
| 2930 | − u16 fc, type, stype; | |
| 2931 | − struct ieee80211_hdr *hdr; | |
| 2932 | − | |
| 2933 | − if (local->ap == NULL) | |
| 2934 | − return AP_RX_CONTINUE; | |
| 2935 | − | |
| 2936 | − hdr = (struct ieee80211_hdr *) skb->data; | |
| 2937 | − | |
| 2938 | − fc = le16_to_cpu(hdr->frame_control); | |
| 2939 | − type = fc & IEEE80211_FCTL_FTYPE; | |
| 2940 | − stype = fc & IEEE80211_FCTL_STYPE; | |
| 2941 | − | |
| 2942 | − spin_lock(&local->ap->sta_table_lock); | |
| 2943 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 2944 | − if (sta) | |
| 2945 | − atomic_inc(&sta->users); | |
| 2946 | − spin_unlock(&local->ap->sta_table_lock); | |
| 2947 | − | |
| 2948 | − if (sta && !(sta->flags & WLAN_STA_AUTHORIZED)) | |
| 2949 | − ret = AP_RX_CONTINUE_NOT_AUTHORIZED; | |
| 2950 | − else | |
| 2951 | − ret = AP_RX_CONTINUE; | |
| 2952 | − | |
| 2953 | − | |
| 2954 | − if (fc & IEEE80211_FCTL_TODS) { | |
| 2955 | − if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { | |
| 2956 | − if (local->hostapd) { | |
| 2957 | − prism2_rx_80211(local->apdev, skb, rx_stats, | |
| 2958 | − PRISM2_RX_NON_ASSOC); | |
| 2959 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 2960 | − } else { | |
| 2961 | − printk(KERN_DEBUG "%s: dropped received packet" | |
| 2962 | − " from non-associated STA %pM" | |
| 2963 | − " (type=0x%02x, subtype=0x%02x)\n", | |
| 2964 | − dev->name, hdr->addr2, | |
| 2965 | − type >> 2, stype >> 4); | |
| 2966 | − hostap_rx(dev, skb, rx_stats); | |
| 2967 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 2968 | − } | |
| 2969 | − ret = AP_RX_EXIT; | |
| 2970 | − goto out; | |
| 2971 | − } | |
| 2972 | − } else if (fc & IEEE80211_FCTL_FROMDS) { | |
| 2973 | − if (!wds) { | |
| 2974 | − /* FromDS frame - not for us; probably | |
| 2975 | − * broadcast/multicast in another BSS - drop */ | |
| 2976 | − if (ether_addr_equal(hdr->addr1, dev->dev_addr)) { | |
| 2977 | − printk(KERN_DEBUG "Odd.. FromDS packet " | |
| 2978 | − "received with own BSSID\n"); | |
| 2979 | − hostap_dump_rx_80211(dev->name, skb, rx_stats); | |
| 2980 | − } | |
| 2981 | − ret = AP_RX_DROP; | |
| 2982 | − goto out; | |
| 2983 | − } | |
| 2984 | − } else if (stype == IEEE80211_STYPE_NULLFUNC && sta == NULL && | |
| 2985 | − ether_addr_equal(hdr->addr1, dev->dev_addr)) { | |
| 2986 | − | |
| 2987 | − if (local->hostapd) { | |
| 2988 | − prism2_rx_80211(local->apdev, skb, rx_stats, | |
| 2989 | − PRISM2_RX_NON_ASSOC); | |
| 2990 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 2991 | − } else { | |
| 2992 | − /* At least Lucent f/w seems to send data::nullfunc | |
| 2993 | − * frames with no ToDS flag when the current AP returns | |
| 2994 | − * after being unavailable for some time. Speed up | |
| 2995 | − * re-association by informing the station about it not | |
| 2996 | − * being associated. */ | |
| 2997 | − printk(KERN_DEBUG "%s: rejected received nullfunc frame" | |
| 2998 | − " without ToDS from not associated STA %pM\n", | |
| 2999 | − dev->name, hdr->addr2); | |
| 3000 | − hostap_rx(dev, skb, rx_stats); | |
| 3001 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 3002 | − } | |
| 3003 | − ret = AP_RX_EXIT; | |
| 3004 | − goto out; | |
| 3005 | − } else if (stype == IEEE80211_STYPE_NULLFUNC) { | |
| 3006 | − /* At least Lucent cards seem to send periodic nullfunc | |
| 3007 | − * frames with ToDS. Let these through to update SQ | |
| 3008 | − * stats and PS state. Nullfunc frames do not contain | |
| 3009 | − * any data and they will be dropped below. */ | |
| 3010 | − } else { | |
| 3011 | − /* If BSSID (Addr3) is foreign, this frame is a normal | |
| 3012 | − * broadcast frame from an IBSS network. Drop it silently. | |
| 3013 | − * If BSSID is own, report the dropping of this frame. */ | |
| 3014 | − if (ether_addr_equal(hdr->addr3, dev->dev_addr)) { | |
| 3015 | − printk(KERN_DEBUG "%s: dropped received packet from %pM" | |
| 3016 | − " with no ToDS flag " | |
| 3017 | − "(type=0x%02x, subtype=0x%02x)\n", dev->name, | |
| 3018 | − hdr->addr2, type >> 2, stype >> 4); | |
| 3019 | − hostap_dump_rx_80211(dev->name, skb, rx_stats); | |
| 3020 | − } | |
| 3021 | − ret = AP_RX_DROP; | |
| 3022 | − goto out; | |
| 3023 | − } | |
| 3024 | − | |
| 3025 | − if (sta) { | |
| 3026 | − hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM, | |
| 3027 | − type, stype); | |
| 3028 | − | |
| 3029 | − sta->rx_packets++; | |
| 3030 | − sta->rx_bytes += skb->len; | |
| 3031 | − sta->last_rx = jiffies; | |
| 3032 | − } | |
| 3033 | − | |
| 3034 | − if (local->ap->nullfunc_ack && stype == IEEE80211_STYPE_NULLFUNC && | |
| 3035 | − fc & IEEE80211_FCTL_TODS) { | |
| 3036 | − if (local->hostapd) { | |
| 3037 | − prism2_rx_80211(local->apdev, skb, rx_stats, | |
| 3038 | − PRISM2_RX_NULLFUNC_ACK); | |
| 3039 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 3040 | − } else { | |
| 3041 | − /* some STA f/w's seem to require control::ACK frame | |
| 3042 | − * for data::nullfunc, but Prism2 f/w 0.8.0 (at least | |
| 3043 | − * from Compaq) does not send this.. Try to generate | |
| 3044 | − * ACK for these frames from the host driver to make | |
| 3045 | − * power saving work with, e.g., Lucent WaveLAN f/w */ | |
| 3046 | − hostap_rx(dev, skb, rx_stats); | |
| 3047 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 3048 | − } | |
| 3049 | − ret = AP_RX_EXIT; | |
| 3050 | − goto out; | |
| 3051 | − } | |
| 3052 | − | |
| 3053 | − out: | |
| 3054 | − if (sta) | |
| 3055 | − atomic_dec(&sta->users); | |
| 3056 | − | |
| 3057 | − return ret; | |
| 3058 | −} | |
| 3059 | − | |
| 3060 | − | |
| 3061 | −/* Called only as a tasklet (software IRQ) */ | |
| 3062 | −int hostap_handle_sta_crypto(local_info_t *local, | |
| 3063 | − struct ieee80211_hdr *hdr, | |
| 3064 | − struct lib80211_crypt_data **crypt, | |
| 3065 | − void **sta_ptr) | |
| 3066 | −{ | |
| 3067 | − struct sta_info *sta; | |
| 3068 | − | |
| 3069 | − spin_lock(&local->ap->sta_table_lock); | |
| 3070 | − sta = ap_get_sta(local->ap, hdr->addr2); | |
| 3071 | − if (sta) | |
| 3072 | − atomic_inc(&sta->users); | |
| 3073 | − spin_unlock(&local->ap->sta_table_lock); | |
| 3074 | − | |
| 3075 | − if (!sta) | |
| 3076 | − return -1; | |
| 3077 | − | |
| 3078 | − if (sta->crypt) { | |
| 3079 | − *crypt = sta->crypt; | |
| 3080 | − *sta_ptr = sta; | |
| 3081 | − /* hostap_handle_sta_release() will be called to release STA | |
| 3082 | − * info */ | |
| 3083 | − } else | |
| 3084 | − atomic_dec(&sta->users); | |
| 3085 | − | |
| 3086 | − return 0; | |
| 3087 | −} | |
| 3088 | − | |
| 3089 | − | |
| 3090 | −/* Called only as a tasklet (software IRQ) */ | |
| 3091 | −int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr) | |
| 3092 | −{ | |
| 3093 | − struct sta_info *sta; | |
| 3094 | − int ret = 0; | |
| 3095 | − | |
| 3096 | − spin_lock(&ap->sta_table_lock); | |
| 3097 | − sta = ap_get_sta(ap, sta_addr); | |
| 3098 | − if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap) | |
| 3099 | − ret = 1; | |
| 3100 | − spin_unlock(&ap->sta_table_lock); | |
| 3101 | − | |
| 3102 | − return ret; | |
| 3103 | −} | |
| 3104 | − | |
| 3105 | − | |
| 3106 | −/* Called only as a tasklet (software IRQ) */ | |
| 3107 | −int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr) | |
| 3108 | −{ | |
| 3109 | − struct sta_info *sta; | |
| 3110 | − int ret = 0; | |
| 3111 | − | |
| 3112 | − spin_lock(&ap->sta_table_lock); | |
| 3113 | − sta = ap_get_sta(ap, sta_addr); | |
| 3114 | − if (sta != NULL && (sta->flags & WLAN_STA_ASSOC) && !sta->ap && | |
| 3115 | − ((sta->flags & WLAN_STA_AUTHORIZED) || | |
| 3116 | − ap->local->ieee_802_1x == 0)) | |
| 3117 | − ret = 1; | |
| 3118 | − spin_unlock(&ap->sta_table_lock); | |
| 3119 | − | |
| 3120 | − return ret; | |
| 3121 | −} | |
| 3122 | − | |
| 3123 | − | |
| 3124 | −/* Called only as a tasklet (software IRQ) */ | |
| 3125 | −int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) | |
| 3126 | −{ | |
| 3127 | − struct sta_info *sta; | |
| 3128 | − int ret = 1; | |
| 3129 | − | |
| 3130 | − if (!ap) | |
| 3131 | − return -1; | |
| 3132 | − | |
| 3133 | − spin_lock(&ap->sta_table_lock); | |
| 3134 | − sta = ap_get_sta(ap, sta_addr); | |
| 3135 | − if (sta) | |
| 3136 | − ret = 0; | |
| 3137 | − spin_unlock(&ap->sta_table_lock); | |
| 3138 | − | |
| 3139 | − if (ret == 1) { | |
| 3140 | − sta = ap_add_sta(ap, sta_addr); | |
| 3141 | − if (!sta) | |
| 3142 | − return -1; | |
| 3143 | − sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; | |
| 3144 | − sta->ap = 1; | |
| 3145 | − memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); | |
| 3146 | − /* No way of knowing which rates are supported since we did not | |
| 3147 | − * get supported rates element from beacon/assoc req. Assume | |
| 3148 | − * that remote end supports all 802.11b rates. */ | |
| 3149 | − sta->supported_rates[0] = 0x82; | |
| 3150 | − sta->supported_rates[1] = 0x84; | |
| 3151 | − sta->supported_rates[2] = 0x0b; | |
| 3152 | − sta->supported_rates[3] = 0x16; | |
| 3153 | − sta->tx_supp_rates = WLAN_RATE_1M | WLAN_RATE_2M | | |
| 3154 | − WLAN_RATE_5M5 | WLAN_RATE_11M; | |
| 3155 | − sta->tx_rate = 110; | |
| 3156 | − sta->tx_max_rate = sta->tx_rate_idx = 3; | |
| 3157 | − } | |
| 3158 | − | |
| 3159 | − return ret; | |
| 3160 | −} | |
| 3161 | − | |
| 3162 | − | |
| 3163 | −/* Called only as a tasklet (software IRQ) */ | |
| 3164 | −int hostap_update_rx_stats(struct ap_data *ap, | |
| 3165 | − struct ieee80211_hdr *hdr, | |
| 3166 | − struct hostap_80211_rx_status *rx_stats) | |
| 3167 | −{ | |
| 3168 | − struct sta_info *sta; | |
| 3169 | − | |
| 3170 | − if (!ap) | |
| 3171 | − return -1; | |
| 3172 | − | |
| 3173 | − spin_lock(&ap->sta_table_lock); | |
| 3174 | − sta = ap_get_sta(ap, hdr->addr2); | |
| 3175 | − if (sta) { | |
| 3176 | − sta->last_rx_silence = rx_stats->noise; | |
| 3177 | − sta->last_rx_signal = rx_stats->signal; | |
| 3178 | − sta->last_rx_rate = rx_stats->rate; | |
| 3179 | − sta->last_rx_updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | |
| 3180 | − if (rx_stats->rate == 10) | |
| 3181 | − sta->rx_count[0]++; | |
| 3182 | − else if (rx_stats->rate == 20) | |
| 3183 | − sta->rx_count[1]++; | |
| 3184 | − else if (rx_stats->rate == 55) | |
| 3185 | − sta->rx_count[2]++; | |
| 3186 | − else if (rx_stats->rate == 110) | |
| 3187 | − sta->rx_count[3]++; | |
| 3188 | − } | |
| 3189 | − spin_unlock(&ap->sta_table_lock); | |
| 3190 | − | |
| 3191 | − return sta ? 0 : -1; | |
| 3192 | −} | |
| 3193 | − | |
| 3194 | − | |
| 3195 | −void hostap_update_rates(local_info_t *local) | |
| 3196 | −{ | |
| 3197 | − struct sta_info *sta; | |
| 3198 | − struct ap_data *ap = local->ap; | |
| 3199 | − | |
| 3200 | − if (!ap) | |
| 3201 | − return; | |
| 3202 | − | |
| 3203 | − spin_lock_bh(&ap->sta_table_lock); | |
| 3204 | − list_for_each_entry(sta, &ap->sta_list, list) { | |
| 3205 | − prism2_check_tx_rates(sta); | |
| 3206 | − } | |
| 3207 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 3208 | −} | |
| 3209 | − | |
| 3210 | − | |
| 3211 | −void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, | |
| 3212 | − struct lib80211_crypt_data ***crypt) | |
| 3213 | −{ | |
| 3214 | − struct sta_info *sta; | |
| 3215 | − | |
| 3216 | − spin_lock_bh(&ap->sta_table_lock); | |
| 3217 | − sta = ap_get_sta(ap, addr); | |
| 3218 | − if (sta) | |
| 3219 | − atomic_inc(&sta->users); | |
| 3220 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 3221 | − | |
| 3222 | − if (!sta && permanent) | |
| 3223 | − sta = ap_add_sta(ap, addr); | |
| 3224 | − | |
| 3225 | − if (!sta) | |
| 3226 | − return NULL; | |
| 3227 | − | |
| 3228 | − if (permanent) | |
| 3229 | − sta->flags |= WLAN_STA_PERM; | |
| 3230 | − | |
| 3231 | − *crypt = &sta->crypt; | |
| 3232 | − | |
| 3233 | − return sta; | |
| 3234 | −} | |
| 3235 | − | |
| 3236 | − | |
| 3237 | −void hostap_add_wds_links(local_info_t *local) | |
| 3238 | −{ | |
| 3239 | − struct ap_data *ap = local->ap; | |
| 3240 | − struct sta_info *sta; | |
| 3241 | − | |
| 3242 | − spin_lock_bh(&ap->sta_table_lock); | |
| 3243 | − list_for_each_entry(sta, &ap->sta_list, list) { | |
| 3244 | − if (sta->ap) | |
| 3245 | − hostap_wds_link_oper(local, sta->addr, WDS_ADD); | |
| 3246 | − } | |
| 3247 | − spin_unlock_bh(&ap->sta_table_lock); | |
| 3248 | − | |
| 3249 | − schedule_work(&local->ap->wds_oper_queue); | |
| 3250 | −} | |
| 3251 | − | |
| 3252 | − | |
| 3253 | −void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type) | |
| 3254 | −{ | |
| 3255 | − struct wds_oper_data *entry; | |
| 3256 | − | |
| 3257 | − entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | |
| 3258 | − if (!entry) | |
| 3259 | − return; | |
| 3260 | − memcpy(entry->addr, addr, ETH_ALEN); | |
| 3261 | − entry->type = type; | |
| 3262 | − spin_lock_bh(&local->lock); | |
| 3263 | − entry->next = local->ap->wds_oper_entries; | |
| 3264 | − local->ap->wds_oper_entries = entry; | |
| 3265 | − spin_unlock_bh(&local->lock); | |
| 3266 | − | |
| 3267 | − schedule_work(&local->ap->wds_oper_queue); | |
| 3268 | −} | |
| 3269 | − | |
| 3270 | − | |
| 3271 | −EXPORT_SYMBOL(hostap_init_data); | |
| 3272 | −EXPORT_SYMBOL(hostap_init_ap_proc); | |
| 3273 | −EXPORT_SYMBOL(hostap_free_data); | |
| 3274 | −EXPORT_SYMBOL(hostap_check_sta_fw_version); | |
| 3275 | −EXPORT_SYMBOL(hostap_handle_sta_tx_exc); | |
| 3276 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 3277 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| @@ -1,264 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −#ifndef HOSTAP_AP_H | |
| 3 | −#define HOSTAP_AP_H | |
| 4 | − | |
| 5 | −#include "hostap_80211.h" | |
| 6 | − | |
| 7 | −/* AP data structures for STAs */ | |
| 8 | − | |
| 9 | −/* maximum number of frames to buffer per STA */ | |
| 10 | −#define STA_MAX_TX_BUFFER 32 | |
| 11 | − | |
| 12 | −/* STA flags */ | |
| 13 | −#define WLAN_STA_AUTH BIT(0) | |
| 14 | −#define WLAN_STA_ASSOC BIT(1) | |
| 15 | −#define WLAN_STA_PS BIT(2) | |
| 16 | −#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ | |
| 17 | −#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ | |
| 18 | −#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is | |
| 19 | − * controlling whether STA is authorized to | |
| 20 | − * send and receive non-IEEE 802.1X frames | |
| 21 | − */ | |
| 22 | −#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */ | |
| 23 | − | |
| 24 | −#define WLAN_RATE_1M BIT(0) | |
| 25 | −#define WLAN_RATE_2M BIT(1) | |
| 26 | −#define WLAN_RATE_5M5 BIT(2) | |
| 27 | −#define WLAN_RATE_11M BIT(3) | |
| 28 | −#define WLAN_RATE_COUNT 4 | |
| 29 | − | |
| 30 | −/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8, | |
| 31 | − * but some pre-standard IEEE 802.11g products use longer elements. */ | |
| 32 | −#define WLAN_SUPP_RATES_MAX 32 | |
| 33 | − | |
| 34 | −/* Try to increase TX rate after # successfully sent consecutive packets */ | |
| 35 | −#define WLAN_RATE_UPDATE_COUNT 50 | |
| 36 | − | |
| 37 | −/* Decrease TX rate after # consecutive dropped packets */ | |
| 38 | −#define WLAN_RATE_DECREASE_THRESHOLD 2 | |
| 39 | − | |
| 40 | −struct sta_info { | |
| 41 | − struct list_head list; | |
| 42 | − struct sta_info *hnext; /* next entry in hash table list */ | |
| 43 | − atomic_t users; /* number of users (do not remove if > 0) */ | |
| 44 | − struct proc_dir_entry *proc; | |
| 45 | − | |
| 46 | − u8 addr[6]; | |
| 47 | − u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ | |
| 48 | − u32 flags; | |
| 49 | − u16 capability; | |
| 50 | − u16 listen_interval; /* or beacon_int for APs */ | |
| 51 | − u8 supported_rates[WLAN_SUPP_RATES_MAX]; | |
| 52 | − | |
| 53 | − unsigned long last_auth; | |
| 54 | − unsigned long last_assoc; | |
| 55 | − unsigned long last_rx; | |
| 56 | − unsigned long last_tx; | |
| 57 | − unsigned long rx_packets, tx_packets; | |
| 58 | − unsigned long rx_bytes, tx_bytes; | |
| 59 | − struct sk_buff_head tx_buf; | |
| 60 | − /* FIX: timeout buffers with an expiry time somehow derived from | |
| 61 | − * listen_interval */ | |
| 62 | − | |
| 63 | − s8 last_rx_silence; /* Noise in dBm */ | |
| 64 | − s8 last_rx_signal; /* Signal strength in dBm */ | |
| 65 | − u8 last_rx_rate; /* TX rate in 0.1 Mbps */ | |
| 66 | − u8 last_rx_updated; /* IWSPY's struct iw_quality::updated */ | |
| 67 | − | |
| 68 | − u8 tx_supp_rates; /* bit field of supported TX rates */ | |
| 69 | − u8 tx_rate; /* current TX rate (in 0.1 Mbps) */ | |
| 70 | − u8 tx_rate_idx; /* current TX rate (WLAN_RATE_*) */ | |
| 71 | − u8 tx_max_rate; /* max TX rate (WLAN_RATE_*) */ | |
| 72 | − u32 tx_count[WLAN_RATE_COUNT]; /* number of frames sent (per rate) */ | |
| 73 | − u32 rx_count[WLAN_RATE_COUNT]; /* number of frames received (per rate) | |
| 74 | − */ | |
| 75 | − u32 tx_since_last_failure; | |
| 76 | − u32 tx_consecutive_exc; | |
| 77 | − | |
| 78 | − struct lib80211_crypt_data *crypt; | |
| 79 | − | |
| 80 | − int ap; /* whether this station is an AP */ | |
| 81 | − | |
| 82 | − local_info_t *local; | |
| 83 | − | |
| 84 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 85 | − union { | |
| 86 | − struct { | |
| 87 | − char *challenge; /* shared key authentication | |
| 88 | − * challenge */ | |
| 89 | − } sta; | |
| 90 | − struct { | |
| 91 | − int ssid_len; | |
| 92 | − unsigned char ssid[MAX_SSID_LEN + 1]; /* AP's ssid */ | |
| 93 | − int channel; | |
| 94 | − unsigned long last_beacon; /* last RX beacon time */ | |
| 95 | − } ap; | |
| 96 | − } u; | |
| 97 | − | |
| 98 | − struct timer_list timer; | |
| 99 | − enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; | |
| 100 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 101 | −}; | |
| 102 | − | |
| 103 | − | |
| 104 | −#define MAX_STA_COUNT 1024 | |
| 105 | − | |
| 106 | −/* Maximum number of AIDs to use for STAs; must be 2007 or lower | |
| 107 | − * (8802.11 limitation) */ | |
| 108 | −#define MAX_AID_TABLE_SIZE 128 | |
| 109 | − | |
| 110 | −#define STA_HASH_SIZE 256 | |
| 111 | −#define STA_HASH(sta) (sta[5]) | |
| 112 | − | |
| 113 | − | |
| 114 | −/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY_SEC | |
| 115 | − * has passed since last received frame from the station, a nullfunc data | |
| 116 | − * frame is sent to the station. If this frame is not acknowledged and no other | |
| 117 | − * frames have been received, the station will be disassociated after | |
| 118 | − * AP_DISASSOC_DELAY. Similarly, a the station will be deauthenticated after | |
| 119 | − * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with | |
| 120 | − * max inactivity timer. */ | |
| 121 | −#define AP_MAX_INACTIVITY_SEC (5 * 60) | |
| 122 | −#define AP_DISASSOC_DELAY (HZ) | |
| 123 | −#define AP_DEAUTH_DELAY (HZ) | |
| 124 | − | |
| 125 | −/* ap_policy: whether to accept frames to/from other APs/IBSS */ | |
| 126 | −typedef enum { | |
| 127 | − AP_OTHER_AP_SKIP_ALL = 0, | |
| 128 | − AP_OTHER_AP_SAME_SSID = 1, | |
| 129 | − AP_OTHER_AP_ALL = 2, | |
| 130 | − AP_OTHER_AP_EVEN_IBSS = 3 | |
| 131 | −} ap_policy_enum; | |
| 132 | − | |
| 133 | −#define PRISM2_AUTH_OPEN BIT(0) | |
| 134 | −#define PRISM2_AUTH_SHARED_KEY BIT(1) | |
| 135 | − | |
| 136 | − | |
| 137 | −/* MAC address-based restrictions */ | |
| 138 | −struct mac_entry { | |
| 139 | − struct list_head list; | |
| 140 | − u8 addr[6]; | |
| 141 | −}; | |
| 142 | − | |
| 143 | −struct mac_restrictions { | |
| 144 | − enum { MAC_POLICY_OPEN = 0, MAC_POLICY_ALLOW, MAC_POLICY_DENY } policy; | |
| 145 | − unsigned int entries; | |
| 146 | − struct list_head mac_list; | |
| 147 | − spinlock_t lock; | |
| 148 | −}; | |
| 149 | − | |
| 150 | − | |
| 151 | −struct add_sta_proc_data { | |
| 152 | − u8 addr[ETH_ALEN]; | |
| 153 | − struct add_sta_proc_data *next; | |
| 154 | −}; | |
| 155 | − | |
| 156 | − | |
| 157 | −typedef enum { WDS_ADD, WDS_DEL } wds_oper_type; | |
| 158 | −struct wds_oper_data { | |
| 159 | − wds_oper_type type; | |
| 160 | − u8 addr[ETH_ALEN]; | |
| 161 | − struct wds_oper_data *next; | |
| 162 | −}; | |
| 163 | − | |
| 164 | − | |
| 165 | −struct ap_data { | |
| 166 | − int initialized; /* whether ap_data has been initialized */ | |
| 167 | − local_info_t *local; | |
| 168 | − int bridge_packets; /* send packet to associated STAs directly to the | |
| 169 | − * wireless media instead of higher layers in the | |
| 170 | − * kernel */ | |
| 171 | − unsigned int bridged_unicast; /* number of unicast frames bridged on | |
| 172 | − * wireless media */ | |
| 173 | − unsigned int bridged_multicast; /* number of non-unicast frames | |
| 174 | − * bridged on wireless media */ | |
| 175 | − unsigned int tx_drop_nonassoc; /* number of unicast TX packets dropped | |
| 176 | − * because they were to an address that | |
| 177 | − * was not associated */ | |
| 178 | − int nullfunc_ack; /* use workaround for nullfunc frame ACKs */ | |
| 179 | − | |
| 180 | − spinlock_t sta_table_lock; | |
| 181 | − int num_sta; /* number of entries in sta_list */ | |
| 182 | − struct list_head sta_list; /* STA info list head */ | |
| 183 | − struct sta_info *sta_hash[STA_HASH_SIZE]; | |
| 184 | − | |
| 185 | − struct proc_dir_entry *proc; | |
| 186 | − | |
| 187 | − ap_policy_enum ap_policy; | |
| 188 | − unsigned int max_inactivity; | |
| 189 | − int autom_ap_wds; | |
| 190 | − | |
| 191 | − struct mac_restrictions mac_restrictions; /* MAC-based auth */ | |
| 192 | − int last_tx_rate; | |
| 193 | − | |
| 194 | − struct work_struct add_sta_proc_queue; | |
| 195 | − struct add_sta_proc_data *add_sta_proc_entries; | |
| 196 | − | |
| 197 | − struct work_struct wds_oper_queue; | |
| 198 | − struct wds_oper_data *wds_oper_entries; | |
| 199 | − | |
| 200 | − u16 tx_callback_idx; | |
| 201 | − | |
| 202 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 203 | − /* pointers to STA info; based on allocated AID or NULL if AID free | |
| 204 | − * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 | |
| 205 | − * and so on | |
| 206 | − */ | |
| 207 | − struct sta_info *sta_aid[MAX_AID_TABLE_SIZE]; | |
| 208 | − | |
| 209 | − u16 tx_callback_auth, tx_callback_assoc, tx_callback_poll; | |
| 210 | − | |
| 211 | − /* WEP operations for generating challenges to be used with shared key | |
| 212 | − * authentication */ | |
| 213 | − struct lib80211_crypto_ops *crypt; | |
| 214 | − void *crypt_priv; | |
| 215 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 216 | −}; | |
| 217 | − | |
| 218 | − | |
| 219 | −void hostap_rx(struct net_device *dev, struct sk_buff *skb, | |
| 220 | − struct hostap_80211_rx_status *rx_stats); | |
| 221 | −void hostap_init_data(local_info_t *local); | |
| 222 | −void hostap_init_ap_proc(local_info_t *local); | |
| 223 | −void hostap_free_data(struct ap_data *ap); | |
| 224 | −void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver); | |
| 225 | − | |
| 226 | −typedef enum { | |
| 227 | − AP_TX_CONTINUE, AP_TX_DROP, AP_TX_RETRY, AP_TX_BUFFERED, | |
| 228 | − AP_TX_CONTINUE_NOT_AUTHORIZED | |
| 229 | −} ap_tx_ret; | |
| 230 | −struct hostap_tx_data { | |
| 231 | − struct sk_buff *skb; | |
| 232 | − int host_encrypt; | |
| 233 | − struct lib80211_crypt_data *crypt; | |
| 234 | − void *sta_ptr; | |
| 235 | −}; | |
| 236 | −ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); | |
| 237 | −void hostap_handle_sta_release(void *ptr); | |
| 238 | −void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb); | |
| 239 | −int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr); | |
| 240 | −typedef enum { | |
| 241 | − AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED | |
| 242 | −} ap_rx_ret; | |
| 243 | −ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, | |
| 244 | − struct sk_buff *skb, | |
| 245 | − struct hostap_80211_rx_status *rx_stats, | |
| 246 | − int wds); | |
| 247 | −int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr, | |
| 248 | − struct lib80211_crypt_data **crypt, | |
| 249 | − void **sta_ptr); | |
| 250 | −int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); | |
| 251 | −int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); | |
| 252 | −int hostap_add_sta(struct ap_data *ap, u8 *sta_addr); | |
| 253 | −int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr, | |
| 254 | − struct hostap_80211_rx_status *rx_stats); | |
| 255 | −void hostap_update_rates(local_info_t *local); | |
| 256 | −void hostap_add_wds_links(local_info_t *local); | |
| 257 | −void hostap_wds_link_oper(local_info_t *local, u8 *addr, wds_oper_type type); | |
| 258 | − | |
| 259 | −#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT | |
| 260 | −void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, | |
| 261 | − int resend); | |
| 262 | −#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 263 | − | |
| 264 | −#endif /* HOSTAP_AP_H */ | |
| @@ -1,420 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −#ifndef HOSTAP_COMMON_H | |
| 3 | −#define HOSTAP_COMMON_H | |
| 4 | − | |
| 5 | −#include <linux/types.h> | |
| 6 | −#include <linux/if_ether.h> | |
| 7 | − | |
| 8 | −/* IEEE 802.11 defines */ | |
| 9 | − | |
| 10 | −/* HFA384X Configuration RIDs */ | |
| 11 | −#define HFA384X_RID_CNFPORTTYPE 0xFC00 | |
| 12 | −#define HFA384X_RID_CNFOWNMACADDR 0xFC01 | |
| 13 | −#define HFA384X_RID_CNFDESIREDSSID 0xFC02 | |
| 14 | −#define HFA384X_RID_CNFOWNCHANNEL 0xFC03 | |
| 15 | −#define HFA384X_RID_CNFOWNSSID 0xFC04 | |
| 16 | −#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05 | |
| 17 | −#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06 | |
| 18 | −#define HFA384X_RID_CNFMAXDATALEN 0xFC07 | |
| 19 | −#define HFA384X_RID_CNFWDSADDRESS 0xFC08 | |
| 20 | −#define HFA384X_RID_CNFPMENABLED 0xFC09 | |
| 21 | −#define HFA384X_RID_CNFPMEPS 0xFC0A | |
| 22 | −#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B | |
| 23 | −#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C | |
| 24 | −#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D | |
| 25 | −#define HFA384X_RID_CNFOWNNAME 0xFC0E | |
| 26 | −#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10 | |
| 27 | −#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */ | |
| 28 | −#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */ | |
| 29 | −#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */ | |
| 30 | −#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */ | |
| 31 | −#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */ | |
| 32 | −#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */ | |
| 33 | −#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */ | |
| 34 | −#define HFA384X_RID_UNKNOWN1 0xFC20 | |
| 35 | −#define HFA384X_RID_UNKNOWN2 0xFC21 | |
| 36 | −#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23 | |
| 37 | −#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24 | |
| 38 | −#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25 | |
| 39 | −#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26 | |
| 40 | −#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27 | |
| 41 | −#define HFA384X_RID_CNFWEPFLAGS 0xFC28 | |
| 42 | −#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29 | |
| 43 | −#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A | |
| 44 | −#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */ | |
| 45 | −#define HFA384X_RID_CNFTXCONTROL 0xFC2C | |
| 46 | −#define HFA384X_RID_CNFROAMINGMODE 0xFC2D | |
| 47 | −#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */ | |
| 48 | −#define HFA384X_RID_CNFRCVCRCERROR 0xFC30 | |
| 49 | −#define HFA384X_RID_CNFMMLIFE 0xFC31 | |
| 50 | −#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32 | |
| 51 | −#define HFA384X_RID_CNFBEACONINT 0xFC33 | |
| 52 | −#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */ | |
| 53 | −#define HFA384X_RID_CNFSTAPCFINFO 0xFC35 | |
| 54 | −#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37 | |
| 55 | −#define HFA384X_RID_CNFTIMCTRL 0xFC40 | |
| 56 | −#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */ | |
| 57 | −#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */ | |
| 58 | −#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */ | |
| 59 | −#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */ | |
| 60 | −#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0; | |
| 61 | − * write only */ | |
| 62 | −#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */ | |
| 63 | −#define HFA384X_RID_GROUPADDRESSES 0xFC80 | |
| 64 | −#define HFA384X_RID_CREATEIBSS 0xFC81 | |
| 65 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82 | |
| 66 | −#define HFA384X_RID_RTSTHRESHOLD 0xFC83 | |
| 67 | −#define HFA384X_RID_TXRATECONTROL 0xFC84 | |
| 68 | −#define HFA384X_RID_PROMISCUOUSMODE 0xFC85 | |
| 69 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */ | |
| 70 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */ | |
| 71 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */ | |
| 72 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */ | |
| 73 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */ | |
| 74 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */ | |
| 75 | −#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */ | |
| 76 | −#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */ | |
| 77 | −#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */ | |
| 78 | −#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */ | |
| 79 | −#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */ | |
| 80 | −#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */ | |
| 81 | −#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */ | |
| 82 | −#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */ | |
| 83 | −#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */ | |
| 84 | −#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */ | |
| 85 | −#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */ | |
| 86 | −#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */ | |
| 87 | −#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */ | |
| 88 | −#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */ | |
| 89 | −#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */ | |
| 90 | −#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0 | |
| 91 | −#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1 | |
| 92 | −#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2 | |
| 93 | −#define HFA384X_RID_CNFBASICRATES 0xFCB3 | |
| 94 | −#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4 | |
| 95 | −#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */ | |
| 96 | −#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */ | |
| 97 | −#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */ | |
| 98 | −#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */ | |
| 99 | −#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */ | |
| 100 | −#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */ | |
| 101 | −#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */ | |
| 102 | −#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */ | |
| 103 | −#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */ | |
| 104 | −#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */ | |
| 105 | −#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */ | |
| 106 | −#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */ | |
| 107 | −#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */ | |
| 108 | −#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */ | |
| 109 | −#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */ | |
| 110 | −#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */ | |
| 111 | −#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */ | |
| 112 | −#define HFA384X_RID_TICKTIME 0xFCE0 | |
| 113 | −#define HFA384X_RID_SCANREQUEST 0xFCE1 | |
| 114 | −#define HFA384X_RID_JOINREQUEST 0xFCE2 | |
| 115 | −#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */ | |
| 116 | −#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */ | |
| 117 | −#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */ | |
| 118 | − | |
| 119 | −/* HFA384X Information RIDs */ | |
| 120 | −#define HFA384X_RID_MAXLOADTIME 0xFD00 | |
| 121 | −#define HFA384X_RID_DOWNLOADBUFFER 0xFD01 | |
| 122 | −#define HFA384X_RID_PRIID 0xFD02 | |
| 123 | −#define HFA384X_RID_PRISUPRANGE 0xFD03 | |
| 124 | −#define HFA384X_RID_CFIACTRANGES 0xFD04 | |
| 125 | −#define HFA384X_RID_NICSERNUM 0xFD0A | |
| 126 | −#define HFA384X_RID_NICID 0xFD0B | |
| 127 | −#define HFA384X_RID_MFISUPRANGE 0xFD0C | |
| 128 | −#define HFA384X_RID_CFISUPRANGE 0xFD0D | |
| 129 | −#define HFA384X_RID_CHANNELLIST 0xFD10 | |
| 130 | −#define HFA384X_RID_REGULATORYDOMAINS 0xFD11 | |
| 131 | −#define HFA384X_RID_TEMPTYPE 0xFD12 | |
| 132 | −#define HFA384X_RID_CIS 0xFD13 | |
| 133 | −#define HFA384X_RID_STAID 0xFD20 | |
| 134 | −#define HFA384X_RID_STASUPRANGE 0xFD21 | |
| 135 | −#define HFA384X_RID_MFIACTRANGES 0xFD22 | |
| 136 | −#define HFA384X_RID_CFIACTRANGES2 0xFD23 | |
| 137 | −#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1; | |
| 138 | − * only Prism2.5(?) */ | |
| 139 | −#define HFA384X_RID_PORTSTATUS 0xFD40 | |
| 140 | −#define HFA384X_RID_CURRENTSSID 0xFD41 | |
| 141 | −#define HFA384X_RID_CURRENTBSSID 0xFD42 | |
| 142 | −#define HFA384X_RID_COMMSQUALITY 0xFD43 | |
| 143 | −#define HFA384X_RID_CURRENTTXRATE 0xFD44 | |
| 144 | −#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45 | |
| 145 | −#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46 | |
| 146 | −#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47 | |
| 147 | −#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48 | |
| 148 | −#define HFA384X_RID_LONGRETRYLIMIT 0xFD49 | |
| 149 | −#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A | |
| 150 | −#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B | |
| 151 | −#define HFA384X_RID_CFPOLLABLE 0xFD4C | |
| 152 | −#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D | |
| 153 | −#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F | |
| 154 | −#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */ | |
| 155 | −#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */ | |
| 156 | −#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */ | |
| 157 | −#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */ | |
| 158 | −#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */ | |
| 159 | −#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */ | |
| 160 | −#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */ | |
| 161 | −#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */ | |
| 162 | −#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */ | |
| 163 | −#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */ | |
| 164 | −#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */ | |
| 165 | −#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */ | |
| 166 | −#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */ | |
| 167 | −#define HFA384X_RID_PHYTYPE 0xFDC0 | |
| 168 | −#define HFA384X_RID_CURRENTCHANNEL 0xFDC1 | |
| 169 | −#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2 | |
| 170 | −#define HFA384X_RID_CCAMODE 0xFDC3 | |
| 171 | −#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6 | |
| 172 | −#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */ | |
| 173 | −#define HFA384X_RID_BUILDSEQ 0xFFFE | |
| 174 | −#define HFA384X_RID_FWID 0xFFFF | |
| 175 | − | |
| 176 | − | |
| 177 | −struct hfa384x_comp_ident | |
| 178 | −{ | |
| 179 | − __le16 id; | |
| 180 | − __le16 variant; | |
| 181 | − __le16 major; | |
| 182 | − __le16 minor; | |
| 183 | −} __packed; | |
| 184 | − | |
| 185 | −#define HFA384X_COMP_ID_PRI 0x15 | |
| 186 | −#define HFA384X_COMP_ID_STA 0x1f | |
| 187 | −#define HFA384X_COMP_ID_FW_AP 0x14b | |
| 188 | − | |
| 189 | −struct hfa384x_sup_range | |
| 190 | −{ | |
| 191 | − __le16 role; | |
| 192 | − __le16 id; | |
| 193 | − __le16 variant; | |
| 194 | − __le16 bottom; | |
| 195 | − __le16 top; | |
| 196 | −} __packed; | |
| 197 | − | |
| 198 | − | |
| 199 | −struct hfa384x_build_id | |
| 200 | −{ | |
| 201 | − __le16 pri_seq; | |
| 202 | − __le16 sec_seq; | |
| 203 | −} __packed; | |
| 204 | − | |
| 205 | −/* FD01 - Download Buffer */ | |
| 206 | −struct hfa384x_rid_download_buffer | |
| 207 | −{ | |
| 208 | − __le16 page; | |
| 209 | − __le16 offset; | |
| 210 | − __le16 length; | |
| 211 | −} __packed; | |
| 212 | − | |
| 213 | −/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */ | |
| 214 | −struct hfa384x_comms_quality { | |
| 215 | − __le16 comm_qual; /* 0 .. 92 */ | |
| 216 | − __le16 signal_level; /* 27 .. 154 */ | |
| 217 | − __le16 noise_level; /* 27 .. 154 */ | |
| 218 | −} __packed; | |
| 219 | − | |
| 220 | − | |
| 221 | −/* netdevice private ioctls (used, e.g., with iwpriv from user space) */ | |
| 222 | − | |
| 223 | −/* New wireless extensions API - SET/GET convention (even ioctl numbers are | |
| 224 | − * root only) | |
| 225 | − */ | |
| 226 | −#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0) | |
| 227 | −#define PRISM2_IOCTL_GET_PRISM2_PARAM (SIOCIWFIRSTPRIV + 1) | |
| 228 | −#define PRISM2_IOCTL_WRITEMIF (SIOCIWFIRSTPRIV + 2) | |
| 229 | −#define PRISM2_IOCTL_READMIF (SIOCIWFIRSTPRIV + 3) | |
| 230 | −#define PRISM2_IOCTL_MONITOR (SIOCIWFIRSTPRIV + 4) | |
| 231 | −#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6) | |
| 232 | −#define PRISM2_IOCTL_INQUIRE (SIOCIWFIRSTPRIV + 8) | |
| 233 | −#define PRISM2_IOCTL_WDS_ADD (SIOCIWFIRSTPRIV + 10) | |
| 234 | −#define PRISM2_IOCTL_WDS_DEL (SIOCIWFIRSTPRIV + 12) | |
| 235 | −#define PRISM2_IOCTL_SET_RID_WORD (SIOCIWFIRSTPRIV + 14) | |
| 236 | −#define PRISM2_IOCTL_MACCMD (SIOCIWFIRSTPRIV + 16) | |
| 237 | −#define PRISM2_IOCTL_ADDMAC (SIOCIWFIRSTPRIV + 18) | |
| 238 | −#define PRISM2_IOCTL_DELMAC (SIOCIWFIRSTPRIV + 20) | |
| 239 | −#define PRISM2_IOCTL_KICKMAC (SIOCIWFIRSTPRIV + 22) | |
| 240 | − | |
| 241 | −/* following are not in SIOCGIWPRIV list; check permission in the driver code | |
| 242 | − */ | |
| 243 | −#define PRISM2_IOCTL_DOWNLOAD (SIOCDEVPRIVATE + 13) | |
| 244 | −#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14) | |
| 245 | − | |
| 246 | − | |
| 247 | −/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */ | |
| 248 | −enum { | |
| 249 | − /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */ | |
| 250 | − PRISM2_PARAM_TXRATECTRL = 2, | |
| 251 | − PRISM2_PARAM_BEACON_INT = 3, | |
| 252 | − PRISM2_PARAM_PSEUDO_IBSS = 4, | |
| 253 | − PRISM2_PARAM_ALC = 5, | |
| 254 | − /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */ | |
| 255 | − PRISM2_PARAM_DUMP = 7, | |
| 256 | − PRISM2_PARAM_OTHER_AP_POLICY = 8, | |
| 257 | − PRISM2_PARAM_AP_MAX_INACTIVITY = 9, | |
| 258 | − PRISM2_PARAM_AP_BRIDGE_PACKETS = 10, | |
| 259 | − PRISM2_PARAM_DTIM_PERIOD = 11, | |
| 260 | − PRISM2_PARAM_AP_NULLFUNC_ACK = 12, | |
| 261 | − PRISM2_PARAM_MAX_WDS = 13, | |
| 262 | − PRISM2_PARAM_AP_AUTOM_AP_WDS = 14, | |
| 263 | − PRISM2_PARAM_AP_AUTH_ALGS = 15, | |
| 264 | − PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16, | |
| 265 | − PRISM2_PARAM_HOST_ENCRYPT = 17, | |
| 266 | − PRISM2_PARAM_HOST_DECRYPT = 18, | |
| 267 | − /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19, REMOVED 2005-08-14 */ | |
| 268 | − /* PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20, REMOVED 2005-08-14 */ | |
| 269 | − PRISM2_PARAM_HOST_ROAMING = 21, | |
| 270 | − PRISM2_PARAM_BCRX_STA_KEY = 22, | |
| 271 | − PRISM2_PARAM_IEEE_802_1X = 23, | |
| 272 | − PRISM2_PARAM_ANTSEL_TX = 24, | |
| 273 | − PRISM2_PARAM_ANTSEL_RX = 25, | |
| 274 | − PRISM2_PARAM_MONITOR_TYPE = 26, | |
| 275 | − PRISM2_PARAM_WDS_TYPE = 27, | |
| 276 | − PRISM2_PARAM_HOSTSCAN = 28, | |
| 277 | − PRISM2_PARAM_AP_SCAN = 29, | |
| 278 | − PRISM2_PARAM_ENH_SEC = 30, | |
| 279 | − PRISM2_PARAM_IO_DEBUG = 31, | |
| 280 | − PRISM2_PARAM_BASIC_RATES = 32, | |
| 281 | − PRISM2_PARAM_OPER_RATES = 33, | |
| 282 | − PRISM2_PARAM_HOSTAPD = 34, | |
| 283 | − PRISM2_PARAM_HOSTAPD_STA = 35, | |
| 284 | − PRISM2_PARAM_WPA = 36, | |
| 285 | − PRISM2_PARAM_PRIVACY_INVOKED = 37, | |
| 286 | − PRISM2_PARAM_TKIP_COUNTERMEASURES = 38, | |
| 287 | − PRISM2_PARAM_DROP_UNENCRYPTED = 39, | |
| 288 | − PRISM2_PARAM_SCAN_CHANNEL_MASK = 40, | |
| 289 | −}; | |
| 290 | − | |
| 291 | −enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, | |
| 292 | − HOSTAP_ANTSEL_LOW = 2, HOSTAP_ANTSEL_HIGH = 3 }; | |
| 293 | − | |
| 294 | − | |
| 295 | −/* PRISM2_IOCTL_MACCMD ioctl() subcommands: */ | |
| 296 | −enum { AP_MAC_CMD_POLICY_OPEN = 0, AP_MAC_CMD_POLICY_ALLOW = 1, | |
| 297 | − AP_MAC_CMD_POLICY_DENY = 2, AP_MAC_CMD_FLUSH = 3, | |
| 298 | − AP_MAC_CMD_KICKALL = 4 }; | |
| 299 | − | |
| 300 | − | |
| 301 | −/* PRISM2_IOCTL_DOWNLOAD ioctl() dl_cmd: */ | |
| 302 | −enum { | |
| 303 | − PRISM2_DOWNLOAD_VOLATILE = 1 /* RAM */, | |
| 304 | − /* Note! Old versions of prism2_srec have a fatal error in CRC-16 | |
| 305 | − * calculation, which will corrupt all non-volatile downloads. | |
| 306 | − * PRISM2_DOWNLOAD_NON_VOLATILE used to be 2, but it is now 3 to | |
| 307 | − * prevent use of old versions of prism2_srec for non-volatile | |
| 308 | − * download. */ | |
| 309 | − PRISM2_DOWNLOAD_NON_VOLATILE = 3 /* FLASH */, | |
| 310 | − PRISM2_DOWNLOAD_VOLATILE_GENESIS = 4 /* RAM in Genesis mode */, | |
| 311 | − /* Persistent versions of volatile download commands (keep firmware | |
| 312 | − * data in memory and automatically re-download after hw_reset */ | |
| 313 | − PRISM2_DOWNLOAD_VOLATILE_PERSISTENT = 5, | |
| 314 | − PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT = 6, | |
| 315 | −}; | |
| 316 | − | |
| 317 | −struct prism2_download_param { | |
| 318 | − u32 dl_cmd; | |
| 319 | − u32 start_addr; | |
| 320 | − u32 num_areas; | |
| 321 | − struct prism2_download_area { | |
| 322 | − u32 addr; /* wlan card address */ | |
| 323 | − u32 len; | |
| 324 | − void __user *ptr; /* pointer to data in user space */ | |
| 325 | − } data[]; | |
| 326 | −}; | |
| 327 | − | |
| 328 | −#define PRISM2_MAX_DOWNLOAD_AREA_LEN 131072 | |
| 329 | −#define PRISM2_MAX_DOWNLOAD_LEN 262144 | |
| 330 | − | |
| 331 | − | |
| 332 | −/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */ | |
| 333 | −enum { | |
| 334 | − PRISM2_HOSTAPD_FLUSH = 1, | |
| 335 | − PRISM2_HOSTAPD_ADD_STA = 2, | |
| 336 | − PRISM2_HOSTAPD_REMOVE_STA = 3, | |
| 337 | − PRISM2_HOSTAPD_GET_INFO_STA = 4, | |
| 338 | − /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */ | |
| 339 | − PRISM2_SET_ENCRYPTION = 6, | |
| 340 | − PRISM2_GET_ENCRYPTION = 7, | |
| 341 | − PRISM2_HOSTAPD_SET_FLAGS_STA = 8, | |
| 342 | − PRISM2_HOSTAPD_GET_RID = 9, | |
| 343 | − PRISM2_HOSTAPD_SET_RID = 10, | |
| 344 | − PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11, | |
| 345 | − PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12, | |
| 346 | − PRISM2_HOSTAPD_MLME = 13, | |
| 347 | − PRISM2_HOSTAPD_SCAN_REQ = 14, | |
| 348 | − PRISM2_HOSTAPD_STA_CLEAR_STATS = 15, | |
| 349 | −}; | |
| 350 | − | |
| 351 | −#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 | |
| 352 | −#define PRISM2_HOSTAPD_RID_HDR_LEN \ | |
| 353 | −offsetof(struct prism2_hostapd_param, u.rid.data) | |
| 354 | −#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ | |
| 355 | −offsetof(struct prism2_hostapd_param, u.generic_elem.data) | |
| 356 | − | |
| 357 | −/* Maximum length for algorithm names (-1 for nul termination) used in ioctl() | |
| 358 | − */ | |
| 359 | −#define HOSTAP_CRYPT_ALG_NAME_LEN 16 | |
| 360 | − | |
| 361 | − | |
| 362 | −struct prism2_hostapd_param { | |
| 363 | − u32 cmd; | |
| 364 | − u8 sta_addr[ETH_ALEN]; | |
| 365 | − union { | |
| 366 | − struct { | |
| 367 | − u16 aid; | |
| 368 | − u16 capability; | |
| 369 | − u8 tx_supp_rates; | |
| 370 | − } add_sta; | |
| 371 | − struct { | |
| 372 | − u32 inactive_sec; | |
| 373 | − } get_info_sta; | |
| 374 | − struct { | |
| 375 | − u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN]; | |
| 376 | − u32 flags; | |
| 377 | − u32 err; | |
| 378 | − u8 idx; | |
| 379 | − u8 seq[8]; /* sequence counter (set: RX, get: TX) */ | |
| 380 | − u16 key_len; | |
| 381 | − u8 key[0]; | |
| 382 | − } crypt; | |
| 383 | − struct { | |
| 384 | − u32 flags_and; | |
| 385 | − u32 flags_or; | |
| 386 | − } set_flags_sta; | |
| 387 | − struct { | |
| 388 | − u16 rid; | |
| 389 | − u16 len; | |
| 390 | − u8 data[0]; | |
| 391 | − } rid; | |
| 392 | − struct { | |
| 393 | − u8 len; | |
| 394 | − u8 data[0]; | |
| 395 | − } generic_elem; | |
| 396 | − struct { | |
| 397 | −#define MLME_STA_DEAUTH 0 | |
| 398 | −#define MLME_STA_DISASSOC 1 | |
| 399 | − u16 cmd; | |
| 400 | − u16 reason_code; | |
| 401 | − } mlme; | |
| 402 | − struct { | |
| 403 | − u8 ssid_len; | |
| 404 | − u8 ssid[32]; | |
| 405 | − } scan_req; | |
| 406 | − } u; | |
| 407 | −}; | |
| 408 | − | |
| 409 | −#define HOSTAP_CRYPT_FLAG_SET_TX_KEY BIT(0) | |
| 410 | −#define HOSTAP_CRYPT_FLAG_PERMANENT BIT(1) | |
| 411 | − | |
| 412 | −#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2 | |
| 413 | −#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3 | |
| 414 | −#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4 | |
| 415 | −#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5 | |
| 416 | −#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6 | |
| 417 | −#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7 | |
| 418 | − | |
| 419 | − | |
| 420 | −#endif /* HOSTAP_COMMON_H */ | |
| @@ -1,49 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | −#ifndef HOSTAP_CONFIG_H | |
| 3 | −#define HOSTAP_CONFIG_H | |
| 4 | − | |
| 5 | −/* In the previous versions of Host AP driver, support for user space version | |
| 6 | − * of IEEE 802.11 management (hostapd) used to be disabled in the default | |
| 7 | − * configuration. From now on, support for hostapd is always included and it is | |
| 8 | − * possible to disable kernel driver version of IEEE 802.11 management with a | |
| 9 | − * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ | |
| 10 | −/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ | |
| 11 | − | |
| 12 | −/* Maximum number of events handler per one interrupt */ | |
| 13 | −#define PRISM2_MAX_INTERRUPT_EVENTS 20 | |
| 14 | − | |
| 15 | −/* Include code for downloading firmware images into volatile RAM. */ | |
| 16 | −#define PRISM2_DOWNLOAD_SUPPORT | |
| 17 | − | |
| 18 | −/* Allow kernel configuration to enable download support. */ | |
| 19 | −#if !defined(PRISM2_DOWNLOAD_SUPPORT) && defined(CONFIG_HOSTAP_FIRMWARE) | |
| 20 | −#define PRISM2_DOWNLOAD_SUPPORT | |
| 21 | −#endif | |
| 22 | − | |
| 23 | −/* Allow kernel configuration to enable non-volatile download support. */ | |
| 24 | −#ifdef CONFIG_HOSTAP_FIRMWARE_NVRAM | |
| 25 | −#define PRISM2_NON_VOLATILE_DOWNLOAD | |
| 26 | −#endif | |
| 27 | − | |
| 28 | −/* Save low-level I/O for debugging. This should not be enabled in normal use. | |
| 29 | − */ | |
| 30 | −/* #define PRISM2_IO_DEBUG */ | |
| 31 | − | |
| 32 | −/* Following defines can be used to remove unneeded parts of the driver, e.g., | |
| 33 | − * to limit the size of the kernel module. Definitions can be added here in | |
| 34 | − * hostap_config.h or they can be added to make command with ccflags-y, | |
| 35 | − * e.g., | |
| 36 | − * 'make pccard ccflags-y="-DPRISM2_NO_DEBUG -DPRISM2_NO_PROCFS_DEBUG"' | |
| 37 | − */ | |
| 38 | − | |
| 39 | −/* Do not include debug messages into the driver */ | |
| 40 | −/* #define PRISM2_NO_DEBUG */ | |
| 41 | − | |
| 42 | −/* Do not include /proc/net/prism2/wlan#/{registers,debug} */ | |
| 43 | −/* #define PRISM2_NO_PROCFS_DEBUG */ | |
| 44 | − | |
| 45 | −/* Do not include station functionality (i.e., allow only Master (Host AP) mode | |
| 46 | − */ | |
| 47 | −/* #define PRISM2_NO_STATION_MODES */ | |
| 48 | − | |
| 49 | −#endif /* HOSTAP_CONFIG_H */ | |
| @@ -1,710 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −#define PRISM2_PCCARD | |
| 3 | − | |
| 4 | −#include <linux/module.h> | |
| 5 | −#include <linux/if.h> | |
| 6 | −#include <linux/slab.h> | |
| 7 | −#include <linux/wait.h> | |
| 8 | −#include <linux/timer.h> | |
| 9 | −#include <linux/skbuff.h> | |
| 10 | −#include <linux/netdevice.h> | |
| 11 | −#include <linux/workqueue.h> | |
| 12 | −#include <linux/wireless.h> | |
| 13 | −#include <net/iw_handler.h> | |
| 14 | − | |
| 15 | −#include <pcmcia/cistpl.h> | |
| 16 | −#include <pcmcia/cisreg.h> | |
| 17 | −#include <pcmcia/ds.h> | |
| 18 | − | |
| 19 | −#include <asm/io.h> | |
| 20 | − | |
| 21 | −#include "hostap_wlan.h" | |
| 22 | − | |
| 23 | − | |
| 24 | −static char *dev_info = "hostap_cs"; | |
| 25 | − | |
| 26 | −MODULE_AUTHOR("Jouni Malinen"); | |
| 27 | −MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " | |
| 28 | − "cards (PC Card)."); | |
| 29 | −MODULE_LICENSE("GPL"); | |
| 30 | − | |
| 31 | − | |
| 32 | −static int ignore_cis_vcc; | |
| 33 | −module_param(ignore_cis_vcc, int, 0444); | |
| 34 | −MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry"); | |
| 35 | − | |
| 36 | − | |
| 37 | −/* struct local_info::hw_priv */ | |
| 38 | −struct hostap_cs_priv { | |
| 39 | − struct pcmcia_device *link; | |
| 40 | − int sandisk_connectplus; | |
| 41 | −}; | |
| 42 | − | |
| 43 | − | |
| 44 | −#ifdef PRISM2_IO_DEBUG | |
| 45 | − | |
| 46 | −static inline void hfa384x_outb_debug(struct net_device *dev, int a, u8 v) | |
| 47 | −{ | |
| 48 | − struct hostap_interface *iface; | |
| 49 | − local_info_t *local; | |
| 50 | − unsigned long flags; | |
| 51 | − | |
| 52 | − iface = netdev_priv(dev); | |
| 53 | − local = iface->local; | |
| 54 | − spin_lock_irqsave(&local->lock, flags); | |
| 55 | − prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTB, a, v); | |
| 56 | − outb(v, dev->base_addr + a); | |
| 57 | − spin_unlock_irqrestore(&local->lock, flags); | |
| 58 | −} | |
| 59 | − | |
| 60 | −static inline u8 hfa384x_inb_debug(struct net_device *dev, int a) | |
| 61 | −{ | |
| 62 | − struct hostap_interface *iface; | |
| 63 | − local_info_t *local; | |
| 64 | − unsigned long flags; | |
| 65 | − u8 v; | |
| 66 | − | |
| 67 | − iface = netdev_priv(dev); | |
| 68 | − local = iface->local; | |
| 69 | − spin_lock_irqsave(&local->lock, flags); | |
| 70 | − v = inb(dev->base_addr + a); | |
| 71 | − prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INB, a, v); | |
| 72 | − spin_unlock_irqrestore(&local->lock, flags); | |
| 73 | − return v; | |
| 74 | −} | |
| 75 | − | |
| 76 | −static inline void hfa384x_outw_debug(struct net_device *dev, int a, u16 v) | |
| 77 | −{ | |
| 78 | − struct hostap_interface *iface; | |
| 79 | − local_info_t *local; | |
| 80 | − unsigned long flags; | |
| 81 | − | |
| 82 | − iface = netdev_priv(dev); | |
| 83 | − local = iface->local; | |
| 84 | − spin_lock_irqsave(&local->lock, flags); | |
| 85 | − prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTW, a, v); | |
| 86 | − outw(v, dev->base_addr + a); | |
| 87 | − spin_unlock_irqrestore(&local->lock, flags); | |
| 88 | −} | |
| 89 | − | |
| 90 | −static inline u16 hfa384x_inw_debug(struct net_device *dev, int a) | |
| 91 | −{ | |
| 92 | − struct hostap_interface *iface; | |
| 93 | − local_info_t *local; | |
| 94 | − unsigned long flags; | |
| 95 | − u16 v; | |
| 96 | − | |
| 97 | − iface = netdev_priv(dev); | |
| 98 | − local = iface->local; | |
| 99 | − spin_lock_irqsave(&local->lock, flags); | |
| 100 | − v = inw(dev->base_addr + a); | |
| 101 | − prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INW, a, v); | |
| 102 | − spin_unlock_irqrestore(&local->lock, flags); | |
| 103 | − return v; | |
| 104 | −} | |
| 105 | − | |
| 106 | −static inline void hfa384x_outsw_debug(struct net_device *dev, int a, | |
| 107 | − u8 *buf, int wc) | |
| 108 | −{ | |
| 109 | − struct hostap_interface *iface; | |
| 110 | − local_info_t *local; | |
| 111 | − unsigned long flags; | |
| 112 | − | |
| 113 | − iface = netdev_priv(dev); | |
| 114 | − local = iface->local; | |
| 115 | − spin_lock_irqsave(&local->lock, flags); | |
| 116 | − prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_OUTSW, a, wc); | |
| 117 | − outsw(dev->base_addr + a, buf, wc); | |
| 118 | − spin_unlock_irqrestore(&local->lock, flags); | |
| 119 | −} | |
| 120 | − | |
| 121 | −static inline void hfa384x_insw_debug(struct net_device *dev, int a, | |
| 122 | − u8 *buf, int wc) | |
| 123 | −{ | |
| 124 | − struct hostap_interface *iface; | |
| 125 | − local_info_t *local; | |
| 126 | − unsigned long flags; | |
| 127 | − | |
| 128 | − iface = netdev_priv(dev); | |
| 129 | − local = iface->local; | |
| 130 | − spin_lock_irqsave(&local->lock, flags); | |
| 131 | − prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INSW, a, wc); | |
| 132 | − insw(dev->base_addr + a, buf, wc); | |
| 133 | − spin_unlock_irqrestore(&local->lock, flags); | |
| 134 | −} | |
| 135 | − | |
| 136 | −#define HFA384X_OUTB(v,a) hfa384x_outb_debug(dev, (a), (v)) | |
| 137 | −#define HFA384X_INB(a) hfa384x_inb_debug(dev, (a)) | |
| 138 | −#define HFA384X_OUTW(v,a) hfa384x_outw_debug(dev, (a), (v)) | |
| 139 | −#define HFA384X_INW(a) hfa384x_inw_debug(dev, (a)) | |
| 140 | −#define HFA384X_OUTSW(a, buf, wc) hfa384x_outsw_debug(dev, (a), (buf), (wc)) | |
| 141 | −#define HFA384X_INSW(a, buf, wc) hfa384x_insw_debug(dev, (a), (buf), (wc)) | |
| 142 | − | |
| 143 | −#else /* PRISM2_IO_DEBUG */ | |
| 144 | − | |
| 145 | −#define HFA384X_OUTB(v,a) outb((v), dev->base_addr + (a)) | |
| 146 | −#define HFA384X_INB(a) inb(dev->base_addr + (a)) | |
| 147 | −#define HFA384X_OUTW(v,a) outw((v), dev->base_addr + (a)) | |
| 148 | −#define HFA384X_INW(a) inw(dev->base_addr + (a)) | |
| 149 | −#define HFA384X_INSW(a, buf, wc) insw(dev->base_addr + (a), buf, wc) | |
| 150 | −#define HFA384X_OUTSW(a, buf, wc) outsw(dev->base_addr + (a), buf, wc) | |
| 151 | − | |
| 152 | −#endif /* PRISM2_IO_DEBUG */ | |
| 153 | − | |
| 154 | − | |
| 155 | −static int hfa384x_from_bap(struct net_device *dev, u16 bap, void *buf, | |
| 156 | − int len) | |
| 157 | −{ | |
| 158 | − u16 d_off; | |
| 159 | − u16 *pos; | |
| 160 | − | |
| 161 | − d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | |
| 162 | − pos = (u16 *) buf; | |
| 163 | − | |
| 164 | − if (len / 2) | |
| 165 | − HFA384X_INSW(d_off, buf, len / 2); | |
| 166 | − pos += len / 2; | |
| 167 | − | |
| 168 | − if (len & 1) | |
| 169 | − *((char *) pos) = HFA384X_INB(d_off); | |
| 170 | − | |
| 171 | − return 0; | |
| 172 | −} | |
| 173 | − | |
| 174 | − | |
| 175 | −static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | |
| 176 | −{ | |
| 177 | − u16 d_off; | |
| 178 | − u16 *pos; | |
| 179 | − | |
| 180 | − d_off = (bap == 1) ? HFA384X_DATA1_OFF : HFA384X_DATA0_OFF; | |
| 181 | − pos = (u16 *) buf; | |
| 182 | − | |
| 183 | − if (len / 2) | |
| 184 | − HFA384X_OUTSW(d_off, buf, len / 2); | |
| 185 | − pos += len / 2; | |
| 186 | − | |
| 187 | − if (len & 1) | |
| 188 | − HFA384X_OUTB(*((char *) pos), d_off); | |
| 189 | − | |
| 190 | − return 0; | |
| 191 | −} | |
| 192 | − | |
| 193 | − | |
| 194 | −/* FIX: This might change at some point.. */ | |
| 195 | −#include "hostap_hw.c" | |
| 196 | − | |
| 197 | − | |
| 198 | − | |
| 199 | −static void prism2_detach(struct pcmcia_device *p_dev); | |
| 200 | −static void prism2_release(u_long arg); | |
| 201 | −static int prism2_config(struct pcmcia_device *link); | |
| 202 | − | |
| 203 | − | |
| 204 | −static int prism2_pccard_card_present(local_info_t *local) | |
| 205 | −{ | |
| 206 | − struct hostap_cs_priv *hw_priv = local->hw_priv; | |
| 207 | − if (hw_priv != NULL && hw_priv->link != NULL && pcmcia_dev_present(hw_priv->link)) | |
| 208 | − return 1; | |
| 209 | − return 0; | |
| 210 | −} | |
| 211 | − | |
| 212 | − | |
| 213 | −/* | |
| 214 | − * SanDisk CompactFlash WLAN Flashcard - Product Manual v1.0 | |
| 215 | − * Document No. 20-10-00058, January 2004 | |
| 216 | − * http://www.sandisk.com/pdf/industrial/ProdManualCFWLANv1.0.pdf | |
| 217 | − */ | |
| 218 | −#define SANDISK_WLAN_ACTIVATION_OFF 0x40 | |
| 219 | −#define SANDISK_HCR_OFF 0x42 | |
| 220 | − | |
| 221 | − | |
| 222 | −static void sandisk_set_iobase(local_info_t *local) | |
| 223 | −{ | |
| 224 | − int res; | |
| 225 | − struct hostap_cs_priv *hw_priv = local->hw_priv; | |
| 226 | − | |
| 227 | − res = pcmcia_write_config_byte(hw_priv->link, 0x10, | |
| 228 | − hw_priv->link->resource[0]->start & 0x00ff); | |
| 229 | − if (res != 0) { | |
| 230 | − printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 0 -" | |
| 231 | − " res=%d\n", res); | |
| 232 | − } | |
| 233 | − udelay(10); | |
| 234 | − | |
| 235 | − res = pcmcia_write_config_byte(hw_priv->link, 0x12, | |
| 236 | − (hw_priv->link->resource[0]->start >> 8) & 0x00ff); | |
| 237 | − if (res != 0) { | |
| 238 | − printk(KERN_DEBUG "Prism3 SanDisk - failed to set I/O base 1 -" | |
| 239 | − " res=%d\n", res); | |
| 240 | − } | |
| 241 | −} | |
| 242 | − | |
| 243 | − | |
| 244 | −static void sandisk_write_hcr(local_info_t *local, int hcr) | |
| 245 | −{ | |
| 246 | − struct net_device *dev = local->dev; | |
| 247 | − int i; | |
| 248 | − | |
| 249 | − HFA384X_OUTB(0x80, SANDISK_WLAN_ACTIVATION_OFF); | |
| 250 | − udelay(50); | |
| 251 | − for (i = 0; i < 10; i++) { | |
| 252 | − HFA384X_OUTB(hcr, SANDISK_HCR_OFF); | |
| 253 | − } | |
| 254 | − udelay(55); | |
| 255 | − HFA384X_OUTB(0x45, SANDISK_WLAN_ACTIVATION_OFF); | |
| 256 | −} | |
| 257 | − | |
| 258 | − | |
| 259 | −static int sandisk_enable_wireless(struct net_device *dev) | |
| 260 | −{ | |
| 261 | − int res, ret = 0; | |
| 262 | − struct hostap_interface *iface = netdev_priv(dev); | |
| 263 | − local_info_t *local = iface->local; | |
| 264 | − struct hostap_cs_priv *hw_priv = local->hw_priv; | |
| 265 | − | |
| 266 | − if (resource_size(hw_priv->link->resource[0]) < 0x42) { | |
| 267 | − /* Not enough ports to be SanDisk multi-function card */ | |
| 268 | − ret = -ENODEV; | |
| 269 | − goto done; | |
| 270 | − } | |
| 271 | − | |
| 272 | − if (hw_priv->link->manf_id != 0xd601 || hw_priv->link->card_id != 0x0101) { | |
| 273 | − /* No SanDisk manfid found */ | |
| 274 | − ret = -ENODEV; | |
| 275 | − goto done; | |
| 276 | − } | |
| 277 | − | |
| 278 | − if (hw_priv->link->socket->functions < 2) { | |
| 279 | − /* No multi-function links found */ | |
| 280 | − ret = -ENODEV; | |
| 281 | − goto done; | |
| 282 | − } | |
| 283 | − | |
| 284 | − printk(KERN_DEBUG "%s: Multi-function SanDisk ConnectPlus detected" | |
| 285 | − " - using vendor-specific initialization\n", dev->name); | |
| 286 | − hw_priv->sandisk_connectplus = 1; | |
| 287 | − | |
| 288 | − res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, | |
| 289 | − COR_SOFT_RESET); | |
| 290 | − if (res != 0) { | |
| 291 | − printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | |
| 292 | − dev->name, res); | |
| 293 | − goto done; | |
| 294 | − } | |
| 295 | − mdelay(5); | |
| 296 | − | |
| 297 | − /* | |
| 298 | − * Do not enable interrupts here to avoid some bogus events. Interrupts | |
| 299 | − * will be enabled during the first cor_sreset call. | |
| 300 | − */ | |
| 301 | − res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, | |
| 302 | − (COR_LEVEL_REQ | 0x8 | COR_ADDR_DECODE | | |
| 303 | − COR_FUNC_ENA)); | |
| 304 | − if (res != 0) { | |
| 305 | − printk(KERN_DEBUG "%s: SanDisk - COR sreset failed (%d)\n", | |
| 306 | − dev->name, res); | |
| 307 | − goto done; | |
| 308 | − } | |
| 309 | − mdelay(5); | |
| 310 | − | |
| 311 | − sandisk_set_iobase(local); | |
| 312 | − | |
| 313 | − HFA384X_OUTB(0xc5, SANDISK_WLAN_ACTIVATION_OFF); | |
| 314 | − udelay(10); | |
| 315 | − HFA384X_OUTB(0x4b, SANDISK_WLAN_ACTIVATION_OFF); | |
| 316 | − udelay(10); | |
| 317 | − | |
| 318 | −done: | |
| 319 | − return ret; | |
| 320 | −} | |
| 321 | − | |
| 322 | − | |
| 323 | −static void prism2_pccard_cor_sreset(local_info_t *local) | |
| 324 | −{ | |
| 325 | − int res; | |
| 326 | − u8 val; | |
| 327 | − struct hostap_cs_priv *hw_priv = local->hw_priv; | |
| 328 | − | |
| 329 | − if (!prism2_pccard_card_present(local)) | |
| 330 | − return; | |
| 331 | − | |
| 332 | − res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &val); | |
| 333 | − if (res != 0) { | |
| 334 | − printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 1 (%d)\n", | |
| 335 | − res); | |
| 336 | − return; | |
| 337 | − } | |
| 338 | − printk(KERN_DEBUG "prism2_pccard_cor_sreset: original COR %02x\n", | |
| 339 | − val); | |
| 340 | − | |
| 341 | − val |= COR_SOFT_RESET; | |
| 342 | − res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); | |
| 343 | − if (res != 0) { | |
| 344 | − printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 2 (%d)\n", | |
| 345 | − res); | |
| 346 | − return; | |
| 347 | − } | |
| 348 | − | |
| 349 | − mdelay(hw_priv->sandisk_connectplus ? 5 : 2); | |
| 350 | − | |
| 351 | − val &= ~COR_SOFT_RESET; | |
| 352 | − if (hw_priv->sandisk_connectplus) | |
| 353 | − val |= COR_IREQ_ENA; | |
| 354 | − res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, val); | |
| 355 | − if (res != 0) { | |
| 356 | − printk(KERN_DEBUG "prism2_pccard_cor_sreset failed 3 (%d)\n", | |
| 357 | − res); | |
| 358 | − return; | |
| 359 | − } | |
| 360 | − | |
| 361 | − mdelay(hw_priv->sandisk_connectplus ? 5 : 2); | |
| 362 | − | |
| 363 | − if (hw_priv->sandisk_connectplus) | |
| 364 | − sandisk_set_iobase(local); | |
| 365 | −} | |
| 366 | − | |
| 367 | − | |
| 368 | −static void prism2_pccard_genesis_reset(local_info_t *local, int hcr) | |
| 369 | −{ | |
| 370 | − int res; | |
| 371 | − u8 old_cor; | |
| 372 | − struct hostap_cs_priv *hw_priv = local->hw_priv; | |
| 373 | − | |
| 374 | − if (!prism2_pccard_card_present(local)) | |
| 375 | − return; | |
| 376 | − | |
| 377 | − if (hw_priv->sandisk_connectplus) { | |
| 378 | − sandisk_write_hcr(local, hcr); | |
| 379 | − return; | |
| 380 | − } | |
| 381 | − | |
| 382 | − res = pcmcia_read_config_byte(hw_priv->link, CISREG_COR, &old_cor); | |
| 383 | − if (res != 0) { | |
| 384 | − printk(KERN_DEBUG "%s failed 1 (%d)\n", __func__, res); | |
| 385 | − return; | |
| 386 | − } | |
| 387 | − printk(KERN_DEBUG "%s: original COR %02x\n", __func__, old_cor); | |
| 388 | − | |
| 389 | − res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, | |
| 390 | − old_cor | COR_SOFT_RESET); | |
| 391 | − if (res != 0) { | |
| 392 | − printk(KERN_DEBUG "%s failed 2 (%d)\n", __func__, res); | |
| 393 | − return; | |
| 394 | − } | |
| 395 | − | |
| 396 | − mdelay(10); | |
| 397 | − | |
| 398 | − /* Setup Genesis mode */ | |
| 399 | − res = pcmcia_write_config_byte(hw_priv->link, CISREG_CCSR, hcr); | |
| 400 | − if (res != 0) { | |
| 401 | − printk(KERN_DEBUG "%s failed 3 (%d)\n", __func__, res); | |
| 402 | − return; | |
| 403 | − } | |
| 404 | − mdelay(10); | |
| 405 | − | |
| 406 | − res = pcmcia_write_config_byte(hw_priv->link, CISREG_COR, | |
| 407 | − old_cor & ~COR_SOFT_RESET); | |
| 408 | − if (res != 0) { | |
| 409 | − printk(KERN_DEBUG "%s failed 4 (%d)\n", __func__, res); | |
| 410 | − return; | |
| 411 | − } | |
| 412 | − | |
| 413 | − mdelay(10); | |
| 414 | −} | |
| 415 | − | |
| 416 | − | |
| 417 | −static struct prism2_helper_functions prism2_pccard_funcs = | |
| 418 | −{ | |
| 419 | − .card_present = prism2_pccard_card_present, | |
| 420 | − .cor_sreset = prism2_pccard_cor_sreset, | |
| 421 | − .genesis_reset = prism2_pccard_genesis_reset, | |
| 422 | − .hw_type = HOSTAP_HW_PCCARD, | |
| 423 | −}; | |
| 424 | − | |
| 425 | − | |
| 426 | −/* allocate local data and register with CardServices | |
| 427 | − * initialize dev_link structure, but do not configure the card yet */ | |
| 428 | −static int hostap_cs_probe(struct pcmcia_device *p_dev) | |
| 429 | −{ | |
| 430 | − int ret; | |
| 431 | − | |
| 432 | − PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); | |
| 433 | − | |
| 434 | − ret = prism2_config(p_dev); | |
| 435 | − if (ret) { | |
| 436 | − PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); | |
| 437 | − } | |
| 438 | − | |
| 439 | − return ret; | |
| 440 | −} | |
| 441 | − | |
| 442 | − | |
| 443 | −static void prism2_detach(struct pcmcia_device *link) | |
| 444 | −{ | |
| 445 | − PDEBUG(DEBUG_FLOW, "prism2_detach\n"); | |
| 446 | − | |
| 447 | − prism2_release((u_long)link); | |
| 448 | − | |
| 449 | − /* release net devices */ | |
| 450 | − if (link->priv) { | |
| 451 | − struct hostap_cs_priv *hw_priv; | |
| 452 | − struct net_device *dev; | |
| 453 | − struct hostap_interface *iface; | |
| 454 | − dev = link->priv; | |
| 455 | − iface = netdev_priv(dev); | |
| 456 | − hw_priv = iface->local->hw_priv; | |
| 457 | − prism2_free_local_data(dev); | |
| 458 | − kfree(hw_priv); | |
| 459 | − } | |
| 460 | −} | |
| 461 | − | |
| 462 | − | |
| 463 | −static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data) | |
| 464 | −{ | |
| 465 | − if (p_dev->config_index == 0) | |
| 466 | − return -EINVAL; | |
| 467 | − | |
| 468 | − return pcmcia_request_io(p_dev); | |
| 469 | −} | |
| 470 | − | |
| 471 | −static int prism2_config(struct pcmcia_device *link) | |
| 472 | −{ | |
| 473 | − struct net_device *dev; | |
| 474 | − struct hostap_interface *iface; | |
| 475 | − local_info_t *local; | |
| 476 | − int ret; | |
| 477 | − struct hostap_cs_priv *hw_priv; | |
| 478 | − unsigned long flags; | |
| 479 | − | |
| 480 | − PDEBUG(DEBUG_FLOW, "prism2_config()\n"); | |
| 481 | − | |
| 482 | − hw_priv = kzalloc(sizeof(*hw_priv), GFP_KERNEL); | |
| 483 | − if (hw_priv == NULL) { | |
| 484 | − ret = -ENOMEM; | |
| 485 | − goto failed; | |
| 486 | − } | |
| 487 | − | |
| 488 | − /* Look for an appropriate configuration table entry in the CIS */ | |
| 489 | − link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | | |
| 490 | − CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; | |
| 491 | − if (ignore_cis_vcc) | |
| 492 | − link->config_flags &= ~CONF_AUTO_CHECK_VCC; | |
| 493 | − ret = pcmcia_loop_config(link, prism2_config_check, NULL); | |
| 494 | − if (ret) { | |
| 495 | − if (!ignore_cis_vcc) | |
| 496 | − printk(KERN_ERR "GetNextTuple(): No matching " | |
| 497 | − "CIS configuration. Maybe you need the " | |
| 498 | − "ignore_cis_vcc=1 parameter.\n"); | |
| 499 | − goto failed; | |
| 500 | − } | |
| 501 | − | |
| 502 | − /* Need to allocate net_device before requesting IRQ handler */ | |
| 503 | − dev = prism2_init_local_data(&prism2_pccard_funcs, 0, | |
| 504 | − &link->dev); | |
| 505 | − if (!dev) { | |
| 506 | − ret = -ENOMEM; | |
| 507 | − goto failed; | |
| 508 | − } | |
| 509 | − link->priv = dev; | |
| 510 | − | |
| 511 | − iface = netdev_priv(dev); | |
| 512 | − local = iface->local; | |
| 513 | − local->hw_priv = hw_priv; | |
| 514 | − hw_priv->link = link; | |
| 515 | − | |
| 516 | − /* | |
| 517 | − * We enable IRQ here, but IRQ handler will not proceed | |
| 518 | − * until dev->base_addr is set below. This protect us from | |
| 519 | − * receive interrupts when driver is not initialized. | |
| 520 | − */ | |
| 521 | − ret = pcmcia_request_irq(link, prism2_interrupt); | |
| 522 | − if (ret) | |
| 523 | − goto failed; | |
| 524 | − | |
| 525 | − ret = pcmcia_enable_device(link); | |
| 526 | − if (ret) | |
| 527 | − goto failed; | |
| 528 | − | |
| 529 | − spin_lock_irqsave(&local->irq_init_lock, flags); | |
| 530 | − dev->irq = link->irq; | |
| 531 | − dev->base_addr = link->resource[0]->start; | |
| 532 | − spin_unlock_irqrestore(&local->irq_init_lock, flags); | |
| 533 | − | |
| 534 | − local->shutdown = 0; | |
| 535 | − | |
| 536 | − sandisk_enable_wireless(dev); | |
| 537 | − | |
| 538 | − ret = prism2_hw_config(dev, 1); | |
| 539 | − if (!ret) | |
| 540 | − ret = hostap_hw_ready(dev); | |
| 541 | − | |
| 542 | − return ret; | |
| 543 | − | |
| 544 | − failed: | |
| 545 | − kfree(hw_priv); | |
| 546 | − prism2_release((u_long)link); | |
| 547 | − return ret; | |
| 548 | −} | |
| 549 | − | |
| 550 | − | |
| 551 | −static void prism2_release(u_long arg) | |
| 552 | −{ | |
| 553 | − struct pcmcia_device *link = (struct pcmcia_device *)arg; | |
| 554 | − | |
| 555 | − PDEBUG(DEBUG_FLOW, "prism2_release\n"); | |
| 556 | − | |
| 557 | − if (link->priv) { | |
| 558 | − struct net_device *dev = link->priv; | |
| 559 | − struct hostap_interface *iface; | |
| 560 | − | |
| 561 | − iface = netdev_priv(dev); | |
| 562 | − prism2_hw_shutdown(dev, 0); | |
| 563 | − iface->local->shutdown = 1; | |
| 564 | − } | |
| 565 | − | |
| 566 | − pcmcia_disable_device(link); | |
| 567 | − PDEBUG(DEBUG_FLOW, "release - done\n"); | |
| 568 | −} | |
| 569 | − | |
| 570 | −static int hostap_cs_suspend(struct pcmcia_device *link) | |
| 571 | −{ | |
| 572 | − struct net_device *dev = (struct net_device *) link->priv; | |
| 573 | − int dev_open = 0; | |
| 574 | − struct hostap_interface *iface = NULL; | |
| 575 | − | |
| 576 | − if (!dev) | |
| 577 | − return -ENODEV; | |
| 578 | − | |
| 579 | − iface = netdev_priv(dev); | |
| 580 | − | |
| 581 | − PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); | |
| 582 | − if (iface && iface->local) | |
| 583 | − dev_open = iface->local->num_dev_open > 0; | |
| 584 | − if (dev_open) { | |
| 585 | − netif_stop_queue(dev); | |
| 586 | − netif_device_detach(dev); | |
| 587 | − } | |
| 588 | − prism2_suspend(dev); | |
| 589 | − | |
| 590 | − return 0; | |
| 591 | −} | |
| 592 | − | |
| 593 | −static int hostap_cs_resume(struct pcmcia_device *link) | |
| 594 | −{ | |
| 595 | − struct net_device *dev = (struct net_device *) link->priv; | |
| 596 | − int dev_open = 0; | |
| 597 | − struct hostap_interface *iface = NULL; | |
| 598 | − | |
| 599 | − if (!dev) | |
| 600 | − return -ENODEV; | |
| 601 | − | |
| 602 | − iface = netdev_priv(dev); | |
| 603 | − | |
| 604 | − PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); | |
| 605 | − | |
| 606 | − if (iface && iface->local) | |
| 607 | − dev_open = iface->local->num_dev_open > 0; | |
| 608 | − | |
| 609 | − prism2_hw_shutdown(dev, 1); | |
| 610 | − prism2_hw_config(dev, dev_open ? 0 : 1); | |
| 611 | − if (dev_open) { | |
| 612 | − netif_device_attach(dev); | |
| 613 | − netif_start_queue(dev); | |
| 614 | − } | |
| 615 | − | |
| 616 | − return 0; | |
| 617 | −} | |
| 618 | − | |
| 619 | −static const struct pcmcia_device_id hostap_cs_ids[] = { | |
| 620 | − PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), | |
| 621 | − PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), | |
| 622 | − PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), | |
| 623 | − PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), | |
| 624 | − PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), | |
| 625 | − PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301), | |
| 626 | − PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), | |
| 627 | − PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b), | |
| 628 | − PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), | |
| 629 | − PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), | |
| 630 | − PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), | |
| 631 | − PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), | |
| 632 | − PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), | |
| 633 | − PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001), | |
| 634 | − PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), | |
| 635 | −/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */ | |
| 636 | − PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), | |
| 637 | − PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), | |
| 638 | − PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), | |
| 639 | − PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), | |
| 640 | − PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), | |
| 641 | − PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", | |
| 642 | − 0x2d858104), | |
| 643 | − PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", | |
| 644 | − 0x74c5e40d), | |
| 645 | − PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", | |
| 646 | − 0x4b801a17), | |
| 647 | − PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.02", | |
| 648 | − 0x4b74baa0), | |
| 649 | − PCMCIA_MFC_DEVICE_PROD_ID12(0, "SanDisk", "ConnectPlus", | |
| 650 | − 0x7a954bd9, 0x74be00c6), | |
| 651 | − PCMCIA_DEVICE_PROD_ID123( | |
| 652 | − "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", | |
| 653 | − 0xe6ec52ce, 0x08649af2, 0x4b74baa0), | |
| 654 | − PCMCIA_DEVICE_PROD_ID123( | |
| 655 | − "Canon", "Wireless LAN CF Card K30225", "Version 01.00", | |
| 656 | − 0x96ef6fe2, 0x263fcbab, 0xa57adb8c), | |
| 657 | − PCMCIA_DEVICE_PROD_ID123( | |
| 658 | − "D", "Link DWL-650 11Mbps WLAN Card", "Version 01.02", | |
| 659 | − 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), | |
| 660 | − PCMCIA_DEVICE_PROD_ID123( | |
| 661 | − "Instant Wireless ", " Network PC CARD", "Version 01.02", | |
| 662 | − 0x11d901af, 0x6e9bd926, 0x4b74baa0), | |
| 663 | − PCMCIA_DEVICE_PROD_ID123( | |
| 664 | − "SMC", "SMC2632W", "Version 01.02", | |
| 665 | − 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), | |
| 666 | − PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", | |
| 667 | − 0x2decece3, 0x82067c18), | |
| 668 | − PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", | |
| 669 | − 0x54f7c49c, 0x15a75e5b), | |
| 670 | − PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", | |
| 671 | − 0x74c5e40d, 0xdb472a18), | |
| 672 | − PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", | |
| 673 | − 0x0733cc81, 0x0c52f395), | |
| 674 | − PCMCIA_DEVICE_PROD_ID12( | |
| 675 | − "ZoomAir 11Mbps High", "Rate wireless Networking", | |
| 676 | − 0x273fe3db, 0x32a1eaee), | |
| 677 | − PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", | |
| 678 | − 0xa37434e9, 0x9762e8f1), | |
| 679 | − PCMCIA_DEVICE_PROD_ID123( | |
| 680 | − "Pretec", "CompactWLAN Card 802.11b", "2.5", | |
| 681 | − 0x1cadd3e5, 0xe697636c, 0x7a5bfcf1), | |
| 682 | − PCMCIA_DEVICE_PROD_ID123( | |
| 683 | − "U.S. Robotics", "IEEE 802.11b PC-CARD", "Version 01.02", | |
| 684 | − 0xc7b8df9d, 0x1700d087, 0x4b74baa0), | |
| 685 | − PCMCIA_DEVICE_PROD_ID123( | |
| 686 | − "Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", | |
| 687 | − "Ver. 1.00", | |
| 688 | − 0x5cd01705, 0x4271660f, 0x9d08ee12), | |
| 689 | − PCMCIA_DEVICE_PROD_ID123( | |
| 690 | − "Wireless LAN" , "11Mbps PC Card", "Version 01.02", | |
| 691 | − 0x4b8870ff, 0x70e946d1, 0x4b74baa0), | |
| 692 | − PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092), | |
| 693 | − PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2), | |
| 694 | − PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b), | |
| 695 | − PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39), | |
| 696 | − PCMCIA_DEVICE_NULL | |
| 697 | −}; | |
| 698 | −MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids); | |
| 699 | − | |
| 700 | − | |
| 701 | −static struct pcmcia_driver hostap_driver = { | |
| 702 | − .name = "hostap_cs", | |
| 703 | − .probe = hostap_cs_probe, | |
| 704 | − .remove = prism2_detach, | |
| 705 | − .owner = THIS_MODULE, | |
| 706 | − .id_table = hostap_cs_ids, | |
| 707 | − .suspend = hostap_cs_suspend, | |
| 708 | − .resume = hostap_cs_resume, | |
| 709 | −}; | |
| 710 | −module_pcmcia_driver(hostap_driver); | |
| @@ -1,810 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −static int prism2_enable_aux_port(struct net_device *dev, int enable) | |
| 3 | −{ | |
| 4 | − u16 val, reg; | |
| 5 | − int i, tries; | |
| 6 | − unsigned long flags; | |
| 7 | − struct hostap_interface *iface; | |
| 8 | − local_info_t *local; | |
| 9 | − | |
| 10 | − iface = netdev_priv(dev); | |
| 11 | − local = iface->local; | |
| 12 | − | |
| 13 | − if (local->no_pri) { | |
| 14 | − if (enable) { | |
| 15 | − PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux " | |
| 16 | − "port is already enabled\n", dev->name); | |
| 17 | − } | |
| 18 | − return 0; | |
| 19 | − } | |
| 20 | − | |
| 21 | − spin_lock_irqsave(&local->cmdlock, flags); | |
| 22 | − | |
| 23 | − /* wait until busy bit is clear */ | |
| 24 | − tries = HFA384X_CMD_BUSY_TIMEOUT; | |
| 25 | − while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | |
| 26 | − tries--; | |
| 27 | − udelay(1); | |
| 28 | − } | |
| 29 | − if (tries == 0) { | |
| 30 | − reg = HFA384X_INW(HFA384X_CMD_OFF); | |
| 31 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 32 | − printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n", | |
| 33 | − dev->name, reg); | |
| 34 | − return -ETIMEDOUT; | |
| 35 | − } | |
| 36 | − | |
| 37 | − val = HFA384X_INW(HFA384X_CONTROL_OFF); | |
| 38 | − | |
| 39 | − if (enable) { | |
| 40 | − HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF); | |
| 41 | − HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF); | |
| 42 | − HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF); | |
| 43 | − | |
| 44 | − if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED) | |
| 45 | − printk("prism2_enable_aux_port: was not disabled!?\n"); | |
| 46 | − val &= ~HFA384X_AUX_PORT_MASK; | |
| 47 | − val |= HFA384X_AUX_PORT_ENABLE; | |
| 48 | − } else { | |
| 49 | − HFA384X_OUTW(0, HFA384X_PARAM0_OFF); | |
| 50 | − HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | |
| 51 | − HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | |
| 52 | − | |
| 53 | − if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED) | |
| 54 | − printk("prism2_enable_aux_port: was not enabled!?\n"); | |
| 55 | − val &= ~HFA384X_AUX_PORT_MASK; | |
| 56 | − val |= HFA384X_AUX_PORT_DISABLE; | |
| 57 | − } | |
| 58 | − HFA384X_OUTW(val, HFA384X_CONTROL_OFF); | |
| 59 | − | |
| 60 | − udelay(5); | |
| 61 | − | |
| 62 | − i = 10000; | |
| 63 | − while (i > 0) { | |
| 64 | − val = HFA384X_INW(HFA384X_CONTROL_OFF); | |
| 65 | − val &= HFA384X_AUX_PORT_MASK; | |
| 66 | − | |
| 67 | − if ((enable && val == HFA384X_AUX_PORT_ENABLED) || | |
| 68 | − (!enable && val == HFA384X_AUX_PORT_DISABLED)) | |
| 69 | − break; | |
| 70 | − | |
| 71 | − udelay(10); | |
| 72 | − i--; | |
| 73 | − } | |
| 74 | − | |
| 75 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 76 | − | |
| 77 | − if (i == 0) { | |
| 78 | − printk("prism2_enable_aux_port(%d) timed out\n", | |
| 79 | − enable); | |
| 80 | − return -ETIMEDOUT; | |
| 81 | − } | |
| 82 | − | |
| 83 | − return 0; | |
| 84 | −} | |
| 85 | − | |
| 86 | − | |
| 87 | −static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len, | |
| 88 | − void *buf) | |
| 89 | −{ | |
| 90 | − u16 page, offset; | |
| 91 | − if (addr & 1 || len & 1) | |
| 92 | − return -1; | |
| 93 | − | |
| 94 | − page = addr >> 7; | |
| 95 | − offset = addr & 0x7f; | |
| 96 | − | |
| 97 | − HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | |
| 98 | − HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | |
| 99 | − | |
| 100 | − udelay(5); | |
| 101 | − | |
| 102 | −#ifdef PRISM2_PCI | |
| 103 | − { | |
| 104 | − __le16 *pos = (__le16 *) buf; | |
| 105 | − while (len > 0) { | |
| 106 | − *pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF); | |
| 107 | − len -= 2; | |
| 108 | − } | |
| 109 | − } | |
| 110 | −#else /* PRISM2_PCI */ | |
| 111 | − HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2); | |
| 112 | −#endif /* PRISM2_PCI */ | |
| 113 | − | |
| 114 | − return 0; | |
| 115 | −} | |
| 116 | − | |
| 117 | − | |
| 118 | −static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len, | |
| 119 | − void *buf) | |
| 120 | −{ | |
| 121 | − u16 page, offset; | |
| 122 | − if (addr & 1 || len & 1) | |
| 123 | − return -1; | |
| 124 | − | |
| 125 | − page = addr >> 7; | |
| 126 | − offset = addr & 0x7f; | |
| 127 | − | |
| 128 | − HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF); | |
| 129 | − HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF); | |
| 130 | − | |
| 131 | − udelay(5); | |
| 132 | − | |
| 133 | −#ifdef PRISM2_PCI | |
| 134 | − { | |
| 135 | − __le16 *pos = (__le16 *) buf; | |
| 136 | − while (len > 0) { | |
| 137 | − HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF); | |
| 138 | − len -= 2; | |
| 139 | − } | |
| 140 | − } | |
| 141 | −#else /* PRISM2_PCI */ | |
| 142 | − HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2); | |
| 143 | −#endif /* PRISM2_PCI */ | |
| 144 | − | |
| 145 | − return 0; | |
| 146 | −} | |
| 147 | − | |
| 148 | − | |
| 149 | −static int prism2_pda_ok(u8 *buf) | |
| 150 | −{ | |
| 151 | − __le16 *pda = (__le16 *) buf; | |
| 152 | − int pos; | |
| 153 | − u16 len, pdr; | |
| 154 | − | |
| 155 | − if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff && | |
| 156 | − buf[3] == 0x00) | |
| 157 | − return 0; | |
| 158 | − | |
| 159 | − pos = 0; | |
| 160 | − while (pos + 1 < PRISM2_PDA_SIZE / 2) { | |
| 161 | − len = le16_to_cpu(pda[pos]); | |
| 162 | − pdr = le16_to_cpu(pda[pos + 1]); | |
| 163 | − if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2) | |
| 164 | − return 0; | |
| 165 | − | |
| 166 | − if (pdr == 0x0000 && len == 2) { | |
| 167 | − /* PDA end found */ | |
| 168 | − return 1; | |
| 169 | − } | |
| 170 | − | |
| 171 | − pos += len + 1; | |
| 172 | − } | |
| 173 | − | |
| 174 | − return 0; | |
| 175 | −} | |
| 176 | − | |
| 177 | − | |
| 178 | −#define prism2_download_aux_dump_npages 65536 | |
| 179 | − | |
| 180 | −struct prism2_download_aux_dump { | |
| 181 | − local_info_t *local; | |
| 182 | − u16 page[0x80]; | |
| 183 | −}; | |
| 184 | − | |
| 185 | −static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v) | |
| 186 | −{ | |
| 187 | − struct prism2_download_aux_dump *ctx = m->private; | |
| 188 | − | |
| 189 | − hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page); | |
| 190 | − seq_write(m, ctx->page, 0x80); | |
| 191 | − return 0; | |
| 192 | −} | |
| 193 | − | |
| 194 | −static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos) | |
| 195 | −{ | |
| 196 | − struct prism2_download_aux_dump *ctx = m->private; | |
| 197 | − prism2_enable_aux_port(ctx->local->dev, 1); | |
| 198 | − if (*_pos >= prism2_download_aux_dump_npages) | |
| 199 | − return NULL; | |
| 200 | − return (void *)((unsigned long)*_pos + 1); | |
| 201 | −} | |
| 202 | − | |
| 203 | −static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos) | |
| 204 | −{ | |
| 205 | − ++*_pos; | |
| 206 | − if (*_pos >= prism2_download_aux_dump_npages) | |
| 207 | − return NULL; | |
| 208 | − return (void *)((unsigned long)*_pos + 1); | |
| 209 | −} | |
| 210 | − | |
| 211 | −static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v) | |
| 212 | −{ | |
| 213 | − struct prism2_download_aux_dump *ctx = m->private; | |
| 214 | − prism2_enable_aux_port(ctx->local->dev, 0); | |
| 215 | −} | |
| 216 | − | |
| 217 | −static const struct seq_operations prism2_download_aux_dump_proc_seqops = { | |
| 218 | − .start = prism2_download_aux_dump_proc_start, | |
| 219 | − .next = prism2_download_aux_dump_proc_next, | |
| 220 | − .stop = prism2_download_aux_dump_proc_stop, | |
| 221 | − .show = prism2_download_aux_dump_proc_show, | |
| 222 | −}; | |
| 223 | − | |
| 224 | −static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file) | |
| 225 | −{ | |
| 226 | − int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops, | |
| 227 | − sizeof(struct prism2_download_aux_dump)); | |
| 228 | − if (ret == 0) { | |
| 229 | − struct seq_file *m = file->private_data; | |
| 230 | − m->private = pde_data(inode); | |
| 231 | − } | |
| 232 | − return ret; | |
| 233 | −} | |
| 234 | − | |
| 235 | −static const struct proc_ops prism2_download_aux_dump_proc_ops = { | |
| 236 | − .proc_open = prism2_download_aux_dump_proc_open, | |
| 237 | − .proc_read = seq_read, | |
| 238 | − .proc_lseek = seq_lseek, | |
| 239 | − .proc_release = seq_release_private, | |
| 240 | −}; | |
| 241 | − | |
| 242 | − | |
| 243 | −static u8 * prism2_read_pda(struct net_device *dev) | |
| 244 | −{ | |
| 245 | − u8 *buf; | |
| 246 | − int res, i, found = 0; | |
| 247 | −#define NUM_PDA_ADDRS 4 | |
| 248 | − unsigned int pda_addr[NUM_PDA_ADDRS] = { | |
| 249 | − 0x7f0000 /* others than HFA3841 */, | |
| 250 | − 0x3f0000 /* HFA3841 */, | |
| 251 | − 0x390000 /* apparently used in older cards */, | |
| 252 | − 0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */, | |
| 253 | − }; | |
| 254 | − | |
| 255 | − buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL); | |
| 256 | − if (buf == NULL) | |
| 257 | − return NULL; | |
| 258 | − | |
| 259 | − /* Note: wlan card should be in initial state (just after init cmd) | |
| 260 | − * and no other operations should be performed concurrently. */ | |
| 261 | − | |
| 262 | − prism2_enable_aux_port(dev, 1); | |
| 263 | − | |
| 264 | − for (i = 0; i < NUM_PDA_ADDRS; i++) { | |
| 265 | − PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x", | |
| 266 | − dev->name, pda_addr[i]); | |
| 267 | − res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf); | |
| 268 | − if (res) | |
| 269 | − continue; | |
| 270 | − if (res == 0 && prism2_pda_ok(buf)) { | |
| 271 | − PDEBUG2(DEBUG_EXTRA2, ": OK\n"); | |
| 272 | − found = 1; | |
| 273 | − break; | |
| 274 | − } else { | |
| 275 | − PDEBUG2(DEBUG_EXTRA2, ": failed\n"); | |
| 276 | − } | |
| 277 | − } | |
| 278 | − | |
| 279 | − prism2_enable_aux_port(dev, 0); | |
| 280 | − | |
| 281 | − if (!found) { | |
| 282 | − printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name); | |
| 283 | − kfree(buf); | |
| 284 | − buf = NULL; | |
| 285 | − } | |
| 286 | − | |
| 287 | − return buf; | |
| 288 | −} | |
| 289 | − | |
| 290 | − | |
| 291 | −static int prism2_download_volatile(local_info_t *local, | |
| 292 | − struct prism2_download_data *param) | |
| 293 | −{ | |
| 294 | − struct net_device *dev = local->dev; | |
| 295 | − int ret = 0, i; | |
| 296 | − u16 param0, param1; | |
| 297 | − | |
| 298 | − if (local->hw_downloading) { | |
| 299 | − printk(KERN_WARNING "%s: Already downloading - aborting new " | |
| 300 | − "request\n", dev->name); | |
| 301 | − return -1; | |
| 302 | − } | |
| 303 | − | |
| 304 | − local->hw_downloading = 1; | |
| 305 | − if (local->pri_only) { | |
| 306 | − hfa384x_disable_interrupts(dev); | |
| 307 | − } else { | |
| 308 | − prism2_hw_shutdown(dev, 0); | |
| 309 | − | |
| 310 | − if (prism2_hw_init(dev, 0)) { | |
| 311 | − printk(KERN_WARNING "%s: Could not initialize card for" | |
| 312 | − " download\n", dev->name); | |
| 313 | − ret = -1; | |
| 314 | − goto out; | |
| 315 | − } | |
| 316 | − } | |
| 317 | − | |
| 318 | − if (prism2_enable_aux_port(dev, 1)) { | |
| 319 | − printk(KERN_WARNING "%s: Could not enable AUX port\n", | |
| 320 | − dev->name); | |
| 321 | − ret = -1; | |
| 322 | − goto out; | |
| 323 | − } | |
| 324 | − | |
| 325 | − param0 = param->start_addr & 0xffff; | |
| 326 | − param1 = param->start_addr >> 16; | |
| 327 | − | |
| 328 | − HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | |
| 329 | − HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | |
| 330 | − if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | |
| 331 | − (HFA384X_PROGMODE_ENABLE_VOLATILE << 8), | |
| 332 | − param0)) { | |
| 333 | − printk(KERN_WARNING "%s: Download command execution failed\n", | |
| 334 | − dev->name); | |
| 335 | − ret = -1; | |
| 336 | − goto out; | |
| 337 | − } | |
| 338 | − | |
| 339 | − for (i = 0; i < param->num_areas; i++) { | |
| 340 | − PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | |
| 341 | − dev->name, param->data[i].len, param->data[i].addr); | |
| 342 | − if (hfa384x_to_aux(dev, param->data[i].addr, | |
| 343 | − param->data[i].len, param->data[i].data)) { | |
| 344 | − printk(KERN_WARNING "%s: RAM download at 0x%08x " | |
| 345 | − "(len=%d) failed\n", dev->name, | |
| 346 | − param->data[i].addr, param->data[i].len); | |
| 347 | − ret = -1; | |
| 348 | − goto out; | |
| 349 | − } | |
| 350 | − } | |
| 351 | − | |
| 352 | − HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | |
| 353 | − HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | |
| 354 | − if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | |
| 355 | − (HFA384X_PROGMODE_DISABLE << 8), param0)) { | |
| 356 | − printk(KERN_WARNING "%s: Download command execution failed\n", | |
| 357 | − dev->name); | |
| 358 | − ret = -1; | |
| 359 | − goto out; | |
| 360 | − } | |
| 361 | − /* ProgMode disable causes the hardware to restart itself from the | |
| 362 | − * given starting address. Give hw some time and ACK command just in | |
| 363 | − * case restart did not happen. */ | |
| 364 | − mdelay(5); | |
| 365 | − HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | |
| 366 | − | |
| 367 | − if (prism2_enable_aux_port(dev, 0)) { | |
| 368 | − printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | |
| 369 | − dev->name); | |
| 370 | − /* continue anyway.. restart should have taken care of this */ | |
| 371 | − } | |
| 372 | − | |
| 373 | − mdelay(5); | |
| 374 | − local->hw_downloading = 0; | |
| 375 | − if (prism2_hw_config(dev, 2)) { | |
| 376 | − printk(KERN_WARNING "%s: Card configuration after RAM " | |
| 377 | − "download failed\n", dev->name); | |
| 378 | − ret = -1; | |
| 379 | − goto out; | |
| 380 | − } | |
| 381 | − | |
| 382 | − out: | |
| 383 | − local->hw_downloading = 0; | |
| 384 | − return ret; | |
| 385 | −} | |
| 386 | − | |
| 387 | − | |
| 388 | −static int prism2_enable_genesis(local_info_t *local, int hcr) | |
| 389 | −{ | |
| 390 | − struct net_device *dev = local->dev; | |
| 391 | − u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff }; | |
| 392 | − u8 readbuf[4]; | |
| 393 | − | |
| 394 | − printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n", | |
| 395 | − dev->name, hcr); | |
| 396 | − local->func->cor_sreset(local); | |
| 397 | − hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | |
| 398 | − local->func->genesis_reset(local, hcr); | |
| 399 | − | |
| 400 | − /* Readback test */ | |
| 401 | − hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | |
| 402 | − hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq); | |
| 403 | − hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf); | |
| 404 | − | |
| 405 | − if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) { | |
| 406 | − printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n", | |
| 407 | − hcr); | |
| 408 | − return 0; | |
| 409 | − } else { | |
| 410 | − printk(KERN_DEBUG "Readback test failed, HCR 0x%02x write %4ph read %4ph\n", | |
| 411 | − hcr, initseq, readbuf); | |
| 412 | − return 1; | |
| 413 | − } | |
| 414 | −} | |
| 415 | − | |
| 416 | − | |
| 417 | −static int prism2_get_ram_size(local_info_t *local) | |
| 418 | −{ | |
| 419 | − int ret; | |
| 420 | − | |
| 421 | − /* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | |
| 422 | − if (prism2_enable_genesis(local, 0x1f) == 0) | |
| 423 | − ret = 8; | |
| 424 | − else if (prism2_enable_genesis(local, 0x0f) == 0) | |
| 425 | − ret = 16; | |
| 426 | − else | |
| 427 | − ret = -1; | |
| 428 | − | |
| 429 | − /* Disable genesis mode */ | |
| 430 | − local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17); | |
| 431 | − | |
| 432 | − return ret; | |
| 433 | −} | |
| 434 | − | |
| 435 | − | |
| 436 | −static int prism2_download_genesis(local_info_t *local, | |
| 437 | − struct prism2_download_data *param) | |
| 438 | −{ | |
| 439 | − struct net_device *dev = local->dev; | |
| 440 | − int ram16 = 0, i; | |
| 441 | − int ret = 0; | |
| 442 | − | |
| 443 | − if (local->hw_downloading) { | |
| 444 | − printk(KERN_WARNING "%s: Already downloading - aborting new " | |
| 445 | − "request\n", dev->name); | |
| 446 | − return -EBUSY; | |
| 447 | − } | |
| 448 | − | |
| 449 | − if (!local->func->genesis_reset || !local->func->cor_sreset) { | |
| 450 | − printk(KERN_INFO "%s: Genesis mode downloading not supported " | |
| 451 | − "with this hwmodel\n", dev->name); | |
| 452 | − return -EOPNOTSUPP; | |
| 453 | − } | |
| 454 | − | |
| 455 | − local->hw_downloading = 1; | |
| 456 | − | |
| 457 | − if (prism2_enable_aux_port(dev, 1)) { | |
| 458 | − printk(KERN_DEBUG "%s: failed to enable AUX port\n", | |
| 459 | − dev->name); | |
| 460 | − ret = -EIO; | |
| 461 | − goto out; | |
| 462 | − } | |
| 463 | − | |
| 464 | − if (local->sram_type == -1) { | |
| 465 | − /* 0x1F for x8 SRAM or 0x0F for x16 SRAM */ | |
| 466 | − if (prism2_enable_genesis(local, 0x1f) == 0) { | |
| 467 | − ram16 = 0; | |
| 468 | − PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 " | |
| 469 | − "SRAM\n", dev->name); | |
| 470 | − } else if (prism2_enable_genesis(local, 0x0f) == 0) { | |
| 471 | − ram16 = 1; | |
| 472 | − PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 " | |
| 473 | − "SRAM\n", dev->name); | |
| 474 | − } else { | |
| 475 | − printk(KERN_DEBUG "%s: Could not initiate genesis " | |
| 476 | − "mode\n", dev->name); | |
| 477 | − ret = -EIO; | |
| 478 | − goto out; | |
| 479 | − } | |
| 480 | − } else { | |
| 481 | − if (prism2_enable_genesis(local, local->sram_type == 8 ? | |
| 482 | − 0x1f : 0x0f)) { | |
| 483 | − printk(KERN_DEBUG "%s: Failed to set Genesis " | |
| 484 | − "mode (sram_type=%d)\n", dev->name, | |
| 485 | − local->sram_type); | |
| 486 | − ret = -EIO; | |
| 487 | − goto out; | |
| 488 | − } | |
| 489 | − ram16 = local->sram_type != 8; | |
| 490 | − } | |
| 491 | − | |
| 492 | − for (i = 0; i < param->num_areas; i++) { | |
| 493 | − PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n", | |
| 494 | − dev->name, param->data[i].len, param->data[i].addr); | |
| 495 | − if (hfa384x_to_aux(dev, param->data[i].addr, | |
| 496 | − param->data[i].len, param->data[i].data)) { | |
| 497 | − printk(KERN_WARNING "%s: RAM download at 0x%08x " | |
| 498 | − "(len=%d) failed\n", dev->name, | |
| 499 | − param->data[i].addr, param->data[i].len); | |
| 500 | − ret = -EIO; | |
| 501 | − goto out; | |
| 502 | − } | |
| 503 | − } | |
| 504 | − | |
| 505 | − PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n"); | |
| 506 | − local->func->genesis_reset(local, ram16 ? 0x07 : 0x17); | |
| 507 | − if (prism2_enable_aux_port(dev, 0)) { | |
| 508 | − printk(KERN_DEBUG "%s: Failed to disable AUX port\n", | |
| 509 | − dev->name); | |
| 510 | − } | |
| 511 | − | |
| 512 | − mdelay(5); | |
| 513 | − local->hw_downloading = 0; | |
| 514 | − | |
| 515 | − PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n"); | |
| 516 | − /* | |
| 517 | − * Make sure the INIT command does not generate a command completion | |
| 518 | − * event by disabling interrupts. | |
| 519 | − */ | |
| 520 | − hfa384x_disable_interrupts(dev); | |
| 521 | − if (prism2_hw_init(dev, 1)) { | |
| 522 | − printk(KERN_DEBUG "%s: Initialization after genesis mode " | |
| 523 | − "download failed\n", dev->name); | |
| 524 | − ret = -EIO; | |
| 525 | − goto out; | |
| 526 | − } | |
| 527 | − | |
| 528 | − PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n"); | |
| 529 | − if (prism2_hw_init2(dev, 1)) { | |
| 530 | − printk(KERN_DEBUG "%s: Initialization(2) after genesis mode " | |
| 531 | − "download failed\n", dev->name); | |
| 532 | − ret = -EIO; | |
| 533 | − goto out; | |
| 534 | − } | |
| 535 | − | |
| 536 | − out: | |
| 537 | − local->hw_downloading = 0; | |
| 538 | − return ret; | |
| 539 | −} | |
| 540 | − | |
| 541 | − | |
| 542 | −#ifdef PRISM2_NON_VOLATILE_DOWNLOAD | |
| 543 | −/* Note! Non-volatile downloading functionality has not yet been tested | |
| 544 | − * thoroughly and it may corrupt flash image and effectively kill the card that | |
| 545 | − * is being updated. You have been warned. */ | |
| 546 | − | |
| 547 | −static inline int prism2_download_block(struct net_device *dev, | |
| 548 | − u32 addr, u8 *data, | |
| 549 | − u32 bufaddr, int rest_len) | |
| 550 | −{ | |
| 551 | − u16 param0, param1; | |
| 552 | − int block_len; | |
| 553 | − | |
| 554 | − block_len = rest_len < 4096 ? rest_len : 4096; | |
| 555 | − | |
| 556 | − param0 = addr & 0xffff; | |
| 557 | − param1 = addr >> 16; | |
| 558 | − | |
| 559 | − HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF); | |
| 560 | − HFA384X_OUTW(param1, HFA384X_PARAM1_OFF); | |
| 561 | − | |
| 562 | − if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | |
| 563 | − (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8), | |
| 564 | − param0)) { | |
| 565 | − printk(KERN_WARNING "%s: Flash download command execution " | |
| 566 | − "failed\n", dev->name); | |
| 567 | − return -1; | |
| 568 | − } | |
| 569 | − | |
| 570 | − if (hfa384x_to_aux(dev, bufaddr, block_len, data)) { | |
| 571 | − printk(KERN_WARNING "%s: flash download at 0x%08x " | |
| 572 | − "(len=%d) failed\n", dev->name, addr, block_len); | |
| 573 | − return -1; | |
| 574 | − } | |
| 575 | − | |
| 576 | − HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | |
| 577 | − HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | |
| 578 | − if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | |
| 579 | − (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8), | |
| 580 | − 0)) { | |
| 581 | − printk(KERN_WARNING "%s: Flash write command execution " | |
| 582 | − "failed\n", dev->name); | |
| 583 | − return -1; | |
| 584 | − } | |
| 585 | − | |
| 586 | − return block_len; | |
| 587 | −} | |
| 588 | − | |
| 589 | − | |
| 590 | −static int prism2_download_nonvolatile(local_info_t *local, | |
| 591 | − struct prism2_download_data *dl) | |
| 592 | −{ | |
| 593 | − struct net_device *dev = local->dev; | |
| 594 | − int ret = 0, i; | |
| 595 | − struct { | |
| 596 | − __le16 page; | |
| 597 | − __le16 offset; | |
| 598 | − __le16 len; | |
| 599 | − } dlbuffer; | |
| 600 | − u32 bufaddr; | |
| 601 | − | |
| 602 | − if (local->hw_downloading) { | |
| 603 | − printk(KERN_WARNING "%s: Already downloading - aborting new " | |
| 604 | − "request\n", dev->name); | |
| 605 | − return -1; | |
| 606 | − } | |
| 607 | − | |
| 608 | − ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER, | |
| 609 | − &dlbuffer, 6, 0); | |
| 610 | − | |
| 611 | − if (ret < 0) { | |
| 612 | − printk(KERN_WARNING "%s: Could not read download buffer " | |
| 613 | − "parameters\n", dev->name); | |
| 614 | − goto out; | |
| 615 | − } | |
| 616 | − | |
| 617 | − printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n", | |
| 618 | − le16_to_cpu(dlbuffer.len), | |
| 619 | − le16_to_cpu(dlbuffer.page), | |
| 620 | − le16_to_cpu(dlbuffer.offset)); | |
| 621 | − | |
| 622 | − bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset); | |
| 623 | − | |
| 624 | − local->hw_downloading = 1; | |
| 625 | − | |
| 626 | − if (!local->pri_only) { | |
| 627 | − prism2_hw_shutdown(dev, 0); | |
| 628 | − | |
| 629 | − if (prism2_hw_init(dev, 0)) { | |
| 630 | − printk(KERN_WARNING "%s: Could not initialize card for" | |
| 631 | − " download\n", dev->name); | |
| 632 | − ret = -1; | |
| 633 | − goto out; | |
| 634 | − } | |
| 635 | − } | |
| 636 | − | |
| 637 | − hfa384x_disable_interrupts(dev); | |
| 638 | − | |
| 639 | − if (prism2_enable_aux_port(dev, 1)) { | |
| 640 | − printk(KERN_WARNING "%s: Could not enable AUX port\n", | |
| 641 | − dev->name); | |
| 642 | − ret = -1; | |
| 643 | − goto out; | |
| 644 | − } | |
| 645 | − | |
| 646 | − printk(KERN_DEBUG "%s: starting flash download\n", dev->name); | |
| 647 | − for (i = 0; i < dl->num_areas; i++) { | |
| 648 | − int rest_len = dl->data[i].len; | |
| 649 | − int data_off = 0; | |
| 650 | − | |
| 651 | − while (rest_len > 0) { | |
| 652 | − int block_len; | |
| 653 | − | |
| 654 | − block_len = prism2_download_block( | |
| 655 | − dev, dl->data[i].addr + data_off, | |
| 656 | − dl->data[i].data + data_off, bufaddr, | |
| 657 | − rest_len); | |
| 658 | − | |
| 659 | − if (block_len < 0) { | |
| 660 | − ret = -1; | |
| 661 | − goto out; | |
| 662 | − } | |
| 663 | − | |
| 664 | − rest_len -= block_len; | |
| 665 | − data_off += block_len; | |
| 666 | − } | |
| 667 | − } | |
| 668 | − | |
| 669 | − HFA384X_OUTW(0, HFA384X_PARAM1_OFF); | |
| 670 | − HFA384X_OUTW(0, HFA384X_PARAM2_OFF); | |
| 671 | − if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD | | |
| 672 | − (HFA384X_PROGMODE_DISABLE << 8), 0)) { | |
| 673 | − printk(KERN_WARNING "%s: Download command execution failed\n", | |
| 674 | − dev->name); | |
| 675 | − ret = -1; | |
| 676 | − goto out; | |
| 677 | − } | |
| 678 | − | |
| 679 | − if (prism2_enable_aux_port(dev, 0)) { | |
| 680 | − printk(KERN_DEBUG "%s: Disabling AUX port failed\n", | |
| 681 | − dev->name); | |
| 682 | − /* continue anyway.. restart should have taken care of this */ | |
| 683 | − } | |
| 684 | − | |
| 685 | − mdelay(5); | |
| 686 | − | |
| 687 | − local->func->hw_reset(dev); | |
| 688 | − local->hw_downloading = 0; | |
| 689 | − if (prism2_hw_config(dev, 2)) { | |
| 690 | − printk(KERN_WARNING "%s: Card configuration after flash " | |
| 691 | − "download failed\n", dev->name); | |
| 692 | − ret = -1; | |
| 693 | − } else { | |
| 694 | − printk(KERN_INFO "%s: Card initialized successfully after " | |
| 695 | − "flash download\n", dev->name); | |
| 696 | − } | |
| 697 | − | |
| 698 | − out: | |
| 699 | − local->hw_downloading = 0; | |
| 700 | − return ret; | |
| 701 | −} | |
| 702 | −#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ | |
| 703 | − | |
| 704 | − | |
| 705 | −static void prism2_download_free_data(struct prism2_download_data *dl) | |
| 706 | −{ | |
| 707 | − int i; | |
| 708 | − | |
| 709 | − if (dl == NULL) | |
| 710 | − return; | |
| 711 | − | |
| 712 | − for (i = 0; i < dl->num_areas; i++) | |
| 713 | − kfree(dl->data[i].data); | |
| 714 | − kfree(dl); | |
| 715 | −} | |
| 716 | − | |
| 717 | − | |
| 718 | −static int prism2_download(local_info_t *local, | |
| 719 | − struct prism2_download_param *param) | |
| 720 | −{ | |
| 721 | − int ret = 0; | |
| 722 | − int i; | |
| 723 | − u32 total_len = 0; | |
| 724 | − struct prism2_download_data *dl = NULL; | |
| 725 | − | |
| 726 | − printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x " | |
| 727 | − "num_areas=%d\n", | |
| 728 | − param->dl_cmd, param->start_addr, param->num_areas); | |
| 729 | − | |
| 730 | − if (param->num_areas > 100) { | |
| 731 | − ret = -EINVAL; | |
| 732 | − goto out; | |
| 733 | − } | |
| 734 | − | |
| 735 | − dl = kzalloc(struct_size(dl, data, param->num_areas), GFP_KERNEL); | |
| 736 | − if (dl == NULL) { | |
| 737 | − ret = -ENOMEM; | |
| 738 | − goto out; | |
| 739 | − } | |
| 740 | − dl->dl_cmd = param->dl_cmd; | |
| 741 | − dl->start_addr = param->start_addr; | |
| 742 | − dl->num_areas = param->num_areas; | |
| 743 | − for (i = 0; i < param->num_areas; i++) { | |
| 744 | − PDEBUG(DEBUG_EXTRA2, | |
| 745 | − " area %d: addr=0x%08x len=%d ptr=0x%p\n", | |
| 746 | − i, param->data[i].addr, param->data[i].len, | |
| 747 | − param->data[i].ptr); | |
| 748 | − | |
| 749 | − dl->data[i].addr = param->data[i].addr; | |
| 750 | − dl->data[i].len = param->data[i].len; | |
| 751 | − | |
| 752 | − total_len += param->data[i].len; | |
| 753 | − if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN || | |
| 754 | − total_len > PRISM2_MAX_DOWNLOAD_LEN) { | |
| 755 | − ret = -E2BIG; | |
| 756 | − goto out; | |
| 757 | − } | |
| 758 | − | |
| 759 | − dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL); | |
| 760 | − if (dl->data[i].data == NULL) { | |
| 761 | − ret = -ENOMEM; | |
| 762 | − goto out; | |
| 763 | − } | |
| 764 | − | |
| 765 | − if (copy_from_user(dl->data[i].data, param->data[i].ptr, | |
| 766 | − param->data[i].len)) { | |
| 767 | − ret = -EFAULT; | |
| 768 | − goto out; | |
| 769 | − } | |
| 770 | − } | |
| 771 | − | |
| 772 | − switch (param->dl_cmd) { | |
| 773 | − case PRISM2_DOWNLOAD_VOLATILE: | |
| 774 | − case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT: | |
| 775 | − ret = prism2_download_volatile(local, dl); | |
| 776 | − break; | |
| 777 | − case PRISM2_DOWNLOAD_VOLATILE_GENESIS: | |
| 778 | − case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT: | |
| 779 | − ret = prism2_download_genesis(local, dl); | |
| 780 | − break; | |
| 781 | − case PRISM2_DOWNLOAD_NON_VOLATILE: | |
| 782 | −#ifdef PRISM2_NON_VOLATILE_DOWNLOAD | |
| 783 | − ret = prism2_download_nonvolatile(local, dl); | |
| 784 | −#else /* PRISM2_NON_VOLATILE_DOWNLOAD */ | |
| 785 | − printk(KERN_INFO "%s: non-volatile downloading not enabled\n", | |
| 786 | − local->dev->name); | |
| 787 | − ret = -EOPNOTSUPP; | |
| 788 | −#endif /* PRISM2_NON_VOLATILE_DOWNLOAD */ | |
| 789 | − break; | |
| 790 | − default: | |
| 791 | − printk(KERN_DEBUG "%s: unsupported download command %d\n", | |
| 792 | − local->dev->name, param->dl_cmd); | |
| 793 | − ret = -EINVAL; | |
| 794 | − break; | |
| 795 | − } | |
| 796 | − | |
| 797 | − out: | |
| 798 | − if (ret == 0 && dl && | |
| 799 | − param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) { | |
| 800 | − prism2_download_free_data(local->dl_pri); | |
| 801 | − local->dl_pri = dl; | |
| 802 | − } else if (ret == 0 && dl && | |
| 803 | − param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) { | |
| 804 | − prism2_download_free_data(local->dl_sec); | |
| 805 | − local->dl_sec = dl; | |
| 806 | − } else | |
| 807 | − prism2_download_free_data(dl); | |
| 808 | − | |
| 809 | − return ret; | |
| 810 | −} | |
| @@ -1,3387 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0-only | |
| 2 | −/* | |
| 3 | − * Host AP (software wireless LAN access point) driver for | |
| 4 | − * Intersil Prism2/2.5/3. | |
| 5 | − * | |
| 6 | − * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | |
| 7 | − * <j@w1.fi> | |
| 8 | − * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> | |
| 9 | − * | |
| 10 | − * FIX: | |
| 11 | − * - there is currently no way of associating TX packets to correct wds device | |
| 12 | − * when TX Exc/OK event occurs, so all tx_packets and some | |
| 13 | − * tx_errors/tx_dropped are added to the main netdevice; using sw_support | |
| 14 | − * field in txdesc might be used to fix this (using Alloc event to increment | |
| 15 | − * tx_packets would need some further info in txfid table) | |
| 16 | − * | |
| 17 | − * Buffer Access Path (BAP) usage: | |
| 18 | − * Prism2 cards have two separate BAPs for accessing the card memory. These | |
| 19 | − * should allow concurrent access to two different frames and the driver | |
| 20 | − * previously used BAP0 for sending data and BAP1 for receiving data. | |
| 21 | − * However, there seems to be number of issues with concurrent access and at | |
| 22 | − * least one know hardware bug in using BAP0 and BAP1 concurrently with PCI | |
| 23 | − * Prism2.5. Therefore, the driver now only uses BAP0 for moving data between | |
| 24 | − * host and card memories. BAP0 accesses are protected with local->baplock | |
| 25 | − * (spin_lock_bh) to prevent concurrent use. | |
| 26 | − */ | |
| 27 | − | |
| 28 | − | |
| 29 | − | |
| 30 | −#include <asm/delay.h> | |
| 31 | −#include <linux/uaccess.h> | |
| 32 | − | |
| 33 | −#include <linux/slab.h> | |
| 34 | −#include <linux/netdevice.h> | |
| 35 | −#include <linux/etherdevice.h> | |
| 36 | −#include <linux/proc_fs.h> | |
| 37 | −#include <linux/seq_file.h> | |
| 38 | −#include <linux/if_arp.h> | |
| 39 | −#include <linux/delay.h> | |
| 40 | −#include <linux/random.h> | |
| 41 | −#include <linux/wait.h> | |
| 42 | −#include <linux/sched/signal.h> | |
| 43 | −#include <linux/rtnetlink.h> | |
| 44 | −#include <linux/wireless.h> | |
| 45 | −#include <net/iw_handler.h> | |
| 46 | −#include <net/lib80211.h> | |
| 47 | −#include <asm/irq.h> | |
| 48 | − | |
| 49 | −#include "hostap_80211.h" | |
| 50 | −#include "hostap.h" | |
| 51 | −#include "hostap_ap.h" | |
| 52 | − | |
| 53 | − | |
| 54 | −/* #define final_version */ | |
| 55 | − | |
| 56 | −static int mtu = 1500; | |
| 57 | −module_param(mtu, int, 0444); | |
| 58 | −MODULE_PARM_DESC(mtu, "Maximum transfer unit"); | |
| 59 | − | |
| 60 | −static int channel[MAX_PARM_DEVICES] = { 3, DEF_INTS }; | |
| 61 | −module_param_array(channel, int, NULL, 0444); | |
| 62 | −MODULE_PARM_DESC(channel, "Initial channel"); | |
| 63 | − | |
| 64 | −static char essid[33] = "test"; | |
| 65 | −module_param_string(essid, essid, sizeof(essid), 0444); | |
| 66 | −MODULE_PARM_DESC(essid, "Host AP's ESSID"); | |
| 67 | − | |
| 68 | −static int iw_mode[MAX_PARM_DEVICES] = { IW_MODE_MASTER, DEF_INTS }; | |
| 69 | −module_param_array(iw_mode, int, NULL, 0444); | |
| 70 | −MODULE_PARM_DESC(iw_mode, "Initial operation mode"); | |
| 71 | − | |
| 72 | −static int beacon_int[MAX_PARM_DEVICES] = { 100, DEF_INTS }; | |
| 73 | −module_param_array(beacon_int, int, NULL, 0444); | |
| 74 | −MODULE_PARM_DESC(beacon_int, "Beacon interval (1 = 1024 usec)"); | |
| 75 | − | |
| 76 | −static int dtim_period[MAX_PARM_DEVICES] = { 1, DEF_INTS }; | |
| 77 | −module_param_array(dtim_period, int, NULL, 0444); | |
| 78 | −MODULE_PARM_DESC(dtim_period, "DTIM period"); | |
| 79 | − | |
| 80 | −static char dev_template[16] = "wlan%d"; | |
| 81 | −module_param_string(dev_template, dev_template, sizeof(dev_template), 0444); | |
| 82 | −MODULE_PARM_DESC(dev_template, "Prefix for network device name (default: " | |
| 83 | − "wlan%d)"); | |
| 84 | − | |
| 85 | −#ifdef final_version | |
| 86 | −#define EXTRA_EVENTS_WTERR 0 | |
| 87 | −#else | |
| 88 | −/* check WTERR events (Wait Time-out) in development versions */ | |
| 89 | −#define EXTRA_EVENTS_WTERR HFA384X_EV_WTERR | |
| 90 | −#endif | |
| 91 | − | |
| 92 | −/* Events that will be using BAP0 */ | |
| 93 | −#define HFA384X_BAP0_EVENTS \ | |
| 94 | − (HFA384X_EV_TXEXC | HFA384X_EV_RX | HFA384X_EV_INFO | HFA384X_EV_TX) | |
| 95 | − | |
| 96 | −/* event mask, i.e., events that will result in an interrupt */ | |
| 97 | −#define HFA384X_EVENT_MASK \ | |
| 98 | − (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ | |
| 99 | − HFA384X_EV_CMD | HFA384X_EV_TICK | \ | |
| 100 | − EXTRA_EVENTS_WTERR) | |
| 101 | − | |
| 102 | −/* Default TX control flags: use 802.11 headers and request interrupt for | |
| 103 | − * failed transmits. Frames that request ACK callback, will add | |
| 104 | − * _TX_OK flag and _ALT_RTRY flag may be used to select different retry policy. | |
| 105 | − */ | |
| 106 | −#define HFA384X_TX_CTRL_FLAGS \ | |
| 107 | − (HFA384X_TX_CTRL_802_11 | HFA384X_TX_CTRL_TX_EX) | |
| 108 | − | |
| 109 | − | |
| 110 | −/* ca. 1 usec */ | |
| 111 | −#define HFA384X_CMD_BUSY_TIMEOUT 5000 | |
| 112 | −#define HFA384X_BAP_BUSY_TIMEOUT 50000 | |
| 113 | − | |
| 114 | −/* ca. 10 usec */ | |
| 115 | −#define HFA384X_CMD_COMPL_TIMEOUT 20000 | |
| 116 | −#define HFA384X_DL_COMPL_TIMEOUT 1000000 | |
| 117 | − | |
| 118 | −/* Wait times for initialization; yield to other processes to avoid busy | |
| 119 | − * waiting for long time. */ | |
| 120 | −#define HFA384X_INIT_TIMEOUT (HZ / 2) /* 500 ms */ | |
| 121 | −#define HFA384X_ALLOC_COMPL_TIMEOUT (HZ / 20) /* 50 ms */ | |
| 122 | − | |
| 123 | − | |
| 124 | −static void prism2_hw_reset(struct net_device *dev); | |
| 125 | −static void prism2_check_sta_fw_version(local_info_t *local); | |
| 126 | − | |
| 127 | −#ifdef PRISM2_DOWNLOAD_SUPPORT | |
| 128 | −/* hostap_download.c */ | |
| 129 | −static const struct proc_ops prism2_download_aux_dump_proc_ops; | |
| 130 | −static u8 * prism2_read_pda(struct net_device *dev); | |
| 131 | −static int prism2_download(local_info_t *local, | |
| 132 | − struct prism2_download_param *param); | |
| 133 | −static void prism2_download_free_data(struct prism2_download_data *dl); | |
| 134 | −static int prism2_download_volatile(local_info_t *local, | |
| 135 | − struct prism2_download_data *param); | |
| 136 | −static int prism2_download_genesis(local_info_t *local, | |
| 137 | − struct prism2_download_data *param); | |
| 138 | −static int prism2_get_ram_size(local_info_t *local); | |
| 139 | −#endif /* PRISM2_DOWNLOAD_SUPPORT */ | |
| 140 | − | |
| 141 | − | |
| 142 | − | |
| 143 | − | |
| 144 | −#ifndef final_version | |
| 145 | −/* magic value written to SWSUPPORT0 reg. for detecting whether card is still | |
| 146 | − * present */ | |
| 147 | −#define HFA384X_MAGIC 0x8A32 | |
| 148 | −#endif | |
| 149 | − | |
| 150 | −static void hfa384x_read_regs(struct net_device *dev, | |
| 151 | − struct hfa384x_regs *regs) | |
| 152 | −{ | |
| 153 | − regs->cmd = HFA384X_INW(HFA384X_CMD_OFF); | |
| 154 | − regs->evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); | |
| 155 | − regs->offset0 = HFA384X_INW(HFA384X_OFFSET0_OFF); | |
| 156 | − regs->offset1 = HFA384X_INW(HFA384X_OFFSET1_OFF); | |
| 157 | − regs->swsupport0 = HFA384X_INW(HFA384X_SWSUPPORT0_OFF); | |
| 158 | −} | |
| 159 | − | |
| 160 | − | |
| 161 | −/** | |
| 162 | − * __hostap_cmd_queue_free - Free Prism2 command queue entry (private) | |
| 163 | − * @local: pointer to private Host AP driver data | |
| 164 | − * @entry: Prism2 command queue entry to be freed | |
| 165 | − * @del_req: request the entry to be removed | |
| 166 | − * | |
| 167 | − * Internal helper function for freeing Prism2 command queue entries. | |
| 168 | − * Caller must have acquired local->cmdlock before calling this function. | |
| 169 | − */ | |
| 170 | −static inline void __hostap_cmd_queue_free(local_info_t *local, | |
| 171 | − struct hostap_cmd_queue *entry, | |
| 172 | − int del_req) | |
| 173 | −{ | |
| 174 | − if (del_req) { | |
| 175 | − entry->del_req = 1; | |
| 176 | − if (!list_empty(&entry->list)) { | |
| 177 | − list_del_init(&entry->list); | |
| 178 | − local->cmd_queue_len--; | |
| 179 | − } | |
| 180 | − } | |
| 181 | − | |
| 182 | − if (refcount_dec_and_test(&entry->usecnt) && entry->del_req) | |
| 183 | − kfree(entry); | |
| 184 | −} | |
| 185 | − | |
| 186 | − | |
| 187 | −/** | |
| 188 | − * hostap_cmd_queue_free - Free Prism2 command queue entry | |
| 189 | − * @local: pointer to private Host AP driver data | |
| 190 | − * @entry: Prism2 command queue entry to be freed | |
| 191 | − * @del_req: request the entry to be removed | |
| 192 | − * | |
| 193 | − * Free a Prism2 command queue entry. | |
| 194 | − */ | |
| 195 | −static inline void hostap_cmd_queue_free(local_info_t *local, | |
| 196 | − struct hostap_cmd_queue *entry, | |
| 197 | − int del_req) | |
| 198 | −{ | |
| 199 | − unsigned long flags; | |
| 200 | − | |
| 201 | − spin_lock_irqsave(&local->cmdlock, flags); | |
| 202 | − __hostap_cmd_queue_free(local, entry, del_req); | |
| 203 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 204 | −} | |
| 205 | − | |
| 206 | − | |
| 207 | −/** | |
| 208 | − * prism2_clear_cmd_queue - Free all pending Prism2 command queue entries | |
| 209 | − * @local: pointer to private Host AP driver data | |
| 210 | − */ | |
| 211 | −static void prism2_clear_cmd_queue(local_info_t *local) | |
| 212 | −{ | |
| 213 | − struct list_head *ptr, *n; | |
| 214 | − unsigned long flags; | |
| 215 | − struct hostap_cmd_queue *entry; | |
| 216 | − | |
| 217 | − spin_lock_irqsave(&local->cmdlock, flags); | |
| 218 | − list_for_each_safe(ptr, n, &local->cmd_queue) { | |
| 219 | − entry = list_entry(ptr, struct hostap_cmd_queue, list); | |
| 220 | − refcount_inc(&entry->usecnt); | |
| 221 | − printk(KERN_DEBUG "%s: removed pending cmd_queue entry " | |
| 222 | − "(type=%d, cmd=0x%04x, param0=0x%04x)\n", | |
| 223 | − local->dev->name, entry->type, entry->cmd, | |
| 224 | − entry->param0); | |
| 225 | − __hostap_cmd_queue_free(local, entry, 1); | |
| 226 | − } | |
| 227 | − if (local->cmd_queue_len) { | |
| 228 | − /* This should not happen; print debug message and clear | |
| 229 | − * queue length. */ | |
| 230 | − printk(KERN_DEBUG "%s: cmd_queue_len (%d) not zero after " | |
| 231 | − "flush\n", local->dev->name, local->cmd_queue_len); | |
| 232 | − local->cmd_queue_len = 0; | |
| 233 | − } | |
| 234 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 235 | −} | |
| 236 | − | |
| 237 | − | |
| 238 | −/** | |
| 239 | − * hfa384x_cmd_issue - Issue a Prism2 command to the hardware | |
| 240 | − * @dev: pointer to net_device | |
| 241 | − * @entry: Prism2 command queue entry to be issued | |
| 242 | − */ | |
| 243 | −static int hfa384x_cmd_issue(struct net_device *dev, | |
| 244 | − struct hostap_cmd_queue *entry) | |
| 245 | −{ | |
| 246 | − struct hostap_interface *iface; | |
| 247 | − local_info_t *local; | |
| 248 | − int tries; | |
| 249 | − u16 reg; | |
| 250 | − unsigned long flags; | |
| 251 | − | |
| 252 | − iface = netdev_priv(dev); | |
| 253 | − local = iface->local; | |
| 254 | − | |
| 255 | − if (local->func->card_present && !local->func->card_present(local)) | |
| 256 | − return -ENODEV; | |
| 257 | − | |
| 258 | − if (entry->issued) { | |
| 259 | − printk(KERN_DEBUG "%s: driver bug - re-issuing command @%p\n", | |
| 260 | − dev->name, entry); | |
| 261 | − } | |
| 262 | − | |
| 263 | − /* wait until busy bit is clear; this should always be clear since the | |
| 264 | − * commands are serialized */ | |
| 265 | − tries = HFA384X_CMD_BUSY_TIMEOUT; | |
| 266 | − while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | |
| 267 | − tries--; | |
| 268 | − udelay(1); | |
| 269 | − } | |
| 270 | −#ifndef final_version | |
| 271 | − if (tries != HFA384X_CMD_BUSY_TIMEOUT) { | |
| 272 | − prism2_io_debug_error(dev, 1); | |
| 273 | − printk(KERN_DEBUG "%s: hfa384x_cmd_issue: cmd reg was busy " | |
| 274 | − "for %d usec\n", dev->name, | |
| 275 | − HFA384X_CMD_BUSY_TIMEOUT - tries); | |
| 276 | − } | |
| 277 | −#endif | |
| 278 | − if (tries == 0) { | |
| 279 | − reg = HFA384X_INW(HFA384X_CMD_OFF); | |
| 280 | − prism2_io_debug_error(dev, 2); | |
| 281 | − printk(KERN_DEBUG "%s: hfa384x_cmd_issue - timeout - " | |
| 282 | − "reg=0x%04x\n", dev->name, reg); | |
| 283 | − return -ETIMEDOUT; | |
| 284 | − } | |
| 285 | − | |
| 286 | − /* write command */ | |
| 287 | − spin_lock_irqsave(&local->cmdlock, flags); | |
| 288 | − HFA384X_OUTW(entry->param0, HFA384X_PARAM0_OFF); | |
| 289 | − HFA384X_OUTW(entry->param1, HFA384X_PARAM1_OFF); | |
| 290 | − HFA384X_OUTW(entry->cmd, HFA384X_CMD_OFF); | |
| 291 | − entry->issued = 1; | |
| 292 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 293 | − | |
| 294 | − return 0; | |
| 295 | −} | |
| 296 | − | |
| 297 | − | |
| 298 | −/** | |
| 299 | − * hfa384x_cmd - Issue a Prism2 command and wait (sleep) for completion | |
| 300 | − * @dev: pointer to net_device | |
| 301 | − * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | |
| 302 | − * @param0: value for Param0 register | |
| 303 | − * @param1: value for Param1 register (pointer; %NULL if not used) | |
| 304 | − * @resp0: pointer for Resp0 data or %NULL if Resp0 is not needed | |
| 305 | − * | |
| 306 | − * Issue given command (possibly after waiting in command queue) and sleep | |
| 307 | − * until the command is completed (or timed out or interrupted). This can be | |
| 308 | − * called only from user process context. | |
| 309 | − */ | |
| 310 | −static int hfa384x_cmd(struct net_device *dev, u16 cmd, u16 param0, | |
| 311 | − u16 *param1, u16 *resp0) | |
| 312 | −{ | |
| 313 | − struct hostap_interface *iface; | |
| 314 | − local_info_t *local; | |
| 315 | − int err, res, issue, issued = 0; | |
| 316 | − unsigned long flags; | |
| 317 | − struct hostap_cmd_queue *entry; | |
| 318 | − DECLARE_WAITQUEUE(wait, current); | |
| 319 | − | |
| 320 | − iface = netdev_priv(dev); | |
| 321 | − local = iface->local; | |
| 322 | − | |
| 323 | − if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN) { | |
| 324 | − printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | |
| 325 | − dev->name); | |
| 326 | − return -1; | |
| 327 | − } | |
| 328 | − | |
| 329 | − if (signal_pending(current)) | |
| 330 | − return -EINTR; | |
| 331 | − | |
| 332 | − entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | |
| 333 | − if (entry == NULL) | |
| 334 | − return -ENOMEM; | |
| 335 | − | |
| 336 | − refcount_set(&entry->usecnt, 1); | |
| 337 | − entry->type = CMD_SLEEP; | |
| 338 | − entry->cmd = cmd; | |
| 339 | − entry->param0 = param0; | |
| 340 | − if (param1) | |
| 341 | − entry->param1 = *param1; | |
| 342 | − init_waitqueue_head(&entry->compl); | |
| 343 | − | |
| 344 | − /* prepare to wait for command completion event, but do not sleep yet | |
| 345 | − */ | |
| 346 | − add_wait_queue(&entry->compl, &wait); | |
| 347 | − set_current_state(TASK_INTERRUPTIBLE); | |
| 348 | − | |
| 349 | − spin_lock_irqsave(&local->cmdlock, flags); | |
| 350 | − issue = list_empty(&local->cmd_queue); | |
| 351 | − if (issue) | |
| 352 | − entry->issuing = 1; | |
| 353 | − list_add_tail(&entry->list, &local->cmd_queue); | |
| 354 | − local->cmd_queue_len++; | |
| 355 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 356 | − | |
| 357 | − err = 0; | |
| 358 | − if (!issue) | |
| 359 | − goto wait_completion; | |
| 360 | − | |
| 361 | − if (signal_pending(current)) | |
| 362 | − err = -EINTR; | |
| 363 | − | |
| 364 | − if (!err) { | |
| 365 | − if (hfa384x_cmd_issue(dev, entry)) | |
| 366 | − err = -ETIMEDOUT; | |
| 367 | − else | |
| 368 | − issued = 1; | |
| 369 | − } | |
| 370 | − | |
| 371 | − wait_completion: | |
| 372 | − if (!err && entry->type != CMD_COMPLETED) { | |
| 373 | − /* sleep until command is completed or timed out */ | |
| 374 | − res = schedule_timeout(2 * HZ); | |
| 375 | − } else | |
| 376 | − res = -1; | |
| 377 | − | |
| 378 | − if (!err && signal_pending(current)) | |
| 379 | − err = -EINTR; | |
| 380 | − | |
| 381 | − if (err && issued) { | |
| 382 | − /* the command was issued, so a CmdCompl event should occur | |
| 383 | − * soon; however, there's a pending signal and | |
| 384 | − * schedule_timeout() would be interrupted; wait a short period | |
| 385 | − * of time to avoid removing entry from the list before | |
| 386 | − * CmdCompl event */ | |
| 387 | − udelay(300); | |
| 388 | − } | |
| 389 | − | |
| 390 | − set_current_state(TASK_RUNNING); | |
| 391 | − remove_wait_queue(&entry->compl, &wait); | |
| 392 | − | |
| 393 | − /* If entry->list is still in the list, it must be removed | |
| 394 | − * first and in this case prism2_cmd_ev() does not yet have | |
| 395 | − * local reference to it, and the data can be kfree()'d | |
| 396 | − * here. If the command completion event is still generated, | |
| 397 | − * it will be assigned to next (possibly) pending command, but | |
| 398 | − * the driver will reset the card anyway due to timeout | |
| 399 | − * | |
| 400 | − * If the entry is not in the list prism2_cmd_ev() has a local | |
| 401 | − * reference to it, but keeps cmdlock as long as the data is | |
| 402 | − * needed, so the data can be kfree()'d here. */ | |
| 403 | − | |
| 404 | − /* FIX: if the entry->list is in the list, it has not been completed | |
| 405 | − * yet, so removing it here is somewhat wrong.. this could cause | |
| 406 | − * references to freed memory and next list_del() causing NULL pointer | |
| 407 | − * dereference.. it would probably be better to leave the entry in the | |
| 408 | − * list and the list should be emptied during hw reset */ | |
| 409 | − | |
| 410 | − spin_lock_irqsave(&local->cmdlock, flags); | |
| 411 | − if (!list_empty(&entry->list)) { | |
| 412 | − printk(KERN_DEBUG "%s: hfa384x_cmd: entry still in list? " | |
| 413 | − "(entry=%p, type=%d, res=%d)\n", dev->name, entry, | |
| 414 | − entry->type, res); | |
| 415 | − list_del_init(&entry->list); | |
| 416 | − local->cmd_queue_len--; | |
| 417 | − } | |
| 418 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 419 | − | |
| 420 | − if (err) { | |
| 421 | − printk(KERN_DEBUG "%s: hfa384x_cmd: interrupted; err=%d\n", | |
| 422 | − dev->name, err); | |
| 423 | − res = err; | |
| 424 | − goto done; | |
| 425 | − } | |
| 426 | − | |
| 427 | − if (entry->type != CMD_COMPLETED) { | |
| 428 | − u16 reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | |
| 429 | − printk(KERN_DEBUG "%s: hfa384x_cmd: command was not " | |
| 430 | − "completed (res=%d, entry=%p, type=%d, cmd=0x%04x, " | |
| 431 | − "param0=0x%04x, EVSTAT=%04x INTEN=%04x)\n", dev->name, | |
| 432 | − res, entry, entry->type, entry->cmd, entry->param0, reg, | |
| 433 | − HFA384X_INW(HFA384X_INTEN_OFF)); | |
| 434 | − if (reg & HFA384X_EV_CMD) { | |
| 435 | − /* Command completion event is pending, but the | |
| 436 | − * interrupt was not delivered - probably an issue | |
| 437 | − * with pcmcia-cs configuration. */ | |
| 438 | − printk(KERN_WARNING "%s: interrupt delivery does not " | |
| 439 | − "seem to work\n", dev->name); | |
| 440 | − } | |
| 441 | − prism2_io_debug_error(dev, 3); | |
| 442 | − res = -ETIMEDOUT; | |
| 443 | − goto done; | |
| 444 | − } | |
| 445 | − | |
| 446 | − if (resp0 != NULL) | |
| 447 | − *resp0 = entry->resp0; | |
| 448 | −#ifndef final_version | |
| 449 | − if (entry->res) { | |
| 450 | − printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x, " | |
| 451 | − "resp0=0x%04x\n", | |
| 452 | − dev->name, cmd, entry->res, entry->resp0); | |
| 453 | − } | |
| 454 | −#endif /* final_version */ | |
| 455 | − | |
| 456 | − res = entry->res; | |
| 457 | − done: | |
| 458 | − hostap_cmd_queue_free(local, entry, 1); | |
| 459 | − return res; | |
| 460 | −} | |
| 461 | − | |
| 462 | − | |
| 463 | −/** | |
| 464 | − * hfa384x_cmd_callback - Issue a Prism2 command; callback when completed | |
| 465 | − * @dev: pointer to net_device | |
| 466 | − * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | |
| 467 | − * @param0: value for Param0 register | |
| 468 | − * @callback: command completion callback function (%NULL = no callback) | |
| 469 | − * @context: context data to be given to the callback function | |
| 470 | − * | |
| 471 | − * Issue given command (possibly after waiting in command queue) and use | |
| 472 | − * callback function to indicate command completion. This can be called both | |
| 473 | − * from user and interrupt context. The callback function will be called in | |
| 474 | − * hardware IRQ context. It can be %NULL, when no function is called when | |
| 475 | − * command is completed. | |
| 476 | − */ | |
| 477 | −static int hfa384x_cmd_callback(struct net_device *dev, u16 cmd, u16 param0, | |
| 478 | − void (*callback)(struct net_device *dev, | |
| 479 | − long context, u16 resp0, | |
| 480 | − u16 status), | |
| 481 | − long context) | |
| 482 | −{ | |
| 483 | − struct hostap_interface *iface; | |
| 484 | − local_info_t *local; | |
| 485 | − int issue, ret; | |
| 486 | − unsigned long flags; | |
| 487 | − struct hostap_cmd_queue *entry; | |
| 488 | − | |
| 489 | − iface = netdev_priv(dev); | |
| 490 | − local = iface->local; | |
| 491 | − | |
| 492 | − if (local->cmd_queue_len >= HOSTAP_CMD_QUEUE_MAX_LEN + 2) { | |
| 493 | − printk(KERN_DEBUG "%s: hfa384x_cmd: cmd_queue full\n", | |
| 494 | − dev->name); | |
| 495 | − return -1; | |
| 496 | − } | |
| 497 | − | |
| 498 | − entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | |
| 499 | − if (entry == NULL) | |
| 500 | − return -ENOMEM; | |
| 501 | − | |
| 502 | − refcount_set(&entry->usecnt, 1); | |
| 503 | − entry->type = CMD_CALLBACK; | |
| 504 | − entry->cmd = cmd; | |
| 505 | − entry->param0 = param0; | |
| 506 | − entry->callback = callback; | |
| 507 | − entry->context = context; | |
| 508 | − | |
| 509 | − spin_lock_irqsave(&local->cmdlock, flags); | |
| 510 | − issue = list_empty(&local->cmd_queue); | |
| 511 | − if (issue) | |
| 512 | − entry->issuing = 1; | |
| 513 | − list_add_tail(&entry->list, &local->cmd_queue); | |
| 514 | − local->cmd_queue_len++; | |
| 515 | − spin_unlock_irqrestore(&local->cmdlock, flags); | |
| 516 | − | |
| 517 | − if (issue && hfa384x_cmd_issue(dev, entry)) | |
| 518 | − ret = -ETIMEDOUT; | |
| 519 | − else | |
| 520 | − ret = 0; | |
| 521 | − | |
| 522 | − hostap_cmd_queue_free(local, entry, ret); | |
| 523 | − | |
| 524 | − return ret; | |
| 525 | −} | |
| 526 | − | |
| 527 | − | |
| 528 | −/** | |
| 529 | − * __hfa384x_cmd_no_wait - Issue a Prism2 command (private) | |
| 530 | − * @dev: pointer to net_device | |
| 531 | − * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | |
| 532 | − * @param0: value for Param0 register | |
| 533 | − * @io_debug_num: I/O debug error number | |
| 534 | − * | |
| 535 | − * Shared helper function for hfa384x_cmd_wait() and hfa384x_cmd_no_wait(). | |
| 536 | − */ | |
| 537 | −static int __hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, u16 param0, | |
| 538 | − int io_debug_num) | |
| 539 | −{ | |
| 540 | − int tries; | |
| 541 | − u16 reg; | |
| 542 | − | |
| 543 | − /* wait until busy bit is clear; this should always be clear since the | |
| 544 | − * commands are serialized */ | |
| 545 | − tries = HFA384X_CMD_BUSY_TIMEOUT; | |
| 546 | − while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) { | |
| 547 | − tries--; | |
| 548 | − udelay(1); | |
| 549 | − } | |
| 550 | − if (tries == 0) { | |
| 551 | − reg = HFA384X_INW(HFA384X_CMD_OFF); | |
| 552 | − prism2_io_debug_error(dev, io_debug_num); | |
| 553 | − printk(KERN_DEBUG "%s: __hfa384x_cmd_no_wait(%d) - timeout - " | |
| 554 | − "reg=0x%04x\n", dev->name, io_debug_num, reg); | |
| 555 | − return -ETIMEDOUT; | |
| 556 | − } | |
| 557 | − | |
| 558 | − /* write command */ | |
| 559 | − HFA384X_OUTW(param0, HFA384X_PARAM0_OFF); | |
| 560 | − HFA384X_OUTW(cmd, HFA384X_CMD_OFF); | |
| 561 | − | |
| 562 | − return 0; | |
| 563 | −} | |
| 564 | − | |
| 565 | − | |
| 566 | −/** | |
| 567 | − * hfa384x_cmd_wait - Issue a Prism2 command and busy wait for completion | |
| 568 | − * @dev: pointer to net_device | |
| 569 | − * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | |
| 570 | − * @param0: value for Param0 register | |
| 571 | − */ | |
| 572 | −static int hfa384x_cmd_wait(struct net_device *dev, u16 cmd, u16 param0) | |
| 573 | −{ | |
| 574 | − int res, tries; | |
| 575 | − u16 reg; | |
| 576 | − | |
| 577 | − res = __hfa384x_cmd_no_wait(dev, cmd, param0, 4); | |
| 578 | − if (res) | |
| 579 | − return res; | |
| 580 | − | |
| 581 | − /* wait for command completion */ | |
| 582 | − if ((cmd & HFA384X_CMDCODE_MASK) == HFA384X_CMDCODE_DOWNLOAD) | |
| 583 | − tries = HFA384X_DL_COMPL_TIMEOUT; | |
| 584 | − else | |
| 585 | − tries = HFA384X_CMD_COMPL_TIMEOUT; | |
| 586 | − | |
| 587 | − while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | |
| 588 | − tries > 0) { | |
| 589 | − tries--; | |
| 590 | − udelay(10); | |
| 591 | − } | |
| 592 | − if (tries == 0) { | |
| 593 | − reg = HFA384X_INW(HFA384X_EVSTAT_OFF); | |
| 594 | − prism2_io_debug_error(dev, 5); | |
| 595 | − printk(KERN_DEBUG "%s: hfa384x_cmd_wait - timeout2 - " | |
| 596 | − "reg=0x%04x\n", dev->name, reg); | |
| 597 | − return -ETIMEDOUT; | |
| 598 | − } | |
| 599 | − | |
| 600 | − res = (HFA384X_INW(HFA384X_STATUS_OFF) & | |
| 601 | − (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9) | | |
| 602 | − BIT(8))) >> 8; | |
| 603 | −#ifndef final_version | |
| 604 | − if (res) { | |
| 605 | − printk(KERN_DEBUG "%s: CMD=0x%04x => res=0x%02x\n", | |
| 606 | − dev->name, cmd, res); | |
| 607 | − } | |
| 608 | −#endif | |
| 609 | − | |
| 610 | − HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | |
| 611 | − | |
| 612 | − return res; | |
| 613 | −} | |
| 614 | − | |
| 615 | − | |
| 616 | −/** | |
| 617 | − * hfa384x_cmd_no_wait - Issue a Prism2 command; do not wait for completion | |
| 618 | − * @dev: pointer to net_device | |
| 619 | − * @cmd: Prism2 command code (HFA384X_CMD_CODE_*) | |
| 620 | − * @param0: value for Param0 register | |
| 621 | − */ | |
| 622 | −static inline int hfa384x_cmd_no_wait(struct net_device *dev, u16 cmd, | |
| 623 | − u16 param0) | |
| 624 | −{ | |
| 625 | − return __hfa384x_cmd_no_wait(dev, cmd, param0, 6); | |
| 626 | −} | |
| 627 | − | |
| 628 | − | |
| 629 | −/** | |
| 630 | − * prism2_cmd_ev - Prism2 command completion event handler | |
| 631 | − * @dev: pointer to net_device | |
| 632 | − * | |
| 633 | − * Interrupt handler for command completion events. Called by the main | |
| 634 | − * interrupt handler in hardware IRQ context. Read Resp0 and status registers | |
| 635 | − * from the hardware and ACK the event. Depending on the issued command type | |
| 636 | − * either wake up the sleeping process that is waiting for command completion | |
| 637 | − * or call the callback function. Issue the next command, if one is pending. | |
| 638 | − */ | |
| 639 | −static void prism2_cmd_ev(struct net_device *dev) | |
| 640 | −{ | |
| 641 | − struct hostap_interface *iface; | |
| 642 | − local_info_t *local; | |
| 643 | − struct hostap_cmd_queue *entry = NULL; | |
| 644 | − | |
| 645 | − iface = netdev_priv(dev); | |
| 646 | − local = iface->local; | |
| 647 | − | |
| 648 | − spin_lock(&local->cmdlock); | |
| 649 | − if (!list_empty(&local->cmd_queue)) { | |
| 650 | − entry = list_entry(local->cmd_queue.next, | |
| 651 | − struct hostap_cmd_queue, list); | |
| 652 | − refcount_inc(&entry->usecnt); | |
| 653 | − list_del_init(&entry->list); | |
| 654 | − local->cmd_queue_len--; | |
| 655 | − | |
| 656 | − if (!entry->issued) { | |
| 657 | − printk(KERN_DEBUG "%s: Command completion event, but " | |
| 658 | − "cmd not issued\n", dev->name); | |
| 659 | − __hostap_cmd_queue_free(local, entry, 1); | |
| 660 | − entry = NULL; | |
| 661 | − } | |
| 662 | − } | |
| 663 | − spin_unlock(&local->cmdlock); | |
| 664 | − | |
| 665 | − if (!entry) { | |
| 666 | − HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | |
| 667 | − printk(KERN_DEBUG "%s: Command completion event, but no " | |
| 668 | − "pending commands\n", dev->name); | |
| 669 | − return; | |
| 670 | − } | |
| 671 | − | |
| 672 | − entry->resp0 = HFA384X_INW(HFA384X_RESP0_OFF); | |
| 673 | − entry->res = (HFA384X_INW(HFA384X_STATUS_OFF) & | |
| 674 | − (BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | | |
| 675 | − BIT(9) | BIT(8))) >> 8; | |
| 676 | − HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | |
| 677 | − | |
| 678 | − /* TODO: rest of the CmdEv handling could be moved to tasklet */ | |
| 679 | − if (entry->type == CMD_SLEEP) { | |
| 680 | − entry->type = CMD_COMPLETED; | |
| 681 | − wake_up_interruptible(&entry->compl); | |
| 682 | − } else if (entry->type == CMD_CALLBACK) { | |
| 683 | − if (entry->callback) | |
| 684 | − entry->callback(dev, entry->context, entry->resp0, | |
| 685 | − entry->res); | |
| 686 | − } else { | |
| 687 | − printk(KERN_DEBUG "%s: Invalid command completion type %d\n", | |
| 688 | − dev->name, entry->type); | |
| 689 | − } | |
| 690 | − hostap_cmd_queue_free(local, entry, 1); | |
| 691 | − | |
| 692 | − /* issue next command, if pending */ | |
| 693 | − entry = NULL; | |
| 694 | − spin_lock(&local->cmdlock); | |
| 695 | − if (!list_empty(&local->cmd_queue)) { | |
| 696 | − entry = list_entry(local->cmd_queue.next, | |
| 697 | − struct hostap_cmd_queue, list); | |
| 698 | − if (entry->issuing) { | |
| 699 | − /* hfa384x_cmd() has already started issuing this | |
| 700 | − * command, so do not start here */ | |
| 701 | − entry = NULL; | |
| 702 | − } | |
| 703 | − if (entry) | |
| 704 | − refcount_inc(&entry->usecnt); | |
| 705 | − } | |
| 706 | − spin_unlock(&local->cmdlock); | |
| 707 | − | |
| 708 | − if (entry) { | |
| 709 | − /* issue next command; if command issuing fails, remove the | |
| 710 | − * entry from cmd_queue */ | |
| 711 | − int res = hfa384x_cmd_issue(dev, entry); | |
| 712 | − spin_lock(&local->cmdlock); | |
| 713 | − __hostap_cmd_queue_free(local, entry, res); | |
| 714 | − spin_unlock(&local->cmdlock); | |
| 715 | − } | |
| 716 | −} | |
| 717 | − | |
| 718 | − | |
| 719 | −static int hfa384x_wait_offset(struct net_device *dev, u16 o_off) | |
| 720 | −{ | |
| 721 | − int tries = HFA384X_BAP_BUSY_TIMEOUT; | |
| 722 | − int res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | |
| 723 | − | |
| 724 | − while (res && tries > 0) { | |
| 725 | − tries--; | |
| 726 | − udelay(1); | |
| 727 | − res = HFA384X_INW(o_off) & HFA384X_OFFSET_BUSY; | |
| 728 | − } | |
| 729 | − return res; | |
| 730 | −} | |
| 731 | − | |
| 732 | − | |
| 733 | −/* Offset must be even */ | |
| 734 | −static int hfa384x_setup_bap(struct net_device *dev, u16 bap, u16 id, | |
| 735 | − int offset) | |
| 736 | −{ | |
| 737 | − u16 o_off, s_off; | |
| 738 | − int ret = 0; | |
| 739 | − | |
| 740 | − if (offset % 2 || bap > 1) | |
| 741 | − return -EINVAL; | |
| 742 | − | |
| 743 | − if (bap == BAP1) { | |
| 744 | − o_off = HFA384X_OFFSET1_OFF; | |
| 745 | − s_off = HFA384X_SELECT1_OFF; | |
| 746 | − } else { | |
| 747 | − o_off = HFA384X_OFFSET0_OFF; | |
| 748 | − s_off = HFA384X_SELECT0_OFF; | |
| 749 | − } | |
| 750 | − | |
| 751 | − if (hfa384x_wait_offset(dev, o_off)) { | |
| 752 | − prism2_io_debug_error(dev, 7); | |
| 753 | − printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout before\n", | |
| 754 | − dev->name); | |
| 755 | − ret = -ETIMEDOUT; | |
| 756 | − goto out; | |
| 757 | − } | |
| 758 | − | |
| 759 | − HFA384X_OUTW(id, s_off); | |
| 760 | − HFA384X_OUTW(offset, o_off); | |
| 761 | − | |
| 762 | − if (hfa384x_wait_offset(dev, o_off)) { | |
| 763 | − prism2_io_debug_error(dev, 8); | |
| 764 | − printk(KERN_DEBUG "%s: hfa384x_setup_bap - timeout after\n", | |
| 765 | − dev->name); | |
| 766 | − ret = -ETIMEDOUT; | |
| 767 | − goto out; | |
| 768 | − } | |
| 769 | −#ifndef final_version | |
| 770 | − if (HFA384X_INW(o_off) & HFA384X_OFFSET_ERR) { | |
| 771 | − prism2_io_debug_error(dev, 9); | |
| 772 | − printk(KERN_DEBUG "%s: hfa384x_setup_bap - offset error " | |
| 773 | − "(%d,0x04%x,%d); reg=0x%04x\n", | |
| 774 | − dev->name, bap, id, offset, HFA384X_INW(o_off)); | |
| 775 | − ret = -EINVAL; | |
| 776 | − } | |
| 777 | −#endif | |
| 778 | − | |
| 779 | − out: | |
| 780 | − return ret; | |
| 781 | −} | |
| 782 | − | |
| 783 | − | |
| 784 | −static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len, | |
| 785 | − int exact_len) | |
| 786 | −{ | |
| 787 | − struct hostap_interface *iface; | |
| 788 | − local_info_t *local; | |
| 789 | − int res, rlen = 0; | |
| 790 | − struct hfa384x_rid_hdr rec; | |
| 791 | − | |
| 792 | − iface = netdev_priv(dev); | |
| 793 | − local = iface->local; | |
| 794 | − | |
| 795 | − if (local->no_pri) { | |
| 796 | − printk(KERN_DEBUG "%s: cannot get RID %04x (len=%d) - no PRI " | |
| 797 | − "f/w\n", dev->name, rid, len); | |
| 798 | − return -ENOTTY; /* Well.. not really correct, but return | |
| 799 | − * something unique enough.. */ | |
| 800 | − } | |
| 801 | − | |
| 802 | − if ((local->func->card_present && !local->func->card_present(local)) || | |
| 803 | − local->hw_downloading) | |
| 804 | − return -ENODEV; | |
| 805 | − | |
| 806 | − res = mutex_lock_interruptible(&local->rid_bap_mtx); | |
| 807 | − if (res) | |
| 808 | − return res; | |
| 809 | − | |
| 810 | − res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS, rid, NULL, NULL); | |
| 811 | − if (res) { | |
| 812 | − printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed " | |
| 813 | − "(res=%d, rid=%04x, len=%d)\n", | |
| 814 | − dev->name, res, rid, len); | |
| 815 | − mutex_unlock(&local->rid_bap_mtx); | |
| 816 | − return res; | |
| 817 | − } | |
| 818 | − | |
| 819 | − spin_lock_bh(&local->baplock); | |
| 820 | − | |
| 821 | − res = hfa384x_setup_bap(dev, BAP0, rid, 0); | |
| 822 | − if (res) | |
| 823 | − goto unlock; | |
| 824 | − | |
| 825 | − res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec)); | |
| 826 | − if (res) | |
| 827 | − goto unlock; | |
| 828 | − | |
| 829 | − if (le16_to_cpu(rec.len) == 0) { | |
| 830 | − /* RID not available */ | |
| 831 | − res = -ENODATA; | |
| 832 | − goto unlock; | |
| 833 | − } | |
| 834 | − | |
| 835 | − rlen = (le16_to_cpu(rec.len) - 1) * 2; | |
| 836 | − if (exact_len && rlen != len) { | |
| 837 | − printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: " | |
| 838 | − "rid=0x%04x, len=%d (expected %d)\n", | |
| 839 | − dev->name, rid, rlen, len); | |
| 840 | − res = -ENODATA; | |
| 841 | − } | |
| 842 | − | |
| 843 | − res = hfa384x_from_bap(dev, BAP0, buf, len); | |
| 844 | − | |
| 845 | −unlock: | |
| 846 | − spin_unlock_bh(&local->baplock); | |
| 847 | − mutex_unlock(&local->rid_bap_mtx); | |
| 848 | − | |
| 849 | − if (res) { | |
| 850 | − if (res != -ENODATA) | |
| 851 | − printk(KERN_DEBUG "%s: hfa384x_get_rid (rid=%04x, " | |
| 852 | − "len=%d) - failed - res=%d\n", dev->name, rid, | |
| 853 | − len, res); | |
| 854 | − if (res == -ETIMEDOUT) | |
| 855 | − prism2_hw_reset(dev); | |
| 856 | − return res; | |
| 857 | − } | |
| 858 | − | |
| 859 | − return rlen; | |
| 860 | −} | |
| 861 | − | |
| 862 | − | |
| 863 | −static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) | |
| 864 | −{ | |
| 865 | − struct hostap_interface *iface; | |
| 866 | − local_info_t *local; | |
| 867 | − struct hfa384x_rid_hdr rec; | |
| 868 | − int res; | |
| 869 | − | |
| 870 | − iface = netdev_priv(dev); | |
| 871 | − local = iface->local; | |
| 872 | − | |
| 873 | − if (local->no_pri) { | |
| 874 | − printk(KERN_DEBUG "%s: cannot set RID %04x (len=%d) - no PRI " | |
| 875 | − "f/w\n", dev->name, rid, len); | |
| 876 | − return -ENOTTY; /* Well.. not really correct, but return | |
| 877 | − * something unique enough.. */ | |
| 878 | − } | |
| 879 | − | |
| 880 | − if ((local->func->card_present && !local->func->card_present(local)) || | |
| 881 | − local->hw_downloading) | |
| 882 | − return -ENODEV; | |
| 883 | − | |
| 884 | − rec.rid = cpu_to_le16(rid); | |
| 885 | − /* RID len in words and +1 for rec.rid */ | |
| 886 | − rec.len = cpu_to_le16(len / 2 + len % 2 + 1); | |
| 887 | − | |
| 888 | − res = mutex_lock_interruptible(&local->rid_bap_mtx); | |
| 889 | − if (res) | |
| 890 | − return res; | |
| 891 | − | |
| 892 | − spin_lock_bh(&local->baplock); | |
| 893 | − res = hfa384x_setup_bap(dev, BAP0, rid, 0); | |
| 894 | − if (!res) | |
| 895 | − res = hfa384x_to_bap(dev, BAP0, &rec, sizeof(rec)); | |
| 896 | − if (!res) | |
| 897 | − res = hfa384x_to_bap(dev, BAP0, buf, len); | |
| 898 | − spin_unlock_bh(&local->baplock); | |
| 899 | − | |
| 900 | − if (res) { | |
| 901 | − printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - " | |
| 902 | − "failed - res=%d\n", dev->name, rid, len, res); | |
| 903 | − mutex_unlock(&local->rid_bap_mtx); | |
| 904 | − return res; | |
| 905 | − } | |
| 906 | − | |
| 907 | − res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); | |
| 908 | − mutex_unlock(&local->rid_bap_mtx); | |
| 909 | − | |
| 910 | − if (res) { | |
| 911 | − printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " | |
| 912 | − "failed (res=%d, rid=%04x, len=%d)\n", | |
| 913 | − dev->name, res, rid, len); | |
| 914 | − | |
| 915 | − if (res == -ETIMEDOUT) | |
| 916 | − prism2_hw_reset(dev); | |
| 917 | − } | |
| 918 | − | |
| 919 | − return res; | |
| 920 | −} | |
| 921 | − | |
| 922 | − | |
| 923 | −static void hfa384x_disable_interrupts(struct net_device *dev) | |
| 924 | −{ | |
| 925 | − /* disable interrupts and clear event status */ | |
| 926 | − HFA384X_OUTW(0, HFA384X_INTEN_OFF); | |
| 927 | − HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | |
| 928 | −} | |
| 929 | − | |
| 930 | − | |
| 931 | −static void hfa384x_enable_interrupts(struct net_device *dev) | |
| 932 | −{ | |
| 933 | − /* ack pending events and enable interrupts from selected events */ | |
| 934 | − HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); | |
| 935 | − HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | |
| 936 | −} | |
| 937 | − | |
| 938 | − | |
| 939 | −static void hfa384x_events_no_bap0(struct net_device *dev) | |
| 940 | −{ | |
| 941 | − HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, | |
| 942 | − HFA384X_INTEN_OFF); | |
| 943 | −} | |
| 944 | − | |
| 945 | − | |
| 946 | −static void hfa384x_events_all(struct net_device *dev) | |
| 947 | −{ | |
| 948 | − HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); | |
| 949 | −} | |
| 950 | − | |
| 951 | − | |
| 952 | −static void hfa384x_events_only_cmd(struct net_device *dev) | |
| 953 | −{ | |
| 954 | − HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); | |
| 955 | −} | |
| 956 | − | |
| 957 | − | |
| 958 | −static u16 hfa384x_allocate_fid(struct net_device *dev, int len) | |
| 959 | −{ | |
| 960 | − u16 fid; | |
| 961 | − unsigned long delay; | |
| 962 | − | |
| 963 | − /* FIX: this could be replace with hfa384x_cmd() if the Alloc event | |
| 964 | − * below would be handled like CmdCompl event (sleep here, wake up from | |
| 965 | − * interrupt handler */ | |
| 966 | − if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_ALLOC, len)) { | |
| 967 | − printk(KERN_DEBUG "%s: cannot allocate fid, len=%d\n", | |
| 968 | − dev->name, len); | |
| 969 | − return 0xffff; | |
| 970 | − } | |
| 971 | − | |
| 972 | − delay = jiffies + HFA384X_ALLOC_COMPL_TIMEOUT; | |
| 973 | − while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC) && | |
| 974 | − time_before(jiffies, delay)) | |
| 975 | − yield(); | |
| 976 | − if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_ALLOC)) { | |
| 977 | − printk("%s: fid allocate, len=%d - timeout\n", dev->name, len); | |
| 978 | − return 0xffff; | |
| 979 | − } | |
| 980 | − | |
| 981 | − fid = HFA384X_INW(HFA384X_ALLOCFID_OFF); | |
| 982 | − HFA384X_OUTW(HFA384X_EV_ALLOC, HFA384X_EVACK_OFF); | |
| 983 | − | |
| 984 | − return fid; | |
| 985 | −} | |
| 986 | − | |
| 987 | − | |
| 988 | −static int prism2_reset_port(struct net_device *dev) | |
| 989 | −{ | |
| 990 | − struct hostap_interface *iface; | |
| 991 | − local_info_t *local; | |
| 992 | − int res; | |
| 993 | − | |
| 994 | − iface = netdev_priv(dev); | |
| 995 | − local = iface->local; | |
| 996 | − | |
| 997 | − if (!local->dev_enabled) | |
| 998 | − return 0; | |
| 999 | − | |
| 1000 | − res = hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, | |
| 1001 | − NULL, NULL); | |
| 1002 | − if (res) | |
| 1003 | − printk(KERN_DEBUG "%s: reset port failed to disable port\n", | |
| 1004 | − dev->name); | |
| 1005 | − else { | |
| 1006 | − res = hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, | |
| 1007 | − NULL, NULL); | |
| 1008 | − if (res) | |
| 1009 | − printk(KERN_DEBUG "%s: reset port failed to enable " | |
| 1010 | − "port\n", dev->name); | |
| 1011 | − } | |
| 1012 | − | |
| 1013 | − /* It looks like at least some STA firmware versions reset | |
| 1014 | − * fragmentation threshold back to 2346 after enable command. Restore | |
| 1015 | − * the configured value, if it differs from this default. */ | |
| 1016 | − if (local->fragm_threshold != 2346 && | |
| 1017 | − hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | |
| 1018 | − local->fragm_threshold)) { | |
| 1019 | − printk(KERN_DEBUG "%s: failed to restore fragmentation " | |
| 1020 | − "threshold (%d) after Port0 enable\n", | |
| 1021 | − dev->name, local->fragm_threshold); | |
| 1022 | − } | |
| 1023 | − | |
| 1024 | − /* Some firmwares lose antenna selection settings on reset */ | |
| 1025 | − (void) hostap_set_antsel(local); | |
| 1026 | − | |
| 1027 | − return res; | |
| 1028 | −} | |
| 1029 | − | |
| 1030 | − | |
| 1031 | −static int prism2_get_version_info(struct net_device *dev, u16 rid, | |
| 1032 | − const char *txt) | |
| 1033 | −{ | |
| 1034 | − struct hfa384x_comp_ident comp; | |
| 1035 | − struct hostap_interface *iface; | |
| 1036 | − local_info_t *local; | |
| 1037 | − | |
| 1038 | − iface = netdev_priv(dev); | |
| 1039 | − local = iface->local; | |
| 1040 | − | |
| 1041 | − if (local->no_pri) { | |
| 1042 | − /* PRI f/w not yet available - cannot read RIDs */ | |
| 1043 | − return -1; | |
| 1044 | − } | |
| 1045 | − if (hfa384x_get_rid(dev, rid, &comp, sizeof(comp), 1) < 0) { | |
| 1046 | − printk(KERN_DEBUG "Could not get RID for component %s\n", txt); | |
| 1047 | − return -1; | |
| 1048 | − } | |
| 1049 | − | |
| 1050 | − printk(KERN_INFO "%s: %s: id=0x%02x v%d.%d.%d\n", dev->name, txt, | |
| 1051 | − __le16_to_cpu(comp.id), __le16_to_cpu(comp.major), | |
| 1052 | − __le16_to_cpu(comp.minor), __le16_to_cpu(comp.variant)); | |
| 1053 | − return 0; | |
| 1054 | −} | |
| 1055 | − | |
| 1056 | − | |
| 1057 | −static int prism2_setup_rids(struct net_device *dev) | |
| 1058 | −{ | |
| 1059 | − struct hostap_interface *iface; | |
| 1060 | − local_info_t *local; | |
| 1061 | − __le16 tmp; | |
| 1062 | − int ret = 0; | |
| 1063 | − | |
| 1064 | − iface = netdev_priv(dev); | |
| 1065 | − local = iface->local; | |
| 1066 | − | |
| 1067 | − hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); | |
| 1068 | − | |
| 1069 | − if (!local->fw_ap) { | |
| 1070 | − u16 tmp1 = hostap_get_porttype(local); | |
| 1071 | − ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp1); | |
| 1072 | − if (ret) { | |
| 1073 | − printk("%s: Port type setting to %d failed\n", | |
| 1074 | − dev->name, tmp1); | |
| 1075 | − goto fail; | |
| 1076 | − } | |
| 1077 | − } | |
| 1078 | − | |
| 1079 | − /* Setting SSID to empty string seems to kill the card in Host AP mode | |
| 1080 | − */ | |
| 1081 | − if (local->iw_mode != IW_MODE_MASTER || local->essid[0] != '\0') { | |
| 1082 | − ret = hostap_set_string(dev, HFA384X_RID_CNFOWNSSID, | |
| 1083 | − local->essid); | |
| 1084 | − if (ret) { | |
| 1085 | − printk("%s: AP own SSID setting failed\n", dev->name); | |
| 1086 | − goto fail; | |
| 1087 | − } | |
| 1088 | − } | |
| 1089 | − | |
| 1090 | − ret = hostap_set_word(dev, HFA384X_RID_CNFMAXDATALEN, | |
| 1091 | − PRISM2_DATA_MAXLEN); | |
| 1092 | − if (ret) { | |
| 1093 | − printk("%s: MAC data length setting to %d failed\n", | |
| 1094 | − dev->name, PRISM2_DATA_MAXLEN); | |
| 1095 | − goto fail; | |
| 1096 | − } | |
| 1097 | − | |
| 1098 | − if (hfa384x_get_rid(dev, HFA384X_RID_CHANNELLIST, &tmp, 2, 1) < 0) { | |
| 1099 | − printk("%s: Channel list read failed\n", dev->name); | |
| 1100 | − ret = -EINVAL; | |
| 1101 | − goto fail; | |
| 1102 | − } | |
| 1103 | − local->channel_mask = le16_to_cpu(tmp); | |
| 1104 | − | |
| 1105 | − if (local->channel < 1 || local->channel > 14 || | |
| 1106 | − !(local->channel_mask & (1 << (local->channel - 1)))) { | |
| 1107 | − printk(KERN_WARNING "%s: Channel setting out of range " | |
| 1108 | − "(%d)!\n", dev->name, local->channel); | |
| 1109 | − ret = -EBUSY; | |
| 1110 | − goto fail; | |
| 1111 | − } | |
| 1112 | − | |
| 1113 | − ret = hostap_set_word(dev, HFA384X_RID_CNFOWNCHANNEL, local->channel); | |
| 1114 | − if (ret) { | |
| 1115 | − printk("%s: Channel setting to %d failed\n", | |
| 1116 | − dev->name, local->channel); | |
| 1117 | − goto fail; | |
| 1118 | − } | |
| 1119 | − | |
| 1120 | − ret = hostap_set_word(dev, HFA384X_RID_CNFBEACONINT, | |
| 1121 | − local->beacon_int); | |
| 1122 | − if (ret) { | |
| 1123 | − printk("%s: Beacon interval setting to %d failed\n", | |
| 1124 | − dev->name, local->beacon_int); | |
| 1125 | − /* this may fail with Symbol/Lucent firmware */ | |
| 1126 | − if (ret == -ETIMEDOUT) | |
| 1127 | − goto fail; | |
| 1128 | − } | |
| 1129 | − | |
| 1130 | − ret = hostap_set_word(dev, HFA384X_RID_CNFOWNDTIMPERIOD, | |
| 1131 | − local->dtim_period); | |
| 1132 | − if (ret) { | |
| 1133 | − printk("%s: DTIM period setting to %d failed\n", | |
| 1134 | − dev->name, local->dtim_period); | |
| 1135 | − /* this may fail with Symbol/Lucent firmware */ | |
| 1136 | − if (ret == -ETIMEDOUT) | |
| 1137 | − goto fail; | |
| 1138 | − } | |
| 1139 | − | |
| 1140 | − ret = hostap_set_word(dev, HFA384X_RID_PROMISCUOUSMODE, | |
| 1141 | − local->is_promisc); | |
| 1142 | − if (ret) | |
| 1143 | − printk(KERN_INFO "%s: Setting promiscuous mode (%d) failed\n", | |
| 1144 | − dev->name, local->is_promisc); | |
| 1145 | − | |
| 1146 | − if (!local->fw_ap) { | |
| 1147 | − ret = hostap_set_string(dev, HFA384X_RID_CNFDESIREDSSID, | |
| 1148 | − local->essid); | |
| 1149 | − if (ret) { | |
| 1150 | − printk("%s: Desired SSID setting failed\n", dev->name); | |
| 1151 | − goto fail; | |
| 1152 | − } | |
| 1153 | − } | |
| 1154 | − | |
| 1155 | − /* Setup TXRateControl, defaults to allow use of 1, 2, 5.5, and | |
| 1156 | − * 11 Mbps in automatic TX rate fallback and 1 and 2 Mbps as basic | |
| 1157 | − * rates */ | |
| 1158 | − if (local->tx_rate_control == 0) { | |
| 1159 | − local->tx_rate_control = | |
| 1160 | − HFA384X_RATES_1MBPS | | |
| 1161 | − HFA384X_RATES_2MBPS | | |
| 1162 | − HFA384X_RATES_5MBPS | | |
| 1163 | − HFA384X_RATES_11MBPS; | |
| 1164 | − } | |
| 1165 | − if (local->basic_rates == 0) | |
| 1166 | − local->basic_rates = HFA384X_RATES_1MBPS | HFA384X_RATES_2MBPS; | |
| 1167 | − | |
| 1168 | − if (!local->fw_ap) { | |
| 1169 | − ret = hostap_set_word(dev, HFA384X_RID_TXRATECONTROL, | |
| 1170 | − local->tx_rate_control); | |
| 1171 | − if (ret) { | |
| 1172 | − printk("%s: TXRateControl setting to %d failed\n", | |
| 1173 | − dev->name, local->tx_rate_control); | |
| 1174 | − goto fail; | |
| 1175 | − } | |
| 1176 | − | |
| 1177 | − ret = hostap_set_word(dev, HFA384X_RID_CNFSUPPORTEDRATES, | |
| 1178 | − local->tx_rate_control); | |
| 1179 | − if (ret) { | |
| 1180 | − printk("%s: cnfSupportedRates setting to %d failed\n", | |
| 1181 | − dev->name, local->tx_rate_control); | |
| 1182 | − } | |
| 1183 | − | |
| 1184 | − ret = hostap_set_word(dev, HFA384X_RID_CNFBASICRATES, | |
| 1185 | − local->basic_rates); | |
| 1186 | − if (ret) { | |
| 1187 | − printk("%s: cnfBasicRates setting to %d failed\n", | |
| 1188 | − dev->name, local->basic_rates); | |
| 1189 | − } | |
| 1190 | − | |
| 1191 | − ret = hostap_set_word(dev, HFA384X_RID_CREATEIBSS, 1); | |
| 1192 | − if (ret) { | |
| 1193 | − printk("%s: Create IBSS setting to 1 failed\n", | |
| 1194 | − dev->name); | |
| 1195 | − } | |
| 1196 | − } | |
| 1197 | − | |
| 1198 | − if (local->name_set) | |
| 1199 | − (void) hostap_set_string(dev, HFA384X_RID_CNFOWNNAME, | |
| 1200 | − local->name); | |
| 1201 | − | |
| 1202 | − if (hostap_set_encryption(local)) { | |
| 1203 | − printk(KERN_INFO "%s: could not configure encryption\n", | |
| 1204 | − dev->name); | |
| 1205 | − } | |
| 1206 | − | |
| 1207 | − (void) hostap_set_antsel(local); | |
| 1208 | − | |
| 1209 | − if (hostap_set_roaming(local)) { | |
| 1210 | − printk(KERN_INFO "%s: could not set host roaming\n", | |
| 1211 | − dev->name); | |
| 1212 | − } | |
| 1213 | − | |
| 1214 | − if (local->sta_fw_ver >= PRISM2_FW_VER(1,6,3) && | |
| 1215 | − hostap_set_word(dev, HFA384X_RID_CNFENHSECURITY, local->enh_sec)) | |
| 1216 | − printk(KERN_INFO "%s: cnfEnhSecurity setting to 0x%x failed\n", | |
| 1217 | − dev->name, local->enh_sec); | |
| 1218 | − | |
| 1219 | − /* 32-bit tallies were added in STA f/w 0.8.0, but they were apparently | |
| 1220 | − * not working correctly (last seven counters report bogus values). | |
| 1221 | − * This has been fixed in 0.8.2, so enable 32-bit tallies only | |
| 1222 | − * beginning with that firmware version. Another bug fix for 32-bit | |
| 1223 | − * tallies in 1.4.0; should 16-bit tallies be used for some other | |
| 1224 | − * versions, too? */ | |
| 1225 | − if (local->sta_fw_ver >= PRISM2_FW_VER(0,8,2)) { | |
| 1226 | − if (hostap_set_word(dev, HFA384X_RID_CNFTHIRTY2TALLY, 1)) { | |
| 1227 | − printk(KERN_INFO "%s: cnfThirty2Tally setting " | |
| 1228 | − "failed\n", dev->name); | |
| 1229 | − local->tallies32 = 0; | |
| 1230 | − } else | |
| 1231 | − local->tallies32 = 1; | |
| 1232 | − } else | |
| 1233 | − local->tallies32 = 0; | |
| 1234 | − | |
| 1235 | − hostap_set_auth_algs(local); | |
| 1236 | − | |
| 1237 | − if (hostap_set_word(dev, HFA384X_RID_FRAGMENTATIONTHRESHOLD, | |
| 1238 | − local->fragm_threshold)) { | |
| 1239 | − printk(KERN_INFO "%s: setting FragmentationThreshold to %d " | |
| 1240 | − "failed\n", dev->name, local->fragm_threshold); | |
| 1241 | − } | |
| 1242 | − | |
| 1243 | − if (hostap_set_word(dev, HFA384X_RID_RTSTHRESHOLD, | |
| 1244 | − local->rts_threshold)) { | |
| 1245 | − printk(KERN_INFO "%s: setting RTSThreshold to %d failed\n", | |
| 1246 | − dev->name, local->rts_threshold); | |
| 1247 | − } | |
| 1248 | − | |
| 1249 | − if (local->manual_retry_count >= 0 && | |
| 1250 | − hostap_set_word(dev, HFA384X_RID_CNFALTRETRYCOUNT, | |
| 1251 | − local->manual_retry_count)) { | |
| 1252 | − printk(KERN_INFO "%s: setting cnfAltRetryCount to %d failed\n", | |
| 1253 | − dev->name, local->manual_retry_count); | |
| 1254 | − } | |
| 1255 | − | |
| 1256 | − if (local->sta_fw_ver >= PRISM2_FW_VER(1,3,1) && | |
| 1257 | − hfa384x_get_rid(dev, HFA384X_RID_CNFDBMADJUST, &tmp, 2, 1) == 2) { | |
| 1258 | − local->rssi_to_dBm = le16_to_cpu(tmp); | |
| 1259 | − } | |
| 1260 | − | |
| 1261 | − if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->wpa && | |
| 1262 | − hostap_set_word(dev, HFA384X_RID_SSNHANDLINGMODE, 1)) { | |
| 1263 | − printk(KERN_INFO "%s: setting ssnHandlingMode to 1 failed\n", | |
| 1264 | − dev->name); | |
| 1265 | − } | |
| 1266 | − | |
| 1267 | − if (local->sta_fw_ver >= PRISM2_FW_VER(1,7,0) && local->generic_elem && | |
| 1268 | − hfa384x_set_rid(dev, HFA384X_RID_GENERICELEMENT, | |
| 1269 | − local->generic_elem, local->generic_elem_len)) { | |
| 1270 | − printk(KERN_INFO "%s: setting genericElement failed\n", | |
| 1271 | − dev->name); | |
| 1272 | − } | |
| 1273 | − | |
| 1274 | − fail: | |
| 1275 | − return ret; | |
| 1276 | −} | |
| 1277 | − | |
| 1278 | − | |
| 1279 | −static int prism2_hw_init(struct net_device *dev, int initial) | |
| 1280 | −{ | |
| 1281 | − struct hostap_interface *iface; | |
| 1282 | − local_info_t *local; | |
| 1283 | − int ret, first = 1; | |
| 1284 | − unsigned long start, delay; | |
| 1285 | − | |
| 1286 | − PDEBUG(DEBUG_FLOW, "prism2_hw_init()\n"); | |
| 1287 | − | |
| 1288 | − iface = netdev_priv(dev); | |
| 1289 | − local = iface->local; | |
| 1290 | − | |
| 1291 | − clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits); | |
| 1292 | − | |
| 1293 | − init: | |
| 1294 | − /* initialize HFA 384x */ | |
| 1295 | − ret = hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_INIT, 0); | |
| 1296 | − if (ret) { | |
| 1297 | − printk(KERN_INFO "%s: first command failed - assuming card " | |
| 1298 | − "does not have primary firmware\n", dev_info); | |
| 1299 | − } | |
| 1300 | − | |
| 1301 | − if (first && (HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | |
| 1302 | − /* EvStat has Cmd bit set in some cases, so retry once if no | |
| 1303 | − * wait was needed */ | |
| 1304 | − HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | |
| 1305 | − printk(KERN_DEBUG "%s: init command completed too quickly - " | |
| 1306 | − "retrying\n", dev->name); | |
| 1307 | − first = 0; | |
| 1308 | − goto init; | |
| 1309 | − } | |
| 1310 | − | |
| 1311 | − start = jiffies; | |
| 1312 | − delay = jiffies + HFA384X_INIT_TIMEOUT; | |
| 1313 | − while (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD) && | |
| 1314 | − time_before(jiffies, delay)) | |
| 1315 | − yield(); | |
| 1316 | − if (!(HFA384X_INW(HFA384X_EVSTAT_OFF) & HFA384X_EV_CMD)) { | |
| 1317 | − printk(KERN_DEBUG "%s: assuming no Primary image in " | |
| 1318 | − "flash - card initialization not completed\n", | |
| 1319 | − dev_info); | |
| 1320 | − local->no_pri = 1; | |
| 1321 | −#ifdef PRISM2_DOWNLOAD_SUPPORT | |
| 1322 | − if (local->sram_type == -1) | |
| 1323 | − local->sram_type = prism2_get_ram_size(local); | |
| 1324 | −#endif /* PRISM2_DOWNLOAD_SUPPORT */ | |
| 1325 | − return 1; | |
| 1326 | − } | |
| 1327 | − local->no_pri = 0; | |
| 1328 | − printk(KERN_DEBUG "prism2_hw_init: initialized in %lu ms\n", | |
| 1329 | − (jiffies - start) * 1000 / HZ); | |
| 1330 | − HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); | |
| 1331 | − return 0; | |
| 1332 | −} | |
| 1333 | − | |
| 1334 | − | |
| 1335 | −static int prism2_hw_init2(struct net_device *dev, int initial) | |
| 1336 | −{ | |
| 1337 | − struct hostap_interface *iface; | |
| 1338 | − local_info_t *local; | |
| 1339 | − int i; | |
| 1340 | − | |
| 1341 | − iface = netdev_priv(dev); | |
| 1342 | − local = iface->local; | |
| 1343 | − | |
| 1344 | −#ifdef PRISM2_DOWNLOAD_SUPPORT | |
| 1345 | − kfree(local->pda); | |
| 1346 | − if (local->no_pri) | |
| 1347 | − local->pda = NULL; | |
| 1348 | − else | |
| 1349 | − local->pda = prism2_read_pda(dev); | |
| 1350 | −#endif /* PRISM2_DOWNLOAD_SUPPORT */ | |
| 1351 | − | |
| 1352 | − hfa384x_disable_interrupts(dev); | |
| 1353 | − | |
| 1354 | −#ifndef final_version | |
| 1355 | − HFA384X_OUTW(HFA384X_MAGIC, HFA384X_SWSUPPORT0_OFF); | |
| 1356 | − if (HFA384X_INW(HFA384X_SWSUPPORT0_OFF) != HFA384X_MAGIC) { | |
| 1357 | − printk("SWSUPPORT0 write/read failed: %04X != %04X\n", | |
| 1358 | − HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); | |
| 1359 | − goto failed; | |
| 1360 | − } | |
| 1361 | −#endif | |
| 1362 | − | |
| 1363 | − if (initial || local->pri_only) { | |
| 1364 | − hfa384x_events_only_cmd(dev); | |
| 1365 | − /* get card version information */ | |
| 1366 | − if (prism2_get_version_info(dev, HFA384X_RID_NICID, "NIC") || | |
| 1367 | − prism2_get_version_info(dev, HFA384X_RID_PRIID, "PRI")) { | |
| 1368 | − hfa384x_disable_interrupts(dev); | |
| 1369 | − goto failed; | |
| 1370 | − } | |
| 1371 | − | |
| 1372 | − if (prism2_get_version_info(dev, HFA384X_RID_STAID, "STA")) { | |
| 1373 | − printk(KERN_DEBUG "%s: Failed to read STA f/w version " | |
| 1374 | − "- only Primary f/w present\n", dev->name); | |
| 1375 | − local->pri_only = 1; | |
| 1376 | − return 0; | |
| 1377 | − } | |
| 1378 | − local->pri_only = 0; | |
| 1379 | − hfa384x_disable_interrupts(dev); | |
| 1380 | − } | |
| 1381 | − | |
| 1382 | − /* FIX: could convert allocate_fid to use sleeping CmdCompl wait and | |
| 1383 | − * enable interrupts before this. This would also require some sort of | |
| 1384 | − * sleeping AllocEv waiting */ | |
| 1385 | − | |
| 1386 | − /* allocate TX FIDs */ | |
| 1387 | − local->txfid_len = PRISM2_TXFID_LEN; | |
| 1388 | − for (i = 0; i < PRISM2_TXFID_COUNT; i++) { | |
| 1389 | − local->txfid[i] = hfa384x_allocate_fid(dev, local->txfid_len); | |
| 1390 | − if (local->txfid[i] == 0xffff && local->txfid_len > 1600) { | |
| 1391 | − local->txfid[i] = hfa384x_allocate_fid(dev, 1600); | |
| 1392 | − if (local->txfid[i] != 0xffff) { | |
| 1393 | − printk(KERN_DEBUG "%s: Using shorter TX FID " | |
| 1394 | − "(1600 bytes)\n", dev->name); | |
| 1395 | − local->txfid_len = 1600; | |
| 1396 | − } | |
| 1397 | − } | |
| 1398 | − if (local->txfid[i] == 0xffff) | |
| 1399 | − goto failed; | |
| 1400 | − local->intransmitfid[i] = PRISM2_TXFID_EMPTY; | |
| 1401 | − } | |
| 1402 | − | |
| 1403 | − hfa384x_events_only_cmd(dev); | |
| 1404 | − | |
| 1405 | − if (initial) { | |
| 1406 | − u8 addr[ETH_ALEN] = {}; | |
| 1407 | − struct list_head *ptr; | |
| 1408 | − | |
| 1409 | − prism2_check_sta_fw_version(local); | |
| 1410 | − | |
| 1411 | − if (hfa384x_get_rid(dev, HFA384X_RID_CNFOWNMACADDR, | |
| 1412 | − addr, ETH_ALEN, 1) < 0) { | |
| 1413 | − printk("%s: could not get own MAC address\n", | |
| 1414 | − dev->name); | |
| 1415 | − } | |
| 1416 | − eth_hw_addr_set(dev, addr); | |
| 1417 | − list_for_each(ptr, &local->hostap_interfaces) { | |
| 1418 | − iface = list_entry(ptr, struct hostap_interface, list); | |
| 1419 | − eth_hw_addr_inherit(iface->dev, dev); | |
| 1420 | − } | |
| 1421 | − } else if (local->fw_ap) | |
| 1422 | − prism2_check_sta_fw_version(local); | |
| 1423 | − | |
| 1424 | − prism2_setup_rids(dev); | |
| 1425 | − | |
| 1426 | − /* MAC is now configured, but port 0 is not yet enabled */ | |
| 1427 | − return 0; | |
| 1428 | − | |
| 1429 | − failed: | |
| 1430 | − if (!local->no_pri) | |
| 1431 | − printk(KERN_WARNING "%s: Initialization failed\n", dev_info); | |
| 1432 | − return 1; | |
| 1433 | −} | |
| 1434 | − | |
| 1435 | − | |
| 1436 | −static int prism2_hw_enable(struct net_device *dev, int initial) | |
| 1437 | −{ | |
| 1438 | − struct hostap_interface *iface; | |
| 1439 | − local_info_t *local; | |
| 1440 | − int was_resetting; | |
| 1441 | − | |
| 1442 | − iface = netdev_priv(dev); | |
| 1443 | − local = iface->local; | |
| 1444 | − was_resetting = local->hw_resetting; | |
| 1445 | − | |
| 1446 | − if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { | |
| 1447 | − printk("%s: MAC port 0 enabling failed\n", dev->name); | |
| 1448 | − return 1; | |
| 1449 | − } | |
| 1450 | − | |
| 1451 | − local->hw_ready = 1; | |
| 1452 | − local->hw_reset_tries = 0; | |
| 1453 | − local->hw_resetting = 0; | |
| 1454 | − hfa384x_enable_interrupts(dev); | |
| 1455 | − | |
| 1456 | − /* at least D-Link DWL-650 seems to require additional port reset | |
| 1457 | − * before it starts acting as an AP, so reset port automatically | |
| 1458 | − * here just in case */ | |
| 1459 | − if (initial && prism2_reset_port(dev)) { | |
| 1460 | − printk("%s: MAC port 0 resetting failed\n", dev->name); | |
| 1461 | − return 1; | |
| 1462 | − } | |
| 1463 | − | |
| 1464 | − if (was_resetting && netif_queue_stopped(dev)) { | |
| 1465 | − /* If hw_reset() was called during pending transmit, netif | |
| 1466 | − * queue was stopped. Wake it up now since the wlan card has | |
| 1467 | − * been resetted. */ | |
| 1468 | − netif_wake_queue(dev); | |
| 1469 | − } | |
| 1470 | − | |
| 1471 | − return 0; | |
| 1472 | −} | |
| 1473 | − | |
| 1474 | − | |
| 1475 | −static int prism2_hw_config(struct net_device *dev, int initial) | |
| 1476 | −{ | |
| 1477 | − struct hostap_interface *iface; | |
| 1478 | − local_info_t *local; | |
| 1479 | − | |
| 1480 | − iface = netdev_priv(dev); | |
| 1481 | − local = iface->local; | |
| 1482 | − | |
| 1483 | − if (local->hw_downloading) | |
| 1484 | − return 1; | |
| 1485 | − | |
| 1486 | − if (prism2_hw_init(dev, initial)) { | |
| 1487 | − return local->no_pri ? 0 : 1; | |
| 1488 | − } | |
| 1489 | − | |
| 1490 | − if (prism2_hw_init2(dev, initial)) | |
| 1491 | − return 1; | |
| 1492 | − | |
| 1493 | − /* Enable firmware if secondary image is loaded and at least one of the | |
| 1494 | − * netdevices is up. */ | |
| 1495 | − if (!local->pri_only && | |
| 1496 | − (initial == 0 || (initial == 2 && local->num_dev_open > 0))) { | |
| 1497 | − if (!local->dev_enabled) | |
| 1498 | − prism2_callback(local, PRISM2_CALLBACK_ENABLE); | |
| 1499 | − local->dev_enabled = 1; | |
| 1500 | − return prism2_hw_enable(dev, initial); | |
| 1501 | − } | |
| 1502 | − | |
| 1503 | − return 0; | |
| 1504 | −} | |
| 1505 | − | |
| 1506 | − | |
| 1507 | −static void prism2_hw_shutdown(struct net_device *dev, int no_disable) | |
| 1508 | −{ | |
| 1509 | − struct hostap_interface *iface; | |
| 1510 | − local_info_t *local; | |
| 1511 | − | |
| 1512 | − iface = netdev_priv(dev); | |
| 1513 | − local = iface->local; | |
| 1514 | − | |
| 1515 | − /* Allow only command completion events during disable */ | |
| 1516 | − hfa384x_events_only_cmd(dev); | |
| 1517 | − | |
| 1518 | − local->hw_ready = 0; | |
| 1519 | − if (local->dev_enabled) | |
| 1520 | − prism2_callback(local, PRISM2_CALLBACK_DISABLE); | |
| 1521 | − local->dev_enabled = 0; | |
| 1522 | − | |
| 1523 | − if (local->func->card_present && !local->func->card_present(local)) { | |
| 1524 | − printk(KERN_DEBUG "%s: card already removed or not configured " | |
| 1525 | − "during shutdown\n", dev->name); | |
| 1526 | − return; | |
| 1527 | − } | |
| 1528 | − | |
| 1529 | − if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && | |
| 1530 | − hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) | |
| 1531 | − printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); | |
| 1532 | − | |
| 1533 | − hfa384x_disable_interrupts(dev); | |
| 1534 | − | |
| 1535 | − if (no_disable & HOSTAP_HW_ENABLE_CMDCOMPL) | |
| 1536 | − hfa384x_events_only_cmd(dev); | |
| 1537 | − else | |
| 1538 | − prism2_clear_cmd_queue(local); | |
| 1539 | −} | |
| 1540 | − | |
| 1541 | − | |
| 1542 | −static void prism2_hw_reset(struct net_device *dev) | |
| 1543 | −{ | |
| 1544 | − struct hostap_interface *iface; | |
| 1545 | − local_info_t *local; | |
| 1546 | − | |
| 1547 | −#if 0 | |
| 1548 | − static long last_reset = 0; | |
| 1549 | − | |
| 1550 | − /* do not reset card more than once per second to avoid ending up in a | |
| 1551 | − * busy loop resetting the card */ | |
| 1552 | − if (time_before_eq(jiffies, last_reset + HZ)) | |
| 1553 | − return; | |
| 1554 | − last_reset = jiffies; | |
| 1555 | −#endif | |
| 1556 | − | |
| 1557 | − iface = netdev_priv(dev); | |
| 1558 | − local = iface->local; | |
| 1559 | − | |
| 1560 | − if (local->hw_downloading) | |
| 1561 | − return; | |
| 1562 | − | |
| 1563 | − if (local->hw_resetting) { | |
| 1564 | − printk(KERN_WARNING "%s: %s: already resetting card - " | |
| 1565 | − "ignoring reset request\n", dev_info, dev->name); | |
| 1566 | − return; | |
| 1567 | − } | |
| 1568 | − | |
| 1569 | − local->hw_reset_tries++; | |
| 1570 | − if (local->hw_reset_tries > 10) { | |
| 1571 | − printk(KERN_WARNING "%s: too many reset tries, skipping\n", | |
| 1572 | − dev->name); | |
| 1573 | − return; | |
| 1574 | − } | |
| 1575 | − | |
| 1576 | − printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); | |
| 1577 | − hfa384x_disable_interrupts(dev); | |
| 1578 | − local->hw_resetting = 1; | |
| 1579 | − if (local->func->cor_sreset) { | |
| 1580 | − /* Host system seems to hang in some cases with high traffic | |
| 1581 | − * load or shared interrupts during COR sreset. Disable shared | |
| 1582 | − * interrupts during reset to avoid these crashes. COS sreset | |
| 1583 | − * takes quite a long time, so it is unfortunate that this | |
| 1584 | − * seems to be needed. Anyway, I do not know of any better way | |
| 1585 | − * of avoiding the crash. */ | |
| 1586 | − disable_irq(dev->irq); | |
| 1587 | − local->func->cor_sreset(local); | |
| 1588 | − enable_irq(dev->irq); | |
| 1589 | − } | |
| 1590 | − prism2_hw_shutdown(dev, 1); | |
| 1591 | − prism2_hw_config(dev, 0); | |
| 1592 | − local->hw_resetting = 0; | |
| 1593 | − | |
| 1594 | −#ifdef PRISM2_DOWNLOAD_SUPPORT | |
| 1595 | − if (local->dl_pri) { | |
| 1596 | − printk(KERN_DEBUG "%s: persistent download of primary " | |
| 1597 | − "firmware\n", dev->name); | |
| 1598 | − if (prism2_download_genesis(local, local->dl_pri) < 0) | |
| 1599 | − printk(KERN_WARNING "%s: download (PRI) failed\n", | |
| 1600 | − dev->name); | |
| 1601 | − } | |
| 1602 | − | |
| 1603 | − if (local->dl_sec) { | |
| 1604 | − printk(KERN_DEBUG "%s: persistent download of secondary " | |
| 1605 | − "firmware\n", dev->name); | |
| 1606 | − if (prism2_download_volatile(local, local->dl_sec) < 0) | |
| 1607 | − printk(KERN_WARNING "%s: download (SEC) failed\n", | |
| 1608 | − dev->name); | |
| 1609 | − } | |
| 1610 | −#endif /* PRISM2_DOWNLOAD_SUPPORT */ | |
| 1611 | − | |
| 1612 | − /* TODO: restore beacon TIM bits for STAs that have buffered frames */ | |
| 1613 | −} | |
| 1614 | − | |
| 1615 | − | |
| 1616 | −static void prism2_schedule_reset(local_info_t *local) | |
| 1617 | −{ | |
| 1618 | − schedule_work(&local->reset_queue); | |
| 1619 | −} | |
| 1620 | − | |
| 1621 | − | |
| 1622 | −/* Called only as scheduled task after noticing card timeout in interrupt | |
| 1623 | − * context */ | |
| 1624 | −static void handle_reset_queue(struct work_struct *work) | |
| 1625 | −{ | |
| 1626 | − local_info_t *local = container_of(work, local_info_t, reset_queue); | |
| 1627 | − | |
| 1628 | − printk(KERN_DEBUG "%s: scheduled card reset\n", local->dev->name); | |
| 1629 | − prism2_hw_reset(local->dev); | |
| 1630 | − | |
| 1631 | − if (netif_queue_stopped(local->dev)) { | |
| 1632 | − int i; | |
| 1633 | − | |
| 1634 | − for (i = 0; i < PRISM2_TXFID_COUNT; i++) | |
| 1635 | − if (local->intransmitfid[i] == PRISM2_TXFID_EMPTY) { | |
| 1636 | − PDEBUG(DEBUG_EXTRA, "prism2_tx_timeout: " | |
| 1637 | − "wake up queue\n"); | |
| 1638 | − netif_wake_queue(local->dev); | |
| 1639 | − break; | |
| 1640 | − } | |
| 1641 | − } | |
| 1642 | −} | |
| 1643 | − | |
| 1644 | − | |
| 1645 | −static int prism2_get_txfid_idx(local_info_t *local) | |
| 1646 | −{ | |
| 1647 | − int idx, end; | |
| 1648 | − unsigned long flags; | |
| 1649 | − | |
| 1650 | − spin_lock_irqsave(&local->txfidlock, flags); | |
| 1651 | − end = idx = local->next_txfid; | |
| 1652 | − do { | |
| 1653 | − if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | |
| 1654 | − local->intransmitfid[idx] = PRISM2_TXFID_RESERVED; | |
| 1655 | − spin_unlock_irqrestore(&local->txfidlock, flags); | |
| 1656 | − return idx; | |
| 1657 | − } | |
| 1658 | − idx++; | |
| 1659 | − if (idx >= PRISM2_TXFID_COUNT) | |
| 1660 | − idx = 0; | |
| 1661 | − } while (idx != end); | |
| 1662 | − spin_unlock_irqrestore(&local->txfidlock, flags); | |
| 1663 | − | |
| 1664 | − PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: " | |
| 1665 | − "packet dropped\n"); | |
| 1666 | − local->dev->stats.tx_dropped++; | |
| 1667 | − | |
| 1668 | − return -1; | |
| 1669 | −} | |
| 1670 | − | |
| 1671 | − | |
| 1672 | −/* Called only from hardware IRQ */ | |
| 1673 | −static void prism2_transmit_cb(struct net_device *dev, long context, | |
| 1674 | − u16 resp0, u16 res) | |
| 1675 | −{ | |
| 1676 | − struct hostap_interface *iface; | |
| 1677 | − local_info_t *local; | |
| 1678 | − int idx = (int) context; | |
| 1679 | − | |
| 1680 | − iface = netdev_priv(dev); | |
| 1681 | − local = iface->local; | |
| 1682 | − | |
| 1683 | − if (res) { | |
| 1684 | − printk(KERN_DEBUG "%s: prism2_transmit_cb - res=0x%02x\n", | |
| 1685 | − dev->name, res); | |
| 1686 | − return; | |
| 1687 | − } | |
| 1688 | − | |
| 1689 | − if (idx < 0 || idx >= PRISM2_TXFID_COUNT) { | |
| 1690 | − printk(KERN_DEBUG "%s: prism2_transmit_cb called with invalid " | |
| 1691 | − "idx=%d\n", dev->name, idx); | |
| 1692 | − return; | |
| 1693 | − } | |
| 1694 | − | |
| 1695 | − if (!test_and_clear_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | |
| 1696 | − printk(KERN_DEBUG "%s: driver bug: prism2_transmit_cb called " | |
| 1697 | − "with no pending transmit\n", dev->name); | |
| 1698 | − } | |
| 1699 | − | |
| 1700 | − if (netif_queue_stopped(dev)) { | |
| 1701 | − /* ready for next TX, so wake up queue that was stopped in | |
| 1702 | − * prism2_transmit() */ | |
| 1703 | − netif_wake_queue(dev); | |
| 1704 | − } | |
| 1705 | − | |
| 1706 | − spin_lock(&local->txfidlock); | |
| 1707 | − | |
| 1708 | − /* With reclaim, Resp0 contains new txfid for transmit; the old txfid | |
| 1709 | − * will be automatically allocated for the next TX frame */ | |
| 1710 | − local->intransmitfid[idx] = resp0; | |
| 1711 | − | |
| 1712 | − PDEBUG(DEBUG_FID, "%s: prism2_transmit_cb: txfid[%d]=0x%04x, " | |
| 1713 | − "resp0=0x%04x, transmit_txfid=0x%04x\n", | |
| 1714 | − dev->name, idx, local->txfid[idx], | |
| 1715 | − resp0, local->intransmitfid[local->next_txfid]); | |
| 1716 | − | |
| 1717 | − idx++; | |
| 1718 | − if (idx >= PRISM2_TXFID_COUNT) | |
| 1719 | − idx = 0; | |
| 1720 | − local->next_txfid = idx; | |
| 1721 | − | |
| 1722 | − /* check if all TX buffers are occupied */ | |
| 1723 | − do { | |
| 1724 | − if (local->intransmitfid[idx] == PRISM2_TXFID_EMPTY) { | |
| 1725 | − spin_unlock(&local->txfidlock); | |
| 1726 | − return; | |
| 1727 | − } | |
| 1728 | − idx++; | |
| 1729 | − if (idx >= PRISM2_TXFID_COUNT) | |
| 1730 | − idx = 0; | |
| 1731 | − } while (idx != local->next_txfid); | |
| 1732 | − spin_unlock(&local->txfidlock); | |
| 1733 | − | |
| 1734 | − /* no empty TX buffers, stop queue */ | |
| 1735 | − netif_stop_queue(dev); | |
| 1736 | −} | |
| 1737 | − | |
| 1738 | − | |
| 1739 | −/* Called only from software IRQ if PCI bus master is not used (with bus master | |
| 1740 | − * this can be called both from software and hardware IRQ) */ | |
| 1741 | −static int prism2_transmit(struct net_device *dev, int idx) | |
| 1742 | −{ | |
| 1743 | − struct hostap_interface *iface; | |
| 1744 | − local_info_t *local; | |
| 1745 | − int res; | |
| 1746 | − | |
| 1747 | − iface = netdev_priv(dev); | |
| 1748 | − local = iface->local; | |
| 1749 | − | |
| 1750 | − /* The driver tries to stop netif queue so that there would not be | |
| 1751 | − * more than one attempt to transmit frames going on; check that this | |
| 1752 | − * is really the case */ | |
| 1753 | − | |
| 1754 | − if (test_and_set_bit(HOSTAP_BITS_TRANSMIT, &local->bits)) { | |
| 1755 | − printk(KERN_DEBUG "%s: driver bug - prism2_transmit() called " | |
| 1756 | − "when previous TX was pending\n", dev->name); | |
| 1757 | − return -1; | |
| 1758 | − } | |
| 1759 | − | |
| 1760 | − /* stop the queue for the time that transmit is pending */ | |
| 1761 | − netif_stop_queue(dev); | |
| 1762 | − | |
| 1763 | − /* transmit packet */ | |
| 1764 | − res = hfa384x_cmd_callback( | |
| 1765 | − dev, | |
| 1766 | − HFA384X_CMDCODE_TRANSMIT | HFA384X_CMD_TX_RECLAIM, | |
| 1767 | − local->txfid[idx], | |
| 1768 | − prism2_transmit_cb, (long) idx); | |
| 1769 | − | |
| 1770 | − if (res) { | |
| 1771 | − printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT " | |
| 1772 | − "failed (res=%d)\n", dev->name, res); | |
| 1773 | − dev->stats.tx_dropped++; | |
| 1774 | − netif_wake_queue(dev); | |
| 1775 | − return -1; | |
| 1776 | − } | |
| 1777 | − netif_trans_update(dev); | |
| 1778 | − | |
| 1779 | − /* Since we did not wait for command completion, the card continues | |
| 1780 | − * to process on the background and we will finish handling when | |
| 1781 | − * command completion event is handled (prism2_cmd_ev() function) */ | |
| 1782 | − | |
| 1783 | − return 0; | |
| 1784 | −} | |
| 1785 | − | |
| 1786 | − | |
| 1787 | −/* Send IEEE 802.11 frame (convert the header into Prism2 TX descriptor and | |
| 1788 | − * send the payload with this descriptor) */ | |
| 1789 | −/* Called only from software IRQ */ | |
| 1790 | −static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) | |
| 1791 | −{ | |
| 1792 | − struct hostap_interface *iface; | |
| 1793 | − local_info_t *local; | |
| 1794 | − struct hfa384x_tx_frame txdesc; | |
| 1795 | − struct hostap_skb_tx_data *meta; | |
| 1796 | − int hdr_len, data_len, idx, res, ret = -1; | |
| 1797 | − u16 tx_control; | |
| 1798 | − | |
| 1799 | − iface = netdev_priv(dev); | |
| 1800 | − local = iface->local; | |
| 1801 | − | |
| 1802 | − meta = (struct hostap_skb_tx_data *) skb->cb; | |
| 1803 | − | |
| 1804 | − prism2_callback(local, PRISM2_CALLBACK_TX_START); | |
| 1805 | − | |
| 1806 | − if ((local->func->card_present && !local->func->card_present(local)) || | |
| 1807 | − !local->hw_ready || local->hw_downloading || local->pri_only) { | |
| 1808 | − if (net_ratelimit()) { | |
| 1809 | − printk(KERN_DEBUG "%s: prism2_tx_80211: hw not ready -" | |
| 1810 | − " skipping\n", dev->name); | |
| 1811 | − } | |
| 1812 | − goto fail; | |
| 1813 | − } | |
| 1814 | − | |
| 1815 | − memset(&txdesc, 0, sizeof(txdesc)); | |
| 1816 | − | |
| 1817 | − /* skb->data starts with txdesc->frame_control */ | |
| 1818 | − hdr_len = sizeof(txdesc.header); | |
| 1819 | − BUILD_BUG_ON(hdr_len != 24); | |
| 1820 | − skb_copy_from_linear_data(skb, &txdesc.header, hdr_len); | |
| 1821 | − if (ieee80211_is_data(txdesc.frame_control) && | |
| 1822 | − ieee80211_has_a4(txdesc.frame_control) && | |
| 1823 | − skb->len >= 30) { | |
| 1824 | − /* Addr4 */ | |
| 1825 | − skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4, | |
| 1826 | − ETH_ALEN); | |
| 1827 | − hdr_len += ETH_ALEN; | |
| 1828 | − } | |
| 1829 | − | |
| 1830 | − tx_control = local->tx_control; | |
| 1831 | − if (meta->tx_cb_idx) { | |
| 1832 | − tx_control |= HFA384X_TX_CTRL_TX_OK; | |
| 1833 | − txdesc.sw_support = cpu_to_le32(meta->tx_cb_idx); | |
| 1834 | − } | |
| 1835 | − txdesc.tx_control = cpu_to_le16(tx_control); | |
| 1836 | − txdesc.tx_rate = meta->rate; | |
| 1837 | − | |
| 1838 | − data_len = skb->len - hdr_len; | |
| 1839 | − txdesc.data_len = cpu_to_le16(data_len); | |
| 1840 | − txdesc.len = cpu_to_be16(data_len); | |
| 1841 | − | |
| 1842 | − idx = prism2_get_txfid_idx(local); | |
| 1843 | − if (idx < 0) | |
| 1844 | − goto fail; | |
| 1845 | − | |
| 1846 | − if (local->frame_dump & PRISM2_DUMP_TX_HDR) | |
| 1847 | − hostap_dump_tx_header(dev->name, &txdesc); | |
| 1848 | − | |
| 1849 | − spin_lock(&local->baplock); | |
| 1850 | − res = hfa384x_setup_bap(dev, BAP0, local->txfid[idx], 0); | |
| 1851 | − | |
| 1852 | − if (!res) | |
| 1853 | − res = hfa384x_to_bap(dev, BAP0, &txdesc, sizeof(txdesc)); | |
| 1854 | − if (!res) | |
| 1855 | − res = hfa384x_to_bap(dev, BAP0, skb->data + hdr_len, | |
| 1856 | − skb->len - hdr_len); | |
| 1857 | − spin_unlock(&local->baplock); | |
| 1858 | − | |
| 1859 | − if (!res) | |
| 1860 | − res = prism2_transmit(dev, idx); | |
| 1861 | − if (res) { | |
| 1862 | − printk(KERN_DEBUG "%s: prism2_tx_80211 - to BAP0 failed\n", | |
| 1863 | − dev->name); | |
| 1864 | − local->intransmitfid[idx] = PRISM2_TXFID_EMPTY; | |
| 1865 | − schedule_work(&local->reset_queue); | |
| 1866 | − goto fail; | |
| 1867 | − } | |
| 1868 | − | |
| 1869 | − ret = 0; | |
| 1870 | − | |
| 1871 | −fail: | |
| 1872 | − prism2_callback(local, PRISM2_CALLBACK_TX_END); | |
| 1873 | − return ret; | |
| 1874 | −} | |
| 1875 | − | |
| 1876 | − | |
| 1877 | −/* Some SMP systems have reported number of odd errors with hostap_pci. fid | |
| 1878 | − * register has changed values between consecutive reads for an unknown reason. | |
| 1879 | − * This should really not happen, so more debugging is needed. This test | |
| 1880 | − * version is a bit slower, but it will detect most of such register changes | |
| 1881 | − * and will try to get the correct fid eventually. */ | |
| 1882 | −#define EXTRA_FID_READ_TESTS | |
| 1883 | − | |
| 1884 | −static u16 prism2_read_fid_reg(struct net_device *dev, u16 reg) | |
| 1885 | −{ | |
| 1886 | −#ifdef EXTRA_FID_READ_TESTS | |
| 1887 | − u16 val, val2, val3; | |
| 1888 | − int i; | |
| 1889 | − | |
| 1890 | − for (i = 0; i < 10; i++) { | |
| 1891 | − val = HFA384X_INW(reg); | |
| 1892 | − val2 = HFA384X_INW(reg); | |
| 1893 | − val3 = HFA384X_INW(reg); | |
| 1894 | − | |
| 1895 | − if (val == val2 && val == val3) | |
| 1896 | − return val; | |
| 1897 | − | |
1490 more lines aren’t shown here.
This diff is large: its 510 lines aren’t shown here.
This diff is large: its 3848 lines aren’t shown here.
This diff is large: its 1124 lines aren’t shown here.
This diff is large: its 446 lines aren’t shown here.
This diff is large: its 618 lines aren’t shown here.
This diff is large: its 412 lines aren’t shown here.
This diff is large: its 1052 lines aren’t shown here.
This diff is large: its 144 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 269 lines aren’t shown here.
This diff is large: its 292 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 388 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 779 lines aren’t shown here.
This diff is large: its 535 lines aren’t shown here.
This diff is large: its 478 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 1363 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 2415 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 90 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 252 lines aren’t shown here.
This diff is large: its 351 lines aren’t shown here.
This diff is large: its 315 lines aren’t shown here.
This diff is large: its 258 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 363 lines aren’t shown here.
This diff is large: its 238 lines aren’t shown here.
This diff is large: its 1788 lines aren’t shown here.
This diff is large: its 260 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 329 lines aren’t shown here.
This diff is large: its 1429 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 2825 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 735 lines aren’t shown here.
This diff is large: its 3761 lines aren’t shown here.
This diff is large: its 616 lines aren’t shown here.
This diff is large: its 2037 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 958 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 181 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 421 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 665 lines aren’t shown here.
This diff is large: its 631 lines aren’t shown here.
This diff is large: its 510 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 507 lines aren’t shown here.
This diff is large: its 270 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 364 lines aren’t shown here.
This diff is large: its 74 lines aren’t shown here.
This diff is large: its 89 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 1910 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 69 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.