[PATCH 10/10] [RFC] wifi: remove ipw2100/ipw2200 drivers
Arnd Bergmann
arnd at kernel.org
Tue Oct 24 00:19:52 AEDT 2023
From: Arnd Bergmann <arnd at arndb.de>
These two drivers were used for the earliest "Centrino" branded Intel
laptops during the late 32-bit Pentium-M era, roughly 2003 to 2005, which
probably makes it the most modern platform that still uses the wireless
extension interface instead of cfg80211. Unlike the other drivers that
are suggested for removal, this one is still officially maintained.
According to Johannes Berg, there was an effort to finish the move away
from wext in the past, but the last evidence of this that I could find
is from commit a3caa99e6c68f ("libipw: initiate cfg80211 API conversion
(v2)") in 2009.
Link: https://lore.kernel.org/all/87fs2fgals.fsf@kernel.org/
Cc: Stanislav Yakovlev <stas.yakovlev at gmail.com>
Cc: Linux Wireless <ilw at linux.intel.com>
Signed-off-by: Arnd Bergmann <arnd at arndb.de>
---
I'm not convinced this should be in the same set of drivers as the
rest, since this is clearly less obsolete than the other hardware
that I would remove support for.
---
.../networking/device_drivers/wifi/index.rst | 19 -
.../device_drivers/wifi/intel/ipw2100.rst | 323 -
.../device_drivers/wifi/intel/ipw2200.rst | 526 -
MAINTAINERS | 8 -
drivers/net/wireless/intel/Kconfig | 1 -
drivers/net/wireless/intel/Makefile | 3 -
drivers/net/wireless/intel/ipw2x00/Kconfig | 195 -
drivers/net/wireless/intel/ipw2x00/Makefile | 15 -
drivers/net/wireless/intel/ipw2x00/ipw.h | 20 -
drivers/net/wireless/intel/ipw2x00/ipw2100.c | 8587 -----------
drivers/net/wireless/intel/ipw2x00/ipw2100.h | 1142 --
drivers/net/wireless/intel/ipw2x00/ipw2200.c | 11965 ----------------
drivers/net/wireless/intel/ipw2x00/ipw2200.h | 1984 ---
drivers/net/wireless/intel/ipw2x00/libipw.h | 1001 --
.../net/wireless/intel/ipw2x00/libipw_geo.c | 179 -
.../wireless/intel/ipw2x00/libipw_module.c | 297 -
.../net/wireless/intel/ipw2x00/libipw_rx.c | 1737 ---
.../net/wireless/intel/ipw2x00/libipw_tx.c | 519 -
.../net/wireless/intel/ipw2x00/libipw_wx.c | 726 -
19 files changed, 29247 deletions(-)
delete mode 100644 Documentation/networking/device_drivers/wifi/index.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
delete mode 100644 Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Kconfig
delete mode 100644 drivers/net/wireless/intel/ipw2x00/Makefile
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2100.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/ipw2200.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw.h
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_geo.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_module.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_rx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_tx.c
delete mode 100644 drivers/net/wireless/intel/ipw2x00/libipw_wx.c
diff --git a/Documentation/networking/device_drivers/wifi/index.rst b/Documentation/networking/device_drivers/wifi/index.rst
deleted file mode 100644
index fb394f5de4a94..0000000000000
--- a/Documentation/networking/device_drivers/wifi/index.rst
+++ /dev/null
@@ -1,19 +0,0 @@
-.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-
-Wi-Fi Device Drivers
-====================
-
-Contents:
-
-.. toctree::
- :maxdepth: 2
-
- intel/ipw2100
- intel/ipw2200
-
-.. only:: subproject and html
-
- Indices
- =======
-
- * :ref:`genindex`
diff --git a/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst b/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
deleted file mode 100644
index 883e963557992..0000000000000
--- a/Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
+++ /dev/null
@@ -1,323 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-===========================================
-Intel(R) PRO/Wireless 2100 Driver for Linux
-===========================================
-
-Support for:
-
-- Intel(R) PRO/Wireless 2100 Network Connection
-
-Copyright |copy| 2003-2006, Intel Corporation
-
-README.ipw2100
-
-:Version: git-1.1.5
-:Date: January 25, 2006
-
-.. Index
-
- 0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
- 1. Introduction
- 2. Release git-1.1.5 Current Features
- 3. Command Line Parameters
- 4. Sysfs Helper Files
- 5. Radio Kill Switch
- 6. Dynamic Firmware
- 7. Power Management
- 8. Support
- 9. License
-
-
-0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
-=================================================
-
-Important Notice FOR ALL USERS OR DISTRIBUTORS!!!!
-
-Intel wireless LAN adapters are engineered, manufactured, tested, and
-quality checked to ensure that they meet all necessary local and
-governmental regulatory agency requirements for the regions that they
-are designated and/or marked to ship into. Since wireless LANs are
-generally unlicensed devices that share spectrum with radars,
-satellites, and other licensed and unlicensed devices, it is sometimes
-necessary to dynamically detect, avoid, and limit usage to avoid
-interference with these devices. In many instances Intel is required to
-provide test data to prove regional and local compliance to regional and
-governmental regulations before certification or approval to use the
-product is granted. Intel's wireless LAN's EEPROM, firmware, and
-software driver are designed to carefully control parameters that affect
-radio operation and to ensure electromagnetic compliance (EMC). These
-parameters include, without limitation, RF power, spectrum usage,
-channel scanning, and human exposure.
-
-For these reasons Intel cannot permit any manipulation by third parties
-of the software provided in binary format with the wireless WLAN
-adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
-patches, utilities, or code with the Intel wireless LAN adapters that
-have been manipulated by an unauthorized party (i.e., patches,
-utilities, or code (including open source code modifications) which have
-not been validated by Intel), (i) you will be solely responsible for
-ensuring the regulatory compliance of the products, (ii) Intel will bear
-no liability, under any theory of liability for any issues associated
-with the modified products, including without limitation, claims under
-the warranty and/or issues arising from regulatory non-compliance, and
-(iii) Intel will not provide or be required to assist in providing
-support to any third parties for such modified products.
-
-Note: Many regulatory agencies consider Wireless LAN adapters to be
-modules, and accordingly, condition system-level regulatory approval
-upon receipt and review of test data documenting that the antennas and
-system configuration do not cause the EMC and radio operation to be
-non-compliant.
-
-The drivers available for download from SourceForge are provided as a
-part of a development project. Conformance to local regulatory
-requirements is the responsibility of the individual developer. As
-such, if you are interested in deploying or shipping a driver as part of
-solution intended to be used for purposes other than development, please
-obtain a tested driver from Intel Customer Support at:
-
-https://www.intel.com/support/wireless/sb/CS-006408.htm
-
-1. Introduction
-===============
-
-This document provides a brief overview of the features supported by the
-IPW2100 driver project. The main project website, where the latest
-development version of the driver can be found, is:
-
- http://ipw2100.sourceforge.net
-
-There you can find the not only the latest releases, but also information about
-potential fixes and patches, as well as links to the development mailing list
-for the driver project.
-
-
-2. Release git-1.1.5 Current Supported Features
-===============================================
-
-- Managed (BSS) and Ad-Hoc (IBSS)
-- WEP (shared key and open)
-- Wireless Tools support
-- 802.1x (tested with XSupplicant 1.0.1)
-
-Enabled (but not supported) features:
-- Monitor/RFMon mode
-- WPA/WPA2
-
-The distinction between officially supported and enabled is a reflection
-on the amount of validation and interoperability testing that has been
-performed on a given feature.
-
-
-3. Command Line Parameters
-==========================
-
-If the driver is built as a module, the following optional parameters are used
-by entering them on the command line with the modprobe command using this
-syntax::
-
- modprobe ipw2100 [<option>=<VAL1><,VAL2>...]
-
-For example, to disable the radio on driver loading, enter:
-
- modprobe ipw2100 disable=1
-
-The ipw2100 driver supports the following module parameters:
-
-========= ============== ============ ==============================
-Name Value Example Meaning
-========= ============== ============ ==============================
-debug 0x0-0xffffffff debug=1024 Debug level set to 1024
-mode 0,1,2 mode=1 AdHoc
-channel int channel=3 Only valid in AdHoc or Monitor
-associate boolean associate=0 Do NOT auto associate
-disable boolean disable=1 Do not power the HW
-========= ============== ============ ==============================
-
-
-4. Sysfs Helper Files
-=====================
-
-There are several ways to control the behavior of the driver. Many of the
-general capabilities are exposed through the Wireless Tools (iwconfig). There
-are a few capabilities that are exposed through entries in the Linux Sysfs.
-
-
-**Driver Level**
-
-For the driver level files, look in /sys/bus/pci/drivers/ipw2100/
-
- debug_level
- This controls the same global as the 'debug' module parameter. For
- information on the various debugging levels available, run the 'dvals'
- script found in the driver source directory.
-
- .. note::
-
- 'debug_level' is only enabled if CONFIG_IPW2100_DEBUG is turn on.
-
-**Device Level**
-
-For the device level files look in::
-
- /sys/bus/pci/drivers/ipw2100/{PCI-ID}/
-
-For example::
-
- /sys/bus/pci/drivers/ipw2100/0000:02:01.0
-
-For the device level files, see /sys/bus/pci/drivers/ipw2100:
-
- rf_kill
- read
-
- == =========================================
- 0 RF kill not enabled (radio on)
- 1 SW based RF kill active (radio off)
- 2 HW based RF kill active (radio off)
- 3 Both HW and SW RF kill active (radio off)
- == =========================================
-
- write
-
- == ==================================================
- 0 If SW based RF kill active, turn the radio back on
- 1 If radio is on, activate SW based RF kill
- == ==================================================
-
- .. note::
-
- If you enable the SW based RF kill and then toggle the HW
- based RF kill from ON -> OFF -> ON, the radio will NOT come back on
-
-
-5. Radio Kill Switch
-====================
-
-Most laptops provide the ability for the user to physically disable the radio.
-Some vendors have implemented this as a physical switch that requires no
-software to turn the radio off and on. On other laptops, however, the switch
-is controlled through a button being pressed and a software driver then making
-calls to turn the radio off and on. This is referred to as a "software based
-RF kill switch"
-
-See the Sysfs helper file 'rf_kill' for determining the state of the RF switch
-on your system.
-
-
-6. Dynamic Firmware
-===================
-
-As the firmware is licensed under a restricted use license, it can not be
-included within the kernel sources. To enable the IPW2100 you will need a
-firmware image to load into the wireless NIC's processors.
-
-You can obtain these images from <http://ipw2100.sf.net/firmware.php>.
-
-See INSTALL for instructions on installing the firmware.
-
-
-7. Power Management
-===================
-
-The IPW2100 supports the configuration of the Power Save Protocol
-through a private wireless extension interface. The IPW2100 supports
-the following different modes:
-
- === ===========================================================
- off No power management. Radio is always on.
- on Automatic power management
- 1-5 Different levels of power management. The higher the
- number the greater the power savings, but with an impact to
- packet latencies.
- === ===========================================================
-
-Power management works by powering down the radio after a certain
-interval of time has passed where no packets are passed through the
-radio. Once powered down, the radio remains in that state for a given
-period of time. For higher power savings, the interval between last
-packet processed to sleep is shorter and the sleep period is longer.
-
-When the radio is asleep, the access point sending data to the station
-must buffer packets at the AP until the station wakes up and requests
-any buffered packets. If you have an AP that does not correctly support
-the PSP protocol you may experience packet loss or very poor performance
-while power management is enabled. If this is the case, you will need
-to try and find a firmware update for your AP, or disable power
-management (via ``iwconfig eth1 power off``)
-
-To configure the power level on the IPW2100 you use a combination of
-iwconfig and iwpriv. iwconfig is used to turn power management on, off,
-and set it to auto.
-
- ========================= ====================================
- iwconfig eth1 power off Disables radio power down
- iwconfig eth1 power on Enables radio power management to
- last set level (defaults to AUTO)
- iwpriv eth1 set_power 0 Sets power level to AUTO and enables
- power management if not previously
- enabled.
- iwpriv eth1 set_power 1-5 Set the power level as specified,
- enabling power management if not
- previously enabled.
- ========================= ====================================
-
-You can view the current power level setting via::
-
- iwpriv eth1 get_power
-
-It will return the current period or timeout that is configured as a string
-in the form of xxxx/yyyy (z) where xxxx is the timeout interval (amount of
-time after packet processing), yyyy is the period to sleep (amount of time to
-wait before powering the radio and querying the access point for buffered
-packets), and z is the 'power level'. If power management is turned off the
-xxxx/yyyy will be replaced with 'off' -- the level reported will be the active
-level if `iwconfig eth1 power on` is invoked.
-
-
-8. Support
-==========
-
-For general development information and support,
-go to:
-
- http://ipw2100.sf.net/
-
-The ipw2100 1.1.0 driver and firmware can be downloaded from:
-
- http://support.intel.com
-
-For installation support on the ipw2100 1.1.0 driver on Linux kernels
-2.6.8 or greater, email support is available from:
-
- http://supportmail.intel.com
-
-9. License
-==========
-
- Copyright |copy| 2003 - 2006 Intel Corporation. All rights reserved.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License (version 2) as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- License Contact Information:
-
- James P. Ketrenos <ipw2100-admin at linux.intel.com>
-
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
diff --git a/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst b/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
deleted file mode 100644
index 0cb42d2fd7e5f..0000000000000
--- a/Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
+++ /dev/null
@@ -1,526 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-.. include:: <isonum.txt>
-
-==============================================
-Intel(R) PRO/Wireless 2915ABG Driver for Linux
-==============================================
-
-
-Support for:
-
-- Intel(R) PRO/Wireless 2200BG Network Connection
-- Intel(R) PRO/Wireless 2915ABG Network Connection
-
-Note: The Intel(R) PRO/Wireless 2915ABG Driver for Linux and Intel(R)
-PRO/Wireless 2200BG Driver for Linux is a unified driver that works on
-both hardware adapters listed above. In this document the Intel(R)
-PRO/Wireless 2915ABG Driver for Linux will be used to reference the
-unified driver.
-
-Copyright |copy| 2004-2006, Intel Corporation
-
-README.ipw2200
-
-:Version: 1.1.2
-:Date: March 30, 2006
-
-
-.. Index
-
- 0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
- 1. Introduction
- 1.1. Overview of features
- 1.2. Module parameters
- 1.3. Wireless Extension Private Methods
- 1.4. Sysfs Helper Files
- 1.5. Supported channels
- 2. Ad-Hoc Networking
- 3. Interacting with Wireless Tools
- 3.1. iwconfig mode
- 3.2. iwconfig sens
- 4. About the Version Numbers
- 5. Firmware installation
- 6. Support
- 7. License
-
-
-0. IMPORTANT INFORMATION BEFORE USING THIS DRIVER
-=================================================
-
-Important Notice FOR ALL USERS OR DISTRIBUTORS!!!!
-
-Intel wireless LAN adapters are engineered, manufactured, tested, and
-quality checked to ensure that they meet all necessary local and
-governmental regulatory agency requirements for the regions that they
-are designated and/or marked to ship into. Since wireless LANs are
-generally unlicensed devices that share spectrum with radars,
-satellites, and other licensed and unlicensed devices, it is sometimes
-necessary to dynamically detect, avoid, and limit usage to avoid
-interference with these devices. In many instances Intel is required to
-provide test data to prove regional and local compliance to regional and
-governmental regulations before certification or approval to use the
-product is granted. Intel's wireless LAN's EEPROM, firmware, and
-software driver are designed to carefully control parameters that affect
-radio operation and to ensure electromagnetic compliance (EMC). These
-parameters include, without limitation, RF power, spectrum usage,
-channel scanning, and human exposure.
-
-For these reasons Intel cannot permit any manipulation by third parties
-of the software provided in binary format with the wireless WLAN
-adapters (e.g., the EEPROM and firmware). Furthermore, if you use any
-patches, utilities, or code with the Intel wireless LAN adapters that
-have been manipulated by an unauthorized party (i.e., patches,
-utilities, or code (including open source code modifications) which have
-not been validated by Intel), (i) you will be solely responsible for
-ensuring the regulatory compliance of the products, (ii) Intel will bear
-no liability, under any theory of liability for any issues associated
-with the modified products, including without limitation, claims under
-the warranty and/or issues arising from regulatory non-compliance, and
-(iii) Intel will not provide or be required to assist in providing
-support to any third parties for such modified products.
-
-Note: Many regulatory agencies consider Wireless LAN adapters to be
-modules, and accordingly, condition system-level regulatory approval
-upon receipt and review of test data documenting that the antennas and
-system configuration do not cause the EMC and radio operation to be
-non-compliant.
-
-The drivers available for download from SourceForge are provided as a
-part of a development project. Conformance to local regulatory
-requirements is the responsibility of the individual developer. As
-such, if you are interested in deploying or shipping a driver as part of
-solution intended to be used for purposes other than development, please
-obtain a tested driver from Intel Customer Support at:
-
-http://support.intel.com
-
-
-1. Introduction
-===============
-
-The following sections attempt to provide a brief introduction to using
-the Intel(R) PRO/Wireless 2915ABG Driver for Linux.
-
-This document is not meant to be a comprehensive manual on
-understanding or using wireless technologies, but should be sufficient
-to get you moving without wires on Linux.
-
-For information on building and installing the driver, see the INSTALL
-file.
-
-
-1.1. Overview of Features
--------------------------
-The current release (1.1.2) supports the following features:
-
-+ BSS mode (Infrastructure, Managed)
-+ IBSS mode (Ad-Hoc)
-+ WEP (OPEN and SHARED KEY mode)
-+ 802.1x EAP via wpa_supplicant and xsupplicant
-+ Wireless Extension support
-+ Full B and G rate support (2200 and 2915)
-+ Full A rate support (2915 only)
-+ Transmit power control
-+ S state support (ACPI suspend/resume)
-
-The following features are currently enabled, but not officially
-supported:
-
-+ WPA
-+ long/short preamble support
-+ Monitor mode (aka RFMon)
-
-The distinction between officially supported and enabled is a reflection
-on the amount of validation and interoperability testing that has been
-performed on a given feature.
-
-
-
-1.2. Command Line Parameters
-----------------------------
-
-Like many modules used in the Linux kernel, the Intel(R) PRO/Wireless
-2915ABG Driver for Linux allows configuration options to be provided
-as module parameters. The most common way to specify a module parameter
-is via the command line.
-
-The general form is::
-
- % modprobe ipw2200 parameter=value
-
-Where the supported parameter are:
-
- associate
- Set to 0 to disable the auto scan-and-associate functionality of the
- driver. If disabled, the driver will not attempt to scan
- for and associate to a network until it has been configured with
- one or more properties for the target network, for example configuring
- the network SSID. Default is 0 (do not auto-associate)
-
- Example: % modprobe ipw2200 associate=0
-
- auto_create
- Set to 0 to disable the auto creation of an Ad-Hoc network
- matching the channel and network name parameters provided.
- Default is 1.
-
- channel
- channel number for association. The normal method for setting
- the channel would be to use the standard wireless tools
- (i.e. `iwconfig eth1 channel 10`), but it is useful sometimes
- to set this while debugging. Channel 0 means 'ANY'
-
- debug
- If using a debug build, this is used to control the amount of debug
- info is logged. See the 'dvals' and 'load' script for more info on
- how to use this (the dvals and load scripts are provided as part
- of the ipw2200 development snapshot releases available from the
- SourceForge project at http://ipw2200.sf.net)
-
- led
- Can be used to turn on experimental LED code.
- 0 = Off, 1 = On. Default is 1.
-
- mode
- Can be used to set the default mode of the adapter.
- 0 = Managed, 1 = Ad-Hoc, 2 = Monitor
-
-
-1.3. Wireless Extension Private Methods
----------------------------------------
-
-As an interface designed to handle generic hardware, there are certain
-capabilities not exposed through the normal Wireless Tool interface. As
-such, a provision is provided for a driver to declare custom, or
-private, methods. The Intel(R) PRO/Wireless 2915ABG Driver for Linux
-defines several of these to configure various settings.
-
-The general form of using the private wireless methods is::
-
- % iwpriv $IFNAME method parameters
-
-Where $IFNAME is the interface name the device is registered with
-(typically eth1, customized via one of the various network interface
-name managers, such as ifrename)
-
-The supported private methods are:
-
- get_mode
- Can be used to report out which IEEE mode the driver is
- configured to support. Example:
-
- % iwpriv eth1 get_mode
- eth1 get_mode:802.11bg (6)
-
- set_mode
- Can be used to configure which IEEE mode the driver will
- support.
-
- Usage::
-
- % iwpriv eth1 set_mode {mode}
-
- Where {mode} is a number in the range 1-7:
-
- == =====================
- 1 802.11a (2915 only)
- 2 802.11b
- 3 802.11ab (2915 only)
- 4 802.11g
- 5 802.11ag (2915 only)
- 6 802.11bg
- 7 802.11abg (2915 only)
- == =====================
-
- get_preamble
- Can be used to report configuration of preamble length.
-
- set_preamble
- Can be used to set the configuration of preamble length:
-
- Usage::
-
- % iwpriv eth1 set_preamble {mode}
-
- Where {mode} is one of:
-
- == ========================================
- 1 Long preamble only
- 0 Auto (long or short based on connection)
- == ========================================
-
-
-1.4. Sysfs Helper Files
------------------------
-
-The Linux kernel provides a pseudo file system that can be used to
-access various components of the operating system. The Intel(R)
-PRO/Wireless 2915ABG Driver for Linux exposes several configuration
-parameters through this mechanism.
-
-An entry in the sysfs can support reading and/or writing. You can
-typically query the contents of a sysfs entry through the use of cat,
-and can set the contents via echo. For example::
-
- % cat /sys/bus/pci/drivers/ipw2200/debug_level
-
-Will report the current debug level of the driver's logging subsystem
-(only available if CONFIG_IPW2200_DEBUG was configured when the driver
-was built).
-
-You can set the debug level via::
-
- % echo $VALUE > /sys/bus/pci/drivers/ipw2200/debug_level
-
-Where $VALUE would be a number in the case of this sysfs entry. The
-input to sysfs files does not have to be a number. For example, the
-firmware loader used by hotplug utilizes sysfs entries for transferring
-the firmware image from user space into the driver.
-
-The Intel(R) PRO/Wireless 2915ABG Driver for Linux exposes sysfs entries
-at two levels -- driver level, which apply to all instances of the driver
-(in the event that there are more than one device installed) and device
-level, which applies only to the single specific instance.
-
-
-1.4.1 Driver Level Sysfs Helper Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-For the driver level files, look in /sys/bus/pci/drivers/ipw2200/
-
- debug_level
- This controls the same global as the 'debug' module parameter
-
-
-
-1.4.2 Device Level Sysfs Helper Files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-For the device level files, look in::
-
- /sys/bus/pci/drivers/ipw2200/{PCI-ID}/
-
-For example:::
-
- /sys/bus/pci/drivers/ipw2200/0000:02:01.0
-
-For the device level files, see /sys/bus/pci/drivers/ipw2200:
-
- rf_kill
- read -
-
- == =========================================
- 0 RF kill not enabled (radio on)
- 1 SW based RF kill active (radio off)
- 2 HW based RF kill active (radio off)
- 3 Both HW and SW RF kill active (radio off)
- == =========================================
-
- write -
-
- == ==================================================
- 0 If SW based RF kill active, turn the radio back on
- 1 If radio is on, activate SW based RF kill
- == ==================================================
-
- .. note::
-
- If you enable the SW based RF kill and then toggle the HW
- based RF kill from ON -> OFF -> ON, the radio will NOT come back on
-
- ucode
- read-only access to the ucode version number
-
- led
- read -
-
- == =================
- 0 LED code disabled
- 1 LED code enabled
- == =================
-
- write -
-
- == ================
- 0 Disable LED code
- 1 Enable LED code
- == ================
-
-
- .. note::
-
- The LED code has been reported to hang some systems when
- running ifconfig and is therefore disabled by default.
-
-
-1.5. Supported channels
------------------------
-
-Upon loading the Intel(R) PRO/Wireless 2915ABG Driver for Linux, a
-message stating the detected geography code and the number of 802.11
-channels supported by the card will be displayed in the log.
-
-The geography code corresponds to a regulatory domain as shown in the
-table below.
-
- +------+----------------------------+--------------------+
- | | | Supported channels |
- | Code | Geography +----------+---------+
- | | | 802.11bg | 802.11a |
- +======+============================+==========+=========+
- | --- | Restricted | 11 | 0 |
- +------+----------------------------+----------+---------+
- | ZZF | Custom US/Canada | 11 | 8 |
- +------+----------------------------+----------+---------+
- | ZZD | Rest of World | 13 | 0 |
- +------+----------------------------+----------+---------+
- | ZZA | Custom USA & Europe & High | 11 | 13 |
- +------+----------------------------+----------+---------+
- | ZZB | Custom NA & Europe | 11 | 13 |
- +------+----------------------------+----------+---------+
- | ZZC | Custom Japan | 11 | 4 |
- +------+----------------------------+----------+---------+
- | ZZM | Custom | 11 | 0 |
- +------+----------------------------+----------+---------+
- | ZZE | Europe | 13 | 19 |
- +------+----------------------------+----------+---------+
- | ZZJ | Custom Japan | 14 | 4 |
- +------+----------------------------+----------+---------+
- | ZZR | Rest of World | 14 | 0 |
- +------+----------------------------+----------+---------+
- | ZZH | High Band | 13 | 4 |
- +------+----------------------------+----------+---------+
- | ZZG | Custom Europe | 13 | 4 |
- +------+----------------------------+----------+---------+
- | ZZK | Europe | 13 | 24 |
- +------+----------------------------+----------+---------+
- | ZZL | Europe | 11 | 13 |
- +------+----------------------------+----------+---------+
-
-2. Ad-Hoc Networking
-=====================
-
-When using a device in an Ad-Hoc network, it is useful to understand the
-sequence and requirements for the driver to be able to create, join, or
-merge networks.
-
-The following attempts to provide enough information so that you can
-have a consistent experience while using the driver as a member of an
-Ad-Hoc network.
-
-2.1. Joining an Ad-Hoc Network
-------------------------------
-
-The easiest way to get onto an Ad-Hoc network is to join one that
-already exists.
-
-2.2. Creating an Ad-Hoc Network
--------------------------------
-
-An Ad-Hoc networks is created using the syntax of the Wireless tool.
-
-For Example:
-iwconfig eth1 mode ad-hoc essid testing channel 2
-
-2.3. Merging Ad-Hoc Networks
-----------------------------
-
-
-3. Interaction with Wireless Tools
-==================================
-
-3.1 iwconfig mode
------------------
-
-When configuring the mode of the adapter, all run-time configured parameters
-are reset to the value used when the module was loaded. This includes
-channels, rates, ESSID, etc.
-
-3.2 iwconfig sens
------------------
-
-The 'iwconfig ethX sens XX' command will not set the signal sensitivity
-threshold, as described in iwconfig documentation, but rather the number
-of consecutive missed beacons that will trigger handover, i.e. roaming
-to another access point. At the same time, it will set the disassociation
-threshold to 3 times the given value.
-
-
-4. About the Version Numbers
-=============================
-
-Due to the nature of open source development projects, there are
-frequently changes being incorporated that have not gone through
-a complete validation process. These changes are incorporated into
-development snapshot releases.
-
-Releases are numbered with a three level scheme:
-
- major.minor.development
-
-Any version where the 'development' portion is 0 (for example
-1.0.0, 1.1.0, etc.) indicates a stable version that will be made
-available for kernel inclusion.
-
-Any version where the 'development' portion is not a 0 (for
-example 1.0.1, 1.1.5, etc.) indicates a development version that is
-being made available for testing and cutting edge users. The stability
-and functionality of the development releases are not know. We make
-efforts to try and keep all snapshots reasonably stable, but due to the
-frequency of their release, and the desire to get those releases
-available as quickly as possible, unknown anomalies should be expected.
-
-The major version number will be incremented when significant changes
-are made to the driver. Currently, there are no major changes planned.
-
-5. Firmware installation
-========================
-
-The driver requires a firmware image, download it and extract the
-files under /lib/firmware (or wherever your hotplug's firmware.agent
-will look for firmware files)
-
-The firmware can be downloaded from the following URL:
-
- http://ipw2200.sf.net/
-
-
-6. Support
-==========
-
-For direct support of the 1.0.0 version, you can contact
-http://supportmail.intel.com, or you can use the open source project
-support.
-
-For general information and support, go to:
-
- http://ipw2200.sf.net/
-
-
-7. License
-==========
-
- Copyright |copy| 2003 - 2006 Intel Corporation. All rights reserved.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59
- Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
- Contact Information:
-
- James P. Ketrenos <ipw2100-admin at linux.intel.com>
-
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
diff --git a/MAINTAINERS b/MAINTAINERS
index 42117d5a1d4e4..73e843194739a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10823,14 +10823,6 @@ M: David E. Box <david.e.box at linux.intel.com>
S: Supported
F: drivers/platform/x86/intel/pmt/
-INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
-M: Stanislav Yakovlev <stas.yakovlev at gmail.com>
-L: linux-wireless at vger.kernel.org
-S: Maintained
-F: Documentation/networking/device_drivers/wifi/intel/ipw2100.rst
-F: Documentation/networking/device_drivers/wifi/intel/ipw2200.rst
-F: drivers/net/wireless/intel/ipw2x00/
-
INTEL PSTATE DRIVER
M: Srinivas Pandruvada <srinivas.pandruvada at linux.intel.com>
M: Len Brown <lenb at kernel.org>
diff --git a/drivers/net/wireless/intel/Kconfig b/drivers/net/wireless/intel/Kconfig
index 3d1d7d11a3961..12c380ddb0cb0 100644
--- a/drivers/net/wireless/intel/Kconfig
+++ b/drivers/net/wireless/intel/Kconfig
@@ -12,7 +12,6 @@ config WLAN_VENDOR_INTEL
if WLAN_VENDOR_INTEL
-source "drivers/net/wireless/intel/ipw2x00/Kconfig"
source "drivers/net/wireless/intel/iwlegacy/Kconfig"
source "drivers/net/wireless/intel/iwlwifi/Kconfig"
diff --git a/drivers/net/wireless/intel/Makefile b/drivers/net/wireless/intel/Makefile
index 208e73a160519..6d5762d96f739 100644
--- a/drivers/net/wireless/intel/Makefile
+++ b/drivers/net/wireless/intel/Makefile
@@ -1,7 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_IPW2100) += ipw2x00/
-obj-$(CONFIG_IPW2200) += ipw2x00/
-
obj-$(CONFIG_IWLEGACY) += iwlegacy/
obj-$(CONFIG_IWLWIFI) += iwlwifi/
diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig
deleted file mode 100644
index 1650d5865aa02..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/Kconfig
+++ /dev/null
@@ -1,195 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-#
-# Intel Centrino wireless drivers
-#
-
-config IPW2100
- tristate "Intel PRO/Wireless 2100 Network Connection"
- depends on PCI && CFG80211
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select LIB80211
- select LIBIPW
- help
- A driver for the Intel PRO/Wireless 2100 Network
- Connection 802.11b wireless network adapter.
-
- See <file:Documentation/networking/device_drivers/wifi/intel/ipw2100.rst>
- for information on the capabilities currently enabled in this driver
- and for tips for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2100.sf.net/>. Once you have the firmware image, you
- will need to place it in /lib/firmware.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2100_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2100
- help
- Enables promiscuous/monitor mode support for the ipw2100 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2100_DEBUG
- bool "Enable full debugging output in IPW2100 module."
- depends on IPW2100
- help
- This option will enable debug tracing output for the IPW2100.
-
- This will result in the kernel module being ~60k larger. You can
- control which debug output is sent to the kernel log by setting the
- value in
-
- /sys/bus/pci/drivers/ipw2100/debug_level
-
- This entry will only exist if this option is enabled.
-
- If you are not trying to debug or develop the IPW2100 driver, you
- most likely want to say N here.
-
-config IPW2200
- tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
- depends on PCI && CFG80211
- select CFG80211_WEXT_EXPORT
- select WIRELESS_EXT
- select WEXT_SPY
- select WEXT_PRIV
- select FW_LOADER
- select LIB80211
- select LIBIPW
- help
- A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network
- Connection adapters.
-
- See <file:Documentation/networking/device_drivers/wifi/intel/ipw2200.rst>
- for information on the capabilities currently enabled in this
- driver and for tips for debugging issues and problems.
-
- In order to use this driver, you will need a firmware image for it.
- You can obtain the firmware from
- <http://ipw2200.sf.net/>. See the above referenced README.ipw2200
- for information on where to install the firmware images.
-
- You will also very likely need the Wireless Tools in order to
- configure your card:
-
- <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
-
- It is recommended that you compile this driver as a module (M)
- rather than built-in (Y). This driver requires firmware at device
- initialization time, and when built-in this typically happens
- before the filesystem is accessible (hence firmware will be
- unavailable and initialization will fail). If you do choose to build
- this driver into your kernel image, you can avoid this problem by
- including the firmware and a firmware loader in an initramfs.
-
-config IPW2200_MONITOR
- bool "Enable promiscuous mode"
- depends on IPW2200
- help
- Enables promiscuous/monitor mode support for the ipw2200 driver.
- With this feature compiled into the driver, you can switch to
- promiscuous mode via the Wireless Tool's Monitor mode. While in this
- mode, no packets can be sent.
-
-config IPW2200_RADIOTAP
- bool "Enable radiotap format 802.11 raw packet support"
- depends on IPW2200_MONITOR
-
-config IPW2200_PROMISCUOUS
- bool "Enable creation of a RF radiotap promiscuous interface"
- depends on IPW2200_MONITOR
- select IPW2200_RADIOTAP
- help
- Enables the creation of a second interface prefixed 'rtap'.
- This second interface will provide every received in radiotap
- format.
-
- This is useful for performing wireless network analysis while
- maintaining an active association.
-
- Example usage:
-
- % modprobe ipw2200 rtap_iface=1
- % ifconfig rtap0 up
- % tethereal -i rtap0
-
- If you do not specify 'rtap_iface=1' as a module parameter then
- the rtap interface will not be created and you will need to turn
- it on via sysfs:
-
- % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface
-
-config IPW2200_QOS
- bool "Enable QoS support"
- depends on IPW2200
-
-config IPW2200_DEBUG
- bool "Enable full debugging output in IPW2200 module."
- depends on IPW2200
- help
- This option will enable low level debug tracing output for IPW2200.
-
- Note, normal debug code is already compiled in. This low level
- debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
- will result in the kernel module being ~70 larger. Most users
- will typically not need this high verbosity debug information.
-
- If you are not sure, say N here.
-
-config LIBIPW
- tristate
- depends on PCI && CFG80211
- select WIRELESS_EXT
- select WEXT_SPY
- select CRYPTO
- select CRYPTO_MICHAEL_MIC
- select CRC32
- select LIB80211
- select LIB80211_CRYPT_WEP
- select LIB80211_CRYPT_TKIP
- select LIB80211_CRYPT_CCMP
- help
- This option enables the hardware independent IEEE 802.11
- networking stack. This component is deprecated in favor of the
- mac80211 component.
-
-config LIBIPW_DEBUG
- bool "Full debugging output for the LIBIPW component"
- depends on LIBIPW
- help
- This option will enable debug tracing output for the
- libipw component.
-
- This will result in the kernel module being ~70k larger. You
- can control which debug output is sent to the kernel log by
- setting the value in
-
- /proc/net/ieee80211/debug_level
-
- For example:
-
- % echo 0x00000FFO > /proc/net/ieee80211/debug_level
-
- For a list of values you can assign to debug_level, you
- can look at the bit mask values in ieee80211.h
-
- If you are not trying to debug or develop the libipw
- component, you most likely want to say N here.
diff --git a/drivers/net/wireless/intel/ipw2x00/Makefile b/drivers/net/wireless/intel/ipw2x00/Makefile
deleted file mode 100644
index e1ec50359dffc..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for the Intel Centrino wireless drivers
-#
-
-obj-$(CONFIG_IPW2100) += ipw2100.o
-obj-$(CONFIG_IPW2200) += ipw2200.o
-
-obj-$(CONFIG_LIBIPW) += libipw.o
-libipw-objs := \
- libipw_module.o \
- libipw_tx.o \
- libipw_rx.o \
- libipw_wx.o \
- libipw_geo.o
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw.h b/drivers/net/wireless/intel/ipw2x00/ipw.h
deleted file mode 100644
index 7b230a132daa7..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Intel Pro/Wireless 2100, 2200BG, 2915ABG network connection driver
- *
- * Copyright 2012 Stanislav Yakovlev <stas.yakovlev at gmail.com>
- */
-
-#ifndef __IPW_H__
-#define __IPW_H__
-
-#include <linux/ieee80211.h>
-
-static const u32 ipw_cipher_suites[] = {
- WLAN_CIPHER_SUITE_WEP40,
- WLAN_CIPHER_SUITE_WEP104,
- WLAN_CIPHER_SUITE_TKIP,
- WLAN_CIPHER_SUITE_CCMP,
-};
-
-#endif
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
deleted file mode 100644
index 0812db8936f13..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+++ /dev/null
@@ -1,8587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
- Portions of this file are based on the sample_* files provided by Wireless
- Extensions 0.26 package and copyright (c) 1997-2003 Jean Tourrilhes
- <jt at hpl.hp.com>
-
- Portions of this file are based on the Host AP project,
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <j at w1.fi>
- Copyright (c) 2002-2003, Jouni Malinen <j at w1.fi>
-
- Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and
- ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c
- available in the 2.4.25 kernel sources, and are copyright (c) Alan Cox
-
-******************************************************************************/
-/*
-
- Initial driver on which this is based was developed by Janusz Gorycki,
- Maciej Urbaniak, and Maciej Sosnowski.
-
- Promiscuous mode support added by Jacek Wysoczynski and Maciej Urbaniak.
-
-Theory of Operation
-
-Tx - Commands and Data
-
-Firmware and host share a circular queue of Transmit Buffer Descriptors (TBDs)
-Each TBD contains a pointer to the physical (dma_addr_t) address of data being
-sent to the firmware as well as the length of the data.
-
-The host writes to the TBD queue at the WRITE index. The WRITE index points
-to the _next_ packet to be written and is advanced when after the TBD has been
-filled.
-
-The firmware pulls from the TBD queue at the READ index. The READ index points
-to the currently being read entry, and is advanced once the firmware is
-done with a packet.
-
-When data is sent to the firmware, the first TBD is used to indicate to the
-firmware if a Command or Data is being sent. If it is Command, all of the
-command information is contained within the physical address referred to by the
-TBD. If it is Data, the first TBD indicates the type of data packet, number
-of fragments, etc. The next TBD then refers to the actual packet location.
-
-The Tx flow cycle is as follows:
-
-1) ipw2100_tx() is called by kernel with SKB to transmit
-2) Packet is move from the tx_free_list and appended to the transmit pending
- list (tx_pend_list)
-3) work is scheduled to move pending packets into the shared circular queue.
-4) when placing packet in the circular queue, the incoming SKB is DMA mapped
- to a physical address. That address is entered into a TBD. Two TBDs are
- filled out. The first indicating a data packet, the second referring to the
- actual payload data.
-5) the packet is removed from tx_pend_list and placed on the end of the
- firmware pending list (fw_pend_list)
-6) firmware is notified that the WRITE index has
-7) Once the firmware has processed the TBD, INTA is triggered.
-8) For each Tx interrupt received from the firmware, the READ index is checked
- to see which TBDs are done being processed.
-9) For each TBD that has been processed, the ISR pulls the oldest packet
- from the fw_pend_list.
-10)The packet structure contained in the fw_pend_list is then used
- to unmap the DMA address and to free the SKB originally passed to the driver
- from the kernel.
-11)The packet structure is placed onto the tx_free_list
-
-The above steps are the same for commands, only the msg_free_list/msg_pend_list
-are used instead of tx_free_list/tx_pend_list
-
-...
-
-Critical Sections / Locking :
-
-There are two locks utilized. The first is the low level lock (priv->low_lock)
-that protects the following:
-
-- Access to the Tx/Rx queue lists via priv->low_lock. The lists are as follows:
-
- tx_free_list : Holds pre-allocated Tx buffers.
- TAIL modified in __ipw2100_tx_process()
- HEAD modified in ipw2100_tx()
-
- tx_pend_list : Holds used Tx buffers waiting to go into the TBD ring
- TAIL modified ipw2100_tx()
- HEAD modified by ipw2100_tx_send_data()
-
- msg_free_list : Holds pre-allocated Msg (Command) buffers
- TAIL modified in __ipw2100_tx_process()
- HEAD modified in ipw2100_hw_send_command()
-
- msg_pend_list : Holds used Msg buffers waiting to go into the TBD ring
- TAIL modified in ipw2100_hw_send_command()
- HEAD modified in ipw2100_tx_send_commands()
-
- The flow of data on the TX side is as follows:
-
- MSG_FREE_LIST + COMMAND => MSG_PEND_LIST => TBD => MSG_FREE_LIST
- TX_FREE_LIST + DATA => TX_PEND_LIST => TBD => TX_FREE_LIST
-
- The methods that work on the TBD ring are protected via priv->low_lock.
-
-- The internal data state of the device itself
-- Access to the firmware read/write indexes for the BD queues
- and associated logic
-
-All external entry functions are locked with the priv->action_lock to ensure
-that only one external action is invoked at a time.
-
-
-*/
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/uaccess.h>
-#include <asm/io.h>
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/stringify.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/time.h>
-#include <linux/firmware.h>
-#include <linux/acpi.h>
-#include <linux/ctype.h>
-#include <linux/pm_qos.h>
-
-#include <net/lib80211.h>
-
-#include "ipw2100.h"
-#include "ipw.h"
-
-#define IPW2100_VERSION "git-1.2.2"
-
-#define DRV_NAME "ipw2100"
-#define DRV_VERSION IPW2100_VERSION
-#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-
-static struct pm_qos_request ipw2100_pm_qos_req;
-
-/* Debugging stuff */
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW2100_RX_DEBUG /* Reception debugging */
-#endif
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-
-static int debug = 0;
-static int network_mode = 0;
-static int channel = 0;
-static int associate = 0;
-static int disable = 0;
-#ifdef CONFIG_PM
-static struct ipw2100_fw ipw2100_firmware;
-#endif
-
-#include <linux/moduleparam.h>
-module_param(debug, int, 0444);
-module_param_named(mode, network_mode, int, 0444);
-module_param(channel, int, 0444);
-module_param(associate, int, 0444);
-module_param(disable, int, 0444);
-
-MODULE_PARM_DESC(debug, "debug level");
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
-MODULE_PARM_DESC(channel, "channel");
-MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-
-static u32 ipw2100_debug_level = IPW_DL_NONE;
-
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW_DEBUG(level, message...) \
-do { \
- if (ipw2100_debug_level & (level)) { \
- printk(KERN_DEBUG "ipw2100: %s ", __func__); \
- printk(message); \
- } \
-} while (0)
-#else
-#define IPW_DEBUG(level, message...) do {} while (0)
-#endif /* CONFIG_IPW2100_DEBUG */
-
-#ifdef CONFIG_IPW2100_DEBUG
-static const char *command_types[] = {
- "undefined",
- "unused", /* HOST_ATTENTION */
- "HOST_COMPLETE",
- "unused", /* SLEEP */
- "unused", /* HOST_POWER_DOWN */
- "unused",
- "SYSTEM_CONFIG",
- "unused", /* SET_IMR */
- "SSID",
- "MANDATORY_BSSID",
- "AUTHENTICATION_TYPE",
- "ADAPTER_ADDRESS",
- "PORT_TYPE",
- "INTERNATIONAL_MODE",
- "CHANNEL",
- "RTS_THRESHOLD",
- "FRAG_THRESHOLD",
- "POWER_MODE",
- "TX_RATES",
- "BASIC_TX_RATES",
- "WEP_KEY_INFO",
- "unused",
- "unused",
- "unused",
- "unused",
- "WEP_KEY_INDEX",
- "WEP_FLAGS",
- "ADD_MULTICAST",
- "CLEAR_ALL_MULTICAST",
- "BEACON_INTERVAL",
- "ATIM_WINDOW",
- "CLEAR_STATISTICS",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "TX_POWER_INDEX",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "undefined",
- "BROADCAST_SCAN",
- "CARD_DISABLE",
- "PREFERRED_BSSID",
- "SET_SCAN_OPTIONS",
- "SCAN_DWELL_TIME",
- "SWEEP_TABLE",
- "AP_OR_STATION_TABLE",
- "GROUP_ORDINALS",
- "SHORT_RETRY_LIMIT",
- "LONG_RETRY_LIMIT",
- "unused", /* SAVE_CALIBRATION */
- "unused", /* RESTORE_CALIBRATION */
- "undefined",
- "undefined",
- "undefined",
- "HOST_PRE_POWER_DOWN",
- "unused", /* HOST_INTERRUPT_COALESCING */
- "undefined",
- "CARD_DISABLE_PHY_OFF",
- "MSDU_TX_RATES",
- "undefined",
- "SET_STATION_STAT_BITS",
- "CLEAR_STATIONS_STAT_BITS",
- "LEAP_ROGUE_MODE",
- "SET_SECURITY_INFORMATION",
- "DISASSOCIATION_BSSID",
- "SET_WPA_ASS_IE"
-};
-#endif
-
-static const long ipw2100_frequencies[] = {
- 2412, 2417, 2422, 2427,
- 2432, 2437, 2442, 2447,
- 2452, 2457, 2462, 2467,
- 2472, 2484
-};
-
-#define FREQ_COUNT ARRAY_SIZE(ipw2100_frequencies)
-
-static struct ieee80211_rate ipw2100_bg_rates[] = {
- { .bitrate = 10 },
- { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-};
-
-#define RATE_COUNT ARRAY_SIZE(ipw2100_bg_rates)
-
-/* Pre-decl until we get the code solid and then we can clean it up */
-static void ipw2100_tx_send_commands(struct ipw2100_priv *priv);
-static void ipw2100_tx_send_data(struct ipw2100_priv *priv);
-static int ipw2100_adapter_setup(struct ipw2100_priv *priv);
-
-static void ipw2100_queues_initialize(struct ipw2100_priv *priv);
-static void ipw2100_queues_free(struct ipw2100_priv *priv);
-static int ipw2100_queues_allocate(struct ipw2100_priv *priv);
-
-static int ipw2100_fw_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_get_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
- size_t max);
-static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
- size_t max);
-static void ipw2100_release_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static int ipw2100_ucode_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw);
-static void ipw2100_wx_event_work(struct work_struct *work);
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev);
-static const struct iw_handler_def ipw2100_wx_handler_def;
-
-static inline void read_register(struct net_device *dev, u32 reg, u32 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread32(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val);
-}
-
-static inline void write_register(struct net_device *dev, u32 reg, u32 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite32(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val);
-}
-
-static inline void read_register_word(struct net_device *dev, u32 reg,
- u16 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread16(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val);
-}
-
-static inline void read_register_byte(struct net_device *dev, u32 reg, u8 * val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- *val = ioread8(priv->ioaddr + reg);
- IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val);
-}
-
-static inline void write_register_word(struct net_device *dev, u32 reg, u16 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite16(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val);
-}
-
-static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- iowrite8(val, priv->ioaddr + reg);
- IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val);
-}
-
-static inline void read_nic_dword(struct net_device *dev, u32 addr, u32 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_dword(struct net_device *dev, u32 addr, u32 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void read_nic_word(struct net_device *dev, u32 addr, u16 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_word(struct net_device *dev, u32 addr, u16 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register_word(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void read_nic_byte(struct net_device *dev, u32 addr, u8 * val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static inline void write_nic_byte(struct net_device *dev, u32 addr, u8 val)
-{
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- addr & IPW_REG_INDIRECT_ADDR_MASK);
- write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA, val);
-}
-
-static void write_nic_memory(struct net_device *dev, u32 addr, u32 len,
- const u8 * buf)
-{
- u32 aligned_addr;
- u32 aligned_len;
- u32 dif_len;
- u32 i;
-
- /* read first nibble byte by byte */
- aligned_addr = addr & (~0x3);
- dif_len = addr - aligned_addr;
- if (dif_len) {
- /* Start reading at aligned_addr + dif_len */
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- write_register_byte(dev,
- IPW_REG_INDIRECT_ACCESS_DATA + i,
- *buf);
-
- len -= dif_len;
- aligned_addr += 4;
- }
-
- /* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
- aligned_len = len & (~0x3);
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- write_register(dev, IPW_REG_AUTOINCREMENT_DATA, *(u32 *) buf);
-
- /* copy the last nibble */
- dif_len = len - aligned_len;
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- write_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i,
- *buf);
-}
-
-static void read_nic_memory(struct net_device *dev, u32 addr, u32 len,
- u8 * buf)
-{
- u32 aligned_addr;
- u32 aligned_len;
- u32 dif_len;
- u32 i;
-
- /* read first nibble byte by byte */
- aligned_addr = addr & (~0x3);
- dif_len = addr - aligned_addr;
- if (dif_len) {
- /* Start reading at aligned_addr + dif_len */
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS,
- aligned_addr);
- for (i = dif_len; i < 4; i++, buf++)
- read_register_byte(dev,
- IPW_REG_INDIRECT_ACCESS_DATA + i,
- buf);
-
- len -= dif_len;
- aligned_addr += 4;
- }
-
- /* read DWs through autoincrement registers */
- write_register(dev, IPW_REG_AUTOINCREMENT_ADDRESS, aligned_addr);
- aligned_len = len & (~0x3);
- for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4)
- read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf);
-
- /* copy the last nibble */
- dif_len = len - aligned_len;
- write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr);
- for (i = 0; i < dif_len; i++, buf++)
- read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);
-}
-
-static bool ipw2100_hw_is_adapter_in_system(struct net_device *dev)
-{
- u32 dbg;
-
- read_register(dev, IPW_REG_DOA_DEBUG_AREA_START, &dbg);
-
- return dbg == IPW_DATA_DOA_DEBUG_VALUE;
-}
-
-static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord,
- void *val, u32 * len)
-{
- struct ipw2100_ordinals *ordinals = &priv->ordinals;
- u32 addr;
- u32 field_info;
- u16 field_len;
- u16 field_count;
- u32 total_length;
-
- if (ordinals->table1_addr == 0) {
- printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals "
- "before they have been loaded.\n");
- return -EINVAL;
- }
-
- if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
- if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) {
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- printk(KERN_WARNING DRV_NAME
- ": ordinal buffer length too small, need %zd\n",
- IPW_ORD_TAB_1_ENTRY_SIZE);
-
- return -EINVAL;
- }
-
- read_nic_dword(priv->net_dev,
- ordinals->table1_addr + (ord << 2), &addr);
- read_nic_dword(priv->net_dev, addr, val);
-
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- return 0;
- }
-
- if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) {
-
- ord -= IPW_START_ORD_TAB_2;
-
- /* get the address of statistic */
- read_nic_dword(priv->net_dev,
- ordinals->table2_addr + (ord << 3), &addr);
-
- /* get the second DW of statistics ;
- * two 16-bit words - first is length, second is count */
- read_nic_dword(priv->net_dev,
- ordinals->table2_addr + (ord << 3) + sizeof(u32),
- &field_info);
-
- /* get each entry length */
- field_len = *((u16 *) & field_info);
-
- /* get number of entries */
- field_count = *(((u16 *) & field_info) + 1);
-
- /* abort if no enough memory */
- total_length = field_len * field_count;
- if (total_length > *len) {
- *len = total_length;
- return -EINVAL;
- }
-
- *len = total_length;
- if (!total_length)
- return 0;
-
- /* read the ordinal data from the SRAM */
- read_nic_memory(priv->net_dev, addr, total_length, val);
-
- return 0;
- }
-
- printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor "
- "in table 2\n", ord);
-
- return -EINVAL;
-}
-
-static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val,
- u32 * len)
-{
- struct ipw2100_ordinals *ordinals = &priv->ordinals;
- u32 addr;
-
- if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) {
- if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) {
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
- IPW_DEBUG_INFO("wrong size\n");
- return -EINVAL;
- }
-
- read_nic_dword(priv->net_dev,
- ordinals->table1_addr + (ord << 2), &addr);
-
- write_nic_dword(priv->net_dev, addr, *val);
-
- *len = IPW_ORD_TAB_1_ENTRY_SIZE;
-
- return 0;
- }
-
- IPW_DEBUG_INFO("wrong table\n");
- if (IS_ORDINAL_TABLE_TWO(ordinals, ord))
- return -EINVAL;
-
- return -EINVAL;
-}
-
-static char *snprint_line(char *buf, size_t count,
- const u8 * data, u32 len, u32 ofs)
-{
- int out, i, j, l;
- char c;
-
- out = scnprintf(buf, count, "%08X", ofs);
-
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++)
- out += scnprintf(buf + out, count - out, "%02X ",
- data[(i * 8 + j)]);
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- out += scnprintf(buf + out, count - out, " ");
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++) {
- c = data[(i * 8 + j)];
- if (!isascii(c) || !isprint(c))
- c = '.';
-
- out += scnprintf(buf + out, count - out, "%c", c);
- }
-
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- return buf;
-}
-
-static void printk_buf(int level, const u8 * data, u32 len)
-{
- char line[81];
- u32 ofs = 0;
- if (!(ipw2100_debug_level & level))
- return;
-
- while (len) {
- printk(KERN_DEBUG "%s\n",
- snprint_line(line, sizeof(line), &data[ofs],
- min(len, 16U), ofs));
- ofs += 16;
- len -= min(len, 16U);
- }
-}
-
-#define MAX_RESET_BACKOFF 10
-
-static void schedule_reset(struct ipw2100_priv *priv)
-{
- time64_t now = ktime_get_boottime_seconds();
-
- /* If we haven't received a reset request within the backoff period,
- * then we can reset the backoff interval so this reset occurs
- * immediately */
- if (priv->reset_backoff &&
- (now - priv->last_reset > priv->reset_backoff))
- priv->reset_backoff = 0;
-
- priv->last_reset = now;
-
- if (!(priv->status & STATUS_RESET_PENDING)) {
- IPW_DEBUG_INFO("%s: Scheduling firmware restart (%llds).\n",
- priv->net_dev->name, priv->reset_backoff);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
- priv->status |= STATUS_RESET_PENDING;
- if (priv->reset_backoff)
- schedule_delayed_work(&priv->reset_work,
- priv->reset_backoff * HZ);
- else
- schedule_delayed_work(&priv->reset_work, 0);
-
- if (priv->reset_backoff < MAX_RESET_BACKOFF)
- priv->reset_backoff++;
-
- wake_up_interruptible(&priv->wait_command_queue);
- } else
- IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n",
- priv->net_dev->name);
-
-}
-
-#define HOST_COMPLETE_TIMEOUT (2 * HZ)
-static int ipw2100_hw_send_command(struct ipw2100_priv *priv,
- struct host_command *cmd)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- unsigned long flags;
- int err = 0;
-
- IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n",
- command_types[cmd->host_command], cmd->host_command,
- cmd->host_command_length);
- printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters,
- cmd->host_command_length);
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->fatal_error) {
- IPW_DEBUG_INFO
- ("Attempt to send command while hardware in fatal error condition.\n");
- err = -EIO;
- goto fail_unlock;
- }
-
- if (!(priv->status & STATUS_RUNNING)) {
- IPW_DEBUG_INFO
- ("Attempt to send command while hardware is not running.\n");
- err = -EIO;
- goto fail_unlock;
- }
-
- if (priv->status & STATUS_CMD_ACTIVE) {
- IPW_DEBUG_INFO
- ("Attempt to send command while another command is pending.\n");
- err = -EBUSY;
- goto fail_unlock;
- }
-
- if (list_empty(&priv->msg_free_list)) {
- IPW_DEBUG_INFO("no available msg buffers\n");
- goto fail_unlock;
- }
-
- priv->status |= STATUS_CMD_ACTIVE;
- priv->messages_sent++;
-
- element = priv->msg_free_list.next;
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
- packet->jiffy_start = jiffies;
-
- /* initialize the firmware command packet */
- packet->info.c_struct.cmd->host_command_reg = cmd->host_command;
- packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1;
- packet->info.c_struct.cmd->host_command_len_reg =
- cmd->host_command_length;
- packet->info.c_struct.cmd->sequence = cmd->host_command_sequence;
-
- memcpy(packet->info.c_struct.cmd->host_command_params_reg,
- cmd->host_command_parameters,
- sizeof(packet->info.c_struct.cmd->host_command_params_reg));
-
- list_del(element);
- DEC_STAT(&priv->msg_free_stat);
-
- list_add_tail(element, &priv->msg_pend_list);
- INC_STAT(&priv->msg_pend_stat);
-
- ipw2100_tx_send_commands(priv);
- ipw2100_tx_send_data(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- /*
- * We must wait for this command to complete before another
- * command can be sent... but if we wait more than 3 seconds
- * then there is a problem.
- */
-
- err =
- wait_event_interruptible_timeout(priv->wait_command_queue,
- !(priv->
- status & STATUS_CMD_ACTIVE),
- HOST_COMPLETE_TIMEOUT);
-
- if (err == 0) {
- IPW_DEBUG_INFO("Command completion failed out after %dms.\n",
- 1000 * (HOST_COMPLETE_TIMEOUT / HZ));
- priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT;
- priv->status &= ~STATUS_CMD_ACTIVE;
- schedule_reset(priv);
- return -EIO;
- }
-
- if (priv->fatal_error) {
- printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* !!!!! HACK TEST !!!!!
- * When lots of debug trace statements are enabled, the driver
- * doesn't seem to have as many firmware restart cycles...
- *
- * As a test, we're sticking in a 1/100s delay here */
- schedule_timeout_uninterruptible(msecs_to_jiffies(10));
-
- return 0;
-
- fail_unlock:
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- return err;
-}
-
-/*
- * Verify the values and data access of the hardware
- * No locks needed or used. No functions called.
- */
-static int ipw2100_verify(struct ipw2100_priv *priv)
-{
- u32 data1, data2;
- u32 address;
-
- u32 val1 = 0x76543210;
- u32 val2 = 0xFEDCBA98;
-
- /* Domain 0 check - all values should be DOA_DEBUG */
- for (address = IPW_REG_DOA_DEBUG_AREA_START;
- address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) {
- read_register(priv->net_dev, address, &data1);
- if (data1 != IPW_DATA_DOA_DEBUG_VALUE)
- return -EIO;
- }
-
- /* Domain 1 check - use arbitrary read/write compare */
- for (address = 0; address < 5; address++) {
- /* The memory area is not used now */
- write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
- val1);
- write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
- val2);
- read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32,
- &data1);
- read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36,
- &data2);
- if (val1 == data1 && val2 == data2)
- return 0;
- }
-
- return -EIO;
-}
-
-/*
- *
- * Loop until the CARD_DISABLED bit is the same value as the
- * supplied parameter
- *
- * TODO: See if it would be more efficient to do a wait/wake
- * cycle and have the completion event trigger the wakeup
- *
- */
-#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 milli
-static int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state)
-{
- int i;
- u32 card_state;
- u32 len = sizeof(card_state);
- int err;
-
- for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) {
- err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED,
- &card_state, &len);
- if (err) {
- IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal "
- "failed.\n");
- return 0;
- }
-
- /* We'll break out if either the HW state says it is
- * in the state we want, or if HOST_COMPLETE command
- * finishes */
- if ((card_state == state) ||
- ((priv->status & STATUS_ENABLED) ?
- IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) {
- if (state == IPW_HW_STATE_ENABLED)
- priv->status |= STATUS_ENABLED;
- else
- priv->status &= ~STATUS_ENABLED;
-
- return 0;
- }
-
- udelay(50);
- }
-
- IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n",
- state ? "DISABLED" : "ENABLED");
- return -EIO;
-}
-
-/*********************************************************************
- Procedure : sw_reset_and_clock
- Purpose : Asserts s/w reset, asserts clock initialization
- and waits for clock stabilization
- ********************************************************************/
-static int sw_reset_and_clock(struct ipw2100_priv *priv)
-{
- int i;
- u32 r;
-
- // assert s/w reset
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- // wait for clock stabilization
- for (i = 0; i < 1000; i++) {
- udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY);
-
- // check clock ready bit
- read_register(priv->net_dev, IPW_REG_RESET_REG, &r);
- if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET)
- break;
- }
-
- if (i == 1000)
- return -EIO; // TODO: better error value
-
- /* set "initialization complete" bit to move adapter to
- * D0 state */
- write_register(priv->net_dev, IPW_REG_GP_CNTRL,
- IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE);
-
- /* wait for clock stabilization */
- for (i = 0; i < 10000; i++) {
- udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4);
-
- /* check clock ready bit */
- read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
- if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY)
- break;
- }
-
- if (i == 10000)
- return -EIO; /* TODO: better error value */
-
- /* set D0 standby bit */
- read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r);
- write_register(priv->net_dev, IPW_REG_GP_CNTRL,
- r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
-
- return 0;
-}
-
-/*********************************************************************
- Procedure : ipw2100_download_firmware
- Purpose : Initiaze adapter after power on.
- The sequence is:
- 1. assert s/w reset first!
- 2. awake clocks & wait for clock stabilization
- 3. hold ARC (don't ask me why...)
- 4. load Dino ucode and reset/clock init again
- 5. zero-out shared mem
- 6. download f/w
- *******************************************************************/
-static int ipw2100_download_firmware(struct ipw2100_priv *priv)
-{
- u32 address;
- int err;
-
-#ifndef CONFIG_PM
- /* Fetch the firmware and microcode */
- struct ipw2100_fw ipw2100_firmware;
-#endif
-
- if (priv->fatal_error) {
- IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after "
- "fatal error %d. Interface must be brought down.\n",
- priv->net_dev->name, priv->fatal_error);
- return -EINVAL;
- }
-#ifdef CONFIG_PM
- if (!ipw2100_firmware.version) {
- err = ipw2100_get_firmware(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
- priv->fatal_error = IPW2100_ERR_FW_LOAD;
- goto fail;
- }
- }
-#else
- err = ipw2100_get_firmware(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n",
- priv->net_dev->name, err);
- priv->fatal_error = IPW2100_ERR_FW_LOAD;
- goto fail;
- }
-#endif
- priv->firmware_version = ipw2100_firmware.version;
-
- /* s/w reset and clock stabilization */
- err = sw_reset_and_clock(priv);
- if (err) {
- IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- err = ipw2100_verify(priv);
- if (err) {
- IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* Hold ARC */
- write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000);
-
- /* allow ARC to run */
- write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
-
- /* load microcode */
- err = ipw2100_ucode_download(priv, &ipw2100_firmware);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* release ARC */
- write_nic_dword(priv->net_dev,
- IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000);
-
- /* s/w reset and clock stabilization (again!!!) */
- err = sw_reset_and_clock(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: sw_reset_and_clock failed: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-
- /* load f/w */
- err = ipw2100_fw_download(priv, &ipw2100_firmware);
- if (err) {
- IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n",
- priv->net_dev->name, err);
- goto fail;
- }
-#ifndef CONFIG_PM
- /*
- * When the .resume method of the driver is called, the other
- * part of the system, i.e. the ide driver could still stay in
- * the suspend stage. This prevents us from loading the firmware
- * from the disk. --YZ
- */
-
- /* free any storage allocated for firmware image */
- ipw2100_release_firmware(priv, &ipw2100_firmware);
-#endif
-
- /* zero out Domain 1 area indirectly (Si requirement) */
- for (address = IPW_HOST_FW_SHARED_AREA0;
- address < IPW_HOST_FW_SHARED_AREA0_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA1;
- address < IPW_HOST_FW_SHARED_AREA1_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA2;
- address < IPW_HOST_FW_SHARED_AREA2_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_SHARED_AREA3;
- address < IPW_HOST_FW_SHARED_AREA3_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
- for (address = IPW_HOST_FW_INTERRUPT_AREA;
- address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4)
- write_nic_dword(priv->net_dev, address, 0);
-
- return 0;
-
- fail:
- ipw2100_release_firmware(priv, &ipw2100_firmware);
- return err;
-}
-
-static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv)
-{
- if (priv->status & STATUS_INT_ENABLED)
- return;
- priv->status |= STATUS_INT_ENABLED;
- write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);
-}
-
-static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv)
-{
- if (!(priv->status & STATUS_INT_ENABLED))
- return;
- priv->status &= ~STATUS_INT_ENABLED;
- write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);
-}
-
-static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv)
-{
- struct ipw2100_ordinals *ord = &priv->ordinals;
-
- IPW_DEBUG_INFO("enter\n");
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1,
- &ord->table1_addr);
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2,
- &ord->table2_addr);
-
- read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size);
- read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size);
-
- ord->table2_size &= 0x0000FFFF;
-
- IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size);
- IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size);
- IPW_DEBUG_INFO("exit\n");
-}
-
-static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv)
-{
- u32 reg = 0;
- /*
- * Set GPIO 3 writable by FW; GPIO 1 writable
- * by driver and enable clock
- */
- reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE |
- IPW_BIT_GPIO_LED_OFF);
- write_register(priv->net_dev, IPW_REG_GPIO, reg);
-}
-
-static int rf_kill_active(struct ipw2100_priv *priv)
-{
-#define MAX_RF_KILL_CHECKS 5
-#define RF_KILL_CHECK_DELAY 40
-
- unsigned short value = 0;
- u32 reg = 0;
- int i;
-
- if (!(priv->hw_features & HW_FEATURE_RFKILL)) {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- priv->status &= ~STATUS_RF_KILL_HW;
- return 0;
- }
-
- for (i = 0; i < MAX_RF_KILL_CHECKS; i++) {
- udelay(RF_KILL_CHECK_DELAY);
- read_register(priv->net_dev, IPW_REG_GPIO, ®);
- value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1);
- }
-
- if (value == 0) {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- priv->status |= STATUS_RF_KILL_HW;
- } else {
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- priv->status &= ~STATUS_RF_KILL_HW;
- }
-
- return (value == 0);
-}
-
-static int ipw2100_get_hw_features(struct ipw2100_priv *priv)
-{
- u32 addr, len;
- u32 val;
-
- /*
- * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1
- */
- len = sizeof(addr);
- if (ipw2100_get_ordinal
- (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return -EIO;
- }
-
- IPW_DEBUG_INFO("EEPROM address: %08X\n", addr);
-
- /*
- * EEPROM version is the byte at offset 0xfd in firmware
- * We read 4 bytes, then shift out the byte we actually want */
- read_nic_dword(priv->net_dev, addr + 0xFC, &val);
- priv->eeprom_version = (val >> 24) & 0xFF;
- IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version);
-
- /*
- * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware
- *
- * notice that the EEPROM bit is reverse polarity, i.e.
- * bit = 0 signifies HW RF kill switch is supported
- * bit = 1 signifies HW RF kill switch is NOT supported
- */
- read_nic_dword(priv->net_dev, addr + 0x20, &val);
- if (!((val >> 24) & 0x01))
- priv->hw_features |= HW_FEATURE_RFKILL;
-
- IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n",
- (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not ");
-
- return 0;
-}
-
-/*
- * Start firmware execution after power on and initialization
- * The sequence is:
- * 1. Release ARC
- * 2. Wait for f/w initialization completes;
- */
-static int ipw2100_start_adapter(struct ipw2100_priv *priv)
-{
- int i;
- u32 inta, inta_mask, gpio;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->status & STATUS_RUNNING)
- return 0;
-
- /*
- * Initialize the hw - drive adapter to DO state by setting
- * init_done bit. Wait for clk_ready bit and Download
- * fw & dino ucode
- */
- if (ipw2100_download_firmware(priv)) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to power on the adapter.\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* Clear the Tx, Rx and Msg queues and the r/w indexes
- * in the firmware RBD and TBD ring queue */
- ipw2100_queues_initialize(priv);
-
- ipw2100_hw_set_gpio(priv);
-
- /* TODO -- Look at disabling interrupts here to make sure none
- * get fired during FW initialization */
-
- /* Release ARC - clear reset bit */
- write_register(priv->net_dev, IPW_REG_RESET_REG, 0);
-
- /* wait for f/w initialization complete */
- IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n");
- i = 5000;
- do {
- schedule_timeout_uninterruptible(msecs_to_jiffies(40));
- /* Todo... wait for sync command ... */
-
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
-
- /* check "init done" bit */
- if (inta & IPW2100_INTA_FW_INIT_DONE) {
- /* reset "init done" bit */
- write_register(priv->net_dev, IPW_REG_INTA,
- IPW2100_INTA_FW_INIT_DONE);
- break;
- }
-
- /* check error conditions : we check these after the firmware
- * check so that if there is an error, the interrupt handler
- * will see it and the adapter will be reset */
- if (inta &
- (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) {
- /* clear error conditions */
- write_register(priv->net_dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR);
- }
- } while (--i);
-
- /* Clear out any pending INTAs since we aren't supposed to have
- * interrupts enabled at this point... */
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
- read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
- inta &= IPW_INTERRUPT_MASK;
- /* Clear out any pending interrupts */
- if (inta & inta_mask)
- write_register(priv->net_dev, IPW_REG_INTA, inta);
-
- IPW_DEBUG_FW("f/w initialization complete: %s\n",
- i ? "SUCCESS" : "FAILED");
-
- if (!i) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Firmware did not initialize.\n",
- priv->net_dev->name);
- return -EIO;
- }
-
- /* allow firmware to write to GPIO1 & GPIO3 */
- read_register(priv->net_dev, IPW_REG_GPIO, &gpio);
-
- gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK);
-
- write_register(priv->net_dev, IPW_REG_GPIO, gpio);
-
- /* Ready to receive commands */
- priv->status |= STATUS_RUNNING;
-
- /* The adapter has been reset; we are not associated */
- priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv)
-{
- if (!priv->fatal_error)
- return;
-
- priv->fatal_errors[priv->fatal_index++] = priv->fatal_error;
- priv->fatal_index %= IPW2100_ERROR_QUEUE;
- priv->fatal_error = 0;
-}
-
-/* NOTE: Our interrupt is disabled when this method is called */
-static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv)
-{
- u32 reg;
- int i;
-
- IPW_DEBUG_INFO("Power cycling the hardware.\n");
-
- ipw2100_hw_set_gpio(priv);
-
- /* Step 1. Stop Master Assert */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
-
- /* Step 2. Wait for stop Master Assert
- * (not more than 50us, otherwise ret error */
- i = 5;
- do {
- udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
- read_register(priv->net_dev, IPW_REG_RESET_REG, ®);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- } while (--i);
-
- priv->status &= ~STATUS_RESET_PENDING;
-
- if (!i) {
- IPW_DEBUG_INFO
- ("exit - waited too long for master assert stop\n");
- return -EIO;
- }
-
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- /* Reset any fatal_error conditions */
- ipw2100_reset_fatalerror(priv);
-
- /* At this point, the adapter is now stopped and disabled */
- priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING |
- STATUS_ASSOCIATED | STATUS_ENABLED);
-
- return 0;
-}
-
-/*
- * Send the CARD_DISABLE_PHY_OFF command to the card to disable it
- *
- * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent.
- *
- * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of
- * if STATUS_ASSN_LOST is sent.
- */
-static int ipw2100_hw_phy_off(struct ipw2100_priv *priv)
-{
-
-#define HW_PHY_OFF_LOOP_DELAY (msecs_to_jiffies(50))
-
- struct host_command cmd = {
- .host_command = CARD_DISABLE_PHY_OFF,
- .host_command_sequence = 0,
- .host_command_length = 0,
- };
- int err, i;
- u32 val1, val2;
-
- IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n");
-
- /* Turn off the radio */
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- for (i = 0; i < 2500; i++) {
- read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1);
- read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2);
-
- if ((val1 & IPW2100_CONTROL_PHY_OFF) &&
- (val2 & IPW2100_COMMAND_PHY_OFF))
- return 0;
-
- schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY);
- }
-
- return -EIO;
-}
-
-static int ipw2100_enable_adapter(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = HOST_COMPLETE,
- .host_command_sequence = 0,
- .host_command_length = 0
- };
- int err = 0;
-
- IPW_DEBUG_HC("HOST_COMPLETE\n");
-
- if (priv->status & STATUS_ENABLED)
- return 0;
-
- mutex_lock(&priv->adapter_mutex);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_HC("Command aborted due to RF kill active.\n");
- goto fail_up;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n");
- goto fail_up;
- }
-
- err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_ENABLED);
- if (err) {
- IPW_DEBUG_INFO("%s: card not responding to init command.\n",
- priv->net_dev->name);
- goto fail_up;
- }
-
- if (priv->stop_hang_check) {
- priv->stop_hang_check = 0;
- schedule_delayed_work(&priv->hang_check, HZ / 2);
- }
-
- fail_up:
- mutex_unlock(&priv->adapter_mutex);
- return err;
-}
-
-static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
-{
-#define HW_POWER_DOWN_DELAY (msecs_to_jiffies(100))
-
- struct host_command cmd = {
- .host_command = HOST_PRE_POWER_DOWN,
- .host_command_sequence = 0,
- .host_command_length = 0,
- };
- int err, i;
- u32 reg;
-
- if (!(priv->status & STATUS_RUNNING))
- return 0;
-
- priv->status |= STATUS_STOPPING;
-
- /* We can only shut down the card if the firmware is operational. So,
- * if we haven't reset since a fatal_error, then we can not send the
- * shutdown commands. */
- if (!priv->fatal_error) {
- /* First, make sure the adapter is enabled so that the PHY_OFF
- * command can shut it down */
- ipw2100_enable_adapter(priv);
-
- err = ipw2100_hw_phy_off(priv);
- if (err)
- printk(KERN_WARNING DRV_NAME
- ": Error disabling radio %d\n", err);
-
- /*
- * If in D0-standby mode going directly to D3 may cause a
- * PCI bus violation. Therefore we must change out of the D0
- * state.
- *
- * Sending the PREPARE_FOR_POWER_DOWN will restrict the
- * hardware from going into standby mode and will transition
- * out of D0-standby if it is already in that state.
- *
- * STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
- * driver upon completion. Once received, the driver can
- * proceed to the D3 state.
- *
- * Prepare for power down command to fw. This command would
- * take HW out of D0-standby and prepare it for D3 state.
- *
- * Currently FW does not support event notification for this
- * event. Therefore, skip waiting for it. Just wait a fixed
- * 100ms
- */
- IPW_DEBUG_HC("HOST_PRE_POWER_DOWN\n");
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Power down command failed: Error %d\n",
- priv->net_dev->name, err);
- else
- schedule_timeout_uninterruptible(HW_POWER_DOWN_DELAY);
- }
-
- priv->status &= ~STATUS_ENABLED;
-
- /*
- * Set GPIO 3 writable by FW; GPIO 1 writable
- * by driver and enable clock
- */
- ipw2100_hw_set_gpio(priv);
-
- /*
- * Power down adapter. Sequence:
- * 1. Stop master assert (RESET_REG[9]=1)
- * 2. Wait for stop master (RESET_REG[8]==1)
- * 3. S/w reset assert (RESET_REG[7] = 1)
- */
-
- /* Stop master assert */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
-
- /* wait stop master not more than 50 usec.
- * Otherwise return error. */
- for (i = 5; i > 0; i--) {
- udelay(10);
-
- /* Check master stop bit */
- read_register(priv->net_dev, IPW_REG_RESET_REG, ®);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- }
-
- if (i == 0)
- printk(KERN_WARNING DRV_NAME
- ": %s: Could now power down adapter.\n",
- priv->net_dev->name);
-
- /* assert s/w reset */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_SW_RESET);
-
- priv->status &= ~(STATUS_RUNNING | STATUS_STOPPING);
-
- return 0;
-}
-
-static int ipw2100_disable_adapter(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = CARD_DISABLE,
- .host_command_sequence = 0,
- .host_command_length = 0
- };
- int err = 0;
-
- IPW_DEBUG_HC("CARD_DISABLE\n");
-
- if (!(priv->status & STATUS_ENABLED))
- return 0;
-
- /* Make sure we clear the associated state */
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
-
- if (!priv->stop_hang_check) {
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
- }
-
- mutex_lock(&priv->adapter_mutex);
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": exit - failed to send CARD_DISABLE command\n");
- goto fail_up;
- }
-
- err = ipw2100_wait_for_card_state(priv, IPW_HW_STATE_DISABLED);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": exit - card failed to change to DISABLED\n");
- goto fail_up;
- }
-
- IPW_DEBUG_INFO("TODO: implement scan state machine\n");
-
- fail_up:
- mutex_unlock(&priv->adapter_mutex);
- return err;
-}
-
-static int ipw2100_set_scan_options(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = SET_SCAN_OPTIONS,
- .host_command_sequence = 0,
- .host_command_length = 8
- };
- int err;
-
- IPW_DEBUG_INFO("enter\n");
-
- IPW_DEBUG_SCAN("setting scan options\n");
-
- cmd.host_command_parameters[0] = 0;
-
- if (!(priv->config & CFG_ASSOCIATE))
- cmd.host_command_parameters[0] |= IPW_SCAN_NOASSOCIATE;
- if ((priv->ieee->sec.flags & SEC_ENABLED) && priv->ieee->sec.enabled)
- cmd.host_command_parameters[0] |= IPW_SCAN_MIXED_CELL;
- if (priv->config & CFG_PASSIVE_SCAN)
- cmd.host_command_parameters[0] |= IPW_SCAN_PASSIVE;
-
- cmd.host_command_parameters[1] = priv->channel_mask;
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- IPW_DEBUG_HC("SET_SCAN_OPTIONS 0x%04X\n",
- cmd.host_command_parameters[0]);
-
- return err;
-}
-
-static int ipw2100_start_scan(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = BROADCAST_SCAN,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- IPW_DEBUG_HC("START_SCAN\n");
-
- cmd.host_command_parameters[0] = 0;
-
- /* No scanning if in monitor mode */
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- return 1;
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan requested while already in scan...\n");
- return 0;
- }
-
- IPW_DEBUG_INFO("enter\n");
-
- /* Not clearing here; doing so makes iwlist always return nothing...
- *
- * We should modify the table logic to use aging tables vs. clearing
- * the table on each scan start.
- */
- IPW_DEBUG_SCAN("starting scan\n");
-
- priv->status |= STATUS_SCANNING;
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- priv->status &= ~STATUS_SCANNING;
-
- IPW_DEBUG_INFO("exit\n");
-
- return err;
-}
-
-static const struct libipw_geo ipw_geos[] = {
- { /* Restricted */
- "---",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14}},
- },
-};
-
-static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
-{
- unsigned long flags;
- int err = 0;
- u32 lock;
- u32 ord_len = sizeof(lock);
-
- /* Age scan list entries found before suspend */
- if (priv->suspend_time) {
- libipw_networks_age(priv->ieee, priv->suspend_time);
- priv->suspend_time = 0;
- }
-
- /* Quiet if manually disabled. */
- if (priv->status & STATUS_RF_KILL_SW) {
- IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
- "switch\n", priv->net_dev->name);
- return 0;
- }
-
- /* the ipw2100 hardware really doesn't want power management delays
- * longer than 175usec
- */
- cpu_latency_qos_update_request(&ipw2100_pm_qos_req, 175);
-
- /* If the interrupt is enabled, turn it off... */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
-
- /* Reset any fatal_error conditions */
- ipw2100_reset_fatalerror(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- if (priv->status & STATUS_POWERED ||
- (priv->status & STATUS_RESET_PENDING)) {
- /* Power cycle the card ... */
- err = ipw2100_power_cycle_adapter(priv);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Could not cycle adapter.\n",
- priv->net_dev->name);
- goto exit;
- }
- } else
- priv->status |= STATUS_POWERED;
-
- /* Load the firmware, start the clocks, etc. */
- err = ipw2100_start_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to start the firmware.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- ipw2100_initialize_ordinals(priv);
-
- /* Determine capabilities of this particular HW configuration */
- err = ipw2100_get_hw_features(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to determine HW features.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- /* Initialize the geo */
- libipw_set_geo(priv->ieee, &ipw_geos[0]);
- priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
-
- lock = LOCK_NONE;
- err = ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Failed to clear ordinal lock.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- priv->status &= ~STATUS_SCANNING;
-
- if (rf_kill_active(priv)) {
- printk(KERN_INFO "%s: Radio is disabled by RF switch.\n",
- priv->net_dev->name);
-
- if (priv->stop_rf_kill) {
- priv->stop_rf_kill = 0;
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(HZ));
- }
-
- deferred = 1;
- }
-
- /* Turn on the interrupt so that commands can be processed */
- ipw2100_enable_interrupts(priv);
-
- /* Send all of the commands that must be sent prior to
- * HOST_COMPLETE */
- err = ipw2100_adapter_setup(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Failed to start the card.\n",
- priv->net_dev->name);
- goto exit;
- }
-
- if (!deferred) {
- /* Enable the adapter - sends HOST_COMPLETE */
- err = ipw2100_enable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: failed in call to enable adapter.\n",
- priv->net_dev->name);
- ipw2100_hw_stop_adapter(priv);
- goto exit;
- }
-
- /* Start a scan . . . */
- ipw2100_set_scan_options(priv);
- ipw2100_start_scan(priv);
- }
-
- exit:
- return err;
-}
-
-static void ipw2100_down(struct ipw2100_priv *priv)
-{
- unsigned long flags;
- union iwreq_data wrqu = {
- .ap_addr = {
- .sa_family = ARPHRD_ETHER}
- };
- int associated = priv->status & STATUS_ASSOCIATED;
-
- /* Kill the RF switch timer */
- if (!priv->stop_rf_kill) {
- priv->stop_rf_kill = 1;
- cancel_delayed_work(&priv->rf_kill);
- }
-
- /* Kill the firmware hang check timer */
- if (!priv->stop_hang_check) {
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
- }
-
- /* Kill any pending resets */
- if (priv->status & STATUS_RESET_PENDING)
- cancel_delayed_work(&priv->reset_work);
-
- /* Make sure the interrupt is on so that FW commands will be
- * processed correctly */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- if (ipw2100_hw_stop_adapter(priv))
- printk(KERN_ERR DRV_NAME ": %s: Error stopping adapter.\n",
- priv->net_dev->name);
-
- /* Do not disable the interrupt until _after_ we disable
- * the adaptor. Otherwise the CARD_DISABLE command will never
- * be ack'd by the firmware */
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- cpu_latency_qos_update_request(&ipw2100_pm_qos_req,
- PM_QOS_DEFAULT_VALUE);
-
- /* We have to signal any supplicant if we are disassociating */
- if (associated)
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
-}
-
-static int ipw2100_wdev_init(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct wireless_dev *wdev = &priv->ieee->wdev;
- int i;
-
- memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
-
- /* fill-out priv->ieee->bg_band */
- if (geo->bg_channels) {
- struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
-
- bg_band->band = NL80211_BAND_2GHZ;
- bg_band->n_channels = geo->bg_channels;
- bg_band->channels = kcalloc(geo->bg_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!bg_band->channels) {
- ipw2100_down(priv);
- return -ENOMEM;
- }
- /* translate geo->bg to bg_band.channels */
- for (i = 0; i < geo->bg_channels; i++) {
- bg_band->channels[i].band = NL80211_BAND_2GHZ;
- bg_band->channels[i].center_freq = geo->bg[i].freq;
- bg_band->channels[i].hw_value = geo->bg[i].channel;
- bg_band->channels[i].max_power = geo->bg[i].max_power;
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- bg_band->bitrates = ipw2100_bg_rates;
- bg_band->n_bitrates = RATE_COUNT;
-
- wdev->wiphy->bands[NL80211_BAND_2GHZ] = bg_band;
- }
-
- wdev->wiphy->cipher_suites = ipw_cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
-
- set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
- if (wiphy_register(wdev->wiphy))
- return -EIO;
- return 0;
-}
-
-static void ipw2100_reset_adapter(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, reset_work.work);
- unsigned long flags;
- union iwreq_data wrqu = {
- .ap_addr = {
- .sa_family = ARPHRD_ETHER}
- };
- int associated = priv->status & STATUS_ASSOCIATED;
-
- spin_lock_irqsave(&priv->low_lock, flags);
- IPW_DEBUG_INFO(": %s: Restarting adapter.\n", priv->net_dev->name);
- priv->resets++;
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- priv->status |= STATUS_SECURITY_UPDATED;
-
- /* Force a power cycle even if interface hasn't been opened
- * yet */
- cancel_delayed_work(&priv->reset_work);
- priv->status |= STATUS_RESET_PENDING;
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- mutex_lock(&priv->action_mutex);
- /* stop timed checks so that they don't interfere with reset */
- priv->stop_hang_check = 1;
- cancel_delayed_work(&priv->hang_check);
-
- /* We have to signal any supplicant if we are disassociating */
- if (associated)
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-
- ipw2100_up(priv, 0);
- mutex_unlock(&priv->action_mutex);
-
-}
-
-static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
-{
-
-#define MAC_ASSOCIATION_READ_DELAY (HZ)
- int ret;
- unsigned int len, essid_len;
- char essid[IW_ESSID_MAX_SIZE];
- u32 txrate;
- u32 chan;
- char *txratename;
- u8 bssid[ETH_ALEN];
-
- /*
- * TBD: BSSID is usually 00:00:00:00:00:00 here and not
- * an actual MAC of the AP. Seems like FW sets this
- * address too late. Read it later and expose through
- * /proc or schedule a later task to query and update
- */
-
- essid_len = IW_ESSID_MAX_SIZE;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID,
- essid, &essid_len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
-
- len = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &txrate, &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
-
- len = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
- len = ETH_ALEN;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid,
- &len);
- if (ret) {
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
- return;
- }
- memcpy(priv->ieee->bssid, bssid, ETH_ALEN);
-
- switch (txrate) {
- case TX_RATE_1_MBIT:
- txratename = "1Mbps";
- break;
- case TX_RATE_2_MBIT:
- txratename = "2Mbsp";
- break;
- case TX_RATE_5_5_MBIT:
- txratename = "5.5Mbps";
- break;
- case TX_RATE_11_MBIT:
- txratename = "11Mbps";
- break;
- default:
- IPW_DEBUG_INFO("Unknown rate: %d\n", txrate);
- txratename = "unknown rate";
- break;
- }
-
- IPW_DEBUG_INFO("%s: Associated with '%*pE' at %s, channel %d (BSSID=%pM)\n",
- priv->net_dev->name, essid_len, essid,
- txratename, chan, bssid);
-
- /* now we copy read ssid into dev */
- if (!(priv->config & CFG_STATIC_ESSID)) {
- priv->essid_len = min((u8) essid_len, (u8) IW_ESSID_MAX_SIZE);
- memcpy(priv->essid, essid, priv->essid_len);
- }
- priv->channel = chan;
- memcpy(priv->bssid, bssid, ETH_ALEN);
-
- priv->status |= STATUS_ASSOCIATING;
- priv->connect_start = ktime_get_boottime_seconds();
-
- schedule_delayed_work(&priv->wx_event_work, HZ / 10);
-}
-
-static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid,
- int length, int batch_mode)
-{
- int ssid_len = min(length, IW_ESSID_MAX_SIZE);
- struct host_command cmd = {
- .host_command = SSID,
- .host_command_sequence = 0,
- .host_command_length = ssid_len
- };
- int err;
-
- IPW_DEBUG_HC("SSID: '%*pE'\n", ssid_len, essid);
-
- if (ssid_len)
- memcpy(cmd.host_command_parameters, essid, ssid_len);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- /* Bug in FW currently doesn't honor bit 0 in SET_SCAN_OPTIONS to
- * disable auto association -- so we cheat by setting a bogus SSID */
- if (!ssid_len && !(priv->config & CFG_ASSOCIATE)) {
- int i;
- u8 *bogus = (u8 *) cmd.host_command_parameters;
- for (i = 0; i < IW_ESSID_MAX_SIZE; i++)
- bogus[i] = 0x18 + i;
- cmd.host_command_length = IW_ESSID_MAX_SIZE;
- }
-
- /* NOTE: We always send the SSID command even if the provided ESSID is
- * the same as what we currently think is set. */
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (!err) {
- memset(priv->essid + ssid_len, 0, IW_ESSID_MAX_SIZE - ssid_len);
- memcpy(priv->essid, essid, ssid_len);
- priv->essid_len = ssid_len;
- }
-
- if (!batch_mode) {
- if (ipw2100_enable_adapter(priv))
- err = -EIO;
- }
-
- return err;
-}
-
-static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
- "disassociated: '%*pE' %pM\n", priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
-
- if (priv->status & STATUS_STOPPING) {
- IPW_DEBUG_INFO("Card is stopping itself, discard ASSN_LOST.\n");
- return;
- }
-
- eth_zero_addr(priv->bssid);
- eth_zero_addr(priv->ieee->bssid);
-
- netif_carrier_off(priv->net_dev);
- netif_stop_queue(priv->net_dev);
-
- if (!(priv->status & STATUS_RUNNING))
- return;
-
- if (priv->status & STATUS_SECURITY_UPDATED)
- schedule_delayed_work(&priv->security_work, 0);
-
- schedule_delayed_work(&priv->wx_event_work, 0);
-}
-
-static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_INFO("%s: RF Kill state changed to radio OFF.\n",
- priv->net_dev->name);
-
- /* RF_KILL is now enabled (else we wouldn't be here) */
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- priv->status |= STATUS_RF_KILL_HW;
-
- /* Make sure the RF Kill check timer is running */
- priv->stop_rf_kill = 0;
- mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
-}
-
-static void ipw2100_scan_event(struct work_struct *work)
-{
- struct ipw2100_priv *priv = container_of(work, struct ipw2100_priv,
- scan_event.work);
- union iwreq_data wrqu;
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_SCAN("scan complete\n");
- /* Age the scan results... */
- priv->ieee->scans++;
- priv->status &= ~STATUS_SCANNING;
-
- /* Only userspace-requested scan completion events go out immediately */
- if (!priv->user_requested_scan) {
- schedule_delayed_work(&priv->scan_event,
- round_jiffies_relative(msecs_to_jiffies(4000)));
- } else {
- priv->user_requested_scan = 0;
- mod_delayed_work(system_wq, &priv->scan_event, 0);
- }
-}
-
-#ifdef CONFIG_IPW2100_DEBUG
-#define IPW2100_HANDLER(v, f) { v, f, # v }
-struct ipw2100_status_indicator {
- int status;
- void (*cb) (struct ipw2100_priv * priv, u32 status);
- char *name;
-};
-#else
-#define IPW2100_HANDLER(v, f) { v, f }
-struct ipw2100_status_indicator {
- int status;
- void (*cb) (struct ipw2100_priv * priv, u32 status);
-};
-#endif /* CONFIG_IPW2100_DEBUG */
-
-static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status)
-{
- IPW_DEBUG_SCAN("Scanning...\n");
- priv->status |= STATUS_SCANNING;
-}
-
-static const struct ipw2100_status_indicator status_handlers[] = {
- IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL),
- IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL),
- IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated),
- IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost),
- IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL),
- IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete),
- IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL),
- IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL),
- IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill),
- IPW2100_HANDLER(IPW_STATE_DISABLED, NULL),
- IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL),
- IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning),
- IPW2100_HANDLER(-1, NULL)
-};
-
-static void isr_status_change(struct ipw2100_priv *priv, int status)
-{
- int i;
-
- if (status == IPW_STATE_SCANNING &&
- priv->status & STATUS_ASSOCIATED &&
- !(priv->status & STATUS_SCANNING)) {
- IPW_DEBUG_INFO("Scan detected while associated, with "
- "no scan request. Restarting firmware.\n");
-
- /* Wake up any sleeping jobs */
- schedule_reset(priv);
- }
-
- for (i = 0; status_handlers[i].status != -1; i++) {
- if (status == status_handlers[i].status) {
- IPW_DEBUG_NOTIF("Status change: %s\n",
- status_handlers[i].name);
- if (status_handlers[i].cb)
- status_handlers[i].cb(priv, status);
- priv->wstats.status = status;
- return;
- }
- }
-
- IPW_DEBUG_NOTIF("unknown status received: %04x\n", status);
-}
-
-static void isr_rx_complete_command(struct ipw2100_priv *priv,
- struct ipw2100_cmd_header *cmd)
-{
-#ifdef CONFIG_IPW2100_DEBUG
- if (cmd->host_command_reg < ARRAY_SIZE(command_types)) {
- IPW_DEBUG_HC("Command completed '%s (%d)'\n",
- command_types[cmd->host_command_reg],
- cmd->host_command_reg);
- }
-#endif
- if (cmd->host_command_reg == HOST_COMPLETE)
- priv->status |= STATUS_ENABLED;
-
- if (cmd->host_command_reg == CARD_DISABLE)
- priv->status &= ~STATUS_ENABLED;
-
- priv->status &= ~STATUS_CMD_ACTIVE;
-
- wake_up_interruptible(&priv->wait_command_queue);
-}
-
-#ifdef CONFIG_IPW2100_DEBUG
-static const char *frame_types[] = {
- "COMMAND_STATUS_VAL",
- "STATUS_CHANGE_VAL",
- "P80211_DATA_VAL",
- "P8023_DATA_VAL",
- "HOST_NOTIFICATION_VAL"
-};
-#endif
-
-static int ipw2100_alloc_skb(struct ipw2100_priv *priv,
- struct ipw2100_rx_packet *packet)
-{
- packet->skb = dev_alloc_skb(sizeof(struct ipw2100_rx));
- if (!packet->skb)
- return -ENOMEM;
-
- packet->rxp = (struct ipw2100_rx *)packet->skb->data;
- packet->dma_addr = dma_map_single(&priv->pci_dev->dev,
- packet->skb->data,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
- if (dma_mapping_error(&priv->pci_dev->dev, packet->dma_addr)) {
- dev_kfree_skb(packet->skb);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-#define SEARCH_ERROR 0xffffffff
-#define SEARCH_FAIL 0xfffffffe
-#define SEARCH_SUCCESS 0xfffffff0
-#define SEARCH_DISCARD 0
-#define SEARCH_SNAPSHOT 1
-
-#define SNAPSHOT_ADDR(ofs) (priv->snapshot[((ofs) >> 12) & 0xff] + ((ofs) & 0xfff))
-static void ipw2100_snapshot_free(struct ipw2100_priv *priv)
-{
- int i;
- if (!priv->snapshot[0])
- return;
- for (i = 0; i < 0x30; i++)
- kfree(priv->snapshot[i]);
- priv->snapshot[0] = NULL;
-}
-
-#ifdef IPW2100_DEBUG_C3
-static int ipw2100_snapshot_alloc(struct ipw2100_priv *priv)
-{
- int i;
- if (priv->snapshot[0])
- return 1;
- for (i = 0; i < 0x30; i++) {
- priv->snapshot[i] = kmalloc(0x1000, GFP_ATOMIC);
- if (!priv->snapshot[i]) {
- IPW_DEBUG_INFO("%s: Error allocating snapshot "
- "buffer %d\n", priv->net_dev->name, i);
- while (i > 0)
- kfree(priv->snapshot[--i]);
- priv->snapshot[0] = NULL;
- return 0;
- }
- }
-
- return 1;
-}
-
-static u32 ipw2100_match_buf(struct ipw2100_priv *priv, u8 * in_buf,
- size_t len, int mode)
-{
- u32 i, j;
- u32 tmp;
- u8 *s, *d;
- u32 ret;
-
- s = in_buf;
- if (mode == SEARCH_SNAPSHOT) {
- if (!ipw2100_snapshot_alloc(priv))
- mode = SEARCH_DISCARD;
- }
-
- for (ret = SEARCH_FAIL, i = 0; i < 0x30000; i += 4) {
- read_nic_dword(priv->net_dev, i, &tmp);
- if (mode == SEARCH_SNAPSHOT)
- *(u32 *) SNAPSHOT_ADDR(i) = tmp;
- if (ret == SEARCH_FAIL) {
- d = (u8 *) & tmp;
- for (j = 0; j < 4; j++) {
- if (*s != *d) {
- s = in_buf;
- continue;
- }
-
- s++;
- d++;
-
- if ((s - in_buf) == len)
- ret = (i + j) - len + 1;
- }
- } else if (mode == SEARCH_DISCARD)
- return ret;
- }
-
- return ret;
-}
-#endif
-
-/*
- *
- * 0) Disconnect the SKB from the firmware (just unmap)
- * 1) Pack the ETH header into the SKB
- * 2) Pass the SKB to the network stack
- *
- * When packet is provided by the firmware, it contains the following:
- *
- * . libipw_hdr
- * . libipw_snap_hdr
- *
- * The size of the constructed ethernet
- *
- */
-#ifdef IPW2100_RX_DEBUG
-static u8 packet_data[IPW_RX_NIC_BUFFER_LENGTH];
-#endif
-
-static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
-{
-#ifdef IPW2100_DEBUG_C3
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- u32 match, reg;
- int j;
-#endif
-
- IPW_DEBUG_INFO(": PCI latency error detected at 0x%04zX.\n",
- i * sizeof(struct ipw2100_status));
-
-#ifdef IPW2100_DEBUG_C3
- /* Halt the firmware so we can get a good image */
- write_register(priv->net_dev, IPW_REG_RESET_REG,
- IPW_AUX_HOST_RESET_REG_STOP_MASTER);
- j = 5;
- do {
- udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY);
- read_register(priv->net_dev, IPW_REG_RESET_REG, ®);
-
- if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED)
- break;
- } while (j--);
-
- match = ipw2100_match_buf(priv, (u8 *) status,
- sizeof(struct ipw2100_status),
- SEARCH_SNAPSHOT);
- if (match < SEARCH_SUCCESS)
- IPW_DEBUG_INFO("%s: DMA status match in Firmware at "
- "offset 0x%06X, length %d:\n",
- priv->net_dev->name, match,
- sizeof(struct ipw2100_status));
- else
- IPW_DEBUG_INFO("%s: No DMA status match in "
- "Firmware.\n", priv->net_dev->name);
-
- printk_buf((u8 *) priv->status_queue.drv,
- sizeof(struct ipw2100_status) * RX_QUEUE_LENGTH);
-#endif
-
- priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
- priv->net_dev->stats.rx_errors++;
- schedule_reset(priv);
-}
-
-static void isr_rx(struct ipw2100_priv *priv, int i,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- IPW_DEBUG_RX("Handler...\n");
-
- if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
- IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
- " Dropping.\n",
- dev->name,
- status->frame_size, skb_tailroom(packet->skb));
- dev->stats.rx_errors++;
- return;
- }
-
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR &&
- !(priv->status & STATUS_ASSOCIATED))) {
- IPW_DEBUG_DROP("Dropping packet while not associated.\n");
- priv->wstats.discard.misc++;
- return;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
-
- skb_put(packet->skb, status->frame_size);
-
-#ifdef IPW2100_RX_DEBUG
- /* Make a copy of the frame so we can dump it to the logs if
- * libipw_rx fails */
- skb_copy_from_linear_data(packet->skb, packet_data,
- min_t(u32, status->frame_size,
- IPW_RX_NIC_BUFFER_LENGTH));
-#endif
-
- if (!libipw_rx(priv->ieee, packet->skb, stats)) {
-#ifdef IPW2100_RX_DEBUG
- IPW_DEBUG_DROP("%s: Non consumed packet:\n",
- dev->name);
- printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
-#endif
- dev->stats.rx_errors++;
-
- /* libipw_rx failed, so it didn't free the SKB */
- dev_kfree_skb_any(packet->skb);
- packet->skb = NULL;
- }
-
- /* We need to allocate a new SKB and attach it to the RDB. */
- if (unlikely(ipw2100_alloc_skb(priv, packet))) {
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Unable to allocate SKB onto RBD ring - disabling "
- "adapter.\n", dev->name);
- /* TODO: schedule adapter shutdown */
- IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
- }
-
- /* Update the RDB entry */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
-}
-
-#ifdef CONFIG_IPW2100_MONITOR
-
-static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- /* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE */
- struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
- s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
- } *ipw_rt;
-
- IPW_DEBUG_RX("Handler...\n");
-
- if (unlikely(status->frame_size > skb_tailroom(packet->skb) -
- sizeof(struct ipw_rt_hdr))) {
- IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
- " Dropping.\n",
- dev->name,
- status->frame_size,
- skb_tailroom(packet->skb));
- dev->stats.rx_errors++;
- return;
- }
-
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- if (unlikely(priv->config & CFG_CRC_CHECK &&
- status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
- IPW_DEBUG_RX("CRC error in packet. Dropping.\n");
- dev->stats.rx_errors++;
- return;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx), DMA_FROM_DEVICE);
- memmove(packet->skb->data + sizeof(struct ipw_rt_hdr),
- packet->skb->data, status->frame_size);
-
- ipw_rt = (struct ipw_rt_hdr *) packet->skb->data;
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total hdr+data */
-
- ipw_rt->rt_hdr.it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL);
-
- ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM;
-
- skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
-
- if (!libipw_rx(priv->ieee, packet->skb, stats)) {
- dev->stats.rx_errors++;
-
- /* libipw_rx failed, so it didn't free the SKB */
- dev_kfree_skb_any(packet->skb);
- packet->skb = NULL;
- }
-
- /* We need to allocate a new SKB and attach it to the RDB. */
- if (unlikely(ipw2100_alloc_skb(priv, packet))) {
- IPW_DEBUG_WARNING(
- "%s: Unable to allocate SKB onto RBD ring - disabling "
- "adapter.\n", dev->name);
- /* TODO: schedule adapter shutdown */
- IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
- }
-
- /* Update the RDB entry */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
-}
-
-#endif
-
-static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i)
-{
- struct ipw2100_status *status = &priv->status_queue.drv[i];
- struct ipw2100_rx *u = priv->rx_buffers[i].rxp;
- u16 frame_type = status->status_fields & STATUS_TYPE_MASK;
-
- switch (frame_type) {
- case COMMAND_STATUS_VAL:
- return (status->frame_size != sizeof(u->rx_data.command));
- case STATUS_CHANGE_VAL:
- return (status->frame_size != sizeof(u->rx_data.status));
- case HOST_NOTIFICATION_VAL:
- return (status->frame_size < sizeof(u->rx_data.notification));
- case P80211_DATA_VAL:
- case P8023_DATA_VAL:
-#ifdef CONFIG_IPW2100_MONITOR
- return 0;
-#else
- switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
- case IEEE80211_FTYPE_MGMT:
- case IEEE80211_FTYPE_CTL:
- return 0;
- case IEEE80211_FTYPE_DATA:
- return (status->frame_size >
- IPW_MAX_802_11_PAYLOAD_LENGTH);
- }
-#endif
- }
-
- return 1;
-}
-
-/*
- * ipw2100 interrupts are disabled at this point, and the ISR
- * is the only code that calls this method. So, we do not need
- * to play with any locks.
- *
- * RX Queue works as follows:
- *
- * Read index - firmware places packet in entry identified by the
- * Read index and advances Read index. In this manner,
- * Read index will always point to the next packet to
- * be filled--but not yet valid.
- *
- * Write index - driver fills this entry with an unused RBD entry.
- * This entry has not filled by the firmware yet.
- *
- * In between the W and R indexes are the RBDs that have been received
- * but not yet processed.
- *
- * The process of handling packets will start at WRITE + 1 and advance
- * until it reaches the READ index.
- *
- * The WRITE index is cached in the variable 'priv->rx_queue.next'.
- *
- */
-static void __ipw2100_rx_process(struct ipw2100_priv *priv)
-{
- struct ipw2100_bd_queue *rxq = &priv->rx_queue;
- struct ipw2100_status_queue *sq = &priv->status_queue;
- struct ipw2100_rx_packet *packet;
- u16 frame_type;
- u32 r, w, i, s;
- struct ipw2100_rx *u;
- struct libipw_rx_stats stats = {
- .mac_time = jiffies,
- };
-
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_READ_INDEX, &r);
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, &w);
-
- if (r >= rxq->entries) {
- IPW_DEBUG_RX("exit - bad read index\n");
- return;
- }
-
- i = (rxq->next + 1) % rxq->entries;
- s = i;
- while (i != r) {
- /* IPW_DEBUG_RX("r = %d : w = %d : processing = %d\n",
- r, rxq->next, i); */
-
- packet = &priv->rx_buffers[i];
-
- /* Sync the DMA for the RX buffer so CPU is sure to get
- * the correct values */
- dma_sync_single_for_cpu(&priv->pci_dev->dev, packet->dma_addr,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
-
- if (unlikely(ipw2100_corruption_check(priv, i))) {
- ipw2100_corruption_detected(priv, i);
- goto increment;
- }
-
- u = packet->rxp;
- frame_type = sq->drv[i].status_fields & STATUS_TYPE_MASK;
- stats.rssi = sq->drv[i].rssi + IPW2100_RSSI_TO_DBM;
- stats.len = sq->drv[i].frame_size;
-
- stats.mask = 0;
- if (stats.rssi != 0)
- stats.mask |= LIBIPW_STATMASK_RSSI;
- stats.freq = LIBIPW_24GHZ_BAND;
-
- IPW_DEBUG_RX("%s: '%s' frame type received (%d).\n",
- priv->net_dev->name, frame_types[frame_type],
- stats.len);
-
- switch (frame_type) {
- case COMMAND_STATUS_VAL:
- /* Reset Rx watchdog */
- isr_rx_complete_command(priv, &u->rx_data.command);
- break;
-
- case STATUS_CHANGE_VAL:
- isr_status_change(priv, u->rx_data.status);
- break;
-
- case P80211_DATA_VAL:
- case P8023_DATA_VAL:
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- isr_rx_monitor(priv, i, &stats);
- break;
- }
-#endif
- if (stats.len < sizeof(struct libipw_hdr_3addr))
- break;
- switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) {
- case IEEE80211_FTYPE_MGMT:
- libipw_rx_mgt(priv->ieee,
- &u->rx_data.header, &stats);
- break;
-
- case IEEE80211_FTYPE_CTL:
- break;
-
- case IEEE80211_FTYPE_DATA:
- isr_rx(priv, i, &stats);
- break;
-
- }
- break;
- }
-
- increment:
- /* clear status field associated with this RBD */
- rxq->drv[i].status.info.field = 0;
-
- i = (i + 1) % rxq->entries;
- }
-
- if (i != s) {
- /* backtrack one entry, wrapping to end if at 0 */
- rxq->next = (i ? i : rxq->entries) - 1;
-
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_RX_WRITE_INDEX, rxq->next);
- }
-}
-
-/*
- * __ipw2100_tx_process
- *
- * This routine will determine whether the next packet on
- * the fw_pend_list has been processed by the firmware yet.
- *
- * If not, then it does nothing and returns.
- *
- * If so, then it removes the item from the fw_pend_list, frees
- * any associated storage, and places the item back on the
- * free list of its source (either msg_free_list or tx_free_list)
- *
- * TX Queue works as follows:
- *
- * Read index - points to the next TBD that the firmware will
- * process. The firmware will read the data, and once
- * done processing, it will advance the Read index.
- *
- * Write index - driver fills this entry with an constructed TBD
- * entry. The Write index is not advanced until the
- * packet has been configured.
- *
- * In between the W and R indexes are the TBDs that have NOT been
- * processed. Lagging behind the R index are packets that have
- * been processed but have not been freed by the driver.
- *
- * In order to free old storage, an internal index will be maintained
- * that points to the next packet to be freed. When all used
- * packets have been freed, the oldest index will be the same as the
- * firmware's read index.
- *
- * The OLDEST index is cached in the variable 'priv->tx_queue.oldest'
- *
- * Because the TBD structure can not contain arbitrary data, the
- * driver must keep an internal queue of cached allocations such that
- * it can put that data back into the tx_free_list and msg_free_list
- * for use by future command and data packets.
- *
- */
-static int __ipw2100_tx_process(struct ipw2100_priv *priv)
-{
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- int descriptors_used;
- int e, i;
- u32 r, w, frag_num = 0;
-
- if (list_empty(&priv->fw_pend_list))
- return 0;
-
- element = priv->fw_pend_list.next;
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
- tbd = &txq->drv[packet->index];
-
- /* Determine how many TBD entries must be finished... */
- switch (packet->type) {
- case COMMAND:
- /* COMMAND uses only one slot; don't advance */
- descriptors_used = 1;
- e = txq->oldest;
- break;
-
- case DATA:
- /* DATA uses two slots; advance and loop position. */
- descriptors_used = tbd->num_fragments;
- frag_num = tbd->num_fragments - 1;
- e = txq->oldest + frag_num;
- e %= txq->entries;
- break;
-
- default:
- printk(KERN_WARNING DRV_NAME ": %s: Bad fw_pend_list entry!\n",
- priv->net_dev->name);
- return 0;
- }
-
- /* if the last TBD is not done by NIC yet, then packet is
- * not ready to be released.
- *
- */
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
- &r);
- read_register(priv->net_dev, IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- &w);
- if (w != txq->next)
- printk(KERN_WARNING DRV_NAME ": %s: write index mismatch\n",
- priv->net_dev->name);
-
- /*
- * txq->next is the index of the last packet written txq->oldest is
- * the index of the r is the index of the next packet to be read by
- * firmware
- */
-
- /*
- * Quick graphic to help you visualize the following
- * if / else statement
- *
- * ===>| s---->|===============
- * e>|
- * | a | b | c | d | e | f | g | h | i | j | k | l
- * r---->|
- * w
- *
- * w - updated by driver
- * r - updated by firmware
- * s - start of oldest BD entry (txq->oldest)
- * e - end of oldest BD entry
- *
- */
- if (!((r <= w && (e < r || e >= w)) || (e < r && e >= w))) {
- IPW_DEBUG_TX("exit - no processed packets ready to release.\n");
- return 0;
- }
-
- list_del(element);
- DEC_STAT(&priv->fw_pend_stat);
-
-#ifdef CONFIG_IPW2100_DEBUG
- {
- i = txq->oldest;
- IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32) (txq->nic + i * sizeof(struct ipw2100_bd)),
- txq->drv[i].host_addr, txq->drv[i].buf_length);
-
- if (packet->type == DATA) {
- i = (i + 1) % txq->entries;
-
- IPW_DEBUG_TX("TX%d V=%p P=%04X T=%04X L=%d\n", i,
- &txq->drv[i],
- (u32) (txq->nic + i *
- sizeof(struct ipw2100_bd)),
- (u32) txq->drv[i].host_addr,
- txq->drv[i].buf_length);
- }
- }
-#endif
-
- switch (packet->type) {
- case DATA:
- if (txq->drv[txq->oldest].status.info.fields.txType != 0)
- printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
- "Expecting DATA TBD but pulled "
- "something else: ids %d=%d.\n",
- priv->net_dev->name, txq->oldest, packet->index);
-
- /* DATA packet; we have to unmap and free the SKB */
- for (i = 0; i < frag_num; i++) {
- tbd = &txq->drv[(packet->index + 1 + i) % txq->entries];
-
- IPW_DEBUG_TX("TX%d P=%08x L=%d\n",
- (packet->index + 1 + i) % txq->entries,
- tbd->host_addr, tbd->buf_length);
-
- dma_unmap_single(&priv->pci_dev->dev, tbd->host_addr,
- tbd->buf_length, DMA_TO_DEVICE);
- }
-
- libipw_txb_free(packet->info.d_struct.txb);
- packet->info.d_struct.txb = NULL;
-
- list_add_tail(element, &priv->tx_free_list);
- INC_STAT(&priv->tx_free_stat);
-
- /* We have a free slot in the Tx queue, so wake up the
- * transmit layer if it is stopped. */
- if (priv->status & STATUS_ASSOCIATED)
- netif_wake_queue(priv->net_dev);
-
- /* A packet was processed by the hardware, so update the
- * watchdog */
- netif_trans_update(priv->net_dev);
-
- break;
-
- case COMMAND:
- if (txq->drv[txq->oldest].status.info.fields.txType != 1)
- printk(KERN_WARNING DRV_NAME ": %s: Queue mismatch. "
- "Expecting COMMAND TBD but pulled "
- "something else: ids %d=%d.\n",
- priv->net_dev->name, txq->oldest, packet->index);
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (packet->info.c_struct.cmd->host_command_reg <
- ARRAY_SIZE(command_types))
- IPW_DEBUG_TX("Command '%s (%d)' processed: %d.\n",
- command_types[packet->info.c_struct.cmd->
- host_command_reg],
- packet->info.c_struct.cmd->
- host_command_reg,
- packet->info.c_struct.cmd->cmd_status_reg);
-#endif
-
- list_add_tail(element, &priv->msg_free_list);
- INC_STAT(&priv->msg_free_stat);
- break;
- }
-
- /* advance oldest used TBD pointer to start of next entry */
- txq->oldest = (e + 1) % txq->entries;
- /* increase available TBDs number */
- txq->available += descriptors_used;
- SET_STAT(&priv->txq_stat, txq->available);
-
- IPW_DEBUG_TX("packet latency (send to process) %ld jiffies\n",
- jiffies - packet->jiffy_start);
-
- return (!list_empty(&priv->fw_pend_list));
-}
-
-static inline void __ipw2100_tx_complete(struct ipw2100_priv *priv)
-{
- int i = 0;
-
- while (__ipw2100_tx_process(priv) && i < 200)
- i++;
-
- if (i == 200) {
- printk(KERN_WARNING DRV_NAME ": "
- "%s: Driver is running slow (%d iters).\n",
- priv->net_dev->name, i);
- }
-}
-
-static void ipw2100_tx_send_commands(struct ipw2100_priv *priv)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- int next = txq->next;
-
- while (!list_empty(&priv->msg_pend_list)) {
- /* if there isn't enough space in TBD queue, then
- * don't stuff a new one in.
- * NOTE: 3 are needed as a command will take one,
- * and there is a minimum of 2 that must be
- * maintained between the r and w indexes
- */
- if (txq->available <= 3) {
- IPW_DEBUG_TX("no room in tx_queue\n");
- break;
- }
-
- element = priv->msg_pend_list.next;
- list_del(element);
- DEC_STAT(&priv->msg_pend_stat);
-
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- IPW_DEBUG_TX("using TBD at virt=%p, phys=%04X\n",
- &txq->drv[txq->next],
- (u32) (txq->nic + txq->next *
- sizeof(struct ipw2100_bd)));
-
- packet->index = txq->next;
-
- tbd = &txq->drv[txq->next];
-
- /* initialize TBD */
- tbd->host_addr = packet->info.c_struct.cmd_phys;
- tbd->buf_length = sizeof(struct ipw2100_cmd_header);
- /* not marking number of fragments causes problems
- * with f/w debug version */
- tbd->num_fragments = 1;
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_COMMAND |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
-
- /* update TBD queue counters */
- txq->next++;
- txq->next %= txq->entries;
- txq->available--;
- DEC_STAT(&priv->txq_stat);
-
- list_add_tail(element, &priv->fw_pend_list);
- INC_STAT(&priv->fw_pend_stat);
- }
-
- if (txq->next != next) {
- /* kick off the DMA by notifying firmware the
- * write index has moved; make sure TBD stores are sync'd */
- wmb();
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- txq->next);
- }
-}
-
-/*
- * ipw2100_tx_send_data
- *
- */
-static void ipw2100_tx_send_data(struct ipw2100_priv *priv)
-{
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- struct ipw2100_bd_queue *txq = &priv->tx_queue;
- struct ipw2100_bd *tbd;
- int next = txq->next;
- int i = 0;
- struct ipw2100_data_header *ipw_hdr;
- struct libipw_hdr_3addr *hdr;
-
- while (!list_empty(&priv->tx_pend_list)) {
- /* if there isn't enough space in TBD queue, then
- * don't stuff a new one in.
- * NOTE: 4 are needed as a data will take two,
- * and there is a minimum of 2 that must be
- * maintained between the r and w indexes
- */
- element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- if (unlikely(1 + packet->info.d_struct.txb->nr_frags >
- IPW_MAX_BDS)) {
- /* TODO: Support merging buffers if more than
- * IPW_MAX_BDS are used */
- IPW_DEBUG_INFO("%s: Maximum BD threshold exceeded. "
- "Increase fragmentation level.\n",
- priv->net_dev->name);
- }
-
- if (txq->available <= 3 + packet->info.d_struct.txb->nr_frags) {
- IPW_DEBUG_TX("no room in tx_queue\n");
- break;
- }
-
- list_del(element);
- DEC_STAT(&priv->tx_pend_stat);
-
- tbd = &txq->drv[txq->next];
-
- packet->index = txq->next;
-
- ipw_hdr = packet->info.d_struct.data;
- hdr = (struct libipw_hdr_3addr *)packet->info.d_struct.txb->
- fragments[0]->data;
-
- if (priv->ieee->iw_mode == IW_MODE_INFRA) {
- /* To DS: Addr1 = BSSID, Addr2 = SA,
- Addr3 = DA */
- memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(ipw_hdr->dst_addr, hdr->addr3, ETH_ALEN);
- } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA,
- Addr3 = BSSID */
- memcpy(ipw_hdr->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(ipw_hdr->dst_addr, hdr->addr1, ETH_ALEN);
- }
-
- ipw_hdr->host_command_reg = SEND;
- ipw_hdr->host_command_reg1 = 0;
-
- /* For now we only support host based encryption */
- ipw_hdr->needs_encryption = 0;
- ipw_hdr->encrypted = packet->info.d_struct.txb->encrypted;
- if (packet->info.d_struct.txb->nr_frags > 1)
- ipw_hdr->fragment_size =
- packet->info.d_struct.txb->frag_size -
- LIBIPW_3ADDR_LEN;
- else
- ipw_hdr->fragment_size = 0;
-
- tbd->host_addr = packet->info.d_struct.data_phys;
- tbd->buf_length = sizeof(struct ipw2100_data_header);
- tbd->num_fragments = 1 + packet->info.d_struct.txb->nr_frags;
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
- txq->next++;
- txq->next %= txq->entries;
-
- IPW_DEBUG_TX("data header tbd TX%d P=%08x L=%d\n",
- packet->index, tbd->host_addr, tbd->buf_length);
-#ifdef CONFIG_IPW2100_DEBUG
- if (packet->info.d_struct.txb->nr_frags > 1)
- IPW_DEBUG_FRAG("fragment Tx: %d frames\n",
- packet->info.d_struct.txb->nr_frags);
-#endif
-
- for (i = 0; i < packet->info.d_struct.txb->nr_frags; i++) {
- tbd = &txq->drv[txq->next];
- if (i == packet->info.d_struct.txb->nr_frags - 1)
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_INTERRUPT_ENABLE;
- else
- tbd->status.info.field =
- IPW_BD_STATUS_TX_FRAME_802_3 |
- IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT;
-
- tbd->buf_length = packet->info.d_struct.txb->
- fragments[i]->len - LIBIPW_3ADDR_LEN;
-
- tbd->host_addr = dma_map_single(&priv->pci_dev->dev,
- packet->info.d_struct.
- txb->fragments[i]->data +
- LIBIPW_3ADDR_LEN,
- tbd->buf_length,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&priv->pci_dev->dev, tbd->host_addr)) {
- IPW_DEBUG_TX("dma mapping error\n");
- break;
- }
-
- IPW_DEBUG_TX("data frag tbd TX%d P=%08x L=%d\n",
- txq->next, tbd->host_addr,
- tbd->buf_length);
-
- dma_sync_single_for_device(&priv->pci_dev->dev,
- tbd->host_addr,
- tbd->buf_length,
- DMA_TO_DEVICE);
-
- txq->next++;
- txq->next %= txq->entries;
- }
-
- txq->available -= 1 + packet->info.d_struct.txb->nr_frags;
- SET_STAT(&priv->txq_stat, txq->available);
-
- list_add_tail(element, &priv->fw_pend_list);
- INC_STAT(&priv->fw_pend_stat);
- }
-
- if (txq->next != next) {
- /* kick off the DMA by notifying firmware the
- * write index has moved; make sure TBD stores are sync'd */
- write_register(priv->net_dev,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX,
- txq->next);
- }
-}
-
-static void ipw2100_irq_tasklet(struct tasklet_struct *t)
-{
- struct ipw2100_priv *priv = from_tasklet(priv, t, irq_tasklet);
- struct net_device *dev = priv->net_dev;
- unsigned long flags;
- u32 inta, tmp;
-
- spin_lock_irqsave(&priv->low_lock, flags);
- ipw2100_disable_interrupts(priv);
-
- read_register(dev, IPW_REG_INTA, &inta);
-
- IPW_DEBUG_ISR("enter - INTA: 0x%08lX\n",
- (unsigned long)inta & IPW_INTERRUPT_MASK);
-
- priv->in_isr++;
- priv->interrupts++;
-
- /* We do not loop and keep polling for more interrupts as this
- * is frowned upon and doesn't play nicely with other potentially
- * chained IRQs */
- IPW_DEBUG_ISR("INTA: 0x%08lX\n",
- (unsigned long)inta & IPW_INTERRUPT_MASK);
-
- if (inta & IPW2100_INTA_FATAL_ERROR) {
- printk(KERN_WARNING DRV_NAME
- ": Fatal interrupt. Scheduling firmware restart.\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR);
-
- read_nic_dword(dev, IPW_NIC_FATAL_ERROR, &priv->fatal_error);
- IPW_DEBUG_INFO("%s: Fatal error value: 0x%08X\n",
- priv->net_dev->name, priv->fatal_error);
-
- read_nic_dword(dev, IPW_ERROR_ADDR(priv->fatal_error), &tmp);
- IPW_DEBUG_INFO("%s: Fatal error address value: 0x%08X\n",
- priv->net_dev->name, tmp);
-
- /* Wake up any sleeping jobs */
- schedule_reset(priv);
- }
-
- if (inta & IPW2100_INTA_PARITY_ERROR) {
- printk(KERN_ERR DRV_NAME
- ": ***** PARITY ERROR INTERRUPT !!!!\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_PARITY_ERROR);
- }
-
- if (inta & IPW2100_INTA_RX_TRANSFER) {
- IPW_DEBUG_ISR("RX interrupt\n");
-
- priv->rx_interrupts++;
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_RX_TRANSFER);
-
- __ipw2100_rx_process(priv);
- __ipw2100_tx_complete(priv);
- }
-
- if (inta & IPW2100_INTA_TX_TRANSFER) {
- IPW_DEBUG_ISR("TX interrupt\n");
-
- priv->tx_interrupts++;
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_TRANSFER);
-
- __ipw2100_tx_complete(priv);
- ipw2100_tx_send_commands(priv);
- ipw2100_tx_send_data(priv);
- }
-
- if (inta & IPW2100_INTA_TX_COMPLETE) {
- IPW_DEBUG_ISR("TX complete\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_TX_COMPLETE);
-
- __ipw2100_tx_complete(priv);
- }
-
- if (inta & IPW2100_INTA_EVENT_INTERRUPT) {
- /* ipw2100_handle_event(dev); */
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_EVENT_INTERRUPT);
- }
-
- if (inta & IPW2100_INTA_FW_INIT_DONE) {
- IPW_DEBUG_ISR("FW init done interrupt\n");
- priv->inta_other++;
-
- read_register(dev, IPW_REG_INTA, &tmp);
- if (tmp & (IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR)) {
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_FATAL_ERROR |
- IPW2100_INTA_PARITY_ERROR);
- }
-
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE);
- }
-
- if (inta & IPW2100_INTA_STATUS_CHANGE) {
- IPW_DEBUG_ISR("Status change interrupt\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA, IPW2100_INTA_STATUS_CHANGE);
- }
-
- if (inta & IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE) {
- IPW_DEBUG_ISR("slave host mode interrupt\n");
- priv->inta_other++;
- write_register(dev, IPW_REG_INTA,
- IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE);
- }
-
- priv->in_isr--;
- ipw2100_enable_interrupts(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- IPW_DEBUG_ISR("exit\n");
-}
-
-static irqreturn_t ipw2100_interrupt(int irq, void *data)
-{
- struct ipw2100_priv *priv = data;
- u32 inta, inta_mask;
-
- if (!data)
- return IRQ_NONE;
-
- spin_lock(&priv->low_lock);
-
- /* We check to see if we should be ignoring interrupts before
- * we touch the hardware. During ucode load if we try and handle
- * an interrupt we can cause keyboard problems as well as cause
- * the ucode to fail to initialize */
- if (!(priv->status & STATUS_INT_ENABLED)) {
- /* Shared IRQ */
- goto none;
- }
-
- read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask);
- read_register(priv->net_dev, IPW_REG_INTA, &inta);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- printk(KERN_WARNING DRV_NAME ": IRQ INTA == 0xFFFFFFFF\n");
- goto none;
- }
-
- inta &= IPW_INTERRUPT_MASK;
-
- if (!(inta & inta_mask)) {
- /* Shared interrupt */
- goto none;
- }
-
- /* We disable the hardware interrupt here just to prevent unneeded
- * calls to be made. We disable this again within the actual
- * work tasklet, so if another part of the code re-enables the
- * interrupt, that is fine */
- ipw2100_disable_interrupts(priv);
-
- tasklet_schedule(&priv->irq_tasklet);
- spin_unlock(&priv->low_lock);
-
- return IRQ_HANDLED;
- none:
- spin_unlock(&priv->low_lock);
- return IRQ_NONE;
-}
-
-static netdev_tx_t ipw2100_tx(struct libipw_txb *txb,
- struct net_device *dev, int pri)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_INFO("Can not transmit when not connected.\n");
- priv->net_dev->stats.tx_carrier_errors++;
- netif_stop_queue(dev);
- goto fail_unlock;
- }
-
- if (list_empty(&priv->tx_free_list))
- goto fail_unlock;
-
- element = priv->tx_free_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- packet->info.d_struct.txb = txb;
-
- IPW_DEBUG_TX("Sending fragment (%d bytes):\n", txb->fragments[0]->len);
- printk_buf(IPW_DL_TX, txb->fragments[0]->data, txb->fragments[0]->len);
-
- packet->jiffy_start = jiffies;
-
- list_del(element);
- DEC_STAT(&priv->tx_free_stat);
-
- list_add_tail(element, &priv->tx_pend_list);
- INC_STAT(&priv->tx_pend_stat);
-
- ipw2100_tx_send_data(priv);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
- return NETDEV_TX_OK;
-
-fail_unlock:
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&priv->low_lock, flags);
- return NETDEV_TX_BUSY;
-}
-
-static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err = -EINVAL;
- void *v;
- dma_addr_t p;
-
- priv->msg_buffers =
- kmalloc_array(IPW_COMMAND_POOL_SIZE,
- sizeof(struct ipw2100_tx_packet),
- GFP_KERNEL);
- if (!priv->msg_buffers)
- return -ENOMEM;
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
- v = dma_alloc_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header), &p,
- GFP_KERNEL);
- if (!v) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: PCI alloc failed for msg "
- "buffers.\n", priv->net_dev->name);
- err = -ENOMEM;
- break;
- }
-
- priv->msg_buffers[i].type = COMMAND;
- priv->msg_buffers[i].info.c_struct.cmd =
- (struct ipw2100_cmd_header *)v;
- priv->msg_buffers[i].info.c_struct.cmd_phys = p;
- }
-
- if (i == IPW_COMMAND_POOL_SIZE)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header),
- priv->msg_buffers[j].info.c_struct.cmd,
- priv->msg_buffers[j].info.c_struct.cmd_phys);
- }
-
- kfree(priv->msg_buffers);
- priv->msg_buffers = NULL;
-
- return err;
-}
-
-static int ipw2100_msg_initialize(struct ipw2100_priv *priv)
-{
- int i;
-
- INIT_LIST_HEAD(&priv->msg_free_list);
- INIT_LIST_HEAD(&priv->msg_pend_list);
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++)
- list_add_tail(&priv->msg_buffers[i].list, &priv->msg_free_list);
- SET_STAT(&priv->msg_free_stat, i);
-
- return 0;
-}
-
-static void ipw2100_msg_free(struct ipw2100_priv *priv)
-{
- int i;
-
- if (!priv->msg_buffers)
- return;
-
- for (i = 0; i < IPW_COMMAND_POOL_SIZE; i++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_cmd_header),
- priv->msg_buffers[i].info.c_struct.cmd,
- priv->msg_buffers[i].info.c_struct.cmd_phys);
- }
-
- kfree(priv->msg_buffers);
- priv->msg_buffers = NULL;
-}
-
-static ssize_t pci_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct pci_dev *pci_dev = to_pci_dev(d);
- char *out = buf;
- int i, j;
- u32 val;
-
- for (i = 0; i < 16; i++) {
- out += sprintf(out, "[%08X] ", i * 16);
- for (j = 0; j < 16; j += 4) {
- pci_read_config_dword(pci_dev, i * 16 + j, &val);
- out += sprintf(out, "%08X ", val);
- }
- out += sprintf(out, "\n");
- }
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(pci);
-
-static ssize_t cfg_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->config);
-}
-
-static DEVICE_ATTR_RO(cfg);
-
-static ssize_t status_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->status);
-}
-
-static DEVICE_ATTR_RO(status);
-
-static ssize_t capability_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->capability);
-}
-
-static DEVICE_ATTR_RO(capability);
-
-#define IPW2100_REG(x) { IPW_ ##x, #x }
-static const struct {
- u32 addr;
- const char *name;
-} hw_data[] = {
-IPW2100_REG(REG_GP_CNTRL),
- IPW2100_REG(REG_GPIO),
- IPW2100_REG(REG_INTA),
- IPW2100_REG(REG_INTA_MASK), IPW2100_REG(REG_RESET_REG),};
-#define IPW2100_NIC(x, s) { x, #x, s }
-static const struct {
- u32 addr;
- const char *name;
- size_t size;
-} nic_data[] = {
-IPW2100_NIC(IPW2100_CONTROL_REG, 2),
- IPW2100_NIC(0x210014, 1), IPW2100_NIC(0x210000, 1),};
-#define IPW2100_ORD(x, d) { IPW_ORD_ ##x, #x, d }
-static const struct {
- u8 index;
- const char *name;
- const char *desc;
-} ord_data[] = {
-IPW2100_ORD(STAT_TX_HOST_REQUESTS, "requested Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_HOST_COMPLETE,
- "successful Host Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA,
- "successful Directed Tx's (MSDU)"),
- IPW2100_ORD(STAT_TX_DIR_DATA1,
- "successful Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA2,
- "successful Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA5_5,
- "successful Directed Tx's (MSDU) @ 5_5MB"),
- IPW2100_ORD(STAT_TX_DIR_DATA11,
- "successful Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA1,
- "successful Non_Directed Tx's (MSDU) @ 1MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA2,
- "successful Non_Directed Tx's (MSDU) @ 2MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA5_5,
- "successful Non_Directed Tx's (MSDU) @ 5.5MB"),
- IPW2100_ORD(STAT_TX_NODIR_DATA11,
- "successful Non_Directed Tx's (MSDU) @ 11MB"),
- IPW2100_ORD(STAT_NULL_DATA, "successful NULL data Tx's"),
- IPW2100_ORD(STAT_TX_RTS, "successful Tx RTS"),
- IPW2100_ORD(STAT_TX_CTS, "successful Tx CTS"),
- IPW2100_ORD(STAT_TX_ACK, "successful Tx ACK"),
- IPW2100_ORD(STAT_TX_ASSN, "successful Association Tx's"),
- IPW2100_ORD(STAT_TX_ASSN_RESP,
- "successful Association response Tx's"),
- IPW2100_ORD(STAT_TX_REASSN,
- "successful Reassociation Tx's"),
- IPW2100_ORD(STAT_TX_REASSN_RESP,
- "successful Reassociation response Tx's"),
- IPW2100_ORD(STAT_TX_PROBE,
- "probes successfully transmitted"),
- IPW2100_ORD(STAT_TX_PROBE_RESP,
- "probe responses successfully transmitted"),
- IPW2100_ORD(STAT_TX_BEACON, "tx beacon"),
- IPW2100_ORD(STAT_TX_ATIM, "Tx ATIM"),
- IPW2100_ORD(STAT_TX_DISASSN,
- "successful Disassociation TX"),
- IPW2100_ORD(STAT_TX_AUTH, "successful Authentication Tx"),
- IPW2100_ORD(STAT_TX_DEAUTH,
- "successful Deauthentication TX"),
- IPW2100_ORD(STAT_TX_TOTAL_BYTES,
- "Total successful Tx data bytes"),
- IPW2100_ORD(STAT_TX_RETRIES, "Tx retries"),
- IPW2100_ORD(STAT_TX_RETRY1, "Tx retries at 1MBPS"),
- IPW2100_ORD(STAT_TX_RETRY2, "Tx retries at 2MBPS"),
- IPW2100_ORD(STAT_TX_RETRY5_5, "Tx retries at 5.5MBPS"),
- IPW2100_ORD(STAT_TX_RETRY11, "Tx retries at 11MBPS"),
- IPW2100_ORD(STAT_TX_FAILURES, "Tx Failures"),
- IPW2100_ORD(STAT_TX_MAX_TRIES_IN_HOP,
- "times max tries in a hop failed"),
- IPW2100_ORD(STAT_TX_DISASSN_FAIL,
- "times disassociation failed"),
- IPW2100_ORD(STAT_TX_ERR_CTS, "missed/bad CTS frames"),
- IPW2100_ORD(STAT_TX_ERR_ACK, "tx err due to acks"),
- IPW2100_ORD(STAT_RX_HOST, "packets passed to host"),
- IPW2100_ORD(STAT_RX_DIR_DATA, "directed packets"),
- IPW2100_ORD(STAT_RX_DIR_DATA1, "directed packets at 1MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA2, "directed packets at 2MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA5_5,
- "directed packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DIR_DATA11, "directed packets at 11MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA, "nondirected packets"),
- IPW2100_ORD(STAT_RX_NODIR_DATA1,
- "nondirected packets at 1MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA2,
- "nondirected packets at 2MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA5_5,
- "nondirected packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_NODIR_DATA11,
- "nondirected packets at 11MB"),
- IPW2100_ORD(STAT_RX_NULL_DATA, "null data rx's"),
- IPW2100_ORD(STAT_RX_RTS, "Rx RTS"), IPW2100_ORD(STAT_RX_CTS,
- "Rx CTS"),
- IPW2100_ORD(STAT_RX_ACK, "Rx ACK"),
- IPW2100_ORD(STAT_RX_CFEND, "Rx CF End"),
- IPW2100_ORD(STAT_RX_CFEND_ACK, "Rx CF End + CF Ack"),
- IPW2100_ORD(STAT_RX_ASSN, "Association Rx's"),
- IPW2100_ORD(STAT_RX_ASSN_RESP, "Association response Rx's"),
- IPW2100_ORD(STAT_RX_REASSN, "Reassociation Rx's"),
- IPW2100_ORD(STAT_RX_REASSN_RESP,
- "Reassociation response Rx's"),
- IPW2100_ORD(STAT_RX_PROBE, "probe Rx's"),
- IPW2100_ORD(STAT_RX_PROBE_RESP, "probe response Rx's"),
- IPW2100_ORD(STAT_RX_BEACON, "Rx beacon"),
- IPW2100_ORD(STAT_RX_ATIM, "Rx ATIM"),
- IPW2100_ORD(STAT_RX_DISASSN, "disassociation Rx"),
- IPW2100_ORD(STAT_RX_AUTH, "authentication Rx"),
- IPW2100_ORD(STAT_RX_DEAUTH, "deauthentication Rx"),
- IPW2100_ORD(STAT_RX_TOTAL_BYTES,
- "Total rx data bytes received"),
- IPW2100_ORD(STAT_RX_ERR_CRC, "packets with Rx CRC error"),
- IPW2100_ORD(STAT_RX_ERR_CRC1, "Rx CRC errors at 1MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC2, "Rx CRC errors at 2MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC5_5, "Rx CRC errors at 5.5MB"),
- IPW2100_ORD(STAT_RX_ERR_CRC11, "Rx CRC errors at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE1,
- "duplicate rx packets at 1MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE2,
- "duplicate rx packets at 2MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE5_5,
- "duplicate rx packets at 5.5MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE11,
- "duplicate rx packets at 11MB"),
- IPW2100_ORD(STAT_RX_DUPLICATE, "duplicate rx packets"),
- IPW2100_ORD(PERS_DB_LOCK, "locking fw permanent db"),
- IPW2100_ORD(PERS_DB_SIZE, "size of fw permanent db"),
- IPW2100_ORD(PERS_DB_ADDR, "address of fw permanent db"),
- IPW2100_ORD(STAT_RX_INVALID_PROTOCOL,
- "rx frames with invalid protocol"),
- IPW2100_ORD(SYS_BOOT_TIME, "Boot time"),
- IPW2100_ORD(STAT_RX_NO_BUFFER,
- "rx frames rejected due to no buffer"),
- IPW2100_ORD(STAT_RX_MISSING_FRAG,
- "rx frames dropped due to missing fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAG,
- "rx frames dropped due to non-sequential fragment"),
- IPW2100_ORD(STAT_RX_ORPHAN_FRAME,
- "rx frames dropped due to unmatched 1st frame"),
- IPW2100_ORD(STAT_RX_FRAG_AGEOUT,
- "rx frames dropped due to uncompleted frame"),
- IPW2100_ORD(STAT_RX_ICV_ERRORS,
- "ICV errors during decryption"),
- IPW2100_ORD(STAT_PSP_SUSPENSION, "times adapter suspended"),
- IPW2100_ORD(STAT_PSP_BCN_TIMEOUT, "beacon timeout"),
- IPW2100_ORD(STAT_PSP_POLL_TIMEOUT,
- "poll response timeouts"),
- IPW2100_ORD(STAT_PSP_NONDIR_TIMEOUT,
- "timeouts waiting for last {broad,multi}cast pkt"),
- IPW2100_ORD(STAT_PSP_RX_DTIMS, "PSP DTIMs received"),
- IPW2100_ORD(STAT_PSP_RX_TIMS, "PSP TIMs received"),
- IPW2100_ORD(STAT_PSP_STATION_ID, "PSP Station ID"),
- IPW2100_ORD(LAST_ASSN_TIME, "RTC time of last association"),
- IPW2100_ORD(STAT_PERCENT_MISSED_BCNS,
- "current calculation of % missed beacons"),
- IPW2100_ORD(STAT_PERCENT_RETRIES,
- "current calculation of % missed tx retries"),
- IPW2100_ORD(ASSOCIATED_AP_PTR,
- "0 if not associated, else pointer to AP table entry"),
- IPW2100_ORD(AVAILABLE_AP_CNT,
- "AP's described in the AP table"),
- IPW2100_ORD(AP_LIST_PTR, "Ptr to list of available APs"),
- IPW2100_ORD(STAT_AP_ASSNS, "associations"),
- IPW2100_ORD(STAT_ASSN_FAIL, "association failures"),
- IPW2100_ORD(STAT_ASSN_RESP_FAIL,
- "failures due to response fail"),
- IPW2100_ORD(STAT_FULL_SCANS, "full scans"),
- IPW2100_ORD(CARD_DISABLED, "Card Disabled"),
- IPW2100_ORD(STAT_ROAM_INHIBIT,
- "times roaming was inhibited due to activity"),
- IPW2100_ORD(RSSI_AT_ASSN,
- "RSSI of associated AP at time of association"),
- IPW2100_ORD(STAT_ASSN_CAUSE1,
- "reassociation: no probe response or TX on hop"),
- IPW2100_ORD(STAT_ASSN_CAUSE2,
- "reassociation: poor tx/rx quality"),
- IPW2100_ORD(STAT_ASSN_CAUSE3,
- "reassociation: tx/rx quality (excessive AP load"),
- IPW2100_ORD(STAT_ASSN_CAUSE4,
- "reassociation: AP RSSI level"),
- IPW2100_ORD(STAT_ASSN_CAUSE5,
- "reassociations due to load leveling"),
- IPW2100_ORD(STAT_AUTH_FAIL, "times authentication failed"),
- IPW2100_ORD(STAT_AUTH_RESP_FAIL,
- "times authentication response failed"),
- IPW2100_ORD(STATION_TABLE_CNT,
- "entries in association table"),
- IPW2100_ORD(RSSI_AVG_CURR, "Current avg RSSI"),
- IPW2100_ORD(POWER_MGMT_MODE, "Power mode - 0=CAM, 1=PSP"),
- IPW2100_ORD(COUNTRY_CODE,
- "IEEE country code as recv'd from beacon"),
- IPW2100_ORD(COUNTRY_CHANNELS,
- "channels supported by country"),
- IPW2100_ORD(RESET_CNT, "adapter resets (warm)"),
- IPW2100_ORD(BEACON_INTERVAL, "Beacon interval"),
- IPW2100_ORD(ANTENNA_DIVERSITY,
- "TRUE if antenna diversity is disabled"),
- IPW2100_ORD(DTIM_PERIOD, "beacon intervals between DTIMs"),
- IPW2100_ORD(OUR_FREQ,
- "current radio freq lower digits - channel ID"),
- IPW2100_ORD(RTC_TIME, "current RTC time"),
- IPW2100_ORD(PORT_TYPE, "operating mode"),
- IPW2100_ORD(CURRENT_TX_RATE, "current tx rate"),
- IPW2100_ORD(SUPPORTED_RATES, "supported tx rates"),
- IPW2100_ORD(ATIM_WINDOW, "current ATIM Window"),
- IPW2100_ORD(BASIC_RATES, "basic tx rates"),
- IPW2100_ORD(NIC_HIGHEST_RATE, "NIC highest tx rate"),
- IPW2100_ORD(AP_HIGHEST_RATE, "AP highest tx rate"),
- IPW2100_ORD(CAPABILITIES,
- "Management frame capability field"),
- IPW2100_ORD(AUTH_TYPE, "Type of authentication"),
- IPW2100_ORD(RADIO_TYPE, "Adapter card platform type"),
- IPW2100_ORD(RTS_THRESHOLD,
- "Min packet length for RTS handshaking"),
- IPW2100_ORD(INT_MODE, "International mode"),
- IPW2100_ORD(FRAGMENTATION_THRESHOLD,
- "protocol frag threshold"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_START_ADDRESS,
- "EEPROM offset in SRAM"),
- IPW2100_ORD(EEPROM_SRAM_DB_BLOCK_SIZE,
- "EEPROM size in SRAM"),
- IPW2100_ORD(EEPROM_SKU_CAPABILITY, "EEPROM SKU Capability"),
- IPW2100_ORD(EEPROM_IBSS_11B_CHANNELS,
- "EEPROM IBSS 11b channel set"),
- IPW2100_ORD(MAC_VERSION, "MAC Version"),
- IPW2100_ORD(MAC_REVISION, "MAC Revision"),
- IPW2100_ORD(RADIO_VERSION, "Radio Version"),
- IPW2100_ORD(NIC_MANF_DATE_TIME, "MANF Date/Time STAMP"),
- IPW2100_ORD(UCODE_VERSION, "Ucode Version"),};
-
-static ssize_t registers_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- int i;
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- char *out = buf;
- u32 val = 0;
-
- out += sprintf(out, "%30s [Address ] : Hex\n", "Register");
-
- for (i = 0; i < ARRAY_SIZE(hw_data); i++) {
- read_register(dev, hw_data[i].addr, &val);
- out += sprintf(out, "%30s [%08X] : %08X\n",
- hw_data[i].name, hw_data[i].addr, val);
- }
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(registers);
-
-static ssize_t hardware_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- char *out = buf;
- int i;
-
- out += sprintf(out, "%30s [Address ] : Hex\n", "NIC entry");
-
- for (i = 0; i < ARRAY_SIZE(nic_data); i++) {
- u8 tmp8;
- u16 tmp16;
- u32 tmp32;
-
- switch (nic_data[i].size) {
- case 1:
- read_nic_byte(dev, nic_data[i].addr, &tmp8);
- out += sprintf(out, "%30s [%08X] : %02X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp8);
- break;
- case 2:
- read_nic_word(dev, nic_data[i].addr, &tmp16);
- out += sprintf(out, "%30s [%08X] : %04X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp16);
- break;
- case 4:
- read_nic_dword(dev, nic_data[i].addr, &tmp32);
- out += sprintf(out, "%30s [%08X] : %08X\n",
- nic_data[i].name, nic_data[i].addr,
- tmp32);
- break;
- }
- }
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(hardware);
-
-static ssize_t memory_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- static unsigned long loop = 0;
- int len = 0;
- u32 buffer[4];
- int i;
- char line[81];
-
- if (loop >= 0x30000)
- loop = 0;
-
- /* sysfs provides us PAGE_SIZE buffer */
- while (len < PAGE_SIZE - 128 && loop < 0x30000) {
-
- if (priv->snapshot[0])
- for (i = 0; i < 4; i++)
- buffer[i] =
- *(u32 *) SNAPSHOT_ADDR(loop + i * 4);
- else
- for (i = 0; i < 4; i++)
- read_nic_dword(dev, loop + i * 4, &buffer[i]);
-
- if (priv->dump_raw)
- len += sprintf(buf + len,
- "%c%c%c%c"
- "%c%c%c%c"
- "%c%c%c%c"
- "%c%c%c%c",
- ((u8 *) buffer)[0x0],
- ((u8 *) buffer)[0x1],
- ((u8 *) buffer)[0x2],
- ((u8 *) buffer)[0x3],
- ((u8 *) buffer)[0x4],
- ((u8 *) buffer)[0x5],
- ((u8 *) buffer)[0x6],
- ((u8 *) buffer)[0x7],
- ((u8 *) buffer)[0x8],
- ((u8 *) buffer)[0x9],
- ((u8 *) buffer)[0xa],
- ((u8 *) buffer)[0xb],
- ((u8 *) buffer)[0xc],
- ((u8 *) buffer)[0xd],
- ((u8 *) buffer)[0xe],
- ((u8 *) buffer)[0xf]);
- else
- len += sprintf(buf + len, "%s\n",
- snprint_line(line, sizeof(line),
- (u8 *) buffer, 16, loop));
- loop += 16;
- }
-
- return len;
-}
-
-static ssize_t memory_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- const char *p = buf;
-
- (void)dev; /* kill unused-var warning for debug-only code */
-
- if (count < 1)
- return count;
-
- if (p[0] == '1' ||
- (count >= 2 && tolower(p[0]) == 'o' && tolower(p[1]) == 'n')) {
- IPW_DEBUG_INFO("%s: Setting memory dump to RAW mode.\n",
- dev->name);
- priv->dump_raw = 1;
-
- } else if (p[0] == '0' || (count >= 2 && tolower(p[0]) == 'o' &&
- tolower(p[1]) == 'f')) {
- IPW_DEBUG_INFO("%s: Setting memory dump to HEX mode.\n",
- dev->name);
- priv->dump_raw = 0;
-
- } else if (tolower(p[0]) == 'r') {
- IPW_DEBUG_INFO("%s: Resetting firmware snapshot.\n", dev->name);
- ipw2100_snapshot_free(priv);
-
- } else
- IPW_DEBUG_INFO("%s: Usage: 0|on = HEX, 1|off = RAW, "
- "reset = clear memory snapshot\n", dev->name);
-
- return count;
-}
-
-static DEVICE_ATTR_RW(memory);
-
-static ssize_t ordinals_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- u32 val = 0;
- int len = 0;
- u32 val_len;
- static int loop = 0;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return 0;
-
- if (loop >= ARRAY_SIZE(ord_data))
- loop = 0;
-
- /* sysfs provides us PAGE_SIZE buffer */
- while (len < PAGE_SIZE - 128 && loop < ARRAY_SIZE(ord_data)) {
- val_len = sizeof(u32);
-
- if (ipw2100_get_ordinal(priv, ord_data[loop].index, &val,
- &val_len))
- len += sprintf(buf + len, "[0x%02X] = ERROR %s\n",
- ord_data[loop].index,
- ord_data[loop].desc);
- else
- len += sprintf(buf + len, "[0x%02X] = 0x%08X %s\n",
- ord_data[loop].index, val,
- ord_data[loop].desc);
- loop++;
- }
-
- return len;
-}
-
-static DEVICE_ATTR_RO(ordinals);
-
-static ssize_t stats_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char *out = buf;
-
- out += sprintf(out, "interrupts: %d {tx: %d, rx: %d, other: %d}\n",
- priv->interrupts, priv->tx_interrupts,
- priv->rx_interrupts, priv->inta_other);
- out += sprintf(out, "firmware resets: %d\n", priv->resets);
- out += sprintf(out, "firmware hangs: %d\n", priv->hangs);
-#ifdef CONFIG_IPW2100_DEBUG
- out += sprintf(out, "packet mismatch image: %s\n",
- priv->snapshot[0] ? "YES" : "NO");
-#endif
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(stats);
-
-static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode)
-{
- int err;
-
- if (mode == priv->ieee->iw_mode)
- return 0;
-
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
-
- switch (mode) {
- case IW_MODE_INFRA:
- priv->net_dev->type = ARPHRD_ETHER;
- break;
- case IW_MODE_ADHOC:
- priv->net_dev->type = ARPHRD_ETHER;
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- priv->last_mode = priv->ieee->iw_mode;
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- break;
-#endif /* CONFIG_IPW2100_MONITOR */
- }
-
- priv->ieee->iw_mode = mode;
-
-#ifdef CONFIG_PM
- /* Indicate ipw2100_download_firmware download firmware
- * from disk instead of memory. */
- ipw2100_firmware.version = 0;
-#endif
-
- printk(KERN_INFO "%s: Resetting on mode change.\n", priv->net_dev->name);
- priv->reset_backoff = 0;
- schedule_reset(priv);
-
- return 0;
-}
-
-static ssize_t internals_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- int len = 0;
-
-#define DUMP_VAR(x,y) len += sprintf(buf + len, # x ": %" y "\n", priv-> x)
-
- if (priv->status & STATUS_ASSOCIATED)
- len += sprintf(buf + len, "connected: %llu\n",
- ktime_get_boottime_seconds() - priv->connect_start);
- else
- len += sprintf(buf + len, "not connected\n");
-
- DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p");
- DUMP_VAR(status, "08lx");
- DUMP_VAR(config, "08lx");
- DUMP_VAR(capability, "08lx");
-
- len +=
- sprintf(buf + len, "last_rtc: %lu\n",
- (unsigned long)priv->last_rtc);
-
- DUMP_VAR(fatal_error, "d");
- DUMP_VAR(stop_hang_check, "d");
- DUMP_VAR(stop_rf_kill, "d");
- DUMP_VAR(messages_sent, "d");
-
- DUMP_VAR(tx_pend_stat.value, "d");
- DUMP_VAR(tx_pend_stat.hi, "d");
-
- DUMP_VAR(tx_free_stat.value, "d");
- DUMP_VAR(tx_free_stat.lo, "d");
-
- DUMP_VAR(msg_free_stat.value, "d");
- DUMP_VAR(msg_free_stat.lo, "d");
-
- DUMP_VAR(msg_pend_stat.value, "d");
- DUMP_VAR(msg_pend_stat.hi, "d");
-
- DUMP_VAR(fw_pend_stat.value, "d");
- DUMP_VAR(fw_pend_stat.hi, "d");
-
- DUMP_VAR(txq_stat.value, "d");
- DUMP_VAR(txq_stat.lo, "d");
-
- DUMP_VAR(ieee->scans, "d");
- DUMP_VAR(reset_backoff, "lld");
-
- return len;
-}
-
-static DEVICE_ATTR_RO(internals);
-
-static ssize_t bssinfo_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char essid[IW_ESSID_MAX_SIZE + 1];
- u8 bssid[ETH_ALEN];
- u32 chan = 0;
- char *out = buf;
- unsigned int length;
- int ret;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return 0;
-
- memset(essid, 0, sizeof(essid));
- memset(bssid, 0, sizeof(bssid));
-
- length = IW_ESSID_MAX_SIZE;
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_SSID, essid, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- length = sizeof(bssid);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
- bssid, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- length = sizeof(u32);
- ret = ipw2100_get_ordinal(priv, IPW_ORD_OUR_FREQ, &chan, &length);
- if (ret)
- IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
- __LINE__);
-
- out += sprintf(out, "ESSID: %s\n", essid);
- out += sprintf(out, "BSSID: %pM\n", bssid);
- out += sprintf(out, "Channel: %d\n", chan);
-
- return out - buf;
-}
-
-static DEVICE_ATTR_RO(bssinfo);
-
-#ifdef CONFIG_IPW2100_DEBUG
-static ssize_t debug_level_show(struct device_driver *d, char *buf)
-{
- return sprintf(buf, "0x%08X\n", ipw2100_debug_level);
-}
-
-static ssize_t debug_level_store(struct device_driver *d,
- const char *buf, size_t count)
-{
- u32 val;
- int ret;
-
- ret = kstrtou32(buf, 0, &val);
- if (ret)
- IPW_DEBUG_INFO(": %s is not in hex or decimal form.\n", buf);
- else
- ipw2100_debug_level = val;
-
- return strnlen(buf, count);
-}
-static DRIVER_ATTR_RW(debug_level);
-#endif /* CONFIG_IPW2100_DEBUG */
-
-static ssize_t fatal_error_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- char *out = buf;
- int i;
-
- if (priv->fatal_error)
- out += sprintf(out, "0x%08X\n", priv->fatal_error);
- else
- out += sprintf(out, "0\n");
-
- for (i = 1; i <= IPW2100_ERROR_QUEUE; i++) {
- if (!priv->fatal_errors[(priv->fatal_index - i) %
- IPW2100_ERROR_QUEUE])
- continue;
-
- out += sprintf(out, "%d. 0x%08X\n", i,
- priv->fatal_errors[(priv->fatal_index - i) %
- IPW2100_ERROR_QUEUE]);
- }
-
- return out - buf;
-}
-
-static ssize_t fatal_error_store(struct device *d,
- struct device_attribute *attr, const char *buf,
- size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- schedule_reset(priv);
- return count;
-}
-
-static DEVICE_ATTR_RW(fatal_error);
-
-static ssize_t scan_age_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", priv->ieee->scan_age);
-}
-
-static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
- unsigned long val;
- int ret;
-
- (void)dev; /* kill unused-var warning for debug-only code */
-
- IPW_DEBUG_INFO("enter\n");
-
- ret = kstrtoul(buf, 0, &val);
- if (ret) {
- IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
- } else {
- priv->ieee->scan_age = val;
- IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(scan_age);
-
-static ssize_t rf_kill_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- /* 0 - RF kill not enabled
- 1 - SW based RF kill active (sysfs)
- 2 - HW based RF kill active
- 3 - Both HW and SW baed RF kill active */
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
- (rf_kill_active(priv) ? 0x2 : 0x0);
- return sprintf(buf, "%i\n", val);
-}
-
-static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
-{
- if ((disable_radio ? 1 : 0) ==
- (priv->status & STATUS_RF_KILL_SW ? 1 : 0))
- return 0;
-
- IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
- disable_radio ? "OFF" : "ON");
-
- mutex_lock(&priv->action_mutex);
-
- if (disable_radio) {
- priv->status |= STATUS_RF_KILL_SW;
- ipw2100_down(priv);
- } else {
- priv->status &= ~STATUS_RF_KILL_SW;
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("Can not turn radio back on - "
- "disabled by HW switch\n");
- /* Make sure the RF_KILL check timer is running */
- priv->stop_rf_kill = 0;
- mod_delayed_work(system_wq, &priv->rf_kill,
- round_jiffies_relative(HZ));
- } else
- schedule_reset(priv);
- }
-
- mutex_unlock(&priv->action_mutex);
- return 1;
-}
-
-static ssize_t rf_kill_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(d);
- ipw_radio_kill_sw(priv, buf[0] == '1');
- return count;
-}
-
-static DEVICE_ATTR_RW(rf_kill);
-
-static struct attribute *ipw2100_sysfs_entries[] = {
- &dev_attr_hardware.attr,
- &dev_attr_registers.attr,
- &dev_attr_ordinals.attr,
- &dev_attr_pci.attr,
- &dev_attr_stats.attr,
- &dev_attr_internals.attr,
- &dev_attr_bssinfo.attr,
- &dev_attr_memory.attr,
- &dev_attr_scan_age.attr,
- &dev_attr_fatal_error.attr,
- &dev_attr_rf_kill.attr,
- &dev_attr_cfg.attr,
- &dev_attr_status.attr,
- &dev_attr_capability.attr,
- NULL,
-};
-
-static const struct attribute_group ipw2100_attribute_group = {
- .attrs = ipw2100_sysfs_entries,
-};
-
-static int status_queue_allocate(struct ipw2100_priv *priv, int entries)
-{
- struct ipw2100_status_queue *q = &priv->status_queue;
-
- IPW_DEBUG_INFO("enter\n");
-
- q->size = entries * sizeof(struct ipw2100_status);
- q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
- GFP_KERNEL);
- if (!q->drv) {
- IPW_DEBUG_WARNING("Can not allocate status queue.\n");
- return -ENOMEM;
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void status_queue_free(struct ipw2100_priv *priv)
-{
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->status_queue.drv) {
- dma_free_coherent(&priv->pci_dev->dev,
- priv->status_queue.size,
- priv->status_queue.drv,
- priv->status_queue.nic);
- priv->status_queue.drv = NULL;
- }
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int bd_queue_allocate(struct ipw2100_priv *priv,
- struct ipw2100_bd_queue *q, int entries)
-{
- IPW_DEBUG_INFO("enter\n");
-
- memset(q, 0, sizeof(struct ipw2100_bd_queue));
-
- q->entries = entries;
- q->size = entries * sizeof(struct ipw2100_bd);
- q->drv = dma_alloc_coherent(&priv->pci_dev->dev, q->size, &q->nic,
- GFP_KERNEL);
- if (!q->drv) {
- IPW_DEBUG_INFO
- ("can't allocate shared memory for buffer descriptors\n");
- return -ENOMEM;
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void bd_queue_free(struct ipw2100_priv *priv, struct ipw2100_bd_queue *q)
-{
- IPW_DEBUG_INFO("enter\n");
-
- if (!q)
- return;
-
- if (q->drv) {
- dma_free_coherent(&priv->pci_dev->dev, q->size, q->drv,
- q->nic);
- q->drv = NULL;
- }
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void bd_queue_initialize(struct ipw2100_priv *priv,
- struct ipw2100_bd_queue *q, u32 base, u32 size,
- u32 r, u32 w)
-{
- IPW_DEBUG_INFO("enter\n");
-
- IPW_DEBUG_INFO("initializing bd queue at virt=%p, phys=%08x\n", q->drv,
- (u32) q->nic);
-
- write_register(priv->net_dev, base, q->nic);
- write_register(priv->net_dev, size, q->entries);
- write_register(priv->net_dev, r, q->oldest);
- write_register(priv->net_dev, w, q->next);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void ipw2100_kill_works(struct ipw2100_priv *priv)
-{
- priv->stop_rf_kill = 1;
- priv->stop_hang_check = 1;
- cancel_delayed_work_sync(&priv->reset_work);
- cancel_delayed_work_sync(&priv->security_work);
- cancel_delayed_work_sync(&priv->wx_event_work);
- cancel_delayed_work_sync(&priv->hang_check);
- cancel_delayed_work_sync(&priv->rf_kill);
- cancel_delayed_work_sync(&priv->scan_event);
-}
-
-static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err;
- void *v;
- dma_addr_t p;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = bd_queue_allocate(priv, &priv->tx_queue, TX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_ERROR("%s: failed bd_queue_allocate\n",
- priv->net_dev->name);
- return err;
- }
-
- priv->tx_buffers = kmalloc_array(TX_PENDED_QUEUE_LENGTH,
- sizeof(struct ipw2100_tx_packet),
- GFP_KERNEL);
- if (!priv->tx_buffers) {
- bd_queue_free(priv, &priv->tx_queue);
- return -ENOMEM;
- }
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- v = dma_alloc_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header), &p,
- GFP_KERNEL);
- if (!v) {
- printk(KERN_ERR DRV_NAME
- ": %s: PCI alloc failed for tx " "buffers.\n",
- priv->net_dev->name);
- err = -ENOMEM;
- break;
- }
-
- priv->tx_buffers[i].type = DATA;
- priv->tx_buffers[i].info.d_struct.data =
- (struct ipw2100_data_header *)v;
- priv->tx_buffers[i].info.d_struct.data_phys = p;
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
-
- if (i == TX_PENDED_QUEUE_LENGTH)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[j].info.d_struct.data,
- priv->tx_buffers[j].info.d_struct.data_phys);
- }
-
- kfree(priv->tx_buffers);
- priv->tx_buffers = NULL;
-
- return err;
-}
-
-static void ipw2100_tx_initialize(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- /*
- * reinitialize packet info lists
- */
- INIT_LIST_HEAD(&priv->fw_pend_list);
- INIT_STAT(&priv->fw_pend_stat);
-
- /*
- * reinitialize lists
- */
- INIT_LIST_HEAD(&priv->tx_pend_list);
- INIT_LIST_HEAD(&priv->tx_free_list);
- INIT_STAT(&priv->tx_pend_stat);
- INIT_STAT(&priv->tx_free_stat);
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- /* We simply drop any SKBs that have been queued for
- * transmit */
- if (priv->tx_buffers[i].info.d_struct.txb) {
- libipw_txb_free(priv->tx_buffers[i].info.d_struct.
- txb);
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
-
- list_add_tail(&priv->tx_buffers[i].list, &priv->tx_free_list);
- }
-
- SET_STAT(&priv->tx_free_stat, i);
-
- priv->tx_queue.oldest = 0;
- priv->tx_queue.available = priv->tx_queue.entries;
- priv->tx_queue.next = 0;
- INIT_STAT(&priv->txq_stat);
- SET_STAT(&priv->txq_stat, priv->tx_queue.available);
-
- bd_queue_initialize(priv, &priv->tx_queue,
- IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE,
- IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE,
- IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX,
- IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX);
-
- IPW_DEBUG_INFO("exit\n");
-
-}
-
-static void ipw2100_tx_free(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- bd_queue_free(priv, &priv->tx_queue);
-
- if (!priv->tx_buffers)
- return;
-
- for (i = 0; i < TX_PENDED_QUEUE_LENGTH; i++) {
- if (priv->tx_buffers[i].info.d_struct.txb) {
- libipw_txb_free(priv->tx_buffers[i].info.d_struct.
- txb);
- priv->tx_buffers[i].info.d_struct.txb = NULL;
- }
- if (priv->tx_buffers[i].info.d_struct.data)
- dma_free_coherent(&priv->pci_dev->dev,
- sizeof(struct ipw2100_data_header),
- priv->tx_buffers[i].info.d_struct.data,
- priv->tx_buffers[i].info.d_struct.data_phys);
- }
-
- kfree(priv->tx_buffers);
- priv->tx_buffers = NULL;
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
-{
- int i, j, err = -EINVAL;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = bd_queue_allocate(priv, &priv->rx_queue, RX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_INFO("failed bd_queue_allocate\n");
- return err;
- }
-
- err = status_queue_allocate(priv, RX_QUEUE_LENGTH);
- if (err) {
- IPW_DEBUG_INFO("failed status_queue_allocate\n");
- bd_queue_free(priv, &priv->rx_queue);
- return err;
- }
-
- /*
- * allocate packets
- */
- priv->rx_buffers = kmalloc_array(RX_QUEUE_LENGTH,
- sizeof(struct ipw2100_rx_packet),
- GFP_KERNEL);
- if (!priv->rx_buffers) {
- IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
-
- bd_queue_free(priv, &priv->rx_queue);
-
- status_queue_free(priv);
-
- return -ENOMEM;
- }
-
- for (i = 0; i < RX_QUEUE_LENGTH; i++) {
- struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
-
- err = ipw2100_alloc_skb(priv, packet);
- if (unlikely(err)) {
- err = -ENOMEM;
- break;
- }
-
- /* The BD holds the cache aligned address */
- priv->rx_queue.drv[i].host_addr = packet->dma_addr;
- priv->rx_queue.drv[i].buf_length = IPW_RX_NIC_BUFFER_LENGTH;
- priv->status_queue.drv[i].status_fields = 0;
- }
-
- if (i == RX_QUEUE_LENGTH)
- return 0;
-
- for (j = 0; j < i; j++) {
- dma_unmap_single(&priv->pci_dev->dev,
- priv->rx_buffers[j].dma_addr,
- sizeof(struct ipw2100_rx_packet),
- DMA_FROM_DEVICE);
- dev_kfree_skb(priv->rx_buffers[j].skb);
- }
-
- kfree(priv->rx_buffers);
- priv->rx_buffers = NULL;
-
- bd_queue_free(priv, &priv->rx_queue);
-
- status_queue_free(priv);
-
- return err;
-}
-
-static void ipw2100_rx_initialize(struct ipw2100_priv *priv)
-{
- IPW_DEBUG_INFO("enter\n");
-
- priv->rx_queue.oldest = 0;
- priv->rx_queue.available = priv->rx_queue.entries - 1;
- priv->rx_queue.next = priv->rx_queue.entries - 1;
-
- INIT_STAT(&priv->rxq_stat);
- SET_STAT(&priv->rxq_stat, priv->rx_queue.available);
-
- bd_queue_initialize(priv, &priv->rx_queue,
- IPW_MEM_HOST_SHARED_RX_BD_BASE,
- IPW_MEM_HOST_SHARED_RX_BD_SIZE,
- IPW_MEM_HOST_SHARED_RX_READ_INDEX,
- IPW_MEM_HOST_SHARED_RX_WRITE_INDEX);
-
- /* set up the status queue */
- write_register(priv->net_dev, IPW_MEM_HOST_SHARED_RX_STATUS_BASE,
- priv->status_queue.nic);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static void ipw2100_rx_free(struct ipw2100_priv *priv)
-{
- int i;
-
- IPW_DEBUG_INFO("enter\n");
-
- bd_queue_free(priv, &priv->rx_queue);
- status_queue_free(priv);
-
- if (!priv->rx_buffers)
- return;
-
- for (i = 0; i < RX_QUEUE_LENGTH; i++) {
- if (priv->rx_buffers[i].rxp) {
- dma_unmap_single(&priv->pci_dev->dev,
- priv->rx_buffers[i].dma_addr,
- sizeof(struct ipw2100_rx),
- DMA_FROM_DEVICE);
- dev_kfree_skb(priv->rx_buffers[i].skb);
- }
- }
-
- kfree(priv->rx_buffers);
- priv->rx_buffers = NULL;
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
-{
- u32 length = ETH_ALEN;
- u8 addr[ETH_ALEN];
-
- int err;
-
- err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
- if (err) {
- IPW_DEBUG_INFO("MAC address read failed\n");
- return -EIO;
- }
-
- eth_hw_addr_set(priv->net_dev, addr);
- IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr);
-
- return 0;
-}
-
-/********************************************************************
- *
- * Firmware Commands
- *
- ********************************************************************/
-
-static int ipw2100_set_mac_address(struct ipw2100_priv *priv, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = ADAPTER_ADDRESS,
- .host_command_sequence = 0,
- .host_command_length = ETH_ALEN
- };
- int err;
-
- IPW_DEBUG_HC("SET_MAC_ADDRESS\n");
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->config & CFG_CUSTOM_MAC) {
- memcpy(cmd.host_command_parameters, priv->mac_addr, ETH_ALEN);
- eth_hw_addr_set(priv->net_dev, priv->mac_addr);
- } else
- memcpy(cmd.host_command_parameters, priv->net_dev->dev_addr,
- ETH_ALEN);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- IPW_DEBUG_INFO("exit\n");
- return err;
-}
-
-static int ipw2100_set_port_type(struct ipw2100_priv *priv, u32 port_type,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = PORT_TYPE,
- .host_command_sequence = 0,
- .host_command_length = sizeof(u32)
- };
- int err;
-
- switch (port_type) {
- case IW_MODE_INFRA:
- cmd.host_command_parameters[0] = IPW_BSS;
- break;
- case IW_MODE_ADHOC:
- cmd.host_command_parameters[0] = IPW_IBSS;
- break;
- }
-
- IPW_DEBUG_HC("PORT_TYPE: %s\n",
- port_type == IPW_IBSS ? "Ad-Hoc" : "Managed");
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_set_channel(struct ipw2100_priv *priv, u32 channel,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = CHANNEL,
- .host_command_sequence = 0,
- .host_command_length = sizeof(u32)
- };
- int err;
-
- cmd.host_command_parameters[0] = channel;
-
- IPW_DEBUG_HC("CHANNEL: %d\n", channel);
-
- /* If BSS then we don't support channel selection */
- if (priv->ieee->iw_mode == IW_MODE_INFRA)
- return 0;
-
- if ((channel != 0) &&
- ((channel < REG_MIN_CHANNEL) || (channel > REG_MAX_CHANNEL)))
- return -EINVAL;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err) {
- IPW_DEBUG_INFO("Failed to set channel to %d", channel);
- return err;
- }
-
- if (channel)
- priv->config |= CFG_STATIC_CHANNEL;
- else
- priv->config &= ~CFG_STATIC_CHANNEL;
-
- priv->channel = channel;
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int ipw2100_system_config(struct ipw2100_priv *priv, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SYSTEM_CONFIG,
- .host_command_sequence = 0,
- .host_command_length = 12,
- };
- u32 ibss_mask, len = sizeof(u32);
- int err;
-
- /* Set system configuration */
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- cmd.host_command_parameters[0] |= IPW_CFG_IBSS_AUTO_START;
-
- cmd.host_command_parameters[0] |= IPW_CFG_IBSS_MASK |
- IPW_CFG_BSS_MASK | IPW_CFG_802_1x_ENABLE;
-
- if (!(priv->config & CFG_LONG_PREAMBLE))
- cmd.host_command_parameters[0] |= IPW_CFG_PREAMBLE_AUTO;
-
- err = ipw2100_get_ordinal(priv,
- IPW_ORD_EEPROM_IBSS_11B_CHANNELS,
- &ibss_mask, &len);
- if (err)
- ibss_mask = IPW_IBSS_11B_DEFAULT_MASK;
-
- cmd.host_command_parameters[1] = REG_CHANNEL_MASK;
- cmd.host_command_parameters[2] = REG_CHANNEL_MASK & ibss_mask;
-
- /* 11b only */
- /*cmd.host_command_parameters[0] |= DIVERSITY_ANTENNA_A; */
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
-/* If IPv6 is configured in the kernel then we don't want to filter out all
- * of the multicast packets as IPv6 needs some. */
-#if !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE)
- cmd.host_command = ADD_MULTICAST;
- cmd.host_command_sequence = 0;
- cmd.host_command_length = 0;
-
- ipw2100_hw_send_command(priv, &cmd);
-#endif
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int ipw2100_set_tx_rates(struct ipw2100_priv *priv, u32 rate,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = BASIC_TX_RATES,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = rate & TX_RATE_MASK;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- /* Set BASIC TX Rate first */
- ipw2100_hw_send_command(priv, &cmd);
-
- /* Set TX Rate */
- cmd.host_command = TX_RATES;
- ipw2100_hw_send_command(priv, &cmd);
-
- /* Set MSDU TX Rate */
- cmd.host_command = MSDU_TX_RATES;
- ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
-
- priv->tx_rates = rate;
-
- return 0;
-}
-
-static int ipw2100_set_power_mode(struct ipw2100_priv *priv, int power_level)
-{
- struct host_command cmd = {
- .host_command = POWER_MODE,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = power_level;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- if (power_level == IPW_POWER_MODE_CAM)
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- else
- priv->power_mode = IPW_POWER_ENABLED | power_level;
-
-#ifdef IPW2100_TX_POWER
- if (priv->port_type == IBSS && priv->adhoc_power != DFTL_IBSS_TX_POWER) {
- /* Set beacon interval */
- cmd.host_command = TX_POWER_INDEX;
- cmd.host_command_parameters[0] = (u32) priv->adhoc_power;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
- }
-#endif
-
- return 0;
-}
-
-static int ipw2100_set_rts_threshold(struct ipw2100_priv *priv, u32 threshold)
-{
- struct host_command cmd = {
- .host_command = RTS_THRESHOLD,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- if (threshold & RTS_DISABLED)
- cmd.host_command_parameters[0] = MAX_RTS_THRESHOLD;
- else
- cmd.host_command_parameters[0] = threshold & ~RTS_DISABLED;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->rts_threshold = threshold;
-
- return 0;
-}
-
-#if 0
-int ipw2100_set_fragmentation_threshold(struct ipw2100_priv *priv,
- u32 threshold, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = FRAG_THRESHOLD,
- .host_command_sequence = 0,
- .host_command_length = 4,
- .host_command_parameters[0] = 0,
- };
- int err;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (threshold == 0)
- threshold = DEFAULT_FRAG_THRESHOLD;
- else {
- threshold = max(threshold, MIN_FRAG_THRESHOLD);
- threshold = min(threshold, MAX_FRAG_THRESHOLD);
- }
-
- cmd.host_command_parameters[0] = threshold;
-
- IPW_DEBUG_HC("FRAG_THRESHOLD: %u\n", threshold);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- if (!err)
- priv->frag_threshold = threshold;
-
- return err;
-}
-#endif
-
-static int ipw2100_set_short_retry(struct ipw2100_priv *priv, u32 retry)
-{
- struct host_command cmd = {
- .host_command = SHORT_RETRY_LIMIT,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = retry;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->short_retry_limit = retry;
-
- return 0;
-}
-
-static int ipw2100_set_long_retry(struct ipw2100_priv *priv, u32 retry)
-{
- struct host_command cmd = {
- .host_command = LONG_RETRY_LIMIT,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = retry;
-
- err = ipw2100_hw_send_command(priv, &cmd);
- if (err)
- return err;
-
- priv->long_retry_limit = retry;
-
- return 0;
-}
-
-static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = MANDATORY_BSSID,
- .host_command_sequence = 0,
- .host_command_length = (bssid == NULL) ? 0 : ETH_ALEN
- };
- int err;
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (bssid != NULL)
- IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid);
- else
- IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
-#endif
- /* if BSSID is empty then we disable mandatory bssid mode */
- if (bssid != NULL)
- memcpy(cmd.host_command_parameters, bssid, ETH_ALEN);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_disassociate_bssid(struct ipw2100_priv *priv)
-{
- struct host_command cmd = {
- .host_command = DISASSOCIATION_BSSID,
- .host_command_sequence = 0,
- .host_command_length = ETH_ALEN
- };
- int err;
-
- IPW_DEBUG_HC("DISASSOCIATION_BSSID\n");
-
- /* The Firmware currently ignores the BSSID and just disassociates from
- * the currently associated AP -- but in the off chance that a future
- * firmware does use the BSSID provided here, we go ahead and try and
- * set it to the currently associated AP's BSSID */
- memcpy(cmd.host_command_parameters, priv->bssid, ETH_ALEN);
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- return err;
-}
-
-static int ipw2100_set_wpa_ie(struct ipw2100_priv *,
- struct ipw2100_wpa_assoc_frame *, int)
- __attribute__ ((unused));
-
-static int ipw2100_set_wpa_ie(struct ipw2100_priv *priv,
- struct ipw2100_wpa_assoc_frame *wpa_frame,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SET_WPA_IE,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct ipw2100_wpa_assoc_frame),
- };
- int err;
-
- IPW_DEBUG_HC("SET_WPA_IE\n");
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- memcpy(cmd.host_command_parameters, wpa_frame,
- sizeof(struct ipw2100_wpa_assoc_frame));
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- if (ipw2100_enable_adapter(priv))
- err = -EIO;
- }
-
- return err;
-}
-
-struct security_info_params {
- u32 allowed_ciphers;
- u16 version;
- u8 auth_mode;
- u8 replay_counters_number;
- u8 unicast_using_group;
-} __packed;
-
-static int ipw2100_set_security_information(struct ipw2100_priv *priv,
- int auth_mode,
- int security_level,
- int unicast_using_group,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = SET_SECURITY_INFORMATION,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct security_info_params)
- };
- struct security_info_params *security =
- (struct security_info_params *)&cmd.host_command_parameters;
- int err;
- memset(security, 0, sizeof(*security));
-
- /* If shared key AP authentication is turned on, then we need to
- * configure the firmware to try and use it.
- *
- * Actual data encryption/decryption is handled by the host. */
- security->auth_mode = auth_mode;
- security->unicast_using_group = unicast_using_group;
-
- switch (security_level) {
- default:
- case SEC_LEVEL_0:
- security->allowed_ciphers = IPW_NONE_CIPHER;
- break;
- case SEC_LEVEL_1:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER;
- break;
- case SEC_LEVEL_2:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER;
- break;
- case SEC_LEVEL_2_CKIP:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_CKIP_CIPHER;
- break;
- case SEC_LEVEL_3:
- security->allowed_ciphers = IPW_WEP40_CIPHER |
- IPW_WEP104_CIPHER | IPW_TKIP_CIPHER | IPW_CCMP_CIPHER;
- break;
- }
-
- IPW_DEBUG_HC
- ("SET_SECURITY_INFORMATION: auth:%d cipher:0x%02X (level %d)\n",
- security->auth_mode, security->allowed_ciphers, security_level);
-
- security->replay_counters_number = 0;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power)
-{
- struct host_command cmd = {
- .host_command = TX_POWER_INDEX,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err = 0;
- u32 tmp = tx_power;
-
- if (tx_power != IPW_TX_POWER_DEFAULT)
- tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 /
- (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM);
-
- cmd.host_command_parameters[0] = tmp;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- err = ipw2100_hw_send_command(priv, &cmd);
- if (!err)
- priv->tx_power = tx_power;
-
- return 0;
-}
-
-static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv,
- u32 interval, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = BEACON_INTERVAL,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = interval;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- err = ipw2100_enable_adapter(priv);
- if (err)
- return err;
- }
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-static void ipw2100_queues_initialize(struct ipw2100_priv *priv)
-{
- ipw2100_tx_initialize(priv);
- ipw2100_rx_initialize(priv);
- ipw2100_msg_initialize(priv);
-}
-
-static void ipw2100_queues_free(struct ipw2100_priv *priv)
-{
- ipw2100_tx_free(priv);
- ipw2100_rx_free(priv);
- ipw2100_msg_free(priv);
-}
-
-static int ipw2100_queues_allocate(struct ipw2100_priv *priv)
-{
- if (ipw2100_tx_allocate(priv) ||
- ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv))
- goto fail;
-
- return 0;
-
- fail:
- ipw2100_tx_free(priv);
- ipw2100_rx_free(priv);
- ipw2100_msg_free(priv);
- return -ENOMEM;
-}
-
-#define IPW_PRIVACY_CAPABLE 0x0008
-
-static int ipw2100_set_wep_flags(struct ipw2100_priv *priv, u32 flags,
- int batch_mode)
-{
- struct host_command cmd = {
- .host_command = WEP_FLAGS,
- .host_command_sequence = 0,
- .host_command_length = 4
- };
- int err;
-
- cmd.host_command_parameters[0] = flags;
-
- IPW_DEBUG_HC("WEP_FLAGS: flags = 0x%08X\n", flags);
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-struct ipw2100_wep_key {
- u8 idx;
- u8 len;
- u8 key[13];
-};
-
-/* Macros to ease up priting WEP keys */
-#define WEP_FMT_64 "%02X%02X%02X%02X-%02X"
-#define WEP_FMT_128 "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X"
-#define WEP_STR_64(x) x[0],x[1],x[2],x[3],x[4]
-#define WEP_STR_128(x) x[0],x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10]
-
-/**
- * ipw2100_set_key() - Set a the wep key
- *
- * @priv: struct to work on
- * @idx: index of the key we want to set
- * @key: ptr to the key data to set
- * @len: length of the buffer at @key
- * @batch_mode: FIXME perform the operation in batch mode, not
- * disabling the device.
- *
- * @returns 0 if OK, < 0 errno code on error.
- *
- * Fill out a command structure with the new wep key, length an
- * index and send it down the wire.
- */
-static int ipw2100_set_key(struct ipw2100_priv *priv,
- int idx, char *key, int len, int batch_mode)
-{
- int keylen = len ? (len <= 5 ? 5 : 13) : 0;
- struct host_command cmd = {
- .host_command = WEP_KEY_INFO,
- .host_command_sequence = 0,
- .host_command_length = sizeof(struct ipw2100_wep_key),
- };
- struct ipw2100_wep_key *wep_key = (void *)cmd.host_command_parameters;
- int err;
-
- IPW_DEBUG_HC("WEP_KEY_INFO: index = %d, len = %d/%d\n",
- idx, keylen, len);
-
- /* NOTE: We don't check cached values in case the firmware was reset
- * or some other problem is occurring. If the user is setting the key,
- * then we push the change */
-
- wep_key->idx = idx;
- wep_key->len = keylen;
-
- if (keylen) {
- memcpy(wep_key->key, key, len);
- memset(wep_key->key + len, 0, keylen - len);
- }
-
- /* Will be optimized out on debug not being configured in */
- if (keylen == 0)
- IPW_DEBUG_WEP("%s: Clearing key %d\n",
- priv->net_dev->name, wep_key->idx);
- else if (keylen == 5)
- IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_64 "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_64(wep_key->key));
- else
- IPW_DEBUG_WEP("%s: idx: %d, len: %d key: " WEP_FMT_128
- "\n",
- priv->net_dev->name, wep_key->idx, wep_key->len,
- WEP_STR_128(wep_key->key));
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- /* FIXME: IPG: shouldn't this prink be in _disable_adapter()? */
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode) {
- int err2 = ipw2100_enable_adapter(priv);
- if (err == 0)
- err = err2;
- }
- return err;
-}
-
-static int ipw2100_set_key_index(struct ipw2100_priv *priv,
- int idx, int batch_mode)
-{
- struct host_command cmd = {
- .host_command = WEP_KEY_INDEX,
- .host_command_sequence = 0,
- .host_command_length = 4,
- .host_command_parameters = {idx},
- };
- int err;
-
- IPW_DEBUG_HC("WEP_KEY_INDEX: index = %d\n", idx);
-
- if (idx < 0 || idx > 3)
- return -EINVAL;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err) {
- printk(KERN_ERR DRV_NAME
- ": %s: Could not disable adapter %d\n",
- priv->net_dev->name, err);
- return err;
- }
- }
-
- /* send cmd to firmware */
- err = ipw2100_hw_send_command(priv, &cmd);
-
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode)
-{
- int i, err, auth_mode, sec_level, use_group;
-
- if (!(priv->status & STATUS_RUNNING))
- return 0;
-
- if (!batch_mode) {
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
- }
-
- if (!priv->ieee->sec.enabled) {
- err =
- ipw2100_set_security_information(priv, IPW_AUTH_OPEN,
- SEC_LEVEL_0, 0, 1);
- } else {
- auth_mode = IPW_AUTH_OPEN;
- if (priv->ieee->sec.flags & SEC_AUTH_MODE) {
- if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)
- auth_mode = IPW_AUTH_SHARED;
- else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)
- auth_mode = IPW_AUTH_LEAP_CISCO_ID;
- }
-
- sec_level = SEC_LEVEL_0;
- if (priv->ieee->sec.flags & SEC_LEVEL)
- sec_level = priv->ieee->sec.level;
-
- use_group = 0;
- if (priv->ieee->sec.flags & SEC_UNICAST_GROUP)
- use_group = priv->ieee->sec.unicast_uses_group;
-
- err =
- ipw2100_set_security_information(priv, auth_mode, sec_level,
- use_group, 1);
- }
-
- if (err)
- goto exit;
-
- if (priv->ieee->sec.enabled) {
- for (i = 0; i < 4; i++) {
- if (!(priv->ieee->sec.flags & (1 << i))) {
- memset(priv->ieee->sec.keys[i], 0, WEP_KEY_LEN);
- priv->ieee->sec.key_sizes[i] = 0;
- } else {
- err = ipw2100_set_key(priv, i,
- priv->ieee->sec.keys[i],
- priv->ieee->sec.
- key_sizes[i], 1);
- if (err)
- goto exit;
- }
- }
-
- ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1);
- }
-
- /* Always enable privacy so the Host can filter WEP packets if
- * encrypted data is sent up */
- err =
- ipw2100_set_wep_flags(priv,
- priv->ieee->sec.
- enabled ? IPW_PRIVACY_CAPABLE : 0, 1);
- if (err)
- goto exit;
-
- priv->status &= ~STATUS_SECURITY_UPDATED;
-
- exit:
- if (!batch_mode)
- ipw2100_enable_adapter(priv);
-
- return err;
-}
-
-static void ipw2100_security_work(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, security_work.work);
-
- /* If we happen to have reconnected before we get a chance to
- * process this, then update the security settings--which causes
- * a disassociation to occur */
- if (!(priv->status & STATUS_ASSOCIATED) &&
- priv->status & STATUS_SECURITY_UPDATED)
- ipw2100_configure_security(priv, 0);
-}
-
-static void shim__set_security(struct net_device *dev,
- struct libipw_security *sec)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int i;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED))
- goto done;
-
- for (i = 0; i < 4; i++) {
- if (sec->flags & (1 << i)) {
- priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
- if (sec->key_sizes[i] == 0)
- priv->ieee->sec.flags &= ~(1 << i);
- else
- memcpy(priv->ieee->sec.keys[i], sec->keys[i],
- sec->key_sizes[i]);
- if (sec->level == SEC_LEVEL_1) {
- priv->ieee->sec.flags |= (1 << i);
- priv->status |= STATUS_SECURITY_UPDATED;
- } else
- priv->ieee->sec.flags &= ~(1 << i);
- }
- }
-
- if ((sec->flags & SEC_ACTIVE_KEY) &&
- priv->ieee->sec.active_key != sec->active_key) {
- priv->ieee->sec.active_key = sec->active_key;
- priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->ieee->sec.auth_mode != sec->auth_mode)) {
- priv->ieee->sec.auth_mode = sec->auth_mode;
- priv->ieee->sec.flags |= SEC_AUTH_MODE;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
- priv->ieee->sec.flags |= SEC_ENABLED;
- priv->ieee->sec.enabled = sec->enabled;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENCRYPT)
- priv->ieee->sec.encrypt = sec->encrypt;
-
- if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
- priv->ieee->sec.level = sec->level;
- priv->ieee->sec.flags |= SEC_LEVEL;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- IPW_DEBUG_WEP("Security flags: %c %c%c%c%c %c%c%c%c\n",
- priv->ieee->sec.flags & (1 << 8) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 7) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 6) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 5) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 4) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 3) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 2) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 1) ? '1' : '0',
- priv->ieee->sec.flags & (1 << 0) ? '1' : '0');
-
-/* As a temporary work around to enable WPA until we figure out why
- * wpa_supplicant toggles the security capability of the driver, which
- * forces a disassociation with force_update...
- *
- * if (force_update || !(priv->status & STATUS_ASSOCIATED))*/
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
- ipw2100_configure_security(priv, 0);
- done:
- mutex_unlock(&priv->action_mutex);
-}
-
-static int ipw2100_adapter_setup(struct ipw2100_priv *priv)
-{
- int err;
- int batch_mode = 1;
- u8 *bssid;
-
- IPW_DEBUG_INFO("enter\n");
-
- err = ipw2100_disable_adapter(priv);
- if (err)
- return err;
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- err = ipw2100_set_channel(priv, priv->channel, batch_mode);
- if (err)
- return err;
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
- }
-#endif /* CONFIG_IPW2100_MONITOR */
-
- err = ipw2100_read_mac_address(priv);
- if (err)
- return -EIO;
-
- err = ipw2100_set_mac_address(priv, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_port_type(priv, priv->ieee->iw_mode, batch_mode);
- if (err)
- return err;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- err = ipw2100_set_channel(priv, priv->channel, batch_mode);
- if (err)
- return err;
- }
-
- err = ipw2100_system_config(priv, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_tx_rates(priv, priv->tx_rates, batch_mode);
- if (err)
- return err;
-
- /* Default to power mode OFF */
- err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
- if (err)
- return err;
-
- err = ipw2100_set_rts_threshold(priv, priv->rts_threshold);
- if (err)
- return err;
-
- if (priv->config & CFG_STATIC_BSSID)
- bssid = priv->bssid;
- else
- bssid = NULL;
- err = ipw2100_set_mandatory_bssid(priv, bssid, batch_mode);
- if (err)
- return err;
-
- if (priv->config & CFG_STATIC_ESSID)
- err = ipw2100_set_essid(priv, priv->essid, priv->essid_len,
- batch_mode);
- else
- err = ipw2100_set_essid(priv, NULL, 0, batch_mode);
- if (err)
- return err;
-
- err = ipw2100_configure_security(priv, batch_mode);
- if (err)
- return err;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- err =
- ipw2100_set_ibss_beacon_interval(priv,
- priv->beacon_interval,
- batch_mode);
- if (err)
- return err;
-
- err = ipw2100_set_tx_power(priv, priv->tx_power);
- if (err)
- return err;
- }
-
- /*
- err = ipw2100_set_fragmentation_threshold(
- priv, priv->frag_threshold, batch_mode);
- if (err)
- return err;
- */
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-/*************************************************************************
- *
- * EXTERNALLY CALLED METHODS
- *
- *************************************************************************/
-
-/* This method is called by the network layer -- not to be confused with
- * ipw2100_set_mac_address() declared above called by this driver (and this
- * method as well) to talk to the firmware */
-static int ipw2100_set_address(struct net_device *dev, void *p)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct sockaddr *addr = p;
- int err = 0;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
-
- mutex_lock(&priv->action_mutex);
-
- priv->config |= CFG_CUSTOM_MAC;
- memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
-
- err = ipw2100_set_mac_address(priv, 0);
- if (err)
- goto done;
-
- priv->reset_backoff = 0;
- mutex_unlock(&priv->action_mutex);
- ipw2100_reset_adapter(&priv->reset_work.work);
- return 0;
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_open(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- unsigned long flags;
- IPW_DEBUG_INFO("dev->open\n");
-
- spin_lock_irqsave(&priv->low_lock, flags);
- if (priv->status & STATUS_ASSOCIATED) {
- netif_carrier_on(dev);
- netif_start_queue(dev);
- }
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- return 0;
-}
-
-static int ipw2100_close(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- unsigned long flags;
- struct list_head *element;
- struct ipw2100_tx_packet *packet;
-
- IPW_DEBUG_INFO("enter\n");
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->status & STATUS_ASSOCIATED)
- netif_carrier_off(dev);
- netif_stop_queue(dev);
-
- /* Flush the TX queue ... */
- while (!list_empty(&priv->tx_pend_list)) {
- element = priv->tx_pend_list.next;
- packet = list_entry(element, struct ipw2100_tx_packet, list);
-
- list_del(element);
- DEC_STAT(&priv->tx_pend_stat);
-
- libipw_txb_free(packet->info.d_struct.txb);
- packet->info.d_struct.txb = NULL;
-
- list_add_tail(element, &priv->tx_free_list);
- INC_STAT(&priv->tx_free_stat);
- }
- spin_unlock_irqrestore(&priv->low_lock, flags);
-
- IPW_DEBUG_INFO("exit\n");
-
- return 0;
-}
-
-/*
- * TODO: Fix this function... its just wrong
- */
-static void ipw2100_tx_timeout(struct net_device *dev, unsigned int txqueue)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- dev->stats.tx_errors++;
-
-#ifdef CONFIG_IPW2100_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- return;
-#endif
-
- IPW_DEBUG_INFO("%s: TX timed out. Scheduling firmware restart.\n",
- dev->name);
- schedule_reset(priv);
-}
-
-static int ipw2100_wpa_enable(struct ipw2100_priv *priv, int value)
-{
- /* This is called when wpa_supplicant loads and closes the driver
- * interface. */
- priv->ieee->wpa_enabled = value;
- return 0;
-}
-
-static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value)
-{
-
- struct libipw_device *ieee = priv->ieee;
- struct libipw_security sec = {
- .flags = SEC_AUTH_MODE,
- };
- int ret = 0;
-
- if (value & IW_AUTH_ALG_SHARED_KEY) {
- sec.auth_mode = WLAN_AUTH_SHARED_KEY;
- ieee->open_wep = 0;
- } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
- sec.auth_mode = WLAN_AUTH_OPEN;
- ieee->open_wep = 1;
- } else if (value & IW_AUTH_ALG_LEAP) {
- sec.auth_mode = WLAN_AUTH_LEAP;
- ieee->open_wep = 1;
- } else
- return -EINVAL;
-
- if (ieee->set_security)
- ieee->set_security(ieee->dev, &sec);
- else
- ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv,
- char *wpa_ie, int wpa_ie_len)
-{
-
- struct ipw2100_wpa_assoc_frame frame;
-
- frame.fixed_ie_mask = 0;
-
- /* copy WPA IE */
- memcpy(frame.var_ie, wpa_ie, wpa_ie_len);
- frame.var_ie_len = wpa_ie_len;
-
- /* make sure WPA is enabled */
- ipw2100_wpa_enable(priv, 1);
- ipw2100_set_wpa_ie(priv, &frame, 0);
-}
-
-static void ipw_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- char fw_ver[64], ucode_ver[64];
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
-
- ipw2100_get_fwversion(priv, fw_ver, sizeof(fw_ver));
- ipw2100_get_ucodeversion(priv, ucode_ver, sizeof(ucode_ver));
-
- snprintf(info->fw_version, sizeof(info->fw_version), "%s:%d:%s",
- fw_ver, priv->eeprom_version, ucode_ver);
-
- strscpy(info->bus_info, pci_name(priv->pci_dev),
- sizeof(info->bus_info));
-}
-
-static u32 ipw2100_ethtool_get_link(struct net_device *dev)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
-}
-
-static const struct ethtool_ops ipw2100_ethtool_ops = {
- .get_link = ipw2100_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
-};
-
-static void ipw2100_hang_check(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, hang_check.work);
- unsigned long flags;
- u32 rtc = 0xa5a5a5a5;
- u32 len = sizeof(rtc);
- int restart = 0;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (priv->fatal_error != 0) {
- /* If fatal_error is set then we need to restart */
- IPW_DEBUG_INFO("%s: Hardware fatal error detected.\n",
- priv->net_dev->name);
-
- restart = 1;
- } else if (ipw2100_get_ordinal(priv, IPW_ORD_RTC_TIME, &rtc, &len) ||
- (rtc == priv->last_rtc)) {
- /* Check if firmware is hung */
- IPW_DEBUG_INFO("%s: Firmware RTC stalled.\n",
- priv->net_dev->name);
-
- restart = 1;
- }
-
- if (restart) {
- /* Kill timer */
- priv->stop_hang_check = 1;
- priv->hangs++;
-
- /* Restart the NIC */
- schedule_reset(priv);
- }
-
- priv->last_rtc = rtc;
-
- if (!priv->stop_hang_check)
- schedule_delayed_work(&priv->hang_check, HZ / 2);
-
- spin_unlock_irqrestore(&priv->low_lock, flags);
-}
-
-static void ipw2100_rf_kill(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, rf_kill.work);
- unsigned long flags;
-
- spin_lock_irqsave(&priv->low_lock, flags);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
- if (!priv->stop_rf_kill)
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(HZ));
- goto exit_unlock;
- }
-
- /* RF Kill is now disabled, so bring the device back up */
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
- "device\n");
- schedule_reset(priv);
- } else
- IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
- "enabled\n");
-
- exit_unlock:
- spin_unlock_irqrestore(&priv->low_lock, flags);
-}
-
-static void ipw2100_irq_tasklet(struct tasklet_struct *t);
-
-static const struct net_device_ops ipw2100_netdev_ops = {
- .ndo_open = ipw2100_open,
- .ndo_stop = ipw2100_close,
- .ndo_start_xmit = libipw_xmit,
- .ndo_tx_timeout = ipw2100_tx_timeout,
- .ndo_set_mac_address = ipw2100_set_address,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-/* Look into using netdev destructor to shutdown libipw? */
-
-static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
- void __iomem * ioaddr)
-{
- struct ipw2100_priv *priv;
- struct net_device *dev;
-
- dev = alloc_libipw(sizeof(struct ipw2100_priv), 0);
- if (!dev)
- return NULL;
- priv = libipw_priv(dev);
- priv->ieee = netdev_priv(dev);
- priv->pci_dev = pci_dev;
- priv->net_dev = dev;
- priv->ioaddr = ioaddr;
-
- priv->ieee->hard_start_xmit = ipw2100_tx;
- priv->ieee->set_security = shim__set_security;
-
- priv->ieee->perfect_rssi = -20;
- priv->ieee->worst_rssi = -85;
-
- dev->netdev_ops = &ipw2100_netdev_ops;
- dev->ethtool_ops = &ipw2100_ethtool_ops;
- dev->wireless_handlers = &ipw2100_wx_handler_def;
- priv->wireless_data.libipw = priv->ieee;
- dev->wireless_data = &priv->wireless_data;
- dev->watchdog_timeo = 3 * HZ;
- dev->irq = 0;
- dev->min_mtu = 68;
- dev->max_mtu = LIBIPW_DATA_LEN;
-
- /* NOTE: We don't use the wireless_handlers hook
- * in dev as the system will start throwing WX requests
- * to us before we're actually initialized and it just
- * ends up causing problems. So, we just handle
- * the WX extensions through the ipw2100_ioctl interface */
-
- /* memset() puts everything to 0, so we only have explicitly set
- * those values that need to be something else */
-
- /* If power management is turned on, default to AUTO mode */
- priv->power_mode = IPW_POWER_AUTO;
-
-#ifdef CONFIG_IPW2100_MONITOR
- priv->config |= CFG_CRC_CHECK;
-#endif
- priv->ieee->wpa_enabled = 0;
- priv->ieee->drop_unencrypted = 0;
- priv->ieee->privacy_invoked = 0;
- priv->ieee->ieee802_1x = 1;
-
- /* Set module parameters */
- switch (network_mode) {
- case 1:
- priv->ieee->iw_mode = IW_MODE_ADHOC;
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case 2:
- priv->ieee->iw_mode = IW_MODE_MONITOR;
- break;
-#endif
- default:
- case 0:
- priv->ieee->iw_mode = IW_MODE_INFRA;
- break;
- }
-
- if (disable == 1)
- priv->status |= STATUS_RF_KILL_SW;
-
- if (channel != 0 &&
- ((channel >= REG_MIN_CHANNEL) && (channel <= REG_MAX_CHANNEL))) {
- priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = channel;
- }
-
- if (associate)
- priv->config |= CFG_ASSOCIATE;
-
- priv->beacon_interval = DEFAULT_BEACON_INTERVAL;
- priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
- priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD | RTS_DISABLED;
- priv->frag_threshold = DEFAULT_FTS | FRAG_DISABLED;
- priv->tx_power = IPW_TX_POWER_DEFAULT;
- priv->tx_rates = DEFAULT_TX_RATES;
-
- strcpy(priv->nick, "ipw2100");
-
- spin_lock_init(&priv->low_lock);
- mutex_init(&priv->action_mutex);
- mutex_init(&priv->adapter_mutex);
-
- init_waitqueue_head(&priv->wait_command_queue);
-
- netif_carrier_off(dev);
-
- INIT_LIST_HEAD(&priv->msg_free_list);
- INIT_LIST_HEAD(&priv->msg_pend_list);
- INIT_STAT(&priv->msg_free_stat);
- INIT_STAT(&priv->msg_pend_stat);
-
- INIT_LIST_HEAD(&priv->tx_free_list);
- INIT_LIST_HEAD(&priv->tx_pend_list);
- INIT_STAT(&priv->tx_free_stat);
- INIT_STAT(&priv->tx_pend_stat);
-
- INIT_LIST_HEAD(&priv->fw_pend_list);
- INIT_STAT(&priv->fw_pend_stat);
-
- INIT_DELAYED_WORK(&priv->reset_work, ipw2100_reset_adapter);
- INIT_DELAYED_WORK(&priv->security_work, ipw2100_security_work);
- INIT_DELAYED_WORK(&priv->wx_event_work, ipw2100_wx_event_work);
- INIT_DELAYED_WORK(&priv->hang_check, ipw2100_hang_check);
- INIT_DELAYED_WORK(&priv->rf_kill, ipw2100_rf_kill);
- INIT_DELAYED_WORK(&priv->scan_event, ipw2100_scan_event);
-
- tasklet_setup(&priv->irq_tasklet, ipw2100_irq_tasklet);
-
- /* NOTE: We do not start the deferred work for status checks yet */
- priv->stop_rf_kill = 1;
- priv->stop_hang_check = 1;
-
- return dev;
-}
-
-static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
- const struct pci_device_id *ent)
-{
- void __iomem *ioaddr;
- struct net_device *dev = NULL;
- struct ipw2100_priv *priv = NULL;
- int err = 0;
- int registered = 0;
- u32 val;
-
- IPW_DEBUG_INFO("enter\n");
-
- if (!(pci_resource_flags(pci_dev, 0) & IORESOURCE_MEM)) {
- IPW_DEBUG_INFO("weird - resource type is not memory\n");
- err = -ENODEV;
- goto out;
- }
-
- ioaddr = pci_iomap(pci_dev, 0, 0);
- if (!ioaddr) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ioremap.\n");
- err = -EIO;
- goto fail;
- }
-
- /* allocate and initialize our net_device */
- dev = ipw2100_alloc_device(pci_dev, ioaddr);
- if (!dev) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ipw2100_alloc_device.\n");
- err = -ENOMEM;
- goto fail;
- }
-
- /* set up PCI mappings for device */
- err = pci_enable_device(pci_dev);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_enable_device.\n");
- return err;
- }
-
- priv = libipw_priv(dev);
-
- pci_set_master(pci_dev);
- pci_set_drvdata(pci_dev, priv);
-
- err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_set_dma_mask.\n");
- pci_disable_device(pci_dev);
- return err;
- }
-
- err = pci_request_regions(pci_dev, DRV_NAME);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling pci_request_regions.\n");
- pci_disable_device(pci_dev);
- return err;
- }
-
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_read_config_dword(pci_dev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
-
- if (!ipw2100_hw_is_adapter_in_system(dev)) {
- printk(KERN_WARNING DRV_NAME
- "Device not found via register read.\n");
- err = -ENODEV;
- goto fail;
- }
-
- SET_NETDEV_DEV(dev, &pci_dev->dev);
-
- /* Force interrupts to be shut off on the device */
- priv->status |= STATUS_INT_ENABLED;
- ipw2100_disable_interrupts(priv);
-
- /* Allocate and initialize the Tx/Rx queues and lists */
- if (ipw2100_queues_allocate(priv)) {
- printk(KERN_WARNING DRV_NAME
- "Error calling ipw2100_queues_allocate.\n");
- err = -ENOMEM;
- goto fail;
- }
- ipw2100_queues_initialize(priv);
-
- err = request_irq(pci_dev->irq,
- ipw2100_interrupt, IRQF_SHARED, dev->name, priv);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling request_irq: %d.\n", pci_dev->irq);
- goto fail;
- }
- dev->irq = pci_dev->irq;
-
- IPW_DEBUG_INFO("Attempting to register device...\n");
-
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2100 Network Connection\n");
-
- err = ipw2100_up(priv, 1);
- if (err)
- goto fail;
-
- err = ipw2100_wdev_init(dev);
- if (err)
- goto fail;
- registered = 1;
-
- /* Bring up the interface. Pre 0.46, after we registered the
- * network device we would call ipw2100_up. This introduced a race
- * condition with newer hotplug configurations (network was coming
- * up and making calls before the device was initialized).
- */
- err = register_netdev(dev);
- if (err) {
- printk(KERN_WARNING DRV_NAME
- "Error calling register_netdev.\n");
- goto fail;
- }
- registered = 2;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
-
- /* perform this after register_netdev so that dev->name is set */
- err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
- if (err)
- goto fail_unlock;
-
- /* If the RF Kill switch is disabled, go ahead and complete the
- * startup sequence */
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- /* Enable the adapter - sends HOST_COMPLETE */
- if (ipw2100_enable_adapter(priv)) {
- printk(KERN_WARNING DRV_NAME
- ": %s: failed in call to enable adapter.\n",
- priv->net_dev->name);
- ipw2100_hw_stop_adapter(priv);
- err = -EIO;
- goto fail_unlock;
- }
-
- /* Start a scan . . . */
- ipw2100_set_scan_options(priv);
- ipw2100_start_scan(priv);
- }
-
- IPW_DEBUG_INFO("exit\n");
-
- priv->status |= STATUS_INITIALIZED;
-
- mutex_unlock(&priv->action_mutex);
-out:
- return err;
-
- fail_unlock:
- mutex_unlock(&priv->action_mutex);
- fail:
- if (dev) {
- if (registered >= 2)
- unregister_netdev(dev);
-
- if (registered) {
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->bg_band.channels);
- }
-
- ipw2100_hw_stop_adapter(priv);
-
- ipw2100_disable_interrupts(priv);
-
- if (dev->irq)
- free_irq(dev->irq, priv);
-
- ipw2100_kill_works(priv);
-
- /* These are safe to call even if they weren't allocated */
- ipw2100_queues_free(priv);
- sysfs_remove_group(&pci_dev->dev.kobj,
- &ipw2100_attribute_group);
-
- free_libipw(dev, 0);
- }
-
- pci_iounmap(pci_dev, ioaddr);
-
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
- goto out;
-}
-
-static void ipw2100_pci_remove_one(struct pci_dev *pci_dev)
-{
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
- struct net_device *dev = priv->net_dev;
-
- mutex_lock(&priv->action_mutex);
-
- priv->status &= ~STATUS_INITIALIZED;
-
- sysfs_remove_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
-
-#ifdef CONFIG_PM
- if (ipw2100_firmware.version)
- ipw2100_release_firmware(priv, &ipw2100_firmware);
-#endif
- /* Take down the hardware */
- ipw2100_down(priv);
-
- /* Release the mutex so that the network subsystem can
- * complete any needed calls into the driver... */
- mutex_unlock(&priv->action_mutex);
-
- /* Unregister the device first - this results in close()
- * being called if the device is open. If we free storage
- * first, then close() will crash.
- * FIXME: remove the comment above. */
- unregister_netdev(dev);
-
- ipw2100_kill_works(priv);
-
- ipw2100_queues_free(priv);
-
- /* Free potential debugging firmware snapshot */
- ipw2100_snapshot_free(priv);
-
- free_irq(dev->irq, priv);
-
- pci_iounmap(pci_dev, priv->ioaddr);
-
- /* wiphy_unregister needs to be here, before free_libipw */
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->bg_band.channels);
- free_libipw(dev, 0);
-
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
-
- IPW_DEBUG_INFO("exit\n");
-}
-
-static int __maybe_unused ipw2100_suspend(struct device *dev_d)
-{
- struct ipw2100_priv *priv = dev_get_drvdata(dev_d);
- struct net_device *dev = priv->net_dev;
-
- IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name);
-
- mutex_lock(&priv->action_mutex);
- if (priv->status & STATUS_INITIALIZED) {
- /* Take down the device; powers it off, etc. */
- ipw2100_down(priv);
- }
-
- /* Remove the PRESENT state of the device */
- netif_device_detach(dev);
-
- priv->suspend_at = ktime_get_boottime_seconds();
-
- mutex_unlock(&priv->action_mutex);
-
- return 0;
-}
-
-static int __maybe_unused ipw2100_resume(struct device *dev_d)
-{
- struct pci_dev *pci_dev = to_pci_dev(dev_d);
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
- struct net_device *dev = priv->net_dev;
- u32 val;
-
- if (IPW2100_PM_DISABLED)
- return 0;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name);
-
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
- * from interfering with C3 CPU state. pci_restore_state won't help
- * here since it only restores the first 64 bytes pci config header.
- */
- pci_read_config_dword(pci_dev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pci_dev, 0x40, val & 0xffff00ff);
-
- /* Set the device back into the PRESENT state; this will also wake
- * the queue of needed */
- netif_device_attach(dev);
-
- priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at;
-
- /* Bring the device back up */
- if (!(priv->status & STATUS_RF_KILL_SW))
- ipw2100_up(priv, 0);
-
- mutex_unlock(&priv->action_mutex);
-
- return 0;
-}
-
-static void ipw2100_shutdown(struct pci_dev *pci_dev)
-{
- struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
-
- /* Take down the device; powers it off, etc. */
- ipw2100_down(priv);
-
- pci_disable_device(pci_dev);
-}
-
-#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
-
-static const struct pci_device_id ipw2100_pci_id_table[] = {
- IPW2100_DEV_ID(0x2520), /* IN 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2521), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2524), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2525), /* IN 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2526), /* IN 2100A mPCI Gen A3 */
- IPW2100_DEV_ID(0x2522), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2523), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2527), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2528), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2529), /* IN 2100 mPCI 3B */
- IPW2100_DEV_ID(0x252B), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252C), /* IN 2100 mPCI 3A */
- IPW2100_DEV_ID(0x252D), /* IN 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2550), /* IB 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2551), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2553), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2554), /* IB 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2555), /* IB 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2560), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2562), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2563), /* DE 2100A mPCI 3A */
- IPW2100_DEV_ID(0x2561), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2565), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2566), /* DE 2100 mPCI 3A */
- IPW2100_DEV_ID(0x2567), /* DE 2100 mPCI 3A */
-
- IPW2100_DEV_ID(0x2570), /* GA 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2580), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2582), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2583), /* TO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2581), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2585), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2586), /* TO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2587), /* TO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x2590), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2592), /* SO 2100A mPCI 3B */
- IPW2100_DEV_ID(0x2591), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2593), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2596), /* SO 2100 mPCI 3B */
- IPW2100_DEV_ID(0x2598), /* SO 2100 mPCI 3B */
-
- IPW2100_DEV_ID(0x25A0), /* HP 2100 mPCI 3B */
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, ipw2100_pci_id_table);
-
-static SIMPLE_DEV_PM_OPS(ipw2100_pm_ops, ipw2100_suspend, ipw2100_resume);
-
-static struct pci_driver ipw2100_pci_driver = {
- .name = DRV_NAME,
- .id_table = ipw2100_pci_id_table,
- .probe = ipw2100_pci_init_one,
- .remove = ipw2100_pci_remove_one,
- .driver.pm = &ipw2100_pm_ops,
- .shutdown = ipw2100_shutdown,
-};
-
-/*
- * Initialize the ipw2100 driver/module
- *
- * @returns 0 if ok, < 0 errno node con error.
- *
- * Note: we cannot init the /proc stuff until the PCI driver is there,
- * or we risk an unlikely race condition on someone accessing
- * uninitialized data in the PCI dev struct through /proc.
- */
-static int __init ipw2100_init(void)
-{
- int ret;
-
- printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
- printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
-
- cpu_latency_qos_add_request(&ipw2100_pm_qos_req, PM_QOS_DEFAULT_VALUE);
-
- ret = pci_register_driver(&ipw2100_pci_driver);
- if (ret)
- goto out;
-
-#ifdef CONFIG_IPW2100_DEBUG
- ipw2100_debug_level = debug;
- ret = driver_create_file(&ipw2100_pci_driver.driver,
- &driver_attr_debug_level);
-#endif
-
-out:
- return ret;
-}
-
-/*
- * Cleanup ipw2100 driver registration
- */
-static void __exit ipw2100_exit(void)
-{
- /* FIXME: IPG: check that we have no instances of the devices open */
-#ifdef CONFIG_IPW2100_DEBUG
- driver_remove_file(&ipw2100_pci_driver.driver,
- &driver_attr_debug_level);
-#endif
- pci_unregister_driver(&ipw2100_pci_driver);
- cpu_latency_qos_remove_request(&ipw2100_pm_qos_req);
-}
-
-module_init(ipw2100_init);
-module_exit(ipw2100_exit);
-
-static int ipw2100_wx_get_name(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- if (!(priv->status & STATUS_ASSOCIATED))
- strcpy(wrqu->name, "unassociated");
- else
- snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11b");
-
- IPW_DEBUG_WX("Name: %s\n", wrqu->name);
- return 0;
-}
-
-static int ipw2100_wx_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_freq *fwrq = &wrqu->freq;
- int err = 0;
-
- if (priv->ieee->iw_mode == IW_MODE_INFRA)
- return -EOPNOTSUPP;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- /* if setting by freq convert to channel */
- if (fwrq->e == 1) {
- if ((fwrq->m >= (int)2.412e8 && fwrq->m <= (int)2.487e8)) {
- int f = fwrq->m / 100000;
- int c = 0;
-
- while ((c < REG_MAX_CHANNEL) &&
- (f != ipw2100_frequencies[c]))
- c++;
-
- /* hack to fall through */
- fwrq->e = 0;
- fwrq->m = c + 1;
- }
- }
-
- if (fwrq->e > 0 || fwrq->m > 1000) {
- err = -EOPNOTSUPP;
- goto done;
- } else { /* Set the channel */
- IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
- err = ipw2100_set_channel(priv, fwrq->m, 0);
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->freq.e = 0;
-
- /* If we are associated, trying to associate, or have a statically
- * configured CHANNEL then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_CHANNEL ||
- priv->status & STATUS_ASSOCIATED)
- wrqu->freq.m = priv->channel;
- else
- wrqu->freq.m = 0;
-
- IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
- return 0;
-
-}
-
-static int ipw2100_wx_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("SET Mode -> %d\n", wrqu->mode);
-
- if (wrqu->mode == priv->ieee->iw_mode)
- return 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- switch (wrqu->mode) {
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
- break;
-#endif /* CONFIG_IPW2100_MONITOR */
- case IW_MODE_ADHOC:
- err = ipw2100_switch_mode(priv, IW_MODE_ADHOC);
- break;
- case IW_MODE_INFRA:
- case IW_MODE_AUTO:
- default:
- err = ipw2100_switch_mode(priv, IW_MODE_INFRA);
- break;
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->mode = priv->ieee->iw_mode;
- IPW_DEBUG_WX("GET Mode -> %d\n", wrqu->mode);
-
- return 0;
-}
-
-#define POWER_MODES 5
-
-/* Values are in microsecond */
-static const s32 timeout_duration[POWER_MODES] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-
-static const s32 period_duration[POWER_MODES] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
-static int ipw2100_wx_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_range *range = (struct iw_range *)extra;
- u16 val;
- int i, level;
-
- wrqu->data.length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- /* Let's try to keep this struct in the same order as in
- * linux/include/wireless.h
- */
-
- /* TODO: See what values we can set, and remove the ones we can't
- * set, or fill them with some default data.
- */
-
- /* ~5 Mb/s real (802.11b) */
- range->throughput = 5 * 1000 * 1000;
-
-// range->sensitivity; /* signal level threshold range */
-
- range->max_qual.qual = 100;
- /* TODO: Find real max RSSI and stick here */
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
-
- range->avg_qual.qual = 70; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
- range->avg_qual.level = 20 + IPW2100_RSSI_TO_DBM;
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
-
- range->num_bitrates = RATE_COUNT;
-
- for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) {
- range->bitrate[i] = ipw2100_bg_rates[i].bitrate * 100 * 1000;
- }
-
- range->min_rts = MIN_RTS_THRESHOLD;
- range->max_rts = MAX_RTS_THRESHOLD;
- range->min_frag = MIN_FRAG_THRESHOLD;
- range->max_frag = MAX_FRAG_THRESHOLD;
-
- range->min_pmp = period_duration[0]; /* Minimal PM period */
- range->max_pmp = period_duration[POWER_MODES - 1]; /* Maximal PM period */
- range->min_pmt = timeout_duration[POWER_MODES - 1]; /* Minimal PM timeout */
- range->max_pmt = timeout_duration[0]; /* Maximal PM timeout */
-
- /* How to decode max/min PM period */
- range->pmp_flags = IW_POWER_PERIOD;
- /* How to decode max/min PM period */
- range->pmt_flags = IW_POWER_TIMEOUT;
- /* What PM options are supported */
- range->pm_capa = IW_POWER_TIMEOUT | IW_POWER_PERIOD;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13; /* Different token sizes */
- range->num_encoding_sizes = 2; /* Number of entry in the list */
- range->max_encoding_tokens = WEP_KEYS; /* Max number of tokens */
-// range->encoding_login_index; /* token index for login token */
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- range->txpower_capa = IW_TXPOW_DBM;
- range->num_txpower = IW_MAX_TXPOWER;
- for (i = 0, level = (IPW_TX_POWER_MAX_DBM * 16);
- i < IW_MAX_TXPOWER;
- i++, level -=
- ((IPW_TX_POWER_MAX_DBM -
- IPW_TX_POWER_MIN_DBM) * 16) / (IW_MAX_TXPOWER - 1))
- range->txpower[i] = level / 16;
- } else {
- range->txpower_capa = 0;
- range->num_txpower = 0;
- }
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
-// range->retry_capa; /* What retry options are supported */
-// range->retry_flags; /* How to decode max/min retry limit */
-// range->r_time_flags; /* How to decode max/min retry life */
-// range->min_retry; /* Minimal number of retries */
-// range->max_retry; /* Maximal number of retries */
-// range->min_r_time; /* Minimal retry lifetime */
-// range->max_r_time; /* Maximal retry lifetime */
-
- range->num_channels = FREQ_COUNT;
-
- val = 0;
- for (i = 0; i < FREQ_COUNT; i++) {
- // TODO: Include only legal frequencies for some countries
-// if (local->channel_mask & (1 << i)) {
- range->freq[val].i = i + 1;
- range->freq[val].m = ipw2100_frequencies[i] * 100000;
- range->freq[val].e = 1;
- val++;
-// }
- if (val == IW_MAX_FREQUENCIES)
- break;
- }
- range->num_frequency = val;
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWAP));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- IPW_DEBUG_WX("GET Range\n");
-
- return 0;
-}
-
-static int ipw2100_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- // sanity checks
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- return -EINVAL;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
- is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
- /* we disable mandatory BSSID association */
- IPW_DEBUG_WX("exit - disable mandatory BSSID\n");
- priv->config &= ~CFG_STATIC_BSSID;
- err = ipw2100_set_mandatory_bssid(priv, NULL, 0);
- goto done;
- }
-
- priv->config |= CFG_STATIC_BSSID;
- memcpy(priv->mandatory_bssid_mac, wrqu->ap_addr.sa_data, ETH_ALEN);
-
- err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
-
- IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured BSSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_BSSID || priv->status & STATUS_ASSOCIATED) {
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
- } else
- eth_zero_addr(wrqu->ap_addr.sa_data);
-
- IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data);
- return 0;
-}
-
-static int ipw2100_wx_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- char *essid = ""; /* ANY */
- int length = 0;
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->essid.flags && wrqu->essid.length) {
- length = wrqu->essid.length;
- essid = extra;
- }
-
- if (length == 0) {
- IPW_DEBUG_WX("Setting ESSID to ANY\n");
- priv->config &= ~CFG_STATIC_ESSID;
- err = ipw2100_set_essid(priv, NULL, 0, 0);
- goto done;
- }
-
- length = min(length, IW_ESSID_MAX_SIZE);
-
- priv->config |= CFG_STATIC_ESSID;
-
- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
- IPW_DEBUG_WX("ESSID set to current ESSID.\n");
- err = 0;
- goto done;
- }
-
- IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, essid, length);
-
- priv->essid_len = length;
- memcpy(priv->essid, essid, priv->essid_len);
-
- err = ipw2100_set_essid(priv, essid, length, 0);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured ESSID then return that; otherwise return ANY */
- if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) {
- IPW_DEBUG_WX("Getting essid: '%*pE'\n",
- priv->essid_len, priv->essid);
- memcpy(extra, priv->essid, priv->essid_len);
- wrqu->essid.length = priv->essid_len;
- wrqu->essid.flags = 1; /* active */
- } else {
- IPW_DEBUG_WX("Getting essid: ANY\n");
- wrqu->essid.length = 0;
- wrqu->essid.flags = 0; /* active */
- }
-
- return 0;
-}
-
-static int ipw2100_wx_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (wrqu->data.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
-
- wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
-
- IPW_DEBUG_WX("SET Nickname -> %s\n", priv->nick);
-
- return 0;
-}
-
-static int ipw2100_wx_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->data.length = strlen(priv->nick);
- memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
-
- IPW_DEBUG_WX("GET Nickname -> %s\n", extra);
-
- return 0;
-}
-
-static int ipw2100_wx_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- u32 target_rate = wrqu->bitrate.value;
- u32 rate;
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- rate = 0;
-
- if (target_rate == 1000000 ||
- (!wrqu->bitrate.fixed && target_rate > 1000000))
- rate |= TX_RATE_1_MBIT;
- if (target_rate == 2000000 ||
- (!wrqu->bitrate.fixed && target_rate > 2000000))
- rate |= TX_RATE_2_MBIT;
- if (target_rate == 5500000 ||
- (!wrqu->bitrate.fixed && target_rate > 5500000))
- rate |= TX_RATE_5_5_MBIT;
- if (target_rate == 11000000 ||
- (!wrqu->bitrate.fixed && target_rate > 11000000))
- rate |= TX_RATE_11_MBIT;
- if (rate == 0)
- rate = DEFAULT_TX_RATES;
-
- err = ipw2100_set_tx_rates(priv, rate, 0);
-
- IPW_DEBUG_WX("SET Rate -> %04X\n", rate);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int val;
- unsigned int len = sizeof(val);
- int err = 0;
-
- if (!(priv->status & STATUS_ENABLED) ||
- priv->status & STATUS_RF_KILL_MASK ||
- !(priv->status & STATUS_ASSOCIATED)) {
- wrqu->bitrate.value = 0;
- return 0;
- }
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- err = ipw2100_get_ordinal(priv, IPW_ORD_CURRENT_TX_RATE, &val, &len);
- if (err) {
- IPW_DEBUG_WX("failed querying ordinals.\n");
- goto done;
- }
-
- switch (val & TX_RATE_MASK) {
- case TX_RATE_1_MBIT:
- wrqu->bitrate.value = 1000000;
- break;
- case TX_RATE_2_MBIT:
- wrqu->bitrate.value = 2000000;
- break;
- case TX_RATE_5_5_MBIT:
- wrqu->bitrate.value = 5500000;
- break;
- case TX_RATE_11_MBIT:
- wrqu->bitrate.value = 11000000;
- break;
- default:
- wrqu->bitrate.value = 0;
- }
-
- IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int value, err;
-
- /* Auto RTS not yet supported */
- if (wrqu->rts.fixed == 0)
- return -EINVAL;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->rts.disabled)
- value = priv->rts_threshold | RTS_DISABLED;
- else {
- if (wrqu->rts.value < 1 || wrqu->rts.value > 2304) {
- err = -EINVAL;
- goto done;
- }
- value = wrqu->rts.value;
- }
-
- err = ipw2100_set_rts_threshold(priv, value);
-
- IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X\n", value);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->rts.value = priv->rts_threshold & ~RTS_DISABLED;
- wrqu->rts.fixed = 1; /* no auto select */
-
- /* If RTS is set to the default value, then it is disabled */
- wrqu->rts.disabled = (priv->rts_threshold & RTS_DISABLED) ? 1 : 0;
-
- IPW_DEBUG_WX("GET RTS Threshold -> 0x%08X\n", wrqu->rts.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0, value;
-
- if (ipw_radio_kill_sw(priv, wrqu->txpower.disabled))
- return -EINPROGRESS;
-
- if (priv->ieee->iw_mode != IW_MODE_ADHOC)
- return 0;
-
- if ((wrqu->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
- return -EINVAL;
-
- if (wrqu->txpower.fixed == 0)
- value = IPW_TX_POWER_DEFAULT;
- else {
- if (wrqu->txpower.value < IPW_TX_POWER_MIN_DBM ||
- wrqu->txpower.value > IPW_TX_POWER_MAX_DBM)
- return -EINVAL;
-
- value = wrqu->txpower.value;
- }
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- err = ipw2100_set_tx_power(priv, value);
-
- IPW_DEBUG_WX("SET TX Power -> %d\n", value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->txpower.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
-
- if (priv->tx_power == IPW_TX_POWER_DEFAULT) {
- wrqu->txpower.fixed = 0;
- wrqu->txpower.value = IPW_TX_POWER_MAX_DBM;
- } else {
- wrqu->txpower.fixed = 1;
- wrqu->txpower.value = priv->tx_power;
- }
-
- wrqu->txpower.flags = IW_TXPOW_DBM;
-
- IPW_DEBUG_WX("GET TX Power -> %d\n", wrqu->txpower.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (!wrqu->frag.fixed)
- return -EINVAL;
-
- if (wrqu->frag.disabled) {
- priv->frag_threshold |= FRAG_DISABLED;
- priv->ieee->fts = DEFAULT_FTS;
- } else {
- if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD)
- return -EINVAL;
-
- priv->ieee->fts = wrqu->frag.value & ~0x1;
- priv->frag_threshold = priv->ieee->fts;
- }
-
- IPW_DEBUG_WX("SET Frag Threshold -> %d\n", priv->ieee->fts);
-
- return 0;
-}
-
-static int ipw2100_wx_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- wrqu->frag.value = priv->frag_threshold & ~FRAG_DISABLED;
- wrqu->frag.fixed = 0; /* no auto select */
- wrqu->frag.disabled = (priv->frag_threshold & FRAG_DISABLED) ? 1 : 0;
-
- IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
- return -EINVAL;
-
- if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
- return 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->retry.flags & IW_RETRY_SHORT) {
- err = ipw2100_set_short_retry(priv, wrqu->retry.value);
- IPW_DEBUG_WX("SET Short Retry Limit -> %d\n",
- wrqu->retry.value);
- goto done;
- }
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- err = ipw2100_set_long_retry(priv, wrqu->retry.value);
- IPW_DEBUG_WX("SET Long Retry Limit -> %d\n",
- wrqu->retry.value);
- goto done;
- }
-
- err = ipw2100_set_short_retry(priv, wrqu->retry.value);
- if (!err)
- err = ipw2100_set_long_retry(priv, wrqu->retry.value);
-
- IPW_DEBUG_WX("SET Both Retry Limits -> %d\n", wrqu->retry.value);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- wrqu->retry.disabled = 0; /* can't be disabled */
-
- if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
- return -EINVAL;
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- wrqu->retry.value = priv->long_retry_limit;
- } else {
- wrqu->retry.flags =
- (priv->short_retry_limit !=
- priv->long_retry_limit) ?
- IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
-
- wrqu->retry.value = priv->short_retry_limit;
- }
-
- IPW_DEBUG_WX("GET Retry -> %d\n", wrqu->retry.value);
-
- return 0;
-}
-
-static int ipw2100_wx_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- IPW_DEBUG_WX("Initiating scan...\n");
-
- priv->user_requested_scan = 1;
- if (ipw2100_set_scan_options(priv) || ipw2100_start_scan(priv)) {
- IPW_DEBUG_WX("Start scan failed.\n");
-
- /* TODO: Mark a scan as pending so when hardware initialized
- * a scan starts */
- }
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
-}
-
-/*
- * Implementation based on code in hostap-driver v0.1.3 hostap_ioctl.c
- */
-static int ipw2100_wx_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- /*
- * No check of STATUS_INITIALIZED required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_set_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw2100_wx_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw2100_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (wrqu->power.disabled) {
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- err = ipw2100_set_power_mode(priv, IPW_POWER_MODE_CAM);
- IPW_DEBUG_WX("SET Power Management Mode -> off\n");
- goto done;
- }
-
- switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitly state all */
- break;
- default: /* Otherwise we don't support it */
- IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
- wrqu->power.flags);
- err = -EOPNOTSUPP;
- goto done;
- }
-
- /* If the user hasn't specified a power management mode yet, default
- * to BATTERY */
- priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
- err = ipw2100_set_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
-
- IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-
-}
-
-static int ipw2100_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- wrqu->power.disabled = 1;
- else {
- wrqu->power.disabled = 0;
- wrqu->power.flags = 0;
- }
-
- IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
-
- return 0;
-}
-
-/*
- * WE-18 WPA support
- */
-
-/* SIOCSIWGENIE */
-static int ipw2100_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- u8 *buf;
-
- if (!ieee->wpa_enabled)
- return -EOPNOTSUPP;
-
- if (wrqu->data.length > MAX_WPA_IE_LEN ||
- (wrqu->data.length && extra == NULL))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = buf;
- ieee->wpa_ie_len = wrqu->data.length;
- } else {
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = NULL;
- ieee->wpa_ie_len = 0;
- }
-
- ipw2100_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
-
- return 0;
-}
-
-/* SIOCGIWGENIE */
-static int ipw2100_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
-
- if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
- wrqu->data.length = 0;
- return 0;
- }
-
- if (wrqu->data.length < ieee->wpa_ie_len)
- return -E2BIG;
-
- wrqu->data.length = ieee->wpa_ie_len;
- memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
-
- return 0;
-}
-
-/* SIOCSIWAUTH */
-static int ipw2100_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
- unsigned long flags;
- int ret = 0;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * ipw2200 does not use these parameters
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
- break;
-
- flags = crypt->ops->get_flags(crypt->priv);
-
- if (param->value)
- flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
- else
- flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
-
- crypt->ops->set_flags(flags, crypt->priv);
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:{
- /* HACK:
- *
- * wpa_supplicant calls set_wpa_enabled when the driver
- * is loaded and unloaded, regardless of if WPA is being
- * used. No other calls are made which can be used to
- * determine if encryption will be used or not prior to
- * association being expected. If encryption is not being
- * used, drop_unencrypted is set to false, else true -- we
- * can use this to determine if the CAP_PRIVACY_ON bit should
- * be set.
- */
- struct libipw_security sec = {
- .flags = SEC_ENABLED,
- .enabled = param->value,
- };
- priv->ieee->drop_unencrypted = param->value;
- /* We only change SEC_LEVEL for open mode. Others
- * are set by ipw_wpa_set_encryption.
- */
- if (!param->value) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_0;
- } else {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- }
- if (priv->ieee->set_security)
- priv->ieee->set_security(priv->ieee->dev, &sec);
- break;
- }
-
- case IW_AUTH_80211_AUTH_ALG:
- ret = ipw2100_wpa_set_auth_algs(priv, param->value);
- break;
-
- case IW_AUTH_WPA_ENABLED:
- ret = ipw2100_wpa_enable(priv, param->value);
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = param->value;
- break;
-
- //case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = param->value;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return ret;
-}
-
-/* SIOCGIWAUTH */
-static int ipw2100_wx_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * wpa_supplicant will control these internally
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->get_flags) {
- IPW_DEBUG_WARNING("Can't get TKIP countermeasures: "
- "crypt not set!\n");
- break;
- }
-
- param->value = (crypt->ops->get_flags(crypt->priv) &
- IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value = ieee->drop_unencrypted;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- param->value = priv->ieee->sec.auth_mode;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = ieee->wpa_enabled;
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- param->value = ieee->ieee802_1x;
- break;
-
- case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- param->value = ieee->privacy_invoked;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/* SIOCSIWENCODEEXT */
-static int ipw2100_wx_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCGIWENCODEEXT */
-static int ipw2100_wx_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCSIWMLME */
-static int ipw2100_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- // silently ignore
- break;
-
- case IW_MLME_DISASSOC:
- ipw2100_disassociate_bssid(priv);
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/*
- *
- * IWPRIV handlers
- *
- */
-#ifdef CONFIG_IPW2100_MONITOR
-static int ipw2100_wx_set_promisc(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int *parms = (int *)extra;
- int enable = (parms[0] > 0);
- int err = 0;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (enable) {
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- err = ipw2100_set_channel(priv, parms[1], 0);
- goto done;
- }
- priv->channel = parms[1];
- err = ipw2100_switch_mode(priv, IW_MODE_MONITOR);
- } else {
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- err = ipw2100_switch_mode(priv, priv->last_mode);
- }
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- if (priv->status & STATUS_INITIALIZED)
- schedule_reset(priv);
- return 0;
-}
-
-#endif
-
-static int ipw2100_wx_set_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err = 0, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if ((mode < 0) || (mode > POWER_MODES))
- mode = IPW_POWER_AUTO;
-
- if (IPW_POWER_LEVEL(priv->power_mode) != mode)
- err = ipw2100_set_power_mode(priv, mode);
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-#define MAX_POWER_STRING 80
-static int ipw2100_wx_get_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- int level = IPW_POWER_LEVEL(priv->power_mode);
- s32 timeout, period;
-
- if (!(priv->power_mode & IPW_POWER_ENABLED)) {
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Off)", level);
- } else {
- switch (level) {
- case IPW_POWER_MODE_CAM:
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (None)", level);
- break;
- case IPW_POWER_AUTO:
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Auto)", level);
- break;
- default:
- timeout = timeout_duration[level - 1] / 1000;
- period = period_duration[level - 1] / 1000;
- snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d "
- "(Timeout %dms, Period %dms)",
- level, timeout, period);
- }
- }
-
- wrqu->data.length = strlen(extra) + 1;
-
- return 0;
-}
-
-static int ipw2100_wx_set_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (mode == 1)
- priv->config |= CFG_LONG_PREAMBLE;
- else if (mode == 0)
- priv->config &= ~CFG_LONG_PREAMBLE;
- else {
- err = -EINVAL;
- goto done;
- }
-
- err = ipw2100_system_config(priv, 0);
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (priv->config & CFG_LONG_PREAMBLE)
- snprintf(wrqu->name, IFNAMSIZ, "long (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
-
- return 0;
-}
-
-#ifdef CONFIG_IPW2100_MONITOR
-static int ipw2100_wx_set_crc_check(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw2100_priv *priv = libipw_priv(dev);
- int err, mode = *(int *)extra;
-
- mutex_lock(&priv->action_mutex);
- if (!(priv->status & STATUS_INITIALIZED)) {
- err = -EIO;
- goto done;
- }
-
- if (mode == 1)
- priv->config |= CFG_CRC_CHECK;
- else if (mode == 0)
- priv->config &= ~CFG_CRC_CHECK;
- else {
- err = -EINVAL;
- goto done;
- }
- err = 0;
-
- done:
- mutex_unlock(&priv->action_mutex);
- return err;
-}
-
-static int ipw2100_wx_get_crc_check(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /*
- * This can be called at any time. No action lock required
- */
-
- struct ipw2100_priv *priv = libipw_priv(dev);
-
- if (priv->config & CFG_CRC_CHECK)
- snprintf(wrqu->name, IFNAMSIZ, "CRC checked (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "CRC ignored (0)");
-
- return 0;
-}
-#endif /* CONFIG_IPW2100_MONITOR */
-
-static iw_handler ipw2100_wx_handlers[] = {
- IW_HANDLER(SIOCGIWNAME, ipw2100_wx_get_name),
- IW_HANDLER(SIOCSIWFREQ, ipw2100_wx_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ipw2100_wx_get_freq),
- IW_HANDLER(SIOCSIWMODE, ipw2100_wx_set_mode),
- IW_HANDLER(SIOCGIWMODE, ipw2100_wx_get_mode),
- IW_HANDLER(SIOCGIWRANGE, ipw2100_wx_get_range),
- IW_HANDLER(SIOCSIWAP, ipw2100_wx_set_wap),
- IW_HANDLER(SIOCGIWAP, ipw2100_wx_get_wap),
- IW_HANDLER(SIOCSIWMLME, ipw2100_wx_set_mlme),
- IW_HANDLER(SIOCSIWSCAN, ipw2100_wx_set_scan),
- IW_HANDLER(SIOCGIWSCAN, ipw2100_wx_get_scan),
- IW_HANDLER(SIOCSIWESSID, ipw2100_wx_set_essid),
- IW_HANDLER(SIOCGIWESSID, ipw2100_wx_get_essid),
- IW_HANDLER(SIOCSIWNICKN, ipw2100_wx_set_nick),
- IW_HANDLER(SIOCGIWNICKN, ipw2100_wx_get_nick),
- IW_HANDLER(SIOCSIWRATE, ipw2100_wx_set_rate),
- IW_HANDLER(SIOCGIWRATE, ipw2100_wx_get_rate),
- IW_HANDLER(SIOCSIWRTS, ipw2100_wx_set_rts),
- IW_HANDLER(SIOCGIWRTS, ipw2100_wx_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ipw2100_wx_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ipw2100_wx_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, ipw2100_wx_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, ipw2100_wx_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, ipw2100_wx_set_retry),
- IW_HANDLER(SIOCGIWRETRY, ipw2100_wx_get_retry),
- IW_HANDLER(SIOCSIWENCODE, ipw2100_wx_set_encode),
- IW_HANDLER(SIOCGIWENCODE, ipw2100_wx_get_encode),
- IW_HANDLER(SIOCSIWPOWER, ipw2100_wx_set_power),
- IW_HANDLER(SIOCGIWPOWER, ipw2100_wx_get_power),
- IW_HANDLER(SIOCSIWGENIE, ipw2100_wx_set_genie),
- IW_HANDLER(SIOCGIWGENIE, ipw2100_wx_get_genie),
- IW_HANDLER(SIOCSIWAUTH, ipw2100_wx_set_auth),
- IW_HANDLER(SIOCGIWAUTH, ipw2100_wx_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, ipw2100_wx_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, ipw2100_wx_get_encodeext),
-};
-
-#define IPW2100_PRIV_SET_MONITOR SIOCIWFIRSTPRIV
-#define IPW2100_PRIV_RESET SIOCIWFIRSTPRIV+1
-#define IPW2100_PRIV_SET_POWER SIOCIWFIRSTPRIV+2
-#define IPW2100_PRIV_GET_POWER SIOCIWFIRSTPRIV+3
-#define IPW2100_PRIV_SET_LONGPREAMBLE SIOCIWFIRSTPRIV+4
-#define IPW2100_PRIV_GET_LONGPREAMBLE SIOCIWFIRSTPRIV+5
-#define IPW2100_PRIV_SET_CRC_CHECK SIOCIWFIRSTPRIV+6
-#define IPW2100_PRIV_GET_CRC_CHECK SIOCIWFIRSTPRIV+7
-
-static const struct iw_priv_args ipw2100_private_args[] = {
-
-#ifdef CONFIG_IPW2100_MONITOR
- {
- IPW2100_PRIV_SET_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
- {
- IPW2100_PRIV_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
-#endif /* CONFIG_IPW2100_MONITOR */
-
- {
- IPW2100_PRIV_SET_POWER,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_power"},
- {
- IPW2100_PRIV_GET_POWER,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_POWER_STRING,
- "get_power"},
- {
- IPW2100_PRIV_SET_LONGPREAMBLE,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_preamble"},
- {
- IPW2100_PRIV_GET_LONGPREAMBLE,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_preamble"},
-#ifdef CONFIG_IPW2100_MONITOR
- {
- IPW2100_PRIV_SET_CRC_CHECK,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_crc_check"},
- {
- IPW2100_PRIV_GET_CRC_CHECK,
- 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, "get_crc_check"},
-#endif /* CONFIG_IPW2100_MONITOR */
-};
-
-static iw_handler ipw2100_private_handler[] = {
-#ifdef CONFIG_IPW2100_MONITOR
- ipw2100_wx_set_promisc,
- ipw2100_wx_reset,
-#else /* CONFIG_IPW2100_MONITOR */
- NULL,
- NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
- ipw2100_wx_set_powermode,
- ipw2100_wx_get_powermode,
- ipw2100_wx_set_preamble,
- ipw2100_wx_get_preamble,
-#ifdef CONFIG_IPW2100_MONITOR
- ipw2100_wx_set_crc_check,
- ipw2100_wx_get_crc_check,
-#else /* CONFIG_IPW2100_MONITOR */
- NULL,
- NULL,
-#endif /* CONFIG_IPW2100_MONITOR */
-};
-
-/*
- * Get wireless statistics.
- * Called by /proc/net/wireless
- * Also called by SIOCGIWSTATS
- */
-static struct iw_statistics *ipw2100_wx_wireless_stats(struct net_device *dev)
-{
- enum {
- POOR = 30,
- FAIR = 60,
- GOOD = 80,
- VERY_GOOD = 90,
- EXCELLENT = 95,
- PERFECT = 100
- };
- int rssi_qual;
- int tx_qual;
- int beacon_qual;
- int quality;
-
- struct ipw2100_priv *priv = libipw_priv(dev);
- struct iw_statistics *wstats;
- u32 rssi, tx_retries, missed_beacons, tx_failures;
- u32 ord_len = sizeof(u32);
-
- if (!priv)
- return (struct iw_statistics *)NULL;
-
- wstats = &priv->wstats;
-
- /* if hw is disabled, then ipw2100_get_ordinal() can't be called.
- * ipw2100_wx_wireless_stats seems to be called before fw is
- * initialized. STATUS_ASSOCIATED will only be set if the hw is up
- * and associated; if not associcated, the values are all meaningless
- * anyway, so set them all to NULL and INVALID */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->miss.beacon = 0;
- wstats->discard.retries = 0;
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
- return wstats;
- }
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_MISSED_BCNS,
- &missed_beacons, &ord_len))
- goto fail_get_ordinal;
-
- /* If we don't have a connection the quality and level is 0 */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- } else {
- if (ipw2100_get_ordinal(priv, IPW_ORD_RSSI_AVG_CURR,
- &rssi, &ord_len))
- goto fail_get_ordinal;
- wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
- if (rssi < 10)
- rssi_qual = rssi * POOR / 10;
- else if (rssi < 15)
- rssi_qual = (rssi - 10) * (FAIR - POOR) / 5 + POOR;
- else if (rssi < 20)
- rssi_qual = (rssi - 15) * (GOOD - FAIR) / 5 + FAIR;
- else if (rssi < 30)
- rssi_qual = (rssi - 20) * (VERY_GOOD - GOOD) /
- 10 + GOOD;
- else
- rssi_qual = (rssi - 30) * (PERFECT - VERY_GOOD) /
- 10 + VERY_GOOD;
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_PERCENT_RETRIES,
- &tx_retries, &ord_len))
- goto fail_get_ordinal;
-
- if (tx_retries > 75)
- tx_qual = (90 - tx_retries) * POOR / 15;
- else if (tx_retries > 70)
- tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;
- else if (tx_retries > 65)
- tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;
- else if (tx_retries > 50)
- tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /
- 15 + GOOD;
- else
- tx_qual = (50 - tx_retries) *
- (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
-
- if (missed_beacons > 50)
- beacon_qual = (60 - missed_beacons) * POOR / 10;
- else if (missed_beacons > 40)
- beacon_qual = (50 - missed_beacons) * (FAIR - POOR) /
- 10 + POOR;
- else if (missed_beacons > 32)
- beacon_qual = (40 - missed_beacons) * (GOOD - FAIR) /
- 18 + FAIR;
- else if (missed_beacons > 20)
- beacon_qual = (32 - missed_beacons) *
- (VERY_GOOD - GOOD) / 20 + GOOD;
- else
- beacon_qual = (20 - missed_beacons) *
- (PERFECT - VERY_GOOD) / 20 + VERY_GOOD;
-
- quality = min(tx_qual, rssi_qual);
- quality = min(beacon_qual, quality);
-
-#ifdef CONFIG_IPW2100_DEBUG
- if (beacon_qual == quality)
- IPW_DEBUG_WX("Quality clamped by Missed Beacons\n");
- else if (tx_qual == quality)
- IPW_DEBUG_WX("Quality clamped by Tx Retries\n");
- else if (quality != 100)
- IPW_DEBUG_WX("Quality clamped by Signal Strength\n");
- else
- IPW_DEBUG_WX("Quality not clamped.\n");
-#endif
-
- wstats->qual.qual = quality;
- wstats->qual.level = rssi + IPW2100_RSSI_TO_DBM;
- }
-
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
-
- /* FIXME: this is percent and not a # */
- wstats->miss.beacon = missed_beacons;
-
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURES,
- &tx_failures, &ord_len))
- goto fail_get_ordinal;
- wstats->discard.retries = tx_failures;
-
- return wstats;
-
- fail_get_ordinal:
- IPW_DEBUG_WX("failed querying ordinals.\n");
-
- return (struct iw_statistics *)NULL;
-}
-
-static const struct iw_handler_def ipw2100_wx_handler_def = {
- .standard = ipw2100_wx_handlers,
- .num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
- .num_private = ARRAY_SIZE(ipw2100_private_handler),
- .num_private_args = ARRAY_SIZE(ipw2100_private_args),
- .private = (iw_handler *) ipw2100_private_handler,
- .private_args = (struct iw_priv_args *)ipw2100_private_args,
- .get_wireless_stats = ipw2100_wx_wireless_stats,
-};
-
-static void ipw2100_wx_event_work(struct work_struct *work)
-{
- struct ipw2100_priv *priv =
- container_of(work, struct ipw2100_priv, wx_event_work.work);
- union iwreq_data wrqu;
- unsigned int len = ETH_ALEN;
-
- if (priv->status & STATUS_STOPPING)
- return;
-
- mutex_lock(&priv->action_mutex);
-
- IPW_DEBUG_WX("enter\n");
-
- mutex_unlock(&priv->action_mutex);
-
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-
- /* Fetch BSSID from the hardware */
- if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) ||
- priv->status & STATUS_RF_KILL_MASK ||
- ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID,
- &priv->bssid, &len)) {
- eth_zero_addr(wrqu.ap_addr.sa_data);
- } else {
- /* We now have the BSSID, so can finish setting to the full
- * associated state */
- memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- memcpy(priv->ieee->bssid, priv->bssid, ETH_ALEN);
- priv->status &= ~STATUS_ASSOCIATING;
- priv->status |= STATUS_ASSOCIATED;
- netif_carrier_on(priv->net_dev);
- netif_wake_queue(priv->net_dev);
- }
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_WX("Configuring ESSID\n");
- mutex_lock(&priv->action_mutex);
- /* This is a disassociation event, so kick the firmware to
- * look for another AP */
- if (priv->config & CFG_STATIC_ESSID)
- ipw2100_set_essid(priv, priv->essid, priv->essid_len,
- 0);
- else
- ipw2100_set_essid(priv, NULL, 0, 0);
- mutex_unlock(&priv->action_mutex);
- }
-
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-#define IPW2100_FW_MAJOR_VERSION 1
-#define IPW2100_FW_MINOR_VERSION 3
-
-#define IPW2100_FW_MINOR(x) ((x & 0xff) >> 8)
-#define IPW2100_FW_MAJOR(x) (x & 0xff)
-
-#define IPW2100_FW_VERSION ((IPW2100_FW_MINOR_VERSION << 8) | \
- IPW2100_FW_MAJOR_VERSION)
-
-#define IPW2100_FW_PREFIX "ipw2100-" __stringify(IPW2100_FW_MAJOR_VERSION) \
-"." __stringify(IPW2100_FW_MINOR_VERSION)
-
-#define IPW2100_FW_NAME(x) IPW2100_FW_PREFIX "" x ".fw"
-
-/*
-
-BINARY FIRMWARE HEADER FORMAT
-
-offset length desc
-0 2 version
-2 2 mode == 0:BSS,1:IBSS,2:MONITOR
-4 4 fw_len
-8 4 uc_len
-C fw_len firmware data
-12 + fw_len uc_len microcode data
-
-*/
-
-struct ipw2100_fw_header {
- short version;
- short mode;
- unsigned int fw_size;
- unsigned int uc_size;
-} __packed;
-
-static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
-{
- struct ipw2100_fw_header *h =
- (struct ipw2100_fw_header *)fw->fw_entry->data;
-
- if (IPW2100_FW_MAJOR(h->version) != IPW2100_FW_MAJOR_VERSION) {
- printk(KERN_WARNING DRV_NAME ": Firmware image not compatible "
- "(detected version id of %u). "
- "See Documentation/networking/device_drivers/wifi/intel/ipw2100.rst\n",
- h->version);
- return 1;
- }
-
- fw->version = h->version;
- fw->fw.data = fw->fw_entry->data + sizeof(struct ipw2100_fw_header);
- fw->fw.size = h->fw_size;
- fw->uc.data = fw->fw.data + h->fw_size;
- fw->uc.size = h->uc_size;
-
- return 0;
-}
-
-static int ipw2100_get_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- char *fw_name;
- int rc;
-
- IPW_DEBUG_INFO("%s: Using hotplug firmware load.\n",
- priv->net_dev->name);
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- fw_name = IPW2100_FW_NAME("-i");
- break;
-#ifdef CONFIG_IPW2100_MONITOR
- case IW_MODE_MONITOR:
- fw_name = IPW2100_FW_NAME("-p");
- break;
-#endif
- case IW_MODE_INFRA:
- default:
- fw_name = IPW2100_FW_NAME("");
- break;
- }
-
- rc = request_firmware(&fw->fw_entry, fw_name, &priv->pci_dev->dev);
-
- if (rc < 0) {
- printk(KERN_ERR DRV_NAME ": "
- "%s: Firmware '%s' not available or load failed.\n",
- priv->net_dev->name, fw_name);
- return rc;
- }
- IPW_DEBUG_INFO("firmware data %p size %zd\n", fw->fw_entry->data,
- fw->fw_entry->size);
-
- ipw2100_mod_firmware_load(fw);
-
- return 0;
-}
-
-MODULE_FIRMWARE(IPW2100_FW_NAME("-i"));
-#ifdef CONFIG_IPW2100_MONITOR
-MODULE_FIRMWARE(IPW2100_FW_NAME("-p"));
-#endif
-MODULE_FIRMWARE(IPW2100_FW_NAME(""));
-
-static void ipw2100_release_firmware(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- fw->version = 0;
- release_firmware(fw->fw_entry);
- fw->fw_entry = NULL;
-}
-
-static int ipw2100_get_fwversion(struct ipw2100_priv *priv, char *buf,
- size_t max)
-{
- char ver[MAX_FW_VERSION_LEN];
- u32 len = MAX_FW_VERSION_LEN;
- u32 tmp;
- int i;
- /* firmware version is an ascii string (max len of 14) */
- if (ipw2100_get_ordinal(priv, IPW_ORD_STAT_FW_VER_NUM, ver, &len))
- return -EIO;
- tmp = max;
- if (len >= max)
- len = max - 1;
- for (i = 0; i < len; i++)
- buf[i] = ver[i];
- buf[i] = '\0';
- return tmp;
-}
-
-static int ipw2100_get_ucodeversion(struct ipw2100_priv *priv, char *buf,
- size_t max)
-{
- u32 ver;
- u32 len = sizeof(ver);
- /* microcode version is a 32 bit integer */
- if (ipw2100_get_ordinal(priv, IPW_ORD_UCODE_VERSION, &ver, &len))
- return -EIO;
- return snprintf(buf, max, "%08X", ver);
-}
-
-/*
- * On exit, the firmware will have been freed from the fw list
- */
-static int ipw2100_fw_download(struct ipw2100_priv *priv, struct ipw2100_fw *fw)
-{
- /* firmware is constructed of N contiguous entries, each entry is
- * structured as:
- *
- * offset sie desc
- * 0 4 address to write to
- * 4 2 length of data run
- * 6 length data
- */
- unsigned int addr;
- unsigned short len;
-
- const unsigned char *firmware_data = fw->fw.data;
- unsigned int firmware_data_left = fw->fw.size;
-
- while (firmware_data_left > 0) {
- addr = *(u32 *) (firmware_data);
- firmware_data += 4;
- firmware_data_left -= 4;
-
- len = *(u16 *) (firmware_data);
- firmware_data += 2;
- firmware_data_left -= 2;
-
- if (len > 32) {
- printk(KERN_ERR DRV_NAME ": "
- "Invalid firmware run-length of %d bytes\n",
- len);
- return -EINVAL;
- }
-
- write_nic_memory(priv->net_dev, addr, len, firmware_data);
- firmware_data += len;
- firmware_data_left -= len;
- }
-
- return 0;
-}
-
-struct symbol_alive_response {
- u8 cmd_id;
- u8 seq_num;
- u8 ucode_rev;
- u8 eeprom_valid;
- u16 valid_flags;
- u8 IEEE_addr[6];
- u16 flags;
- u16 pcb_rev;
- u16 clock_settle_time; // 1us LSB
- u16 powerup_settle_time; // 1us LSB
- u16 hop_settle_time; // 1us LSB
- u8 date[3]; // month, day, year
- u8 time[2]; // hours, minutes
- u8 ucode_valid;
-};
-
-static int ipw2100_ucode_download(struct ipw2100_priv *priv,
- struct ipw2100_fw *fw)
-{
- struct net_device *dev = priv->net_dev;
- const unsigned char *microcode_data = fw->uc.data;
- unsigned int microcode_data_left = fw->uc.size;
- void __iomem *reg = priv->ioaddr;
-
- struct symbol_alive_response response;
- int i, j;
- u8 data;
-
- /* Symbol control */
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
- readl(reg);
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
- readl(reg);
-
- /* HW config */
- write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
- readl(reg);
- write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */
- readl(reg);
-
- /* EN_CS_ACCESS bit to reset control store pointer */
- write_nic_byte(dev, 0x210000, 0x40);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x40);
- readl(reg);
-
- /* copy microcode from buffer into Symbol */
-
- while (microcode_data_left > 0) {
- write_nic_byte(dev, 0x210010, *microcode_data++);
- write_nic_byte(dev, 0x210010, *microcode_data++);
- microcode_data_left -= 2;
- }
-
- /* EN_CS_ACCESS bit to reset the control store pointer */
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
-
- /* Enable System (Reg 0)
- * first enable causes garbage in RX FIFO */
- write_nic_byte(dev, 0x210000, 0x0);
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x80);
- readl(reg);
-
- /* Reset External Baseband Reg */
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x703);
- readl(reg);
- write_nic_word(dev, IPW2100_CONTROL_REG, 0x707);
- readl(reg);
-
- /* HW Config (Reg 5) */
- write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
- readl(reg);
- write_nic_byte(dev, 0x210014, 0x72); // fifo width =16
- readl(reg);
-
- /* Enable System (Reg 0)
- * second enable should be OK */
- write_nic_byte(dev, 0x210000, 0x00); // clear enable system
- readl(reg);
- write_nic_byte(dev, 0x210000, 0x80); // set enable system
-
- /* check Symbol is enabled - upped this from 5 as it wasn't always
- * catching the update */
- for (i = 0; i < 10; i++) {
- udelay(10);
-
- /* check Dino is enabled bit */
- read_nic_byte(dev, 0x210000, &data);
- if (data & 0x1)
- break;
- }
-
- if (i == 10) {
- printk(KERN_ERR DRV_NAME ": %s: Error initializing Symbol\n",
- dev->name);
- return -EIO;
- }
-
- /* Get Symbol alive response */
- for (i = 0; i < 30; i++) {
- /* Read alive response structure */
- for (j = 0;
- j < (sizeof(struct symbol_alive_response) >> 1); j++)
- read_nic_word(dev, 0x210004, ((u16 *) & response) + j);
-
- if ((response.cmd_id == 1) && (response.ucode_valid == 0x1))
- break;
- udelay(10);
- }
-
- if (i == 30) {
- printk(KERN_ERR DRV_NAME
- ": %s: No response from Symbol - hw not alive\n",
- dev->name);
- printk_buf(IPW_DL_ERROR, (u8 *) & response, sizeof(response));
- return -EIO;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.h b/drivers/net/wireless/intel/ipw2x00/ipw2100.h
deleted file mode 100644
index b34085ade3aa1..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.h
+++ /dev/null
@@ -1,1142 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#ifndef _IPW2100_H
-#define _IPW2100_H
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/list.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <asm/io.h>
-#include <linux/socket.h>
-#include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <net/iw_handler.h> // new driver API
-
-#ifdef CONFIG_IPW2100_MONITOR
-#include <net/ieee80211_radiotap.h>
-#endif
-
-#include <linux/workqueue.h>
-#include <linux/mutex.h>
-
-#include "libipw.h"
-
-struct ipw2100_priv;
-struct ipw2100_tx_packet;
-struct ipw2100_rx_packet;
-
-#define IPW_DL_UNINIT 0x80000000
-#define IPW_DL_NONE 0x00000000
-#define IPW_DL_ALL 0x7FFFFFFF
-
-/*
- * To use the debug system;
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define IPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a IPW2100_xxxx_DEBUG() macro definition for your
- * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ipw2100/debug_level
- *
- * you simply need to add your entry to the ipw2100_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/ipw2100 then you do not have
- * CONFIG_IPW2100_DEBUG defined in your kernel configuration
- *
- */
-
-#define IPW_DL_ERROR (1<<0)
-#define IPW_DL_WARNING (1<<1)
-#define IPW_DL_INFO (1<<2)
-#define IPW_DL_WX (1<<3)
-#define IPW_DL_HC (1<<5)
-#define IPW_DL_STATE (1<<6)
-
-#define IPW_DL_NOTIF (1<<10)
-#define IPW_DL_SCAN (1<<11)
-#define IPW_DL_ASSOC (1<<12)
-#define IPW_DL_DROP (1<<13)
-
-#define IPW_DL_IOCTL (1<<14)
-#define IPW_DL_RF_KILL (1<<17)
-
-#define IPW_DL_MANAGE (1<<15)
-#define IPW_DL_FW (1<<16)
-
-#define IPW_DL_FRAG (1<<21)
-#define IPW_DL_WEP (1<<22)
-#define IPW_DL_TX (1<<23)
-#define IPW_DL_RX (1<<24)
-#define IPW_DL_ISR (1<<25)
-#define IPW_DL_IO (1<<26)
-#define IPW_DL_TRACE (1<<28)
-
-#define IPW_DEBUG_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_INFO(f...) IPW_DEBUG(IPW_DL_INFO, ## f)
-#define IPW_DEBUG_WX(f...) IPW_DEBUG(IPW_DL_WX, ## f)
-#define IPW_DEBUG_SCAN(f...) IPW_DEBUG(IPW_DL_SCAN, ## f)
-#define IPW_DEBUG_NOTIF(f...) IPW_DEBUG(IPW_DL_NOTIF, ## f)
-#define IPW_DEBUG_TRACE(f...) IPW_DEBUG(IPW_DL_TRACE, ## f)
-#define IPW_DEBUG_RX(f...) IPW_DEBUG(IPW_DL_RX, ## f)
-#define IPW_DEBUG_TX(f...) IPW_DEBUG(IPW_DL_TX, ## f)
-#define IPW_DEBUG_ISR(f...) IPW_DEBUG(IPW_DL_ISR, ## f)
-#define IPW_DEBUG_MANAGEMENT(f...) IPW_DEBUG(IPW_DL_MANAGE, ## f)
-#define IPW_DEBUG_WEP(f...) IPW_DEBUG(IPW_DL_WEP, ## f)
-#define IPW_DEBUG_HC(f...) IPW_DEBUG(IPW_DL_HC, ## f)
-#define IPW_DEBUG_FRAG(f...) IPW_DEBUG(IPW_DL_FRAG, ## f)
-#define IPW_DEBUG_FW(f...) IPW_DEBUG(IPW_DL_FW, ## f)
-#define IPW_DEBUG_RF_KILL(f...) IPW_DEBUG(IPW_DL_RF_KILL, ## f)
-#define IPW_DEBUG_DROP(f...) IPW_DEBUG(IPW_DL_DROP, ## f)
-#define IPW_DEBUG_IO(f...) IPW_DEBUG(IPW_DL_IO, ## f)
-#define IPW_DEBUG_IOCTL(f...) IPW_DEBUG(IPW_DL_IOCTL, ## f)
-#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-
-enum {
- IPW_HW_STATE_DISABLED = 1,
- IPW_HW_STATE_ENABLED = 0
-};
-
-extern const char *port_type_str[];
-extern const char *band_str[];
-
-#define NUMBER_OF_BD_PER_COMMAND_PACKET 1
-#define NUMBER_OF_BD_PER_DATA_PACKET 2
-
-#define IPW_MAX_BDS 6
-#define NUMBER_OF_OVERHEAD_BDS_PER_PACKETR 2
-#define NUMBER_OF_BDS_TO_LEAVE_FOR_COMMANDS 1
-
-#define REQUIRED_SPACE_IN_RING_FOR_COMMAND_PACKET \
- (IPW_BD_QUEUE_W_R_MIN_SPARE + NUMBER_OF_BD_PER_COMMAND_PACKET)
-
-struct bd_status {
- union {
- struct {
- u8 nlf:1, txType:2, intEnabled:1, reserved:4;
- } fields;
- u8 field;
- } info;
-} __packed;
-
-struct ipw2100_bd {
- u32 host_addr;
- u32 buf_length;
- struct bd_status status;
- /* number of fragments for frame (should be set only for
- * 1st TBD) */
- u8 num_fragments;
- u8 reserved[6];
-} __packed;
-
-#define IPW_BD_QUEUE_LENGTH(n) (1<<n)
-#define IPW_BD_ALIGNMENT(L) (L*sizeof(struct ipw2100_bd))
-
-#define IPW_BD_STATUS_TX_FRAME_802_3 0x00
-#define IPW_BD_STATUS_TX_FRAME_NOT_LAST_FRAGMENT 0x01
-#define IPW_BD_STATUS_TX_FRAME_COMMAND 0x02
-#define IPW_BD_STATUS_TX_FRAME_802_11 0x04
-#define IPW_BD_STATUS_TX_INTERRUPT_ENABLE 0x08
-
-struct ipw2100_bd_queue {
- /* driver (virtual) pointer to queue */
- struct ipw2100_bd *drv;
-
- /* firmware (physical) pointer to queue */
- dma_addr_t nic;
-
- /* Length of phy memory allocated for BDs */
- u32 size;
-
- /* Number of BDs in queue (and in array) */
- u32 entries;
-
- /* Number of available BDs (invalid for NIC BDs) */
- u32 available;
-
- /* Offset of oldest used BD in array (next one to
- * check for completion) */
- u32 oldest;
-
- /* Offset of next available (unused) BD */
- u32 next;
-};
-
-#define RX_QUEUE_LENGTH 256
-#define TX_QUEUE_LENGTH 256
-#define HW_QUEUE_LENGTH 256
-
-#define TX_PENDED_QUEUE_LENGTH (TX_QUEUE_LENGTH / NUMBER_OF_BD_PER_DATA_PACKET)
-
-#define STATUS_TYPE_MASK 0x0000000f
-#define COMMAND_STATUS_VAL 0
-#define STATUS_CHANGE_VAL 1
-#define P80211_DATA_VAL 2
-#define P8023_DATA_VAL 3
-#define HOST_NOTIFICATION_VAL 4
-
-#define IPW2100_RSSI_TO_DBM (-98)
-
-struct ipw2100_status {
- u32 frame_size;
- u16 status_fields;
- u8 flags;
-#define IPW_STATUS_FLAG_DECRYPTED (1<<0)
-#define IPW_STATUS_FLAG_WEP_ENCRYPTED (1<<1)
-#define IPW_STATUS_FLAG_CRC_ERROR (1<<2)
- u8 rssi;
-} __packed;
-
-struct ipw2100_status_queue {
- /* driver (virtual) pointer to queue */
- struct ipw2100_status *drv;
-
- /* firmware (physical) pointer to queue */
- dma_addr_t nic;
-
- /* Length of phy memory allocated for BDs */
- u32 size;
-};
-
-#define HOST_COMMAND_PARAMS_REG_LEN 100
-#define CMD_STATUS_PARAMS_REG_LEN 3
-
-#define IPW_WPA_CAPABILITIES 0x1
-#define IPW_WPA_LISTENINTERVAL 0x2
-#define IPW_WPA_AP_ADDRESS 0x4
-
-#define IPW_MAX_VAR_IE_LEN ((HOST_COMMAND_PARAMS_REG_LEN - 4) * sizeof(u32))
-
-struct ipw2100_wpa_assoc_frame {
- u16 fixed_ie_mask;
- struct {
- u16 capab_info;
- u16 listen_interval;
- u8 current_ap[ETH_ALEN];
- } fixed_ies;
- u32 var_ie_len;
- u8 var_ie[IPW_MAX_VAR_IE_LEN];
-};
-
-#define IPW_BSS 1
-#define IPW_MONITOR 2
-#define IPW_IBSS 3
-
-/**
- * @struct _tx_cmd - HWCommand
- * @brief H/W command structure.
- */
-struct ipw2100_cmd_header {
- u32 host_command_reg;
- u32 host_command_reg1;
- u32 sequence;
- u32 host_command_len_reg;
- u32 host_command_params_reg[HOST_COMMAND_PARAMS_REG_LEN];
- u32 cmd_status_reg;
- u32 cmd_status_params_reg[CMD_STATUS_PARAMS_REG_LEN];
- u32 rxq_base_ptr;
- u32 rxq_next_ptr;
- u32 rxq_host_ptr;
- u32 txq_base_ptr;
- u32 txq_next_ptr;
- u32 txq_host_ptr;
- u32 tx_status_reg;
- u32 reserved;
- u32 status_change_reg;
- u32 reserved1[3];
- u32 *ordinal1_ptr;
- u32 *ordinal2_ptr;
-} __packed;
-
-struct ipw2100_data_header {
- u32 host_command_reg;
- u32 host_command_reg1;
- u8 encrypted; // BOOLEAN in win! TRUE if frame is enc by driver
- u8 needs_encryption; // BOOLEAN in win! TRUE if frma need to be enc in NIC
- u8 wep_index; // 0 no key, 1-4 key index, 0xff immediate key
- u8 key_size; // 0 no imm key, 0x5 64bit encr, 0xd 128bit encr, 0x10 128bit encr and 128bit IV
- u8 key[16];
- u8 reserved[10]; // f/w reserved
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
- u16 fragment_size;
-} __packed;
-
-/* Host command data structure */
-struct host_command {
- u32 host_command; // COMMAND ID
- u32 host_command1; // COMMAND ID
- u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID)
- u32 host_command_length; // LENGTH
- u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS
-} __packed;
-
-typedef enum {
- POWER_ON_RESET,
- EXIT_POWER_DOWN_RESET,
- SW_RESET,
- EEPROM_RW,
- SW_RE_INIT
-} ipw2100_reset_event;
-
-enum {
- COMMAND = 0xCAFE,
- DATA,
- RX
-};
-
-struct ipw2100_tx_packet {
- int type;
- int index;
- union {
- struct { /* COMMAND */
- struct ipw2100_cmd_header *cmd;
- dma_addr_t cmd_phys;
- } c_struct;
- struct { /* DATA */
- struct ipw2100_data_header *data;
- dma_addr_t data_phys;
- struct libipw_txb *txb;
- } d_struct;
- } info;
- int jiffy_start;
-
- struct list_head list;
-};
-
-struct ipw2100_rx_packet {
- struct ipw2100_rx *rxp;
- dma_addr_t dma_addr;
- int jiffy_start;
- struct sk_buff *skb;
- struct list_head list;
-};
-
-#define FRAG_DISABLED (1<<31)
-#define RTS_DISABLED (1<<31)
-#define MAX_RTS_THRESHOLD 2304U
-#define MIN_RTS_THRESHOLD 1U
-#define DEFAULT_RTS_THRESHOLD 1000U
-
-#define DEFAULT_BEACON_INTERVAL 100U
-#define DEFAULT_SHORT_RETRY_LIMIT 7U
-#define DEFAULT_LONG_RETRY_LIMIT 4U
-
-struct ipw2100_ordinals {
- u32 table1_addr;
- u32 table2_addr;
- u32 table1_size;
- u32 table2_size;
-};
-
-/* Host Notification header */
-struct ipw2100_notification {
- u32 hnhdr_subtype; /* type of host notification */
- u32 hnhdr_size; /* size in bytes of data
- or number of entries, if table.
- Does NOT include header */
-} __packed;
-
-#define MAX_KEY_SIZE 16
-#define MAX_KEYS 8
-
-#define IPW2100_WEP_ENABLE (1<<1)
-#define IPW2100_WEP_DROP_CLEAR (1<<2)
-
-#define IPW_NONE_CIPHER (1<<0)
-#define IPW_WEP40_CIPHER (1<<1)
-#define IPW_TKIP_CIPHER (1<<2)
-#define IPW_CCMP_CIPHER (1<<4)
-#define IPW_WEP104_CIPHER (1<<5)
-#define IPW_CKIP_CIPHER (1<<6)
-
-#define IPW_AUTH_OPEN 0
-#define IPW_AUTH_SHARED 1
-#define IPW_AUTH_LEAP 2
-#define IPW_AUTH_LEAP_CISCO_ID 0x80
-
-struct statistic {
- int value;
- int hi;
- int lo;
-};
-
-#define INIT_STAT(x) do { \
- (x)->value = (x)->hi = 0; \
- (x)->lo = 0x7fffffff; \
-} while (0)
-#define SET_STAT(x,y) do { \
- (x)->value = y; \
- if ((x)->value > (x)->hi) (x)->hi = (x)->value; \
- if ((x)->value < (x)->lo) (x)->lo = (x)->value; \
-} while (0)
-#define INC_STAT(x) do { if (++(x)->value > (x)->hi) (x)->hi = (x)->value; } \
-while (0)
-#define DEC_STAT(x) do { if (--(x)->value < (x)->lo) (x)->lo = (x)->value; } \
-while (0)
-
-#define IPW2100_ERROR_QUEUE 5
-
-/* Power management code: enable or disable? */
-enum {
-#ifdef CONFIG_PM
- IPW2100_PM_DISABLED = 0,
- PM_STATE_SIZE = 16,
-#else
- IPW2100_PM_DISABLED = 1,
- PM_STATE_SIZE = 0,
-#endif
-};
-
-#define STATUS_POWERED (1<<0)
-#define STATUS_CMD_ACTIVE (1<<1) /**< host command in progress */
-#define STATUS_RUNNING (1<<2) /* Card initialized, but not enabled */
-#define STATUS_ENABLED (1<<3) /* Card enabled -- can scan,Tx,Rx */
-#define STATUS_STOPPING (1<<4) /* Card is in shutdown phase */
-#define STATUS_INITIALIZED (1<<5) /* Card is ready for external calls */
-#define STATUS_ASSOCIATING (1<<9) /* Associated, but no BSSID yet */
-#define STATUS_ASSOCIATED (1<<10) /* Associated and BSSID valid */
-#define STATUS_INT_ENABLED (1<<11)
-#define STATUS_RF_KILL_HW (1<<12)
-#define STATUS_RF_KILL_SW (1<<13)
-#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
-#define STATUS_EXIT_PENDING (1<<14)
-
-#define STATUS_SCAN_PENDING (1<<23)
-#define STATUS_SCANNING (1<<24)
-#define STATUS_SCAN_ABORTING (1<<25)
-#define STATUS_SCAN_COMPLETE (1<<26)
-#define STATUS_WX_EVENT_PENDING (1<<27)
-#define STATUS_RESET_PENDING (1<<29)
-#define STATUS_SECURITY_UPDATED (1<<30) /* Security sync needed */
-
-/* Internal NIC states */
-#define IPW_STATE_INITIALIZED (1<<0)
-#define IPW_STATE_COUNTRY_FOUND (1<<1)
-#define IPW_STATE_ASSOCIATED (1<<2)
-#define IPW_STATE_ASSN_LOST (1<<3)
-#define IPW_STATE_ASSN_CHANGED (1<<4)
-#define IPW_STATE_SCAN_COMPLETE (1<<5)
-#define IPW_STATE_ENTERED_PSP (1<<6)
-#define IPW_STATE_LEFT_PSP (1<<7)
-#define IPW_STATE_RF_KILL (1<<8)
-#define IPW_STATE_DISABLED (1<<9)
-#define IPW_STATE_POWER_DOWN (1<<10)
-#define IPW_STATE_SCANNING (1<<11)
-
-#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
-#define CFG_CUSTOM_MAC (1<<3)
-#define CFG_LONG_PREAMBLE (1<<4)
-#define CFG_ASSOCIATE (1<<6)
-#define CFG_FIXED_RATE (1<<7)
-#define CFG_ADHOC_CREATE (1<<8)
-#define CFG_PASSIVE_SCAN (1<<10)
-#ifdef CONFIG_IPW2100_MONITOR
-#define CFG_CRC_CHECK (1<<11)
-#endif
-
-#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
-
-struct ipw2100_priv {
- void __iomem *ioaddr;
-
- int stop_hang_check; /* Set 1 when shutting down to kill hang_check */
- int stop_rf_kill; /* Set 1 when shutting down to kill rf_kill */
-
- struct libipw_device *ieee;
- unsigned long status;
- unsigned long config;
- unsigned long capability;
-
- /* Statistics */
- int resets;
- time64_t reset_backoff;
-
- /* Context */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
- u8 bssid[ETH_ALEN];
- u8 channel;
- int last_mode;
-
- time64_t connect_start;
- time64_t last_reset;
-
- u32 channel_mask;
- u32 fatal_error;
- u32 fatal_errors[IPW2100_ERROR_QUEUE];
- u32 fatal_index;
- int eeprom_version;
- int firmware_version;
- unsigned long hw_features;
- int hangs;
- u32 last_rtc;
- int dump_raw; /* 1 to dump raw bytes in /sys/.../memory */
- u8 *snapshot[0x30];
-
- u8 mandatory_bssid_mac[ETH_ALEN];
- u8 mac_addr[ETH_ALEN];
-
- int power_mode;
-
- int messages_sent;
-
- int short_retry_limit;
- int long_retry_limit;
-
- u32 rts_threshold;
- u32 frag_threshold;
-
- int in_isr;
-
- u32 tx_rates;
- int tx_power;
- u32 beacon_interval;
-
- char nick[IW_ESSID_MAX_SIZE + 1];
-
- struct ipw2100_status_queue status_queue;
-
- struct statistic txq_stat;
- struct statistic rxq_stat;
- struct ipw2100_bd_queue rx_queue;
- struct ipw2100_bd_queue tx_queue;
- struct ipw2100_rx_packet *rx_buffers;
-
- struct statistic fw_pend_stat;
- struct list_head fw_pend_list;
-
- struct statistic msg_free_stat;
- struct statistic msg_pend_stat;
- struct list_head msg_free_list;
- struct list_head msg_pend_list;
- struct ipw2100_tx_packet *msg_buffers;
-
- struct statistic tx_free_stat;
- struct statistic tx_pend_stat;
- struct list_head tx_free_list;
- struct list_head tx_pend_list;
- struct ipw2100_tx_packet *tx_buffers;
-
- struct ipw2100_ordinals ordinals;
-
- struct pci_dev *pci_dev;
-
- struct proc_dir_entry *dir_dev;
-
- struct net_device *net_dev;
- struct iw_statistics wstats;
-
- struct iw_public_data wireless_data;
-
- struct tasklet_struct irq_tasklet;
-
- struct delayed_work reset_work;
- struct delayed_work security_work;
- struct delayed_work wx_event_work;
- struct delayed_work hang_check;
- struct delayed_work rf_kill;
- struct delayed_work scan_event;
-
- int user_requested_scan;
-
- /* Track time in suspend, using CLOCK_BOOTTIME */
- time64_t suspend_at;
- time64_t suspend_time;
-
- u32 interrupts;
- int tx_interrupts;
- int rx_interrupts;
- int inta_other;
-
- spinlock_t low_lock;
- struct mutex action_mutex;
- struct mutex adapter_mutex;
-
- wait_queue_head_t wait_command_queue;
-};
-
-/*********************************************************
- * Host Command -> From Driver to FW
- *********************************************************/
-
-/**
- * Host command identifiers
- */
-#define HOST_COMPLETE 2
-#define SYSTEM_CONFIG 6
-#define SSID 8
-#define MANDATORY_BSSID 9
-#define AUTHENTICATION_TYPE 10
-#define ADAPTER_ADDRESS 11
-#define PORT_TYPE 12
-#define INTERNATIONAL_MODE 13
-#define CHANNEL 14
-#define RTS_THRESHOLD 15
-#define FRAG_THRESHOLD 16
-#define POWER_MODE 17
-#define TX_RATES 18
-#define BASIC_TX_RATES 19
-#define WEP_KEY_INFO 20
-#define WEP_KEY_INDEX 25
-#define WEP_FLAGS 26
-#define ADD_MULTICAST 27
-#define CLEAR_ALL_MULTICAST 28
-#define BEACON_INTERVAL 29
-#define ATIM_WINDOW 30
-#define CLEAR_STATISTICS 31
-#define SEND 33
-#define TX_POWER_INDEX 36
-#define BROADCAST_SCAN 43
-#define CARD_DISABLE 44
-#define PREFERRED_BSSID 45
-#define SET_SCAN_OPTIONS 46
-#define SCAN_DWELL_TIME 47
-#define SWEEP_TABLE 48
-#define AP_OR_STATION_TABLE 49
-#define GROUP_ORDINALS 50
-#define SHORT_RETRY_LIMIT 51
-#define LONG_RETRY_LIMIT 52
-
-#define HOST_PRE_POWER_DOWN 58
-#define CARD_DISABLE_PHY_OFF 61
-#define MSDU_TX_RATES 62
-
-/* Rogue AP Detection */
-#define SET_STATION_STAT_BITS 64
-#define CLEAR_STATIONS_STAT_BITS 65
-#define LEAP_ROGUE_MODE 66 //TODO tbw replaced by CFG_LEAP_ROGUE_AP
-#define SET_SECURITY_INFORMATION 67
-#define DISASSOCIATION_BSSID 68
-#define SET_WPA_IE 69
-
-/* system configuration bit mask: */
-#define IPW_CFG_MONITOR 0x00004
-#define IPW_CFG_PREAMBLE_AUTO 0x00010
-#define IPW_CFG_IBSS_AUTO_START 0x00020
-#define IPW_CFG_LOOPBACK 0x00100
-#define IPW_CFG_ANSWER_BCSSID_PROBE 0x00800
-#define IPW_CFG_BT_SIDEBAND_SIGNAL 0x02000
-#define IPW_CFG_802_1x_ENABLE 0x04000
-#define IPW_CFG_BSS_MASK 0x08000
-#define IPW_CFG_IBSS_MASK 0x10000
-
-#define IPW_SCAN_NOASSOCIATE (1<<0)
-#define IPW_SCAN_MIXED_CELL (1<<1)
-/* RESERVED (1<<2) */
-#define IPW_SCAN_PASSIVE (1<<3)
-
-#define IPW_NIC_FATAL_ERROR 0x2A7F0
-#define IPW_ERROR_ADDR(x) (x & 0x3FFFF)
-#define IPW_ERROR_CODE(x) ((x & 0xFF000000) >> 24)
-#define IPW2100_ERR_C3_CORRUPTION (0x10 << 24)
-#define IPW2100_ERR_MSG_TIMEOUT (0x11 << 24)
-#define IPW2100_ERR_FW_LOAD (0x12 << 24)
-
-#define IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND 0x200
-#define IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x0D80
-
-#define IPW_MEM_HOST_SHARED_RX_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x40)
-#define IPW_MEM_HOST_SHARED_RX_STATUS_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x44)
-#define IPW_MEM_HOST_SHARED_RX_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x48)
-#define IPW_MEM_HOST_SHARED_RX_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0xa0)
-
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_BASE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x00)
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_BD_SIZE (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x04)
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_READ_INDEX (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x80)
-
-#define IPW_MEM_HOST_SHARED_RX_WRITE_INDEX \
- (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND + 0x20)
-
-#define IPW_MEM_HOST_SHARED_TX_QUEUE_WRITE_INDEX \
- (IPW_MEM_SRAM_HOST_INTERRUPT_AREA_LOWER_BOUND)
-
-#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x180)
-#define IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2 (IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND + 0x184)
-
-#define IPW2100_INTA_TX_TRANSFER (0x00000001) // Bit 0 (LSB)
-#define IPW2100_INTA_RX_TRANSFER (0x00000002) // Bit 1
-#define IPW2100_INTA_TX_COMPLETE (0x00000004) // Bit 2
-#define IPW2100_INTA_EVENT_INTERRUPT (0x00000008) // Bit 3
-#define IPW2100_INTA_STATUS_CHANGE (0x00000010) // Bit 4
-#define IPW2100_INTA_BEACON_PERIOD_EXPIRED (0x00000020) // Bit 5
-#define IPW2100_INTA_SLAVE_MODE_HOST_COMMAND_DONE (0x00010000) // Bit 16
-#define IPW2100_INTA_FW_INIT_DONE (0x01000000) // Bit 24
-#define IPW2100_INTA_FW_CALIBRATION_CALC (0x02000000) // Bit 25
-#define IPW2100_INTA_FATAL_ERROR (0x40000000) // Bit 30
-#define IPW2100_INTA_PARITY_ERROR (0x80000000) // Bit 31 (MSB)
-
-#define IPW_AUX_HOST_RESET_REG_PRINCETON_RESET (0x00000001)
-#define IPW_AUX_HOST_RESET_REG_FORCE_NMI (0x00000002)
-#define IPW_AUX_HOST_RESET_REG_PCI_HOST_CLUSTER_FATAL_NMI (0x00000004)
-#define IPW_AUX_HOST_RESET_REG_CORE_FATAL_NMI (0x00000008)
-#define IPW_AUX_HOST_RESET_REG_SW_RESET (0x00000080)
-#define IPW_AUX_HOST_RESET_REG_MASTER_DISABLED (0x00000100)
-#define IPW_AUX_HOST_RESET_REG_STOP_MASTER (0x00000200)
-
-#define IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY (0x00000001) // Bit 0 (LSB)
-#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY (0x00000002) // Bit 1
-#define IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE (0x00000004) // Bit 2
-#define IPW_AUX_HOST_GP_CNTRL_BITS_SYS_CONFIG (0x000007c0) // Bits 6-10
-#define IPW_AUX_HOST_GP_CNTRL_BIT_BUS_TYPE (0x00000200) // Bit 9
-#define IPW_AUX_HOST_GP_CNTRL_BIT_BAR0_BLOCK_SIZE (0x00000400) // Bit 10
-#define IPW_AUX_HOST_GP_CNTRL_BIT_USB_MODE (0x20000000) // Bit 29
-#define IPW_AUX_HOST_GP_CNTRL_BIT_HOST_FORCES_SYS_CLK (0x40000000) // Bit 30
-#define IPW_AUX_HOST_GP_CNTRL_BIT_FW_FORCES_SYS_CLK (0x80000000) // Bit 31 (MSB)
-
-#define IPW_BIT_GPIO_GPIO1_MASK 0x0000000C
-#define IPW_BIT_GPIO_GPIO3_MASK 0x000000C0
-#define IPW_BIT_GPIO_GPIO1_ENABLE 0x00000008
-#define IPW_BIT_GPIO_RF_KILL 0x00010000
-
-#define IPW_BIT_GPIO_LED_OFF 0x00002000 // Bit 13 = 1
-
-#define IPW_REG_DOMAIN_0_OFFSET 0x0000
-#define IPW_REG_DOMAIN_1_OFFSET IPW_MEM_SRAM_HOST_SHARED_LOWER_BOUND
-
-#define IPW_REG_INTA IPW_REG_DOMAIN_0_OFFSET + 0x0008
-#define IPW_REG_INTA_MASK IPW_REG_DOMAIN_0_OFFSET + 0x000C
-#define IPW_REG_INDIRECT_ACCESS_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0010
-#define IPW_REG_INDIRECT_ACCESS_DATA IPW_REG_DOMAIN_0_OFFSET + 0x0014
-#define IPW_REG_AUTOINCREMENT_ADDRESS IPW_REG_DOMAIN_0_OFFSET + 0x0018
-#define IPW_REG_AUTOINCREMENT_DATA IPW_REG_DOMAIN_0_OFFSET + 0x001C
-#define IPW_REG_RESET_REG IPW_REG_DOMAIN_0_OFFSET + 0x0020
-#define IPW_REG_GP_CNTRL IPW_REG_DOMAIN_0_OFFSET + 0x0024
-#define IPW_REG_GPIO IPW_REG_DOMAIN_0_OFFSET + 0x0030
-#define IPW_REG_FW_TYPE IPW_REG_DOMAIN_1_OFFSET + 0x0188
-#define IPW_REG_FW_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x018C
-#define IPW_REG_FW_COMPATIBILITY_VERSION IPW_REG_DOMAIN_1_OFFSET + 0x0190
-
-#define IPW_REG_INDIRECT_ADDR_MASK 0x00FFFFFC
-
-#define IPW_INTERRUPT_MASK 0xC1010013
-
-#define IPW2100_CONTROL_REG 0x220000
-#define IPW2100_CONTROL_PHY_OFF 0x8
-
-#define IPW2100_COMMAND 0x00300004
-#define IPW2100_COMMAND_PHY_ON 0x0
-#define IPW2100_COMMAND_PHY_OFF 0x1
-
-/* in DEBUG_AREA, values of memory always 0xd55555d5 */
-#define IPW_REG_DOA_DEBUG_AREA_START IPW_REG_DOMAIN_0_OFFSET + 0x0090
-#define IPW_REG_DOA_DEBUG_AREA_END IPW_REG_DOMAIN_0_OFFSET + 0x00FF
-#define IPW_DATA_DOA_DEBUG_VALUE 0xd55555d5
-
-#define IPW_INTERNAL_REGISTER_HALT_AND_RESET 0x003000e0
-
-#define IPW_WAIT_CLOCK_STABILIZATION_DELAY 50 // micro seconds
-#define IPW_WAIT_RESET_ARC_COMPLETE_DELAY 10 // micro seconds
-#define IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY 10 // micro seconds
-
-// BD ring queue read/write difference
-#define IPW_BD_QUEUE_W_R_MIN_SPARE 2
-
-#define IPW_CACHE_LINE_LENGTH_DEFAULT 0x80
-
-#define IPW_CARD_DISABLE_PHY_OFF_COMPLETE_WAIT 100 // 100 milli
-#define IPW_PREPARE_POWER_DOWN_COMPLETE_WAIT 100 // 100 milli
-
-#define IPW_HEADER_802_11_SIZE sizeof(struct libipw_hdr_3addr)
-#define IPW_MAX_80211_PAYLOAD_SIZE 2304U
-#define IPW_MAX_802_11_PAYLOAD_LENGTH 2312
-#define IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH 1536
-#define IPW_MIN_ACCEPTABLE_RX_FRAME_LENGTH 60
-#define IPW_MAX_ACCEPTABLE_RX_FRAME_LENGTH \
- (IPW_MAX_ACCEPTABLE_TX_FRAME_LENGTH + IPW_HEADER_802_11_SIZE - \
- sizeof(struct ethhdr))
-
-#define IPW_802_11_FCS_LENGTH 4
-#define IPW_RX_NIC_BUFFER_LENGTH \
- (IPW_MAX_802_11_PAYLOAD_LENGTH + IPW_HEADER_802_11_SIZE + \
- IPW_802_11_FCS_LENGTH)
-
-#define IPW_802_11_PAYLOAD_OFFSET \
- (sizeof(struct libipw_hdr_3addr) + \
- sizeof(struct libipw_snap_hdr))
-
-struct ipw2100_rx {
- union {
- unsigned char payload[IPW_RX_NIC_BUFFER_LENGTH];
- struct libipw_hdr_4addr header;
- u32 status;
- struct ipw2100_notification notification;
- struct ipw2100_cmd_header command;
- } rx_data;
-} __packed;
-
-/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */
-#define TX_RATE_1_MBIT 0x0001
-#define TX_RATE_2_MBIT 0x0002
-#define TX_RATE_5_5_MBIT 0x0004
-#define TX_RATE_11_MBIT 0x0008
-#define TX_RATE_MASK 0x000F
-#define DEFAULT_TX_RATES 0x000F
-
-#define IPW_POWER_MODE_CAM 0x00 //(always on)
-#define IPW_POWER_INDEX_1 0x01
-#define IPW_POWER_INDEX_2 0x02
-#define IPW_POWER_INDEX_3 0x03
-#define IPW_POWER_INDEX_4 0x04
-#define IPW_POWER_INDEX_5 0x05
-#define IPW_POWER_AUTO 0x06
-#define IPW_POWER_MASK 0x0F
-#define IPW_POWER_ENABLED 0x10
-#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
-
-#define IPW_TX_POWER_AUTO 0
-#define IPW_TX_POWER_ENHANCED 1
-
-#define IPW_TX_POWER_DEFAULT 32
-#define IPW_TX_POWER_MIN 0
-#define IPW_TX_POWER_MAX 16
-#define IPW_TX_POWER_MIN_DBM (-12)
-#define IPW_TX_POWER_MAX_DBM 16
-
-#define FW_SCAN_DONOT_ASSOCIATE 0x0001 // Dont Attempt to Associate after Scan
-#define FW_SCAN_PASSIVE 0x0008 // Force PASSSIVE Scan
-
-#define REG_MIN_CHANNEL 0
-#define REG_MAX_CHANNEL 14
-
-#define REG_CHANNEL_MASK 0x00003FFF
-#define IPW_IBSS_11B_DEFAULT_MASK 0x87ff
-
-#define DIVERSITY_EITHER 0 // Use both antennas
-#define DIVERSITY_ANTENNA_A 1 // Use antenna A
-#define DIVERSITY_ANTENNA_B 2 // Use antenna B
-
-#define HOST_COMMAND_WAIT 0
-#define HOST_COMMAND_NO_WAIT 1
-
-#define LOCK_NONE 0
-#define LOCK_DRIVER 1
-#define LOCK_FW 2
-
-#define TYPE_SWEEP_ORD 0x000D
-#define TYPE_IBSS_STTN_ORD 0x000E
-#define TYPE_BSS_AP_ORD 0x000F
-#define TYPE_RAW_BEACON_ENTRY 0x0010
-#define TYPE_CALIBRATION_DATA 0x0011
-#define TYPE_ROGUE_AP_DATA 0x0012
-#define TYPE_ASSOCIATION_REQUEST 0x0013
-#define TYPE_REASSOCIATION_REQUEST 0x0014
-
-#define HW_FEATURE_RFKILL 0x0001
-#define RF_KILLSWITCH_OFF 1
-#define RF_KILLSWITCH_ON 0
-
-#define IPW_COMMAND_POOL_SIZE 40
-
-#define IPW_START_ORD_TAB_1 1
-#define IPW_START_ORD_TAB_2 1000
-
-#define IPW_ORD_TAB_1_ENTRY_SIZE sizeof(u32)
-
-#define IS_ORDINAL_TABLE_ONE(mgr,id) \
- ((id >= IPW_START_ORD_TAB_1) && (id < mgr->table1_size))
-#define IS_ORDINAL_TABLE_TWO(mgr,id) \
- ((id >= IPW_START_ORD_TAB_2) && (id < (mgr->table2_size + IPW_START_ORD_TAB_2)))
-
-#define BSS_ID_LENGTH 6
-
-// Fixed size data: Ordinal Table 1
-typedef enum _ORDINAL_TABLE_1 { // NS - means Not Supported by FW
-// Transmit statistics
- IPW_ORD_STAT_TX_HOST_REQUESTS = 1, // # of requested Host Tx's (MSDU)
- IPW_ORD_STAT_TX_HOST_COMPLETE, // # of successful Host Tx's (MSDU)
- IPW_ORD_STAT_TX_DIR_DATA, // # of successful Directed Tx's (MSDU)
-
- IPW_ORD_STAT_TX_DIR_DATA1 = 4, // # of successful Directed Tx's (MSDU) @ 1MB
- IPW_ORD_STAT_TX_DIR_DATA2, // # of successful Directed Tx's (MSDU) @ 2MB
- IPW_ORD_STAT_TX_DIR_DATA5_5, // # of successful Directed Tx's (MSDU) @ 5_5MB
- IPW_ORD_STAT_TX_DIR_DATA11, // # of successful Directed Tx's (MSDU) @ 11MB
- IPW_ORD_STAT_TX_DIR_DATA22, // # of successful Directed Tx's (MSDU) @ 22MB
-
- IPW_ORD_STAT_TX_NODIR_DATA1 = 13, // # of successful Non_Directed Tx's (MSDU) @ 1MB
- IPW_ORD_STAT_TX_NODIR_DATA2, // # of successful Non_Directed Tx's (MSDU) @ 2MB
- IPW_ORD_STAT_TX_NODIR_DATA5_5, // # of successful Non_Directed Tx's (MSDU) @ 5.5MB
- IPW_ORD_STAT_TX_NODIR_DATA11, // # of successful Non_Directed Tx's (MSDU) @ 11MB
-
- IPW_ORD_STAT_NULL_DATA = 21, // # of successful NULL data Tx's
- IPW_ORD_STAT_TX_RTS, // # of successful Tx RTS
- IPW_ORD_STAT_TX_CTS, // # of successful Tx CTS
- IPW_ORD_STAT_TX_ACK, // # of successful Tx ACK
- IPW_ORD_STAT_TX_ASSN, // # of successful Association Tx's
- IPW_ORD_STAT_TX_ASSN_RESP, // # of successful Association response Tx's
- IPW_ORD_STAT_TX_REASSN, // # of successful Reassociation Tx's
- IPW_ORD_STAT_TX_REASSN_RESP, // # of successful Reassociation response Tx's
- IPW_ORD_STAT_TX_PROBE, // # of probes successfully transmitted
- IPW_ORD_STAT_TX_PROBE_RESP, // # of probe responses successfully transmitted
- IPW_ORD_STAT_TX_BEACON, // # of tx beacon
- IPW_ORD_STAT_TX_ATIM, // # of Tx ATIM
- IPW_ORD_STAT_TX_DISASSN, // # of successful Disassociation TX
- IPW_ORD_STAT_TX_AUTH, // # of successful Authentication Tx
- IPW_ORD_STAT_TX_DEAUTH, // # of successful Deauthentication TX
-
- IPW_ORD_STAT_TX_TOTAL_BYTES = 41, // Total successful Tx data bytes
- IPW_ORD_STAT_TX_RETRIES, // # of Tx retries
- IPW_ORD_STAT_TX_RETRY1, // # of Tx retries at 1MBPS
- IPW_ORD_STAT_TX_RETRY2, // # of Tx retries at 2MBPS
- IPW_ORD_STAT_TX_RETRY5_5, // # of Tx retries at 5.5MBPS
- IPW_ORD_STAT_TX_RETRY11, // # of Tx retries at 11MBPS
-
- IPW_ORD_STAT_TX_FAILURES = 51, // # of Tx Failures
- IPW_ORD_STAT_TX_ABORT_AT_HOP, //NS // # of Tx's aborted at hop time
- IPW_ORD_STAT_TX_MAX_TRIES_IN_HOP, // # of times max tries in a hop failed
- IPW_ORD_STAT_TX_ABORT_LATE_DMA, //NS // # of times tx aborted due to late dma setup
- IPW_ORD_STAT_TX_ABORT_STX, //NS // # of times backoff aborted
- IPW_ORD_STAT_TX_DISASSN_FAIL, // # of times disassociation failed
- IPW_ORD_STAT_TX_ERR_CTS, // # of missed/bad CTS frames
- IPW_ORD_STAT_TX_BPDU, //NS // # of spanning tree BPDUs sent
- IPW_ORD_STAT_TX_ERR_ACK, // # of tx err due to acks
-
- // Receive statistics
- IPW_ORD_STAT_RX_HOST = 61, // # of packets passed to host
- IPW_ORD_STAT_RX_DIR_DATA, // # of directed packets
- IPW_ORD_STAT_RX_DIR_DATA1, // # of directed packets at 1MB
- IPW_ORD_STAT_RX_DIR_DATA2, // # of directed packets at 2MB
- IPW_ORD_STAT_RX_DIR_DATA5_5, // # of directed packets at 5.5MB
- IPW_ORD_STAT_RX_DIR_DATA11, // # of directed packets at 11MB
- IPW_ORD_STAT_RX_DIR_DATA22, // # of directed packets at 22MB
-
- IPW_ORD_STAT_RX_NODIR_DATA = 71, // # of nondirected packets
- IPW_ORD_STAT_RX_NODIR_DATA1, // # of nondirected packets at 1MB
- IPW_ORD_STAT_RX_NODIR_DATA2, // # of nondirected packets at 2MB
- IPW_ORD_STAT_RX_NODIR_DATA5_5, // # of nondirected packets at 5.5MB
- IPW_ORD_STAT_RX_NODIR_DATA11, // # of nondirected packets at 11MB
-
- IPW_ORD_STAT_RX_NULL_DATA = 80, // # of null data rx's
- IPW_ORD_STAT_RX_POLL, //NS // # of poll rx
- IPW_ORD_STAT_RX_RTS, // # of Rx RTS
- IPW_ORD_STAT_RX_CTS, // # of Rx CTS
- IPW_ORD_STAT_RX_ACK, // # of Rx ACK
- IPW_ORD_STAT_RX_CFEND, // # of Rx CF End
- IPW_ORD_STAT_RX_CFEND_ACK, // # of Rx CF End + CF Ack
- IPW_ORD_STAT_RX_ASSN, // # of Association Rx's
- IPW_ORD_STAT_RX_ASSN_RESP, // # of Association response Rx's
- IPW_ORD_STAT_RX_REASSN, // # of Reassociation Rx's
- IPW_ORD_STAT_RX_REASSN_RESP, // # of Reassociation response Rx's
- IPW_ORD_STAT_RX_PROBE, // # of probe Rx's
- IPW_ORD_STAT_RX_PROBE_RESP, // # of probe response Rx's
- IPW_ORD_STAT_RX_BEACON, // # of Rx beacon
- IPW_ORD_STAT_RX_ATIM, // # of Rx ATIM
- IPW_ORD_STAT_RX_DISASSN, // # of disassociation Rx
- IPW_ORD_STAT_RX_AUTH, // # of authentication Rx
- IPW_ORD_STAT_RX_DEAUTH, // # of deauthentication Rx
-
- IPW_ORD_STAT_RX_TOTAL_BYTES = 101, // Total rx data bytes received
- IPW_ORD_STAT_RX_ERR_CRC, // # of packets with Rx CRC error
- IPW_ORD_STAT_RX_ERR_CRC1, // # of Rx CRC errors at 1MB
- IPW_ORD_STAT_RX_ERR_CRC2, // # of Rx CRC errors at 2MB
- IPW_ORD_STAT_RX_ERR_CRC5_5, // # of Rx CRC errors at 5.5MB
- IPW_ORD_STAT_RX_ERR_CRC11, // # of Rx CRC errors at 11MB
-
- IPW_ORD_STAT_RX_DUPLICATE1 = 112, // # of duplicate rx packets at 1MB
- IPW_ORD_STAT_RX_DUPLICATE2, // # of duplicate rx packets at 2MB
- IPW_ORD_STAT_RX_DUPLICATE5_5, // # of duplicate rx packets at 5.5MB
- IPW_ORD_STAT_RX_DUPLICATE11, // # of duplicate rx packets at 11MB
- IPW_ORD_STAT_RX_DUPLICATE = 119, // # of duplicate rx packets
-
- IPW_ORD_PERS_DB_LOCK = 120, // # locking fw permanent db
- IPW_ORD_PERS_DB_SIZE, // # size of fw permanent db
- IPW_ORD_PERS_DB_ADDR, // # address of fw permanent db
- IPW_ORD_STAT_RX_INVALID_PROTOCOL, // # of rx frames with invalid protocol
- IPW_ORD_SYS_BOOT_TIME, // # Boot time
- IPW_ORD_STAT_RX_NO_BUFFER, // # of rx frames rejected due to no buffer
- IPW_ORD_STAT_RX_ABORT_LATE_DMA, //NS // # of rx frames rejected due to dma setup too late
- IPW_ORD_STAT_RX_ABORT_AT_HOP, //NS // # of rx frames aborted due to hop
- IPW_ORD_STAT_RX_MISSING_FRAG, // # of rx frames dropped due to missing fragment
- IPW_ORD_STAT_RX_ORPHAN_FRAG, // # of rx frames dropped due to non-sequential fragment
- IPW_ORD_STAT_RX_ORPHAN_FRAME, // # of rx frames dropped due to unmatched 1st frame
- IPW_ORD_STAT_RX_FRAG_AGEOUT, // # of rx frames dropped due to uncompleted frame
- IPW_ORD_STAT_RX_BAD_SSID, //NS // Bad SSID (unused)
- IPW_ORD_STAT_RX_ICV_ERRORS, // # of ICV errors during decryption
-
-// PSP Statistics
- IPW_ORD_STAT_PSP_SUSPENSION = 137, // # of times adapter suspended
- IPW_ORD_STAT_PSP_BCN_TIMEOUT, // # of beacon timeout
- IPW_ORD_STAT_PSP_POLL_TIMEOUT, // # of poll response timeouts
- IPW_ORD_STAT_PSP_NONDIR_TIMEOUT, // # of timeouts waiting for last broadcast/muticast pkt
- IPW_ORD_STAT_PSP_RX_DTIMS, // # of PSP DTIMs received
- IPW_ORD_STAT_PSP_RX_TIMS, // # of PSP TIMs received
- IPW_ORD_STAT_PSP_STATION_ID, // PSP Station ID
-
-// Association and roaming
- IPW_ORD_LAST_ASSN_TIME = 147, // RTC time of last association
- IPW_ORD_STAT_PERCENT_MISSED_BCNS, // current calculation of % missed beacons
- IPW_ORD_STAT_PERCENT_RETRIES, // current calculation of % missed tx retries
- IPW_ORD_ASSOCIATED_AP_PTR, // If associated, this is ptr to the associated
- // AP table entry. set to 0 if not associated
- IPW_ORD_AVAILABLE_AP_CNT, // # of AP's described in the AP table
- IPW_ORD_AP_LIST_PTR, // Ptr to list of available APs
- IPW_ORD_STAT_AP_ASSNS, // # of associations
- IPW_ORD_STAT_ASSN_FAIL, // # of association failures
- IPW_ORD_STAT_ASSN_RESP_FAIL, // # of failuresdue to response fail
- IPW_ORD_STAT_FULL_SCANS, // # of full scans
-
- IPW_ORD_CARD_DISABLED, // # Card Disabled
- IPW_ORD_STAT_ROAM_INHIBIT, // # of times roaming was inhibited due to ongoing activity
- IPW_FILLER_40,
- IPW_ORD_RSSI_AT_ASSN = 160, // RSSI of associated AP at time of association
- IPW_ORD_STAT_ASSN_CAUSE1, // # of reassociations due to no tx from AP in last N
- // hops or no prob_ responses in last 3 minutes
- IPW_ORD_STAT_ASSN_CAUSE2, // # of reassociations due to poor tx/rx quality
- IPW_ORD_STAT_ASSN_CAUSE3, // # of reassociations due to tx/rx quality with excessive
- // load at the AP
- IPW_ORD_STAT_ASSN_CAUSE4, // # of reassociations due to AP RSSI level fell below
- // eligible group
- IPW_ORD_STAT_ASSN_CAUSE5, // # of reassociations due to load leveling
- IPW_ORD_STAT_ASSN_CAUSE6, //NS // # of reassociations due to dropped by Ap
- IPW_FILLER_41,
- IPW_FILLER_42,
- IPW_FILLER_43,
- IPW_ORD_STAT_AUTH_FAIL, // # of times authentication failed
- IPW_ORD_STAT_AUTH_RESP_FAIL, // # of times authentication response failed
- IPW_ORD_STATION_TABLE_CNT, // # of entries in association table
-
-// Other statistics
- IPW_ORD_RSSI_AVG_CURR = 173, // Current avg RSSI
- IPW_ORD_STEST_RESULTS_CURR, //NS // Current self test results word
- IPW_ORD_STEST_RESULTS_CUM, //NS // Cummulative self test results word
- IPW_ORD_SELF_TEST_STATUS, //NS //
- IPW_ORD_POWER_MGMT_MODE, // Power mode - 0=CAM, 1=PSP
- IPW_ORD_POWER_MGMT_INDEX, //NS //
- IPW_ORD_COUNTRY_CODE, // IEEE country code as recv'd from beacon
- IPW_ORD_COUNTRY_CHANNELS, // channels supported by country
-// IPW_ORD_COUNTRY_CHANNELS:
-// For 11b the lower 2-byte are used for channels from 1-14
-// and the higher 2-byte are not used.
- IPW_ORD_RESET_CNT, // # of adapter resets (warm)
- IPW_ORD_BEACON_INTERVAL, // Beacon interval
-
- IPW_ORD_PRINCETON_VERSION = 184, //NS // Princeton Version
- IPW_ORD_ANTENNA_DIVERSITY, // TRUE if antenna diversity is disabled
- IPW_ORD_CCA_RSSI, //NS // CCA RSSI value (factory programmed)
- IPW_ORD_STAT_EEPROM_UPDATE, //NS // # of times config EEPROM updated
- IPW_ORD_DTIM_PERIOD, // # of beacon intervals between DTIMs
- IPW_ORD_OUR_FREQ, // current radio freq lower digits - channel ID
-
- IPW_ORD_RTC_TIME = 190, // current RTC time
- IPW_ORD_PORT_TYPE, // operating mode
- IPW_ORD_CURRENT_TX_RATE, // current tx rate
- IPW_ORD_SUPPORTED_RATES, // Bitmap of supported tx rates
- IPW_ORD_ATIM_WINDOW, // current ATIM Window
- IPW_ORD_BASIC_RATES, // bitmap of basic tx rates
- IPW_ORD_NIC_HIGHEST_RATE, // bitmap of basic tx rates
- IPW_ORD_AP_HIGHEST_RATE, // bitmap of basic tx rates
- IPW_ORD_CAPABILITIES, // Management frame capability field
- IPW_ORD_AUTH_TYPE, // Type of authentication
- IPW_ORD_RADIO_TYPE, // Adapter card platform type
- IPW_ORD_RTS_THRESHOLD = 201, // Min length of packet after which RTS handshaking is used
- IPW_ORD_INT_MODE, // International mode
- IPW_ORD_FRAGMENTATION_THRESHOLD, // protocol frag threshold
- IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, // EEPROM offset in SRAM
- IPW_ORD_EEPROM_SRAM_DB_BLOCK_SIZE, // EEPROM size in SRAM
- IPW_ORD_EEPROM_SKU_CAPABILITY, // EEPROM SKU Capability 206 =
- IPW_ORD_EEPROM_IBSS_11B_CHANNELS, // EEPROM IBSS 11b channel set
-
- IPW_ORD_MAC_VERSION = 209, // MAC Version
- IPW_ORD_MAC_REVISION, // MAC Revision
- IPW_ORD_RADIO_VERSION, // Radio Version
- IPW_ORD_NIC_MANF_DATE_TIME, // MANF Date/Time STAMP
- IPW_ORD_UCODE_VERSION, // Ucode Version
- IPW_ORD_HW_RF_SWITCH_STATE = 214, // HW RF Kill Switch State
-} ORDINALTABLE1;
-
-// ordinal table 2
-// Variable length data:
-#define IPW_FIRST_VARIABLE_LENGTH_ORDINAL 1001
-
-typedef enum _ORDINAL_TABLE_2 { // NS - means Not Supported by FW
- IPW_ORD_STAT_BASE = 1000, // contains number of variable ORDs
- IPW_ORD_STAT_ADAPTER_MAC = 1001, // 6 bytes: our adapter MAC address
- IPW_ORD_STAT_PREFERRED_BSSID = 1002, // 6 bytes: BSSID of the preferred AP
- IPW_ORD_STAT_MANDATORY_BSSID = 1003, // 6 bytes: BSSID of the mandatory AP
- IPW_FILL_1, //NS //
- IPW_ORD_STAT_COUNTRY_TEXT = 1005, // 36 bytes: Country name text, First two bytes are Country code
- IPW_ORD_STAT_ASSN_SSID = 1006, // 32 bytes: ESSID String
- IPW_ORD_STATION_TABLE = 1007, // ? bytes: Station/AP table (via Direct SSID Scans)
- IPW_ORD_STAT_SWEEP_TABLE = 1008, // ? bytes: Sweep/Host Table table (via Broadcast Scans)
- IPW_ORD_STAT_ROAM_LOG = 1009, // ? bytes: Roaming log
- IPW_ORD_STAT_RATE_LOG = 1010, //NS // 0 bytes: Rate log
- IPW_ORD_STAT_FIFO = 1011, //NS // 0 bytes: Fifo buffer data structures
- IPW_ORD_STAT_FW_VER_NUM = 1012, // 14 bytes: fw version ID string as in (a.bb.ccc; "0.08.011")
- IPW_ORD_STAT_FW_DATE = 1013, // 14 bytes: fw date string (mmm dd yyyy; "Mar 13 2002")
- IPW_ORD_STAT_ASSN_AP_BSSID = 1014, // 6 bytes: MAC address of associated AP
- IPW_ORD_STAT_DEBUG = 1015, //NS // ? bytes:
- IPW_ORD_STAT_NIC_BPA_NUM = 1016, // 11 bytes: NIC BPA number in ASCII
- IPW_ORD_STAT_UCODE_DATE = 1017, // 5 bytes: uCode date
- IPW_ORD_SECURITY_NGOTIATION_RESULT = 1018,
-} ORDINALTABLE2; // NS - means Not Supported by FW
-
-#define IPW_LAST_VARIABLE_LENGTH_ORDINAL 1018
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY // enable iwspy support
-#endif
-
-#define IPW_HOST_FW_SHARED_AREA0 0x0002f200
-#define IPW_HOST_FW_SHARED_AREA0_END 0x0002f510 // 0x310 bytes
-
-#define IPW_HOST_FW_SHARED_AREA1 0x0002f610
-#define IPW_HOST_FW_SHARED_AREA1_END 0x0002f630 // 0x20 bytes
-
-#define IPW_HOST_FW_SHARED_AREA2 0x0002fa00
-#define IPW_HOST_FW_SHARED_AREA2_END 0x0002fa20 // 0x20 bytes
-
-#define IPW_HOST_FW_SHARED_AREA3 0x0002fc00
-#define IPW_HOST_FW_SHARED_AREA3_END 0x0002fc10 // 0x10 bytes
-
-#define IPW_HOST_FW_INTERRUPT_AREA 0x0002ff80
-#define IPW_HOST_FW_INTERRUPT_AREA_END 0x00030000 // 0x80 bytes
-
-struct ipw2100_fw_chunk {
- unsigned char *buf;
- long len;
- long pos;
- struct list_head list;
-};
-
-struct ipw2100_fw_chunk_set {
- const void *data;
- unsigned long size;
-};
-
-struct ipw2100_fw {
- int version;
- struct ipw2100_fw_chunk_set fw;
- struct ipw2100_fw_chunk_set uc;
- const struct firmware *fw_entry;
-};
-
-#define MAX_FW_VERSION_LEN 14
-
-#endif /* _IPW2100_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
deleted file mode 100644
index 820100cac4915..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ /dev/null
@@ -1,11965 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
- 802.11 status code portion of this file from ethereal-0.10.6:
- Copyright 2000, Axis Communications AB
- Ethereal - Network traffic analyzer
- By Gerald Combs <gerald at ethereal.com>
- Copyright 1998 Gerald Combs
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <net/cfg80211-wext.h>
-#include "ipw2200.h"
-#include "ipw.h"
-
-
-#ifndef KBUILD_EXTMOD
-#define VK "k"
-#else
-#define VK
-#endif
-
-#ifdef CONFIG_IPW2200_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#ifdef CONFIG_IPW2200_MONITOR
-#define VM "m"
-#else
-#define VM
-#endif
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-#define VP "p"
-#else
-#define VP
-#endif
-
-#ifdef CONFIG_IPW2200_RADIOTAP
-#define VR "r"
-#else
-#define VR
-#endif
-
-#ifdef CONFIG_IPW2200_QOS
-#define VQ "q"
-#else
-#define VQ
-#endif
-
-#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ
-#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
-#define DRV_VERSION IPW2200_VERSION
-
-#define ETH_P_80211_STATS (ETH_P_80211_RAW + 1)
-
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("ipw2200-ibss.fw");
-#ifdef CONFIG_IPW2200_MONITOR
-MODULE_FIRMWARE("ipw2200-sniffer.fw");
-#endif
-MODULE_FIRMWARE("ipw2200-bss.fw");
-
-static int cmdlog = 0;
-static int debug = 0;
-static int default_channel = 0;
-static int network_mode = 0;
-
-static u32 ipw_debug_level;
-static int associate;
-static int auto_create = 1;
-static int led_support = 1;
-static int disable = 0;
-static int bt_coexist = 0;
-static int hwcrypto = 0;
-static int roaming = 1;
-static const char ipw_modes[] = {
- 'a', 'b', 'g', '?'
-};
-static int antenna = CFG_SYS_ANTENNA_BOTH;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static int rtap_iface = 0; /* def: 0 -- do not create rtap interface */
-#endif
-
-static struct ieee80211_rate ipw2200_rates[] = {
- { .bitrate = 10 },
- { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
- { .bitrate = 60 },
- { .bitrate = 90 },
- { .bitrate = 120 },
- { .bitrate = 180 },
- { .bitrate = 240 },
- { .bitrate = 360 },
- { .bitrate = 480 },
- { .bitrate = 540 }
-};
-
-#define ipw2200_a_rates (ipw2200_rates + 4)
-#define ipw2200_num_a_rates 8
-#define ipw2200_bg_rates (ipw2200_rates + 0)
-#define ipw2200_num_bg_rates 12
-
-/* Ugly macro to convert literal channel numbers into their mhz equivalents
- * There are certianly some conditions that will break this (like feeding it '30')
- * but they shouldn't arise since nothing talks on channel 30. */
-#define ieee80211chan2mhz(x) \
- (((x) <= 14) ? \
- (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
- ((x) + 1000) * 5)
-
-#ifdef CONFIG_IPW2200_QOS
-static int qos_enable = 0;
-static int qos_burst_enable = 0;
-static int qos_no_ack_mask = 0;
-static int burst_duration_CCK = 0;
-static int burst_duration_OFDM = 0;
-
-static struct libipw_qos_parameters def_qos_parameters_OFDM = {
- {QOS_TX0_CW_MIN_OFDM, QOS_TX1_CW_MIN_OFDM, QOS_TX2_CW_MIN_OFDM,
- QOS_TX3_CW_MIN_OFDM},
- {QOS_TX0_CW_MAX_OFDM, QOS_TX1_CW_MAX_OFDM, QOS_TX2_CW_MAX_OFDM,
- QOS_TX3_CW_MAX_OFDM},
- {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
- {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
- {QOS_TX0_TXOP_LIMIT_OFDM, QOS_TX1_TXOP_LIMIT_OFDM,
- QOS_TX2_TXOP_LIMIT_OFDM, QOS_TX3_TXOP_LIMIT_OFDM}
-};
-
-static struct libipw_qos_parameters def_qos_parameters_CCK = {
- {QOS_TX0_CW_MIN_CCK, QOS_TX1_CW_MIN_CCK, QOS_TX2_CW_MIN_CCK,
- QOS_TX3_CW_MIN_CCK},
- {QOS_TX0_CW_MAX_CCK, QOS_TX1_CW_MAX_CCK, QOS_TX2_CW_MAX_CCK,
- QOS_TX3_CW_MAX_CCK},
- {QOS_TX0_AIFS, QOS_TX1_AIFS, QOS_TX2_AIFS, QOS_TX3_AIFS},
- {QOS_TX0_ACM, QOS_TX1_ACM, QOS_TX2_ACM, QOS_TX3_ACM},
- {QOS_TX0_TXOP_LIMIT_CCK, QOS_TX1_TXOP_LIMIT_CCK, QOS_TX2_TXOP_LIMIT_CCK,
- QOS_TX3_TXOP_LIMIT_CCK}
-};
-
-static struct libipw_qos_parameters def_parameters_OFDM = {
- {DEF_TX0_CW_MIN_OFDM, DEF_TX1_CW_MIN_OFDM, DEF_TX2_CW_MIN_OFDM,
- DEF_TX3_CW_MIN_OFDM},
- {DEF_TX0_CW_MAX_OFDM, DEF_TX1_CW_MAX_OFDM, DEF_TX2_CW_MAX_OFDM,
- DEF_TX3_CW_MAX_OFDM},
- {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
- {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
- {DEF_TX0_TXOP_LIMIT_OFDM, DEF_TX1_TXOP_LIMIT_OFDM,
- DEF_TX2_TXOP_LIMIT_OFDM, DEF_TX3_TXOP_LIMIT_OFDM}
-};
-
-static struct libipw_qos_parameters def_parameters_CCK = {
- {DEF_TX0_CW_MIN_CCK, DEF_TX1_CW_MIN_CCK, DEF_TX2_CW_MIN_CCK,
- DEF_TX3_CW_MIN_CCK},
- {DEF_TX0_CW_MAX_CCK, DEF_TX1_CW_MAX_CCK, DEF_TX2_CW_MAX_CCK,
- DEF_TX3_CW_MAX_CCK},
- {DEF_TX0_AIFS, DEF_TX1_AIFS, DEF_TX2_AIFS, DEF_TX3_AIFS},
- {DEF_TX0_ACM, DEF_TX1_ACM, DEF_TX2_ACM, DEF_TX3_ACM},
- {DEF_TX0_TXOP_LIMIT_CCK, DEF_TX1_TXOP_LIMIT_CCK, DEF_TX2_TXOP_LIMIT_CCK,
- DEF_TX3_TXOP_LIMIT_CCK}
-};
-
-static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
-
-static int from_priority_to_tx_queue[] = {
- IPW_TX_QUEUE_1, IPW_TX_QUEUE_2, IPW_TX_QUEUE_2, IPW_TX_QUEUE_1,
- IPW_TX_QUEUE_3, IPW_TX_QUEUE_3, IPW_TX_QUEUE_4, IPW_TX_QUEUE_4
-};
-
-static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv);
-
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
- *qos_param);
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
- *qos_param);
-#endif /* CONFIG_IPW2200_QOS */
-
-static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev);
-static void ipw_remove_current_network(struct ipw_priv *priv);
-static void ipw_rx(struct ipw_priv *priv);
-static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
- struct clx2_tx_queue *txq, int qindex);
-static int ipw_queue_reset(struct ipw_priv *priv);
-
-static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, const void *buf,
- int len, int sync);
-
-static void ipw_tx_queue_free(struct ipw_priv *);
-
-static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *);
-static void ipw_rx_queue_free(struct ipw_priv *, struct ipw_rx_queue *);
-static void ipw_rx_queue_replenish(void *);
-static int ipw_up(struct ipw_priv *);
-static void ipw_bg_up(struct work_struct *work);
-static void ipw_down(struct ipw_priv *);
-static void ipw_bg_down(struct work_struct *work);
-static int ipw_config(struct ipw_priv *);
-static int init_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *prates);
-static void ipw_set_hwcrypto_keys(struct ipw_priv *);
-static void ipw_send_wep_keys(struct ipw_priv *, int);
-
-static int snprint_line(char *buf, size_t count,
- const u8 * data, u32 len, u32 ofs)
-{
- int out, i, j, l;
- char c;
-
- out = scnprintf(buf, count, "%08X", ofs);
-
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++)
- out += scnprintf(buf + out, count - out, "%02X ",
- data[(i * 8 + j)]);
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- out += scnprintf(buf + out, count - out, " ");
- for (l = 0, i = 0; i < 2; i++) {
- out += scnprintf(buf + out, count - out, " ");
- for (j = 0; j < 8 && l < len; j++, l++) {
- c = data[(i * 8 + j)];
- if (!isascii(c) || !isprint(c))
- c = '.';
-
- out += scnprintf(buf + out, count - out, "%c", c);
- }
-
- for (; j < 8; j++)
- out += scnprintf(buf + out, count - out, " ");
- }
-
- return out;
-}
-
-static void printk_buf(int level, const u8 * data, u32 len)
-{
- char line[81];
- u32 ofs = 0;
- if (!(ipw_debug_level & level))
- return;
-
- while (len) {
- snprint_line(line, sizeof(line), &data[ofs],
- min(len, 16U), ofs);
- printk(KERN_DEBUG "%s\n", line);
- ofs += 16;
- len -= min(len, 16U);
- }
-}
-
-static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len)
-{
- size_t out = size;
- u32 ofs = 0;
- int total = 0;
-
- while (size && len) {
- out = snprint_line(output, size, &data[ofs],
- min_t(size_t, len, 16U), ofs);
-
- ofs += 16;
- output += out;
- size -= out;
- len -= min_t(size_t, len, 16U);
- total += out;
- }
- return total;
-}
-
-/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
-static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg);
-#define ipw_read_reg32(a, b) _ipw_read_reg32(a, b)
-
-/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */
-static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg);
-#define ipw_read_reg8(a, b) _ipw_read_reg8(a, b)
-
-/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value);
-static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect8(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg8(a, b, c);
-}
-
-/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value);
-static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect16(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg16(a, b, c);
-}
-
-/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */
-static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value);
-static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
-{
- IPW_DEBUG_IO("%s %d: write_indirect32(0x%08X, 0x%08X)\n", __FILE__,
- __LINE__, (u32) (b), (u32) (c));
- _ipw_write_reg32(a, b, c);
-}
-
-/* 8-bit direct write (low 4K) */
-static inline void _ipw_write8(struct ipw_priv *ipw, unsigned long ofs,
- u8 val)
-{
- writeb(val, ipw->hw_base + ofs);
-}
-
-/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write8(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write8(ipw, ofs, val); \
-} while (0)
-
-/* 16-bit direct write (low 4K) */
-static inline void _ipw_write16(struct ipw_priv *ipw, unsigned long ofs,
- u16 val)
-{
- writew(val, ipw->hw_base + ofs);
-}
-
-/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write16(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write16(ipw, ofs, val); \
-} while (0)
-
-/* 32-bit direct write (low 4K) */
-static inline void _ipw_write32(struct ipw_priv *ipw, unsigned long ofs,
- u32 val)
-{
- writel(val, ipw->hw_base + ofs);
-}
-
-/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write32(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, \
- __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write32(ipw, ofs, val); \
-} while (0)
-
-/* 8-bit direct read (low 4K) */
-static inline u8 _ipw_read8(struct ipw_priv *ipw, unsigned long ofs)
-{
- return readb(ipw->hw_base + ofs);
-}
-
-/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read8(ipw, ofs) ({ \
- IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", __FILE__, __LINE__, \
- (u32)(ofs)); \
- _ipw_read8(ipw, ofs); \
-})
-
-/* 32-bit direct read (low 4K) */
-static inline u32 _ipw_read32(struct ipw_priv *ipw, unsigned long ofs)
-{
- return readl(ipw->hw_base + ofs);
-}
-
-/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read32(ipw, ofs) ({ \
- IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", __FILE__, __LINE__, \
- (u32)(ofs)); \
- _ipw_read32(ipw, ofs); \
-})
-
-static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
-/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
-#define ipw_read_indirect(a, b, c, d) ({ \
- IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %u bytes\n", __FILE__, \
- __LINE__, (u32)(b), (u32)(d)); \
- _ipw_read_indirect(a, b, c, d); \
-})
-
-/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
-static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
- int num);
-#define ipw_write_indirect(a, b, c, d) do { \
- IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %u bytes\n", __FILE__, \
- __LINE__, (u32)(b), (u32)(d)); \
- _ipw_write_indirect(a, b, c, d); \
-} while (0)
-
-/* 32-bit indirect write (above 4K) */
-static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
-{
- IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
- _ipw_write32(priv, IPW_INDIRECT_DATA, value);
-}
-
-/* 8-bit indirect write (above 4K) */
-static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value)
-{
- u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = reg - aligned_addr;
-
- IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value);
-}
-
-/* 16-bit indirect write (above 4K) */
-static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value)
-{
- u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = (reg - aligned_addr) & (~0x1ul);
-
- IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value);
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value);
-}
-
-/* 8-bit indirect read (above 4K) */
-static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg)
-{
- u32 word;
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK);
- IPW_DEBUG_IO(" reg = 0x%8X :\n", reg);
- word = _ipw_read32(priv, IPW_INDIRECT_DATA);
- return (word >> ((reg & 0x3) * 8)) & 0xff;
-}
-
-/* 32-bit indirect read (above 4K) */
-static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg)
-{
- u32 value;
-
- IPW_DEBUG_IO("%p : reg = 0x%08x\n", priv, reg);
-
- _ipw_write32(priv, IPW_INDIRECT_ADDR, reg);
- value = _ipw_read32(priv, IPW_INDIRECT_DATA);
- IPW_DEBUG_IO(" reg = 0x%4X : value = 0x%4x\n", reg, value);
- return value;
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) read, */
-/* for area above 1st 4K of SRAM/reg space */
-static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
- int num)
-{
- u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = addr - aligned_addr;
- u32 i;
-
- IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
-
- if (num <= 0) {
- return;
- }
-
- /* Read the first dword (or portion) byte by byte */
- if (unlikely(dif_len)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- /* Start reading at aligned_addr + dif_len */
- for (i = dif_len; ((i < 4) && (num > 0)); i++, num--)
- *buf++ = _ipw_read8(priv, IPW_INDIRECT_DATA + i);
- aligned_addr += 4;
- }
-
- /* Read all of the middle dwords as dwords, with auto-increment */
- _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
- for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
- *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA);
-
- /* Read the last dword (or portion) byte by byte */
- if (unlikely(num)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- for (i = 0; num > 0; i++, num--)
- *buf++ = ipw_read8(priv, IPW_INDIRECT_DATA + i);
- }
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) write, */
-/* for area above 1st 4K of SRAM/reg space */
-static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf,
- int num)
-{
- u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */
- u32 dif_len = addr - aligned_addr;
- u32 i;
-
- IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num);
-
- if (num <= 0) {
- return;
- }
-
- /* Write the first dword (or portion) byte by byte */
- if (unlikely(dif_len)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- /* Start writing at aligned_addr + dif_len */
- for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++)
- _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
- aligned_addr += 4;
- }
-
- /* Write all of the middle dwords as dwords, with auto-increment */
- _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr);
- for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4)
- _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf);
-
- /* Write the last dword (or portion) byte by byte */
- if (unlikely(num)) {
- _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr);
- for (i = 0; num > 0; i++, num--, buf++)
- _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf);
- }
-}
-
-/* General purpose, no alignment requirement, iterative (multi-byte) write, */
-/* for 1st 4K of SRAM/regs space */
-static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf,
- int num)
-{
- memcpy_toio((priv->hw_base + addr), buf, num);
-}
-
-/* Set bit(s) in low 4K of SRAM/regs */
-static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask)
-{
- ipw_write32(priv, reg, ipw_read32(priv, reg) | mask);
-}
-
-/* Clear bit(s) in low 4K of SRAM/regs */
-static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask)
-{
- ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask);
-}
-
-static inline void __ipw_enable_interrupts(struct ipw_priv *priv)
-{
- if (priv->status & STATUS_INT_ENABLED)
- return;
- priv->status |= STATUS_INT_ENABLED;
- ipw_write32(priv, IPW_INTA_MASK_R, IPW_INTA_MASK_ALL);
-}
-
-static inline void __ipw_disable_interrupts(struct ipw_priv *priv)
-{
- if (!(priv->status & STATUS_INT_ENABLED))
- return;
- priv->status &= ~STATUS_INT_ENABLED;
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
-}
-
-static inline void ipw_enable_interrupts(struct ipw_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- __ipw_enable_interrupts(priv);
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static inline void ipw_disable_interrupts(struct ipw_priv *priv)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
- __ipw_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-}
-
-static char *ipw_error_desc(u32 val)
-{
- switch (val) {
- case IPW_FW_ERROR_OK:
- return "ERROR_OK";
- case IPW_FW_ERROR_FAIL:
- return "ERROR_FAIL";
- case IPW_FW_ERROR_MEMORY_UNDERFLOW:
- return "MEMORY_UNDERFLOW";
- case IPW_FW_ERROR_MEMORY_OVERFLOW:
- return "MEMORY_OVERFLOW";
- case IPW_FW_ERROR_BAD_PARAM:
- return "BAD_PARAM";
- case IPW_FW_ERROR_BAD_CHECKSUM:
- return "BAD_CHECKSUM";
- case IPW_FW_ERROR_NMI_INTERRUPT:
- return "NMI_INTERRUPT";
- case IPW_FW_ERROR_BAD_DATABASE:
- return "BAD_DATABASE";
- case IPW_FW_ERROR_ALLOC_FAIL:
- return "ALLOC_FAIL";
- case IPW_FW_ERROR_DMA_UNDERRUN:
- return "DMA_UNDERRUN";
- case IPW_FW_ERROR_DMA_STATUS:
- return "DMA_STATUS";
- case IPW_FW_ERROR_DINO_ERROR:
- return "DINO_ERROR";
- case IPW_FW_ERROR_EEPROM_ERROR:
- return "EEPROM_ERROR";
- case IPW_FW_ERROR_SYSASSERT:
- return "SYSASSERT";
- case IPW_FW_ERROR_FATAL_ERROR:
- return "FATAL_ERROR";
- default:
- return "UNKNOWN_ERROR";
- }
-}
-
-static void ipw_dump_error_log(struct ipw_priv *priv,
- struct ipw_fw_error *error)
-{
- u32 i;
-
- if (!error) {
- IPW_ERROR("Error allocating and capturing error log. "
- "Nothing to dump.\n");
- return;
- }
-
- IPW_ERROR("Start IPW Error Log Dump:\n");
- IPW_ERROR("Status: 0x%08X, Config: %08X\n",
- error->status, error->config);
-
- for (i = 0; i < error->elem_len; i++)
- IPW_ERROR("%s %i 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
- ipw_error_desc(error->elem[i].desc),
- error->elem[i].time,
- error->elem[i].blink1,
- error->elem[i].blink2,
- error->elem[i].link1,
- error->elem[i].link2, error->elem[i].data);
- for (i = 0; i < error->log_len; i++)
- IPW_ERROR("%i\t0x%08x\t%i\n",
- error->log[i].time,
- error->log[i].data, error->log[i].event);
-}
-
-static inline int ipw_is_init(struct ipw_priv *priv)
-{
- return (priv->status & STATUS_INIT) ? 1 : 0;
-}
-
-static int ipw_get_ordinal(struct ipw_priv *priv, u32 ord, void *val, u32 * len)
-{
- u32 addr, field_info, field_len, field_count, total_len;
-
- IPW_DEBUG_ORD("ordinal = %i\n", ord);
-
- if (!priv || !val || !len) {
- IPW_DEBUG_ORD("Invalid argument\n");
- return -EINVAL;
- }
-
- /* verify device ordinal tables have been initialized */
- if (!priv->table0_addr || !priv->table1_addr || !priv->table2_addr) {
- IPW_DEBUG_ORD("Access ordinals before initialization\n");
- return -EINVAL;
- }
-
- switch (IPW_ORD_TABLE_ID_MASK & ord) {
- case IPW_ORD_TABLE_0_MASK:
- /*
- * TABLE 0: Direct access to a table of 32 bit values
- *
- * This is a very simple table with the data directly
- * read from the table
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table0_len) {
- IPW_DEBUG_ORD("ordinal value (%i) longer then "
- "max (%i)\n", ord, priv->table0_len);
- return -EINVAL;
- }
-
- /* verify we have enough room to store the value */
- if (*len < sizeof(u32)) {
- IPW_DEBUG_ORD("ordinal buffer length too small, "
- "need %zd\n", sizeof(u32));
- return -EINVAL;
- }
-
- IPW_DEBUG_ORD("Reading TABLE0[%i] from offset 0x%08x\n",
- ord, priv->table0_addr + (ord << 2));
-
- *len = sizeof(u32);
- ord <<= 2;
- *((u32 *) val) = ipw_read32(priv, priv->table0_addr + ord);
- break;
-
- case IPW_ORD_TABLE_1_MASK:
- /*
- * TABLE 1: Indirect access to a table of 32 bit values
- *
- * This is a fairly large table of u32 values each
- * representing starting addr for the data (which is
- * also a u32)
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table1_len) {
- IPW_DEBUG_ORD("ordinal value too long\n");
- return -EINVAL;
- }
-
- /* verify we have enough room to store the value */
- if (*len < sizeof(u32)) {
- IPW_DEBUG_ORD("ordinal buffer length too small, "
- "need %zd\n", sizeof(u32));
- return -EINVAL;
- }
-
- *((u32 *) val) =
- ipw_read_reg32(priv, (priv->table1_addr + (ord << 2)));
- *len = sizeof(u32);
- break;
-
- case IPW_ORD_TABLE_2_MASK:
- /*
- * TABLE 2: Indirect access to a table of variable sized values
- *
- * This table consist of six values, each containing
- * - dword containing the starting offset of the data
- * - dword containing the lengh in the first 16bits
- * and the count in the second 16bits
- */
-
- /* remove the table id from the ordinal */
- ord &= IPW_ORD_TABLE_VALUE_MASK;
-
- /* boundary check */
- if (ord > priv->table2_len) {
- IPW_DEBUG_ORD("ordinal value too long\n");
- return -EINVAL;
- }
-
- /* get the address of statistic */
- addr = ipw_read_reg32(priv, priv->table2_addr + (ord << 3));
-
- /* get the second DW of statistics ;
- * two 16-bit words - first is length, second is count */
- field_info =
- ipw_read_reg32(priv,
- priv->table2_addr + (ord << 3) +
- sizeof(u32));
-
- /* get each entry length */
- field_len = *((u16 *) & field_info);
-
- /* get number of entries */
- field_count = *(((u16 *) & field_info) + 1);
-
- /* abort if not enough memory */
- total_len = field_len * field_count;
- if (total_len > *len) {
- *len = total_len;
- return -EINVAL;
- }
-
- *len = total_len;
- if (!total_len)
- return 0;
-
- IPW_DEBUG_ORD("addr = 0x%08x, total_len = %i, "
- "field_info = 0x%08x\n",
- addr, total_len, field_info);
- ipw_read_indirect(priv, addr, val, total_len);
- break;
-
- default:
- IPW_DEBUG_ORD("Invalid ordinal!\n");
- return -EINVAL;
-
- }
-
- return 0;
-}
-
-static void ipw_init_ordinals(struct ipw_priv *priv)
-{
- priv->table0_addr = IPW_ORDINALS_TABLE_LOWER;
- priv->table0_len = ipw_read32(priv, priv->table0_addr);
-
- IPW_DEBUG_ORD("table 0 offset at 0x%08x, len = %i\n",
- priv->table0_addr, priv->table0_len);
-
- priv->table1_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_1);
- priv->table1_len = ipw_read_reg32(priv, priv->table1_addr);
-
- IPW_DEBUG_ORD("table 1 offset at 0x%08x, len = %i\n",
- priv->table1_addr, priv->table1_len);
-
- priv->table2_addr = ipw_read32(priv, IPW_ORDINALS_TABLE_2);
- priv->table2_len = ipw_read_reg32(priv, priv->table2_addr);
- priv->table2_len &= 0x0000ffff; /* use first two bytes */
-
- IPW_DEBUG_ORD("table 2 offset at 0x%08x, len = %i\n",
- priv->table2_addr, priv->table2_len);
-
-}
-
-static u32 ipw_register_toggle(u32 reg)
-{
- reg &= ~IPW_START_STANDBY;
- if (reg & IPW_GATE_ODMA)
- reg &= ~IPW_GATE_ODMA;
- if (reg & IPW_GATE_IDMA)
- reg &= ~IPW_GATE_IDMA;
- if (reg & IPW_GATE_ADMA)
- reg &= ~IPW_GATE_ADMA;
- return reg;
-}
-
-/*
- * LED behavior:
- * - On radio ON, turn on any LEDs that require to be on during start
- * - On initialization, start unassociated blink
- * - On association, disable unassociated blink
- * - On disassociation, start unassociated blink
- * - On radio OFF, turn off any LEDs started during radio on
- *
- */
-#define LD_TIME_LINK_ON msecs_to_jiffies(300)
-#define LD_TIME_LINK_OFF msecs_to_jiffies(2700)
-#define LD_TIME_ACT_ON msecs_to_jiffies(250)
-
-static void ipw_led_link_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* If configured to not use LEDs, or nic_type is 1,
- * then we don't toggle a LINK led */
- if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (!(priv->status & STATUS_RF_KILL_MASK) &&
- !(priv->status & STATUS_LED_LINK_ON)) {
- IPW_DEBUG_LED("Link LED On\n");
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led |= priv->led_association_on;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- priv->status |= STATUS_LED_LINK_ON;
-
- /* If we aren't associated, schedule turning the LED off */
- if (!(priv->status & STATUS_ASSOCIATED))
- schedule_delayed_work(&priv->led_link_off,
- LD_TIME_LINK_ON);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_link_on(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_link_on.work);
- mutex_lock(&priv->mutex);
- ipw_led_link_on(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_led_link_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* If configured not to use LEDs, or nic type is 1,
- * then we don't goggle the LINK led. */
- if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->status & STATUS_LED_LINK_ON) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_association_off;
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Link LED Off\n");
-
- priv->status &= ~STATUS_LED_LINK_ON;
-
- /* If we aren't associated and the radio is on, schedule
- * turning the LED on (blink while unassociated) */
- if (!(priv->status & STATUS_RF_KILL_MASK) &&
- !(priv->status & STATUS_ASSOCIATED))
- schedule_delayed_work(&priv->led_link_on,
- LD_TIME_LINK_OFF);
-
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_link_off(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_link_off.work);
- mutex_lock(&priv->mutex);
- ipw_led_link_off(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void __ipw_led_activity_on(struct ipw_priv *priv)
-{
- u32 led;
-
- if (priv->config & CFG_NO_LED)
- return;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return;
-
- if (!(priv->status & STATUS_LED_ACT_ON)) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led |= priv->led_activity_on;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Activity LED On\n");
-
- priv->status |= STATUS_LED_ACT_ON;
-
- cancel_delayed_work(&priv->led_act_off);
- schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
- } else {
- /* Reschedule LED off for full time period */
- cancel_delayed_work(&priv->led_act_off);
- schedule_delayed_work(&priv->led_act_off, LD_TIME_ACT_ON);
- }
-}
-
-#if 0
-void ipw_led_activity_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- __ipw_led_activity_on(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-#endif /* 0 */
-
-static void ipw_led_activity_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- if (priv->config & CFG_NO_LED)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->status & STATUS_LED_ACT_ON) {
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_activity_off;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- IPW_DEBUG_LED("Activity LED Off\n");
-
- priv->status &= ~STATUS_LED_ACT_ON;
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_led_activity_off(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, led_act_off.work);
- mutex_lock(&priv->mutex);
- ipw_led_activity_off(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_led_band_on(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* Only nic type 1 supports mode LEDs */
- if (priv->config & CFG_NO_LED ||
- priv->nic_type != EEPROM_NIC_TYPE_1 || !priv->assoc_network)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- if (priv->assoc_network->mode == IEEE_A) {
- led |= priv->led_ofdm_on;
- led &= priv->led_association_off;
- IPW_DEBUG_LED("Mode LED On: 802.11a\n");
- } else if (priv->assoc_network->mode == IEEE_G) {
- led |= priv->led_ofdm_on;
- led |= priv->led_association_on;
- IPW_DEBUG_LED("Mode LED On: 802.11g\n");
- } else {
- led &= priv->led_ofdm_off;
- led |= priv->led_association_on;
- IPW_DEBUG_LED("Mode LED On: 802.11b\n");
- }
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_led_band_off(struct ipw_priv *priv)
-{
- unsigned long flags;
- u32 led;
-
- /* Only nic type 1 supports mode LEDs */
- if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1)
- return;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- led = ipw_read_reg32(priv, IPW_EVENT_REG);
- led &= priv->led_ofdm_off;
- led &= priv->led_association_off;
-
- led = ipw_register_toggle(led);
-
- IPW_DEBUG_LED("Reg: 0x%08X\n", led);
- ipw_write_reg32(priv, IPW_EVENT_REG, led);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_led_radio_on(struct ipw_priv *priv)
-{
- ipw_led_link_on(priv);
-}
-
-static void ipw_led_radio_off(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
-}
-
-static void ipw_led_link_up(struct ipw_priv *priv)
-{
- /* Set the Link Led on for all nic types */
- ipw_led_link_on(priv);
-}
-
-static void ipw_led_link_down(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
-
- if (priv->status & STATUS_RF_KILL_MASK)
- ipw_led_radio_off(priv);
-}
-
-static void ipw_led_init(struct ipw_priv *priv)
-{
- priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE];
-
- /* Set the default PINs for the link and activity leds */
- priv->led_activity_on = IPW_ACTIVITY_LED;
- priv->led_activity_off = ~(IPW_ACTIVITY_LED);
-
- priv->led_association_on = IPW_ASSOCIATED_LED;
- priv->led_association_off = ~(IPW_ASSOCIATED_LED);
-
- /* Set the default PINs for the OFDM leds */
- priv->led_ofdm_on = IPW_OFDM_LED;
- priv->led_ofdm_off = ~(IPW_OFDM_LED);
-
- switch (priv->nic_type) {
- case EEPROM_NIC_TYPE_1:
- /* In this NIC type, the LEDs are reversed.... */
- priv->led_activity_on = IPW_ASSOCIATED_LED;
- priv->led_activity_off = ~(IPW_ASSOCIATED_LED);
- priv->led_association_on = IPW_ACTIVITY_LED;
- priv->led_association_off = ~(IPW_ACTIVITY_LED);
-
- if (!(priv->config & CFG_NO_LED))
- ipw_led_band_on(priv);
-
- /* And we don't blink link LEDs for this nic, so
- * just return here */
- return;
-
- case EEPROM_NIC_TYPE_3:
- case EEPROM_NIC_TYPE_2:
- case EEPROM_NIC_TYPE_4:
- case EEPROM_NIC_TYPE_0:
- break;
-
- default:
- IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n",
- priv->nic_type);
- priv->nic_type = EEPROM_NIC_TYPE_0;
- break;
- }
-
- if (!(priv->config & CFG_NO_LED)) {
- if (priv->status & STATUS_ASSOCIATED)
- ipw_led_link_on(priv);
- else
- ipw_led_link_off(priv);
- }
-}
-
-static void ipw_led_shutdown(struct ipw_priv *priv)
-{
- ipw_led_activity_off(priv);
- ipw_led_link_off(priv);
- ipw_led_band_off(priv);
- cancel_delayed_work(&priv->led_link_on);
- cancel_delayed_work(&priv->led_link_off);
- cancel_delayed_work(&priv->led_act_off);
-}
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/)
- * used for controlling the debug level.
- *
- * See the level definitions in ipw for details.
- */
-static ssize_t debug_level_show(struct device_driver *d, char *buf)
-{
- return sprintf(buf, "0x%08X\n", ipw_debug_level);
-}
-
-static ssize_t debug_level_store(struct device_driver *d, const char *buf,
- size_t count)
-{
- unsigned long val;
-
- int result = kstrtoul(buf, 0, &val);
-
- if (result == -EINVAL)
- printk(KERN_INFO DRV_NAME
- ": %s is not in hex or decimal form.\n", buf);
- else if (result == -ERANGE)
- printk(KERN_INFO DRV_NAME
- ": %s has overflowed.\n", buf);
- else
- ipw_debug_level = val;
-
- return count;
-}
-static DRIVER_ATTR_RW(debug_level);
-
-static inline u32 ipw_get_event_log_len(struct ipw_priv *priv)
-{
- /* length = 1st dword in log */
- return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG));
-}
-
-static void ipw_capture_event_log(struct ipw_priv *priv,
- u32 log_len, struct ipw_event *log)
-{
- u32 base;
-
- if (log_len) {
- base = ipw_read32(priv, IPW_EVENT_LOG);
- ipw_read_indirect(priv, base + sizeof(base) + sizeof(u32),
- (u8 *) log, sizeof(*log) * log_len);
- }
-}
-
-static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
-{
- struct ipw_fw_error *error;
- u32 log_len = ipw_get_event_log_len(priv);
- u32 base = ipw_read32(priv, IPW_ERROR_LOG);
- u32 elem_len = ipw_read_reg32(priv, base);
-
- error = kmalloc(size_add(struct_size(error, elem, elem_len),
- array_size(sizeof(*error->log), log_len)),
- GFP_ATOMIC);
- if (!error) {
- IPW_ERROR("Memory allocation for firmware error log "
- "failed.\n");
- return NULL;
- }
- error->jiffies = jiffies;
- error->status = priv->status;
- error->config = priv->config;
- error->elem_len = elem_len;
- error->log_len = log_len;
- error->log = (struct ipw_event *)(error->elem + elem_len);
-
- ipw_capture_event_log(priv, log_len, error->log);
-
- if (elem_len)
- ipw_read_indirect(priv, base + sizeof(base), (u8 *) error->elem,
- sizeof(*error->elem) * elem_len);
-
- return error;
-}
-
-static ssize_t event_log_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 log_len = ipw_get_event_log_len(priv);
- u32 log_size;
- struct ipw_event *log;
- u32 len = 0, i;
-
- /* not using min() because of its strict type checking */
- log_size = PAGE_SIZE / sizeof(*log) > log_len ?
- sizeof(*log) * log_len : PAGE_SIZE;
- log = kzalloc(log_size, GFP_KERNEL);
- if (!log) {
- IPW_ERROR("Unable to allocate memory for log\n");
- return 0;
- }
- log_len = log_size / sizeof(*log);
- ipw_capture_event_log(priv, log_len, log);
-
- len += scnprintf(buf + len, PAGE_SIZE - len, "%08X", log_len);
- for (i = 0; i < log_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X",
- log[i].time, log[i].event, log[i].data);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- kfree(log);
- return len;
-}
-
-static DEVICE_ATTR_RO(event_log);
-
-static ssize_t error_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 len = 0, i;
- if (!priv->error)
- return 0;
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "%08lX%08X%08X%08X",
- priv->error->jiffies,
- priv->error->status,
- priv->error->config, priv->error->elem_len);
- for (i = 0; i < priv->error->elem_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X%08X%08X%08X%08X",
- priv->error->elem[i].time,
- priv->error->elem[i].desc,
- priv->error->elem[i].blink1,
- priv->error->elem[i].blink2,
- priv->error->elem[i].link1,
- priv->error->elem[i].link2,
- priv->error->elem[i].data);
-
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X", priv->error->log_len);
- for (i = 0; i < priv->error->log_len; i++)
- len += scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08X%08X%08X",
- priv->error->log[i].time,
- priv->error->log[i].event,
- priv->error->log[i].data);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- return len;
-}
-
-static ssize_t error_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- kfree(priv->error);
- priv->error = NULL;
- return count;
-}
-
-static DEVICE_ATTR_RW(error);
-
-static ssize_t cmd_log_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- u32 len = 0, i;
- if (!priv->cmdlog)
- return 0;
- for (i = (priv->cmdlog_pos + 1) % priv->cmdlog_len;
- (i != priv->cmdlog_pos) && (len < PAGE_SIZE);
- i = (i + 1) % priv->cmdlog_len) {
- len +=
- scnprintf(buf + len, PAGE_SIZE - len,
- "\n%08lX%08X%08X%08X\n", priv->cmdlog[i].jiffies,
- priv->cmdlog[i].retcode, priv->cmdlog[i].cmd.cmd,
- priv->cmdlog[i].cmd.len);
- len +=
- snprintk_buf(buf + len, PAGE_SIZE - len,
- (u8 *) priv->cmdlog[i].cmd.param,
- priv->cmdlog[i].cmd.len);
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- }
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- return len;
-}
-
-static DEVICE_ATTR_RO(cmd_log);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static void ipw_prom_free(struct ipw_priv *priv);
-static int ipw_prom_alloc(struct ipw_priv *priv);
-static ssize_t rtap_iface_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int rc = 0;
-
- if (count < 1)
- return -EINVAL;
-
- switch (buf[0]) {
- case '0':
- if (!rtap_iface)
- return count;
-
- if (netif_running(priv->prom_net_dev)) {
- IPW_WARNING("Interface is up. Cannot unregister.\n");
- return count;
- }
-
- ipw_prom_free(priv);
- rtap_iface = 0;
- break;
-
- case '1':
- if (rtap_iface)
- return count;
-
- rc = ipw_prom_alloc(priv);
- if (!rc)
- rtap_iface = 1;
- break;
-
- default:
- return -EINVAL;
- }
-
- if (rc) {
- IPW_ERROR("Failed to register promiscuous network "
- "device (error %d).\n", rc);
- }
-
- return count;
-}
-
-static ssize_t rtap_iface_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- if (rtap_iface)
- return sprintf(buf, "%s", priv->prom_net_dev->name);
- else {
- buf[0] = '-';
- buf[1] = '1';
- buf[2] = '\0';
- return 3;
- }
-}
-
-static DEVICE_ATTR_ADMIN_RW(rtap_iface);
-
-static ssize_t rtap_filter_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (!priv->prom_priv) {
- IPW_ERROR("Attempting to set filter without "
- "rtap_iface enabled.\n");
- return -EPERM;
- }
-
- priv->prom_priv->filter = simple_strtol(buf, NULL, 0);
-
- IPW_DEBUG_INFO("Setting rtap filter to " BIT_FMT16 "\n",
- BIT_ARG16(priv->prom_priv->filter));
-
- return count;
-}
-
-static ssize_t rtap_filter_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "0x%04X",
- priv->prom_priv ? priv->prom_priv->filter : 0);
-}
-
-static DEVICE_ATTR_ADMIN_RW(rtap_filter);
-#endif
-
-static ssize_t scan_age_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", priv->ieee->scan_age);
-}
-
-static ssize_t scan_age_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- struct net_device *dev = priv->net_dev;
-
- IPW_DEBUG_INFO("enter\n");
-
- unsigned long val;
- int result = kstrtoul(buf, 0, &val);
-
- if (result == -EINVAL || result == -ERANGE) {
- IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name);
- } else {
- priv->ieee->scan_age = val;
- IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return count;
-}
-
-static DEVICE_ATTR_RW(scan_age);
-
-static ssize_t led_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1);
-}
-
-static ssize_t led_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- IPW_DEBUG_INFO("enter\n");
-
- if (count == 0)
- return 0;
-
- if (*buf == 0) {
- IPW_DEBUG_LED("Disabling LED control.\n");
- priv->config |= CFG_NO_LED;
- ipw_led_shutdown(priv);
- } else {
- IPW_DEBUG_LED("Enabling LED control.\n");
- priv->config &= ~CFG_NO_LED;
- ipw_led_init(priv);
- }
-
- IPW_DEBUG_INFO("exit\n");
- return count;
-}
-
-static DEVICE_ATTR_RW(led);
-
-static ssize_t status_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->status);
-}
-
-static DEVICE_ATTR_RO(status);
-
-static ssize_t cfg_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- return sprintf(buf, "0x%08x\n", (int)p->config);
-}
-
-static DEVICE_ATTR_RO(cfg);
-
-static ssize_t nic_type_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "TYPE: %d\n", priv->nic_type);
-}
-
-static DEVICE_ATTR_RO(nic_type);
-
-static ssize_t ucode_version_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 len = sizeof(u32), tmp = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- if (ipw_get_ordinal(p, IPW_ORD_STAT_UCODE_VERSION, &tmp, &len))
- return 0;
-
- return sprintf(buf, "0x%08x\n", tmp);
-}
-
-static DEVICE_ATTR_RO(ucode_version);
-
-static ssize_t rtc_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- u32 len = sizeof(u32), tmp = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- if (ipw_get_ordinal(p, IPW_ORD_STAT_RTC, &tmp, &len))
- return 0;
-
- return sprintf(buf, "0x%08x\n", tmp);
-}
-
-static DEVICE_ATTR_RO(rtc);
-
-/*
- * Add a device attribute to view/control the delay between eeprom
- * operations.
- */
-static ssize_t eeprom_delay_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- int n = p->eeprom_delay;
- return sprintf(buf, "%i\n", n);
-}
-static ssize_t eeprom_delay_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *p = dev_get_drvdata(d);
- sscanf(buf, "%i", &p->eeprom_delay);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(eeprom_delay);
-
-static ssize_t command_event_reg_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- reg = ipw_read_reg32(p, IPW_INTERNAL_CMD_EVENT);
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t command_event_reg_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- u32 reg;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- sscanf(buf, "%x", ®);
- ipw_write_reg32(p, IPW_INTERNAL_CMD_EVENT, reg);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(command_event_reg);
-
-static ssize_t mem_gpio_reg_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- reg = ipw_read_reg32(p, 0x301100);
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t mem_gpio_reg_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- u32 reg;
- struct ipw_priv *p = dev_get_drvdata(d);
-
- sscanf(buf, "%x", ®);
- ipw_write_reg32(p, 0x301100, reg);
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(mem_gpio_reg);
-
-static ssize_t indirect_dword_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_INDIRECT_DWORD)
- reg = ipw_read_reg32(priv, priv->indirect_dword);
- else
- reg = 0;
-
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t indirect_dword_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->indirect_dword);
- priv->status |= STATUS_INDIRECT_DWORD;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(indirect_dword);
-
-static ssize_t indirect_byte_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u8 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_INDIRECT_BYTE)
- reg = ipw_read_reg8(priv, priv->indirect_byte);
- else
- reg = 0;
-
- return sprintf(buf, "0x%02x\n", reg);
-}
-static ssize_t indirect_byte_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->indirect_byte);
- priv->status |= STATUS_INDIRECT_BYTE;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(indirect_byte);
-
-static ssize_t direct_dword_show(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- u32 reg = 0;
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- if (priv->status & STATUS_DIRECT_DWORD)
- reg = ipw_read32(priv, priv->direct_dword);
- else
- reg = 0;
-
- return sprintf(buf, "0x%08x\n", reg);
-}
-static ssize_t direct_dword_store(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- sscanf(buf, "%x", &priv->direct_dword);
- priv->status |= STATUS_DIRECT_DWORD;
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR_RW(direct_dword);
-
-static int rf_kill_active(struct ipw_priv *priv)
-{
- if (0 == (ipw_read32(priv, 0x30) & 0x10000)) {
- priv->status |= STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- } else {
- priv->status &= ~STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, false);
- }
-
- return (priv->status & STATUS_RF_KILL_HW) ? 1 : 0;
-}
-
-static ssize_t rf_kill_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- /* 0 - RF kill not enabled
- 1 - SW based RF kill active (sysfs)
- 2 - HW based RF kill active
- 3 - Both HW and SW baed RF kill active */
- struct ipw_priv *priv = dev_get_drvdata(d);
- int val = ((priv->status & STATUS_RF_KILL_SW) ? 0x1 : 0x0) |
- (rf_kill_active(priv) ? 0x2 : 0x0);
- return sprintf(buf, "%i\n", val);
-}
-
-static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
-{
- if ((disable_radio ? 1 : 0) ==
- ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0))
- return 0;
-
- IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n",
- disable_radio ? "OFF" : "ON");
-
- if (disable_radio) {
- priv->status |= STATUS_RF_KILL_SW;
-
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- schedule_work(&priv->down);
- } else {
- priv->status &= ~STATUS_RF_KILL_SW;
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("Can not turn radio back on - "
- "disabled by HW switch\n");
- /* Make sure the RF_KILL check timer is running */
- cancel_delayed_work(&priv->rf_kill);
- schedule_delayed_work(&priv->rf_kill,
- round_jiffies_relative(2 * HZ));
- } else
- schedule_work(&priv->up);
- }
-
- return 1;
-}
-
-static ssize_t rf_kill_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
-
- ipw_radio_kill_sw(priv, buf[0] == '1');
-
- return count;
-}
-
-static DEVICE_ATTR_RW(rf_kill);
-
-static ssize_t speed_scan_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int pos = 0, len = 0;
- if (priv->config & CFG_SPEED_SCAN) {
- while (priv->speed_scan[pos] != 0)
- len += sprintf(&buf[len], "%d ",
- priv->speed_scan[pos++]);
- return len + sprintf(&buf[len], "\n");
- }
-
- return sprintf(buf, "0\n");
-}
-
-static ssize_t speed_scan_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- int channel, pos = 0;
- const char *p = buf;
-
- /* list of space separated channels to scan, optionally ending with 0 */
- while ((channel = simple_strtol(p, NULL, 0))) {
- if (pos == MAX_SPEED_SCAN - 1) {
- priv->speed_scan[pos] = 0;
- break;
- }
-
- if (libipw_is_valid_channel(priv->ieee, channel))
- priv->speed_scan[pos++] = channel;
- else
- IPW_WARNING("Skipping invalid channel request: %d\n",
- channel);
- p = strchr(p, ' ');
- if (!p)
- break;
- while (*p == ' ' || *p == '\t')
- p++;
- }
-
- if (pos == 0)
- priv->config &= ~CFG_SPEED_SCAN;
- else {
- priv->speed_scan_pos = 0;
- priv->config |= CFG_SPEED_SCAN;
- }
-
- return count;
-}
-
-static DEVICE_ATTR_RW(speed_scan);
-
-static ssize_t net_stats_show(struct device *d, struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "%c\n", (priv->config & CFG_NET_STATS) ? '1' : '0');
-}
-
-static ssize_t net_stats_store(struct device *d, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- if (buf[0] == '1')
- priv->config |= CFG_NET_STATS;
- else
- priv->config &= ~CFG_NET_STATS;
-
- return count;
-}
-
-static DEVICE_ATTR_RW(net_stats);
-
-static ssize_t channels_show(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct ipw_priv *priv = dev_get_drvdata(d);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int len = 0, i;
-
- len = sprintf(&buf[len],
- "Displaying %d channels in 2.4Ghz band "
- "(802.11bg):\n", geo->bg_channels);
-
- for (i = 0; i < geo->bg_channels; i++) {
- len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n",
- geo->bg[i].channel,
- geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT ?
- " (radar spectrum)" : "",
- ((geo->bg[i].flags & LIBIPW_CH_NO_IBSS) ||
- (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT))
- ? "" : ", IBSS",
- geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
- "passive only" : "active/passive",
- geo->bg[i].flags & LIBIPW_CH_B_ONLY ?
- "B" : "B/G");
- }
-
- len += sprintf(&buf[len],
- "Displaying %d channels in 5.2Ghz band "
- "(802.11a):\n", geo->a_channels);
- for (i = 0; i < geo->a_channels; i++) {
- len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n",
- geo->a[i].channel,
- geo->a[i].flags & LIBIPW_CH_RADAR_DETECT ?
- " (radar spectrum)" : "",
- ((geo->a[i].flags & LIBIPW_CH_NO_IBSS) ||
- (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT))
- ? "" : ", IBSS",
- geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY ?
- "passive only" : "active/passive");
- }
-
- return len;
-}
-
-static DEVICE_ATTR_ADMIN_RO(channels);
-
-static void notify_wx_assoc_event(struct ipw_priv *priv)
-{
- union iwreq_data wrqu;
- wrqu.ap_addr.sa_family = ARPHRD_ETHER;
- if (priv->status & STATUS_ASSOCIATED)
- memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN);
- else
- eth_zero_addr(wrqu.ap_addr.sa_data);
- wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL);
-}
-
-static void ipw_irq_tasklet(struct tasklet_struct *t)
-{
- struct ipw_priv *priv = from_tasklet(priv, t, irq_tasklet);
- u32 inta, inta_mask, handled = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->irq_lock, flags);
-
- inta = ipw_read32(priv, IPW_INTA_RW);
- inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- IPW_WARNING("TASKLET INTA == 0xFFFFFFFF\n");
- /* Only handle the cached INTA values */
- inta = 0;
- }
- inta &= (IPW_INTA_MASK_ALL & inta_mask);
-
- /* Add any cached INTA values that need to be handled */
- inta |= priv->isr_inta;
-
- spin_unlock_irqrestore(&priv->irq_lock, flags);
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* handle all the justifications for the interrupt */
- if (inta & IPW_INTA_BIT_RX_TRANSFER) {
- ipw_rx(priv);
- handled |= IPW_INTA_BIT_RX_TRANSFER;
- }
-
- if (inta & IPW_INTA_BIT_TX_CMD_QUEUE) {
- IPW_DEBUG_HC("Command completed.\n");
- ipw_queue_tx_reclaim(priv, &priv->txq_cmd, -1);
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
- handled |= IPW_INTA_BIT_TX_CMD_QUEUE;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_1) {
- IPW_DEBUG_TX("TX_QUEUE_1\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[0], 0);
- handled |= IPW_INTA_BIT_TX_QUEUE_1;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_2) {
- IPW_DEBUG_TX("TX_QUEUE_2\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[1], 1);
- handled |= IPW_INTA_BIT_TX_QUEUE_2;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_3) {
- IPW_DEBUG_TX("TX_QUEUE_3\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[2], 2);
- handled |= IPW_INTA_BIT_TX_QUEUE_3;
- }
-
- if (inta & IPW_INTA_BIT_TX_QUEUE_4) {
- IPW_DEBUG_TX("TX_QUEUE_4\n");
- ipw_queue_tx_reclaim(priv, &priv->txq[3], 3);
- handled |= IPW_INTA_BIT_TX_QUEUE_4;
- }
-
- if (inta & IPW_INTA_BIT_STATUS_CHANGE) {
- IPW_WARNING("STATUS_CHANGE\n");
- handled |= IPW_INTA_BIT_STATUS_CHANGE;
- }
-
- if (inta & IPW_INTA_BIT_BEACON_PERIOD_EXPIRED) {
- IPW_WARNING("TX_PERIOD_EXPIRED\n");
- handled |= IPW_INTA_BIT_BEACON_PERIOD_EXPIRED;
- }
-
- if (inta & IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE) {
- IPW_WARNING("HOST_CMD_DONE\n");
- handled |= IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FW_INITIALIZATION_DONE) {
- IPW_WARNING("FW_INITIALIZATION_DONE\n");
- handled |= IPW_INTA_BIT_FW_INITIALIZATION_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE) {
- IPW_WARNING("PHY_OFF_DONE\n");
- handled |= IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE;
- }
-
- if (inta & IPW_INTA_BIT_RF_KILL_DONE) {
- IPW_DEBUG_RF_KILL("RF_KILL_DONE\n");
- priv->status |= STATUS_RF_KILL_HW;
- wiphy_rfkill_set_hw_state(priv->ieee->wdev.wiphy, true);
- wake_up_interruptible(&priv->wait_command_queue);
- priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- schedule_work(&priv->link_down);
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- handled |= IPW_INTA_BIT_RF_KILL_DONE;
- }
-
- if (inta & IPW_INTA_BIT_FATAL_ERROR) {
- IPW_WARNING("Firmware error detected. Restarting.\n");
- if (priv->error) {
- IPW_DEBUG_FW("Sysfs 'error' log already exists.\n");
- if (ipw_debug_level & IPW_DL_FW_ERRORS) {
- struct ipw_fw_error *error =
- ipw_alloc_error_log(priv);
- ipw_dump_error_log(priv, error);
- kfree(error);
- }
- } else {
- priv->error = ipw_alloc_error_log(priv);
- if (priv->error)
- IPW_DEBUG_FW("Sysfs 'error' log captured.\n");
- else
- IPW_DEBUG_FW("Error allocating sysfs 'error' "
- "log.\n");
- if (ipw_debug_level & IPW_DL_FW_ERRORS)
- ipw_dump_error_log(priv, priv->error);
- }
-
- /* XXX: If hardware encryption is for WPA/WPA2,
- * we have to notify the supplicant. */
- if (priv->ieee->sec.encrypt) {
- priv->status &= ~STATUS_ASSOCIATED;
- notify_wx_assoc_event(priv);
- }
-
- /* Keep the restart process from trying to send host
- * commands by clearing the INIT status bit */
- priv->status &= ~STATUS_INIT;
-
- /* Cancel currently queued command. */
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
-
- schedule_work(&priv->adapter_restart);
- handled |= IPW_INTA_BIT_FATAL_ERROR;
- }
-
- if (inta & IPW_INTA_BIT_PARITY_ERROR) {
- IPW_ERROR("Parity error\n");
- handled |= IPW_INTA_BIT_PARITY_ERROR;
- }
-
- if (handled != inta) {
- IPW_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
- }
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* enable all interrupts */
- ipw_enable_interrupts(priv);
-}
-
-#define IPW_CMD(x) case IPW_CMD_ ## x : return #x
-static char *get_cmd_string(u8 cmd)
-{
- switch (cmd) {
- IPW_CMD(HOST_COMPLETE);
- IPW_CMD(POWER_DOWN);
- IPW_CMD(SYSTEM_CONFIG);
- IPW_CMD(MULTICAST_ADDRESS);
- IPW_CMD(SSID);
- IPW_CMD(ADAPTER_ADDRESS);
- IPW_CMD(PORT_TYPE);
- IPW_CMD(RTS_THRESHOLD);
- IPW_CMD(FRAG_THRESHOLD);
- IPW_CMD(POWER_MODE);
- IPW_CMD(WEP_KEY);
- IPW_CMD(TGI_TX_KEY);
- IPW_CMD(SCAN_REQUEST);
- IPW_CMD(SCAN_REQUEST_EXT);
- IPW_CMD(ASSOCIATE);
- IPW_CMD(SUPPORTED_RATES);
- IPW_CMD(SCAN_ABORT);
- IPW_CMD(TX_FLUSH);
- IPW_CMD(QOS_PARAMETERS);
- IPW_CMD(DINO_CONFIG);
- IPW_CMD(RSN_CAPABILITIES);
- IPW_CMD(RX_KEY);
- IPW_CMD(CARD_DISABLE);
- IPW_CMD(SEED_NUMBER);
- IPW_CMD(TX_POWER);
- IPW_CMD(COUNTRY_INFO);
- IPW_CMD(AIRONET_INFO);
- IPW_CMD(AP_TX_POWER);
- IPW_CMD(CCKM_INFO);
- IPW_CMD(CCX_VER_INFO);
- IPW_CMD(SET_CALIBRATION);
- IPW_CMD(SENSITIVITY_CALIB);
- IPW_CMD(RETRY_LIMIT);
- IPW_CMD(IPW_PRE_POWER_DOWN);
- IPW_CMD(VAP_BEACON_TEMPLATE);
- IPW_CMD(VAP_DTIM_PERIOD);
- IPW_CMD(EXT_SUPPORTED_RATES);
- IPW_CMD(VAP_LOCAL_TX_PWR_CONSTRAINT);
- IPW_CMD(VAP_QUIET_INTERVALS);
- IPW_CMD(VAP_CHANNEL_SWITCH);
- IPW_CMD(VAP_MANDATORY_CHANNELS);
- IPW_CMD(VAP_CELL_PWR_LIMIT);
- IPW_CMD(VAP_CF_PARAM_SET);
- IPW_CMD(VAP_SET_BEACONING_STATE);
- IPW_CMD(MEASUREMENT);
- IPW_CMD(POWER_CAPABILITY);
- IPW_CMD(SUPPORTED_CHANNELS);
- IPW_CMD(TPC_REPORT);
- IPW_CMD(WME_INFO);
- IPW_CMD(PRODUCTION_COMMAND);
- default:
- return "UNKNOWN";
- }
-}
-
-#define HOST_COMPLETE_TIMEOUT HZ
-
-static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd)
-{
- int rc = 0;
- unsigned long flags;
- unsigned long now, end;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->status & STATUS_HCMD_ACTIVE) {
- IPW_ERROR("Failed to send %s: Already sending a command.\n",
- get_cmd_string(cmd->cmd));
- spin_unlock_irqrestore(&priv->lock, flags);
- return -EAGAIN;
- }
-
- priv->status |= STATUS_HCMD_ACTIVE;
-
- if (priv->cmdlog) {
- priv->cmdlog[priv->cmdlog_pos].jiffies = jiffies;
- priv->cmdlog[priv->cmdlog_pos].cmd.cmd = cmd->cmd;
- priv->cmdlog[priv->cmdlog_pos].cmd.len = cmd->len;
- memcpy(priv->cmdlog[priv->cmdlog_pos].cmd.param, cmd->param,
- cmd->len);
- priv->cmdlog[priv->cmdlog_pos].retcode = -1;
- }
-
- IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n",
- get_cmd_string(cmd->cmd), cmd->cmd, cmd->len,
- priv->status);
-
-#ifndef DEBUG_CMD_WEP_KEY
- if (cmd->cmd == IPW_CMD_WEP_KEY)
- IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n");
- else
-#endif
- printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len);
-
- rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0);
- if (rc) {
- priv->status &= ~STATUS_HCMD_ACTIVE;
- IPW_ERROR("Failed to send %s: Reason %d\n",
- get_cmd_string(cmd->cmd), rc);
- spin_unlock_irqrestore(&priv->lock, flags);
- goto exit;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- now = jiffies;
- end = now + HOST_COMPLETE_TIMEOUT;
-again:
- rc = wait_event_interruptible_timeout(priv->wait_command_queue,
- !(priv->
- status & STATUS_HCMD_ACTIVE),
- end - now);
- if (rc < 0) {
- now = jiffies;
- if (time_before(now, end))
- goto again;
- rc = 0;
- }
-
- if (rc == 0) {
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->status & STATUS_HCMD_ACTIVE) {
- IPW_ERROR("Failed to send %s: Command timed out.\n",
- get_cmd_string(cmd->cmd));
- priv->status &= ~STATUS_HCMD_ACTIVE;
- spin_unlock_irqrestore(&priv->lock, flags);
- rc = -EIO;
- goto exit;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- } else
- rc = 0;
-
- if (priv->status & STATUS_RF_KILL_HW) {
- IPW_ERROR("Failed to send %s: Aborted due to RF kill switch.\n",
- get_cmd_string(cmd->cmd));
- rc = -EIO;
- goto exit;
- }
-
- exit:
- if (priv->cmdlog) {
- priv->cmdlog[priv->cmdlog_pos++].retcode = rc;
- priv->cmdlog_pos %= priv->cmdlog_len;
- }
- return rc;
-}
-
-static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command)
-{
- struct host_cmd cmd = {
- .cmd = command,
- };
-
- return __ipw_send_cmd(priv, &cmd);
-}
-
-static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len,
- const void *data)
-{
- struct host_cmd cmd = {
- .cmd = command,
- .len = len,
- .param = data,
- };
-
- return __ipw_send_cmd(priv, &cmd);
-}
-
-static int ipw_send_host_complete(struct ipw_priv *priv)
-{
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE);
-}
-
-static int ipw_send_system_config(struct ipw_priv *priv)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG,
- sizeof(priv->sys_config),
- &priv->sys_config);
-}
-
-static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len)
-{
- if (!priv || !ssid) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE),
- ssid);
-}
-
-static int ipw_send_adapter_address(struct ipw_priv *priv, const u8 * mac)
-{
- if (!priv || !mac) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- IPW_DEBUG_INFO("%s: Setting MAC to %pM\n",
- priv->net_dev->name, mac);
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
-}
-
-static void ipw_adapter_restart(void *adapter)
-{
- struct ipw_priv *priv = adapter;
-
- if (priv->status & STATUS_RF_KILL_MASK)
- return;
-
- ipw_down(priv);
-
- if (priv->assoc_network &&
- (priv->assoc_network->capability & WLAN_CAPABILITY_IBSS))
- ipw_remove_current_network(priv);
-
- if (ipw_up(priv)) {
- IPW_ERROR("Failed to up device\n");
- return;
- }
-}
-
-static void ipw_bg_adapter_restart(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, adapter_restart);
- mutex_lock(&priv->mutex);
- ipw_adapter_restart(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_abort_scan(struct ipw_priv *priv);
-
-#define IPW_SCAN_CHECK_WATCHDOG (5 * HZ)
-
-static void ipw_scan_check(void *data)
-{
- struct ipw_priv *priv = data;
-
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_SCAN("Scan completion watchdog resetting "
- "adapter after (%dms).\n",
- jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
- schedule_work(&priv->adapter_restart);
- } else if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan completion watchdog aborting scan "
- "after (%dms).\n",
- jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG));
- ipw_abort_scan(priv);
- schedule_delayed_work(&priv->scan_check, HZ);
- }
-}
-
-static void ipw_bg_scan_check(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, scan_check.work);
- mutex_lock(&priv->mutex);
- ipw_scan_check(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_send_scan_request_ext(struct ipw_priv *priv,
- struct ipw_scan_request_ext *request)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT,
- sizeof(*request), request);
-}
-
-static int ipw_send_scan_abort(struct ipw_priv *priv)
-{
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT);
-}
-
-static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
-{
- struct ipw_sensitivity_calib calib = {
- .beacon_rssi_raw = cpu_to_le16(sens),
- };
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib),
- &calib);
-}
-
-static int ipw_send_associate(struct ipw_priv *priv,
- struct ipw_associate *associate)
-{
- if (!priv || !associate) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(*associate),
- associate);
-}
-
-static int ipw_send_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *rates)
-{
- if (!priv || !rates) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates),
- rates);
-}
-
-static int ipw_set_random_seed(struct ipw_priv *priv)
-{
- u32 val;
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- get_random_bytes(&val, sizeof(val));
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val);
-}
-
-static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
-{
- __le32 v = cpu_to_le32(phy_off);
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(v), &v);
-}
-
-static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power)
-{
- if (!priv || !power) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power);
-}
-
-static int ipw_set_tx_power(struct ipw_priv *priv)
-{
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct ipw_tx_power tx_power;
- s8 max_power;
- int i;
-
- memset(&tx_power, 0, sizeof(tx_power));
-
- /* configure device for 'G' band */
- tx_power.ieee_mode = IPW_G_MODE;
- tx_power.num_channels = geo->bg_channels;
- for (i = 0; i < geo->bg_channels; i++) {
- max_power = geo->bg[i].max_power;
- tx_power.channels_tx_power[i].channel_number =
- geo->bg[i].channel;
- tx_power.channels_tx_power[i].tx_power = max_power ?
- min(max_power, priv->tx_power) : priv->tx_power;
- }
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
-
- /* configure device to also handle 'B' band */
- tx_power.ieee_mode = IPW_B_MODE;
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
-
- /* configure device to also handle 'A' band */
- if (priv->ieee->abg_true) {
- tx_power.ieee_mode = IPW_A_MODE;
- tx_power.num_channels = geo->a_channels;
- for (i = 0; i < tx_power.num_channels; i++) {
- max_power = geo->a[i].max_power;
- tx_power.channels_tx_power[i].channel_number =
- geo->a[i].channel;
- tx_power.channels_tx_power[i].tx_power = max_power ?
- min(max_power, priv->tx_power) : priv->tx_power;
- }
- if (ipw_send_tx_power(priv, &tx_power))
- return -EIO;
- }
- return 0;
-}
-
-static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
-{
- struct ipw_rts_threshold rts_threshold = {
- .rts_threshold = cpu_to_le16(rts),
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD,
- sizeof(rts_threshold), &rts_threshold);
-}
-
-static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
-{
- struct ipw_frag_threshold frag_threshold = {
- .frag_threshold = cpu_to_le16(frag),
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD,
- sizeof(frag_threshold), &frag_threshold);
-}
-
-static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
-{
- __le32 param;
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- /* If on battery, set to 3, if AC set to CAM, else user
- * level */
- switch (mode) {
- case IPW_POWER_BATTERY:
- param = cpu_to_le32(IPW_POWER_INDEX_3);
- break;
- case IPW_POWER_AC:
- param = cpu_to_le32(IPW_POWER_MODE_CAM);
- break;
- default:
- param = cpu_to_le32(mode);
- break;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
- ¶m);
-}
-
-static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit)
-{
- struct ipw_retry_limit retry_limit = {
- .short_retry_limit = slimit,
- .long_retry_limit = llimit
- };
-
- if (!priv) {
- IPW_ERROR("Invalid args\n");
- return -1;
- }
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit),
- &retry_limit);
-}
-
-/*
- * The IPW device contains a Microwire compatible EEPROM that stores
- * various data like the MAC address. Usually the firmware has exclusive
- * access to the eeprom, but during device initialization (before the
- * device driver has sent the HostComplete command to the firmware) the
- * device driver has read access to the EEPROM by way of indirect addressing
- * through a couple of memory mapped registers.
- *
- * The following is a simplified implementation for pulling data out of the
- * eeprom, along with some helper functions to find information in
- * the per device private data's copy of the eeprom.
- *
- * NOTE: To better understand how these functions work (i.e what is a chip
- * select and why do have to keep driving the eeprom clock?), read
- * just about any data sheet for a Microwire compatible EEPROM.
- */
-
-/* write a 32 bit value into the indirect accessor register */
-static inline void eeprom_write_reg(struct ipw_priv *p, u32 data)
-{
- ipw_write_reg32(p, FW_MEM_REG_EEPROM_ACCESS, data);
-
- /* the eeprom requires some time to complete the operation */
- udelay(p->eeprom_delay);
-}
-
-/* perform a chip select operation */
-static void eeprom_cs(struct ipw_priv *priv)
-{
- eeprom_write_reg(priv, 0);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
-}
-
-/* perform a chip select operation */
-static void eeprom_disable_cs(struct ipw_priv *priv)
-{
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- eeprom_write_reg(priv, 0);
- eeprom_write_reg(priv, EEPROM_BIT_SK);
-}
-
-/* push a single bit down to the eeprom */
-static inline void eeprom_write_bit(struct ipw_priv *p, u8 bit)
-{
- int d = (bit ? EEPROM_BIT_DI : 0);
- eeprom_write_reg(p, EEPROM_BIT_CS | d);
- eeprom_write_reg(p, EEPROM_BIT_CS | d | EEPROM_BIT_SK);
-}
-
-/* push an opcode followed by an address down to the eeprom */
-static void eeprom_op(struct ipw_priv *priv, u8 op, u8 addr)
-{
- int i;
-
- eeprom_cs(priv);
- eeprom_write_bit(priv, 1);
- eeprom_write_bit(priv, op & 2);
- eeprom_write_bit(priv, op & 1);
- for (i = 7; i >= 0; i--) {
- eeprom_write_bit(priv, addr & (1 << i));
- }
-}
-
-/* pull 16 bits off the eeprom, one bit at a time */
-static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr)
-{
- int i;
- u16 r = 0;
-
- /* Send READ Opcode */
- eeprom_op(priv, EEPROM_CMD_READ, addr);
-
- /* Send dummy bit */
- eeprom_write_reg(priv, EEPROM_BIT_CS);
-
- /* Read the byte off the eeprom one bit at a time */
- for (i = 0; i < 16; i++) {
- u32 data = 0;
- eeprom_write_reg(priv, EEPROM_BIT_CS | EEPROM_BIT_SK);
- eeprom_write_reg(priv, EEPROM_BIT_CS);
- data = ipw_read_reg32(priv, FW_MEM_REG_EEPROM_ACCESS);
- r = (r << 1) | ((data & EEPROM_BIT_DO) ? 1 : 0);
- }
-
- /* Send another dummy bit */
- eeprom_write_reg(priv, 0);
- eeprom_disable_cs(priv);
-
- return r;
-}
-
-/* helper function for pulling the mac address out of the private */
-/* data's copy of the eeprom data */
-static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac)
-{
- memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], ETH_ALEN);
-}
-
-static void ipw_read_eeprom(struct ipw_priv *priv)
-{
- int i;
- __le16 *eeprom = (__le16 *) priv->eeprom;
-
- IPW_DEBUG_TRACE(">>\n");
-
- /* read entire contents of eeprom into private buffer */
- for (i = 0; i < 128; i++)
- eeprom[i] = cpu_to_le16(eeprom_read_u16(priv, (u8) i));
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-/*
- * Either the device driver (i.e. the host) or the firmware can
- * load eeprom data into the designated region in SRAM. If neither
- * happens then the FW will shutdown with a fatal error.
- *
- * In order to signal the FW to load the EEPROM, the EEPROM_LOAD_DISABLE
- * bit needs region of shared SRAM needs to be non-zero.
- */
-static void ipw_eeprom_init_sram(struct ipw_priv *priv)
-{
- int i;
-
- IPW_DEBUG_TRACE(">>\n");
-
- /*
- If the data looks correct, then copy it to our private
- copy. Otherwise let the firmware know to perform the operation
- on its own.
- */
- if (priv->eeprom[EEPROM_VERSION] != 0) {
- IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n");
-
- /* write the eeprom data to sram */
- for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
- ipw_write8(priv, IPW_EEPROM_DATA + i, priv->eeprom[i]);
-
- /* Do not load eeprom data on fatal error or suspend */
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
- } else {
- IPW_DEBUG_INFO("Enabling FW initialization of SRAM\n");
-
- /* Load eeprom data on fatal error or suspend */
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 1);
- }
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-static void ipw_zero_memory(struct ipw_priv *priv, u32 start, u32 count)
-{
- count >>= 2;
- if (!count)
- return;
- _ipw_write32(priv, IPW_AUTOINC_ADDR, start);
- while (count--)
- _ipw_write32(priv, IPW_AUTOINC_DATA, 0);
-}
-
-static inline void ipw_fw_dma_reset_command_blocks(struct ipw_priv *priv)
-{
- ipw_zero_memory(priv, IPW_SHARED_SRAM_DMA_CONTROL,
- CB_NUMBER_OF_ELEMENTS_SMALL *
- sizeof(struct command_block));
-}
-
-static int ipw_fw_dma_enable(struct ipw_priv *priv)
-{ /* start dma engine but no transfers yet */
-
- IPW_DEBUG_FW(">> :\n");
-
- /* Start the dma */
- ipw_fw_dma_reset_command_blocks(priv);
-
- /* Write CB base address */
- ipw_write_reg32(priv, IPW_DMA_I_CB_BASE, IPW_SHARED_SRAM_DMA_CONTROL);
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-}
-
-static void ipw_fw_dma_abort(struct ipw_priv *priv)
-{
- u32 control = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- /* set the Stop and Abort bit */
- control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
- ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
- priv->sram_desc.last_cb_index = 0;
-
- IPW_DEBUG_FW("<<\n");
-}
-
-static int ipw_fw_dma_write_command_block(struct ipw_priv *priv, int index,
- struct command_block *cb)
-{
- u32 address =
- IPW_SHARED_SRAM_DMA_CONTROL +
- (sizeof(struct command_block) * index);
- IPW_DEBUG_FW(">> :\n");
-
- ipw_write_indirect(priv, address, (u8 *) cb,
- (int)sizeof(struct command_block));
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-
-}
-
-static int ipw_fw_dma_kick(struct ipw_priv *priv)
-{
- u32 control = 0;
- u32 index = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- for (index = 0; index < priv->sram_desc.last_cb_index; index++)
- ipw_fw_dma_write_command_block(priv, index,
- &priv->sram_desc.cb_list[index]);
-
- /* Enable the DMA in the CSR register */
- ipw_clear_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED |
- IPW_RESET_REG_STOP_MASTER);
-
- /* Set the Start bit. */
- control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_START;
- ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
-
- IPW_DEBUG_FW("<< :\n");
- return 0;
-}
-
-static void ipw_fw_dma_dump_command_block(struct ipw_priv *priv)
-{
- u32 address;
- u32 register_value = 0;
- u32 cb_fields_address = 0;
-
- IPW_DEBUG_FW(">> :\n");
- address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
- IPW_DEBUG_FW_INFO("Current CB is 0x%x\n", address);
-
- /* Read the DMA Controlor register */
- register_value = ipw_read_reg32(priv, IPW_DMA_I_DMA_CONTROL);
- IPW_DEBUG_FW_INFO("IPW_DMA_I_DMA_CONTROL is 0x%x\n", register_value);
-
- /* Print the CB values */
- cb_fields_address = address;
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Control Field is 0x%x\n", register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Source Field is 0x%x\n", register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Destination Field is 0x%x\n",
- register_value);
-
- cb_fields_address += sizeof(u32);
- register_value = ipw_read_reg32(priv, cb_fields_address);
- IPW_DEBUG_FW_INFO("Current CB Status Field is 0x%x\n", register_value);
-
- IPW_DEBUG_FW(">> :\n");
-}
-
-static int ipw_fw_dma_command_block_index(struct ipw_priv *priv)
-{
- u32 current_cb_address = 0;
- u32 current_cb_index = 0;
-
- IPW_DEBUG_FW("<< :\n");
- current_cb_address = ipw_read_reg32(priv, IPW_DMA_I_CURRENT_CB);
-
- current_cb_index = (current_cb_address - IPW_SHARED_SRAM_DMA_CONTROL) /
- sizeof(struct command_block);
-
- IPW_DEBUG_FW_INFO("Current CB index 0x%x address = 0x%X\n",
- current_cb_index, current_cb_address);
-
- IPW_DEBUG_FW(">> :\n");
- return current_cb_index;
-
-}
-
-static int ipw_fw_dma_add_command_block(struct ipw_priv *priv,
- u32 src_address,
- u32 dest_address,
- u32 length,
- int interrupt_enabled, int is_last)
-{
-
- u32 control = CB_VALID | CB_SRC_LE | CB_DEST_LE | CB_SRC_AUTOINC |
- CB_SRC_IO_GATED | CB_DEST_AUTOINC | CB_SRC_SIZE_LONG |
- CB_DEST_SIZE_LONG;
- struct command_block *cb;
- u32 last_cb_element = 0;
-
- IPW_DEBUG_FW_INFO("src_address=0x%x dest_address=0x%x length=0x%x\n",
- src_address, dest_address, length);
-
- if (priv->sram_desc.last_cb_index >= CB_NUMBER_OF_ELEMENTS_SMALL)
- return -1;
-
- last_cb_element = priv->sram_desc.last_cb_index;
- cb = &priv->sram_desc.cb_list[last_cb_element];
- priv->sram_desc.last_cb_index++;
-
- /* Calculate the new CB control word */
- if (interrupt_enabled)
- control |= CB_INT_ENABLED;
-
- if (is_last)
- control |= CB_LAST_VALID;
-
- control |= length;
-
- /* Calculate the CB Element's checksum value */
- cb->status = control ^ src_address ^ dest_address;
-
- /* Copy the Source and Destination addresses */
- cb->dest_addr = dest_address;
- cb->source_addr = src_address;
-
- /* Copy the Control Word last */
- cb->control = control;
-
- return 0;
-}
-
-static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, dma_addr_t *src_address,
- int nr, u32 dest_address, u32 len)
-{
- int ret, i;
- u32 size;
-
- IPW_DEBUG_FW(">>\n");
- IPW_DEBUG_FW_INFO("nr=%d dest_address=0x%x len=0x%x\n",
- nr, dest_address, len);
-
- for (i = 0; i < nr; i++) {
- size = min_t(u32, len - i * CB_MAX_LENGTH, CB_MAX_LENGTH);
- ret = ipw_fw_dma_add_command_block(priv, src_address[i],
- dest_address +
- i * CB_MAX_LENGTH, size,
- 0, 0);
- if (ret) {
- IPW_DEBUG_FW_INFO(": Failed\n");
- return -1;
- } else
- IPW_DEBUG_FW_INFO(": Added new cb\n");
- }
-
- IPW_DEBUG_FW("<<\n");
- return 0;
-}
-
-static int ipw_fw_dma_wait(struct ipw_priv *priv)
-{
- u32 current_index = 0, previous_index;
- u32 watchdog = 0;
-
- IPW_DEBUG_FW(">> :\n");
-
- current_index = ipw_fw_dma_command_block_index(priv);
- IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n",
- (int)priv->sram_desc.last_cb_index);
-
- while (current_index < priv->sram_desc.last_cb_index) {
- udelay(50);
- previous_index = current_index;
- current_index = ipw_fw_dma_command_block_index(priv);
-
- if (previous_index < current_index) {
- watchdog = 0;
- continue;
- }
- if (++watchdog > 400) {
- IPW_DEBUG_FW_INFO("Timeout\n");
- ipw_fw_dma_dump_command_block(priv);
- ipw_fw_dma_abort(priv);
- return -1;
- }
- }
-
- ipw_fw_dma_abort(priv);
-
- /*Disable the DMA in the CSR register */
- ipw_set_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED | IPW_RESET_REG_STOP_MASTER);
-
- IPW_DEBUG_FW("<< dmaWaitSync\n");
- return 0;
-}
-
-static void ipw_remove_current_network(struct ipw_priv *priv)
-{
- struct list_head *element, *safe;
- struct libipw_network *network = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_safe(element, safe, &priv->ieee->network_list) {
- network = list_entry(element, struct libipw_network, list);
- if (ether_addr_equal(network->bssid, priv->bssid)) {
- list_del(element);
- list_add_tail(&network->list,
- &priv->ieee->network_free_list);
- }
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-}
-
-/* timeout in msec, attempted in 10-msec quanta */
-static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask,
- int timeout)
-{
- int i = 0;
-
- do {
- if ((ipw_read32(priv, addr) & mask) == mask)
- return i;
- mdelay(10);
- i += 10;
- } while (i < timeout);
-
- return -ETIME;
-}
-
-/* These functions load the firmware and micro code for the operation of
- * the ipw hardware. It assumes the buffer has all the bits for the
- * image and the caller is handling the memory allocation and clean up.
- */
-
-static int ipw_stop_master(struct ipw_priv *priv)
-{
- int rc;
-
- IPW_DEBUG_TRACE(">>\n");
- /* stop master. typical delay - 0 */
- ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
-
- /* timeout is in msec, polled in 10-msec quanta */
- rc = ipw_poll_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED, 100);
- if (rc < 0) {
- IPW_ERROR("wait for stop master failed after 100ms\n");
- return -1;
- }
-
- IPW_DEBUG_INFO("stop master %dms\n", rc);
-
- return rc;
-}
-
-static void ipw_arc_release(struct ipw_priv *priv)
-{
- IPW_DEBUG_TRACE(">>\n");
- mdelay(5);
-
- ipw_clear_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
-
- /* no one knows timing, for safety add some delay */
- mdelay(5);
-}
-
-struct fw_chunk {
- __le32 address;
- __le32 length;
-};
-
-static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
-{
- int rc = 0, i, addr;
- u8 cr = 0;
- __le16 *image;
-
- image = (__le16 *) data;
-
- IPW_DEBUG_TRACE(">>\n");
-
- rc = ipw_stop_master(priv);
-
- if (rc < 0)
- return rc;
-
- for (addr = IPW_SHARED_LOWER_BOUND;
- addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
- ipw_write32(priv, addr, 0);
- }
-
- /* no ucode (yet) */
- memset(&priv->dino_alive, 0, sizeof(priv->dino_alive));
- /* destroy DMA queues */
- /* reset sequence */
-
- ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_ON);
- ipw_arc_release(priv);
- ipw_write_reg32(priv, IPW_MEM_HALT_AND_RESET, IPW_BIT_HALT_RESET_OFF);
- mdelay(1);
-
- /* reset PHY */
- ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, IPW_BASEBAND_POWER_DOWN);
- mdelay(1);
-
- ipw_write_reg32(priv, IPW_INTERNAL_CMD_EVENT, 0);
- mdelay(1);
-
- /* enable ucode store */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0);
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS);
- mdelay(1);
-
- /* write ucode */
- /*
- * @bug
- * Do NOT set indirect address register once and then
- * store data to indirect data register in the loop.
- * It seems very reasonable, but in this case DINO do not
- * accept ucode. It is essential to set address each time.
- */
- /* load new ipw uCode */
- for (i = 0; i < len / 2; i++)
- ipw_write_reg16(priv, IPW_BASEBAND_CONTROL_STORE,
- le16_to_cpu(image[i]));
-
- /* enable DINO */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_SYSTEM);
-
- /* this is where the igx / win driver deveates from the VAP driver. */
-
- /* wait for alive response */
- for (i = 0; i < 100; i++) {
- /* poll for incoming data */
- cr = ipw_read_reg8(priv, IPW_BASEBAND_CONTROL_STATUS);
- if (cr & DINO_RXFIFO_DATA)
- break;
- mdelay(1);
- }
-
- if (cr & DINO_RXFIFO_DATA) {
- /* alive_command_responce size is NOT multiple of 4 */
- __le32 response_buffer[(sizeof(priv->dino_alive) + 3) / 4];
-
- for (i = 0; i < ARRAY_SIZE(response_buffer); i++)
- response_buffer[i] =
- cpu_to_le32(ipw_read_reg32(priv,
- IPW_BASEBAND_RX_FIFO_READ));
- memcpy(&priv->dino_alive, response_buffer,
- sizeof(priv->dino_alive));
- if (priv->dino_alive.alive_command == 1
- && priv->dino_alive.ucode_valid == 1) {
- rc = 0;
- IPW_DEBUG_INFO
- ("Microcode OK, rev. %d (0x%x) dev. %d (0x%x) "
- "of %02d/%02d/%02d %02d:%02d\n",
- priv->dino_alive.software_revision,
- priv->dino_alive.software_revision,
- priv->dino_alive.device_identifier,
- priv->dino_alive.device_identifier,
- priv->dino_alive.time_stamp[0],
- priv->dino_alive.time_stamp[1],
- priv->dino_alive.time_stamp[2],
- priv->dino_alive.time_stamp[3],
- priv->dino_alive.time_stamp[4]);
- } else {
- IPW_DEBUG_INFO("Microcode is not alive\n");
- rc = -EINVAL;
- }
- } else {
- IPW_DEBUG_INFO("No alive response from DINO\n");
- rc = -ETIME;
- }
-
- /* disable DINO, otherwise for some reason
- firmware have problem getting alive resp. */
- ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
-
- return rc;
-}
-
-static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len)
-{
- int ret = -1;
- int offset = 0;
- struct fw_chunk *chunk;
- int total_nr = 0;
- int i;
- struct dma_pool *pool;
- void **virts;
- dma_addr_t *phys;
-
- IPW_DEBUG_TRACE("<< :\n");
-
- virts = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(void *),
- GFP_KERNEL);
- if (!virts)
- return -ENOMEM;
-
- phys = kmalloc_array(CB_NUMBER_OF_ELEMENTS_SMALL, sizeof(dma_addr_t),
- GFP_KERNEL);
- if (!phys) {
- kfree(virts);
- return -ENOMEM;
- }
- pool = dma_pool_create("ipw2200", &priv->pci_dev->dev, CB_MAX_LENGTH, 0,
- 0);
- if (!pool) {
- IPW_ERROR("dma_pool_create failed\n");
- kfree(phys);
- kfree(virts);
- return -ENOMEM;
- }
-
- /* Start the Dma */
- ret = ipw_fw_dma_enable(priv);
-
- /* the DMA is already ready this would be a bug. */
- BUG_ON(priv->sram_desc.last_cb_index > 0);
-
- do {
- u32 chunk_len;
- u8 *start;
- int size;
- int nr = 0;
-
- chunk = (struct fw_chunk *)(data + offset);
- offset += sizeof(struct fw_chunk);
- chunk_len = le32_to_cpu(chunk->length);
- start = data + offset;
-
- nr = (chunk_len + CB_MAX_LENGTH - 1) / CB_MAX_LENGTH;
- for (i = 0; i < nr; i++) {
- virts[total_nr] = dma_pool_alloc(pool, GFP_KERNEL,
- &phys[total_nr]);
- if (!virts[total_nr]) {
- ret = -ENOMEM;
- goto out;
- }
- size = min_t(u32, chunk_len - i * CB_MAX_LENGTH,
- CB_MAX_LENGTH);
- memcpy(virts[total_nr], start, size);
- start += size;
- total_nr++;
- /* We don't support fw chunk larger than 64*8K */
- BUG_ON(total_nr > CB_NUMBER_OF_ELEMENTS_SMALL);
- }
-
- /* build DMA packet and queue up for sending */
- /* dma to chunk->address, the chunk->length bytes from data +
- * offeset*/
- /* Dma loading */
- ret = ipw_fw_dma_add_buffer(priv, &phys[total_nr - nr],
- nr, le32_to_cpu(chunk->address),
- chunk_len);
- if (ret) {
- IPW_DEBUG_INFO("dmaAddBuffer Failed\n");
- goto out;
- }
-
- offset += chunk_len;
- } while (offset < len);
-
- /* Run the DMA and wait for the answer */
- ret = ipw_fw_dma_kick(priv);
- if (ret) {
- IPW_ERROR("dmaKick Failed\n");
- goto out;
- }
-
- ret = ipw_fw_dma_wait(priv);
- if (ret) {
- IPW_ERROR("dmaWaitSync Failed\n");
- goto out;
- }
- out:
- for (i = 0; i < total_nr; i++)
- dma_pool_free(pool, virts[i], phys[i]);
-
- dma_pool_destroy(pool);
- kfree(phys);
- kfree(virts);
-
- return ret;
-}
-
-/* stop nic */
-static int ipw_stop_nic(struct ipw_priv *priv)
-{
- int rc = 0;
-
- /* stop */
- ipw_write32(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER);
-
- rc = ipw_poll_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED, 500);
- if (rc < 0) {
- IPW_ERROR("wait for reg master disabled failed after 500ms\n");
- return rc;
- }
-
- ipw_set_bit(priv, IPW_RESET_REG, CBD_RESET_REG_PRINCETON_RESET);
-
- return rc;
-}
-
-static void ipw_start_nic(struct ipw_priv *priv)
-{
- IPW_DEBUG_TRACE(">>\n");
-
- /* prvHwStartNic release ARC */
- ipw_clear_bit(priv, IPW_RESET_REG,
- IPW_RESET_REG_MASTER_DISABLED |
- IPW_RESET_REG_STOP_MASTER |
- CBD_RESET_REG_PRINCETON_RESET);
-
- /* enable power management */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW,
- IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY);
-
- IPW_DEBUG_TRACE("<<\n");
-}
-
-static int ipw_init_nic(struct ipw_priv *priv)
-{
- int rc;
-
- IPW_DEBUG_TRACE(">>\n");
- /* reset */
- /*prvHwInitNic */
- /* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
-
- /* low-level PLL activation */
- ipw_write32(priv, IPW_READ_INT_REGISTER,
- IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER);
-
- /* wait for clock stabilization */
- rc = ipw_poll_bit(priv, IPW_GP_CNTRL_RW,
- IPW_GP_CNTRL_BIT_CLOCK_READY, 250);
- if (rc < 0)
- IPW_DEBUG_INFO("FAILED wait for clock stablization\n");
-
- /* assert SW reset */
- ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_SW_RESET);
-
- udelay(10);
-
- /* set "initialization complete" bit to move adapter to D0 state */
- ipw_set_bit(priv, IPW_GP_CNTRL_RW, IPW_GP_CNTRL_BIT_INIT_DONE);
-
- IPW_DEBUG_TRACE(">>\n");
- return 0;
-}
-
-/* Call this function from process context, it will sleep in request_firmware.
- * Probe is an ok place to call this from.
- */
-static int ipw_reset_nic(struct ipw_priv *priv)
-{
- int rc = 0;
- unsigned long flags;
-
- IPW_DEBUG_TRACE(">>\n");
-
- rc = ipw_init_nic(priv);
-
- spin_lock_irqsave(&priv->lock, flags);
- /* Clear the 'host command active' bit... */
- priv->status &= ~STATUS_HCMD_ACTIVE;
- wake_up_interruptible(&priv->wait_command_queue);
- priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
- wake_up_interruptible(&priv->wait_state);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- IPW_DEBUG_TRACE("<<\n");
- return rc;
-}
-
-
-struct ipw_fw {
- __le32 ver;
- __le32 boot_size;
- __le32 ucode_size;
- __le32 fw_size;
- u8 data[];
-};
-
-static int ipw_get_fw(struct ipw_priv *priv,
- const struct firmware **raw, const char *name)
-{
- struct ipw_fw *fw;
- int rc;
-
- /* ask firmware_class module to get the boot firmware off disk */
- rc = request_firmware(raw, name, &priv->pci_dev->dev);
- if (rc < 0) {
- IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc);
- return rc;
- }
-
- if ((*raw)->size < sizeof(*fw)) {
- IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size);
- return -EINVAL;
- }
-
- fw = (void *)(*raw)->data;
-
- if ((*raw)->size < sizeof(*fw) + le32_to_cpu(fw->boot_size) +
- le32_to_cpu(fw->ucode_size) + le32_to_cpu(fw->fw_size)) {
- IPW_ERROR("%s is too small or corrupt (%zd)\n",
- name, (*raw)->size);
- return -EINVAL;
- }
-
- IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n",
- name,
- le32_to_cpu(fw->ver) >> 16,
- le32_to_cpu(fw->ver) & 0xff,
- (*raw)->size - sizeof(*fw));
- return 0;
-}
-
-#define IPW_RX_BUF_SIZE (3000)
-
-static void ipw_rx_queue_reset(struct ipw_priv *priv,
- struct ipw_rx_queue *rxq)
-{
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&rxq->lock, flags);
-
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
- /* In the reset function, these buffers may have been allocated
- * to an SKB, so we need to unmap and free potential storage */
- if (rxq->pool[i].skb != NULL) {
- dma_unmap_single(&priv->pci_dev->dev,
- rxq->pool[i].dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb_irq(rxq->pool[i].skb);
- rxq->pool[i].skb = NULL;
- }
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
- }
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
- spin_unlock_irqrestore(&rxq->lock, flags);
-}
-
-#ifdef CONFIG_PM
-static int fw_loaded = 0;
-static const struct firmware *raw = NULL;
-
-static void free_firmware(void)
-{
- if (fw_loaded) {
- release_firmware(raw);
- raw = NULL;
- fw_loaded = 0;
- }
-}
-#else
-#define free_firmware() do {} while (0)
-#endif
-
-static int ipw_load(struct ipw_priv *priv)
-{
-#ifndef CONFIG_PM
- const struct firmware *raw = NULL;
-#endif
- struct ipw_fw *fw;
- u8 *boot_img, *ucode_img, *fw_img;
- u8 *name = NULL;
- int rc = 0, retries = 3;
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- name = "ipw2200-ibss.fw";
- break;
-#ifdef CONFIG_IPW2200_MONITOR
- case IW_MODE_MONITOR:
- name = "ipw2200-sniffer.fw";
- break;
-#endif
- case IW_MODE_INFRA:
- name = "ipw2200-bss.fw";
- break;
- }
-
- if (!name) {
- rc = -EINVAL;
- goto error;
- }
-
-#ifdef CONFIG_PM
- if (!fw_loaded) {
-#endif
- rc = ipw_get_fw(priv, &raw, name);
- if (rc < 0)
- goto error;
-#ifdef CONFIG_PM
- }
-#endif
-
- fw = (void *)raw->data;
- boot_img = &fw->data[0];
- ucode_img = &fw->data[le32_to_cpu(fw->boot_size)];
- fw_img = &fw->data[le32_to_cpu(fw->boot_size) +
- le32_to_cpu(fw->ucode_size)];
-
- if (!priv->rxq)
- priv->rxq = ipw_rx_queue_alloc(priv);
- else
- ipw_rx_queue_reset(priv, priv->rxq);
- if (!priv->rxq) {
- IPW_ERROR("Unable to initialize Rx queue\n");
- rc = -ENOMEM;
- goto error;
- }
-
- retry:
- /* Ensure interrupts are disabled */
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
- priv->status &= ~STATUS_INT_ENABLED;
-
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
- ipw_stop_nic(priv);
-
- rc = ipw_reset_nic(priv);
- if (rc < 0) {
- IPW_ERROR("Unable to reset NIC\n");
- goto error;
- }
-
- ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND,
- IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND);
-
- /* DMA the initial boot firmware into the device */
- rc = ipw_load_firmware(priv, boot_img, le32_to_cpu(fw->boot_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load boot firmware: %d\n", rc);
- goto error;
- }
-
- /* kick start the device */
- ipw_start_nic(priv);
-
- /* wait for the device to finish its initial startup sequence */
- rc = ipw_poll_bit(priv, IPW_INTA_RW,
- IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
- if (rc < 0) {
- IPW_ERROR("device failed to boot initial fw image\n");
- goto error;
- }
- IPW_DEBUG_INFO("initial device response after %dms\n", rc);
-
- /* ack fw init done interrupt */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
-
- /* DMA the ucode into the device */
- rc = ipw_load_ucode(priv, ucode_img, le32_to_cpu(fw->ucode_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load ucode: %d\n", rc);
- goto error;
- }
-
- /* stop nic */
- ipw_stop_nic(priv);
-
- /* DMA bss firmware into the device */
- rc = ipw_load_firmware(priv, fw_img, le32_to_cpu(fw->fw_size));
- if (rc < 0) {
- IPW_ERROR("Unable to load firmware: %d\n", rc);
- goto error;
- }
-#ifdef CONFIG_PM
- fw_loaded = 1;
-#endif
-
- ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0);
-
- rc = ipw_queue_reset(priv);
- if (rc < 0) {
- IPW_ERROR("Unable to initialize queues\n");
- goto error;
- }
-
- /* Ensure interrupts are disabled */
- ipw_write32(priv, IPW_INTA_MASK_R, ~IPW_INTA_MASK_ALL);
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
- /* kick start the device */
- ipw_start_nic(priv);
-
- if (ipw_read32(priv, IPW_INTA_RW) & IPW_INTA_BIT_PARITY_ERROR) {
- if (retries > 0) {
- IPW_WARNING("Parity error. Retrying init.\n");
- retries--;
- goto retry;
- }
-
- IPW_ERROR("TODO: Handle parity error -- schedule restart?\n");
- rc = -EIO;
- goto error;
- }
-
- /* wait for the device */
- rc = ipw_poll_bit(priv, IPW_INTA_RW,
- IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500);
- if (rc < 0) {
- IPW_ERROR("device failed to start within 500ms\n");
- goto error;
- }
- IPW_DEBUG_INFO("device response after %dms\n", rc);
-
- /* ack fw init done interrupt */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE);
-
- /* read eeprom data */
- priv->eeprom_delay = 1;
- ipw_read_eeprom(priv);
- /* initialize the eeprom region of sram */
- ipw_eeprom_init_sram(priv);
-
- /* enable interrupts */
- ipw_enable_interrupts(priv);
-
- /* Ensure our queue has valid packets */
- ipw_rx_queue_replenish(priv);
-
- ipw_write32(priv, IPW_RX_READ_INDEX, priv->rxq->read);
-
- /* ack pending interrupts */
- ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL);
-
-#ifndef CONFIG_PM
- release_firmware(raw);
-#endif
- return 0;
-
- error:
- if (priv->rxq) {
- ipw_rx_queue_free(priv, priv->rxq);
- priv->rxq = NULL;
- }
- ipw_tx_queue_free(priv);
- release_firmware(raw);
-#ifdef CONFIG_PM
- fw_loaded = 0;
- raw = NULL;
-#endif
-
- return rc;
-}
-
-/*
- * DMA services
- *
- * Theory of operation
- *
- * A queue is a circular buffers with 'Read' and 'Write' pointers.
- * 2 empty entries always kept in the buffer to protect from overflow.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- * The IPW operates with six queues, one receive queue in the device's
- * sram, one transmit queue for sending commands to the device firmware,
- * and four transmit queues for data.
- *
- * The four transmit queues allow for performing quality of service (qos)
- * transmissions as per the 802.11 protocol. Currently Linux does not
- * provide a mechanism to the user for utilizing prioritized queues, so
- * we only utilize the first data transmit queue (queue1).
- */
-
-/*
- * Driver allocates buffers of this size for Rx
- */
-
-/*
- * ipw_rx_queue_space - Return number of free slots available in queue.
- */
-static int ipw_rx_queue_space(const struct ipw_rx_queue *q)
-{
- int s = q->read - q->write;
- if (s <= 0)
- s += RX_QUEUE_SIZE;
- /* keep some buffer to not confuse full and empty queue */
- s -= 2;
- if (s < 0)
- s = 0;
- return s;
-}
-
-static inline int ipw_tx_queue_space(const struct clx2_queue *q)
-{
- int s = q->last_used - q->first_empty;
- if (s <= 0)
- s += q->n_bd;
- s -= 2; /* keep some reserve to not confuse empty and full situations */
- if (s < 0)
- s = 0;
- return s;
-}
-
-static inline int ipw_queue_inc_wrap(int index, int n_bd)
-{
- return (++index == n_bd) ? 0 : index;
-}
-
-/*
- * Initialize common DMA queue structure
- *
- * @param q queue to init
- * @param count Number of BD's to allocate. Should be power of 2
- * @param read_register Address for 'read' register
- * (not offset within BAR, full address)
- * @param write_register Address for 'write' register
- * (not offset within BAR, full address)
- * @param base_register Address for 'base' register
- * (not offset within BAR, full address)
- * @param size Address for 'size' register
- * (not offset within BAR, full address)
- */
-static void ipw_queue_init(struct ipw_priv *priv, struct clx2_queue *q,
- int count, u32 read, u32 write, u32 base, u32 size)
-{
- q->n_bd = count;
-
- q->low_mark = q->n_bd / 4;
- if (q->low_mark < 4)
- q->low_mark = 4;
-
- q->high_mark = q->n_bd / 8;
- if (q->high_mark < 2)
- q->high_mark = 2;
-
- q->first_empty = q->last_used = 0;
- q->reg_r = read;
- q->reg_w = write;
-
- ipw_write32(priv, base, q->dma_addr);
- ipw_write32(priv, size, count);
- ipw_write32(priv, read, 0);
- ipw_write32(priv, write, 0);
-
- _ipw_read32(priv, 0x90);
-}
-
-static int ipw_queue_tx_init(struct ipw_priv *priv,
- struct clx2_tx_queue *q,
- int count, u32 read, u32 write, u32 base, u32 size)
-{
- struct pci_dev *dev = priv->pci_dev;
-
- q->txb = kmalloc_array(count, sizeof(q->txb[0]), GFP_KERNEL);
- if (!q->txb)
- return -ENOMEM;
-
- q->bd =
- dma_alloc_coherent(&dev->dev, sizeof(q->bd[0]) * count,
- &q->q.dma_addr, GFP_KERNEL);
- if (!q->bd) {
- IPW_ERROR("dma_alloc_coherent(%zd) failed\n",
- sizeof(q->bd[0]) * count);
- kfree(q->txb);
- q->txb = NULL;
- return -ENOMEM;
- }
-
- ipw_queue_init(priv, &q->q, count, read, write, base, size);
- return 0;
-}
-
-/*
- * Free one TFD, those at index [txq->q.last_used].
- * Do NOT advance any indexes
- *
- * @param dev
- * @param txq
- */
-static void ipw_queue_tx_free_tfd(struct ipw_priv *priv,
- struct clx2_tx_queue *txq)
-{
- struct tfd_frame *bd = &txq->bd[txq->q.last_used];
- struct pci_dev *dev = priv->pci_dev;
- int i;
-
- /* classify bd */
- if (bd->control_flags.message_type == TX_HOST_COMMAND_TYPE)
- /* nothing to cleanup after for host commands */
- return;
-
- /* sanity check */
- if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) {
- IPW_ERROR("Too many chunks: %i\n",
- le32_to_cpu(bd->u.data.num_chunks));
- /* @todo issue fatal error, it is quite serious situation */
- return;
- }
-
- /* unmap chunks if any */
- for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) {
- dma_unmap_single(&dev->dev,
- le32_to_cpu(bd->u.data.chunk_ptr[i]),
- le16_to_cpu(bd->u.data.chunk_len[i]),
- DMA_TO_DEVICE);
- if (txq->txb[txq->q.last_used]) {
- libipw_txb_free(txq->txb[txq->q.last_used]);
- txq->txb[txq->q.last_used] = NULL;
- }
- }
-}
-
-/*
- * Deallocate DMA queue.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- *
- * @param dev
- * @param q
- */
-static void ipw_queue_tx_free(struct ipw_priv *priv, struct clx2_tx_queue *txq)
-{
- struct clx2_queue *q = &txq->q;
- struct pci_dev *dev = priv->pci_dev;
-
- if (q->n_bd == 0)
- return;
-
- /* first, empty all BD's */
- for (; q->first_empty != q->last_used;
- q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
- ipw_queue_tx_free_tfd(priv, txq);
- }
-
- /* free buffers belonging to queue itself */
- dma_free_coherent(&dev->dev, sizeof(txq->bd[0]) * q->n_bd, txq->bd,
- q->dma_addr);
- kfree(txq->txb);
-
- /* 0 fill whole structure */
- memset(txq, 0, sizeof(*txq));
-}
-
-/*
- * Destroy all DMA queues and structures
- *
- * @param priv
- */
-static void ipw_tx_queue_free(struct ipw_priv *priv)
-{
- /* Tx CMD queue */
- ipw_queue_tx_free(priv, &priv->txq_cmd);
-
- /* Tx queues */
- ipw_queue_tx_free(priv, &priv->txq[0]);
- ipw_queue_tx_free(priv, &priv->txq[1]);
- ipw_queue_tx_free(priv, &priv->txq[2]);
- ipw_queue_tx_free(priv, &priv->txq[3]);
-}
-
-static void ipw_create_bssid(struct ipw_priv *priv, u8 * bssid)
-{
- /* First 3 bytes are manufacturer */
- bssid[0] = priv->mac_addr[0];
- bssid[1] = priv->mac_addr[1];
- bssid[2] = priv->mac_addr[2];
-
- /* Last bytes are random */
- get_random_bytes(&bssid[3], ETH_ALEN - 3);
-
- bssid[0] &= 0xfe; /* clear multicast bit */
- bssid[0] |= 0x02; /* set local assignment bit (IEEE802) */
-}
-
-static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid)
-{
- struct ipw_station_entry entry;
- int i;
-
- for (i = 0; i < priv->num_stations; i++) {
- if (ether_addr_equal(priv->stations[i], bssid)) {
- /* Another node is active in network */
- priv->missed_adhoc_beacons = 0;
- if (!(priv->config & CFG_STATIC_CHANNEL))
- /* when other nodes drop out, we drop out */
- priv->config &= ~CFG_ADHOC_PERSIST;
-
- return i;
- }
- }
-
- if (i == MAX_STATIONS)
- return IPW_INVALID_STATION;
-
- IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid);
-
- entry.reserved = 0;
- entry.support_mode = 0;
- memcpy(entry.mac_addr, bssid, ETH_ALEN);
- memcpy(priv->stations[i], bssid, ETH_ALEN);
- ipw_write_direct(priv, IPW_STATION_TABLE_LOWER + i * sizeof(entry),
- &entry, sizeof(entry));
- priv->num_stations++;
-
- return i;
-}
-
-static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid)
-{
- int i;
-
- for (i = 0; i < priv->num_stations; i++)
- if (ether_addr_equal(priv->stations[i], bssid))
- return i;
-
- return IPW_INVALID_STATION;
-}
-
-static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
-{
- int err;
-
- if (priv->status & STATUS_ASSOCIATING) {
- IPW_DEBUG_ASSOC("Disassociating while associating.\n");
- schedule_work(&priv->disassociate);
- return;
- }
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
- return;
- }
-
- IPW_DEBUG_ASSOC("Disassociation attempt from %pM "
- "on channel %d.\n",
- priv->assoc_request.bssid,
- priv->assoc_request.channel);
-
- priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
- priv->status |= STATUS_DISASSOCIATING;
-
- if (quiet)
- priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
- else
- priv->assoc_request.assoc_type = HC_DISASSOCIATE;
-
- err = ipw_send_associate(priv, &priv->assoc_request);
- if (err) {
- IPW_DEBUG_HC("Attempt to send [dis]associate command "
- "failed.\n");
- return;
- }
-
-}
-
-static int ipw_disassociate(void *data)
-{
- struct ipw_priv *priv = data;
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)))
- return 0;
- ipw_send_disassociate(data, 0);
- netif_carrier_off(priv->net_dev);
- return 1;
-}
-
-static void ipw_bg_disassociate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, disassociate);
- mutex_lock(&priv->mutex);
- ipw_disassociate(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_system_config(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, system_config);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
- }
-#endif
-
- ipw_send_system_config(priv);
-}
-
-struct ipw_status_code {
- u16 status;
- const char *reason;
-};
-
-static const struct ipw_status_code ipw_status_codes[] = {
- {0x00, "Successful"},
- {0x01, "Unspecified failure"},
- {0x0A, "Cannot support all requested capabilities in the "
- "Capability information field"},
- {0x0B, "Reassociation denied due to inability to confirm that "
- "association exists"},
- {0x0C, "Association denied due to reason outside the scope of this "
- "standard"},
- {0x0D,
- "Responding station does not support the specified authentication "
- "algorithm"},
- {0x0E,
- "Received an Authentication frame with authentication sequence "
- "transaction sequence number out of expected sequence"},
- {0x0F, "Authentication rejected because of challenge failure"},
- {0x10, "Authentication rejected due to timeout waiting for next "
- "frame in sequence"},
- {0x11, "Association denied because AP is unable to handle additional "
- "associated stations"},
- {0x12,
- "Association denied due to requesting station not supporting all "
- "of the datarates in the BSSBasicServiceSet Parameter"},
- {0x13,
- "Association denied due to requesting station not supporting "
- "short preamble operation"},
- {0x14,
- "Association denied due to requesting station not supporting "
- "PBCC encoding"},
- {0x15,
- "Association denied due to requesting station not supporting "
- "channel agility"},
- {0x19,
- "Association denied due to requesting station not supporting "
- "short slot operation"},
- {0x1A,
- "Association denied due to requesting station not supporting "
- "DSSS-OFDM operation"},
- {0x28, "Invalid Information Element"},
- {0x29, "Group Cipher is not valid"},
- {0x2A, "Pairwise Cipher is not valid"},
- {0x2B, "AKMP is not valid"},
- {0x2C, "Unsupported RSN IE version"},
- {0x2D, "Invalid RSN IE Capabilities"},
- {0x2E, "Cipher suite is rejected per security policy"},
-};
-
-static const char *ipw_get_status_code(u16 status)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++)
- if (ipw_status_codes[i].status == (status & 0xff))
- return ipw_status_codes[i].reason;
- return "Unknown status value.";
-}
-
-static inline void average_init(struct average *avg)
-{
- memset(avg, 0, sizeof(*avg));
-}
-
-#define DEPTH_RSSI 8
-#define DEPTH_NOISE 16
-static s16 exponential_average(s16 prev_avg, s16 val, u8 depth)
-{
- return ((depth-1)*prev_avg + val)/depth;
-}
-
-static void average_add(struct average *avg, s16 val)
-{
- avg->sum -= avg->entries[avg->pos];
- avg->sum += val;
- avg->entries[avg->pos++] = val;
- if (unlikely(avg->pos == AVG_ENTRIES)) {
- avg->init = 1;
- avg->pos = 0;
- }
-}
-
-static s16 average_value(struct average *avg)
-{
- if (!unlikely(avg->init)) {
- if (avg->pos)
- return avg->sum / avg->pos;
- return 0;
- }
-
- return avg->sum / AVG_ENTRIES;
-}
-
-static void ipw_reset_stats(struct ipw_priv *priv)
-{
- u32 len = sizeof(u32);
-
- priv->quality = 0;
-
- average_init(&priv->average_missed_beacons);
- priv->exp_avg_rssi = -60;
- priv->exp_avg_noise = -85 + 0x100;
-
- priv->last_rate = 0;
- priv->last_missed_beacons = 0;
- priv->last_rx_packets = 0;
- priv->last_tx_packets = 0;
- priv->last_tx_failures = 0;
-
- /* Firmware managed, reset only when NIC is restarted, so we have to
- * normalize on the current value */
- ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC,
- &priv->last_rx_err, &len);
- ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE,
- &priv->last_tx_failures, &len);
-
- /* Driver managed, reset with each association */
- priv->missed_adhoc_beacons = 0;
- priv->missed_beacons = 0;
- priv->tx_packets = 0;
- priv->rx_packets = 0;
-
-}
-
-static u32 ipw_get_max_rate(struct ipw_priv *priv)
-{
- u32 i = 0x80000000;
- u32 mask = priv->rates_mask;
- /* If currently associated in B mode, restrict the maximum
- * rate match to B rates */
- if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- mask &= LIBIPW_CCK_RATES_MASK;
-
- /* TODO: Verify that the rate is supported by the current rates
- * list. */
-
- while (i && !(mask & i))
- i >>= 1;
- switch (i) {
- case LIBIPW_CCK_RATE_1MB_MASK:
- return 1000000;
- case LIBIPW_CCK_RATE_2MB_MASK:
- return 2000000;
- case LIBIPW_CCK_RATE_5MB_MASK:
- return 5500000;
- case LIBIPW_OFDM_RATE_6MB_MASK:
- return 6000000;
- case LIBIPW_OFDM_RATE_9MB_MASK:
- return 9000000;
- case LIBIPW_CCK_RATE_11MB_MASK:
- return 11000000;
- case LIBIPW_OFDM_RATE_12MB_MASK:
- return 12000000;
- case LIBIPW_OFDM_RATE_18MB_MASK:
- return 18000000;
- case LIBIPW_OFDM_RATE_24MB_MASK:
- return 24000000;
- case LIBIPW_OFDM_RATE_36MB_MASK:
- return 36000000;
- case LIBIPW_OFDM_RATE_48MB_MASK:
- return 48000000;
- case LIBIPW_OFDM_RATE_54MB_MASK:
- return 54000000;
- }
-
- if (priv->ieee->mode == IEEE_B)
- return 11000000;
- else
- return 54000000;
-}
-
-static u32 ipw_get_current_rate(struct ipw_priv *priv)
-{
- u32 rate, len = sizeof(rate);
- int err;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return 0;
-
- if (priv->tx_packets > IPW_REAL_RATE_RX_PACKET_THRESHOLD) {
- err = ipw_get_ordinal(priv, IPW_ORD_STAT_TX_CURR_RATE, &rate,
- &len);
- if (err) {
- IPW_DEBUG_INFO("failed querying ordinals.\n");
- return 0;
- }
- } else
- return ipw_get_max_rate(priv);
-
- switch (rate) {
- case IPW_TX_RATE_1MB:
- return 1000000;
- case IPW_TX_RATE_2MB:
- return 2000000;
- case IPW_TX_RATE_5MB:
- return 5500000;
- case IPW_TX_RATE_6MB:
- return 6000000;
- case IPW_TX_RATE_9MB:
- return 9000000;
- case IPW_TX_RATE_11MB:
- return 11000000;
- case IPW_TX_RATE_12MB:
- return 12000000;
- case IPW_TX_RATE_18MB:
- return 18000000;
- case IPW_TX_RATE_24MB:
- return 24000000;
- case IPW_TX_RATE_36MB:
- return 36000000;
- case IPW_TX_RATE_48MB:
- return 48000000;
- case IPW_TX_RATE_54MB:
- return 54000000;
- }
-
- return 0;
-}
-
-#define IPW_STATS_INTERVAL (2 * HZ)
-static void ipw_gather_stats(struct ipw_priv *priv)
-{
- u32 rx_err, rx_err_delta, rx_packets_delta;
- u32 tx_failures, tx_failures_delta, tx_packets_delta;
- u32 missed_beacons_percent, missed_beacons_delta;
- u32 quality = 0;
- u32 len = sizeof(u32);
- s16 rssi;
- u32 beacon_quality, signal_quality, tx_quality, rx_quality,
- rate_quality;
- u32 max_rate;
-
- if (!(priv->status & STATUS_ASSOCIATED)) {
- priv->quality = 0;
- return;
- }
-
- /* Update the statistics */
- ipw_get_ordinal(priv, IPW_ORD_STAT_MISSED_BEACONS,
- &priv->missed_beacons, &len);
- missed_beacons_delta = priv->missed_beacons - priv->last_missed_beacons;
- priv->last_missed_beacons = priv->missed_beacons;
- if (priv->assoc_request.beacon_interval) {
- missed_beacons_percent = missed_beacons_delta *
- (HZ * le16_to_cpu(priv->assoc_request.beacon_interval)) /
- (IPW_STATS_INTERVAL * 10);
- } else {
- missed_beacons_percent = 0;
- }
- average_add(&priv->average_missed_beacons, missed_beacons_percent);
-
- ipw_get_ordinal(priv, IPW_ORD_STAT_RX_ERR_CRC, &rx_err, &len);
- rx_err_delta = rx_err - priv->last_rx_err;
- priv->last_rx_err = rx_err;
-
- ipw_get_ordinal(priv, IPW_ORD_STAT_TX_FAILURE, &tx_failures, &len);
- tx_failures_delta = tx_failures - priv->last_tx_failures;
- priv->last_tx_failures = tx_failures;
-
- rx_packets_delta = priv->rx_packets - priv->last_rx_packets;
- priv->last_rx_packets = priv->rx_packets;
-
- tx_packets_delta = priv->tx_packets - priv->last_tx_packets;
- priv->last_tx_packets = priv->tx_packets;
-
- /* Calculate quality based on the following:
- *
- * Missed beacon: 100% = 0, 0% = 70% missed
- * Rate: 60% = 1Mbs, 100% = Max
- * Rx and Tx errors represent a straight % of total Rx/Tx
- * RSSI: 100% = > -50, 0% = < -80
- * Rx errors: 100% = 0, 0% = 50% missed
- *
- * The lowest computed quality is used.
- *
- */
-#define BEACON_THRESHOLD 5
- beacon_quality = 100 - missed_beacons_percent;
- if (beacon_quality < BEACON_THRESHOLD)
- beacon_quality = 0;
- else
- beacon_quality = (beacon_quality - BEACON_THRESHOLD) * 100 /
- (100 - BEACON_THRESHOLD);
- IPW_DEBUG_STATS("Missed beacon: %3d%% (%d%%)\n",
- beacon_quality, missed_beacons_percent);
-
- priv->last_rate = ipw_get_current_rate(priv);
- max_rate = ipw_get_max_rate(priv);
- rate_quality = priv->last_rate * 40 / max_rate + 60;
- IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n",
- rate_quality, priv->last_rate / 1000000);
-
- if (rx_packets_delta > 100 && rx_packets_delta + rx_err_delta)
- rx_quality = 100 - (rx_err_delta * 100) /
- (rx_packets_delta + rx_err_delta);
- else
- rx_quality = 100;
- IPW_DEBUG_STATS("Rx quality : %3d%% (%u errors, %u packets)\n",
- rx_quality, rx_err_delta, rx_packets_delta);
-
- if (tx_packets_delta > 100 && tx_packets_delta + tx_failures_delta)
- tx_quality = 100 - (tx_failures_delta * 100) /
- (tx_packets_delta + tx_failures_delta);
- else
- tx_quality = 100;
- IPW_DEBUG_STATS("Tx quality : %3d%% (%u errors, %u packets)\n",
- tx_quality, tx_failures_delta, tx_packets_delta);
-
- rssi = priv->exp_avg_rssi;
- signal_quality =
- (100 *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) -
- (priv->ieee->perfect_rssi - rssi) *
- (15 * (priv->ieee->perfect_rssi - priv->ieee->worst_rssi) +
- 62 * (priv->ieee->perfect_rssi - rssi))) /
- ((priv->ieee->perfect_rssi - priv->ieee->worst_rssi) *
- (priv->ieee->perfect_rssi - priv->ieee->worst_rssi));
- if (signal_quality > 100)
- signal_quality = 100;
- else if (signal_quality < 1)
- signal_quality = 0;
-
- IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n",
- signal_quality, rssi);
-
- quality = min(rx_quality, signal_quality);
- quality = min(tx_quality, quality);
- quality = min(rate_quality, quality);
- quality = min(beacon_quality, quality);
- if (quality == beacon_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to missed beacons.\n",
- quality);
- if (quality == rate_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to rate quality.\n",
- quality);
- if (quality == tx_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to Tx quality.\n",
- quality);
- if (quality == rx_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to Rx quality.\n",
- quality);
- if (quality == signal_quality)
- IPW_DEBUG_STATS("Quality (%d%%): Clamped to signal quality.\n",
- quality);
-
- priv->quality = quality;
-
- schedule_delayed_work(&priv->gather_stats, IPW_STATS_INTERVAL);
-}
-
-static void ipw_bg_gather_stats(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, gather_stats.work);
- mutex_lock(&priv->mutex);
- ipw_gather_stats(priv);
- mutex_unlock(&priv->mutex);
-}
-
-/* Missed beacon behavior:
- * 1st missed -> roaming_threshold, just wait, don't do any scan/roam.
- * roaming_threshold -> disassociate_threshold, scan and roam for better signal.
- * Above disassociate threshold, give up and stop scanning.
- * Roaming is disabled if disassociate_threshold <= roaming_threshold */
-static void ipw_handle_missed_beacon(struct ipw_priv *priv,
- int missed_count)
-{
- priv->notif_missed_beacons = missed_count;
-
- if (missed_count > priv->disassociate_threshold &&
- priv->status & STATUS_ASSOCIATED) {
- /* If associated and we've hit the missed
- * beacon threshold, disassociate, turn
- * off roaming, and abort any active scans */
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE | IPW_DL_ASSOC,
- "Missed beacon: %d - disassociate\n", missed_count);
- priv->status &= ~STATUS_ROAMING;
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE,
- "Aborting scan with missed beacon.\n");
- schedule_work(&priv->abort_scan);
- }
-
- schedule_work(&priv->disassociate);
- return;
- }
-
- if (priv->status & STATUS_ROAMING) {
- /* If we are currently roaming, then just
- * print a debug statement... */
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "Missed beacon: %d - roam in progress\n",
- missed_count);
- return;
- }
-
- if (roaming &&
- (missed_count > priv->roaming_threshold &&
- missed_count <= priv->disassociate_threshold)) {
- /* If we are not already roaming, set the ROAM
- * bit in the status and kick off a scan.
- * This can happen several times before we reach
- * disassociate_threshold. */
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "Missed beacon: %d - initiate "
- "roaming\n", missed_count);
- if (!(priv->status & STATUS_ROAMING)) {
- priv->status |= STATUS_ROAMING;
- if (!(priv->status & STATUS_SCANNING))
- schedule_delayed_work(&priv->request_scan, 0);
- }
- return;
- }
-
- if (priv->status & STATUS_SCANNING &&
- missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) {
- /* Stop scan to keep fw from getting
- * stuck (only if we aren't roaming --
- * otherwise we'll never scan more than 2 or 3
- * channels..) */
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | IPW_DL_STATE,
- "Aborting scan with missed beacon.\n");
- schedule_work(&priv->abort_scan);
- }
-
- IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
-}
-
-static void ipw_scan_event(struct work_struct *work)
-{
- union iwreq_data wrqu;
-
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, scan_event.work);
-
- wrqu.data.length = 0;
- wrqu.data.flags = 0;
- wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
-}
-
-static void handle_scan_event(struct ipw_priv *priv)
-{
- /* Only userspace-requested scan completion events go out immediately */
- if (!priv->user_requested_scan) {
- schedule_delayed_work(&priv->scan_event,
- round_jiffies_relative(msecs_to_jiffies(4000)));
- } else {
- priv->user_requested_scan = 0;
- mod_delayed_work(system_wq, &priv->scan_event, 0);
- }
-}
-
-/*
- * Handle host notification packet.
- * Called from interrupt routine
- */
-static void ipw_rx_notification(struct ipw_priv *priv,
- struct ipw_rx_notification *notif)
-{
- u16 size = le16_to_cpu(notif->size);
-
- IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, size);
-
- switch (notif->subtype) {
- case HOST_NOTIFICATION_STATUS_ASSOCIATED:{
- struct notif_association *assoc = ¬if->u.assoc;
-
- switch (assoc->state) {
- case CMAS_ASSOCIATED:{
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "associated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_INFRA:
- memcpy(priv->ieee->bssid,
- priv->bssid, ETH_ALEN);
- break;
-
- case IW_MODE_ADHOC:
- memcpy(priv->ieee->bssid,
- priv->bssid, ETH_ALEN);
-
- /* clear out the station table */
- priv->num_stations = 0;
-
- IPW_DEBUG_ASSOC
- ("queueing adhoc check\n");
- schedule_delayed_work(
- &priv->adhoc_check,
- le16_to_cpu(priv->
- assoc_request.
- beacon_interval));
- break;
- }
-
- priv->status &= ~STATUS_ASSOCIATING;
- priv->status |= STATUS_ASSOCIATED;
- schedule_work(&priv->system_config);
-
-#ifdef CONFIG_IPW2200_QOS
-#define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \
- le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control))
- if ((priv->status & STATUS_AUTH) &&
- (IPW_GET_PACKET_STYPE(¬if->u.raw)
- == IEEE80211_STYPE_ASSOC_RESP)) {
- if ((sizeof
- (struct
- libipw_assoc_response)
- <= size)
- && (size <= 2314)) {
- struct
- libipw_rx_stats
- stats = {
- .len = size - 1,
- };
-
- IPW_DEBUG_QOS
- ("QoS Associate "
- "size %d\n", size);
- libipw_rx_mgt(priv->
- ieee,
- (struct
- libipw_hdr_4addr
- *)
- ¬if->u.raw, &stats);
- }
- }
-#endif
-
- schedule_work(&priv->link_up);
-
- break;
- }
-
- case CMAS_AUTHENTICATED:{
- if (priv->
- status & (STATUS_ASSOCIATED |
- STATUS_AUTH)) {
- struct notif_authenticate *auth
- = ¬if->u.auth;
- IPW_DEBUG(IPW_DL_NOTIF |
- IPW_DL_STATE |
- IPW_DL_ASSOC,
- "deauthenticated: '%*pE' %pM: (0x%04X) - %s\n",
- priv->essid_len,
- priv->essid,
- priv->bssid,
- le16_to_cpu(auth->status),
- ipw_get_status_code
- (le16_to_cpu
- (auth->status)));
-
- priv->status &=
- ~(STATUS_ASSOCIATING |
- STATUS_AUTH |
- STATUS_ASSOCIATED);
-
- schedule_work(&priv->link_down);
- break;
- }
-
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "authenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
- break;
- }
-
- case CMAS_INIT:{
- if (priv->status & STATUS_AUTH) {
- struct
- libipw_assoc_response
- *resp;
- resp =
- (struct
- libipw_assoc_response
- *)¬if->u.raw;
- IPW_DEBUG(IPW_DL_NOTIF |
- IPW_DL_STATE |
- IPW_DL_ASSOC,
- "association failed (0x%04X): %s\n",
- le16_to_cpu(resp->status),
- ipw_get_status_code
- (le16_to_cpu
- (resp->status)));
- }
-
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "disassociated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &=
- ~(STATUS_DISASSOCIATING |
- STATUS_ASSOCIATING |
- STATUS_ASSOCIATED | STATUS_AUTH);
- if (priv->assoc_network
- && (priv->assoc_network->
- capability &
- WLAN_CAPABILITY_IBSS))
- ipw_remove_current_network
- (priv);
-
- schedule_work(&priv->link_down);
-
- break;
- }
-
- case CMAS_RX_ASSOC_RESP:
- break;
-
- default:
- IPW_ERROR("assoc: unknown (%d)\n",
- assoc->state);
- break;
- }
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_AUTHENTICATE:{
- struct notif_authenticate *auth = ¬if->u.auth;
- switch (auth->state) {
- case CMAS_AUTHENTICATED:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "authenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
- priv->status |= STATUS_AUTH;
- break;
-
- case CMAS_INIT:
- if (priv->status & STATUS_AUTH) {
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "authentication failed (0x%04X): %s\n",
- le16_to_cpu(auth->status),
- ipw_get_status_code(le16_to_cpu
- (auth->
- status)));
- }
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC,
- "deauthenticated: '%*pE' %pM\n",
- priv->essid_len, priv->essid,
- priv->bssid);
-
- priv->status &= ~(STATUS_ASSOCIATING |
- STATUS_AUTH |
- STATUS_ASSOCIATED);
-
- schedule_work(&priv->link_down);
- break;
-
- case CMAS_TX_AUTH_SEQ_1:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1\n");
- break;
- case CMAS_RX_AUTH_SEQ_2:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_2\n");
- break;
- case CMAS_AUTH_SEQ_1_PASS:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1_PASS\n");
- break;
- case CMAS_AUTH_SEQ_1_FAIL:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_1_FAIL\n");
- break;
- case CMAS_TX_AUTH_SEQ_3:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_3\n");
- break;
- case CMAS_RX_AUTH_SEQ_4:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "RX_AUTH_SEQ_4\n");
- break;
- case CMAS_AUTH_SEQ_2_PASS:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUTH_SEQ_2_PASS\n");
- break;
- case CMAS_AUTH_SEQ_2_FAIL:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "AUT_SEQ_2_FAIL\n");
- break;
- case CMAS_TX_ASSOC:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "TX_ASSOC\n");
- break;
- case CMAS_RX_ASSOC_RESP:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "RX_ASSOC_RESP\n");
-
- break;
- case CMAS_ASSOCIATED:
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
- IPW_DL_ASSOC, "ASSOCIATED\n");
- break;
- default:
- IPW_DEBUG_NOTIF("auth: failure - %d\n",
- auth->state);
- break;
- }
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT:{
- struct notif_channel_result *x =
- ¬if->u.channel_result;
-
- if (size == sizeof(*x)) {
- IPW_DEBUG_SCAN("Scan result for channel %d\n",
- x->channel_num);
- } else {
- IPW_DEBUG_SCAN("Scan result of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_SCAN_COMPLETED:{
- struct notif_scan_complete *x = ¬if->u.scan_complete;
- if (size == sizeof(*x)) {
- IPW_DEBUG_SCAN
- ("Scan completed: type %d, %d channels, "
- "%d status\n", x->scan_type,
- x->num_channels, x->status);
- } else {
- IPW_ERROR("Scan completed of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
-
- priv->status &=
- ~(STATUS_SCANNING | STATUS_SCAN_ABORTING);
-
- wake_up_interruptible(&priv->wait_state);
- cancel_delayed_work(&priv->scan_check);
-
- if (priv->status & STATUS_EXIT_PENDING)
- break;
-
- priv->ieee->scans++;
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- priv->status |= STATUS_SCAN_FORCED;
- schedule_delayed_work(&priv->request_scan, 0);
- break;
- }
- priv->status &= ~STATUS_SCAN_FORCED;
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Do queued direct scans first */
- if (priv->status & STATUS_DIRECT_SCAN_PENDING)
- schedule_delayed_work(&priv->request_direct_scan, 0);
-
- if (!(priv->status & (STATUS_ASSOCIATED |
- STATUS_ASSOCIATING |
- STATUS_ROAMING |
- STATUS_DISASSOCIATING)))
- schedule_work(&priv->associate);
- else if (priv->status & STATUS_ROAMING) {
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
- /* If a scan completed and we are in roam mode, then
- * the scan that completed was the one requested as a
- * result of entering roam... so, schedule the
- * roam work */
- schedule_work(&priv->roam);
- else
- /* Don't schedule if we aborted the scan */
- priv->status &= ~STATUS_ROAMING;
- } else if (priv->status & STATUS_SCAN_PENDING)
- schedule_delayed_work(&priv->request_scan, 0);
- else if (priv->config & CFG_BACKGROUND_SCAN
- && priv->status & STATUS_ASSOCIATED)
- schedule_delayed_work(&priv->request_scan,
- round_jiffies_relative(HZ));
-
- /* Send an empty event to user space.
- * We don't send the received data on the event because
- * it would require us to do complex transcoding, and
- * we want to minimise the work done in the irq handler
- * Use a request to extract the data.
- * Also, we generate this even for any scan, regardless
- * on how the scan was initiated. User space can just
- * sync on periodic scan to get fresh data...
- * Jean II */
- if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
- handle_scan_event(priv);
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{
- struct notif_frag_length *x = ¬if->u.frag_len;
-
- if (size == sizeof(*x))
- IPW_ERROR("Frag length: %d\n",
- le16_to_cpu(x->frag_length));
- else
- IPW_ERROR("Frag length of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{
- struct notif_link_deterioration *x =
- ¬if->u.link_deterioration;
-
- if (size == sizeof(*x)) {
- IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
- "link deterioration: type %d, cnt %d\n",
- x->silence_notification_type,
- x->silence_count);
- memcpy(&priv->last_link_deterioration, x,
- sizeof(*x));
- } else {
- IPW_ERROR("Link Deterioration of wrong size %d "
- "(should be %zd)\n",
- size, sizeof(*x));
- }
- break;
- }
-
- case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{
- IPW_ERROR("Dino config\n");
- if (priv->hcmd
- && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG)
- IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n");
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_BEACON_STATE:{
- struct notif_beacon_state *x = ¬if->u.beacon_state;
- if (size != sizeof(*x)) {
- IPW_ERROR
- ("Beacon state of wrong size %d (should "
- "be %zd)\n", size, sizeof(*x));
- break;
- }
-
- if (le32_to_cpu(x->state) ==
- HOST_NOTIFICATION_STATUS_BEACON_MISSING)
- ipw_handle_missed_beacon(priv,
- le32_to_cpu(x->
- number));
-
- break;
- }
-
- case HOST_NOTIFICATION_STATUS_TGI_TX_KEY:{
- struct notif_tgi_tx_key *x = ¬if->u.tgi_tx_key;
- if (size == sizeof(*x)) {
- IPW_ERROR("TGi Tx Key: state 0x%02x sec type "
- "0x%02x station %d\n",
- x->key_state, x->security_type,
- x->station_index);
- break;
- }
-
- IPW_ERROR
- ("TGi Tx Key of wrong size %d (should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_CALIB_KEEP_RESULTS:{
- struct notif_calibration *x = ¬if->u.calibration;
-
- if (size == sizeof(*x)) {
- memcpy(&priv->calib, x, sizeof(*x));
- IPW_DEBUG_INFO("TODO: Calibration\n");
- break;
- }
-
- IPW_ERROR
- ("Calibration of wrong size %d (should be %zd)\n",
- size, sizeof(*x));
- break;
- }
-
- case HOST_NOTIFICATION_NOISE_STATS:{
- if (size == sizeof(u32)) {
- priv->exp_avg_noise =
- exponential_average(priv->exp_avg_noise,
- (u8) (le32_to_cpu(notif->u.noise.value) & 0xff),
- DEPTH_NOISE);
- break;
- }
-
- IPW_ERROR
- ("Noise stat is wrong size %d (should be %zd)\n",
- size, sizeof(u32));
- break;
- }
-
- default:
- IPW_DEBUG_NOTIF("Unknown notification: "
- "subtype=%d,flags=0x%2x,size=%d\n",
- notif->subtype, notif->flags, size);
- }
-}
-
-/*
- * Destroys all DMA structures and initialise them again
- *
- * @param priv
- * @return error code
- */
-static int ipw_queue_reset(struct ipw_priv *priv)
-{
- int rc = 0;
- /* @todo customize queue sizes */
- int nTx = 64, nTxCmd = 8;
- ipw_tx_queue_free(priv);
- /* Tx CMD queue */
- rc = ipw_queue_tx_init(priv, &priv->txq_cmd, nTxCmd,
- IPW_TX_CMD_QUEUE_READ_INDEX,
- IPW_TX_CMD_QUEUE_WRITE_INDEX,
- IPW_TX_CMD_QUEUE_BD_BASE,
- IPW_TX_CMD_QUEUE_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx Cmd queue init failed\n");
- goto error;
- }
- /* Tx queue(s) */
- rc = ipw_queue_tx_init(priv, &priv->txq[0], nTx,
- IPW_TX_QUEUE_0_READ_INDEX,
- IPW_TX_QUEUE_0_WRITE_INDEX,
- IPW_TX_QUEUE_0_BD_BASE, IPW_TX_QUEUE_0_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 0 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[1], nTx,
- IPW_TX_QUEUE_1_READ_INDEX,
- IPW_TX_QUEUE_1_WRITE_INDEX,
- IPW_TX_QUEUE_1_BD_BASE, IPW_TX_QUEUE_1_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 1 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[2], nTx,
- IPW_TX_QUEUE_2_READ_INDEX,
- IPW_TX_QUEUE_2_WRITE_INDEX,
- IPW_TX_QUEUE_2_BD_BASE, IPW_TX_QUEUE_2_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 2 queue init failed\n");
- goto error;
- }
- rc = ipw_queue_tx_init(priv, &priv->txq[3], nTx,
- IPW_TX_QUEUE_3_READ_INDEX,
- IPW_TX_QUEUE_3_WRITE_INDEX,
- IPW_TX_QUEUE_3_BD_BASE, IPW_TX_QUEUE_3_BD_SIZE);
- if (rc) {
- IPW_ERROR("Tx 3 queue init failed\n");
- goto error;
- }
- /* statistics */
- priv->rx_bufs_min = 0;
- priv->rx_pend_max = 0;
- return rc;
-
- error:
- ipw_tx_queue_free(priv);
- return rc;
-}
-
-/*
- * Reclaim Tx queue entries no more used by NIC.
- *
- * When FW advances 'R' index, all entries between old and
- * new 'R' index need to be reclaimed. As result, some free space
- * forms. If there is enough free space (> low mark), wake Tx queue.
- *
- * @note Need to protect against garbage in 'R' index
- * @param priv
- * @param txq
- * @param qindex
- * @return Number of used entries remains in the queue
- */
-static int ipw_queue_tx_reclaim(struct ipw_priv *priv,
- struct clx2_tx_queue *txq, int qindex)
-{
- u32 hw_tail;
- int used;
- struct clx2_queue *q = &txq->q;
-
- hw_tail = ipw_read32(priv, q->reg_r);
- if (hw_tail >= q->n_bd) {
- IPW_ERROR
- ("Read index for DMA queue (%d) is out of range [0-%d)\n",
- hw_tail, q->n_bd);
- goto done;
- }
- for (; q->last_used != hw_tail;
- q->last_used = ipw_queue_inc_wrap(q->last_used, q->n_bd)) {
- ipw_queue_tx_free_tfd(priv, txq);
- priv->tx_packets++;
- }
- done:
- if ((ipw_tx_queue_space(q) > q->low_mark) &&
- (qindex >= 0))
- netif_wake_queue(priv->net_dev);
- used = q->first_empty - q->last_used;
- if (used < 0)
- used += q->n_bd;
-
- return used;
-}
-
-static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, const void *buf,
- int len, int sync)
-{
- struct clx2_tx_queue *txq = &priv->txq_cmd;
- struct clx2_queue *q = &txq->q;
- struct tfd_frame *tfd;
-
- if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) {
- IPW_ERROR("No space for Tx\n");
- return -EBUSY;
- }
-
- tfd = &txq->bd[q->first_empty];
- txq->txb[q->first_empty] = NULL;
-
- memset(tfd, 0, sizeof(*tfd));
- tfd->control_flags.message_type = TX_HOST_COMMAND_TYPE;
- tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
- priv->hcmd_seq++;
- tfd->u.cmd.index = hcmd;
- tfd->u.cmd.length = len;
- memcpy(tfd->u.cmd.payload, buf, len);
- q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
- ipw_write32(priv, q->reg_w, q->first_empty);
- _ipw_read32(priv, 0x90);
-
- return 0;
-}
-
-/*
- * Rx theory of operation
- *
- * The host allocates 32 DMA target addresses and passes the host address
- * to the firmware at register IPW_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
- * 0 to 31
- *
- * Rx Queue Indexes
- * The host/firmware share two index registers for managing the Rx buffers.
- *
- * The READ index maps to the first position that the firmware may be writing
- * to -- the driver can read up to (but not including) this position and get
- * good data.
- * The READ index is managed by the firmware once the card is enabled.
- *
- * The WRITE index maps to the last position the driver has read from -- the
- * position preceding WRITE is the last slot the firmware can place a packet.
- *
- * The queue is empty (no good data) if WRITE = READ - 1, and is full if
- * WRITE = READ.
- *
- * During initialization the host sets up the READ queue position to the first
- * INDEX position, and WRITE to the last (READ - 1 wrapped)
- *
- * When the firmware places a packet in a buffer it will advance the READ index
- * and fire the RX interrupt. The driver can then query the READ index and
- * process as many packets as possible, moving the WRITE index forward as it
- * resets the Rx queue buffers with new memory.
- *
- * The management in the driver is as follows:
- * + A list of pre-allocated SKBs is stored in ipw->rxq->rx_free. When
- * ipw->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
- * to replensish the ipw->rxq->rx_free.
- * + In ipw_rx_queue_replenish (scheduled) if 'processed' != 'read' then the
- * ipw->rxq is replenished and the READ INDEX is updated (updating the
- * 'processed' and 'read' driver indexes as well)
- * + A received packet is processed and handed to the kernel network stack,
- * detached from the ipw->rxq. The driver 'processed' index is updated.
- * + The Host/Firmware ipw->rxq is replenished at tasklet time from the rx_free
- * list. If there are no allocated buffers in ipw->rxq->rx_free, the READ
- * INDEX is not incremented and ipw->status(RX_STALLED) is set. If there
- * were enough free buffers and RX_STALLED is set it is cleared.
- *
- *
- * Driver sequence:
- *
- * ipw_rx_queue_alloc() Allocates rx_free
- * ipw_rx_queue_replenish() Replenishes rx_free list from rx_used, and calls
- * ipw_rx_queue_restock
- * ipw_rx_queue_restock() Moves available buffers from rx_free into Rx
- * queue, updates firmware pointers, and updates
- * the WRITE index. If insufficient rx_free buffers
- * are available, schedules ipw_rx_queue_replenish
- *
- * -- enable interrupts --
- * ISR - ipw_rx() Detach ipw_rx_mem_buffers from pool up to the
- * READ INDEX, detaching the SKB from the pool.
- * Moves the packet buffer from queue to rx_used.
- * Calls ipw_rx_queue_restock to refill any empty
- * slots.
- * ...
- *
- */
-
-/*
- * If there are slots in the RX queue that need to be restocked,
- * and we have free pre-allocated buffers, fill the ranks as much
- * as we can pulling from rx_free.
- *
- * This moves the 'write' index forward to catch up with 'processed', and
- * also updates the memory address in the firmware to reference the new
- * target buffer.
- */
-static void ipw_rx_queue_restock(struct ipw_priv *priv)
-{
- struct ipw_rx_queue *rxq = priv->rxq;
- struct list_head *element;
- struct ipw_rx_mem_buffer *rxb;
- unsigned long flags;
- int write;
-
- spin_lock_irqsave(&rxq->lock, flags);
- write = rxq->write;
- while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
- element = rxq->rx_free.next;
- rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
- list_del(element);
-
- ipw_write32(priv, IPW_RFDS_TABLE_LOWER + rxq->write * RFD_SIZE,
- rxb->dma_addr);
- rxq->queue[rxq->write] = rxb;
- rxq->write = (rxq->write + 1) % RX_QUEUE_SIZE;
- rxq->free_count--;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- /* If the pre-allocated buffer pool is dropping low, schedule to
- * refill it */
- if (rxq->free_count <= RX_LOW_WATERMARK)
- schedule_work(&priv->rx_replenish);
-
- /* If we've added more space for the firmware to place data, tell it */
- if (write != rxq->write)
- ipw_write32(priv, IPW_RX_WRITE_INDEX, rxq->write);
-}
-
-/*
- * Move all used packet from rx_used to rx_free, allocating a new SKB for each.
- * Also restock the Rx queue via ipw_rx_queue_restock.
- *
- * This is called as a scheduled work item (except for during initialization)
- */
-static void ipw_rx_queue_replenish(void *data)
-{
- struct ipw_priv *priv = data;
- struct ipw_rx_queue *rxq = priv->rxq;
- struct list_head *element;
- struct ipw_rx_mem_buffer *rxb;
- unsigned long flags;
-
- spin_lock_irqsave(&rxq->lock, flags);
- while (!list_empty(&rxq->rx_used)) {
- element = rxq->rx_used.next;
- rxb = list_entry(element, struct ipw_rx_mem_buffer, list);
- rxb->skb = alloc_skb(IPW_RX_BUF_SIZE, GFP_ATOMIC);
- if (!rxb->skb) {
- printk(KERN_CRIT "%s: Can not allocate SKB buffers.\n",
- priv->net_dev->name);
- /* We don't reschedule replenish work here -- we will
- * call the restock method and if it still needs
- * more buffers it will schedule replenish */
- break;
- }
- list_del(element);
-
- rxb->dma_addr =
- dma_map_single(&priv->pci_dev->dev, rxb->skb->data,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
-
- list_add_tail(&rxb->list, &rxq->rx_free);
- rxq->free_count++;
- }
- spin_unlock_irqrestore(&rxq->lock, flags);
-
- ipw_rx_queue_restock(priv);
-}
-
-static void ipw_bg_rx_queue_replenish(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, rx_replenish);
- mutex_lock(&priv->mutex);
- ipw_rx_queue_replenish(priv);
- mutex_unlock(&priv->mutex);
-}
-
-/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
- * If an SKB has been detached, the POOL needs to have its SKB set to NULL
- * This free routine walks the list of POOL entries and if SKB is set to
- * non NULL it is unmapped and freed
- */
-static void ipw_rx_queue_free(struct ipw_priv *priv, struct ipw_rx_queue *rxq)
-{
- int i;
-
- if (!rxq)
- return;
-
- for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
- if (rxq->pool[i].skb != NULL) {
- dma_unmap_single(&priv->pci_dev->dev,
- rxq->pool[i].dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb(rxq->pool[i].skb);
- }
- }
-
- kfree(rxq);
-}
-
-static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv)
-{
- struct ipw_rx_queue *rxq;
- int i;
-
- rxq = kzalloc(sizeof(*rxq), GFP_KERNEL);
- if (unlikely(!rxq)) {
- IPW_ERROR("memory allocation failed\n");
- return NULL;
- }
- spin_lock_init(&rxq->lock);
- INIT_LIST_HEAD(&rxq->rx_free);
- INIT_LIST_HEAD(&rxq->rx_used);
-
- /* Fill the rx_used queue with _all_ of the Rx buffers */
- for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
- list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-
- /* Set us so that we have processed and used all buffers, but have
- * not restocked the Rx queue with fresh buffers */
- rxq->read = rxq->write = 0;
- rxq->free_count = 0;
-
- return rxq;
-}
-
-static int ipw_is_rate_in_mask(struct ipw_priv *priv, int ieee_mode, u8 rate)
-{
- rate &= ~LIBIPW_BASIC_RATE_MASK;
- if (ieee_mode == IEEE_A) {
- switch (rate) {
- case LIBIPW_OFDM_RATE_6MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ?
- 1 : 0;
- case LIBIPW_OFDM_RATE_9MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ?
- 1 : 0;
- case LIBIPW_OFDM_RATE_12MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_18MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_24MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_36MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_48MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_54MB:
- return priv->
- rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
- default:
- return 0;
- }
- }
-
- /* B and G mixed */
- switch (rate) {
- case LIBIPW_CCK_RATE_1MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_1MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_2MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_2MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_5MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_5MB_MASK ? 1 : 0;
- case LIBIPW_CCK_RATE_11MB:
- return priv->rates_mask & LIBIPW_CCK_RATE_11MB_MASK ? 1 : 0;
- }
-
- /* If we are limited to B modulations, bail at this point */
- if (ieee_mode == IEEE_B)
- return 0;
-
- /* G */
- switch (rate) {
- case LIBIPW_OFDM_RATE_6MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_6MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_9MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_9MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_12MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_12MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_18MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_18MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_24MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_24MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_36MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_36MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_48MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_48MB_MASK ? 1 : 0;
- case LIBIPW_OFDM_RATE_54MB:
- return priv->rates_mask & LIBIPW_OFDM_RATE_54MB_MASK ? 1 : 0;
- }
-
- return 0;
-}
-
-static int ipw_compatible_rates(struct ipw_priv *priv,
- const struct libipw_network *network,
- struct ipw_supported_rates *rates)
-{
- int num_rates, i;
-
- memset(rates, 0, sizeof(*rates));
- num_rates = min(network->rates_len, (u8) IPW_MAX_RATES);
- rates->num_rates = 0;
- for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask(priv, network->mode,
- network->rates[i])) {
-
- if (network->rates[i] & LIBIPW_BASIC_RATE_MASK) {
- IPW_DEBUG_SCAN("Adding masked mandatory "
- "rate %02X\n",
- network->rates[i]);
- rates->supported_rates[rates->num_rates++] =
- network->rates[i];
- continue;
- }
-
- IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
- network->rates[i], priv->rates_mask);
- continue;
- }
-
- rates->supported_rates[rates->num_rates++] = network->rates[i];
- }
-
- num_rates = min(network->rates_ex_len,
- (u8) (IPW_MAX_RATES - num_rates));
- for (i = 0; i < num_rates; i++) {
- if (!ipw_is_rate_in_mask(priv, network->mode,
- network->rates_ex[i])) {
- if (network->rates_ex[i] & LIBIPW_BASIC_RATE_MASK) {
- IPW_DEBUG_SCAN("Adding masked mandatory "
- "rate %02X\n",
- network->rates_ex[i]);
- rates->supported_rates[rates->num_rates++] =
- network->rates[i];
- continue;
- }
-
- IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n",
- network->rates_ex[i], priv->rates_mask);
- continue;
- }
-
- rates->supported_rates[rates->num_rates++] =
- network->rates_ex[i];
- }
-
- return 1;
-}
-
-static void ipw_copy_rates(struct ipw_supported_rates *dest,
- const struct ipw_supported_rates *src)
-{
- u8 i;
- for (i = 0; i < src->num_rates; i++)
- dest->supported_rates[i] = src->supported_rates[i];
- dest->num_rates = src->num_rates;
-}
-
-/* TODO: Look at sniffed packets in the air to determine if the basic rate
- * mask should ever be used -- right now all callers to add the scan rates are
- * set with the modulation = CCK, so BASIC_RATE_MASK is never set... */
-static void ipw_add_cck_scan_rates(struct ipw_supported_rates *rates,
- u8 modulation, u32 rate_mask)
-{
- u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
- LIBIPW_BASIC_RATE_MASK : 0;
-
- if (rate_mask & LIBIPW_CCK_RATE_1MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_1MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_2MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_BASIC_RATE_MASK | LIBIPW_CCK_RATE_2MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_5MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_CCK_RATE_5MB;
-
- if (rate_mask & LIBIPW_CCK_RATE_11MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_CCK_RATE_11MB;
-}
-
-static void ipw_add_ofdm_scan_rates(struct ipw_supported_rates *rates,
- u8 modulation, u32 rate_mask)
-{
- u8 basic_mask = (LIBIPW_OFDM_MODULATION == modulation) ?
- LIBIPW_BASIC_RATE_MASK : 0;
-
- if (rate_mask & LIBIPW_OFDM_RATE_6MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_6MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_9MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_9MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_12MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_12MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_18MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_18MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_24MB_MASK)
- rates->supported_rates[rates->num_rates++] = basic_mask |
- LIBIPW_OFDM_RATE_24MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_36MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_36MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_48MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_48MB;
-
- if (rate_mask & LIBIPW_OFDM_RATE_54MB_MASK)
- rates->supported_rates[rates->num_rates++] =
- LIBIPW_OFDM_RATE_54MB;
-}
-
-struct ipw_network_match {
- struct libipw_network *network;
- struct ipw_supported_rates rates;
-};
-
-static int ipw_find_adhoc_network(struct ipw_priv *priv,
- struct ipw_network_match *match,
- struct libipw_network *network,
- int roaming)
-{
- struct ipw_supported_rates rates;
-
- /* Verify that this network's capability is compatible with the
- * current mode (AdHoc or Infrastructure) */
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
- !(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (unlikely(roaming)) {
- /* If we are roaming, then ensure check if this is a valid
- * network to try and roam to */
- if ((network->ssid_len != match->network->ssid_len) ||
- memcmp(network->ssid, match->network->ssid,
- network->ssid_len)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
- } else {
- /* If an ESSID has been configured then compare the broadcast
- * ESSID to ours */
- if ((priv->config & CFG_STATIC_ESSID) &&
- ((network->ssid_len != priv->essid_len) ||
- memcmp(network->ssid, priv->essid,
- min(network->ssid_len, priv->essid_len)))) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->essid_len,
- priv->essid);
- return 0;
- }
- }
-
- /* If the old network rate is better than this one, don't bother
- * testing everything else. */
-
- if (network->time_stamp[0] < match->network->time_stamp[0]) {
- IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
- match->network->ssid_len, match->network->ssid);
- return 0;
- } else if (network->time_stamp[1] < match->network->time_stamp[1]) {
- IPW_DEBUG_MERGE("Network '%*pE excluded because newer than current network.\n",
- match->network->ssid_len, match->network->ssid);
- return 0;
- }
-
- /* Now go through and see if the requested network is valid... */
- if (priv->ieee->scan_age != 0 &&
- time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of age: %ums.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_scanned));
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_CHANNEL) &&
- (network->channel != priv->channel)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- network->channel, priv->channel);
- return 0;
- }
-
- /* Verify privacy compatibility */
- if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
- ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- priv->
- capability & CAP_PRIVACY_ON ? "on" : "off",
- network->
- capability & WLAN_CAPABILITY_PRIVACY ? "on" :
- "off");
- return 0;
- }
-
- if (ether_addr_equal(network->bssid, priv->bssid)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of the same BSSID match: %pM.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->bssid);
- return 0;
- }
-
- /* Filter out any incompatible freq / mode combinations */
- if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Ensure that the rates supported by the driver are compatible with
- * this AP, including verification of basic rates (mandatory) */
- if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (rates.num_rates == 0) {
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* TODO: Perform any further minimal comparititive tests. We do not
- * want to put too much policy logic here; intelligent scan selection
- * should occur within a generic IEEE 802.11 user space tool. */
-
- /* Set up 'new' AP to this network */
- ipw_copy_rates(&match->rates, &rates);
- match->network = network;
- IPW_DEBUG_MERGE("Network '%*pE (%pM)' is a viable match.\n",
- network->ssid_len, network->ssid, network->bssid);
-
- return 1;
-}
-
-static void ipw_merge_adhoc_network(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, merge_networks);
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = priv->assoc_network
- };
-
- if ((priv->status & STATUS_ASSOCIATED) &&
- (priv->ieee->iw_mode == IW_MODE_ADHOC)) {
- /* First pass through ROAM process -- look for a better
- * network */
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list) {
- if (network != priv->assoc_network)
- ipw_find_adhoc_network(priv, &match, network,
- 1);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (match.network == priv->assoc_network) {
- IPW_DEBUG_MERGE("No better ADHOC in this network to "
- "merge to.\n");
- return;
- }
-
- mutex_lock(&priv->mutex);
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- IPW_DEBUG_MERGE("remove network %*pE\n",
- priv->essid_len, priv->essid);
- ipw_remove_current_network(priv);
- }
-
- ipw_disassociate(priv);
- priv->assoc_network = match.network;
- mutex_unlock(&priv->mutex);
- return;
- }
-}
-
-static int ipw_best_network(struct ipw_priv *priv,
- struct ipw_network_match *match,
- struct libipw_network *network, int roaming)
-{
- struct ipw_supported_rates rates;
-
- /* Verify that this network's capability is compatible with the
- * current mode (AdHoc or Infrastructure) */
- if ((priv->ieee->iw_mode == IW_MODE_INFRA &&
- !(network->capability & WLAN_CAPABILITY_ESS)) ||
- (priv->ieee->iw_mode == IW_MODE_ADHOC &&
- !(network->capability & WLAN_CAPABILITY_IBSS))) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded due to capability mismatch.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (unlikely(roaming)) {
- /* If we are roaming, then ensure check if this is a valid
- * network to try and roam to */
- if ((network->ssid_len != match->network->ssid_len) ||
- memcmp(network->ssid, match->network->ssid,
- network->ssid_len)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of non-network ESSID.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
- } else {
- /* If an ESSID has been configured then compare the broadcast
- * ESSID to ours */
- if ((priv->config & CFG_STATIC_ESSID) &&
- ((network->ssid_len != priv->essid_len) ||
- memcmp(network->ssid, priv->essid,
- min(network->ssid_len, priv->essid_len)))) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of ESSID mismatch: '%*pE'.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->essid_len,
- priv->essid);
- return 0;
- }
- }
-
- /* If the old network rate is better than this one, don't bother
- * testing everything else. */
- if (match->network && match->network->stats.rssi > network->stats.rssi) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because '%*pE (%pM)' has a stronger signal.\n",
- network->ssid_len, network->ssid,
- network->bssid, match->network->ssid_len,
- match->network->ssid, match->network->bssid);
- return 0;
- }
-
- /* If this network has already had an association attempt within the
- * last 3 seconds, do not try and associate again... */
- if (network->last_associate &&
- time_after(network->last_associate + (HZ * 3UL), jiffies)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of storming (%ums since last assoc attempt).\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_associate));
- return 0;
- }
-
- /* Now go through and see if the requested network is valid... */
- if (priv->ieee->scan_age != 0 &&
- time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of age: %ums.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- jiffies_to_msecs(jiffies -
- network->last_scanned));
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_CHANNEL) &&
- (network->channel != priv->channel)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of channel mismatch: %d != %d.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- network->channel, priv->channel);
- return 0;
- }
-
- /* Verify privacy compatibility */
- if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
- ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of privacy mismatch: %s != %s.\n",
- network->ssid_len, network->ssid,
- network->bssid,
- priv->capability & CAP_PRIVACY_ON ? "on" :
- "off",
- network->capability &
- WLAN_CAPABILITY_PRIVACY ? "on" : "off");
- return 0;
- }
-
- if ((priv->config & CFG_STATIC_BSSID) &&
- !ether_addr_equal(network->bssid, priv->bssid)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of BSSID mismatch: %pM.\n",
- network->ssid_len, network->ssid,
- network->bssid, priv->bssid);
- return 0;
- }
-
- /* Filter out any incompatible freq / mode combinations */
- if (!libipw_is_valid_mode(priv->ieee, network->mode)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid frequency/mode combination.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Filter out invalid channel in current GEO */
- if (!libipw_is_valid_channel(priv->ieee, network->channel)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of invalid channel in current GEO\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* Ensure that the rates supported by the driver are compatible with
- * this AP, including verification of basic rates (mandatory) */
- if (!ipw_compatible_rates(priv, network, &rates)) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because configured rate mask excludes AP mandatory rate.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- if (rates.num_rates == 0) {
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' excluded because of no compatible rates.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 0;
- }
-
- /* TODO: Perform any further minimal comparititive tests. We do not
- * want to put too much policy logic here; intelligent scan selection
- * should occur within a generic IEEE 802.11 user space tool. */
-
- /* Set up 'new' AP to this network */
- ipw_copy_rates(&match->rates, &rates);
- match->network = network;
-
- IPW_DEBUG_ASSOC("Network '%*pE (%pM)' is a viable match.\n",
- network->ssid_len, network->ssid, network->bssid);
-
- return 1;
-}
-
-static void ipw_adhoc_create(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int i;
-
- /*
- * For the purposes of scanning, we can set our wireless mode
- * to trigger scans across combinations of bands, but when it
- * comes to creating a new ad-hoc network, we have tell the FW
- * exactly which band to use.
- *
- * We also have the possibility of an invalid channel for the
- * chossen band. Attempting to create a new ad-hoc network
- * with an invalid channel for wireless mode will trigger a
- * FW fatal error.
- *
- */
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- network->mode = IEEE_A;
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_WARNING("Overriding invalid channel\n");
- priv->channel = geo->a[0].channel;
- }
- break;
-
- case LIBIPW_24GHZ_BAND:
- if (priv->ieee->mode & IEEE_G)
- network->mode = IEEE_G;
- else
- network->mode = IEEE_B;
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_WARNING("Overriding invalid channel\n");
- priv->channel = geo->bg[0].channel;
- }
- break;
-
- default:
- IPW_WARNING("Overriding invalid channel\n");
- if (priv->ieee->mode & IEEE_A) {
- network->mode = IEEE_A;
- priv->channel = geo->a[0].channel;
- } else if (priv->ieee->mode & IEEE_G) {
- network->mode = IEEE_G;
- priv->channel = geo->bg[0].channel;
- } else {
- network->mode = IEEE_B;
- priv->channel = geo->bg[0].channel;
- }
- break;
- }
-
- network->channel = priv->channel;
- priv->config |= CFG_ADHOC_PERSIST;
- ipw_create_bssid(priv, network->bssid);
- network->ssid_len = priv->essid_len;
- memcpy(network->ssid, priv->essid, priv->essid_len);
- memset(&network->stats, 0, sizeof(network->stats));
- network->capability = WLAN_CAPABILITY_IBSS;
- if (!(priv->config & CFG_PREAMBLE_LONG))
- network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE;
- if (priv->capability & CAP_PRIVACY_ON)
- network->capability |= WLAN_CAPABILITY_PRIVACY;
- network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH);
- memcpy(network->rates, priv->rates.supported_rates, network->rates_len);
- network->rates_ex_len = priv->rates.num_rates - network->rates_len;
- memcpy(network->rates_ex,
- &priv->rates.supported_rates[network->rates_len],
- network->rates_ex_len);
- network->last_scanned = 0;
- network->flags = 0;
- network->last_associate = 0;
- network->time_stamp[0] = 0;
- network->time_stamp[1] = 0;
- network->beacon_interval = 100; /* Default */
- network->listen_interval = 10; /* Default */
- network->atim_window = 0; /* Default */
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-}
-
-static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
-{
- struct ipw_tgi_tx_key key;
-
- if (!(priv->ieee->sec.flags & (1 << index)))
- return;
-
- key.key_id = index;
- memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH);
- key.security_type = type;
- key.station_index = 0; /* always 0 for BSS */
- key.flags = 0;
- /* 0 for new key; previous value of counter (after fatal error) */
- key.tx_counter[0] = cpu_to_le32(0);
- key.tx_counter[1] = cpu_to_le32(0);
-
- ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key);
-}
-
-static void ipw_send_wep_keys(struct ipw_priv *priv, int type)
-{
- struct ipw_wep_key key;
- int i;
-
- key.cmd_id = DINO_CMD_WEP_KEY;
- key.seq_num = 0;
-
- /* Note: AES keys cannot be set for multiple times.
- * Only set it at the first time. */
- for (i = 0; i < 4; i++) {
- key.key_index = i | type;
- if (!(priv->ieee->sec.flags & (1 << i))) {
- key.key_size = 0;
- continue;
- }
-
- key.key_size = priv->ieee->sec.key_sizes[i];
- memcpy(key.key, priv->ieee->sec.keys[i], key.key_size);
-
- ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key);
- }
-}
-
-static void ipw_set_hw_decrypt_unicast(struct ipw_priv *priv, int level)
-{
- if (priv->ieee->host_encrypt)
- return;
-
- switch (level) {
- case SEC_LEVEL_3:
- priv->sys_config.disable_unicast_decryption = 0;
- priv->ieee->host_decrypt = 0;
- break;
- case SEC_LEVEL_2:
- priv->sys_config.disable_unicast_decryption = 1;
- priv->ieee->host_decrypt = 1;
- break;
- case SEC_LEVEL_1:
- priv->sys_config.disable_unicast_decryption = 0;
- priv->ieee->host_decrypt = 0;
- break;
- case SEC_LEVEL_0:
- priv->sys_config.disable_unicast_decryption = 1;
- break;
- default:
- break;
- }
-}
-
-static void ipw_set_hw_decrypt_multicast(struct ipw_priv *priv, int level)
-{
- if (priv->ieee->host_encrypt)
- return;
-
- switch (level) {
- case SEC_LEVEL_3:
- priv->sys_config.disable_multicast_decryption = 0;
- break;
- case SEC_LEVEL_2:
- priv->sys_config.disable_multicast_decryption = 1;
- break;
- case SEC_LEVEL_1:
- priv->sys_config.disable_multicast_decryption = 0;
- break;
- case SEC_LEVEL_0:
- priv->sys_config.disable_multicast_decryption = 1;
- break;
- default:
- break;
- }
-}
-
-static void ipw_set_hwcrypto_keys(struct ipw_priv *priv)
-{
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
- ipw_send_tgi_tx_key(priv,
- DCT_FLAG_EXT_SECURITY_CCM,
- priv->ieee->sec.active_key);
-
- if (!priv->ieee->host_mc_decrypt)
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM);
- break;
- case SEC_LEVEL_2:
- if (priv->ieee->sec.flags & SEC_ACTIVE_KEY)
- ipw_send_tgi_tx_key(priv,
- DCT_FLAG_EXT_SECURITY_TKIP,
- priv->ieee->sec.active_key);
- break;
- case SEC_LEVEL_1:
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
- ipw_set_hw_decrypt_unicast(priv, priv->ieee->sec.level);
- ipw_set_hw_decrypt_multicast(priv, priv->ieee->sec.level);
- break;
- case SEC_LEVEL_0:
- default:
- break;
- }
-}
-
-static void ipw_adhoc_check(void *data)
-{
- struct ipw_priv *priv = data;
-
- if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold &&
- !(priv->config & CFG_ADHOC_PERSIST)) {
- IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF |
- IPW_DL_STATE | IPW_DL_ASSOC,
- "Missed beacon: %d - disassociate\n",
- priv->missed_adhoc_beacons);
- ipw_remove_current_network(priv);
- ipw_disassociate(priv);
- return;
- }
-
- schedule_delayed_work(&priv->adhoc_check,
- le16_to_cpu(priv->assoc_request.beacon_interval));
-}
-
-static void ipw_bg_adhoc_check(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, adhoc_check.work);
- mutex_lock(&priv->mutex);
- ipw_adhoc_check(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_debug_config(struct ipw_priv *priv)
-{
- IPW_DEBUG_INFO("Scan completed, no valid APs matched "
- "[CFG 0x%08X]\n", priv->config);
- if (priv->config & CFG_STATIC_CHANNEL)
- IPW_DEBUG_INFO("Channel locked to %d\n", priv->channel);
- else
- IPW_DEBUG_INFO("Channel unlocked.\n");
- if (priv->config & CFG_STATIC_ESSID)
- IPW_DEBUG_INFO("ESSID locked to '%*pE'\n",
- priv->essid_len, priv->essid);
- else
- IPW_DEBUG_INFO("ESSID unlocked.\n");
- if (priv->config & CFG_STATIC_BSSID)
- IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid);
- else
- IPW_DEBUG_INFO("BSSID unlocked.\n");
- if (priv->capability & CAP_PRIVACY_ON)
- IPW_DEBUG_INFO("PRIVACY on\n");
- else
- IPW_DEBUG_INFO("PRIVACY off\n");
- IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
-}
-
-static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
-{
- /* TODO: Verify that this works... */
- struct ipw_fixed_rate fr;
- u32 reg;
- u16 mask = 0;
- u16 new_tx_rates = priv->rates_mask;
-
- /* Identify 'current FW band' and match it with the fixed
- * Tx rates */
-
- switch (priv->ieee->freq_band) {
- case LIBIPW_52GHZ_BAND: /* A only */
- /* IEEE_A */
- if (priv->rates_mask & ~LIBIPW_OFDM_RATES_MASK) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- break;
- }
-
- new_tx_rates >>= LIBIPW_OFDM_SHIFT_MASK_A;
- break;
-
- default: /* 2.4Ghz or Mixed */
- /* IEEE_B */
- if (mode == IEEE_B) {
- if (new_tx_rates & ~LIBIPW_CCK_RATES_MASK) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- }
- break;
- }
-
- /* IEEE_G */
- if (new_tx_rates & ~(LIBIPW_CCK_RATES_MASK |
- LIBIPW_OFDM_RATES_MASK)) {
- /* Invalid fixed rate mask */
- IPW_DEBUG_WX
- ("invalid fixed rate mask in ipw_set_fixed_rate\n");
- new_tx_rates = 0;
- break;
- }
-
- if (LIBIPW_OFDM_RATE_6MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_6MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_6MB_MASK;
- }
-
- if (LIBIPW_OFDM_RATE_9MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_9MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_9MB_MASK;
- }
-
- if (LIBIPW_OFDM_RATE_12MB_MASK & new_tx_rates) {
- mask |= (LIBIPW_OFDM_RATE_12MB_MASK >> 1);
- new_tx_rates &= ~LIBIPW_OFDM_RATE_12MB_MASK;
- }
-
- new_tx_rates |= mask;
- break;
- }
-
- fr.tx_rates = cpu_to_le16(new_tx_rates);
-
- reg = ipw_read32(priv, IPW_MEM_FIXED_OVERRIDE);
- ipw_write_reg32(priv, reg, *(u32 *) & fr);
-}
-
-static void ipw_abort_scan(struct ipw_priv *priv)
-{
- int err;
-
- if (priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n");
- return;
- }
- priv->status |= STATUS_SCAN_ABORTING;
-
- err = ipw_send_scan_abort(priv);
- if (err)
- IPW_DEBUG_HC("Request to abort scan failed.\n");
-}
-
-static void ipw_add_scan_channels(struct ipw_priv *priv,
- struct ipw_scan_request_ext *scan,
- int scan_type)
-{
- int channel_index = 0;
- const struct libipw_geo *geo;
- int i;
-
- geo = libipw_get_geo(priv->ieee);
-
- if (priv->ieee->freq_band & LIBIPW_52GHZ_BAND) {
- int start = channel_index;
- for (i = 0; i < geo->a_channels; i++) {
- if ((priv->status & STATUS_ASSOCIATED) &&
- geo->a[i].channel == priv->channel)
- continue;
- channel_index++;
- scan->channels_list[channel_index] = geo->a[i].channel;
- ipw_set_scan_type(scan, channel_index,
- geo->a[i].
- flags & LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN :
- scan_type);
- }
-
- if (start != channel_index) {
- scan->channels_list[start] = (u8) (IPW_A_MODE << 6) |
- (channel_index - start);
- channel_index++;
- }
- }
-
- if (priv->ieee->freq_band & LIBIPW_24GHZ_BAND) {
- int start = channel_index;
- if (priv->config & CFG_SPEED_SCAN) {
- int index;
- u8 channels[LIBIPW_24GHZ_CHANNELS] = {
- /* nop out the list */
- [0] = 0
- };
-
- u8 channel;
- while (channel_index < IPW_SCAN_CHANNELS - 1) {
- channel =
- priv->speed_scan[priv->speed_scan_pos];
- if (channel == 0) {
- priv->speed_scan_pos = 0;
- channel = priv->speed_scan[0];
- }
- if ((priv->status & STATUS_ASSOCIATED) &&
- channel == priv->channel) {
- priv->speed_scan_pos++;
- continue;
- }
-
- /* If this channel has already been
- * added in scan, break from loop
- * and this will be the first channel
- * in the next scan.
- */
- if (channels[channel - 1] != 0)
- break;
-
- channels[channel - 1] = 1;
- priv->speed_scan_pos++;
- channel_index++;
- scan->channels_list[channel_index] = channel;
- index =
- libipw_channel_to_index(priv->ieee, channel);
- ipw_set_scan_type(scan, channel_index,
- geo->bg[index].
- flags &
- LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
- : scan_type);
- }
- } else {
- for (i = 0; i < geo->bg_channels; i++) {
- if ((priv->status & STATUS_ASSOCIATED) &&
- geo->bg[i].channel == priv->channel)
- continue;
- channel_index++;
- scan->channels_list[channel_index] =
- geo->bg[i].channel;
- ipw_set_scan_type(scan, channel_index,
- geo->bg[i].
- flags &
- LIBIPW_CH_PASSIVE_ONLY ?
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN
- : scan_type);
- }
- }
-
- if (start != channel_index) {
- scan->channels_list[start] = (u8) (IPW_B_MODE << 6) |
- (channel_index - start);
- }
- }
-}
-
-static int ipw_passive_dwell_time(struct ipw_priv *priv)
-{
- /* staying on passive channels longer than the DTIM interval during a
- * scan, while associated, causes the firmware to cancel the scan
- * without notification. Hence, don't stay on passive channels longer
- * than the beacon interval.
- */
- if (priv->status & STATUS_ASSOCIATED
- && priv->assoc_network->beacon_interval > 10)
- return priv->assoc_network->beacon_interval - 10;
- else
- return 120;
-}
-
-static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct)
-{
- struct ipw_scan_request_ext scan;
- int err = 0, scan_type;
-
- if (!(priv->status & STATUS_INIT) ||
- (priv->status & STATUS_EXIT_PENDING))
- return 0;
-
- mutex_lock(&priv->mutex);
-
- if (direct && (priv->direct_scan_ssid_len == 0)) {
- IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n");
- priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
- goto done;
- }
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- if (!(priv->status & STATUS_SCAN_FORCED) &&
- priv->status & STATUS_SCAN_ABORTING) {
- IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- if (priv->status & STATUS_RF_KILL_MASK) {
- IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n");
- priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING :
- STATUS_SCAN_PENDING;
- goto done;
- }
-
- memset(&scan, 0, sizeof(scan));
- scan.full_scan_index = cpu_to_le32(libipw_get_scans(priv->ieee));
-
- if (type == IW_SCAN_TYPE_PASSIVE) {
- IPW_DEBUG_WX("use passive scanning\n");
- scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(ipw_passive_dwell_time(priv));
- ipw_add_scan_channels(priv, &scan, scan_type);
- goto send_request;
- }
-
- /* Use active scan by default. */
- if (priv->config & CFG_SPEED_SCAN)
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(30);
- else
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(20);
-
- scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] =
- cpu_to_le16(20);
-
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(ipw_passive_dwell_time(priv));
- scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20);
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- u8 channel;
- u8 band = 0;
-
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- band = (u8) (IPW_A_MODE << 6) | 1;
- channel = priv->channel;
- break;
-
- case LIBIPW_24GHZ_BAND:
- band = (u8) (IPW_B_MODE << 6) | 1;
- channel = priv->channel;
- break;
-
- default:
- band = (u8) (IPW_B_MODE << 6) | 1;
- channel = 9;
- break;
- }
-
- scan.channels_list[0] = band;
- scan.channels_list[1] = channel;
- ipw_set_scan_type(&scan, 1, IPW_SCAN_PASSIVE_FULL_DWELL_SCAN);
-
- /* NOTE: The card will sit on this channel for this time
- * period. Scan aborts are timing sensitive and frequently
- * result in firmware restarts. As such, it is best to
- * set a small dwell_time here and just keep re-issuing
- * scans. Otherwise fast channel hopping will not actually
- * hop channels.
- *
- * TODO: Move SPEED SCAN support to all modes and bands */
- scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(2000);
- } else {
-#endif /* CONFIG_IPW2200_MONITOR */
- /* Honor direct scans first, otherwise if we are roaming make
- * this a direct scan for the current network. Finally,
- * ensure that every other scan is a fast channel hop scan */
- if (direct) {
- err = ipw_send_ssid(priv, priv->direct_scan_ssid,
- priv->direct_scan_ssid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command "
- "failed\n");
- goto done;
- }
-
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
- } else if ((priv->status & STATUS_ROAMING)
- || (!(priv->status & STATUS_ASSOCIATED)
- && (priv->config & CFG_STATIC_ESSID)
- && (le32_to_cpu(scan.full_scan_index) % 2))) {
- err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command "
- "failed.\n");
- goto done;
- }
-
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN;
- } else
- scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN;
-
- ipw_add_scan_channels(priv, &scan, scan_type);
-#ifdef CONFIG_IPW2200_MONITOR
- }
-#endif
-
-send_request:
- err = ipw_send_scan_request_ext(priv, &scan);
- if (err) {
- IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
- goto done;
- }
-
- priv->status |= STATUS_SCANNING;
- if (direct) {
- priv->status &= ~STATUS_DIRECT_SCAN_PENDING;
- priv->direct_scan_ssid_len = 0;
- } else
- priv->status &= ~STATUS_SCAN_PENDING;
-
- schedule_delayed_work(&priv->scan_check, IPW_SCAN_CHECK_WATCHDOG);
-done:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static void ipw_request_passive_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_passive_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0);
-}
-
-static void ipw_request_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0);
-}
-
-static void ipw_request_direct_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, request_direct_scan.work);
- ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1);
-}
-
-static void ipw_bg_abort_scan(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, abort_scan);
- mutex_lock(&priv->mutex);
- ipw_abort_scan(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_wpa_enable(struct ipw_priv *priv, int value)
-{
- /* This is called when wpa_supplicant loads and closes the driver
- * interface. */
- priv->ieee->wpa_enabled = value;
- return 0;
-}
-
-static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value)
-{
- struct libipw_device *ieee = priv->ieee;
- struct libipw_security sec = {
- .flags = SEC_AUTH_MODE,
- };
- int ret = 0;
-
- if (value & IW_AUTH_ALG_SHARED_KEY) {
- sec.auth_mode = WLAN_AUTH_SHARED_KEY;
- ieee->open_wep = 0;
- } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) {
- sec.auth_mode = WLAN_AUTH_OPEN;
- ieee->open_wep = 1;
- } else if (value & IW_AUTH_ALG_LEAP) {
- sec.auth_mode = WLAN_AUTH_LEAP;
- ieee->open_wep = 1;
- } else
- return -EINVAL;
-
- if (ieee->set_security)
- ieee->set_security(ieee->dev, &sec);
- else
- ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie,
- int wpa_ie_len)
-{
- /* make sure WPA is enabled */
- ipw_wpa_enable(priv, 1);
-}
-
-static int ipw_set_rsn_capa(struct ipw_priv *priv,
- char *capabilities, int length)
-{
- IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n");
-
- return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length,
- capabilities);
-}
-
-/*
- * WE-18 support
- */
-
-/* SIOCSIWGENIE */
-static int ipw_wx_set_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- u8 *buf;
- int err = 0;
-
- if (wrqu->data.length > MAX_WPA_IE_LEN ||
- (wrqu->data.length && extra == NULL))
- return -EINVAL;
-
- if (wrqu->data.length) {
- buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
- if (buf == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = buf;
- ieee->wpa_ie_len = wrqu->data.length;
- } else {
- kfree(ieee->wpa_ie);
- ieee->wpa_ie = NULL;
- ieee->wpa_ie_len = 0;
- }
-
- ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
- out:
- return err;
-}
-
-/* SIOCGIWGENIE */
-static int ipw_wx_get_genie(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- int err = 0;
-
- if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
- wrqu->data.length = 0;
- goto out;
- }
-
- if (wrqu->data.length < ieee->wpa_ie_len) {
- err = -E2BIG;
- goto out;
- }
-
- wrqu->data.length = ieee->wpa_ie_len;
- memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
-
- out:
- return err;
-}
-
-static int wext_cipher2level(int cipher)
-{
- switch (cipher) {
- case IW_AUTH_CIPHER_NONE:
- return SEC_LEVEL_0;
- case IW_AUTH_CIPHER_WEP40:
- case IW_AUTH_CIPHER_WEP104:
- return SEC_LEVEL_1;
- case IW_AUTH_CIPHER_TKIP:
- return SEC_LEVEL_2;
- case IW_AUTH_CIPHER_CCMP:
- return SEC_LEVEL_3;
- default:
- return -1;
- }
-}
-
-/* SIOCSIWAUTH */
-static int ipw_wx_set_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct iw_param *param = &wrqu->param;
- struct lib80211_crypt_data *crypt;
- unsigned long flags;
- int ret = 0;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- break;
- case IW_AUTH_CIPHER_PAIRWISE:
- ipw_set_hw_decrypt_unicast(priv,
- wext_cipher2level(param->value));
- break;
- case IW_AUTH_CIPHER_GROUP:
- ipw_set_hw_decrypt_multicast(priv,
- wext_cipher2level(param->value));
- break;
- case IW_AUTH_KEY_MGMT:
- /*
- * ipw2200 does not use these parameters
- */
- break;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags)
- break;
-
- flags = crypt->ops->get_flags(crypt->priv);
-
- if (param->value)
- flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
- else
- flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES;
-
- crypt->ops->set_flags(flags, crypt->priv);
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:{
- /* HACK:
- *
- * wpa_supplicant calls set_wpa_enabled when the driver
- * is loaded and unloaded, regardless of if WPA is being
- * used. No other calls are made which can be used to
- * determine if encryption will be used or not prior to
- * association being expected. If encryption is not being
- * used, drop_unencrypted is set to false, else true -- we
- * can use this to determine if the CAP_PRIVACY_ON bit should
- * be set.
- */
- struct libipw_security sec = {
- .flags = SEC_ENABLED,
- .enabled = param->value,
- };
- priv->ieee->drop_unencrypted = param->value;
- /* We only change SEC_LEVEL for open mode. Others
- * are set by ipw_wpa_set_encryption.
- */
- if (!param->value) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_0;
- } else {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- }
- if (priv->ieee->set_security)
- priv->ieee->set_security(priv->ieee->dev, &sec);
- break;
- }
-
- case IW_AUTH_80211_AUTH_ALG:
- ret = ipw_wpa_set_auth_algs(priv, param->value);
- break;
-
- case IW_AUTH_WPA_ENABLED:
- ret = ipw_wpa_enable(priv, param->value);
- ipw_disassociate(priv);
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- ieee->ieee802_1x = param->value;
- break;
-
- case IW_AUTH_PRIVACY_INVOKED:
- ieee->privacy_invoked = param->value;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return ret;
-}
-
-/* SIOCGIWAUTH */
-static int ipw_wx_get_auth(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_device *ieee = priv->ieee;
- struct lib80211_crypt_data *crypt;
- struct iw_param *param = &wrqu->param;
-
- switch (param->flags & IW_AUTH_INDEX) {
- case IW_AUTH_WPA_VERSION:
- case IW_AUTH_CIPHER_PAIRWISE:
- case IW_AUTH_CIPHER_GROUP:
- case IW_AUTH_KEY_MGMT:
- /*
- * wpa_supplicant will control these internally
- */
- return -EOPNOTSUPP;
-
- case IW_AUTH_TKIP_COUNTERMEASURES:
- crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx];
- if (!crypt || !crypt->ops->get_flags)
- break;
-
- param->value = (crypt->ops->get_flags(crypt->priv) &
- IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0;
-
- break;
-
- case IW_AUTH_DROP_UNENCRYPTED:
- param->value = ieee->drop_unencrypted;
- break;
-
- case IW_AUTH_80211_AUTH_ALG:
- param->value = ieee->sec.auth_mode;
- break;
-
- case IW_AUTH_WPA_ENABLED:
- param->value = ieee->wpa_enabled;
- break;
-
- case IW_AUTH_RX_UNENCRYPTED_EAPOL:
- param->value = ieee->ieee802_1x;
- break;
-
- case IW_AUTH_ROAMING_CONTROL:
- case IW_AUTH_PRIVACY_INVOKED:
- param->value = ieee->privacy_invoked;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-/* SIOCSIWENCODEEXT */
-static int ipw_wx_set_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
-
- if (hwcrypto) {
- if (ext->alg == IW_ENCODE_ALG_TKIP) {
- /* IPW HW can't build TKIP MIC,
- host decryption still needed */
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY)
- priv->ieee->host_mc_decrypt = 1;
- else {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 1;
- priv->ieee->host_decrypt = 1;
- }
- } else {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 0;
- priv->ieee->host_decrypt = 0;
- priv->ieee->host_mc_decrypt = 0;
- }
- }
-
- return libipw_wx_set_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCGIWENCODEEXT */
-static int ipw_wx_get_encodeext(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encodeext(priv->ieee, info, wrqu, extra);
-}
-
-/* SIOCSIWMLME */
-static int ipw_wx_set_mlme(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_mlme *mlme = (struct iw_mlme *)extra;
-
- switch (mlme->cmd) {
- case IW_MLME_DEAUTH:
- /* silently ignore */
- break;
-
- case IW_MLME_DISASSOC:
- ipw_disassociate(priv);
- break;
-
- default:
- return -EOPNOTSUPP;
- }
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_QOS
-
-/* QoS */
-/*
-* get the modulation type of the current network or
-* the card current mode
-*/
-static u8 ipw_qos_current_mode(struct ipw_priv * priv)
-{
- u8 mode = 0;
-
- if (priv->status & STATUS_ASSOCIATED) {
- unsigned long flags;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- mode = priv->assoc_network->mode;
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
- } else {
- mode = priv->ieee->mode;
- }
- IPW_DEBUG_QOS("QoS network/card mode %d\n", mode);
- return mode;
-}
-
-/*
-* Handle management frame beacon and probe response
-*/
-static int ipw_qos_handle_probe_response(struct ipw_priv *priv,
- int active_network,
- struct libipw_network *network)
-{
- u32 size = sizeof(struct libipw_qos_parameters);
-
- if (network->capability & WLAN_CAPABILITY_IBSS)
- network->qos_data.active = network->qos_data.supported;
-
- if (network->flags & NETWORK_HAS_QOS_MASK) {
- if (active_network &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS))
- network->qos_data.active = network->qos_data.supported;
-
- if ((network->qos_data.active == 1) && (active_network == 1) &&
- (network->flags & NETWORK_HAS_QOS_PARAMETERS) &&
- (network->qos_data.old_param_count !=
- network->qos_data.param_count)) {
- network->qos_data.old_param_count =
- network->qos_data.param_count;
- schedule_work(&priv->qos_activate);
- IPW_DEBUG_QOS("QoS parameters change call "
- "qos_activate\n");
- }
- } else {
- if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B))
- memcpy(&network->qos_data.parameters,
- &def_parameters_CCK, size);
- else
- memcpy(&network->qos_data.parameters,
- &def_parameters_OFDM, size);
-
- if ((network->qos_data.active == 1) && (active_network == 1)) {
- IPW_DEBUG_QOS("QoS was disabled call qos_activate\n");
- schedule_work(&priv->qos_activate);
- }
-
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- }
- if ((priv->status & STATUS_ASSOCIATED) &&
- (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) {
- if (!ether_addr_equal(network->bssid, priv->bssid))
- if (network->capability & WLAN_CAPABILITY_IBSS)
- if ((network->ssid_len ==
- priv->assoc_network->ssid_len) &&
- !memcmp(network->ssid,
- priv->assoc_network->ssid,
- network->ssid_len)) {
- schedule_work(&priv->merge_networks);
- }
- }
-
- return 0;
-}
-
-/*
-* This function set up the firmware to support QoS. It sends
-* IPW_CMD_QOS_PARAMETERS and IPW_CMD_WME_INFO
-*/
-static int ipw_qos_activate(struct ipw_priv *priv,
- struct libipw_qos_data *qos_network_data)
-{
- int err;
- struct libipw_qos_parameters qos_parameters[QOS_QOS_SETS];
- struct libipw_qos_parameters *active_one = NULL;
- u32 size = sizeof(struct libipw_qos_parameters);
- u32 burst_duration;
- int i;
- u8 type;
-
- type = ipw_qos_current_mode(priv);
-
- active_one = &(qos_parameters[QOS_PARAM_SET_DEF_CCK]);
- memcpy(active_one, priv->qos_data.def_qos_parm_CCK, size);
- active_one = &(qos_parameters[QOS_PARAM_SET_DEF_OFDM]);
- memcpy(active_one, priv->qos_data.def_qos_parm_OFDM, size);
-
- if (qos_network_data == NULL) {
- if (type == IEEE_B) {
- IPW_DEBUG_QOS("QoS activate network mode %d\n", type);
- active_one = &def_parameters_CCK;
- } else
- active_one = &def_parameters_OFDM;
-
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- burst_duration = ipw_qos_get_burst_duration(priv);
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] =
- cpu_to_le16(burst_duration);
- } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (type == IEEE_B) {
- IPW_DEBUG_QOS("QoS activate IBSS network mode %d\n",
- type);
- if (priv->qos_data.qos_enable == 0)
- active_one = &def_parameters_CCK;
- else
- active_one = priv->qos_data.def_qos_parm_CCK;
- } else {
- if (priv->qos_data.qos_enable == 0)
- active_one = &def_parameters_OFDM;
- else
- active_one = priv->qos_data.def_qos_parm_OFDM;
- }
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- } else {
- unsigned long flags;
- int active;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- active_one = &(qos_network_data->parameters);
- qos_network_data->old_param_count =
- qos_network_data->param_count;
- memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size);
- active = qos_network_data->supported;
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (active == 0) {
- burst_duration = ipw_qos_get_burst_duration(priv);
- for (i = 0; i < QOS_QUEUE_NUM; i++)
- qos_parameters[QOS_PARAM_SET_ACTIVE].
- tx_op_limit[i] = cpu_to_le16(burst_duration);
- }
- }
-
- IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
- err = ipw_send_qos_params_command(priv, &qos_parameters[0]);
- if (err)
- IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n");
-
- return err;
-}
-
-/*
-* send IPW_CMD_WME_INFO to the firmware
-*/
-static int ipw_qos_set_info_element(struct ipw_priv *priv)
-{
- int ret = 0;
- struct libipw_qos_information_element qos_info;
-
- if (priv == NULL)
- return -1;
-
- qos_info.elementID = QOS_ELEMENT_ID;
- qos_info.length = sizeof(struct libipw_qos_information_element) - 2;
-
- qos_info.version = QOS_VERSION_1;
- qos_info.ac_info = 0;
-
- memcpy(qos_info.qui, qos_oui, QOS_OUI_LEN);
- qos_info.qui_type = QOS_OUI_TYPE;
- qos_info.qui_subtype = QOS_OUI_INFO_SUB_TYPE;
-
- ret = ipw_send_qos_info_command(priv, &qos_info);
- if (ret != 0) {
- IPW_DEBUG_QOS("QoS error calling ipw_send_qos_info_command\n");
- }
- return ret;
-}
-
-/*
-* Set the QoS parameter with the association request structure
-*/
-static int ipw_qos_association(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- int err = 0;
- struct libipw_qos_data *qos_data = NULL;
- struct libipw_qos_data ibss_data = {
- .supported = 1,
- .active = 1,
- };
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- BUG_ON(!(network->capability & WLAN_CAPABILITY_IBSS));
-
- qos_data = &ibss_data;
- break;
-
- case IW_MODE_INFRA:
- qos_data = &network->qos_data;
- break;
-
- default:
- BUG();
- break;
- }
-
- err = ipw_qos_activate(priv, qos_data);
- if (err) {
- priv->assoc_request.policy_support &= ~HC_QOS_SUPPORT_ASSOC;
- return err;
- }
-
- if (priv->qos_data.qos_enable && qos_data->supported) {
- IPW_DEBUG_QOS("QoS will be enabled for this association\n");
- priv->assoc_request.policy_support |= HC_QOS_SUPPORT_ASSOC;
- return ipw_qos_set_info_element(priv);
- }
-
- return 0;
-}
-
-/*
-* handling the beaconing responses. if we get different QoS setting
-* off the network from the associated setting, adjust the QoS
-* setting
-*/
-static void ipw_qos_association_resp(struct ipw_priv *priv,
- struct libipw_network *network)
-{
- unsigned long flags;
- u32 size = sizeof(struct libipw_qos_parameters);
- int set_qos_param = 0;
-
- if ((priv == NULL) || (network == NULL) ||
- (priv->assoc_network == NULL))
- return;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return;
-
- if ((priv->ieee->iw_mode != IW_MODE_INFRA))
- return;
-
- spin_lock_irqsave(&priv->ieee->lock, flags);
- if (network->flags & NETWORK_HAS_QOS_PARAMETERS) {
- memcpy(&priv->assoc_network->qos_data, &network->qos_data,
- sizeof(struct libipw_qos_data));
- priv->assoc_network->qos_data.active = 1;
- if ((network->qos_data.old_param_count !=
- network->qos_data.param_count)) {
- set_qos_param = 1;
- network->qos_data.old_param_count =
- network->qos_data.param_count;
- }
-
- } else {
- if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B))
- memcpy(&priv->assoc_network->qos_data.parameters,
- &def_parameters_CCK, size);
- else
- memcpy(&priv->assoc_network->qos_data.parameters,
- &def_parameters_OFDM, size);
- priv->assoc_network->qos_data.active = 0;
- priv->assoc_network->qos_data.supported = 0;
- set_qos_param = 1;
- }
-
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- if (set_qos_param == 1)
- schedule_work(&priv->qos_activate);
-}
-
-static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv)
-{
- u32 ret = 0;
-
- if (!priv)
- return 0;
-
- if (!(priv->ieee->modulation & LIBIPW_OFDM_MODULATION))
- ret = priv->qos_data.burst_duration_CCK;
- else
- ret = priv->qos_data.burst_duration_OFDM;
-
- return ret;
-}
-
-/*
-* Initialize the setting of QoS global
-*/
-static void ipw_qos_init(struct ipw_priv *priv, int enable,
- int burst_enable, u32 burst_duration_CCK,
- u32 burst_duration_OFDM)
-{
- priv->qos_data.qos_enable = enable;
-
- if (priv->qos_data.qos_enable) {
- priv->qos_data.def_qos_parm_CCK = &def_qos_parameters_CCK;
- priv->qos_data.def_qos_parm_OFDM = &def_qos_parameters_OFDM;
- IPW_DEBUG_QOS("QoS is enabled\n");
- } else {
- priv->qos_data.def_qos_parm_CCK = &def_parameters_CCK;
- priv->qos_data.def_qos_parm_OFDM = &def_parameters_OFDM;
- IPW_DEBUG_QOS("QoS is not enabled\n");
- }
-
- priv->qos_data.burst_enable = burst_enable;
-
- if (burst_enable) {
- priv->qos_data.burst_duration_CCK = burst_duration_CCK;
- priv->qos_data.burst_duration_OFDM = burst_duration_OFDM;
- } else {
- priv->qos_data.burst_duration_CCK = 0;
- priv->qos_data.burst_duration_OFDM = 0;
- }
-}
-
-/*
-* map the packet priority to the right TX Queue
-*/
-static int ipw_get_tx_queue_number(struct ipw_priv *priv, u16 priority)
-{
- if (priority > 7 || !priv->qos_data.qos_enable)
- priority = 0;
-
- return from_priority_to_tx_queue[priority] - 1;
-}
-
-static int ipw_is_qos_active(struct net_device *dev,
- struct sk_buff *skb)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct libipw_qos_data *qos_data = NULL;
- int active, supported;
- u8 *daddr = skb->data + ETH_ALEN;
- int unicast = !is_multicast_ether_addr(daddr);
-
- if (!(priv->status & STATUS_ASSOCIATED))
- return 0;
-
- qos_data = &priv->assoc_network->qos_data;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- if (unicast == 0)
- qos_data->active = 0;
- else
- qos_data->active = qos_data->supported;
- }
- active = qos_data->active;
- supported = qos_data->supported;
- IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d "
- "unicast %d\n",
- priv->qos_data.qos_enable, active, supported, unicast);
- if (active && priv->qos_data.qos_enable)
- return 1;
-
- return 0;
-
-}
-/*
-* add QoS parameter to the TX command
-*/
-static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
- u16 priority,
- struct tfd_data *tfd)
-{
- int tx_queue_id = 0;
-
-
- tx_queue_id = from_priority_to_tx_queue[priority] - 1;
- tfd->tx_flags_ext |= DCT_FLAG_EXT_QOS_ENABLED;
-
- if (priv->qos_data.qos_no_ack_mask & (1UL << tx_queue_id)) {
- tfd->tx_flags &= ~DCT_FLAG_ACK_REQD;
- tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK);
- }
- return 0;
-}
-
-/*
-* background support to run QoS activate functionality
-*/
-static void ipw_bg_qos_activate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, qos_activate);
-
- mutex_lock(&priv->mutex);
-
- if (priv->status & STATUS_ASSOCIATED)
- ipw_qos_activate(priv, &(priv->assoc_network->qos_data));
-
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_handle_probe_response(struct net_device *dev,
- struct libipw_probe_response *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int active_network = ((priv->status & STATUS_ASSOCIATED) &&
- (network == priv->assoc_network));
-
- ipw_qos_handle_probe_response(priv, active_network, network);
-
- return 0;
-}
-
-static int ipw_handle_beacon(struct net_device *dev,
- struct libipw_beacon *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int active_network = ((priv->status & STATUS_ASSOCIATED) &&
- (network == priv->assoc_network));
-
- ipw_qos_handle_probe_response(priv, active_network, network);
-
- return 0;
-}
-
-static int ipw_handle_assoc_response(struct net_device *dev,
- struct libipw_assoc_response *resp,
- struct libipw_network *network)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- ipw_qos_association_resp(priv, network);
- return 0;
-}
-
-static int ipw_send_qos_params_command(struct ipw_priv *priv, struct libipw_qos_parameters
- *qos_param)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS,
- sizeof(*qos_param) * 3, qos_param);
-}
-
-static int ipw_send_qos_info_command(struct ipw_priv *priv, struct libipw_qos_information_element
- *qos_param)
-{
- return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param),
- qos_param);
-}
-
-#endif /* CONFIG_IPW2200_QOS */
-
-static int ipw_associate_network(struct ipw_priv *priv,
- struct libipw_network *network,
- struct ipw_supported_rates *rates, int roaming)
-{
- int err;
-
- if (priv->config & CFG_FIXED_RATE)
- ipw_set_fixed_rate(priv, network->mode);
-
- if (!(priv->config & CFG_STATIC_ESSID)) {
- priv->essid_len = min(network->ssid_len,
- (u8) IW_ESSID_MAX_SIZE);
- memcpy(priv->essid, network->ssid, priv->essid_len);
- }
-
- network->last_associate = jiffies;
-
- memset(&priv->assoc_request, 0, sizeof(priv->assoc_request));
- priv->assoc_request.channel = network->channel;
- priv->assoc_request.auth_key = 0;
-
- if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) {
- priv->assoc_request.auth_type = AUTH_SHARED_KEY;
- priv->assoc_request.auth_key = priv->ieee->sec.active_key;
-
- if (priv->ieee->sec.level == SEC_LEVEL_1)
- ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP);
-
- } else if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP))
- priv->assoc_request.auth_type = AUTH_LEAP;
- else
- priv->assoc_request.auth_type = AUTH_OPEN;
-
- if (priv->ieee->wpa_ie_len) {
- priv->assoc_request.policy_support = cpu_to_le16(0x02); /* RSN active */
- ipw_set_rsn_capa(priv, priv->ieee->wpa_ie,
- priv->ieee->wpa_ie_len);
- }
-
- /*
- * It is valid for our ieee device to support multiple modes, but
- * when it comes to associating to a given network we have to choose
- * just one mode.
- */
- if (network->mode & priv->ieee->mode & IEEE_A)
- priv->assoc_request.ieee_mode = IPW_A_MODE;
- else if (network->mode & priv->ieee->mode & IEEE_G)
- priv->assoc_request.ieee_mode = IPW_G_MODE;
- else if (network->mode & priv->ieee->mode & IEEE_B)
- priv->assoc_request.ieee_mode = IPW_B_MODE;
-
- priv->assoc_request.capability = cpu_to_le16(network->capability);
- if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
- && !(priv->config & CFG_PREAMBLE_LONG)) {
- priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE;
- } else {
- priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE;
-
- /* Clear the short preamble if we won't be supporting it */
- priv->assoc_request.capability &=
- ~cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE);
- }
-
- /* Clear capability bits that aren't used in Ad Hoc */
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->assoc_request.capability &=
- ~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
-
- IPW_DEBUG_ASSOC("%ssociation attempt: '%*pE', channel %d, 802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
- roaming ? "Rea" : "A",
- priv->essid_len, priv->essid,
- network->channel,
- ipw_modes[priv->assoc_request.ieee_mode],
- rates->num_rates,
- (priv->assoc_request.preamble_length ==
- DCT_FLAG_LONG_PREAMBLE) ? "long" : "short",
- network->capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long",
- priv->capability & CAP_PRIVACY_ON ? "on " : "off",
- priv->capability & CAP_PRIVACY_ON ?
- (priv->capability & CAP_SHARED_KEY ? "(shared)" :
- "(open)") : "",
- priv->capability & CAP_PRIVACY_ON ? " key=" : "",
- priv->capability & CAP_PRIVACY_ON ?
- '1' + priv->ieee->sec.active_key : '.',
- priv->capability & CAP_PRIVACY_ON ? '.' : ' ');
-
- priv->assoc_request.beacon_interval = cpu_to_le16(network->beacon_interval);
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (network->time_stamp[0] == 0) && (network->time_stamp[1] == 0)) {
- priv->assoc_request.assoc_type = HC_IBSS_START;
- priv->assoc_request.assoc_tsf_msw = 0;
- priv->assoc_request.assoc_tsf_lsw = 0;
- } else {
- if (unlikely(roaming))
- priv->assoc_request.assoc_type = HC_REASSOCIATE;
- else
- priv->assoc_request.assoc_type = HC_ASSOCIATE;
- priv->assoc_request.assoc_tsf_msw = cpu_to_le32(network->time_stamp[1]);
- priv->assoc_request.assoc_tsf_lsw = cpu_to_le32(network->time_stamp[0]);
- }
-
- memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN);
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- eth_broadcast_addr(priv->assoc_request.dest);
- priv->assoc_request.atim_window = cpu_to_le16(network->atim_window);
- } else {
- memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN);
- priv->assoc_request.atim_window = 0;
- }
-
- priv->assoc_request.listen_interval = cpu_to_le16(network->listen_interval);
-
- err = ipw_send_ssid(priv, priv->essid, priv->essid_len);
- if (err) {
- IPW_DEBUG_HC("Attempt to send SSID command failed.\n");
- return err;
- }
-
- rates->ieee_mode = priv->assoc_request.ieee_mode;
- rates->purpose = IPW_RATE_CONNECT;
- ipw_send_supported_rates(priv, rates);
-
- if (priv->assoc_request.ieee_mode == IPW_G_MODE)
- priv->sys_config.dot11g_auto_detection = 1;
- else
- priv->sys_config.dot11g_auto_detection = 0;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->sys_config.answer_broadcast_ssid_probe = 1;
- else
- priv->sys_config.answer_broadcast_ssid_probe = 0;
-
- err = ipw_send_system_config(priv);
- if (err) {
- IPW_DEBUG_HC("Attempt to send sys config command failed.\n");
- return err;
- }
-
- IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi);
- err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM);
- if (err) {
- IPW_DEBUG_HC("Attempt to send associate command failed.\n");
- return err;
- }
-
- /*
- * If preemption is enabled, it is possible for the association
- * to complete before we return from ipw_send_associate. Therefore
- * we have to be sure and update our priviate data first.
- */
- priv->channel = network->channel;
- memcpy(priv->bssid, network->bssid, ETH_ALEN);
- priv->status |= STATUS_ASSOCIATING;
- priv->status &= ~STATUS_SECURITY_UPDATED;
-
- priv->assoc_network = network;
-
-#ifdef CONFIG_IPW2200_QOS
- ipw_qos_association(priv, network);
-#endif
-
- err = ipw_send_associate(priv, &priv->assoc_request);
- if (err) {
- IPW_DEBUG_HC("Attempt to send associate command failed.\n");
- return err;
- }
-
- IPW_DEBUG(IPW_DL_STATE, "associating: '%*pE' %pM\n",
- priv->essid_len, priv->essid, priv->bssid);
-
- return 0;
-}
-
-static void ipw_roam(void *data)
-{
- struct ipw_priv *priv = data;
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = priv->assoc_network
- };
-
- /* The roaming process is as follows:
- *
- * 1. Missed beacon threshold triggers the roaming process by
- * setting the status ROAM bit and requesting a scan.
- * 2. When the scan completes, it schedules the ROAM work
- * 3. The ROAM work looks at all of the known networks for one that
- * is a better network than the currently associated. If none
- * found, the ROAM process is over (ROAM bit cleared)
- * 4. If a better network is found, a disassociation request is
- * sent.
- * 5. When the disassociation completes, the roam work is again
- * scheduled. The second time through, the driver is no longer
- * associated, and the newly selected network is sent an
- * association request.
- * 6. At this point ,the roaming process is complete and the ROAM
- * status bit is cleared.
- */
-
- /* If we are no longer associated, and the roaming bit is no longer
- * set, then we are not actively roaming, so just return */
- if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ROAMING)))
- return;
-
- if (priv->status & STATUS_ASSOCIATED) {
- /* First pass through ROAM process -- look for a better
- * network */
- unsigned long flags;
- u8 rssi = priv->assoc_network->stats.rssi;
- priv->assoc_network->stats.rssi = -128;
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list) {
- if (network != priv->assoc_network)
- ipw_best_network(priv, &match, network, 1);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
- priv->assoc_network->stats.rssi = rssi;
-
- if (match.network == priv->assoc_network) {
- IPW_DEBUG_ASSOC("No better APs in this network to "
- "roam to.\n");
- priv->status &= ~STATUS_ROAMING;
- ipw_debug_config(priv);
- return;
- }
-
- ipw_send_disassociate(priv, 1);
- priv->assoc_network = match.network;
-
- return;
- }
-
- /* Second pass through ROAM process -- request association */
- ipw_compatible_rates(priv, priv->assoc_network, &match.rates);
- ipw_associate_network(priv, priv->assoc_network, &match.rates, 1);
- priv->status &= ~STATUS_ROAMING;
-}
-
-static void ipw_bg_roam(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, roam);
- mutex_lock(&priv->mutex);
- ipw_roam(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_associate(void *data)
-{
- struct ipw_priv *priv = data;
-
- struct libipw_network *network = NULL;
- struct ipw_network_match match = {
- .network = NULL
- };
- struct ipw_supported_rates *rates;
- struct list_head *element;
- unsigned long flags;
-
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n");
- return 0;
- }
-
- if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_ASSOC("Not attempting association (already in "
- "progress)\n");
- return 0;
- }
-
- if (priv->status & STATUS_DISASSOCIATING) {
- IPW_DEBUG_ASSOC("Not attempting association (in disassociating)\n");
- schedule_work(&priv->associate);
- return 0;
- }
-
- if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) {
- IPW_DEBUG_ASSOC("Not attempting association (scanning or not "
- "initialized)\n");
- return 0;
- }
-
- if (!(priv->config & CFG_ASSOCIATE) &&
- !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) {
- IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n");
- return 0;
- }
-
- /* Protect our use of the network_list */
- spin_lock_irqsave(&priv->ieee->lock, flags);
- list_for_each_entry(network, &priv->ieee->network_list, list)
- ipw_best_network(priv, &match, network, 0);
-
- network = match.network;
- rates = &match.rates;
-
- if (network == NULL &&
- priv->ieee->iw_mode == IW_MODE_ADHOC &&
- priv->config & CFG_ADHOC_CREATE &&
- priv->config & CFG_STATIC_ESSID &&
- priv->config & CFG_STATIC_CHANNEL) {
- /* Use oldest network if the free list is empty */
- if (list_empty(&priv->ieee->network_free_list)) {
- struct libipw_network *oldest = NULL;
- struct libipw_network *target;
-
- list_for_each_entry(target, &priv->ieee->network_list, list) {
- if ((oldest == NULL) ||
- (target->last_scanned < oldest->last_scanned))
- oldest = target;
- }
-
- /* If there are no more slots, expire the oldest */
- list_del(&oldest->list);
- target = oldest;
- IPW_DEBUG_ASSOC("Expired '%*pE' (%pM) from network list.\n",
- target->ssid_len, target->ssid,
- target->bssid);
- list_add_tail(&target->list,
- &priv->ieee->network_free_list);
- }
-
- element = priv->ieee->network_free_list.next;
- network = list_entry(element, struct libipw_network, list);
- ipw_adhoc_create(priv, network);
- rates = &priv->rates;
- list_del(element);
- list_add_tail(&network->list, &priv->ieee->network_list);
- }
- spin_unlock_irqrestore(&priv->ieee->lock, flags);
-
- /* If we reached the end of the list, then we don't have any valid
- * matching APs */
- if (!network) {
- ipw_debug_config(priv);
-
- if (!(priv->status & STATUS_SCANNING)) {
- if (!(priv->config & CFG_SPEED_SCAN))
- schedule_delayed_work(&priv->request_scan,
- SCAN_INTERVAL);
- else
- schedule_delayed_work(&priv->request_scan, 0);
- }
-
- return 0;
- }
-
- ipw_associate_network(priv, network, rates, 0);
-
- return 1;
-}
-
-static void ipw_bg_associate(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, associate);
- mutex_lock(&priv->mutex);
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv,
- struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- u16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = le16_to_cpu(hdr->frame_control);
- if (!(fc & IEEE80211_FCTL_PROTECTED))
- return;
-
- fc &= ~IEEE80211_FCTL_PROTECTED;
- hdr->frame_control = cpu_to_le16(fc);
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- /* Remove CCMP HDR */
- memmove(skb->data + LIBIPW_3ADDR_LEN,
- skb->data + LIBIPW_3ADDR_LEN + 8,
- skb->len - LIBIPW_3ADDR_LEN - 8);
- skb_trim(skb, skb->len - 16); /* CCMP_HDR_LEN + CCMP_MIC_LEN */
- break;
- case SEC_LEVEL_2:
- break;
- case SEC_LEVEL_1:
- /* Remove IV */
- memmove(skb->data + LIBIPW_3ADDR_LEN,
- skb->data + LIBIPW_3ADDR_LEN + 4,
- skb->len - LIBIPW_3ADDR_LEN - 4);
- skb_trim(skb, skb->len - 8); /* IV + ICV */
- break;
- case SEC_LEVEL_0:
- break;
- default:
- printk(KERN_ERR "Unknown security level %d\n",
- priv->ieee->sec.level);
- break;
- }
-}
-
-static void ipw_handle_data_packet(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct libipw_hdr_4addr *hdr;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- /* We only process data packets if the
- * interface is open */
- if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
- skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- } else if (unlikely(!netif_running(priv->net_dev))) {
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Advance skb->data to the start of the actual payload */
- skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data));
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length));
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
- /* HW decrypt will not clear the WEP bit, MIC, PN, etc. */
- hdr = (struct libipw_hdr_4addr *)rxb->skb->data;
- if (priv->ieee->iw_mode != IW_MODE_MONITOR &&
- (is_multicast_ether_addr(hdr->addr1) ?
- !priv->ieee->host_mc_decrypt : !priv->ieee->host_decrypt))
- ipw_rebuild_decrypted_skb(priv, rxb->skb);
-
- if (!libipw_rx(priv->ieee, rxb->skb, stats))
- dev->stats.rx_errors++;
- else { /* libipw_rx succeeded, so it now owns the SKB */
- rxb->skb = NULL;
- __ipw_led_activity_on(priv);
- }
-}
-
-#ifdef CONFIG_IPW2200_RADIOTAP
-static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->net_dev;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
- struct ipw_rx_frame *frame = &pkt->u.frame;
-
- /* initial pull of some data */
- u16 received_channel = frame->received_channel;
- u8 antennaAndPhy = frame->antennaAndPhy;
- s8 antsignal = frame->rssi_dbm - IPW_RSSI_TO_DBM; /* call it signed anyhow */
- u16 pktrate = frame->rate;
-
- /* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE */
- struct ipw_rt_hdr *ipw_rt;
-
- unsigned short len = le16_to_cpu(pkt->u.frame.length);
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- /* We only process data packets if the
- * interface is open */
- if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
- skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- } else if (unlikely(!netif_running(priv->net_dev))) {
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
- * that now */
- if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
- /* FIXME: Should alloc bigger skb instead */
- dev->stats.rx_dropped++;
- priv->wstats.discard.misc++;
- IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- /* copy the frame itself */
- memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr),
- rxb->skb->data + IPW_RX_FRAME_SIZE, len);
-
- ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data;
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(struct ipw_rt_hdr)); /* total header+data */
-
- /* Big bitfield of all the fields we provide in radiotap */
- ipw_rt->rt_hdr.it_present = cpu_to_le32(
- (1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA));
-
- /* Zero the flags, we'll add to them as we go */
- ipw_rt->rt_flags = 0;
- ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
- frame->parent_tsf[2] << 16 |
- frame->parent_tsf[1] << 8 |
- frame->parent_tsf[0]);
-
- /* Convert signal to DBM */
- ipw_rt->rt_dbmsignal = antsignal;
- ipw_rt->rt_dbmnoise = (s8) le16_to_cpu(frame->noise);
-
- /* Convert the channel data and set the flags */
- ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(received_channel));
- if (received_channel > 14) { /* 802.11a */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- } else if (antennaAndPhy & 32) { /* 802.11b */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- } else { /* 802.11g */
- ipw_rt->rt_chbitmask =
- cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
- }
-
- /* set the rate in multiples of 500k/s */
- switch (pktrate) {
- case IPW_TX_RATE_1MB:
- ipw_rt->rt_rate = 2;
- break;
- case IPW_TX_RATE_2MB:
- ipw_rt->rt_rate = 4;
- break;
- case IPW_TX_RATE_5MB:
- ipw_rt->rt_rate = 10;
- break;
- case IPW_TX_RATE_6MB:
- ipw_rt->rt_rate = 12;
- break;
- case IPW_TX_RATE_9MB:
- ipw_rt->rt_rate = 18;
- break;
- case IPW_TX_RATE_11MB:
- ipw_rt->rt_rate = 22;
- break;
- case IPW_TX_RATE_12MB:
- ipw_rt->rt_rate = 24;
- break;
- case IPW_TX_RATE_18MB:
- ipw_rt->rt_rate = 36;
- break;
- case IPW_TX_RATE_24MB:
- ipw_rt->rt_rate = 48;
- break;
- case IPW_TX_RATE_36MB:
- ipw_rt->rt_rate = 72;
- break;
- case IPW_TX_RATE_48MB:
- ipw_rt->rt_rate = 96;
- break;
- case IPW_TX_RATE_54MB:
- ipw_rt->rt_rate = 108;
- break;
- default:
- ipw_rt->rt_rate = 0;
- break;
- }
-
- /* antenna number */
- ipw_rt->rt_antenna = (antennaAndPhy & 3); /* Is this right? */
-
- /* set the preamble flag if we have it */
- if ((antennaAndPhy & 64))
- ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
- /* Set the size of the skb to the size of the frame */
- skb_put(rxb->skb, len + sizeof(struct ipw_rt_hdr));
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
-
- if (!libipw_rx(priv->ieee, rxb->skb, stats))
- dev->stats.rx_errors++;
- else { /* libipw_rx succeeded, so it now owns the SKB */
- rxb->skb = NULL;
- /* no LED during capture */
- }
-}
-#endif
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-#define libipw_is_probe_response(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && \
- (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP )
-
-#define libipw_is_management(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
-
-#define libipw_is_control(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
-
-#define libipw_is_data(fc) \
- ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
-
-#define libipw_is_assoc_request(fc) \
- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ)
-
-#define libipw_is_reassoc_request(fc) \
- ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
-
-static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct net_device *dev = priv->prom_net_dev;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
- struct ipw_rx_frame *frame = &pkt->u.frame;
- struct ipw_rt_hdr *ipw_rt;
-
- /* First cache any information we need before we overwrite
- * the information provided in the skb from the hardware */
- struct ieee80211_hdr *hdr;
- u16 channel = frame->received_channel;
- u8 phy_flags = frame->antennaAndPhy;
- s8 signal = frame->rssi_dbm - IPW_RSSI_TO_DBM;
- s8 noise = (s8) le16_to_cpu(frame->noise);
- u8 rate = frame->rate;
- unsigned short len = le16_to_cpu(pkt->u.frame.length);
- struct sk_buff *skb;
- int hdr_only = 0;
- u16 filter = priv->prom_priv->filter;
-
- /* If the filter is set to not include Rx frames then return */
- if (filter & IPW_PROM_NO_RX)
- return;
-
- /* We received data from the HW, so stop the watchdog */
- netif_trans_update(dev);
-
- if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
- dev->stats.rx_errors++;
- IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
- return;
- }
-
- /* We only process data packets if the interface is open */
- if (unlikely(!netif_running(dev))) {
- dev->stats.rx_dropped++;
- IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
- return;
- }
-
- /* Libpcap 0.9.3+ can handle variable length radiotap, so we'll use
- * that now */
- if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
- /* FIXME: Should alloc bigger skb instead */
- dev->stats.rx_dropped++;
- IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
- return;
- }
-
- hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
- if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_MGMT)
- return;
- if (filter & IPW_PROM_MGMT_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_CTL)
- return;
- if (filter & IPW_PROM_CTL_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_DATA)
- return;
- if (filter & IPW_PROM_DATA_HEADER_ONLY)
- hdr_only = 1;
- }
-
- /* Copy the SKB since this is for the promiscuous side */
- skb = skb_copy(rxb->skb, GFP_ATOMIC);
- if (skb == NULL) {
- IPW_ERROR("skb_clone failed for promiscuous copy.\n");
- return;
- }
-
- /* copy the frame data to write after where the radiotap header goes */
- ipw_rt = (void *)skb->data;
-
- if (hdr_only)
- len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
-
- memcpy(ipw_rt->payload, hdr, len);
-
- ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
- ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */
- ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */
-
- /* Set the size of the skb to the size of the frame */
- skb_put(skb, sizeof(*ipw_rt) + len);
-
- /* Big bitfield of all the fields we provide in radiotap */
- ipw_rt->rt_hdr.it_present = cpu_to_le32(
- (1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA));
-
- /* Zero the flags, we'll add to them as we go */
- ipw_rt->rt_flags = 0;
- ipw_rt->rt_tsf = (u64)(frame->parent_tsf[3] << 24 |
- frame->parent_tsf[2] << 16 |
- frame->parent_tsf[1] << 8 |
- frame->parent_tsf[0]);
-
- /* Convert to DBM */
- ipw_rt->rt_dbmsignal = signal;
- ipw_rt->rt_dbmnoise = noise;
-
- /* Convert the channel data and set the flags */
- ipw_rt->rt_channel = cpu_to_le16(ieee80211chan2mhz(channel));
- if (channel > 14) { /* 802.11a */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
- } else if (phy_flags & (1 << 5)) { /* 802.11b */
- ipw_rt->rt_chbitmask =
- cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
- } else { /* 802.11g */
- ipw_rt->rt_chbitmask =
- cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ);
- }
-
- /* set the rate in multiples of 500k/s */
- switch (rate) {
- case IPW_TX_RATE_1MB:
- ipw_rt->rt_rate = 2;
- break;
- case IPW_TX_RATE_2MB:
- ipw_rt->rt_rate = 4;
- break;
- case IPW_TX_RATE_5MB:
- ipw_rt->rt_rate = 10;
- break;
- case IPW_TX_RATE_6MB:
- ipw_rt->rt_rate = 12;
- break;
- case IPW_TX_RATE_9MB:
- ipw_rt->rt_rate = 18;
- break;
- case IPW_TX_RATE_11MB:
- ipw_rt->rt_rate = 22;
- break;
- case IPW_TX_RATE_12MB:
- ipw_rt->rt_rate = 24;
- break;
- case IPW_TX_RATE_18MB:
- ipw_rt->rt_rate = 36;
- break;
- case IPW_TX_RATE_24MB:
- ipw_rt->rt_rate = 48;
- break;
- case IPW_TX_RATE_36MB:
- ipw_rt->rt_rate = 72;
- break;
- case IPW_TX_RATE_48MB:
- ipw_rt->rt_rate = 96;
- break;
- case IPW_TX_RATE_54MB:
- ipw_rt->rt_rate = 108;
- break;
- default:
- ipw_rt->rt_rate = 0;
- break;
- }
-
- /* antenna number */
- ipw_rt->rt_antenna = (phy_flags & 3);
-
- /* set the preamble flag if we have it */
- if (phy_flags & (1 << 6))
- ipw_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
-
- IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len);
-
- if (!libipw_rx(priv->prom_priv->ieee, skb, stats)) {
- dev->stats.rx_errors++;
- dev_kfree_skb_any(skb);
- }
-}
-#endif
-
-static int is_network_packet(struct ipw_priv *priv,
- struct libipw_hdr_4addr *header)
-{
- /* Filter incoming packets to determine if they are targeted toward
- * this network, discarding packets coming from ourselves */
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */
- /* packets from our adapter are dropped (echo) */
- if (ether_addr_equal(header->addr2, priv->net_dev->dev_addr))
- return 0;
-
- /* {broad,multi}cast packets to our BSSID go through */
- if (is_multicast_ether_addr(header->addr1))
- return ether_addr_equal(header->addr3, priv->bssid);
-
- /* packets to our adapter go through */
- return ether_addr_equal(header->addr1,
- priv->net_dev->dev_addr);
-
- case IW_MODE_INFRA: /* Header: Dest. | BSSID | Source */
- /* packets from our adapter are dropped (echo) */
- if (ether_addr_equal(header->addr3, priv->net_dev->dev_addr))
- return 0;
-
- /* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(header->addr1))
- return ether_addr_equal(header->addr2, priv->bssid);
-
- /* packets to our adapter go through */
- return ether_addr_equal(header->addr1,
- priv->net_dev->dev_addr);
- }
-
- return 1;
-}
-
-#define IPW_PACKET_RETRY_TIME HZ
-
-static int is_duplicate_packet(struct ipw_priv *priv,
- struct libipw_hdr_4addr *header)
-{
- u16 sc = le16_to_cpu(header->seq_ctl);
- u16 seq = WLAN_GET_SEQ_SEQ(sc);
- u16 frag = WLAN_GET_SEQ_FRAG(sc);
- u16 *last_seq, *last_frag;
- unsigned long *last_time;
-
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- {
- struct list_head *p;
- struct ipw_ibss_seq *entry = NULL;
- u8 *mac = header->addr2;
- int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE;
-
- list_for_each(p, &priv->ibss_mac_hash[index]) {
- entry =
- list_entry(p, struct ipw_ibss_seq, list);
- if (ether_addr_equal(entry->mac, mac))
- break;
- }
- if (p == &priv->ibss_mac_hash[index]) {
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry) {
- IPW_ERROR
- ("Cannot malloc new mac entry\n");
- return 0;
- }
- memcpy(entry->mac, mac, ETH_ALEN);
- entry->seq_num = seq;
- entry->frag_num = frag;
- entry->packet_time = jiffies;
- list_add(&entry->list,
- &priv->ibss_mac_hash[index]);
- return 0;
- }
- last_seq = &entry->seq_num;
- last_frag = &entry->frag_num;
- last_time = &entry->packet_time;
- break;
- }
- case IW_MODE_INFRA:
- last_seq = &priv->last_seq_num;
- last_frag = &priv->last_frag_num;
- last_time = &priv->last_packet_time;
- break;
- default:
- return 0;
- }
- if ((*last_seq == seq) &&
- time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) {
- if (*last_frag == frag)
- goto drop;
- if (*last_frag + 1 != frag)
- /* out-of-order fragment */
- goto drop;
- } else
- *last_seq = seq;
-
- *last_frag = frag;
- *last_time = jiffies;
- return 0;
-
- drop:
- /* Comment this line now since we observed the card receives
- * duplicate packets but the FCTL_RETRY bit is not set in the
- * IBSS mode with fragmentation enabled.
- BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */
- return 1;
-}
-
-static void ipw_handle_mgmt_packet(struct ipw_priv *priv,
- struct ipw_rx_mem_buffer *rxb,
- struct libipw_rx_stats *stats)
-{
- struct sk_buff *skb = rxb->skb;
- struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)skb->data;
- struct libipw_hdr_4addr *header = (struct libipw_hdr_4addr *)
- (skb->data + IPW_RX_FRAME_SIZE);
-
- libipw_rx_mgt(priv->ieee, header, stats);
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC &&
- ((WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
- IEEE80211_STYPE_PROBE_RESP) ||
- (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl)) ==
- IEEE80211_STYPE_BEACON))) {
- if (ether_addr_equal(header->addr3, priv->bssid))
- ipw_add_station(priv, header->addr2);
- }
-
- if (priv->config & CFG_NET_STATS) {
- IPW_DEBUG_HC("sending stat packet\n");
-
- /* Set the size of the skb to the size of the full
- * ipw header and 802.11 frame */
- skb_put(skb, le16_to_cpu(pkt->u.frame.length) +
- IPW_RX_FRAME_SIZE);
-
- /* Advance past the ipw packet header to the 802.11 frame */
- skb_pull(skb, IPW_RX_FRAME_SIZE);
-
- /* Push the libipw_rx_stats before the 802.11 frame */
- memcpy(skb_push(skb, sizeof(*stats)), stats, sizeof(*stats));
-
- skb->dev = priv->ieee->dev;
-
- /* Point raw at the libipw_stats */
- skb_reset_mac_header(skb);
-
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = cpu_to_be16(ETH_P_80211_STATS);
- memset(skb->cb, 0, sizeof(rxb->skb->cb));
- netif_rx(skb);
- rxb->skb = NULL;
- }
-}
-
-/*
- * Main entry function for receiving a packet with 80211 headers. This
- * should be called when ever the FW has notified us that there is a new
- * skb in the receive queue.
- */
-static void ipw_rx(struct ipw_priv *priv)
-{
- struct ipw_rx_mem_buffer *rxb;
- struct ipw_rx_packet *pkt;
- struct libipw_hdr_4addr *header;
- u32 r, i;
- u8 network_packet;
- u8 fill_rx = 0;
-
- r = ipw_read32(priv, IPW_RX_READ_INDEX);
- ipw_read32(priv, IPW_RX_WRITE_INDEX);
- i = priv->rxq->read;
-
- if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2))
- fill_rx = 1;
-
- while (i != r) {
- rxb = priv->rxq->queue[i];
- if (unlikely(rxb == NULL)) {
- printk(KERN_CRIT "Queue not allocated!\n");
- break;
- }
- priv->rxq->queue[i] = NULL;
-
- dma_sync_single_for_cpu(&priv->pci_dev->dev, rxb->dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
-
- pkt = (struct ipw_rx_packet *)rxb->skb->data;
- IPW_DEBUG_RX("Packet: type=%02X seq=%02X bits=%02X\n",
- pkt->header.message_type,
- pkt->header.rx_seq_num, pkt->header.control_bits);
-
- switch (pkt->header.message_type) {
- case RX_FRAME_TYPE: /* 802.11 frame */ {
- struct libipw_rx_stats stats = {
- .rssi = pkt->u.frame.rssi_dbm -
- IPW_RSSI_TO_DBM,
- .signal =
- pkt->u.frame.rssi_dbm -
- IPW_RSSI_TO_DBM + 0x100,
- .noise =
- le16_to_cpu(pkt->u.frame.noise),
- .rate = pkt->u.frame.rate,
- .mac_time = jiffies,
- .received_channel =
- pkt->u.frame.received_channel,
- .freq =
- (pkt->u.frame.
- control & (1 << 0)) ?
- LIBIPW_24GHZ_BAND :
- LIBIPW_52GHZ_BAND,
- .len = le16_to_cpu(pkt->u.frame.length),
- };
-
- if (stats.rssi != 0)
- stats.mask |= LIBIPW_STATMASK_RSSI;
- if (stats.signal != 0)
- stats.mask |= LIBIPW_STATMASK_SIGNAL;
- if (stats.noise != 0)
- stats.mask |= LIBIPW_STATMASK_NOISE;
- if (stats.rate != 0)
- stats.mask |= LIBIPW_STATMASK_RATE;
-
- priv->rx_packets++;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev))
- ipw_handle_promiscuous_rx(priv, rxb, &stats);
-#endif
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
-#ifdef CONFIG_IPW2200_RADIOTAP
-
- ipw_handle_data_packet_monitor(priv,
- rxb,
- &stats);
-#else
- ipw_handle_data_packet(priv, rxb,
- &stats);
-#endif
- break;
- }
-#endif
-
- header =
- (struct libipw_hdr_4addr *)(rxb->skb->
- data +
- IPW_RX_FRAME_SIZE);
- /* TODO: Check Ad-Hoc dest/source and make sure
- * that we are actually parsing these packets
- * correctly -- we should probably use the
- * frame control of the packet and disregard
- * the current iw_mode */
-
- network_packet =
- is_network_packet(priv, header);
- if (network_packet && priv->assoc_network) {
- priv->assoc_network->stats.rssi =
- stats.rssi;
- priv->exp_avg_rssi =
- exponential_average(priv->exp_avg_rssi,
- stats.rssi, DEPTH_RSSI);
- }
-
- IPW_DEBUG_RX("Frame: len=%u\n",
- le16_to_cpu(pkt->u.frame.length));
-
- if (le16_to_cpu(pkt->u.frame.length) <
- libipw_get_hdrlen(le16_to_cpu(
- header->frame_ctl))) {
- IPW_DEBUG_DROP
- ("Received packet is too small. "
- "Dropping.\n");
- priv->net_dev->stats.rx_errors++;
- priv->wstats.discard.misc++;
- break;
- }
-
- switch (WLAN_FC_GET_TYPE
- (le16_to_cpu(header->frame_ctl))) {
-
- case IEEE80211_FTYPE_MGMT:
- ipw_handle_mgmt_packet(priv, rxb,
- &stats);
- break;
-
- case IEEE80211_FTYPE_CTL:
- break;
-
- case IEEE80211_FTYPE_DATA:
- if (unlikely(!network_packet ||
- is_duplicate_packet(priv,
- header)))
- {
- IPW_DEBUG_DROP("Dropping: "
- "%pM, "
- "%pM, "
- "%pM\n",
- header->addr1,
- header->addr2,
- header->addr3);
- break;
- }
-
- ipw_handle_data_packet(priv, rxb,
- &stats);
-
- break;
- }
- break;
- }
-
- case RX_HOST_NOTIFICATION_TYPE:{
- IPW_DEBUG_RX
- ("Notification: subtype=%02X flags=%02X size=%d\n",
- pkt->u.notification.subtype,
- pkt->u.notification.flags,
- le16_to_cpu(pkt->u.notification.size));
- ipw_rx_notification(priv, &pkt->u.notification);
- break;
- }
-
- default:
- IPW_DEBUG_RX("Bad Rx packet of type %d\n",
- pkt->header.message_type);
- break;
- }
-
- /* For now we just don't re-use anything. We can tweak this
- * later to try and re-use notification packets and SKBs that
- * fail to Rx correctly */
- if (rxb->skb != NULL) {
- dev_kfree_skb_any(rxb->skb);
- rxb->skb = NULL;
- }
-
- dma_unmap_single(&priv->pci_dev->dev, rxb->dma_addr,
- IPW_RX_BUF_SIZE, DMA_FROM_DEVICE);
- list_add_tail(&rxb->list, &priv->rxq->rx_used);
-
- i = (i + 1) % RX_QUEUE_SIZE;
-
- /* If there are a lot of unsued frames, restock the Rx queue
- * so the ucode won't assert */
- if (fill_rx) {
- priv->rxq->read = i;
- ipw_rx_queue_replenish(priv);
- }
- }
-
- /* Backtrack one entry */
- priv->rxq->read = i;
- ipw_rx_queue_restock(priv);
-}
-
-#define DEFAULT_RTS_THRESHOLD 2304U
-#define MIN_RTS_THRESHOLD 1U
-#define MAX_RTS_THRESHOLD 2304U
-#define DEFAULT_BEACON_INTERVAL 100U
-#define DEFAULT_SHORT_RETRY_LIMIT 7U
-#define DEFAULT_LONG_RETRY_LIMIT 4U
-
-/*
- * ipw_sw_reset
- * @option: options to control different reset behaviour
- * 0 = reset everything except the 'disable' module_param
- * 1 = reset everything and print out driver info (for probe only)
- * 2 = reset everything
- */
-static int ipw_sw_reset(struct ipw_priv *priv, int option)
-{
- int band, modulation;
- int old_mode = priv->ieee->iw_mode;
-
- /* Initialize module parameter values here */
- priv->config = 0;
-
- /* We default to disabling the LED code as right now it causes
- * too many systems to lock up... */
- if (!led_support)
- priv->config |= CFG_NO_LED;
-
- if (associate)
- priv->config |= CFG_ASSOCIATE;
- else
- IPW_DEBUG_INFO("Auto associate disabled.\n");
-
- if (auto_create)
- priv->config |= CFG_ADHOC_CREATE;
- else
- IPW_DEBUG_INFO("Auto adhoc creation disabled.\n");
-
- priv->config &= ~CFG_STATIC_ESSID;
- priv->essid_len = 0;
- memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
-
- if (disable && option) {
- priv->status |= STATUS_RF_KILL_SW;
- IPW_DEBUG_INFO("Radio disabled.\n");
- }
-
- if (default_channel != 0) {
- priv->config |= CFG_STATIC_CHANNEL;
- priv->channel = default_channel;
- IPW_DEBUG_INFO("Bind to static channel %d\n", default_channel);
- /* TODO: Validate that provided channel is in range */
- }
-#ifdef CONFIG_IPW2200_QOS
- ipw_qos_init(priv, qos_enable, qos_burst_enable,
- burst_duration_CCK, burst_duration_OFDM);
-#endif /* CONFIG_IPW2200_QOS */
-
- switch (network_mode) {
- case 1:
- priv->ieee->iw_mode = IW_MODE_ADHOC;
- priv->net_dev->type = ARPHRD_ETHER;
-
- break;
-#ifdef CONFIG_IPW2200_MONITOR
- case 2:
- priv->ieee->iw_mode = IW_MODE_MONITOR;
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
- break;
-#endif
- default:
- case 0:
- priv->net_dev->type = ARPHRD_ETHER;
- priv->ieee->iw_mode = IW_MODE_INFRA;
- break;
- }
-
- if (hwcrypto) {
- priv->ieee->host_encrypt = 0;
- priv->ieee->host_encrypt_msdu = 0;
- priv->ieee->host_decrypt = 0;
- priv->ieee->host_mc_decrypt = 0;
- }
- IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off");
-
- /* IPW2200/2915 is abled to do hardware fragmentation. */
- priv->ieee->host_open_frag = 0;
-
- if ((priv->pci_dev->device == 0x4223) ||
- (priv->pci_dev->device == 0x4224)) {
- if (option == 1)
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2915ABG Network "
- "Connection\n");
- priv->ieee->abg_true = 1;
- band = LIBIPW_52GHZ_BAND | LIBIPW_24GHZ_BAND;
- modulation = LIBIPW_OFDM_MODULATION |
- LIBIPW_CCK_MODULATION;
- priv->adapter = IPW_2915ABG;
- priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B;
- } else {
- if (option == 1)
- printk(KERN_INFO DRV_NAME
- ": Detected Intel PRO/Wireless 2200BG Network "
- "Connection\n");
-
- priv->ieee->abg_true = 0;
- band = LIBIPW_24GHZ_BAND;
- modulation = LIBIPW_OFDM_MODULATION |
- LIBIPW_CCK_MODULATION;
- priv->adapter = IPW_2200BG;
- priv->ieee->mode = IEEE_G | IEEE_B;
- }
-
- priv->ieee->freq_band = band;
- priv->ieee->modulation = modulation;
-
- priv->rates_mask = LIBIPW_DEFAULT_RATES_MASK;
-
- priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
- priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
-
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
- priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT;
- priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT;
-
- /* If power management is turned on, default to AC mode */
- priv->power_mode = IPW_POWER_AC;
- priv->tx_power = IPW_TX_POWER_DEFAULT;
-
- return old_mode == priv->ieee->iw_mode;
-}
-
-/*
- * This file defines the Wireless Extension handlers. It does not
- * define any methods of hardware manipulation and relies on the
- * functions defined in ipw_main to provide the HW interaction.
- *
- * The exception to this is the use of the ipw_get_ordinal()
- * function used to poll the hardware vs. making unnecessary calls.
- *
- */
-
-static int ipw_set_channel(struct ipw_priv *priv, u8 channel)
-{
- if (channel == 0) {
- IPW_DEBUG_INFO("Setting channel to ANY (0)\n");
- priv->config &= ~CFG_STATIC_CHANNEL;
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- return 0;
- }
-
- priv->config |= CFG_STATIC_CHANNEL;
-
- if (priv->channel == channel) {
- IPW_DEBUG_INFO("Request to set channel to current value (%d)\n",
- channel);
- return 0;
- }
-
- IPW_DEBUG_INFO("Setting channel to %i\n", (int)channel);
- priv->channel = channel;
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
- int i;
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_SCAN("Scan abort triggered due to "
- "channel change.\n");
- ipw_abort_scan(priv);
- }
-
- for (i = 1000; i && (priv->status & STATUS_SCANNING); i--)
- udelay(10);
-
- if (priv->status & STATUS_SCANNING)
- IPW_DEBUG_SCAN("Still scanning...\n");
- else
- IPW_DEBUG_SCAN("Took %dms to abort current scan\n",
- 1000 - i);
-
- return 0;
- }
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to channel change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- return 0;
-}
-
-static int ipw_wx_set_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct iw_freq *fwrq = &wrqu->freq;
- int ret = 0, i;
- u8 channel, flags;
- int band;
-
- if (fwrq->m == 0) {
- IPW_DEBUG_WX("SET Freq/Channel -> any\n");
- mutex_lock(&priv->mutex);
- ret = ipw_set_channel(priv, 0);
- mutex_unlock(&priv->mutex);
- return ret;
- }
- /* if setting by freq convert to channel */
- if (fwrq->e == 1) {
- channel = libipw_freq_to_channel(priv->ieee, fwrq->m);
- if (channel == 0)
- return -EINVAL;
- } else
- channel = fwrq->m;
-
- if (!(band = libipw_is_valid_channel(priv->ieee, channel)))
- return -EINVAL;
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC) {
- i = libipw_channel_to_index(priv->ieee, channel);
- if (i == -1)
- return -EINVAL;
-
- flags = (band == LIBIPW_24GHZ_BAND) ?
- geo->bg[i].flags : geo->a[i].flags;
- if (flags & LIBIPW_CH_PASSIVE_ONLY) {
- IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n");
- return -EINVAL;
- }
- }
-
- IPW_DEBUG_WX("SET Freq/Channel -> %d\n", fwrq->m);
- mutex_lock(&priv->mutex);
- ret = ipw_set_channel(priv, channel);
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static int ipw_wx_get_freq(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- wrqu->freq.e = 0;
-
- /* If we are associated, trying to associate, or have a statically
- * configured CHANNEL then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_CHANNEL ||
- priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) {
- int i;
-
- i = libipw_channel_to_index(priv->ieee, priv->channel);
- BUG_ON(i == -1);
- wrqu->freq.e = 1;
-
- switch (libipw_is_valid_channel(priv->ieee, priv->channel)) {
- case LIBIPW_52GHZ_BAND:
- wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000;
- break;
-
- case LIBIPW_24GHZ_BAND:
- wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000;
- break;
-
- default:
- BUG();
- }
- } else
- wrqu->freq.m = 0;
-
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Freq/Channel -> %d\n", priv->channel);
- return 0;
-}
-
-static int ipw_wx_set_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("Set MODE: %d\n", wrqu->mode);
-
- switch (wrqu->mode) {
-#ifdef CONFIG_IPW2200_MONITOR
- case IW_MODE_MONITOR:
-#endif
- case IW_MODE_ADHOC:
- case IW_MODE_INFRA:
- break;
- case IW_MODE_AUTO:
- wrqu->mode = IW_MODE_INFRA;
- break;
- default:
- return -EINVAL;
- }
- if (wrqu->mode == priv->ieee->iw_mode)
- return 0;
-
- mutex_lock(&priv->mutex);
-
- ipw_sw_reset(priv, 0);
-
-#ifdef CONFIG_IPW2200_MONITOR
- if (priv->ieee->iw_mode == IW_MODE_MONITOR)
- priv->net_dev->type = ARPHRD_ETHER;
-
- if (wrqu->mode == IW_MODE_MONITOR)
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
-#endif /* CONFIG_IPW2200_MONITOR */
-
- /* Free the existing firmware and reset the fw_loaded
- * flag so ipw_load() will bring in the new firmware */
- free_firmware();
-
- priv->ieee->iw_mode = wrqu->mode;
-
- schedule_work(&priv->adapter_restart);
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->mode = priv->ieee->iw_mode;
- IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-/* Values are in microsecond */
-static const s32 timeout_duration[] = {
- 350000,
- 250000,
- 75000,
- 37000,
- 25000,
-};
-
-static const s32 period_duration[] = {
- 400000,
- 700000,
- 1000000,
- 1000000,
- 1000000
-};
-
-static int ipw_wx_get_range(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_range *range = (struct iw_range *)extra;
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- int i = 0, j;
-
- wrqu->data.length = sizeof(*range);
- memset(range, 0, sizeof(*range));
-
- /* 54Mbs == ~27 Mb/s real (802.11g) */
- range->throughput = 27 * 1000 * 1000;
-
- range->max_qual.qual = 100;
- /* TODO: Find real max RSSI and stick here */
- range->max_qual.level = 0;
- range->max_qual.noise = 0;
- range->max_qual.updated = 7; /* Updated all three */
-
- range->avg_qual.qual = 70;
- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
- range->avg_qual.level = 0; /* FIXME to real average level */
- range->avg_qual.noise = 0;
- range->avg_qual.updated = 7; /* Updated all three */
- mutex_lock(&priv->mutex);
- range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES);
-
- for (i = 0; i < range->num_bitrates; i++)
- range->bitrate[i] = (priv->rates.supported_rates[i] & 0x7F) *
- 500000;
-
- range->max_rts = DEFAULT_RTS_THRESHOLD;
- range->min_frag = MIN_FRAG_THRESHOLD;
- range->max_frag = MAX_FRAG_THRESHOLD;
-
- range->encoding_size[0] = 5;
- range->encoding_size[1] = 13;
- range->num_encoding_sizes = 2;
- range->max_encoding_tokens = WEP_KEYS;
-
- /* Set the Wireless Extension versions */
- range->we_version_compiled = WIRELESS_EXT;
- range->we_version_source = 18;
-
- i = 0;
- if (priv->ieee->mode & (IEEE_B | IEEE_G)) {
- for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) {
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->bg[j].flags & LIBIPW_CH_PASSIVE_ONLY))
- continue;
-
- range->freq[i].i = geo->bg[j].channel;
- range->freq[i].m = geo->bg[j].freq * 100000;
- range->freq[i].e = 1;
- i++;
- }
- }
-
- if (priv->ieee->mode & IEEE_A) {
- for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) {
- if ((priv->ieee->iw_mode == IW_MODE_ADHOC) &&
- (geo->a[j].flags & LIBIPW_CH_PASSIVE_ONLY))
- continue;
-
- range->freq[i].i = geo->a[j].channel;
- range->freq[i].m = geo->a[j].freq * 100000;
- range->freq[i].e = 1;
- i++;
- }
- }
-
- range->num_channels = i;
- range->num_frequency = i;
-
- mutex_unlock(&priv->mutex);
-
- /* Event capability (kernel + driver) */
- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
- IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
- IW_EVENT_CAPA_MASK(SIOCGIWAP) |
- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
- range->event_capa[1] = IW_EVENT_CAPA_K_1;
-
- range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
- IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
- range->scan_capa = IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE;
-
- IPW_DEBUG_WX("GET Range\n");
- return 0;
-}
-
-static int ipw_wx_set_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
- return -EINVAL;
- mutex_lock(&priv->mutex);
- if (is_broadcast_ether_addr(wrqu->ap_addr.sa_data) ||
- is_zero_ether_addr(wrqu->ap_addr.sa_data)) {
- /* we disable mandatory BSSID association */
- IPW_DEBUG_WX("Setting AP BSSID to ANY\n");
- priv->config &= ~CFG_STATIC_BSSID;
- IPW_DEBUG_ASSOC("Attempting to associate with new "
- "parameters.\n");
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- priv->config |= CFG_STATIC_BSSID;
- if (ether_addr_equal(priv->bssid, wrqu->ap_addr.sa_data)) {
- IPW_DEBUG_WX("BSSID set to current BSSID.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n",
- wrqu->ap_addr.sa_data);
-
- memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to BSSID change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_wap(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured BSSID then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_BSSID ||
- priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- wrqu->ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN);
- } else
- eth_zero_addr(wrqu->ap_addr.sa_data);
-
- IPW_DEBUG_WX("Getting WAP BSSID: %pM\n",
- wrqu->ap_addr.sa_data);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int length;
-
- mutex_lock(&priv->mutex);
-
- if (!wrqu->essid.flags)
- {
- IPW_DEBUG_WX("Setting ESSID to ANY\n");
- ipw_disassociate(priv);
- priv->config &= ~CFG_STATIC_ESSID;
- ipw_associate(priv);
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
-
- priv->config |= CFG_STATIC_ESSID;
-
- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)
- && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) {
- IPW_DEBUG_WX("ESSID set to current ESSID.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- IPW_DEBUG_WX("Setting ESSID: '%*pE' (%d)\n", length, extra, length);
-
- priv->essid_len = length;
- memcpy(priv->essid, extra, priv->essid_len);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_essid(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- /* If we are associated, trying to associate, or have a statically
- * configured ESSID then return that; otherwise return ANY */
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_STATIC_ESSID ||
- priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) {
- IPW_DEBUG_WX("Getting essid: '%*pE'\n",
- priv->essid_len, priv->essid);
- memcpy(extra, priv->essid, priv->essid_len);
- wrqu->essid.length = priv->essid_len;
- wrqu->essid.flags = 1; /* active */
- } else {
- IPW_DEBUG_WX("Getting essid: ANY\n");
- wrqu->essid.length = 0;
- wrqu->essid.flags = 0; /* active */
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- IPW_DEBUG_WX("Setting nick to '%s'\n", extra);
- if (wrqu->data.length > IW_ESSID_MAX_SIZE)
- return -E2BIG;
- mutex_lock(&priv->mutex);
- wrqu->data.length = min_t(size_t, wrqu->data.length, sizeof(priv->nick));
- memset(priv->nick, 0, sizeof(priv->nick));
- memcpy(priv->nick, extra, wrqu->data.length);
- IPW_DEBUG_TRACE("<<\n");
- mutex_unlock(&priv->mutex);
- return 0;
-
-}
-
-static int ipw_wx_get_nick(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- IPW_DEBUG_WX("Getting nick\n");
- mutex_lock(&priv->mutex);
- wrqu->data.length = strlen(priv->nick);
- memcpy(extra, priv->nick, wrqu->data.length);
- wrqu->data.flags = 1; /* active */
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_set_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value);
- IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value);
- mutex_lock(&priv->mutex);
-
- if (wrqu->sens.fixed == 0)
- {
- priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT;
- priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT;
- goto out;
- }
- if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) ||
- (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) {
- err = -EINVAL;
- goto out;
- }
-
- priv->roaming_threshold = wrqu->sens.value;
- priv->disassociate_threshold = 3*wrqu->sens.value;
- out:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_sens(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->sens.fixed = 1;
- wrqu->sens.value = priv->roaming_threshold;
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET roaming threshold -> %s %d\n",
- wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
-
- return 0;
-}
-
-static int ipw_wx_set_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- /* TODO: We should use semaphores or locks for access to priv */
- struct ipw_priv *priv = libipw_priv(dev);
- u32 target_rate = wrqu->bitrate.value;
- u32 fixed, mask;
-
- /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */
- /* value = X, fixed = 1 means only rate X */
- /* value = X, fixed = 0 means all rates lower equal X */
-
- if (target_rate == -1) {
- fixed = 0;
- mask = LIBIPW_DEFAULT_RATES_MASK;
- /* Now we should reassociate */
- goto apply;
- }
-
- mask = 0;
- fixed = wrqu->bitrate.fixed;
-
- if (target_rate == 1000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_1MB_MASK;
- if (target_rate == 1000000)
- goto apply;
-
- if (target_rate == 2000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_2MB_MASK;
- if (target_rate == 2000000)
- goto apply;
-
- if (target_rate == 5500000 || !fixed)
- mask |= LIBIPW_CCK_RATE_5MB_MASK;
- if (target_rate == 5500000)
- goto apply;
-
- if (target_rate == 6000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_6MB_MASK;
- if (target_rate == 6000000)
- goto apply;
-
- if (target_rate == 9000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_9MB_MASK;
- if (target_rate == 9000000)
- goto apply;
-
- if (target_rate == 11000000 || !fixed)
- mask |= LIBIPW_CCK_RATE_11MB_MASK;
- if (target_rate == 11000000)
- goto apply;
-
- if (target_rate == 12000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_12MB_MASK;
- if (target_rate == 12000000)
- goto apply;
-
- if (target_rate == 18000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_18MB_MASK;
- if (target_rate == 18000000)
- goto apply;
-
- if (target_rate == 24000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_24MB_MASK;
- if (target_rate == 24000000)
- goto apply;
-
- if (target_rate == 36000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_36MB_MASK;
- if (target_rate == 36000000)
- goto apply;
-
- if (target_rate == 48000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_48MB_MASK;
- if (target_rate == 48000000)
- goto apply;
-
- if (target_rate == 54000000 || !fixed)
- mask |= LIBIPW_OFDM_RATE_54MB_MASK;
- if (target_rate == 54000000)
- goto apply;
-
- IPW_DEBUG_WX("invalid rate specified, returning error\n");
- return -EINVAL;
-
- apply:
- IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n",
- mask, fixed ? "fixed" : "sub-rates");
- mutex_lock(&priv->mutex);
- if (mask == LIBIPW_DEFAULT_RATES_MASK) {
- priv->config &= ~CFG_FIXED_RATE;
- ipw_set_fixed_rate(priv, priv->ieee->mode);
- } else
- priv->config |= CFG_FIXED_RATE;
-
- if (priv->rates_mask == mask) {
- IPW_DEBUG_WX("Mask set to current mask.\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- priv->rates_mask = mask;
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to rates change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
-
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_rate(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->bitrate.value = priv->last_rate;
- wrqu->bitrate.fixed = (priv->config & CFG_FIXED_RATE) ? 1 : 0;
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Rate -> %d\n", wrqu->bitrate.value);
- return 0;
-}
-
-static int ipw_wx_set_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (wrqu->rts.disabled || !wrqu->rts.fixed)
- priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
- else {
- if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
- wrqu->rts.value > MAX_RTS_THRESHOLD) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
- priv->rts_threshold = wrqu->rts.value;
- }
-
- ipw_send_rts_threshold(priv, priv->rts_threshold);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET RTS Threshold -> %d\n", priv->rts_threshold);
- return 0;
-}
-
-static int ipw_wx_get_rts(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->rts.value = priv->rts_threshold;
- wrqu->rts.fixed = 0; /* no auto select */
- wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET RTS Threshold -> %d\n", wrqu->rts.value);
- return 0;
-}
-
-static int ipw_wx_set_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err = 0;
-
- mutex_lock(&priv->mutex);
- if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) {
- err = -EINPROGRESS;
- goto out;
- }
-
- if (!wrqu->power.fixed)
- wrqu->power.value = IPW_TX_POWER_DEFAULT;
-
- if (wrqu->power.flags != IW_TXPOW_DBM) {
- err = -EINVAL;
- goto out;
- }
-
- if ((wrqu->power.value > IPW_TX_POWER_MAX) ||
- (wrqu->power.value < IPW_TX_POWER_MIN)) {
- err = -EINVAL;
- goto out;
- }
-
- priv->tx_power = wrqu->power.value;
- err = ipw_set_tx_power(priv);
- out:
- mutex_unlock(&priv->mutex);
- return err;
-}
-
-static int ipw_wx_get_txpow(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->power.value = priv->tx_power;
- wrqu->power.fixed = 1;
- wrqu->power.flags = IW_TXPOW_DBM;
- wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0;
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET TX Power -> %s %d\n",
- wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value);
-
- return 0;
-}
-
-static int ipw_wx_set_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (wrqu->frag.disabled || !wrqu->frag.fixed)
- priv->ieee->fts = DEFAULT_FTS;
- else {
- if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
- wrqu->frag.value > MAX_FRAG_THRESHOLD) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- priv->ieee->fts = wrqu->frag.value & ~0x1;
- }
-
- ipw_send_frag_threshold(priv, wrqu->frag.value);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET Frag Threshold -> %d\n", wrqu->frag.value);
- return 0;
-}
-
-static int ipw_wx_get_frag(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- wrqu->frag.value = priv->ieee->fts;
- wrqu->frag.fixed = 0; /* no auto select */
- wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Frag Threshold -> %d\n", wrqu->frag.value);
-
- return 0;
-}
-
-static int ipw_wx_set_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled)
- return -EINVAL;
-
- if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
- return 0;
-
- if (wrqu->retry.value < 0 || wrqu->retry.value >= 255)
- return -EINVAL;
-
- mutex_lock(&priv->mutex);
- if (wrqu->retry.flags & IW_RETRY_SHORT)
- priv->short_retry_limit = (u8) wrqu->retry.value;
- else if (wrqu->retry.flags & IW_RETRY_LONG)
- priv->long_retry_limit = (u8) wrqu->retry.value;
- else {
- priv->short_retry_limit = (u8) wrqu->retry.value;
- priv->long_retry_limit = (u8) wrqu->retry.value;
- }
-
- ipw_send_retry_limit(priv, priv->short_retry_limit,
- priv->long_retry_limit);
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n",
- priv->short_retry_limit, priv->long_retry_limit);
- return 0;
-}
-
-static int ipw_wx_get_retry(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-
- mutex_lock(&priv->mutex);
- wrqu->retry.disabled = 0;
-
- if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- if (wrqu->retry.flags & IW_RETRY_LONG) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
- wrqu->retry.value = priv->long_retry_limit;
- } else if (wrqu->retry.flags & IW_RETRY_SHORT) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
- wrqu->retry.value = priv->short_retry_limit;
- } else {
- wrqu->retry.flags = IW_RETRY_LIMIT;
- wrqu->retry.value = priv->short_retry_limit;
- }
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("GET retry -> %d\n", wrqu->retry.value);
-
- return 0;
-}
-
-static int ipw_wx_set_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_scan_req *req = (struct iw_scan_req *)extra;
- struct delayed_work *work = NULL;
-
- mutex_lock(&priv->mutex);
-
- priv->user_requested_scan = 1;
-
- if (wrqu->data.length == sizeof(struct iw_scan_req)) {
- if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
- int len = min((int)req->essid_len,
- (int)sizeof(priv->direct_scan_ssid));
- memcpy(priv->direct_scan_ssid, req->essid, len);
- priv->direct_scan_ssid_len = len;
- work = &priv->request_direct_scan;
- } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
- work = &priv->request_passive_scan;
- }
- } else {
- /* Normal active broadcast scan */
- work = &priv->request_scan;
- }
-
- mutex_unlock(&priv->mutex);
-
- IPW_DEBUG_WX("Start scan\n");
-
- schedule_delayed_work(work, 0);
-
- return 0;
-}
-
-static int ipw_wx_get_scan(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_scan(priv->ieee, info, wrqu, extra);
-}
-
-static int ipw_wx_set_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int ret;
- u32 cap = priv->capability;
-
- mutex_lock(&priv->mutex);
- ret = libipw_wx_set_encode(priv->ieee, info, wrqu, key);
-
- /* In IBSS mode, we need to notify the firmware to update
- * the beacon info after we changed the capability. */
- if (cap != priv->capability &&
- priv->ieee->iw_mode == IW_MODE_ADHOC &&
- priv->status & STATUS_ASSOCIATED)
- ipw_disassociate(priv);
-
- mutex_unlock(&priv->mutex);
- return ret;
-}
-
-static int ipw_wx_get_encode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *key)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return libipw_wx_get_encode(priv->ieee, info, wrqu, key);
-}
-
-static int ipw_wx_set_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int err;
- mutex_lock(&priv->mutex);
- if (wrqu->power.disabled) {
- priv->power_mode = IPW_POWER_LEVEL(priv->power_mode);
- err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM);
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
- IPW_DEBUG_WX("SET Power Management Mode -> off\n");
- mutex_unlock(&priv->mutex);
- return 0;
- }
-
- switch (wrqu->power.flags & IW_POWER_MODE) {
- case IW_POWER_ON: /* If not specified */
- case IW_POWER_MODE: /* If set all mask */
- case IW_POWER_ALL_R: /* If explicitly state all */
- break;
- default: /* Otherwise we don't support it */
- IPW_DEBUG_WX("SET PM Mode: %X not supported.\n",
- wrqu->power.flags);
- mutex_unlock(&priv->mutex);
- return -EOPNOTSUPP;
- }
-
- /* If the user hasn't specified a power management mode yet, default
- * to BATTERY */
- if (IPW_POWER_LEVEL(priv->power_mode) == IPW_POWER_AC)
- priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
- else
- priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
-
- err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
-
- IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_power(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- wrqu->power.disabled = 1;
- else
- wrqu->power.disabled = 0;
-
- mutex_unlock(&priv->mutex);
- IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode);
-
- return 0;
-}
-
-static int ipw_wx_set_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- int err;
-
- mutex_lock(&priv->mutex);
- if ((mode < 1) || (mode > IPW_POWER_LIMIT))
- mode = IPW_POWER_AC;
-
- if (IPW_POWER_LEVEL(priv->power_mode) != mode) {
- err = ipw_send_power_mode(priv, mode);
- if (err) {
- IPW_DEBUG_WX("failed setting power mode.\n");
- mutex_unlock(&priv->mutex);
- return err;
- }
- priv->power_mode = IPW_POWER_ENABLED | mode;
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#define MAX_WX_STRING 80
-static int ipw_wx_get_powermode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int level = IPW_POWER_LEVEL(priv->power_mode);
- char *p = extra;
-
- p += scnprintf(p, MAX_WX_STRING, "Power save level: %d ", level);
-
- switch (level) {
- case IPW_POWER_AC:
- p += scnprintf(p, MAX_WX_STRING - (p - extra), "(AC)");
- break;
- case IPW_POWER_BATTERY:
- p += scnprintf(p, MAX_WX_STRING - (p - extra), "(BATTERY)");
- break;
- default:
- p += scnprintf(p, MAX_WX_STRING - (p - extra),
- "(Timeout %dms, Period %dms)",
- timeout_duration[level - 1] / 1000,
- period_duration[level - 1] / 1000);
- }
-
- if (!(priv->power_mode & IPW_POWER_ENABLED))
- p += scnprintf(p, MAX_WX_STRING - (p - extra), " OFF");
-
- wrqu->data.length = p - extra + 1;
-
- return 0;
-}
-
-static int ipw_wx_set_wireless_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- u8 band = 0, modulation = 0;
-
- if (mode == 0 || mode & ~IEEE_MODE_MASK) {
- IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode);
- return -EINVAL;
- }
- mutex_lock(&priv->mutex);
- if (priv->adapter == IPW_2915ABG) {
- priv->ieee->abg_true = 1;
- if (mode & IEEE_A) {
- band |= LIBIPW_52GHZ_BAND;
- modulation |= LIBIPW_OFDM_MODULATION;
- } else
- priv->ieee->abg_true = 0;
- } else {
- if (mode & IEEE_A) {
- IPW_WARNING("Attempt to set 2200BG into "
- "802.11a mode\n");
- mutex_unlock(&priv->mutex);
- return -EINVAL;
- }
-
- priv->ieee->abg_true = 0;
- }
-
- if (mode & IEEE_B) {
- band |= LIBIPW_24GHZ_BAND;
- modulation |= LIBIPW_CCK_MODULATION;
- } else
- priv->ieee->abg_true = 0;
-
- if (mode & IEEE_G) {
- band |= LIBIPW_24GHZ_BAND;
- modulation |= LIBIPW_OFDM_MODULATION;
- } else
- priv->ieee->abg_true = 0;
-
- priv->ieee->mode = mode;
- priv->ieee->freq_band = band;
- priv->ieee->modulation = modulation;
- init_supported_rates(priv, &priv->rates);
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to mode change.\n");
- if (!ipw_disassociate(priv)) {
- ipw_send_supported_rates(priv, &priv->rates);
- ipw_associate(priv);
- }
-
- /* Update the band LEDs */
- ipw_led_band_on(priv);
-
- IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n",
- mode & IEEE_A ? 'a' : '.',
- mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.');
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_wireless_mode(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- switch (priv->ieee->mode) {
- case IEEE_A:
- strncpy(extra, "802.11a (1)", MAX_WX_STRING);
- break;
- case IEEE_B:
- strncpy(extra, "802.11b (2)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_B:
- strncpy(extra, "802.11ab (3)", MAX_WX_STRING);
- break;
- case IEEE_G:
- strncpy(extra, "802.11g (4)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_G:
- strncpy(extra, "802.11ag (5)", MAX_WX_STRING);
- break;
- case IEEE_B | IEEE_G:
- strncpy(extra, "802.11bg (6)", MAX_WX_STRING);
- break;
- case IEEE_A | IEEE_B | IEEE_G:
- strncpy(extra, "802.11abg (7)", MAX_WX_STRING);
- break;
- default:
- strncpy(extra, "unknown", MAX_WX_STRING);
- break;
- }
- extra[MAX_WX_STRING - 1] = '\0';
-
- IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra);
-
- wrqu->data.length = strlen(extra) + 1;
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-static int ipw_wx_set_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int mode = *(int *)extra;
- mutex_lock(&priv->mutex);
- /* Switching from SHORT -> LONG requires a disassociation */
- if (mode == 1) {
- if (!(priv->config & CFG_PREAMBLE_LONG)) {
- priv->config |= CFG_PREAMBLE_LONG;
-
- /* Network configuration changed -- force [re]association */
- IPW_DEBUG_ASSOC
- ("[re]association triggered due to preamble change.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
- }
- goto done;
- }
-
- if (mode == 0) {
- priv->config &= ~CFG_PREAMBLE_LONG;
- goto done;
- }
- mutex_unlock(&priv->mutex);
- return -EINVAL;
-
- done:
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static int ipw_wx_get_preamble(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- mutex_lock(&priv->mutex);
- if (priv->config & CFG_PREAMBLE_LONG)
- snprintf(wrqu->name, IFNAMSIZ, "long (1)");
- else
- snprintf(wrqu->name, IFNAMSIZ, "auto (0)");
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_MONITOR
-static int ipw_wx_set_monitor(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int *parms = (int *)extra;
- int enable = (parms[0] > 0);
- mutex_lock(&priv->mutex);
- IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]);
- if (enable) {
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
-#ifdef CONFIG_IPW2200_RADIOTAP
- priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-#else
- priv->net_dev->type = ARPHRD_IEEE80211;
-#endif
- schedule_work(&priv->adapter_restart);
- }
-
- ipw_set_channel(priv, parms[1]);
- } else {
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- mutex_unlock(&priv->mutex);
- return 0;
- }
- priv->net_dev->type = ARPHRD_ETHER;
- schedule_work(&priv->adapter_restart);
- }
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-#endif /* CONFIG_IPW2200_MONITOR */
-
-static int ipw_wx_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- IPW_DEBUG_WX("RESET\n");
- schedule_work(&priv->adapter_restart);
- return 0;
-}
-
-static int ipw_wx_sw_reset(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- union iwreq_data wrqu_sec = {
- .encoding = {
- .flags = IW_ENCODE_DISABLED,
- },
- };
- int ret;
-
- IPW_DEBUG_WX("SW_RESET\n");
-
- mutex_lock(&priv->mutex);
-
- ret = ipw_sw_reset(priv, 2);
- if (!ret) {
- free_firmware();
- ipw_adapter_restart(priv);
- }
-
- /* The SW reset bit might have been toggled on by the 'disable'
- * module parameter, so take appropriate action */
- ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW);
-
- mutex_unlock(&priv->mutex);
- libipw_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL);
- mutex_lock(&priv->mutex);
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- /* Configuration likely changed -- force [re]association */
- IPW_DEBUG_ASSOC("[re]association triggered due to sw "
- "reset.\n");
- if (!ipw_disassociate(priv))
- ipw_associate(priv);
- }
-
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-/* Rebase the WE IOCTLs to zero for the handler array */
-static iw_handler ipw_wx_handlers[] = {
- IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
- IW_HANDLER(SIOCSIWFREQ, ipw_wx_set_freq),
- IW_HANDLER(SIOCGIWFREQ, ipw_wx_get_freq),
- IW_HANDLER(SIOCSIWMODE, ipw_wx_set_mode),
- IW_HANDLER(SIOCGIWMODE, ipw_wx_get_mode),
- IW_HANDLER(SIOCSIWSENS, ipw_wx_set_sens),
- IW_HANDLER(SIOCGIWSENS, ipw_wx_get_sens),
- IW_HANDLER(SIOCGIWRANGE, ipw_wx_get_range),
- IW_HANDLER(SIOCSIWAP, ipw_wx_set_wap),
- IW_HANDLER(SIOCGIWAP, ipw_wx_get_wap),
- IW_HANDLER(SIOCSIWSCAN, ipw_wx_set_scan),
- IW_HANDLER(SIOCGIWSCAN, ipw_wx_get_scan),
- IW_HANDLER(SIOCSIWESSID, ipw_wx_set_essid),
- IW_HANDLER(SIOCGIWESSID, ipw_wx_get_essid),
- IW_HANDLER(SIOCSIWNICKN, ipw_wx_set_nick),
- IW_HANDLER(SIOCGIWNICKN, ipw_wx_get_nick),
- IW_HANDLER(SIOCSIWRATE, ipw_wx_set_rate),
- IW_HANDLER(SIOCGIWRATE, ipw_wx_get_rate),
- IW_HANDLER(SIOCSIWRTS, ipw_wx_set_rts),
- IW_HANDLER(SIOCGIWRTS, ipw_wx_get_rts),
- IW_HANDLER(SIOCSIWFRAG, ipw_wx_set_frag),
- IW_HANDLER(SIOCGIWFRAG, ipw_wx_get_frag),
- IW_HANDLER(SIOCSIWTXPOW, ipw_wx_set_txpow),
- IW_HANDLER(SIOCGIWTXPOW, ipw_wx_get_txpow),
- IW_HANDLER(SIOCSIWRETRY, ipw_wx_set_retry),
- IW_HANDLER(SIOCGIWRETRY, ipw_wx_get_retry),
- IW_HANDLER(SIOCSIWENCODE, ipw_wx_set_encode),
- IW_HANDLER(SIOCGIWENCODE, ipw_wx_get_encode),
- IW_HANDLER(SIOCSIWPOWER, ipw_wx_set_power),
- IW_HANDLER(SIOCGIWPOWER, ipw_wx_get_power),
- IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
- IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
- IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
- IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
- IW_HANDLER(SIOCSIWGENIE, ipw_wx_set_genie),
- IW_HANDLER(SIOCGIWGENIE, ipw_wx_get_genie),
- IW_HANDLER(SIOCSIWMLME, ipw_wx_set_mlme),
- IW_HANDLER(SIOCSIWAUTH, ipw_wx_set_auth),
- IW_HANDLER(SIOCGIWAUTH, ipw_wx_get_auth),
- IW_HANDLER(SIOCSIWENCODEEXT, ipw_wx_set_encodeext),
- IW_HANDLER(SIOCGIWENCODEEXT, ipw_wx_get_encodeext),
-};
-
-enum {
- IPW_PRIV_SET_POWER = SIOCIWFIRSTPRIV,
- IPW_PRIV_GET_POWER,
- IPW_PRIV_SET_MODE,
- IPW_PRIV_GET_MODE,
- IPW_PRIV_SET_PREAMBLE,
- IPW_PRIV_GET_PREAMBLE,
- IPW_PRIV_RESET,
- IPW_PRIV_SW_RESET,
-#ifdef CONFIG_IPW2200_MONITOR
- IPW_PRIV_SET_MONITOR,
-#endif
-};
-
-static struct iw_priv_args ipw_priv_args[] = {
- {
- .cmd = IPW_PRIV_SET_POWER,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_power"},
- {
- .cmd = IPW_PRIV_GET_POWER,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_power"},
- {
- .cmd = IPW_PRIV_SET_MODE,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_mode"},
- {
- .cmd = IPW_PRIV_GET_MODE,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
- .name = "get_mode"},
- {
- .cmd = IPW_PRIV_SET_PREAMBLE,
- .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- .name = "set_preamble"},
- {
- .cmd = IPW_PRIV_GET_PREAMBLE,
- .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ,
- .name = "get_preamble"},
- {
- IPW_PRIV_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"},
- {
- IPW_PRIV_SW_RESET,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "sw_reset"},
-#ifdef CONFIG_IPW2200_MONITOR
- {
- IPW_PRIV_SET_MONITOR,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"},
-#endif /* CONFIG_IPW2200_MONITOR */
-};
-
-static iw_handler ipw_priv_handler[] = {
- ipw_wx_set_powermode,
- ipw_wx_get_powermode,
- ipw_wx_set_wireless_mode,
- ipw_wx_get_wireless_mode,
- ipw_wx_set_preamble,
- ipw_wx_get_preamble,
- ipw_wx_reset,
- ipw_wx_sw_reset,
-#ifdef CONFIG_IPW2200_MONITOR
- ipw_wx_set_monitor,
-#endif
-};
-
-static const struct iw_handler_def ipw_wx_handler_def = {
- .standard = ipw_wx_handlers,
- .num_standard = ARRAY_SIZE(ipw_wx_handlers),
- .num_private = ARRAY_SIZE(ipw_priv_handler),
- .num_private_args = ARRAY_SIZE(ipw_priv_args),
- .private = ipw_priv_handler,
- .private_args = ipw_priv_args,
- .get_wireless_stats = ipw_get_wireless_stats,
-};
-
-/*
- * Get wireless statistics.
- * Called by /proc/net/wireless
- * Also called by SIOCGIWSTATS
- */
-static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct iw_statistics *wstats;
-
- wstats = &priv->wstats;
-
- /* if hw is disabled, then ipw_get_ordinal() can't be called.
- * netdev->get_wireless_stats seems to be called before fw is
- * initialized. STATUS_ASSOCIATED will only be set if the hw is up
- * and associated; if not associcated, the values are all meaningless
- * anyway, so set them all to NULL and INVALID */
- if (!(priv->status & STATUS_ASSOCIATED)) {
- wstats->miss.beacon = 0;
- wstats->discard.retries = 0;
- wstats->qual.qual = 0;
- wstats->qual.level = 0;
- wstats->qual.noise = 0;
- wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
- return wstats;
- }
-
- wstats->qual.qual = priv->quality;
- wstats->qual.level = priv->exp_avg_rssi;
- wstats->qual.noise = priv->exp_avg_noise;
- wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM;
-
- wstats->miss.beacon = average_value(&priv->average_missed_beacons);
- wstats->discard.retries = priv->last_tx_failures;
- wstats->discard.code = priv->ieee->ieee_stats.rx_discards_undecryptable;
-
-/* if (ipw_get_ordinal(priv, IPW_ORD_STAT_TX_RETRY, &tx_retry, &len))
- goto fail_get_ordinal;
- wstats->discard.retries += tx_retry; */
-
- return wstats;
-}
-
-/* net device stuff */
-
-static void init_sys_config(struct ipw_sys_config *sys_config)
-{
- memset(sys_config, 0, sizeof(struct ipw_sys_config));
- sys_config->bt_coexistence = 0;
- sys_config->answer_broadcast_ssid_probe = 0;
- sys_config->accept_all_data_frames = 0;
- sys_config->accept_non_directed_frames = 1;
- sys_config->exclude_unicast_unencrypted = 0;
- sys_config->disable_unicast_decryption = 1;
- sys_config->exclude_multicast_unencrypted = 0;
- sys_config->disable_multicast_decryption = 1;
- if (antenna < CFG_SYS_ANTENNA_BOTH || antenna > CFG_SYS_ANTENNA_B)
- antenna = CFG_SYS_ANTENNA_BOTH;
- sys_config->antenna_diversity = antenna;
- sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */
- sys_config->dot11g_auto_detection = 0;
- sys_config->enable_cts_to_self = 0;
- sys_config->bt_coexist_collision_thr = 0;
- sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */
- sys_config->silence_threshold = 0x1e;
-}
-
-static int ipw_net_open(struct net_device *dev)
-{
- IPW_DEBUG_INFO("dev->open\n");
- netif_start_queue(dev);
- return 0;
-}
-
-static int ipw_net_stop(struct net_device *dev)
-{
- IPW_DEBUG_INFO("dev->close\n");
- netif_stop_queue(dev);
- return 0;
-}
-
-/*
-todo:
-
-modify to send one tfd per fragment instead of using chunking. otherwise
-we need to heavily modify the libipw_skb_to_txb.
-*/
-
-static int ipw_tx_skb(struct ipw_priv *priv, struct libipw_txb *txb,
- int pri)
-{
- struct libipw_hdr_3addrqos *hdr = (struct libipw_hdr_3addrqos *)
- txb->fragments[0]->data;
- int i = 0;
- struct tfd_frame *tfd;
-#ifdef CONFIG_IPW2200_QOS
- int tx_id = ipw_get_tx_queue_number(priv, pri);
- struct clx2_tx_queue *txq = &priv->txq[tx_id];
-#else
- struct clx2_tx_queue *txq = &priv->txq[0];
-#endif
- struct clx2_queue *q = &txq->q;
- u8 id, hdr_len, unicast;
- int fc;
-
- if (!(priv->status & STATUS_ASSOCIATED))
- goto drop;
-
- hdr_len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
- switch (priv->ieee->iw_mode) {
- case IW_MODE_ADHOC:
- unicast = !is_multicast_ether_addr(hdr->addr1);
- id = ipw_find_station(priv, hdr->addr1);
- if (id == IPW_INVALID_STATION) {
- id = ipw_add_station(priv, hdr->addr1);
- if (id == IPW_INVALID_STATION) {
- IPW_WARNING("Attempt to send data to "
- "invalid cell: %pM\n",
- hdr->addr1);
- goto drop;
- }
- }
- break;
-
- case IW_MODE_INFRA:
- default:
- unicast = !is_multicast_ether_addr(hdr->addr3);
- id = 0;
- break;
- }
-
- tfd = &txq->bd[q->first_empty];
- txq->txb[q->first_empty] = txb;
- memset(tfd, 0, sizeof(*tfd));
- tfd->u.data.station_number = id;
-
- tfd->control_flags.message_type = TX_FRAME_TYPE;
- tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK;
-
- tfd->u.data.cmd_id = DINO_CMD_TX;
- tfd->u.data.len = cpu_to_le16(txb->payload_size);
-
- if (priv->assoc_request.ieee_mode == IPW_B_MODE)
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_CCK;
- else
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_MODE_OFDM;
-
- if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE)
- tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE;
-
- fc = le16_to_cpu(hdr->frame_ctl);
- hdr->frame_ctl = cpu_to_le16(fc & ~IEEE80211_FCTL_MOREFRAGS);
-
- memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len);
-
- if (likely(unicast))
- tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
-
- if (txb->encrypted && !priv->ieee->host_encrypt) {
- switch (priv->ieee->sec.level) {
- case SEC_LEVEL_3:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- /* XXX: ACK flag must be set for CCMP even if it
- * is a multicast/broadcast packet, because CCMP
- * group communication encrypted by GTK is
- * actually done by the AP. */
- if (!unicast)
- tfd->u.data.tx_flags |= DCT_FLAG_ACK_REQD;
-
- tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_CCM;
- tfd->u.data.key_index = 0;
- tfd->u.data.key_index |= DCT_WEP_INDEX_USE_IMMEDIATE;
- break;
- case SEC_LEVEL_2:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- tfd->u.data.tx_flags &= ~DCT_FLAG_NO_WEP;
- tfd->u.data.tx_flags_ext |= DCT_FLAG_EXT_SECURITY_TKIP;
- tfd->u.data.key_index = DCT_WEP_INDEX_USE_IMMEDIATE;
- break;
- case SEC_LEVEL_1:
- tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- cpu_to_le16(IEEE80211_FCTL_PROTECTED);
- tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx;
- if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <=
- 40)
- tfd->u.data.key_index |= DCT_WEP_KEY_64Bit;
- else
- tfd->u.data.key_index |= DCT_WEP_KEY_128Bit;
- break;
- case SEC_LEVEL_0:
- break;
- default:
- printk(KERN_ERR "Unknown security level %d\n",
- priv->ieee->sec.level);
- break;
- }
- } else
- /* No hardware encryption */
- tfd->u.data.tx_flags |= DCT_FLAG_NO_WEP;
-
-#ifdef CONFIG_IPW2200_QOS
- if (fc & IEEE80211_STYPE_QOS_DATA)
- ipw_qos_set_tx_queue_command(priv, pri, &(tfd->u.data));
-#endif /* CONFIG_IPW2200_QOS */
-
- /* payload */
- tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2),
- txb->nr_frags));
- IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n",
- txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks));
- for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) {
- IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n",
- i, le32_to_cpu(tfd->u.data.num_chunks),
- txb->fragments[i]->len - hdr_len);
- IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n",
- i, tfd->u.data.num_chunks,
- txb->fragments[i]->len - hdr_len);
- printk_buf(IPW_DL_TX, txb->fragments[i]->data + hdr_len,
- txb->fragments[i]->len - hdr_len);
-
- tfd->u.data.chunk_ptr[i] =
- cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
- txb->fragments[i]->data + hdr_len,
- txb->fragments[i]->len - hdr_len,
- DMA_TO_DEVICE));
- tfd->u.data.chunk_len[i] =
- cpu_to_le16(txb->fragments[i]->len - hdr_len);
- }
-
- if (i != txb->nr_frags) {
- struct sk_buff *skb;
- u16 remaining_bytes = 0;
- int j;
-
- for (j = i; j < txb->nr_frags; j++)
- remaining_bytes += txb->fragments[j]->len - hdr_len;
-
- printk(KERN_INFO "Trying to reallocate for %d bytes\n",
- remaining_bytes);
- skb = alloc_skb(remaining_bytes, GFP_ATOMIC);
- if (skb != NULL) {
- tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes);
- for (j = i; j < txb->nr_frags; j++) {
- int size = txb->fragments[j]->len - hdr_len;
-
- printk(KERN_INFO "Adding frag %d %d...\n",
- j, size);
- skb_put_data(skb,
- txb->fragments[j]->data + hdr_len,
- size);
- }
- dev_kfree_skb_any(txb->fragments[i]);
- txb->fragments[i] = skb;
- tfd->u.data.chunk_ptr[i] =
- cpu_to_le32(dma_map_single(&priv->pci_dev->dev,
- skb->data,
- remaining_bytes,
- DMA_TO_DEVICE));
-
- le32_add_cpu(&tfd->u.data.num_chunks, 1);
- }
- }
-
- /* kick DMA */
- q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd);
- ipw_write32(priv, q->reg_w, q->first_empty);
-
- if (ipw_tx_queue_space(q) < q->high_mark)
- netif_stop_queue(priv->net_dev);
-
- return NETDEV_TX_OK;
-
- drop:
- IPW_DEBUG_DROP("Silently dropping Tx packet.\n");
- libipw_txb_free(txb);
- return NETDEV_TX_OK;
-}
-
-static int ipw_net_is_queue_full(struct net_device *dev, int pri)
-{
- struct ipw_priv *priv = libipw_priv(dev);
-#ifdef CONFIG_IPW2200_QOS
- int tx_id = ipw_get_tx_queue_number(priv, pri);
- struct clx2_tx_queue *txq = &priv->txq[tx_id];
-#else
- struct clx2_tx_queue *txq = &priv->txq[0];
-#endif /* CONFIG_IPW2200_QOS */
-
- if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark)
- return 1;
-
- return 0;
-}
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
- struct libipw_txb *txb)
-{
- struct libipw_rx_stats dummystats;
- struct ieee80211_hdr *hdr;
- u8 n;
- u16 filter = priv->prom_priv->filter;
- int hdr_only = 0;
-
- if (filter & IPW_PROM_NO_TX)
- return;
-
- memset(&dummystats, 0, sizeof(dummystats));
-
- /* Filtering of fragment chains is done against the first fragment */
- hdr = (void *)txb->fragments[0]->data;
- if (libipw_is_management(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_MGMT)
- return;
- if (filter & IPW_PROM_MGMT_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_control(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_CTL)
- return;
- if (filter & IPW_PROM_CTL_HEADER_ONLY)
- hdr_only = 1;
- } else if (libipw_is_data(le16_to_cpu(hdr->frame_control))) {
- if (filter & IPW_PROM_NO_DATA)
- return;
- if (filter & IPW_PROM_DATA_HEADER_ONLY)
- hdr_only = 1;
- }
-
- for(n=0; n<txb->nr_frags; ++n) {
- struct sk_buff *src = txb->fragments[n];
- struct sk_buff *dst;
- struct ieee80211_radiotap_header *rt_hdr;
- int len;
-
- if (hdr_only) {
- hdr = (void *)src->data;
- len = libipw_get_hdrlen(le16_to_cpu(hdr->frame_control));
- } else
- len = src->len;
-
- dst = alloc_skb(len + sizeof(*rt_hdr) + sizeof(u16)*2, GFP_ATOMIC);
- if (!dst)
- continue;
-
- rt_hdr = skb_put(dst, sizeof(*rt_hdr));
-
- rt_hdr->it_version = PKTHDR_RADIOTAP_VERSION;
- rt_hdr->it_pad = 0;
- rt_hdr->it_present = 0; /* after all, it's just an idea */
- rt_hdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL);
-
- *(__le16*)skb_put(dst, sizeof(u16)) = cpu_to_le16(
- ieee80211chan2mhz(priv->channel));
- if (priv->channel > 14) /* 802.11a */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ);
- else if (priv->ieee->mode == IEEE_B) /* 802.11b */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ);
- else /* 802.11g */
- *(__le16*)skb_put(dst, sizeof(u16)) =
- cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_2GHZ);
-
- rt_hdr->it_len = cpu_to_le16(dst->len);
-
- skb_copy_from_linear_data(src, skb_put(dst, len), len);
-
- if (!libipw_rx(priv->prom_priv->ieee, dst, &dummystats))
- dev_kfree_skb_any(dst);
- }
-}
-#endif
-
-static netdev_tx_t ipw_net_hard_start_xmit(struct libipw_txb *txb,
- struct net_device *dev, int pri)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- unsigned long flags;
- netdev_tx_t ret;
-
- IPW_DEBUG_TX("dev->xmit(%d bytes)\n", txb->payload_size);
- spin_lock_irqsave(&priv->lock, flags);
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (rtap_iface && netif_running(priv->prom_net_dev))
- ipw_handle_promiscuous_tx(priv, txb);
-#endif
-
- ret = ipw_tx_skb(priv, txb, pri);
- if (ret == NETDEV_TX_OK)
- __ipw_led_activity_on(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return ret;
-}
-
-static void ipw_net_set_multicast_list(struct net_device *dev)
-{
-
-}
-
-static int ipw_net_set_mac_address(struct net_device *dev, void *p)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- struct sockaddr *addr = p;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
- mutex_lock(&priv->mutex);
- priv->config |= CFG_CUSTOM_MAC;
- memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
- printk(KERN_INFO "%s: Setting MAC to %pM\n",
- priv->net_dev->name, priv->mac_addr);
- schedule_work(&priv->adapter_restart);
- mutex_unlock(&priv->mutex);
- return 0;
-}
-
-static void ipw_ethtool_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *info)
-{
- struct ipw_priv *p = libipw_priv(dev);
- char vers[64];
- char date[32];
- u32 len;
-
- strscpy(info->driver, DRV_NAME, sizeof(info->driver));
- strscpy(info->version, DRV_VERSION, sizeof(info->version));
-
- len = sizeof(vers);
- ipw_get_ordinal(p, IPW_ORD_STAT_FW_VERSION, vers, &len);
- len = sizeof(date);
- ipw_get_ordinal(p, IPW_ORD_STAT_FW_DATE, date, &len);
-
- snprintf(info->fw_version, sizeof(info->fw_version), "%s (%s)",
- vers, date);
- strscpy(info->bus_info, pci_name(p->pci_dev),
- sizeof(info->bus_info));
-}
-
-static u32 ipw_ethtool_get_link(struct net_device *dev)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- return (priv->status & STATUS_ASSOCIATED) != 0;
-}
-
-static int ipw_ethtool_get_eeprom_len(struct net_device *dev)
-{
- return IPW_EEPROM_IMAGE_SIZE;
-}
-
-static int ipw_ethtool_get_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 * bytes)
-{
- struct ipw_priv *p = libipw_priv(dev);
-
- if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
- return -EINVAL;
- mutex_lock(&p->mutex);
- memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len);
- mutex_unlock(&p->mutex);
- return 0;
-}
-
-static int ipw_ethtool_set_eeprom(struct net_device *dev,
- struct ethtool_eeprom *eeprom, u8 * bytes)
-{
- struct ipw_priv *p = libipw_priv(dev);
- int i;
-
- if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE)
- return -EINVAL;
- mutex_lock(&p->mutex);
- memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len);
- for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++)
- ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]);
- mutex_unlock(&p->mutex);
- return 0;
-}
-
-static const struct ethtool_ops ipw_ethtool_ops = {
- .get_link = ipw_ethtool_get_link,
- .get_drvinfo = ipw_ethtool_get_drvinfo,
- .get_eeprom_len = ipw_ethtool_get_eeprom_len,
- .get_eeprom = ipw_ethtool_get_eeprom,
- .set_eeprom = ipw_ethtool_set_eeprom,
-};
-
-static irqreturn_t ipw_isr(int irq, void *data)
-{
- struct ipw_priv *priv = data;
- u32 inta, inta_mask;
-
- if (!priv)
- return IRQ_NONE;
-
- spin_lock(&priv->irq_lock);
-
- if (!(priv->status & STATUS_INT_ENABLED)) {
- /* IRQ is disabled */
- goto none;
- }
-
- inta = ipw_read32(priv, IPW_INTA_RW);
- inta_mask = ipw_read32(priv, IPW_INTA_MASK_R);
-
- if (inta == 0xFFFFFFFF) {
- /* Hardware disappeared */
- IPW_WARNING("IRQ INTA == 0xFFFFFFFF\n");
- goto none;
- }
-
- if (!(inta & (IPW_INTA_MASK_ALL & inta_mask))) {
- /* Shared interrupt */
- goto none;
- }
-
- /* tell the device to stop sending interrupts */
- __ipw_disable_interrupts(priv);
-
- /* ack current interrupts */
- inta &= (IPW_INTA_MASK_ALL & inta_mask);
- ipw_write32(priv, IPW_INTA_RW, inta);
-
- /* Cache INTA value for our tasklet */
- priv->isr_inta = inta;
-
- tasklet_schedule(&priv->irq_tasklet);
-
- spin_unlock(&priv->irq_lock);
-
- return IRQ_HANDLED;
- none:
- spin_unlock(&priv->irq_lock);
- return IRQ_NONE;
-}
-
-static void ipw_rf_kill(void *adapter)
-{
- struct ipw_priv *priv = adapter;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (rf_kill_active(priv)) {
- IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- goto exit_unlock;
- }
-
- /* RF Kill is now disabled, so bring the device back up */
-
- if (!(priv->status & STATUS_RF_KILL_MASK)) {
- IPW_DEBUG_RF_KILL("HW RF Kill no longer active, restarting "
- "device\n");
-
- /* we can not do an adapter restart while inside an irq lock */
- schedule_work(&priv->adapter_restart);
- } else
- IPW_DEBUG_RF_KILL("HW RF Kill deactivated. SW RF Kill still "
- "enabled\n");
-
- exit_unlock:
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void ipw_bg_rf_kill(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, rf_kill.work);
- mutex_lock(&priv->mutex);
- ipw_rf_kill(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_link_up(struct ipw_priv *priv)
-{
- priv->last_seq_num = -1;
- priv->last_frag_num = -1;
- priv->last_packet_time = 0;
-
- netif_carrier_on(priv->net_dev);
-
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->scan_event);
- ipw_reset_stats(priv);
- /* Ensure the rate is updated immediately */
- priv->last_rate = ipw_get_current_rate(priv);
- ipw_gather_stats(priv);
- ipw_led_link_up(priv);
- notify_wx_assoc_event(priv);
-
- if (priv->config & CFG_BACKGROUND_SCAN)
- schedule_delayed_work(&priv->request_scan, HZ);
-}
-
-static void ipw_bg_link_up(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, link_up);
- mutex_lock(&priv->mutex);
- ipw_link_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_link_down(struct ipw_priv *priv)
-{
- ipw_led_link_down(priv);
- netif_carrier_off(priv->net_dev);
- notify_wx_assoc_event(priv);
-
- /* Cancel any queued work ... */
- cancel_delayed_work(&priv->request_scan);
- cancel_delayed_work(&priv->request_direct_scan);
- cancel_delayed_work(&priv->request_passive_scan);
- cancel_delayed_work(&priv->adhoc_check);
- cancel_delayed_work(&priv->gather_stats);
-
- ipw_reset_stats(priv);
-
- if (!(priv->status & STATUS_EXIT_PENDING)) {
- /* Queue up another scan... */
- schedule_delayed_work(&priv->request_scan, 0);
- } else
- cancel_delayed_work(&priv->scan_event);
-}
-
-static void ipw_bg_link_down(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, link_down);
- mutex_lock(&priv->mutex);
- ipw_link_down(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_setup_deferred_work(struct ipw_priv *priv)
-{
- init_waitqueue_head(&priv->wait_command_queue);
- init_waitqueue_head(&priv->wait_state);
-
- INIT_DELAYED_WORK(&priv->adhoc_check, ipw_bg_adhoc_check);
- INIT_WORK(&priv->associate, ipw_bg_associate);
- INIT_WORK(&priv->disassociate, ipw_bg_disassociate);
- INIT_WORK(&priv->system_config, ipw_system_config);
- INIT_WORK(&priv->rx_replenish, ipw_bg_rx_queue_replenish);
- INIT_WORK(&priv->adapter_restart, ipw_bg_adapter_restart);
- INIT_DELAYED_WORK(&priv->rf_kill, ipw_bg_rf_kill);
- INIT_WORK(&priv->up, ipw_bg_up);
- INIT_WORK(&priv->down, ipw_bg_down);
- INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
- INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan);
- INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
- INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
- INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
- INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
- INIT_WORK(&priv->roam, ipw_bg_roam);
- INIT_DELAYED_WORK(&priv->scan_check, ipw_bg_scan_check);
- INIT_WORK(&priv->link_up, ipw_bg_link_up);
- INIT_WORK(&priv->link_down, ipw_bg_link_down);
- INIT_DELAYED_WORK(&priv->led_link_on, ipw_bg_led_link_on);
- INIT_DELAYED_WORK(&priv->led_link_off, ipw_bg_led_link_off);
- INIT_DELAYED_WORK(&priv->led_act_off, ipw_bg_led_activity_off);
- INIT_WORK(&priv->merge_networks, ipw_merge_adhoc_network);
-
-#ifdef CONFIG_IPW2200_QOS
- INIT_WORK(&priv->qos_activate, ipw_bg_qos_activate);
-#endif /* CONFIG_IPW2200_QOS */
-
- tasklet_setup(&priv->irq_tasklet, ipw_irq_tasklet);
-}
-
-static void shim__set_security(struct net_device *dev,
- struct libipw_security *sec)
-{
- struct ipw_priv *priv = libipw_priv(dev);
- int i;
- for (i = 0; i < 4; i++) {
- if (sec->flags & (1 << i)) {
- priv->ieee->sec.encode_alg[i] = sec->encode_alg[i];
- priv->ieee->sec.key_sizes[i] = sec->key_sizes[i];
- if (sec->key_sizes[i] == 0)
- priv->ieee->sec.flags &= ~(1 << i);
- else {
- memcpy(priv->ieee->sec.keys[i], sec->keys[i],
- sec->key_sizes[i]);
- priv->ieee->sec.flags |= (1 << i);
- }
- priv->status |= STATUS_SECURITY_UPDATED;
- } else if (sec->level != SEC_LEVEL_1)
- priv->ieee->sec.flags &= ~(1 << i);
- }
-
- if (sec->flags & SEC_ACTIVE_KEY) {
- priv->ieee->sec.active_key = sec->active_key;
- priv->ieee->sec.flags |= SEC_ACTIVE_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- } else
- priv->ieee->sec.flags &= ~SEC_ACTIVE_KEY;
-
- if ((sec->flags & SEC_AUTH_MODE) &&
- (priv->ieee->sec.auth_mode != sec->auth_mode)) {
- priv->ieee->sec.auth_mode = sec->auth_mode;
- priv->ieee->sec.flags |= SEC_AUTH_MODE;
- if (sec->auth_mode == WLAN_AUTH_SHARED_KEY)
- priv->capability |= CAP_SHARED_KEY;
- else
- priv->capability &= ~CAP_SHARED_KEY;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (sec->flags & SEC_ENABLED && priv->ieee->sec.enabled != sec->enabled) {
- priv->ieee->sec.flags |= SEC_ENABLED;
- priv->ieee->sec.enabled = sec->enabled;
- priv->status |= STATUS_SECURITY_UPDATED;
- if (sec->enabled)
- priv->capability |= CAP_PRIVACY_ON;
- else
- priv->capability &= ~CAP_PRIVACY_ON;
- }
-
- if (sec->flags & SEC_ENCRYPT)
- priv->ieee->sec.encrypt = sec->encrypt;
-
- if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) {
- priv->ieee->sec.level = sec->level;
- priv->ieee->sec.flags |= SEC_LEVEL;
- priv->status |= STATUS_SECURITY_UPDATED;
- }
-
- if (!priv->ieee->host_encrypt && (sec->flags & SEC_ENCRYPT))
- ipw_set_hwcrypto_keys(priv);
-
- /* To match current functionality of ipw2100 (which works well w/
- * various supplicants, we don't force a disassociate if the
- * privacy capability changes ... */
-#if 0
- if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) &&
- (((priv->assoc_request.capability &
- cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && !sec->enabled) ||
- (!(priv->assoc_request.capability &
- cpu_to_le16(WLAN_CAPABILITY_PRIVACY)) && sec->enabled))) {
- IPW_DEBUG_ASSOC("Disassociating due to capability "
- "change.\n");
- ipw_disassociate(priv);
- }
-#endif
-}
-
-static int init_supported_rates(struct ipw_priv *priv,
- struct ipw_supported_rates *rates)
-{
- /* TODO: Mask out rates based on priv->rates_mask */
-
- memset(rates, 0, sizeof(*rates));
- /* configure supported rates */
- switch (priv->ieee->freq_band) {
- case LIBIPW_52GHZ_BAND:
- rates->ieee_mode = IPW_A_MODE;
- rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_OFDM_DEFAULT_RATES_MASK);
- break;
-
- default: /* Mixed or 2.4Ghz */
- rates->ieee_mode = IPW_G_MODE;
- rates->purpose = IPW_RATE_CAPABILITIES;
- ipw_add_cck_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_CCK_DEFAULT_RATES_MASK);
- if (priv->ieee->modulation & LIBIPW_OFDM_MODULATION) {
- ipw_add_ofdm_scan_rates(rates, LIBIPW_CCK_MODULATION,
- LIBIPW_OFDM_DEFAULT_RATES_MASK);
- }
- break;
- }
-
- return 0;
-}
-
-static int ipw_config(struct ipw_priv *priv)
-{
- /* This is only called from ipw_up, which resets/reloads the firmware
- so, we don't need to first disable the card before we configure
- it */
- if (ipw_set_tx_power(priv))
- goto error;
-
- /* initialize adapter address */
- if (ipw_send_adapter_address(priv, priv->net_dev->dev_addr))
- goto error;
-
- /* set basic system config settings */
- init_sys_config(&priv->sys_config);
-
- /* Support Bluetooth if we have BT h/w on board, and user wants to.
- * Does not support BT priority yet (don't abort or defer our Tx) */
- if (bt_coexist) {
- unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY];
-
- if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG)
- priv->sys_config.bt_coexistence
- |= CFG_BT_COEXISTENCE_SIGNAL_CHNL;
- if (bt_caps & EEPROM_SKU_CAP_BT_OOB)
- priv->sys_config.bt_coexistence
- |= CFG_BT_COEXISTENCE_OOB;
- }
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (priv->prom_net_dev && netif_running(priv->prom_net_dev)) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
- }
-#endif
-
- if (priv->ieee->iw_mode == IW_MODE_ADHOC)
- priv->sys_config.answer_broadcast_ssid_probe = 1;
- else
- priv->sys_config.answer_broadcast_ssid_probe = 0;
-
- if (ipw_send_system_config(priv))
- goto error;
-
- init_supported_rates(priv, &priv->rates);
- if (ipw_send_supported_rates(priv, &priv->rates))
- goto error;
-
- /* Set request-to-send threshold */
- if (priv->rts_threshold) {
- if (ipw_send_rts_threshold(priv, priv->rts_threshold))
- goto error;
- }
-#ifdef CONFIG_IPW2200_QOS
- IPW_DEBUG_QOS("QoS: call ipw_qos_activate\n");
- ipw_qos_activate(priv, NULL);
-#endif /* CONFIG_IPW2200_QOS */
-
- if (ipw_set_random_seed(priv))
- goto error;
-
- /* final state transition to the RUN state */
- if (ipw_send_host_complete(priv))
- goto error;
-
- priv->status |= STATUS_INIT;
-
- ipw_led_init(priv);
- ipw_led_radio_on(priv);
- priv->notif_missed_beacons = 0;
-
- /* Set hardware WEP key if it is configured. */
- if ((priv->capability & CAP_PRIVACY_ON) &&
- (priv->ieee->sec.level == SEC_LEVEL_1) &&
- !(priv->ieee->host_encrypt || priv->ieee->host_decrypt))
- ipw_set_hwcrypto_keys(priv);
-
- return 0;
-
- error:
- return -EIO;
-}
-
-/*
- * NOTE:
- *
- * These tables have been tested in conjunction with the
- * Intel PRO/Wireless 2200BG and 2915ABG Network Connection Adapters.
- *
- * Altering this values, using it on other hardware, or in geographies
- * not intended for resale of the above mentioned Intel adapters has
- * not been tested.
- *
- * Remember to update the table in README.ipw2200 when changing this
- * table.
- *
- */
-static const struct libipw_geo ipw_geos[] = {
- { /* Restricted */
- "---",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- },
-
- { /* Custom US/Canada */
- "ZZF",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 8,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Rest of World */
- "ZZD",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}},
- },
-
- { /* Custom USA & Europe & High */
- "ZZA",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149},
- {5765, 153},
- {5785, 157},
- {5805, 161},
- {5825, 165}},
- },
-
- { /* Custom NA & Europe */
- "ZZB",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Custom Japan */
- "ZZC",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 4,
- .a = {{5170, 34}, {5190, 38},
- {5210, 42}, {5230, 46}},
- },
-
- { /* Custom */
- "ZZM",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- },
-
- { /* Europe */
- "ZZE",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}},
- .a_channels = 19,
- .a = {{5180, 36},
- {5200, 40},
- {5220, 44},
- {5240, 48},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
- {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
- {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
- {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
- {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
- {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
- {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
- {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
- {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
- {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
- {5700, 140, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Custom Japan */
- "ZZJ",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY}},
- .a_channels = 4,
- .a = {{5170, 34}, {5190, 38},
- {5210, 42}, {5230, 46}},
- },
-
- { /* Rest of World */
- "ZZR",
- .bg_channels = 14,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}, {2467, 12},
- {2472, 13}, {2484, 14, LIBIPW_CH_B_ONLY |
- LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* High Band */
- "ZZH",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
- {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
- .a_channels = 4,
- .a = {{5745, 149}, {5765, 153},
- {5785, 157}, {5805, 161}},
- },
-
- { /* Custom Europe */
- "ZZG",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12}, {2472, 13}},
- .a_channels = 4,
- .a = {{5180, 36}, {5200, 40},
- {5220, 44}, {5240, 48}},
- },
-
- { /* Europe */
- "ZZK",
- .bg_channels = 13,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11},
- {2467, 12, LIBIPW_CH_PASSIVE_ONLY},
- {2472, 13, LIBIPW_CH_PASSIVE_ONLY}},
- .a_channels = 24,
- .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
- {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
- {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
- {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5500, 100, LIBIPW_CH_PASSIVE_ONLY},
- {5520, 104, LIBIPW_CH_PASSIVE_ONLY},
- {5540, 108, LIBIPW_CH_PASSIVE_ONLY},
- {5560, 112, LIBIPW_CH_PASSIVE_ONLY},
- {5580, 116, LIBIPW_CH_PASSIVE_ONLY},
- {5600, 120, LIBIPW_CH_PASSIVE_ONLY},
- {5620, 124, LIBIPW_CH_PASSIVE_ONLY},
- {5640, 128, LIBIPW_CH_PASSIVE_ONLY},
- {5660, 132, LIBIPW_CH_PASSIVE_ONLY},
- {5680, 136, LIBIPW_CH_PASSIVE_ONLY},
- {5700, 140, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- },
-
- { /* Europe */
- "ZZL",
- .bg_channels = 11,
- .bg = {{2412, 1}, {2417, 2}, {2422, 3},
- {2427, 4}, {2432, 5}, {2437, 6},
- {2442, 7}, {2447, 8}, {2452, 9},
- {2457, 10}, {2462, 11}},
- .a_channels = 13,
- .a = {{5180, 36, LIBIPW_CH_PASSIVE_ONLY},
- {5200, 40, LIBIPW_CH_PASSIVE_ONLY},
- {5220, 44, LIBIPW_CH_PASSIVE_ONLY},
- {5240, 48, LIBIPW_CH_PASSIVE_ONLY},
- {5260, 52, LIBIPW_CH_PASSIVE_ONLY},
- {5280, 56, LIBIPW_CH_PASSIVE_ONLY},
- {5300, 60, LIBIPW_CH_PASSIVE_ONLY},
- {5320, 64, LIBIPW_CH_PASSIVE_ONLY},
- {5745, 149, LIBIPW_CH_PASSIVE_ONLY},
- {5765, 153, LIBIPW_CH_PASSIVE_ONLY},
- {5785, 157, LIBIPW_CH_PASSIVE_ONLY},
- {5805, 161, LIBIPW_CH_PASSIVE_ONLY},
- {5825, 165, LIBIPW_CH_PASSIVE_ONLY}},
- }
-};
-
-static void ipw_set_geo(struct ipw_priv *priv)
-{
- int j;
-
- for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
- if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
- ipw_geos[j].name, 3))
- break;
- }
-
- if (j == ARRAY_SIZE(ipw_geos)) {
- IPW_WARNING("SKU [%c%c%c] not recognized.\n",
- priv->eeprom[EEPROM_COUNTRY_CODE + 0],
- priv->eeprom[EEPROM_COUNTRY_CODE + 1],
- priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
- j = 0;
- }
-
- libipw_set_geo(priv->ieee, &ipw_geos[j]);
-}
-
-#define MAX_HW_RESTARTS 5
-static int ipw_up(struct ipw_priv *priv)
-{
- int rc, i;
-
- /* Age scan list entries found before suspend */
- if (priv->suspend_time) {
- libipw_networks_age(priv->ieee, priv->suspend_time);
- priv->suspend_time = 0;
- }
-
- if (priv->status & STATUS_EXIT_PENDING)
- return -EIO;
-
- if (cmdlog && !priv->cmdlog) {
- priv->cmdlog = kcalloc(cmdlog, sizeof(*priv->cmdlog),
- GFP_KERNEL);
- if (priv->cmdlog == NULL) {
- IPW_ERROR("Error allocating %d command log entries.\n",
- cmdlog);
- return -ENOMEM;
- } else {
- priv->cmdlog_len = cmdlog;
- }
- }
-
- for (i = 0; i < MAX_HW_RESTARTS; i++) {
- /* Load the microcode, firmware, and eeprom.
- * Also start the clocks. */
- rc = ipw_load(priv);
- if (rc) {
- IPW_ERROR("Unable to load firmware: %d\n", rc);
- return rc;
- }
-
- ipw_init_ordinals(priv);
- if (!(priv->config & CFG_CUSTOM_MAC))
- eeprom_parse_mac(priv, priv->mac_addr);
- eth_hw_addr_set(priv->net_dev, priv->mac_addr);
-
- ipw_set_geo(priv);
-
- if (priv->status & STATUS_RF_KILL_SW) {
- IPW_WARNING("Radio disabled by module parameter.\n");
- return 0;
- } else if (rf_kill_active(priv)) {
- IPW_WARNING("Radio Frequency Kill Switch is On:\n"
- "Kill switch must be turned off for "
- "wireless networking to work.\n");
- schedule_delayed_work(&priv->rf_kill, 2 * HZ);
- return 0;
- }
-
- rc = ipw_config(priv);
- if (!rc) {
- IPW_DEBUG_INFO("Configured device on count %i\n", i);
-
- /* If configure to try and auto-associate, kick
- * off a scan. */
- schedule_delayed_work(&priv->request_scan, 0);
-
- return 0;
- }
-
- IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", rc);
- IPW_DEBUG_INFO("Failed to config device on retry %d of %d\n",
- i, MAX_HW_RESTARTS);
-
- /* We had an error bringing up the hardware, so take it
- * all the way back down so we can try again */
- ipw_down(priv);
- }
-
- /* tried to restart and config the device for as long as our
- * patience could withstand */
- IPW_ERROR("Unable to initialize device after %d attempts.\n", i);
-
- return -EIO;
-}
-
-static void ipw_bg_up(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, up);
- mutex_lock(&priv->mutex);
- ipw_up(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void ipw_deinit(struct ipw_priv *priv)
-{
- int i;
-
- if (priv->status & STATUS_SCANNING) {
- IPW_DEBUG_INFO("Aborting scan during shutdown.\n");
- ipw_abort_scan(priv);
- }
-
- if (priv->status & STATUS_ASSOCIATED) {
- IPW_DEBUG_INFO("Disassociating during shutdown.\n");
- ipw_disassociate(priv);
- }
-
- ipw_led_shutdown(priv);
-
- /* Wait up to 1s for status to change to not scanning and not
- * associated (disassociation can take a while for a ful 802.11
- * exchange */
- for (i = 1000; i && (priv->status &
- (STATUS_DISASSOCIATING |
- STATUS_ASSOCIATED | STATUS_SCANNING)); i--)
- udelay(10);
-
- if (priv->status & (STATUS_DISASSOCIATING |
- STATUS_ASSOCIATED | STATUS_SCANNING))
- IPW_DEBUG_INFO("Still associated or scanning...\n");
- else
- IPW_DEBUG_INFO("Took %dms to de-init\n", 1000 - i);
-
- /* Attempt to disable the card */
- ipw_send_card_disable(priv, 0);
-
- priv->status &= ~STATUS_INIT;
-}
-
-static void ipw_down(struct ipw_priv *priv)
-{
- int exit_pending = priv->status & STATUS_EXIT_PENDING;
-
- priv->status |= STATUS_EXIT_PENDING;
-
- if (ipw_is_init(priv))
- ipw_deinit(priv);
-
- /* Wipe out the EXIT_PENDING status bit if we are not actually
- * exiting the module */
- if (!exit_pending)
- priv->status &= ~STATUS_EXIT_PENDING;
-
- /* tell the device to stop sending interrupts */
- ipw_disable_interrupts(priv);
-
- /* Clear all bits but the RF Kill */
- priv->status &= STATUS_RF_KILL_MASK | STATUS_EXIT_PENDING;
- netif_carrier_off(priv->net_dev);
-
- ipw_stop_nic(priv);
-
- ipw_led_radio_off(priv);
-}
-
-static void ipw_bg_down(struct work_struct *work)
-{
- struct ipw_priv *priv =
- container_of(work, struct ipw_priv, down);
- mutex_lock(&priv->mutex);
- ipw_down(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static int ipw_wdev_init(struct net_device *dev)
-{
- int i, rc = 0;
- struct ipw_priv *priv = libipw_priv(dev);
- const struct libipw_geo *geo = libipw_get_geo(priv->ieee);
- struct wireless_dev *wdev = &priv->ieee->wdev;
-
- memcpy(wdev->wiphy->perm_addr, priv->mac_addr, ETH_ALEN);
-
- /* fill-out priv->ieee->bg_band */
- if (geo->bg_channels) {
- struct ieee80211_supported_band *bg_band = &priv->ieee->bg_band;
-
- bg_band->band = NL80211_BAND_2GHZ;
- bg_band->n_channels = geo->bg_channels;
- bg_band->channels = kcalloc(geo->bg_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!bg_band->channels) {
- rc = -ENOMEM;
- goto out;
- }
- /* translate geo->bg to bg_band.channels */
- for (i = 0; i < geo->bg_channels; i++) {
- bg_band->channels[i].band = NL80211_BAND_2GHZ;
- bg_band->channels[i].center_freq = geo->bg[i].freq;
- bg_band->channels[i].hw_value = geo->bg[i].channel;
- bg_band->channels[i].max_power = geo->bg[i].max_power;
- if (geo->bg[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_NO_IBSS)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->bg[i].flags & LIBIPW_CH_RADAR_DETECT)
- bg_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- bg_band->bitrates = ipw2200_bg_rates;
- bg_band->n_bitrates = ipw2200_num_bg_rates;
-
- wdev->wiphy->bands[NL80211_BAND_2GHZ] = bg_band;
- }
-
- /* fill-out priv->ieee->a_band */
- if (geo->a_channels) {
- struct ieee80211_supported_band *a_band = &priv->ieee->a_band;
-
- a_band->band = NL80211_BAND_5GHZ;
- a_band->n_channels = geo->a_channels;
- a_band->channels = kcalloc(geo->a_channels,
- sizeof(struct ieee80211_channel),
- GFP_KERNEL);
- if (!a_band->channels) {
- rc = -ENOMEM;
- goto out;
- }
- /* translate geo->a to a_band.channels */
- for (i = 0; i < geo->a_channels; i++) {
- a_band->channels[i].band = NL80211_BAND_5GHZ;
- a_band->channels[i].center_freq = geo->a[i].freq;
- a_band->channels[i].hw_value = geo->a[i].channel;
- a_band->channels[i].max_power = geo->a[i].max_power;
- if (geo->a[i].flags & LIBIPW_CH_PASSIVE_ONLY)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->a[i].flags & LIBIPW_CH_NO_IBSS)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_NO_IR;
- if (geo->a[i].flags & LIBIPW_CH_RADAR_DETECT)
- a_band->channels[i].flags |=
- IEEE80211_CHAN_RADAR;
- /* No equivalent for LIBIPW_CH_80211H_RULES,
- LIBIPW_CH_UNIFORM_SPREADING, or
- LIBIPW_CH_B_ONLY... */
- }
- /* point at bitrate info */
- a_band->bitrates = ipw2200_a_rates;
- a_band->n_bitrates = ipw2200_num_a_rates;
-
- wdev->wiphy->bands[NL80211_BAND_5GHZ] = a_band;
- }
-
- wdev->wiphy->cipher_suites = ipw_cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(ipw_cipher_suites);
-
- set_wiphy_dev(wdev->wiphy, &priv->pci_dev->dev);
-
- /* With that information in place, we can now register the wiphy... */
- rc = wiphy_register(wdev->wiphy);
- if (rc)
- goto out;
-
- return 0;
-out:
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- return rc;
-}
-
-/* PCI driver stuff */
-static const struct pci_device_id card_ids[] = {
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2701, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2702, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2711, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2712, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2721, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2722, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2731, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2732, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2741, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x103c, 0x2741, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2742, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2751, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2752, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2753, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2754, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2761, 0, 0, 0},
- {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0},
- {PCI_VDEVICE(INTEL, 0x104f), 0},
- {PCI_VDEVICE(INTEL, 0x4220), 0}, /* BG */
- {PCI_VDEVICE(INTEL, 0x4221), 0}, /* BG */
- {PCI_VDEVICE(INTEL, 0x4223), 0}, /* ABG */
- {PCI_VDEVICE(INTEL, 0x4224), 0}, /* ABG */
-
- /* required last entry */
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, card_ids);
-
-static struct attribute *ipw_sysfs_entries[] = {
- &dev_attr_rf_kill.attr,
- &dev_attr_direct_dword.attr,
- &dev_attr_indirect_byte.attr,
- &dev_attr_indirect_dword.attr,
- &dev_attr_mem_gpio_reg.attr,
- &dev_attr_command_event_reg.attr,
- &dev_attr_nic_type.attr,
- &dev_attr_status.attr,
- &dev_attr_cfg.attr,
- &dev_attr_error.attr,
- &dev_attr_event_log.attr,
- &dev_attr_cmd_log.attr,
- &dev_attr_eeprom_delay.attr,
- &dev_attr_ucode_version.attr,
- &dev_attr_rtc.attr,
- &dev_attr_scan_age.attr,
- &dev_attr_led.attr,
- &dev_attr_speed_scan.attr,
- &dev_attr_net_stats.attr,
- &dev_attr_channels.attr,
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- &dev_attr_rtap_iface.attr,
- &dev_attr_rtap_filter.attr,
-#endif
- NULL
-};
-
-static const struct attribute_group ipw_attribute_group = {
- .name = NULL, /* put in device directory */
- .attrs = ipw_sysfs_entries,
-};
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-static int ipw_prom_open(struct net_device *dev)
-{
- struct ipw_prom_priv *prom_priv = libipw_priv(dev);
- struct ipw_priv *priv = prom_priv->priv;
-
- IPW_DEBUG_INFO("prom dev->open\n");
- netif_carrier_off(dev);
-
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- priv->sys_config.accept_all_data_frames = 1;
- priv->sys_config.accept_non_directed_frames = 1;
- priv->sys_config.accept_all_mgmt_bcpr = 1;
- priv->sys_config.accept_all_mgmt_frames = 1;
-
- ipw_send_system_config(priv);
- }
-
- return 0;
-}
-
-static int ipw_prom_stop(struct net_device *dev)
-{
- struct ipw_prom_priv *prom_priv = libipw_priv(dev);
- struct ipw_priv *priv = prom_priv->priv;
-
- IPW_DEBUG_INFO("prom dev->stop\n");
-
- if (priv->ieee->iw_mode != IW_MODE_MONITOR) {
- priv->sys_config.accept_all_data_frames = 0;
- priv->sys_config.accept_non_directed_frames = 0;
- priv->sys_config.accept_all_mgmt_bcpr = 0;
- priv->sys_config.accept_all_mgmt_frames = 0;
-
- ipw_send_system_config(priv);
- }
-
- return 0;
-}
-
-static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- IPW_DEBUG_INFO("prom dev->xmit\n");
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static const struct net_device_ops ipw_prom_netdev_ops = {
- .ndo_open = ipw_prom_open,
- .ndo_stop = ipw_prom_stop,
- .ndo_start_xmit = ipw_prom_hard_start_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ipw_prom_alloc(struct ipw_priv *priv)
-{
- int rc = 0;
-
- if (priv->prom_net_dev)
- return -EPERM;
-
- priv->prom_net_dev = alloc_libipw(sizeof(struct ipw_prom_priv), 1);
- if (priv->prom_net_dev == NULL)
- return -ENOMEM;
-
- priv->prom_priv = libipw_priv(priv->prom_net_dev);
- priv->prom_priv->ieee = netdev_priv(priv->prom_net_dev);
- priv->prom_priv->priv = priv;
-
- strcpy(priv->prom_net_dev->name, "rtap%d");
- eth_hw_addr_set(priv->prom_net_dev, priv->mac_addr);
-
- priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
- priv->prom_net_dev->netdev_ops = &ipw_prom_netdev_ops;
-
- priv->prom_net_dev->min_mtu = 68;
- priv->prom_net_dev->max_mtu = LIBIPW_DATA_LEN;
-
- priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;
- SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev);
-
- rc = register_netdev(priv->prom_net_dev);
- if (rc) {
- free_libipw(priv->prom_net_dev, 1);
- priv->prom_net_dev = NULL;
- return rc;
- }
-
- return 0;
-}
-
-static void ipw_prom_free(struct ipw_priv *priv)
-{
- if (!priv->prom_net_dev)
- return;
-
- unregister_netdev(priv->prom_net_dev);
- free_libipw(priv->prom_net_dev, 1);
-
- priv->prom_net_dev = NULL;
-}
-
-#endif
-
-static const struct net_device_ops ipw_netdev_ops = {
- .ndo_open = ipw_net_open,
- .ndo_stop = ipw_net_stop,
- .ndo_set_rx_mode = ipw_net_set_multicast_list,
- .ndo_set_mac_address = ipw_net_set_mac_address,
- .ndo_start_xmit = libipw_xmit,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ipw_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int err = 0;
- struct net_device *net_dev;
- void __iomem *base;
- u32 length, val;
- struct ipw_priv *priv;
- int i;
-
- net_dev = alloc_libipw(sizeof(struct ipw_priv), 0);
- if (net_dev == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- priv = libipw_priv(net_dev);
- priv->ieee = netdev_priv(net_dev);
-
- priv->net_dev = net_dev;
- priv->pci_dev = pdev;
- ipw_debug_level = debug;
- spin_lock_init(&priv->irq_lock);
- spin_lock_init(&priv->lock);
- for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
- INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
-
- mutex_init(&priv->mutex);
- if (pci_enable_device(pdev)) {
- err = -ENODEV;
- goto out_free_libipw;
- }
-
- pci_set_master(pdev);
-
- err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (!err)
- err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
- if (err) {
- printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
- goto out_pci_disable_device;
- }
-
- pci_set_drvdata(pdev, priv);
-
- err = pci_request_regions(pdev, DRV_NAME);
- if (err)
- goto out_pci_disable_device;
-
- /* We disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- length = pci_resource_len(pdev, 0);
- priv->hw_len = length;
-
- base = pci_ioremap_bar(pdev, 0);
- if (!base) {
- err = -ENODEV;
- goto out_pci_release_regions;
- }
-
- priv->hw_base = base;
- IPW_DEBUG_INFO("pci_resource_len = 0x%08x\n", length);
- IPW_DEBUG_INFO("pci_resource_base = %p\n", base);
-
- ipw_setup_deferred_work(priv);
-
- ipw_sw_reset(priv, 1);
-
- err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv);
- if (err) {
- IPW_ERROR("Error allocating IRQ %d\n", pdev->irq);
- goto out_iounmap;
- }
-
- SET_NETDEV_DEV(net_dev, &pdev->dev);
-
- mutex_lock(&priv->mutex);
-
- priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit;
- priv->ieee->set_security = shim__set_security;
- priv->ieee->is_queue_full = ipw_net_is_queue_full;
-
-#ifdef CONFIG_IPW2200_QOS
- priv->ieee->is_qos_active = ipw_is_qos_active;
- priv->ieee->handle_probe_response = ipw_handle_beacon;
- priv->ieee->handle_beacon = ipw_handle_probe_response;
- priv->ieee->handle_assoc_response = ipw_handle_assoc_response;
-#endif /* CONFIG_IPW2200_QOS */
-
- priv->ieee->perfect_rssi = -20;
- priv->ieee->worst_rssi = -85;
-
- net_dev->netdev_ops = &ipw_netdev_ops;
- priv->wireless_data.spy_data = &priv->ieee->spy_data;
- net_dev->wireless_data = &priv->wireless_data;
- net_dev->wireless_handlers = &ipw_wx_handler_def;
- net_dev->ethtool_ops = &ipw_ethtool_ops;
-
- net_dev->min_mtu = 68;
- net_dev->max_mtu = LIBIPW_DATA_LEN;
-
- err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group);
- if (err) {
- IPW_ERROR("failed to create sysfs device attributes\n");
- mutex_unlock(&priv->mutex);
- goto out_release_irq;
- }
-
- if (ipw_up(priv)) {
- mutex_unlock(&priv->mutex);
- err = -EIO;
- goto out_remove_sysfs;
- }
-
- mutex_unlock(&priv->mutex);
-
- err = ipw_wdev_init(net_dev);
- if (err) {
- IPW_ERROR("failed to register wireless device\n");
- goto out_remove_sysfs;
- }
-
- err = register_netdev(net_dev);
- if (err) {
- IPW_ERROR("failed to register network device\n");
- goto out_unregister_wiphy;
- }
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- if (rtap_iface) {
- err = ipw_prom_alloc(priv);
- if (err) {
- IPW_ERROR("Failed to register promiscuous network "
- "device (error %d).\n", err);
- unregister_netdev(priv->net_dev);
- goto out_unregister_wiphy;
- }
- }
-#endif
-
- printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg "
- "channels, %d 802.11a channels)\n",
- priv->ieee->geo.name, priv->ieee->geo.bg_channels,
- priv->ieee->geo.a_channels);
-
- return 0;
-
- out_unregister_wiphy:
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- out_remove_sysfs:
- sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
- out_release_irq:
- free_irq(pdev->irq, priv);
- out_iounmap:
- iounmap(priv->hw_base);
- out_pci_release_regions:
- pci_release_regions(pdev);
- out_pci_disable_device:
- pci_disable_device(pdev);
- out_free_libipw:
- free_libipw(priv->net_dev, 0);
- out:
- return err;
-}
-
-static void ipw_pci_remove(struct pci_dev *pdev)
-{
- struct ipw_priv *priv = pci_get_drvdata(pdev);
- struct list_head *p, *q;
- int i;
-
- if (!priv)
- return;
-
- mutex_lock(&priv->mutex);
-
- priv->status |= STATUS_EXIT_PENDING;
- ipw_down(priv);
- sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group);
-
- mutex_unlock(&priv->mutex);
-
- unregister_netdev(priv->net_dev);
-
- if (priv->rxq) {
- ipw_rx_queue_free(priv, priv->rxq);
- priv->rxq = NULL;
- }
- ipw_tx_queue_free(priv);
-
- if (priv->cmdlog) {
- kfree(priv->cmdlog);
- priv->cmdlog = NULL;
- }
-
- /* make sure all works are inactive */
- cancel_delayed_work_sync(&priv->adhoc_check);
- cancel_work_sync(&priv->associate);
- cancel_work_sync(&priv->disassociate);
- cancel_work_sync(&priv->system_config);
- cancel_work_sync(&priv->rx_replenish);
- cancel_work_sync(&priv->adapter_restart);
- cancel_delayed_work_sync(&priv->rf_kill);
- cancel_work_sync(&priv->up);
- cancel_work_sync(&priv->down);
- cancel_delayed_work_sync(&priv->request_scan);
- cancel_delayed_work_sync(&priv->request_direct_scan);
- cancel_delayed_work_sync(&priv->request_passive_scan);
- cancel_delayed_work_sync(&priv->scan_event);
- cancel_delayed_work_sync(&priv->gather_stats);
- cancel_work_sync(&priv->abort_scan);
- cancel_work_sync(&priv->roam);
- cancel_delayed_work_sync(&priv->scan_check);
- cancel_work_sync(&priv->link_up);
- cancel_work_sync(&priv->link_down);
- cancel_delayed_work_sync(&priv->led_link_on);
- cancel_delayed_work_sync(&priv->led_link_off);
- cancel_delayed_work_sync(&priv->led_act_off);
- cancel_work_sync(&priv->merge_networks);
-
- /* Free MAC hash list for ADHOC */
- for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) {
- list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
- list_del(p);
- kfree(list_entry(p, struct ipw_ibss_seq, list));
- }
- }
-
- kfree(priv->error);
- priv->error = NULL;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- ipw_prom_free(priv);
-#endif
-
- free_irq(pdev->irq, priv);
- iounmap(priv->hw_base);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
- /* wiphy_unregister needs to be here, before free_libipw */
- wiphy_unregister(priv->ieee->wdev.wiphy);
- kfree(priv->ieee->a_band.channels);
- kfree(priv->ieee->bg_band.channels);
- free_libipw(priv->net_dev, 0);
- free_firmware();
-}
-
-static int __maybe_unused ipw_pci_suspend(struct device *dev_d)
-{
- struct ipw_priv *priv = dev_get_drvdata(dev_d);
- struct net_device *dev = priv->net_dev;
-
- printk(KERN_INFO "%s: Going into suspend...\n", dev->name);
-
- /* Take down the device; powers it off, etc. */
- ipw_down(priv);
-
- /* Remove the PRESENT state of the device */
- netif_device_detach(dev);
-
- priv->suspend_at = ktime_get_boottime_seconds();
-
- return 0;
-}
-
-static int __maybe_unused ipw_pci_resume(struct device *dev_d)
-{
- struct pci_dev *pdev = to_pci_dev(dev_d);
- struct ipw_priv *priv = pci_get_drvdata(pdev);
- struct net_device *dev = priv->net_dev;
- u32 val;
-
- printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name);
-
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
- * from interfering with C3 CPU state. pci_restore_state won't help
- * here since it only restores the first 64 bytes pci config header.
- */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- /* Set the device back into the PRESENT state; this will also wake
- * the queue of needed */
- netif_device_attach(dev);
-
- priv->suspend_time = ktime_get_boottime_seconds() - priv->suspend_at;
-
- /* Bring the device back up */
- schedule_work(&priv->up);
-
- return 0;
-}
-
-static void ipw_pci_shutdown(struct pci_dev *pdev)
-{
- struct ipw_priv *priv = pci_get_drvdata(pdev);
-
- /* Take down the device; powers it off, etc. */
- ipw_down(priv);
-
- pci_disable_device(pdev);
-}
-
-static SIMPLE_DEV_PM_OPS(ipw_pci_pm_ops, ipw_pci_suspend, ipw_pci_resume);
-
-/* driver initialization stuff */
-static struct pci_driver ipw_driver = {
- .name = DRV_NAME,
- .id_table = card_ids,
- .probe = ipw_pci_probe,
- .remove = ipw_pci_remove,
- .driver.pm = &ipw_pci_pm_ops,
- .shutdown = ipw_pci_shutdown,
-};
-
-static int __init ipw_init(void)
-{
- int ret;
-
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-
- ret = pci_register_driver(&ipw_driver);
- if (ret) {
- IPW_ERROR("Unable to initialize PCI module\n");
- return ret;
- }
-
- ret = driver_create_file(&ipw_driver.driver, &driver_attr_debug_level);
- if (ret) {
- IPW_ERROR("Unable to create driver sysfs file\n");
- pci_unregister_driver(&ipw_driver);
- return ret;
- }
-
- return ret;
-}
-
-static void __exit ipw_exit(void)
-{
- driver_remove_file(&ipw_driver.driver, &driver_attr_debug_level);
- pci_unregister_driver(&ipw_driver);
-}
-
-module_param(disable, int, 0444);
-MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
-
-module_param(associate, int, 0444);
-MODULE_PARM_DESC(associate, "auto associate when scanning (default off)");
-
-module_param(auto_create, int, 0444);
-MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)");
-
-module_param_named(led, led_support, int, 0444);
-MODULE_PARM_DESC(led, "enable led control on some systems (default 1 on)");
-
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
-
-module_param_named(channel, default_channel, int, 0444);
-MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-module_param(rtap_iface, int, 0444);
-MODULE_PARM_DESC(rtap_iface, "create the rtap interface (1 - create, default 0)");
-#endif
-
-#ifdef CONFIG_IPW2200_QOS
-module_param(qos_enable, int, 0444);
-MODULE_PARM_DESC(qos_enable, "enable all QoS functionalities");
-
-module_param(qos_burst_enable, int, 0444);
-MODULE_PARM_DESC(qos_burst_enable, "enable QoS burst mode");
-
-module_param(qos_no_ack_mask, int, 0444);
-MODULE_PARM_DESC(qos_no_ack_mask, "mask Tx_Queue to no ack");
-
-module_param(burst_duration_CCK, int, 0444);
-MODULE_PARM_DESC(burst_duration_CCK, "set CCK burst value");
-
-module_param(burst_duration_OFDM, int, 0444);
-MODULE_PARM_DESC(burst_duration_OFDM, "set OFDM burst value");
-#endif /* CONFIG_IPW2200_QOS */
-
-#ifdef CONFIG_IPW2200_MONITOR
-module_param_named(mode, network_mode, int, 0444);
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)");
-#else
-module_param_named(mode, network_mode, int, 0444);
-MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)");
-#endif
-
-module_param(bt_coexist, int, 0444);
-MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)");
-
-module_param(hwcrypto, int, 0444);
-MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)");
-
-module_param(cmdlog, int, 0444);
-MODULE_PARM_DESC(cmdlog,
- "allocate a ring buffer for logging firmware commands");
-
-module_param(roaming, int, 0444);
-MODULE_PARM_DESC(roaming, "enable roaming support (default on)");
-
-module_param(antenna, int, 0444);
-MODULE_PARM_DESC(antenna, "select antenna 1=Main, 3=Aux, default 0 [both], 2=slow_diversity (choose the one with lower background noise)");
-
-module_exit(ipw_exit);
-module_init(ipw_init);
diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.h b/drivers/net/wireless/intel/ipw2x00/ipw2200.h
deleted file mode 100644
index 8ebf09121e173..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.h
+++ /dev/null
@@ -1,1984 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/******************************************************************************
-
- Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#ifndef __ipw2200_h__
-#define __ipw2200_h__
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/ethtool.h>
-#include <linux/skbuff.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/random.h>
-#include <linux/dma-mapping.h>
-
-#include <linux/firmware.h>
-#include <linux/wireless.h>
-#include <linux/jiffies.h>
-#include <asm/io.h>
-
-#include <net/lib80211.h>
-#include <net/ieee80211_radiotap.h>
-
-#define DRV_NAME "ipw2200"
-
-#include <linux/workqueue.h>
-
-#include "libipw.h"
-
-/* Authentication and Association States */
-enum connection_manager_assoc_states {
- CMAS_INIT = 0,
- CMAS_TX_AUTH_SEQ_1,
- CMAS_RX_AUTH_SEQ_2,
- CMAS_AUTH_SEQ_1_PASS,
- CMAS_AUTH_SEQ_1_FAIL,
- CMAS_TX_AUTH_SEQ_3,
- CMAS_RX_AUTH_SEQ_4,
- CMAS_AUTH_SEQ_2_PASS,
- CMAS_AUTH_SEQ_2_FAIL,
- CMAS_AUTHENTICATED,
- CMAS_TX_ASSOC,
- CMAS_RX_ASSOC_RESP,
- CMAS_ASSOCIATED,
- CMAS_LAST
-};
-
-#define IPW_WAIT (1<<0)
-#define IPW_QUIET (1<<1)
-#define IPW_ROAMING (1<<2)
-
-#define IPW_POWER_MODE_CAM 0x00 //(always on)
-#define IPW_POWER_INDEX_1 0x01
-#define IPW_POWER_INDEX_2 0x02
-#define IPW_POWER_INDEX_3 0x03
-#define IPW_POWER_INDEX_4 0x04
-#define IPW_POWER_INDEX_5 0x05
-#define IPW_POWER_AC 0x06
-#define IPW_POWER_BATTERY 0x07
-#define IPW_POWER_LIMIT 0x07
-#define IPW_POWER_MASK 0x0F
-#define IPW_POWER_ENABLED 0x10
-#define IPW_POWER_LEVEL(x) ((x) & IPW_POWER_MASK)
-
-#define IPW_CMD_HOST_COMPLETE 2
-#define IPW_CMD_POWER_DOWN 4
-#define IPW_CMD_SYSTEM_CONFIG 6
-#define IPW_CMD_MULTICAST_ADDRESS 7
-#define IPW_CMD_SSID 8
-#define IPW_CMD_ADAPTER_ADDRESS 11
-#define IPW_CMD_PORT_TYPE 12
-#define IPW_CMD_RTS_THRESHOLD 15
-#define IPW_CMD_FRAG_THRESHOLD 16
-#define IPW_CMD_POWER_MODE 17
-#define IPW_CMD_WEP_KEY 18
-#define IPW_CMD_TGI_TX_KEY 19
-#define IPW_CMD_SCAN_REQUEST 20
-#define IPW_CMD_ASSOCIATE 21
-#define IPW_CMD_SUPPORTED_RATES 22
-#define IPW_CMD_SCAN_ABORT 23
-#define IPW_CMD_TX_FLUSH 24
-#define IPW_CMD_QOS_PARAMETERS 25
-#define IPW_CMD_SCAN_REQUEST_EXT 26
-#define IPW_CMD_DINO_CONFIG 30
-#define IPW_CMD_RSN_CAPABILITIES 31
-#define IPW_CMD_RX_KEY 32
-#define IPW_CMD_CARD_DISABLE 33
-#define IPW_CMD_SEED_NUMBER 34
-#define IPW_CMD_TX_POWER 35
-#define IPW_CMD_COUNTRY_INFO 36
-#define IPW_CMD_AIRONET_INFO 37
-#define IPW_CMD_AP_TX_POWER 38
-#define IPW_CMD_CCKM_INFO 39
-#define IPW_CMD_CCX_VER_INFO 40
-#define IPW_CMD_SET_CALIBRATION 41
-#define IPW_CMD_SENSITIVITY_CALIB 42
-#define IPW_CMD_RETRY_LIMIT 51
-#define IPW_CMD_IPW_PRE_POWER_DOWN 58
-#define IPW_CMD_VAP_BEACON_TEMPLATE 60
-#define IPW_CMD_VAP_DTIM_PERIOD 61
-#define IPW_CMD_EXT_SUPPORTED_RATES 62
-#define IPW_CMD_VAP_LOCAL_TX_PWR_CONSTRAINT 63
-#define IPW_CMD_VAP_QUIET_INTERVALS 64
-#define IPW_CMD_VAP_CHANNEL_SWITCH 65
-#define IPW_CMD_VAP_MANDATORY_CHANNELS 66
-#define IPW_CMD_VAP_CELL_PWR_LIMIT 67
-#define IPW_CMD_VAP_CF_PARAM_SET 68
-#define IPW_CMD_VAP_SET_BEACONING_STATE 69
-#define IPW_CMD_MEASUREMENT 80
-#define IPW_CMD_POWER_CAPABILITY 81
-#define IPW_CMD_SUPPORTED_CHANNELS 82
-#define IPW_CMD_TPC_REPORT 83
-#define IPW_CMD_WME_INFO 84
-#define IPW_CMD_PRODUCTION_COMMAND 85
-#define IPW_CMD_LINKSYS_EOU_INFO 90
-
-#define RFD_SIZE 4
-#define NUM_TFD_CHUNKS 6
-
-#define TX_QUEUE_SIZE 32
-#define RX_QUEUE_SIZE 32
-
-#define DINO_CMD_WEP_KEY 0x08
-#define DINO_CMD_TX 0x0B
-#define DCT_ANTENNA_A 0x01
-#define DCT_ANTENNA_B 0x02
-
-#define IPW_A_MODE 0
-#define IPW_B_MODE 1
-#define IPW_G_MODE 2
-
-/*
- * TX Queue Flag Definitions
- */
-
-/* tx wep key definition */
-#define DCT_WEP_KEY_NOT_IMMIDIATE 0x00
-#define DCT_WEP_KEY_64Bit 0x40
-#define DCT_WEP_KEY_128Bit 0x80
-#define DCT_WEP_KEY_128bitIV 0xC0
-#define DCT_WEP_KEY_SIZE_MASK 0xC0
-
-#define DCT_WEP_KEY_INDEX_MASK 0x0F
-#define DCT_WEP_INDEX_USE_IMMEDIATE 0x20
-
-/* abort attempt if mgmt frame is rx'd */
-#define DCT_FLAG_ABORT_MGMT 0x01
-
-/* require CTS */
-#define DCT_FLAG_CTS_REQUIRED 0x02
-
-/* use short preamble */
-#define DCT_FLAG_LONG_PREAMBLE 0x00
-#define DCT_FLAG_SHORT_PREAMBLE 0x04
-
-/* RTS/CTS first */
-#define DCT_FLAG_RTS_REQD 0x08
-
-/* dont calculate duration field */
-#define DCT_FLAG_DUR_SET 0x10
-
-/* even if MAC WEP set (allows pre-encrypt) */
-#define DCT_FLAG_NO_WEP 0x20
-
-/* overwrite TSF field */
-#define DCT_FLAG_TSF_REQD 0x40
-
-/* ACK rx is expected to follow */
-#define DCT_FLAG_ACK_REQD 0x80
-
-/* TX flags extension */
-#define DCT_FLAG_EXT_MODE_CCK 0x01
-#define DCT_FLAG_EXT_MODE_OFDM 0x00
-
-#define DCT_FLAG_EXT_SECURITY_WEP 0x00
-#define DCT_FLAG_EXT_SECURITY_NO DCT_FLAG_EXT_SECURITY_WEP
-#define DCT_FLAG_EXT_SECURITY_CKIP 0x04
-#define DCT_FLAG_EXT_SECURITY_CCM 0x08
-#define DCT_FLAG_EXT_SECURITY_TKIP 0x0C
-#define DCT_FLAG_EXT_SECURITY_MASK 0x0C
-
-#define DCT_FLAG_EXT_QOS_ENABLED 0x10
-
-#define DCT_FLAG_EXT_HC_NO_SIFS_PIFS 0x00
-#define DCT_FLAG_EXT_HC_SIFS 0x20
-#define DCT_FLAG_EXT_HC_PIFS 0x40
-
-#define TX_RX_TYPE_MASK 0xFF
-#define TX_FRAME_TYPE 0x00
-#define TX_HOST_COMMAND_TYPE 0x01
-#define RX_FRAME_TYPE 0x09
-#define RX_HOST_NOTIFICATION_TYPE 0x03
-#define RX_HOST_CMD_RESPONSE_TYPE 0x04
-#define RX_TX_FRAME_RESPONSE_TYPE 0x05
-#define TFD_NEED_IRQ_MASK 0x04
-
-#define HOST_CMD_DINO_CONFIG 30
-
-#define HOST_NOTIFICATION_STATUS_ASSOCIATED 10
-#define HOST_NOTIFICATION_STATUS_AUTHENTICATE 11
-#define HOST_NOTIFICATION_STATUS_SCAN_CHANNEL_RESULT 12
-#define HOST_NOTIFICATION_STATUS_SCAN_COMPLETED 13
-#define HOST_NOTIFICATION_STATUS_FRAG_LENGTH 14
-#define HOST_NOTIFICATION_STATUS_LINK_DETERIORATION 15
-#define HOST_NOTIFICATION_DINO_CONFIG_RESPONSE 16
-#define HOST_NOTIFICATION_STATUS_BEACON_STATE 17
-#define HOST_NOTIFICATION_STATUS_TGI_TX_KEY 18
-#define HOST_NOTIFICATION_TX_STATUS 19
-#define HOST_NOTIFICATION_CALIB_KEEP_RESULTS 20
-#define HOST_NOTIFICATION_MEASUREMENT_STARTED 21
-#define HOST_NOTIFICATION_MEASUREMENT_ENDED 22
-#define HOST_NOTIFICATION_CHANNEL_SWITCHED 23
-#define HOST_NOTIFICATION_RX_DURING_QUIET_PERIOD 24
-#define HOST_NOTIFICATION_NOISE_STATS 25
-#define HOST_NOTIFICATION_S36_MEASUREMENT_ACCEPTED 30
-#define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31
-
-#define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1
-#define IPW_MB_SCAN_CANCEL_THRESHOLD 3
-#define IPW_MB_ROAMING_THRESHOLD_MIN 1
-#define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8
-#define IPW_MB_ROAMING_THRESHOLD_MAX 30
-#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 3*IPW_MB_ROAMING_THRESHOLD_DEFAULT
-#define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300
-
-#define MACADRR_BYTE_LEN 6
-
-#define DCR_TYPE_AP 0x01
-#define DCR_TYPE_WLAP 0x02
-#define DCR_TYPE_MU_ESS 0x03
-#define DCR_TYPE_MU_IBSS 0x04
-#define DCR_TYPE_MU_PIBSS 0x05
-#define DCR_TYPE_SNIFFER 0x06
-#define DCR_TYPE_MU_BSS DCR_TYPE_MU_ESS
-
-/* QoS definitions */
-
-#define CW_MIN_OFDM 15
-#define CW_MAX_OFDM 1023
-#define CW_MIN_CCK 31
-#define CW_MAX_CCK 1023
-
-#define QOS_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX2_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
-#define QOS_TX3_CW_MIN_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/4 - 1)
-
-#define QOS_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX2_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
-#define QOS_TX3_CW_MIN_CCK cpu_to_le16((CW_MIN_CCK + 1)/4 - 1)
-
-#define QOS_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define QOS_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define QOS_TX2_CW_MAX_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define QOS_TX3_CW_MAX_OFDM cpu_to_le16((CW_MIN_OFDM + 1)/2 - 1)
-
-#define QOS_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define QOS_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define QOS_TX2_CW_MAX_CCK cpu_to_le16(CW_MIN_CCK)
-#define QOS_TX3_CW_MAX_CCK cpu_to_le16((CW_MIN_CCK + 1)/2 - 1)
-
-#define QOS_TX0_AIFS (3 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX1_AIFS (7 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX2_AIFS (2 - QOS_AIFSN_MIN_VALUE)
-#define QOS_TX3_AIFS (2 - QOS_AIFSN_MIN_VALUE)
-
-#define QOS_TX0_ACM 0
-#define QOS_TX1_ACM 0
-#define QOS_TX2_ACM 0
-#define QOS_TX3_ACM 0
-
-#define QOS_TX0_TXOP_LIMIT_CCK 0
-#define QOS_TX1_TXOP_LIMIT_CCK 0
-#define QOS_TX2_TXOP_LIMIT_CCK cpu_to_le16(6016)
-#define QOS_TX3_TXOP_LIMIT_CCK cpu_to_le16(3264)
-
-#define QOS_TX0_TXOP_LIMIT_OFDM 0
-#define QOS_TX1_TXOP_LIMIT_OFDM 0
-#define QOS_TX2_TXOP_LIMIT_OFDM cpu_to_le16(3008)
-#define QOS_TX3_TXOP_LIMIT_OFDM cpu_to_le16(1504)
-
-#define DEF_TX0_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX1_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX2_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-#define DEF_TX3_CW_MIN_OFDM cpu_to_le16(CW_MIN_OFDM)
-
-#define DEF_TX0_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX1_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX2_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-#define DEF_TX3_CW_MIN_CCK cpu_to_le16(CW_MIN_CCK)
-
-#define DEF_TX0_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX1_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX2_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-#define DEF_TX3_CW_MAX_OFDM cpu_to_le16(CW_MAX_OFDM)
-
-#define DEF_TX0_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX1_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX2_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-#define DEF_TX3_CW_MAX_CCK cpu_to_le16(CW_MAX_CCK)
-
-#define DEF_TX0_AIFS 0
-#define DEF_TX1_AIFS 0
-#define DEF_TX2_AIFS 0
-#define DEF_TX3_AIFS 0
-
-#define DEF_TX0_ACM 0
-#define DEF_TX1_ACM 0
-#define DEF_TX2_ACM 0
-#define DEF_TX3_ACM 0
-
-#define DEF_TX0_TXOP_LIMIT_CCK 0
-#define DEF_TX1_TXOP_LIMIT_CCK 0
-#define DEF_TX2_TXOP_LIMIT_CCK 0
-#define DEF_TX3_TXOP_LIMIT_CCK 0
-
-#define DEF_TX0_TXOP_LIMIT_OFDM 0
-#define DEF_TX1_TXOP_LIMIT_OFDM 0
-#define DEF_TX2_TXOP_LIMIT_OFDM 0
-#define DEF_TX3_TXOP_LIMIT_OFDM 0
-
-#define QOS_QOS_SETS 3
-#define QOS_PARAM_SET_ACTIVE 0
-#define QOS_PARAM_SET_DEF_CCK 1
-#define QOS_PARAM_SET_DEF_OFDM 2
-
-#define CTRL_QOS_NO_ACK (0x0020)
-
-#define IPW_TX_QUEUE_1 1
-#define IPW_TX_QUEUE_2 2
-#define IPW_TX_QUEUE_3 3
-#define IPW_TX_QUEUE_4 4
-
-/* QoS sturctures */
-struct ipw_qos_info {
- int qos_enable;
- struct libipw_qos_parameters *def_qos_parm_OFDM;
- struct libipw_qos_parameters *def_qos_parm_CCK;
- u32 burst_duration_CCK;
- u32 burst_duration_OFDM;
- u16 qos_no_ack_mask;
- int burst_enable;
-};
-
-/**************************************************************/
-/**
- * Generic queue structure
- *
- * Contains common data for Rx and Tx queues
- */
-struct clx2_queue {
- int n_bd; /**< number of BDs in this queue */
- int first_empty; /**< 1-st empty entry (index) */
- int last_used; /**< last used entry (index) */
- u32 reg_w; /**< 'write' reg (queue head), addr in domain 1 */
- u32 reg_r; /**< 'read' reg (queue tail), addr in domain 1 */
- dma_addr_t dma_addr; /**< physical addr for BD's */
- int low_mark; /**< low watermark, resume queue if free space more than this */
- int high_mark; /**< high watermark, stop queue if free space less than this */
-} __packed; /* XXX */
-
-struct machdr32 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- u8 addr4[MACADRR_BYTE_LEN];
- __le16 qos_ctrl;
-} __packed;
-
-struct machdr30 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- u8 addr4[MACADRR_BYTE_LEN];
-} __packed;
-
-struct machdr26 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
- __le16 qos_ctrl;
-} __packed;
-
-struct machdr24 {
- __le16 frame_ctl;
- __le16 duration; // watch out for endians!
- u8 addr1[MACADRR_BYTE_LEN];
- u8 addr2[MACADRR_BYTE_LEN];
- u8 addr3[MACADRR_BYTE_LEN];
- __le16 seq_ctrl; // more endians!
-} __packed;
-
-// TX TFD with 32 byte MAC Header
-struct tx_tfd_32 {
- struct machdr32 mchdr; // 32
- __le32 uivplaceholder[2]; // 8
-} __packed;
-
-// TX TFD with 30 byte MAC Header
-struct tx_tfd_30 {
- struct machdr30 mchdr; // 30
- u8 reserved[2]; // 2
- __le32 uivplaceholder[2]; // 8
-} __packed;
-
-// tx tfd with 26 byte mac header
-struct tx_tfd_26 {
- struct machdr26 mchdr; // 26
- u8 reserved1[2]; // 2
- __le32 uivplaceholder[2]; // 8
- u8 reserved2[4]; // 4
-} __packed;
-
-// tx tfd with 24 byte mac header
-struct tx_tfd_24 {
- struct machdr24 mchdr; // 24
- __le32 uivplaceholder[2]; // 8
- u8 reserved[8]; // 8
-} __packed;
-
-#define DCT_WEP_KEY_FIELD_LENGTH 16
-
-struct tfd_command {
- u8 index;
- u8 length;
- __le16 reserved;
- u8 payload[];
-} __packed;
-
-struct tfd_data {
- /* Header */
- __le32 work_area_ptr;
- u8 station_number; /* 0 for BSS */
- u8 reserved1;
- __le16 reserved2;
-
- /* Tx Parameters */
- u8 cmd_id;
- u8 seq_num;
- __le16 len;
- u8 priority;
- u8 tx_flags;
- u8 tx_flags_ext;
- u8 key_index;
- u8 wepkey[DCT_WEP_KEY_FIELD_LENGTH];
- u8 rate;
- u8 antenna;
- __le16 next_packet_duration;
- __le16 next_frag_len;
- __le16 back_off_counter; //////txop;
- u8 retrylimit;
- __le16 cwcurrent;
- u8 reserved3;
-
- /* 802.11 MAC Header */
- union {
- struct tx_tfd_24 tfd_24;
- struct tx_tfd_26 tfd_26;
- struct tx_tfd_30 tfd_30;
- struct tx_tfd_32 tfd_32;
- } tfd;
-
- /* Payload DMA info */
- __le32 num_chunks;
- __le32 chunk_ptr[NUM_TFD_CHUNKS];
- __le16 chunk_len[NUM_TFD_CHUNKS];
-} __packed;
-
-struct txrx_control_flags {
- u8 message_type;
- u8 rx_seq_num;
- u8 control_bits;
- u8 reserved;
-} __packed;
-
-#define TFD_SIZE 128
-#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags))
-
-struct tfd_frame {
- struct txrx_control_flags control_flags;
- union {
- struct tfd_data data;
- struct tfd_command cmd;
- u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
- } u;
-} __packed;
-
-typedef void destructor_func(const void *);
-
-/**
- * Tx Queue for DMA. Queue consists of circular buffer of
- * BD's and required locking structures.
- */
-struct clx2_tx_queue {
- struct clx2_queue q;
- struct tfd_frame *bd;
- struct libipw_txb **txb;
-};
-
-/*
- * RX related structures and functions
- */
-#define RX_FREE_BUFFERS 32
-#define RX_LOW_WATERMARK 8
-
-#define SUP_RATE_11A_MAX_NUM_CHANNELS 8
-#define SUP_RATE_11B_MAX_NUM_CHANNELS 4
-#define SUP_RATE_11G_MAX_NUM_CHANNELS 12
-
-// Used for passing to driver number of successes and failures per rate
-struct rate_histogram {
- union {
- __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
- __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
- __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
- } success;
- union {
- __le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
- __le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
- __le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
- } failed;
-} __packed;
-
-/* statistics command response */
-struct ipw_cmd_stats {
- u8 cmd_id;
- u8 seq_num;
- __le16 good_sfd;
- __le16 bad_plcp;
- __le16 wrong_bssid;
- __le16 valid_mpdu;
- __le16 bad_mac_header;
- __le16 reserved_frame_types;
- __le16 rx_ina;
- __le16 bad_crc32;
- __le16 invalid_cts;
- __le16 invalid_acks;
- __le16 long_distance_ina_fina;
- __le16 dsp_silence_unreachable;
- __le16 accumulated_rssi;
- __le16 rx_ovfl_frame_tossed;
- __le16 rssi_silence_threshold;
- __le16 rx_ovfl_frame_supplied;
- __le16 last_rx_frame_signal;
- __le16 last_rx_frame_noise;
- __le16 rx_autodetec_no_ofdm;
- __le16 rx_autodetec_no_barker;
- __le16 reserved;
-} __packed;
-
-struct notif_channel_result {
- u8 channel_num;
- struct ipw_cmd_stats stats;
- u8 uReserved;
-} __packed;
-
-#define SCAN_COMPLETED_STATUS_COMPLETE 1
-#define SCAN_COMPLETED_STATUS_ABORTED 2
-
-struct notif_scan_complete {
- u8 scan_type;
- u8 num_channels;
- u8 status;
- u8 reserved;
-} __packed;
-
-struct notif_frag_length {
- __le16 frag_length;
- __le16 reserved;
-} __packed;
-
-struct notif_beacon_state {
- __le32 state;
- __le32 number;
-} __packed;
-
-struct notif_tgi_tx_key {
- u8 key_state;
- u8 security_type;
- u8 station_index;
- u8 reserved;
-} __packed;
-
-#define SILENCE_OVER_THRESH (1)
-#define SILENCE_UNDER_THRESH (2)
-
-struct notif_link_deterioration {
- struct ipw_cmd_stats stats;
- u8 rate;
- u8 modulation;
- struct rate_histogram histogram;
- u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */
- __le16 silence_count;
-} __packed;
-
-struct notif_association {
- u8 state;
-} __packed;
-
-struct notif_authenticate {
- u8 state;
- struct machdr24 addr;
- __le16 status;
-} __packed;
-
-struct notif_calibration {
- u8 data[104];
-} __packed;
-
-struct notif_noise {
- __le32 value;
-} __packed;
-
-struct ipw_rx_notification {
- u8 reserved[8];
- u8 subtype;
- u8 flags;
- __le16 size;
- union {
- struct notif_association assoc;
- struct notif_authenticate auth;
- struct notif_channel_result channel_result;
- struct notif_scan_complete scan_complete;
- struct notif_frag_length frag_len;
- struct notif_beacon_state beacon_state;
- struct notif_tgi_tx_key tgi_tx_key;
- struct notif_link_deterioration link_deterioration;
- struct notif_calibration calibration;
- struct notif_noise noise;
- DECLARE_FLEX_ARRAY(u8, raw);
- } u;
-} __packed;
-
-struct ipw_rx_frame {
- __le32 reserved1;
- u8 parent_tsf[4]; // fw_use[0] is boolean for OUR_TSF_IS_GREATER
- u8 received_channel; // The channel that this frame was received on.
- // Note that for .11b this does not have to be
- // the same as the channel that it was sent.
- // Filled by LMAC
- u8 frameStatus;
- u8 rate;
- u8 rssi;
- u8 agc;
- u8 rssi_dbm;
- __le16 signal;
- __le16 noise;
- u8 antennaAndPhy;
- u8 control; // control bit should be on in bg
- u8 rtscts_rate; // rate of rts or cts (in rts cts sequence rate
- // is identical)
- u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen
- __le16 length;
- u8 data[];
-} __packed;
-
-struct ipw_rx_header {
- u8 message_type;
- u8 rx_seq_num;
- u8 control_bits;
- u8 reserved;
-} __packed;
-
-struct ipw_rx_packet {
- struct ipw_rx_header header;
- union {
- struct ipw_rx_frame frame;
- struct ipw_rx_notification notification;
- } u;
-} __packed;
-
-#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
-#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \
- sizeof(struct ipw_rx_frame))
-
-struct ipw_rx_mem_buffer {
- dma_addr_t dma_addr;
- struct sk_buff *skb;
- struct list_head list;
-}; /* Not transferred over network, so not __packed */
-
-struct ipw_rx_queue {
- struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
- struct ipw_rx_mem_buffer *queue[RX_QUEUE_SIZE];
- u32 processed; /* Internal index to last handled Rx packet */
- u32 read; /* Shared index to newest available Rx buffer */
- u32 write; /* Shared index to oldest written Rx packet */
- u32 free_count; /* Number of pre-allocated buffers in rx_free */
- /* Each of these lists is used as a FIFO for ipw_rx_mem_buffers */
- struct list_head rx_free; /* Own an SKBs */
- struct list_head rx_used; /* No SKB allocated */
- spinlock_t lock;
-}; /* Not transferred over network, so not __packed */
-
-struct alive_command_responce {
- u8 alive_command;
- u8 sequence_number;
- __le16 software_revision;
- u8 device_identifier;
- u8 reserved1[5];
- __le16 reserved2;
- __le16 reserved3;
- __le16 clock_settle_time;
- __le16 powerup_settle_time;
- __le16 reserved4;
- u8 time_stamp[5]; /* month, day, year, hours, minutes */
- u8 ucode_valid;
-} __packed;
-
-#define IPW_MAX_RATES 12
-
-struct ipw_rates {
- u8 num_rates;
- u8 rates[IPW_MAX_RATES];
-} __packed;
-
-struct command_block {
- unsigned int control;
- u32 source_addr;
- u32 dest_addr;
- unsigned int status;
-} __packed;
-
-#define CB_NUMBER_OF_ELEMENTS_SMALL 64
-struct fw_image_desc {
- unsigned long last_cb_index;
- unsigned long current_cb_index;
- struct command_block cb_list[CB_NUMBER_OF_ELEMENTS_SMALL];
- void *v_addr;
- unsigned long p_addr;
- unsigned long len;
-};
-
-struct ipw_sys_config {
- u8 bt_coexistence;
- u8 reserved1;
- u8 answer_broadcast_ssid_probe;
- u8 accept_all_data_frames;
- u8 accept_non_directed_frames;
- u8 exclude_unicast_unencrypted;
- u8 disable_unicast_decryption;
- u8 exclude_multicast_unencrypted;
- u8 disable_multicast_decryption;
- u8 antenna_diversity;
- u8 pass_crc_to_host;
- u8 dot11g_auto_detection;
- u8 enable_cts_to_self;
- u8 enable_multicast_filtering;
- u8 bt_coexist_collision_thr;
- u8 silence_threshold;
- u8 accept_all_mgmt_bcpr;
- u8 accept_all_mgmt_frames;
- u8 pass_noise_stats_to_host;
- u8 reserved3;
-} __packed;
-
-struct ipw_multicast_addr {
- u8 num_of_multicast_addresses;
- u8 reserved[3];
- u8 mac1[6];
- u8 mac2[6];
- u8 mac3[6];
- u8 mac4[6];
-} __packed;
-
-#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */
-#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */
-
-#define DCW_WEP_KEY_SEC_TYPE_WEP 0x00
-#define DCW_WEP_KEY_SEC_TYPE_CCM 0x20
-#define DCW_WEP_KEY_SEC_TYPE_TKIP 0x30
-
-#define DCW_WEP_KEY_INVALID_SIZE 0x00 /* 0 = Invalid key */
-#define DCW_WEP_KEY64Bit_SIZE 0x05 /* 64-bit encryption */
-#define DCW_WEP_KEY128Bit_SIZE 0x0D /* 128-bit encryption */
-#define DCW_CCM_KEY128Bit_SIZE 0x10 /* 128-bit key */
-//#define DCW_WEP_KEY128BitIV_SIZE 0x10 /* 128-bit key and 128-bit IV */
-
-struct ipw_wep_key {
- u8 cmd_id;
- u8 seq_num;
- u8 key_index;
- u8 key_size;
- u8 key[16];
-} __packed;
-
-struct ipw_tgi_tx_key {
- u8 key_id;
- u8 security_type;
- u8 station_index;
- u8 flags;
- u8 key[16];
- __le32 tx_counter[2];
-} __packed;
-
-#define IPW_SCAN_CHANNELS 54
-
-struct ipw_scan_request {
- u8 scan_type;
- __le16 dwell_time;
- u8 channels_list[IPW_SCAN_CHANNELS];
- u8 channels_reserved[3];
-} __packed;
-
-enum {
- IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
- IPW_SCAN_PASSIVE_FULL_DWELL_SCAN,
- IPW_SCAN_ACTIVE_DIRECT_SCAN,
- IPW_SCAN_ACTIVE_BROADCAST_SCAN,
- IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN,
- IPW_SCAN_TYPES
-};
-
-struct ipw_scan_request_ext {
- __le32 full_scan_index;
- u8 channels_list[IPW_SCAN_CHANNELS];
- u8 scan_type[IPW_SCAN_CHANNELS / 2];
- u8 reserved;
- __le16 dwell_time[IPW_SCAN_TYPES];
-} __packed;
-
-static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
-{
- if (index % 2)
- return scan->scan_type[index / 2] & 0x0F;
- else
- return (scan->scan_type[index / 2] & 0xF0) >> 4;
-}
-
-static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan,
- u8 index, u8 scan_type)
-{
- if (index % 2)
- scan->scan_type[index / 2] =
- (scan->scan_type[index / 2] & 0xF0) | (scan_type & 0x0F);
- else
- scan->scan_type[index / 2] =
- (scan->scan_type[index / 2] & 0x0F) |
- ((scan_type & 0x0F) << 4);
-}
-
-struct ipw_associate {
- u8 channel;
-#ifdef __LITTLE_ENDIAN_BITFIELD
- u8 auth_type:4, auth_key:4;
-#else
- u8 auth_key:4, auth_type:4;
-#endif
- u8 assoc_type;
- u8 reserved;
- __le16 policy_support;
- u8 preamble_length;
- u8 ieee_mode;
- u8 bssid[ETH_ALEN];
- __le32 assoc_tsf_msw;
- __le32 assoc_tsf_lsw;
- __le16 capability;
- __le16 listen_interval;
- __le16 beacon_interval;
- u8 dest[ETH_ALEN];
- __le16 atim_window;
- u8 smr;
- u8 reserved1;
- __le16 reserved2;
-} __packed;
-
-struct ipw_supported_rates {
- u8 ieee_mode;
- u8 num_rates;
- u8 purpose;
- u8 reserved;
- u8 supported_rates[IPW_MAX_RATES];
-} __packed;
-
-struct ipw_rts_threshold {
- __le16 rts_threshold;
- __le16 reserved;
-} __packed;
-
-struct ipw_frag_threshold {
- __le16 frag_threshold;
- __le16 reserved;
-} __packed;
-
-struct ipw_retry_limit {
- u8 short_retry_limit;
- u8 long_retry_limit;
- __le16 reserved;
-} __packed;
-
-struct ipw_dino_config {
- __le32 dino_config_addr;
- __le16 dino_config_size;
- u8 dino_response;
- u8 reserved;
-} __packed;
-
-struct ipw_aironet_info {
- u8 id;
- u8 length;
- __le16 reserved;
-} __packed;
-
-struct ipw_rx_key {
- u8 station_index;
- u8 key_type;
- u8 key_id;
- u8 key_flag;
- u8 key[16];
- u8 station_address[6];
- u8 key_index;
- u8 reserved;
-} __packed;
-
-struct ipw_country_channel_info {
- u8 first_channel;
- u8 no_channels;
- s8 max_tx_power;
-} __packed;
-
-struct ipw_country_info {
- u8 id;
- u8 length;
- u8 country_str[IEEE80211_COUNTRY_STRING_LEN];
- struct ipw_country_channel_info groups[7];
-} __packed;
-
-struct ipw_channel_tx_power {
- u8 channel_number;
- s8 tx_power;
-} __packed;
-
-#define SCAN_ASSOCIATED_INTERVAL (HZ)
-#define SCAN_INTERVAL (HZ / 10)
-#define MAX_A_CHANNELS 37
-#define MAX_B_CHANNELS 14
-
-struct ipw_tx_power {
- u8 num_channels;
- u8 ieee_mode;
- struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
-} __packed;
-
-struct ipw_rsn_capabilities {
- u8 id;
- u8 length;
- __le16 version;
-} __packed;
-
-struct ipw_sensitivity_calib {
- __le16 beacon_rssi_raw;
- __le16 reserved;
-} __packed;
-
-/**
- * Host command structure.
- *
- * On input, the following fields should be filled:
- * - cmd
- * - len
- * - status_len
- * - param (if needed)
- *
- * On output,
- * - \a status contains status;
- * - \a param filled with status parameters.
- */
-struct ipw_cmd { /* XXX */
- u32 cmd; /**< Host command */
- u32 status;/**< Status */
- u32 status_len;
- /**< How many 32 bit parameters in the status */
- u32 len; /**< incoming parameters length, bytes */
- /**
- * command parameters.
- * There should be enough space for incoming and
- * outcoming parameters.
- * Incoming parameters listed 1-st, followed by outcoming params.
- * nParams=(len+3)/4+status_len
- */
- u32 param[];
-} __packed;
-
-#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */
-
-#define STATUS_INT_ENABLED (1<<1)
-#define STATUS_RF_KILL_HW (1<<2)
-#define STATUS_RF_KILL_SW (1<<3)
-#define STATUS_RF_KILL_MASK (STATUS_RF_KILL_HW | STATUS_RF_KILL_SW)
-
-#define STATUS_INIT (1<<5)
-#define STATUS_AUTH (1<<6)
-#define STATUS_ASSOCIATED (1<<7)
-#define STATUS_STATE_MASK (STATUS_INIT | STATUS_AUTH | STATUS_ASSOCIATED)
-
-#define STATUS_ASSOCIATING (1<<8)
-#define STATUS_DISASSOCIATING (1<<9)
-#define STATUS_ROAMING (1<<10)
-#define STATUS_EXIT_PENDING (1<<11)
-#define STATUS_DISASSOC_PENDING (1<<12)
-#define STATUS_STATE_PENDING (1<<13)
-
-#define STATUS_DIRECT_SCAN_PENDING (1<<19)
-#define STATUS_SCAN_PENDING (1<<20)
-#define STATUS_SCANNING (1<<21)
-#define STATUS_SCAN_ABORTING (1<<22)
-#define STATUS_SCAN_FORCED (1<<23)
-
-#define STATUS_LED_LINK_ON (1<<24)
-#define STATUS_LED_ACT_ON (1<<25)
-
-#define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */
-#define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */
-#define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */
-
-#define STATUS_SECURITY_UPDATED (1<<31) /* Security sync needed */
-
-#define CFG_STATIC_CHANNEL (1<<0) /* Restrict assoc. to single channel */
-#define CFG_STATIC_ESSID (1<<1) /* Restrict assoc. to single SSID */
-#define CFG_STATIC_BSSID (1<<2) /* Restrict assoc. to single BSSID */
-#define CFG_CUSTOM_MAC (1<<3)
-#define CFG_PREAMBLE_LONG (1<<4)
-#define CFG_ADHOC_PERSIST (1<<5)
-#define CFG_ASSOCIATE (1<<6)
-#define CFG_FIXED_RATE (1<<7)
-#define CFG_ADHOC_CREATE (1<<8)
-#define CFG_NO_LED (1<<9)
-#define CFG_BACKGROUND_SCAN (1<<10)
-#define CFG_SPEED_SCAN (1<<11)
-#define CFG_NET_STATS (1<<12)
-
-#define CAP_SHARED_KEY (1<<0) /* Off = OPEN */
-#define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */
-
-#define MAX_STATIONS 32
-#define IPW_INVALID_STATION (0xff)
-
-struct ipw_station_entry {
- u8 mac_addr[ETH_ALEN];
- u8 reserved;
- u8 support_mode;
-};
-
-#define AVG_ENTRIES 8
-struct average {
- s16 entries[AVG_ENTRIES];
- u8 pos;
- u8 init;
- s32 sum;
-};
-
-#define MAX_SPEED_SCAN 100
-#define IPW_IBSS_MAC_HASH_SIZE 31
-
-struct ipw_ibss_seq {
- u8 mac[ETH_ALEN];
- u16 seq_num;
- u16 frag_num;
- unsigned long packet_time;
- struct list_head list;
-};
-
-struct ipw_error_elem { /* XXX */
- u32 desc;
- u32 time;
- u32 blink1;
- u32 blink2;
- u32 link1;
- u32 link2;
- u32 data;
-};
-
-struct ipw_event { /* XXX */
- u32 event;
- u32 time;
- u32 data;
-} __packed;
-
-struct ipw_fw_error { /* XXX */
- unsigned long jiffies;
- u32 status;
- u32 config;
- u32 elem_len;
- u32 log_len;
- struct ipw_event *log;
- struct ipw_error_elem elem[];
-} __packed;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
-
-enum ipw_prom_filter {
- IPW_PROM_CTL_HEADER_ONLY = (1 << 0),
- IPW_PROM_MGMT_HEADER_ONLY = (1 << 1),
- IPW_PROM_DATA_HEADER_ONLY = (1 << 2),
- IPW_PROM_ALL_HEADER_ONLY = 0xf, /* bits 0..3 */
- IPW_PROM_NO_TX = (1 << 4),
- IPW_PROM_NO_RX = (1 << 5),
- IPW_PROM_NO_CTL = (1 << 6),
- IPW_PROM_NO_MGMT = (1 << 7),
- IPW_PROM_NO_DATA = (1 << 8),
-};
-
-struct ipw_priv;
-struct ipw_prom_priv {
- struct ipw_priv *priv;
- struct libipw_device *ieee;
- enum ipw_prom_filter filter;
- int tx_packets;
- int rx_packets;
-};
-#endif
-
-#if defined(CONFIG_IPW2200_RADIOTAP) || defined(CONFIG_IPW2200_PROMISCUOUS)
-/* Magic struct that slots into the radiotap header -- no reason
- * to build this manually element by element, we can write it much
- * more efficiently than we can parse it. ORDER MATTERS HERE
- *
- * When sent to us via the simulated Rx interface in sysfs, the entire
- * structure is provided regardless of any bits unset.
- */
-struct ipw_rt_hdr {
- struct ieee80211_radiotap_header rt_hdr;
- u64 rt_tsf; /* TSF */ /* XXX */
- u8 rt_flags; /* radiotap packet flags */
- u8 rt_rate; /* rate in 500kb/s */
- __le16 rt_channel; /* channel in mhz */
- __le16 rt_chbitmask; /* channel bitfield */
- s8 rt_dbmsignal; /* signal in dbM, kluged to signed */
- s8 rt_dbmnoise;
- u8 rt_antenna; /* antenna number */
- u8 payload[]; /* payload... */
-} __packed;
-#endif
-
-struct ipw_priv {
- /* ieee device used by generic ieee processing code */
- struct libipw_device *ieee;
-
- spinlock_t lock;
- spinlock_t irq_lock;
- struct mutex mutex;
-
- /* basic pci-network driver stuff */
- struct pci_dev *pci_dev;
- struct net_device *net_dev;
-
-#ifdef CONFIG_IPW2200_PROMISCUOUS
- /* Promiscuous mode */
- struct ipw_prom_priv *prom_priv;
- struct net_device *prom_net_dev;
-#endif
-
- /* pci hardware address support */
- void __iomem *hw_base;
- unsigned long hw_len;
-
- struct fw_image_desc sram_desc;
-
- /* result of ucode download */
- struct alive_command_responce dino_alive;
-
- wait_queue_head_t wait_command_queue;
- wait_queue_head_t wait_state;
-
- /* Rx and Tx DMA processing queues */
- struct ipw_rx_queue *rxq;
- struct clx2_tx_queue txq_cmd;
- struct clx2_tx_queue txq[4];
- u32 status;
- u32 config;
- u32 capability;
-
- struct average average_missed_beacons;
- s16 exp_avg_rssi;
- s16 exp_avg_noise;
- u32 port_type;
- int rx_bufs_min; /**< minimum number of bufs in Rx queue */
- int rx_pend_max; /**< maximum pending buffers for one IRQ */
- u32 hcmd_seq; /**< sequence number for hcmd */
- u32 disassociate_threshold;
- u32 roaming_threshold;
-
- struct ipw_associate assoc_request;
- struct libipw_network *assoc_network;
-
- unsigned long ts_scan_abort;
- struct ipw_supported_rates rates;
- struct ipw_rates phy[3]; /**< PHY restrictions, per band */
- struct ipw_rates supp; /**< software defined */
- struct ipw_rates extended; /**< use for corresp. IE, AP only */
-
- struct notif_link_deterioration last_link_deterioration; /** for statistics */
- struct ipw_cmd *hcmd; /**< host command currently executed */
-
- wait_queue_head_t hcmd_wq; /**< host command waits for execution */
- u32 tsf_bcn[2]; /**< TSF from latest beacon */
-
- struct notif_calibration calib; /**< last calibration */
-
- /* ordinal interface with firmware */
- u32 table0_addr;
- u32 table0_len;
- u32 table1_addr;
- u32 table1_len;
- u32 table2_addr;
- u32 table2_len;
-
- /* context information */
- u8 essid[IW_ESSID_MAX_SIZE];
- u8 essid_len;
- u8 nick[IW_ESSID_MAX_SIZE];
- u16 rates_mask;
- u8 channel;
- struct ipw_sys_config sys_config;
- u32 power_mode;
- u8 bssid[ETH_ALEN];
- u16 rts_threshold;
- u8 mac_addr[ETH_ALEN];
- u8 num_stations;
- u8 stations[MAX_STATIONS][ETH_ALEN];
- u8 short_retry_limit;
- u8 long_retry_limit;
-
- u32 notif_missed_beacons;
-
- /* Statistics and counters normalized with each association */
- u32 last_missed_beacons;
- u32 last_tx_packets;
- u32 last_rx_packets;
- u32 last_tx_failures;
- u32 last_rx_err;
- u32 last_rate;
-
- u32 missed_adhoc_beacons;
- u32 missed_beacons;
- u32 rx_packets;
- u32 tx_packets;
- u32 quality;
-
- u8 speed_scan[MAX_SPEED_SCAN];
- u8 speed_scan_pos;
-
- u16 last_seq_num;
- u16 last_frag_num;
- unsigned long last_packet_time;
- struct list_head ibss_mac_hash[IPW_IBSS_MAC_HASH_SIZE];
-
- /* eeprom */
- u8 eeprom[0x100]; /* 256 bytes of eeprom */
- u8 country[4];
- int eeprom_delay;
-
- struct iw_statistics wstats;
-
- struct iw_public_data wireless_data;
-
- int user_requested_scan;
- u8 direct_scan_ssid[IW_ESSID_MAX_SIZE];
- u8 direct_scan_ssid_len;
-
- struct delayed_work adhoc_check;
- struct work_struct associate;
- struct work_struct disassociate;
- struct work_struct system_config;
- struct work_struct rx_replenish;
- struct delayed_work request_scan;
- struct delayed_work request_direct_scan;
- struct delayed_work request_passive_scan;
- struct delayed_work scan_event;
- struct work_struct adapter_restart;
- struct delayed_work rf_kill;
- struct work_struct up;
- struct work_struct down;
- struct delayed_work gather_stats;
- struct work_struct abort_scan;
- struct work_struct roam;
- struct delayed_work scan_check;
- struct work_struct link_up;
- struct work_struct link_down;
-
- struct tasklet_struct irq_tasklet;
-
- /* LED related variables and work_struct */
- u8 nic_type;
- u32 led_activity_on;
- u32 led_activity_off;
- u32 led_association_on;
- u32 led_association_off;
- u32 led_ofdm_on;
- u32 led_ofdm_off;
-
- struct delayed_work led_link_on;
- struct delayed_work led_link_off;
- struct delayed_work led_act_off;
- struct work_struct merge_networks;
-
- struct ipw_cmd_log *cmdlog;
- int cmdlog_len;
- int cmdlog_pos;
-
-#define IPW_2200BG 1
-#define IPW_2915ABG 2
- u8 adapter;
-
- s8 tx_power;
-
- /* Track time in suspend using CLOCK_BOOTTIME */
- time64_t suspend_at;
- time64_t suspend_time;
-
-#ifdef CONFIG_PM
- u32 pm_state[16];
-#endif
-
- struct ipw_fw_error *error;
-
- /* network state */
-
- /* Used to pass the current INTA value from ISR to Tasklet */
- u32 isr_inta;
-
- /* QoS */
- struct ipw_qos_info qos_data;
- struct work_struct qos_activate;
- /*********************************/
-
- /* debugging info */
- u32 indirect_dword;
- u32 direct_dword;
- u32 indirect_byte;
-}; /*ipw_priv */
-
-/* debug macros */
-
-/* Debug and printf string expansion helpers for printing bitfields */
-#define BIT_FMT8 "%c%c%c%c-%c%c%c%c"
-#define BIT_FMT16 BIT_FMT8 ":" BIT_FMT8
-#define BIT_FMT32 BIT_FMT16 " " BIT_FMT16
-
-#define BITC(x,y) (((x>>y)&1)?'1':'0')
-#define BIT_ARG8(x) \
-BITC(x,7),BITC(x,6),BITC(x,5),BITC(x,4),\
-BITC(x,3),BITC(x,2),BITC(x,1),BITC(x,0)
-
-#define BIT_ARG16(x) \
-BITC(x,15),BITC(x,14),BITC(x,13),BITC(x,12),\
-BITC(x,11),BITC(x,10),BITC(x,9),BITC(x,8),\
-BIT_ARG8(x)
-
-#define BIT_ARG32(x) \
-BITC(x,31),BITC(x,30),BITC(x,29),BITC(x,28),\
-BITC(x,27),BITC(x,26),BITC(x,25),BITC(x,24),\
-BITC(x,23),BITC(x,22),BITC(x,21),BITC(x,20),\
-BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\
-BIT_ARG16(x)
-
-
-#define IPW_DEBUG(level, fmt, args...) \
-do { if (ipw_debug_level & (level)) \
- printk(KERN_DEBUG DRV_NAME": %s " fmt, __func__ , ## args); } while (0)
-
-#ifdef CONFIG_IPW2200_DEBUG
-#define IPW_LL_DEBUG(level, fmt, args...) \
-do { if (ipw_debug_level & (level)) \
- printk(KERN_DEBUG DRV_NAME": %s " fmt, __func__ , ## args); } while (0)
-#else
-#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0)
-#endif /* CONFIG_IPW2200_DEBUG */
-
-/*
- * To use the debug system;
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define IPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a IPW_xxxx_DEBUG() macro definition for your
- * classification, or use IPW_DEBUG(IPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ipw/debug_level
- *
- * you simply need to add your entry to the ipw_debug_levels array.
- *
- * If you do not see debug_level in /proc/net/ipw then you do not have
- * CONFIG_IPW2200_DEBUG defined in your kernel configuration
- *
- */
-
-#define IPW_DL_ERROR (1<<0)
-#define IPW_DL_WARNING (1<<1)
-#define IPW_DL_INFO (1<<2)
-#define IPW_DL_WX (1<<3)
-#define IPW_DL_HOST_COMMAND (1<<5)
-#define IPW_DL_STATE (1<<6)
-
-#define IPW_DL_NOTIF (1<<10)
-#define IPW_DL_SCAN (1<<11)
-#define IPW_DL_ASSOC (1<<12)
-#define IPW_DL_DROP (1<<13)
-#define IPW_DL_IOCTL (1<<14)
-
-#define IPW_DL_MANAGE (1<<15)
-#define IPW_DL_FW (1<<16)
-#define IPW_DL_RF_KILL (1<<17)
-#define IPW_DL_FW_ERRORS (1<<18)
-
-#define IPW_DL_LED (1<<19)
-
-#define IPW_DL_ORD (1<<20)
-
-#define IPW_DL_FRAG (1<<21)
-#define IPW_DL_WEP (1<<22)
-#define IPW_DL_TX (1<<23)
-#define IPW_DL_RX (1<<24)
-#define IPW_DL_ISR (1<<25)
-#define IPW_DL_FW_INFO (1<<26)
-#define IPW_DL_IO (1<<27)
-#define IPW_DL_TRACE (1<<28)
-
-#define IPW_DL_STATS (1<<29)
-#define IPW_DL_MERGE (1<<30)
-#define IPW_DL_QOS (1<<31)
-
-#define IPW_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
-#define IPW_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
-#define IPW_DEBUG_INFO(f, a...) IPW_DEBUG(IPW_DL_INFO, f, ## a)
-
-#define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a)
-#define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a)
-#define IPW_DEBUG_TRACE(f, a...) IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a)
-#define IPW_DEBUG_RX(f, a...) IPW_LL_DEBUG(IPW_DL_RX, f, ## a)
-#define IPW_DEBUG_TX(f, a...) IPW_LL_DEBUG(IPW_DL_TX, f, ## a)
-#define IPW_DEBUG_ISR(f, a...) IPW_LL_DEBUG(IPW_DL_ISR, f, ## a)
-#define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a)
-#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a)
-#define IPW_DEBUG_WEP(f, a...) IPW_LL_DEBUG(IPW_DL_WEP, f, ## a)
-#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
-#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a)
-#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a)
-#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
-#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
-#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a)
-#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a)
-#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a)
-#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
-#define IPW_DEBUG_STATE(f, a...) IPW_DEBUG(IPW_DL_STATE | IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_ASSOC(f, a...) IPW_DEBUG(IPW_DL_ASSOC | IPW_DL_INFO, f, ## a)
-#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a)
-#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a)
-#define IPW_DEBUG_QOS(f, a...) IPW_LL_DEBUG(IPW_DL_QOS, f, ## a)
-
-#include <linux/ctype.h>
-
-/*
-* Register bit definitions
-*/
-
-#define IPW_INTA_RW 0x00000008
-#define IPW_INTA_MASK_R 0x0000000C
-#define IPW_INDIRECT_ADDR 0x00000010
-#define IPW_INDIRECT_DATA 0x00000014
-#define IPW_AUTOINC_ADDR 0x00000018
-#define IPW_AUTOINC_DATA 0x0000001C
-#define IPW_RESET_REG 0x00000020
-#define IPW_GP_CNTRL_RW 0x00000024
-
-#define IPW_READ_INT_REGISTER 0xFF4
-
-#define IPW_GP_CNTRL_BIT_INIT_DONE 0x00000004
-
-#define IPW_REGISTER_DOMAIN1_END 0x00001000
-#define IPW_SRAM_READ_INT_REGISTER 0x00000ff4
-
-#define IPW_SHARED_LOWER_BOUND 0x00000200
-#define IPW_INTERRUPT_AREA_LOWER_BOUND 0x00000f80
-
-#define IPW_NIC_SRAM_LOWER_BOUND 0x00000000
-#define IPW_NIC_SRAM_UPPER_BOUND 0x00030000
-
-#define IPW_BIT_INT_HOST_SRAM_READ_INT_REGISTER (1 << 29)
-#define IPW_GP_CNTRL_BIT_CLOCK_READY 0x00000001
-#define IPW_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY 0x00000002
-
-/*
- * RESET Register Bit Indexes
- */
-#define CBD_RESET_REG_PRINCETON_RESET (1<<0)
-#define IPW_START_STANDBY (1<<2)
-#define IPW_ACTIVITY_LED (1<<4)
-#define IPW_ASSOCIATED_LED (1<<5)
-#define IPW_OFDM_LED (1<<6)
-#define IPW_RESET_REG_SW_RESET (1<<7)
-#define IPW_RESET_REG_MASTER_DISABLED (1<<8)
-#define IPW_RESET_REG_STOP_MASTER (1<<9)
-#define IPW_GATE_ODMA (1<<25)
-#define IPW_GATE_IDMA (1<<26)
-#define IPW_ARC_KESHET_CONFIG (1<<27)
-#define IPW_GATE_ADMA (1<<29)
-
-#define IPW_CSR_CIS_UPPER_BOUND 0x00000200
-#define IPW_DOMAIN_0_END 0x1000
-#define CLX_MEM_BAR_SIZE 0x1000
-
-/* Dino/baseband control registers bits */
-
-#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */
-#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */
-#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */
-#define IPW_BASEBAND_CONTROL_STATUS 0X00200000
-#define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004
-#define IPW_BASEBAND_RX_FIFO_READ 0X00200004
-#define IPW_BASEBAND_CONTROL_STORE 0X00200010
-
-#define IPW_INTERNAL_CMD_EVENT 0X00300004
-#define IPW_BASEBAND_POWER_DOWN 0x00000001
-
-#define IPW_MEM_HALT_AND_RESET 0x003000e0
-
-/* defgroup bits_halt_reset MEM_HALT_AND_RESET register bits */
-#define IPW_BIT_HALT_RESET_ON 0x80000000
-#define IPW_BIT_HALT_RESET_OFF 0x00000000
-
-#define CB_LAST_VALID 0x20000000
-#define CB_INT_ENABLED 0x40000000
-#define CB_VALID 0x80000000
-#define CB_SRC_LE 0x08000000
-#define CB_DEST_LE 0x04000000
-#define CB_SRC_AUTOINC 0x00800000
-#define CB_SRC_IO_GATED 0x00400000
-#define CB_DEST_AUTOINC 0x00080000
-#define CB_SRC_SIZE_LONG 0x00200000
-#define CB_DEST_SIZE_LONG 0x00020000
-
-/* DMA DEFINES */
-
-#define DMA_CONTROL_SMALL_CB_CONST_VALUE 0x00540000
-#define DMA_CB_STOP_AND_ABORT 0x00000C00
-#define DMA_CB_START 0x00000100
-
-#define IPW_SHARED_SRAM_SIZE 0x00030000
-#define IPW_SHARED_SRAM_DMA_CONTROL 0x00027000
-#define CB_MAX_LENGTH 0x1FFF
-
-#define IPW_HOST_EEPROM_DATA_SRAM_SIZE 0xA18
-#define IPW_EEPROM_IMAGE_SIZE 0x100
-
-/* DMA defs */
-#define IPW_DMA_I_CURRENT_CB 0x003000D0
-#define IPW_DMA_O_CURRENT_CB 0x003000D4
-#define IPW_DMA_I_DMA_CONTROL 0x003000A4
-#define IPW_DMA_I_CB_BASE 0x003000A0
-
-#define IPW_TX_CMD_QUEUE_BD_BASE 0x00000200
-#define IPW_TX_CMD_QUEUE_BD_SIZE 0x00000204
-#define IPW_TX_QUEUE_0_BD_BASE 0x00000208
-#define IPW_TX_QUEUE_0_BD_SIZE (0x0000020C)
-#define IPW_TX_QUEUE_1_BD_BASE 0x00000210
-#define IPW_TX_QUEUE_1_BD_SIZE 0x00000214
-#define IPW_TX_QUEUE_2_BD_BASE 0x00000218
-#define IPW_TX_QUEUE_2_BD_SIZE (0x0000021C)
-#define IPW_TX_QUEUE_3_BD_BASE 0x00000220
-#define IPW_TX_QUEUE_3_BD_SIZE 0x00000224
-#define IPW_RX_BD_BASE 0x00000240
-#define IPW_RX_BD_SIZE 0x00000244
-#define IPW_RFDS_TABLE_LOWER 0x00000500
-
-#define IPW_TX_CMD_QUEUE_READ_INDEX 0x00000280
-#define IPW_TX_QUEUE_0_READ_INDEX 0x00000284
-#define IPW_TX_QUEUE_1_READ_INDEX 0x00000288
-#define IPW_TX_QUEUE_2_READ_INDEX (0x0000028C)
-#define IPW_TX_QUEUE_3_READ_INDEX 0x00000290
-#define IPW_RX_READ_INDEX (0x000002A0)
-
-#define IPW_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80)
-#define IPW_TX_QUEUE_0_WRITE_INDEX (0x00000F84)
-#define IPW_TX_QUEUE_1_WRITE_INDEX (0x00000F88)
-#define IPW_TX_QUEUE_2_WRITE_INDEX (0x00000F8C)
-#define IPW_TX_QUEUE_3_WRITE_INDEX (0x00000F90)
-#define IPW_RX_WRITE_INDEX (0x00000FA0)
-
-/*
- * EEPROM Related Definitions
- */
-
-#define IPW_EEPROM_DATA_SRAM_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x814)
-#define IPW_EEPROM_DATA_SRAM_SIZE (IPW_SHARED_LOWER_BOUND + 0x818)
-#define IPW_EEPROM_LOAD_DISABLE (IPW_SHARED_LOWER_BOUND + 0x81C)
-#define IPW_EEPROM_DATA (IPW_SHARED_LOWER_BOUND + 0x820)
-#define IPW_EEPROM_UPPER_ADDRESS (IPW_SHARED_LOWER_BOUND + 0x9E0)
-
-#define IPW_STATION_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0xA0C)
-#define IPW_STATION_TABLE_UPPER (IPW_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_REQUEST_ATIM (IPW_SHARED_LOWER_BOUND + 0xB0C)
-#define IPW_ATIM_SENT (IPW_SHARED_LOWER_BOUND + 0xB10)
-#define IPW_WHO_IS_AWAKE (IPW_SHARED_LOWER_BOUND + 0xB14)
-#define IPW_DURING_ATIM_WINDOW (IPW_SHARED_LOWER_BOUND + 0xB18)
-
-#define MSB 1
-#define LSB 0
-#define WORD_TO_BYTE(_word) ((_word) * sizeof(u16))
-
-#define GET_EEPROM_ADDR(_wordoffset,_byteoffset) \
- ( WORD_TO_BYTE(_wordoffset) + (_byteoffset) )
-
-/* EEPROM access by BYTE */
-#define EEPROM_PME_CAPABILITY (GET_EEPROM_ADDR(0x09,MSB)) /* 1 byte */
-#define EEPROM_MAC_ADDRESS (GET_EEPROM_ADDR(0x21,LSB)) /* 6 byte */
-#define EEPROM_VERSION (GET_EEPROM_ADDR(0x24,MSB)) /* 1 byte */
-#define EEPROM_NIC_TYPE (GET_EEPROM_ADDR(0x25,LSB)) /* 1 byte */
-#define EEPROM_SKU_CAPABILITY (GET_EEPROM_ADDR(0x25,MSB)) /* 1 byte */
-#define EEPROM_COUNTRY_CODE (GET_EEPROM_ADDR(0x26,LSB)) /* 3 bytes */
-#define EEPROM_IBSS_CHANNELS_BG (GET_EEPROM_ADDR(0x28,LSB)) /* 2 bytes */
-#define EEPROM_IBSS_CHANNELS_A (GET_EEPROM_ADDR(0x29,MSB)) /* 5 bytes */
-#define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */
-#define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */
-
-/* NIC type as found in the one byte EEPROM_NIC_TYPE offset */
-#define EEPROM_NIC_TYPE_0 0
-#define EEPROM_NIC_TYPE_1 1
-#define EEPROM_NIC_TYPE_2 2
-#define EEPROM_NIC_TYPE_3 3
-#define EEPROM_NIC_TYPE_4 4
-
-/* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */
-#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */
-#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */
-#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */
-
-#define FW_MEM_REG_LOWER_BOUND 0x00300000
-#define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40)
-#define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04)
-#define EEPROM_BIT_SK (1<<0)
-#define EEPROM_BIT_CS (1<<1)
-#define EEPROM_BIT_DI (1<<2)
-#define EEPROM_BIT_DO (1<<4)
-
-#define EEPROM_CMD_READ 0x2
-
-/* Interrupts masks */
-#define IPW_INTA_NONE 0x00000000
-
-#define IPW_INTA_BIT_RX_TRANSFER 0x00000002
-#define IPW_INTA_BIT_STATUS_CHANGE 0x00000010
-#define IPW_INTA_BIT_BEACON_PERIOD_EXPIRED 0x00000020
-
-//Inta Bits for CF
-#define IPW_INTA_BIT_TX_CMD_QUEUE 0x00000800
-#define IPW_INTA_BIT_TX_QUEUE_1 0x00001000
-#define IPW_INTA_BIT_TX_QUEUE_2 0x00002000
-#define IPW_INTA_BIT_TX_QUEUE_3 0x00004000
-#define IPW_INTA_BIT_TX_QUEUE_4 0x00008000
-
-#define IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE 0x00010000
-
-#define IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN 0x00100000
-#define IPW_INTA_BIT_POWER_DOWN 0x00200000
-
-#define IPW_INTA_BIT_FW_INITIALIZATION_DONE 0x01000000
-#define IPW_INTA_BIT_FW_CARD_DISABLE_PHY_OFF_DONE 0x02000000
-#define IPW_INTA_BIT_RF_KILL_DONE 0x04000000
-#define IPW_INTA_BIT_FATAL_ERROR 0x40000000
-#define IPW_INTA_BIT_PARITY_ERROR 0x80000000
-
-/* Interrupts enabled at init time. */
-#define IPW_INTA_MASK_ALL \
- (IPW_INTA_BIT_TX_QUEUE_1 | \
- IPW_INTA_BIT_TX_QUEUE_2 | \
- IPW_INTA_BIT_TX_QUEUE_3 | \
- IPW_INTA_BIT_TX_QUEUE_4 | \
- IPW_INTA_BIT_TX_CMD_QUEUE | \
- IPW_INTA_BIT_RX_TRANSFER | \
- IPW_INTA_BIT_FATAL_ERROR | \
- IPW_INTA_BIT_PARITY_ERROR | \
- IPW_INTA_BIT_STATUS_CHANGE | \
- IPW_INTA_BIT_FW_INITIALIZATION_DONE | \
- IPW_INTA_BIT_BEACON_PERIOD_EXPIRED | \
- IPW_INTA_BIT_SLAVE_MODE_HOST_CMD_DONE | \
- IPW_INTA_BIT_PREPARE_FOR_POWER_DOWN | \
- IPW_INTA_BIT_POWER_DOWN | \
- IPW_INTA_BIT_RF_KILL_DONE )
-
-/* FW event log definitions */
-#define EVENT_ELEM_SIZE (3 * sizeof(u32))
-#define EVENT_START_OFFSET (1 * sizeof(u32) + 2 * sizeof(u16))
-
-/* FW error log definitions */
-#define ERROR_ELEM_SIZE (7 * sizeof(u32))
-#define ERROR_START_OFFSET (1 * sizeof(u32))
-
-/* TX power level (dbm) */
-#define IPW_TX_POWER_MIN -12
-#define IPW_TX_POWER_MAX 20
-#define IPW_TX_POWER_DEFAULT IPW_TX_POWER_MAX
-
-enum {
- IPW_FW_ERROR_OK = 0,
- IPW_FW_ERROR_FAIL,
- IPW_FW_ERROR_MEMORY_UNDERFLOW,
- IPW_FW_ERROR_MEMORY_OVERFLOW,
- IPW_FW_ERROR_BAD_PARAM,
- IPW_FW_ERROR_BAD_CHECKSUM,
- IPW_FW_ERROR_NMI_INTERRUPT,
- IPW_FW_ERROR_BAD_DATABASE,
- IPW_FW_ERROR_ALLOC_FAIL,
- IPW_FW_ERROR_DMA_UNDERRUN,
- IPW_FW_ERROR_DMA_STATUS,
- IPW_FW_ERROR_DINO_ERROR,
- IPW_FW_ERROR_EEPROM_ERROR,
- IPW_FW_ERROR_SYSASSERT,
- IPW_FW_ERROR_FATAL_ERROR
-};
-
-#define AUTH_OPEN 0
-#define AUTH_SHARED_KEY 1
-#define AUTH_LEAP 2
-#define AUTH_IGNORE 3
-
-#define HC_ASSOCIATE 0
-#define HC_REASSOCIATE 1
-#define HC_DISASSOCIATE 2
-#define HC_IBSS_START 3
-#define HC_IBSS_RECONF 4
-#define HC_DISASSOC_QUIET 5
-
-#define HC_QOS_SUPPORT_ASSOC cpu_to_le16(0x01)
-
-#define IPW_RATE_CAPABILITIES 1
-#define IPW_RATE_CONNECT 0
-
-/*
- * Rate values and masks
- */
-#define IPW_TX_RATE_1MB 0x0A
-#define IPW_TX_RATE_2MB 0x14
-#define IPW_TX_RATE_5MB 0x37
-#define IPW_TX_RATE_6MB 0x0D
-#define IPW_TX_RATE_9MB 0x0F
-#define IPW_TX_RATE_11MB 0x6E
-#define IPW_TX_RATE_12MB 0x05
-#define IPW_TX_RATE_18MB 0x07
-#define IPW_TX_RATE_24MB 0x09
-#define IPW_TX_RATE_36MB 0x0B
-#define IPW_TX_RATE_48MB 0x01
-#define IPW_TX_RATE_54MB 0x03
-
-#define IPW_ORD_TABLE_ID_MASK 0x0000FF00
-#define IPW_ORD_TABLE_VALUE_MASK 0x000000FF
-
-#define IPW_ORD_TABLE_0_MASK 0x0000F000
-#define IPW_ORD_TABLE_1_MASK 0x0000F100
-#define IPW_ORD_TABLE_2_MASK 0x0000F200
-#define IPW_ORD_TABLE_3_MASK 0x0000F300
-#define IPW_ORD_TABLE_4_MASK 0x0000F400
-#define IPW_ORD_TABLE_5_MASK 0x0000F500
-#define IPW_ORD_TABLE_6_MASK 0x0000F600
-#define IPW_ORD_TABLE_7_MASK 0x0000F700
-
-/*
- * Table 0 Entries (all entries are 32 bits)
- */
-enum {
- IPW_ORD_STAT_TX_CURR_RATE = IPW_ORD_TABLE_0_MASK + 1,
- IPW_ORD_STAT_FRAG_TRESHOLD,
- IPW_ORD_STAT_RTS_THRESHOLD,
- IPW_ORD_STAT_TX_HOST_REQUESTS,
- IPW_ORD_STAT_TX_HOST_COMPLETE,
- IPW_ORD_STAT_TX_DIR_DATA,
- IPW_ORD_STAT_TX_DIR_DATA_B_1,
- IPW_ORD_STAT_TX_DIR_DATA_B_2,
- IPW_ORD_STAT_TX_DIR_DATA_B_5_5,
- IPW_ORD_STAT_TX_DIR_DATA_B_11,
- /* Hole */
-
- IPW_ORD_STAT_TX_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 19,
- IPW_ORD_STAT_TX_DIR_DATA_G_2,
- IPW_ORD_STAT_TX_DIR_DATA_G_5_5,
- IPW_ORD_STAT_TX_DIR_DATA_G_6,
- IPW_ORD_STAT_TX_DIR_DATA_G_9,
- IPW_ORD_STAT_TX_DIR_DATA_G_11,
- IPW_ORD_STAT_TX_DIR_DATA_G_12,
- IPW_ORD_STAT_TX_DIR_DATA_G_18,
- IPW_ORD_STAT_TX_DIR_DATA_G_24,
- IPW_ORD_STAT_TX_DIR_DATA_G_36,
- IPW_ORD_STAT_TX_DIR_DATA_G_48,
- IPW_ORD_STAT_TX_DIR_DATA_G_54,
- IPW_ORD_STAT_TX_NON_DIR_DATA,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_1,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_2,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_5_5,
- IPW_ORD_STAT_TX_NON_DIR_DATA_B_11,
- /* Hole */
-
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_1 = IPW_ORD_TABLE_0_MASK + 44,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_2,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_5_5,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_6,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_9,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_11,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_12,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_18,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_24,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_36,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_48,
- IPW_ORD_STAT_TX_NON_DIR_DATA_G_54,
- IPW_ORD_STAT_TX_RETRY,
- IPW_ORD_STAT_TX_FAILURE,
- IPW_ORD_STAT_RX_ERR_CRC,
- IPW_ORD_STAT_RX_ERR_ICV,
- IPW_ORD_STAT_RX_NO_BUFFER,
- IPW_ORD_STAT_FULL_SCANS,
- IPW_ORD_STAT_PARTIAL_SCANS,
- IPW_ORD_STAT_TGH_ABORTED_SCANS,
- IPW_ORD_STAT_TX_TOTAL_BYTES,
- IPW_ORD_STAT_CURR_RSSI_RAW,
- IPW_ORD_STAT_RX_BEACON,
- IPW_ORD_STAT_MISSED_BEACONS,
- IPW_ORD_TABLE_0_LAST
-};
-
-#define IPW_RSSI_TO_DBM 112
-
-/* Table 1 Entries
- */
-enum {
- IPW_ORD_TABLE_1_LAST = IPW_ORD_TABLE_1_MASK | 1,
-};
-
-/*
- * Table 2 Entries
- *
- * FW_VERSION: 16 byte string
- * FW_DATE: 16 byte string (only 14 bytes used)
- * UCODE_VERSION: 4 byte version code
- * UCODE_DATE: 5 bytes code code
- * ADDAPTER_MAC: 6 byte MAC address
- * RTC: 4 byte clock
- */
-enum {
- IPW_ORD_STAT_FW_VERSION = IPW_ORD_TABLE_2_MASK | 1,
- IPW_ORD_STAT_FW_DATE,
- IPW_ORD_STAT_UCODE_VERSION,
- IPW_ORD_STAT_UCODE_DATE,
- IPW_ORD_STAT_ADAPTER_MAC,
- IPW_ORD_STAT_RTC,
- IPW_ORD_TABLE_2_LAST
-};
-
-/* Table 3 */
-enum {
- IPW_ORD_STAT_TX_PACKET = IPW_ORD_TABLE_3_MASK | 0,
- IPW_ORD_STAT_TX_PACKET_FAILURE,
- IPW_ORD_STAT_TX_PACKET_SUCCESS,
- IPW_ORD_STAT_TX_PACKET_ABORTED,
- IPW_ORD_TABLE_3_LAST
-};
-
-/* Table 4 */
-enum {
- IPW_ORD_TABLE_4_LAST = IPW_ORD_TABLE_4_MASK
-};
-
-/* Table 5 */
-enum {
- IPW_ORD_STAT_AVAILABLE_AP_COUNT = IPW_ORD_TABLE_5_MASK,
- IPW_ORD_STAT_AP_ASSNS,
- IPW_ORD_STAT_ROAM,
- IPW_ORD_STAT_ROAM_CAUSE_MISSED_BEACONS,
- IPW_ORD_STAT_ROAM_CAUSE_UNASSOC,
- IPW_ORD_STAT_ROAM_CAUSE_RSSI,
- IPW_ORD_STAT_ROAM_CAUSE_LINK_QUALITY,
- IPW_ORD_STAT_ROAM_CAUSE_AP_LOAD_BALANCE,
- IPW_ORD_STAT_ROAM_CAUSE_AP_NO_TX,
- IPW_ORD_STAT_LINK_UP,
- IPW_ORD_STAT_LINK_DOWN,
- IPW_ORD_ANTENNA_DIVERSITY,
- IPW_ORD_CURR_FREQ,
- IPW_ORD_TABLE_5_LAST
-};
-
-/* Table 6 */
-enum {
- IPW_ORD_COUNTRY_CODE = IPW_ORD_TABLE_6_MASK,
- IPW_ORD_CURR_BSSID,
- IPW_ORD_CURR_SSID,
- IPW_ORD_TABLE_6_LAST
-};
-
-/* Table 7 */
-enum {
- IPW_ORD_STAT_PERCENT_MISSED_BEACONS = IPW_ORD_TABLE_7_MASK,
- IPW_ORD_STAT_PERCENT_TX_RETRIES,
- IPW_ORD_STAT_PERCENT_LINK_QUALITY,
- IPW_ORD_STAT_CURR_RSSI_DBM,
- IPW_ORD_TABLE_7_LAST
-};
-
-#define IPW_ERROR_LOG (IPW_SHARED_LOWER_BOUND + 0x410)
-#define IPW_EVENT_LOG (IPW_SHARED_LOWER_BOUND + 0x414)
-#define IPW_ORDINALS_TABLE_LOWER (IPW_SHARED_LOWER_BOUND + 0x500)
-#define IPW_ORDINALS_TABLE_0 (IPW_SHARED_LOWER_BOUND + 0x180)
-#define IPW_ORDINALS_TABLE_1 (IPW_SHARED_LOWER_BOUND + 0x184)
-#define IPW_ORDINALS_TABLE_2 (IPW_SHARED_LOWER_BOUND + 0x188)
-#define IPW_MEM_FIXED_OVERRIDE (IPW_SHARED_LOWER_BOUND + 0x41C)
-
-struct ipw_fixed_rate {
- __le16 tx_rates;
- __le16 reserved;
-} __packed;
-
-#define IPW_INDIRECT_ADDR_MASK (~0x3ul)
-
-struct host_cmd {
- u8 cmd;
- u8 len;
- u16 reserved;
- const u32 *param;
-} __packed; /* XXX */
-
-struct cmdlog_host_cmd {
- u8 cmd;
- u8 len;
- __le16 reserved;
- char param[124];
-} __packed;
-
-struct ipw_cmd_log {
- unsigned long jiffies;
- int retcode;
- struct cmdlog_host_cmd cmd;
-};
-
-/* SysConfig command parameters ... */
-/* bt_coexistence param */
-#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */
-#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */
-#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */
-#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */
-#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */
-
-/* clear-to-send to self param */
-#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x00
-#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x01
-#define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN
-
-/* Antenna diversity param (h/w can select best antenna, based on signal) */
-#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */
-#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */
-#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */
-#define CFG_SYS_ANTENNA_SLOW_DIV 0x02 /* consider background noise */
-
-#define IPW_MAX_CONFIG_RETRIES 10
-
-#endif /* __ipw2200_h__ */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw.h b/drivers/net/wireless/intel/ipw2x00/libipw.h
deleted file mode 100644
index 9065ca5b02085..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw.h
+++ /dev/null
@@ -1,1001 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
- * remains copyright by the original authors
- *
- * Portions of the merged code are based on Host AP (software wireless
- * LAN access point) driver for Intersil Prism2/2.5/3.
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j at w1.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <j at w1.fi>
- *
- * Adaption to a generic IEEE 802.11 stack by James Ketrenos
- * <jketreno at linux.intel.com>
- * Copyright (c) 2004-2005, Intel Corporation
- *
- * API Version History
- * 1.0.x -- Initial version
- * 1.1.x -- Added radiotap, QoS, TIM, libipw_geo APIs,
- * various structure changes, and crypto API init method
- */
-#ifndef LIBIPW_H
-#define LIBIPW_H
-#include <linux/if_ether.h> /* ETH_ALEN */
-#include <linux/kernel.h> /* ARRAY_SIZE */
-#include <linux/wireless.h>
-#include <linux/ieee80211.h>
-
-#include <net/lib80211.h>
-#include <net/cfg80211.h>
-
-#define LIBIPW_VERSION "git-1.1.13"
-
-#define LIBIPW_DATA_LEN 2304
-/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
- 6.2.1.1.2.
-
- The figure in section 7.1.2 suggests a body size of up to 2312
- bytes is allowed, which is a bit confusing, I suspect this
- represents the 2304 bytes of real data, plus a possible 8 bytes of
- WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
-
-#define LIBIPW_1ADDR_LEN 10
-#define LIBIPW_2ADDR_LEN 16
-#define LIBIPW_3ADDR_LEN 24
-#define LIBIPW_4ADDR_LEN 30
-#define LIBIPW_FCS_LEN 4
-#define LIBIPW_HLEN (LIBIPW_4ADDR_LEN)
-#define LIBIPW_FRAME_LEN (LIBIPW_DATA_LEN + LIBIPW_HLEN)
-
-#define MIN_FRAG_THRESHOLD 256U
-#define MAX_FRAG_THRESHOLD 2346U
-
-/* QOS control */
-#define LIBIPW_QCTL_TID 0x000F
-
-/* debug macros */
-
-#ifdef CONFIG_LIBIPW_DEBUG
-extern u32 libipw_debug_level;
-#define LIBIPW_DEBUG(level, fmt, args...) \
-do { if (libipw_debug_level & (level)) \
- printk(KERN_DEBUG "libipw: %s " fmt, __func__ , ## args); } while (0)
-#else
-#define LIBIPW_DEBUG(level, fmt, args...) do {} while (0)
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-/*
- * To use the debug system:
- *
- * If you are defining a new debug classification, simply add it to the #define
- * list here in the form of:
- *
- * #define LIBIPW_DL_xxxx VALUE
- *
- * shifting value to the left one bit from the previous entry. xxxx should be
- * the name of the classification (for example, WEP)
- *
- * You then need to either add a LIBIPW_xxxx_DEBUG() macro definition for your
- * classification, or use LIBIPW_DEBUG(LIBIPW_DL_xxxx, ...) whenever you want
- * to send output to that classification.
- *
- * To add your debug level to the list of levels seen when you perform
- *
- * % cat /proc/net/ieee80211/debug_level
- *
- * you simply need to add your entry to the libipw_debug_level array.
- *
- * If you do not see debug_level in /proc/net/ieee80211 then you do not have
- * CONFIG_LIBIPW_DEBUG defined in your kernel configuration
- *
- */
-
-#define LIBIPW_DL_INFO (1<<0)
-#define LIBIPW_DL_WX (1<<1)
-#define LIBIPW_DL_SCAN (1<<2)
-#define LIBIPW_DL_STATE (1<<3)
-#define LIBIPW_DL_MGMT (1<<4)
-#define LIBIPW_DL_FRAG (1<<5)
-#define LIBIPW_DL_DROP (1<<7)
-
-#define LIBIPW_DL_TX (1<<8)
-#define LIBIPW_DL_RX (1<<9)
-#define LIBIPW_DL_QOS (1<<31)
-
-#define LIBIPW_ERROR(f, a...) printk(KERN_ERR "libipw: " f, ## a)
-#define LIBIPW_WARNING(f, a...) printk(KERN_WARNING "libipw: " f, ## a)
-#define LIBIPW_DEBUG_INFO(f, a...) LIBIPW_DEBUG(LIBIPW_DL_INFO, f, ## a)
-
-#define LIBIPW_DEBUG_WX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_WX, f, ## a)
-#define LIBIPW_DEBUG_SCAN(f, a...) LIBIPW_DEBUG(LIBIPW_DL_SCAN, f, ## a)
-#define LIBIPW_DEBUG_STATE(f, a...) LIBIPW_DEBUG(LIBIPW_DL_STATE, f, ## a)
-#define LIBIPW_DEBUG_MGMT(f, a...) LIBIPW_DEBUG(LIBIPW_DL_MGMT, f, ## a)
-#define LIBIPW_DEBUG_FRAG(f, a...) LIBIPW_DEBUG(LIBIPW_DL_FRAG, f, ## a)
-#define LIBIPW_DEBUG_DROP(f, a...) LIBIPW_DEBUG(LIBIPW_DL_DROP, f, ## a)
-#define LIBIPW_DEBUG_TX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_TX, f, ## a)
-#define LIBIPW_DEBUG_RX(f, a...) LIBIPW_DEBUG(LIBIPW_DL_RX, f, ## a)
-#define LIBIPW_DEBUG_QOS(f, a...) LIBIPW_DEBUG(LIBIPW_DL_QOS, f, ## a)
-#include <linux/netdevice.h>
-#include <linux/if_arp.h> /* ARPHRD_ETHER */
-
-#ifndef WIRELESS_SPY
-#define WIRELESS_SPY /* enable iwspy support */
-#endif
-#include <net/iw_handler.h> /* new driver API */
-
-#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
-#endif
-
-/* IEEE 802.11 defines */
-
-#define P80211_OUI_LEN 3
-
-struct libipw_snap_hdr {
-
- u8 dsap; /* always 0xAA */
- u8 ssap; /* always 0xAA */
- u8 ctrl; /* always 0x03 */
- u8 oui[P80211_OUI_LEN]; /* organizational universal id */
-
-} __packed;
-
-#define SNAP_SIZE sizeof(struct libipw_snap_hdr)
-
-#define WLAN_FC_GET_VERS(fc) ((fc) & IEEE80211_FCTL_VERS)
-#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
-#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
-
-#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
-#define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
-
-#define LIBIPW_STATMASK_SIGNAL (1<<0)
-#define LIBIPW_STATMASK_RSSI (1<<1)
-#define LIBIPW_STATMASK_NOISE (1<<2)
-#define LIBIPW_STATMASK_RATE (1<<3)
-#define LIBIPW_STATMASK_WEMASK 0x7
-
-#define LIBIPW_CCK_MODULATION (1<<0)
-#define LIBIPW_OFDM_MODULATION (1<<1)
-
-#define LIBIPW_24GHZ_BAND (1<<0)
-#define LIBIPW_52GHZ_BAND (1<<1)
-
-#define LIBIPW_CCK_RATE_1MB 0x02
-#define LIBIPW_CCK_RATE_2MB 0x04
-#define LIBIPW_CCK_RATE_5MB 0x0B
-#define LIBIPW_CCK_RATE_11MB 0x16
-#define LIBIPW_OFDM_RATE_6MB 0x0C
-#define LIBIPW_OFDM_RATE_9MB 0x12
-#define LIBIPW_OFDM_RATE_12MB 0x18
-#define LIBIPW_OFDM_RATE_18MB 0x24
-#define LIBIPW_OFDM_RATE_24MB 0x30
-#define LIBIPW_OFDM_RATE_36MB 0x48
-#define LIBIPW_OFDM_RATE_48MB 0x60
-#define LIBIPW_OFDM_RATE_54MB 0x6C
-#define LIBIPW_BASIC_RATE_MASK 0x80
-
-#define LIBIPW_CCK_RATE_1MB_MASK (1<<0)
-#define LIBIPW_CCK_RATE_2MB_MASK (1<<1)
-#define LIBIPW_CCK_RATE_5MB_MASK (1<<2)
-#define LIBIPW_CCK_RATE_11MB_MASK (1<<3)
-#define LIBIPW_OFDM_RATE_6MB_MASK (1<<4)
-#define LIBIPW_OFDM_RATE_9MB_MASK (1<<5)
-#define LIBIPW_OFDM_RATE_12MB_MASK (1<<6)
-#define LIBIPW_OFDM_RATE_18MB_MASK (1<<7)
-#define LIBIPW_OFDM_RATE_24MB_MASK (1<<8)
-#define LIBIPW_OFDM_RATE_36MB_MASK (1<<9)
-#define LIBIPW_OFDM_RATE_48MB_MASK (1<<10)
-#define LIBIPW_OFDM_RATE_54MB_MASK (1<<11)
-
-#define LIBIPW_CCK_RATES_MASK 0x0000000F
-#define LIBIPW_CCK_BASIC_RATES_MASK (LIBIPW_CCK_RATE_1MB_MASK | \
- LIBIPW_CCK_RATE_2MB_MASK)
-#define LIBIPW_CCK_DEFAULT_RATES_MASK (LIBIPW_CCK_BASIC_RATES_MASK | \
- LIBIPW_CCK_RATE_5MB_MASK | \
- LIBIPW_CCK_RATE_11MB_MASK)
-
-#define LIBIPW_OFDM_RATES_MASK 0x00000FF0
-#define LIBIPW_OFDM_BASIC_RATES_MASK (LIBIPW_OFDM_RATE_6MB_MASK | \
- LIBIPW_OFDM_RATE_12MB_MASK | \
- LIBIPW_OFDM_RATE_24MB_MASK)
-#define LIBIPW_OFDM_DEFAULT_RATES_MASK (LIBIPW_OFDM_BASIC_RATES_MASK | \
- LIBIPW_OFDM_RATE_9MB_MASK | \
- LIBIPW_OFDM_RATE_18MB_MASK | \
- LIBIPW_OFDM_RATE_36MB_MASK | \
- LIBIPW_OFDM_RATE_48MB_MASK | \
- LIBIPW_OFDM_RATE_54MB_MASK)
-#define LIBIPW_DEFAULT_RATES_MASK (LIBIPW_OFDM_DEFAULT_RATES_MASK | \
- LIBIPW_CCK_DEFAULT_RATES_MASK)
-
-#define LIBIPW_NUM_OFDM_RATES 8
-#define LIBIPW_NUM_CCK_RATES 4
-#define LIBIPW_OFDM_SHIFT_MASK_A 4
-
-/* NOTE: This data is for statistical purposes; not all hardware provides this
- * information for frames received.
- * For libipw_rx_mgt, you need to set at least the 'len' parameter.
- */
-struct libipw_rx_stats {
- u32 mac_time;
- s8 rssi;
- u8 signal;
- u8 noise;
- u16 rate; /* in 100 kbps */
- u8 received_channel;
- u8 control;
- u8 mask;
- u8 freq;
- u16 len;
- u64 tsf;
- u32 beacon_time;
-};
-
-/* IEEE 802.11 requires that STA supports concurrent reception of at least
- * three fragmented frames. This define can be increased to support more
- * concurrent frames, but it should be noted that each entry can consume about
- * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
-#define LIBIPW_FRAG_CACHE_LEN 4
-
-struct libipw_frag_entry {
- unsigned long first_frag_time;
- unsigned int seq;
- unsigned int last_frag;
- struct sk_buff *skb;
- u8 src_addr[ETH_ALEN];
- u8 dst_addr[ETH_ALEN];
-};
-
-struct libipw_stats {
- unsigned int tx_unicast_frames;
- unsigned int tx_multicast_frames;
- unsigned int tx_fragments;
- unsigned int tx_unicast_octets;
- unsigned int tx_multicast_octets;
- unsigned int tx_deferred_transmissions;
- unsigned int tx_single_retry_frames;
- unsigned int tx_multiple_retry_frames;
- unsigned int tx_retry_limit_exceeded;
- unsigned int tx_discards;
- unsigned int rx_unicast_frames;
- unsigned int rx_multicast_frames;
- unsigned int rx_fragments;
- unsigned int rx_unicast_octets;
- unsigned int rx_multicast_octets;
- unsigned int rx_fcs_errors;
- unsigned int rx_discards_no_buffer;
- unsigned int tx_discards_wrong_sa;
- unsigned int rx_discards_undecryptable;
- unsigned int rx_message_in_msg_fragments;
- unsigned int rx_message_in_bad_msg_fragments;
-};
-
-struct libipw_device;
-
-#define SEC_KEY_1 (1<<0)
-#define SEC_KEY_2 (1<<1)
-#define SEC_KEY_3 (1<<2)
-#define SEC_KEY_4 (1<<3)
-#define SEC_ACTIVE_KEY (1<<4)
-#define SEC_AUTH_MODE (1<<5)
-#define SEC_UNICAST_GROUP (1<<6)
-#define SEC_LEVEL (1<<7)
-#define SEC_ENABLED (1<<8)
-#define SEC_ENCRYPT (1<<9)
-
-#define SEC_LEVEL_0 0 /* None */
-#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
-#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
-#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
-#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
-
-#define SEC_ALG_NONE 0
-#define SEC_ALG_WEP 1
-#define SEC_ALG_TKIP 2
-#define SEC_ALG_CCMP 3
-
-#define WEP_KEYS 4
-#define WEP_KEY_LEN 13
-#define SCM_KEY_LEN 32
-#define SCM_TEMPORAL_KEY_LENGTH 16
-
-struct libipw_security {
- u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1;
- u8 auth_mode;
- u8 encode_alg[WEP_KEYS];
- u8 key_sizes[WEP_KEYS];
- u8 keys[WEP_KEYS][SCM_KEY_LEN];
- u8 level;
- u16 flags;
-} __packed;
-
-/*
-
- 802.11 data frame from AP
-
- ,-------------------------------------------------------------------.
-Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- |------|------|---------|---------|---------|------|---------|------|
-Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
- | | tion | (BSSID) | | | ence | data | |
- `-------------------------------------------------------------------'
-
-Total: 28-2340 bytes
-
-*/
-
-#define BEACON_PROBE_SSID_ID_POSITION 12
-
-struct libipw_hdr_1addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_2addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_3addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_4addr {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 addr4[ETH_ALEN];
- u8 payload[];
-} __packed;
-
-struct libipw_hdr_3addrqos {
- __le16 frame_ctl;
- __le16 duration_id;
- u8 addr1[ETH_ALEN];
- u8 addr2[ETH_ALEN];
- u8 addr3[ETH_ALEN];
- __le16 seq_ctl;
- u8 payload[0];
- __le16 qos_ctl;
-} __packed;
-
-struct libipw_info_element {
- u8 id;
- u8 len;
- u8 data[];
-} __packed;
-
-/*
- * These are the data types that can make up management packets
- *
- u16 auth_algorithm;
- u16 auth_sequence;
- u16 beacon_interval;
- u16 capability;
- u8 current_ap[ETH_ALEN];
- u16 listen_interval;
- struct {
- u16 association_id:14, reserved:2;
- } __packed;
- u32 time_stamp[2];
- u16 reason;
- u16 status;
-*/
-
-struct libipw_auth {
- struct libipw_hdr_3addr header;
- __le16 algorithm;
- __le16 transaction;
- __le16 status;
- /* challenge */
- u8 variable[];
-} __packed;
-
-struct libipw_channel_switch {
- u8 id;
- u8 len;
- u8 mode;
- u8 channel;
- u8 count;
-} __packed;
-
-struct libipw_action {
- struct libipw_hdr_3addr header;
- u8 category;
- u8 action;
- union {
- struct libipw_action_exchange {
- u8 token;
- } exchange;
- struct libipw_channel_switch channel_switch;
-
- } format;
-} __packed;
-
-struct libipw_disassoc {
- struct libipw_hdr_3addr header;
- __le16 reason;
-} __packed;
-
-/* Alias deauth for disassoc */
-#define libipw_deauth libipw_disassoc
-
-struct libipw_probe_request {
- struct libipw_hdr_3addr header;
- /* SSID, supported rates */
- u8 variable[];
-} __packed;
-
-struct libipw_probe_response {
- struct libipw_hdr_3addr header;
- __le32 time_stamp[2];
- __le16 beacon_interval;
- __le16 capability;
- /* SSID, supported rates, FH params, DS params,
- * CF params, IBSS params, TIM (if beacon), RSN */
- u8 variable[];
-} __packed;
-
-/* Alias beacon for probe_response */
-#define libipw_beacon libipw_probe_response
-
-struct libipw_assoc_request {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- /* SSID, supported rates, RSN */
- u8 variable[];
-} __packed;
-
-struct libipw_reassoc_request {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 listen_interval;
- u8 current_ap[ETH_ALEN];
- u8 variable[];
-} __packed;
-
-struct libipw_assoc_response {
- struct libipw_hdr_3addr header;
- __le16 capability;
- __le16 status;
- __le16 aid;
- /* supported rates */
- u8 variable[];
-} __packed;
-
-struct libipw_txb {
- u8 nr_frags;
- u8 encrypted;
- u8 rts_included;
- u8 reserved;
- u16 frag_size;
- u16 payload_size;
- struct sk_buff *fragments[] __counted_by(nr_frags);
-};
-
-/* SWEEP TABLE ENTRIES NUMBER */
-#define MAX_SWEEP_TAB_ENTRIES 42
-#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
-/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
- * only use 8, and then use extended rates for the remaining supported
- * rates. Other APs, however, stick all of their supported rates on the
- * main rates information element... */
-#define MAX_RATES_LENGTH ((u8)12)
-#define MAX_RATES_EX_LENGTH ((u8)16)
-#define MAX_NETWORK_COUNT 128
-
-#define CRC_LENGTH 4U
-
-#define MAX_WPA_IE_LEN 64
-
-#define NETWORK_HAS_OFDM (1<<1)
-#define NETWORK_HAS_CCK (1<<2)
-
-/* QoS structure */
-#define NETWORK_HAS_QOS_PARAMETERS (1<<3)
-#define NETWORK_HAS_QOS_INFORMATION (1<<4)
-#define NETWORK_HAS_QOS_MASK (NETWORK_HAS_QOS_PARAMETERS | \
- NETWORK_HAS_QOS_INFORMATION)
-
-/* 802.11h */
-#define NETWORK_HAS_POWER_CONSTRAINT (1<<5)
-#define NETWORK_HAS_CSA (1<<6)
-#define NETWORK_HAS_QUIET (1<<7)
-#define NETWORK_HAS_IBSS_DFS (1<<8)
-#define NETWORK_HAS_TPC_REPORT (1<<9)
-
-#define NETWORK_HAS_ERP_VALUE (1<<10)
-
-#define QOS_QUEUE_NUM 4
-#define QOS_OUI_LEN 3
-#define QOS_OUI_TYPE 2
-#define QOS_ELEMENT_ID 221
-#define QOS_OUI_INFO_SUB_TYPE 0
-#define QOS_OUI_PARAM_SUB_TYPE 1
-#define QOS_VERSION_1 1
-#define QOS_AIFSN_MIN_VALUE 2
-
-struct libipw_qos_information_element {
- u8 elementID;
- u8 length;
- u8 qui[QOS_OUI_LEN];
- u8 qui_type;
- u8 qui_subtype;
- u8 version;
- u8 ac_info;
-} __packed;
-
-struct libipw_qos_ac_parameter {
- u8 aci_aifsn;
- u8 ecw_min_max;
- __le16 tx_op_limit;
-} __packed;
-
-struct libipw_qos_parameter_info {
- struct libipw_qos_information_element info_element;
- u8 reserved;
- struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __packed;
-
-struct libipw_qos_parameters {
- __le16 cw_min[QOS_QUEUE_NUM];
- __le16 cw_max[QOS_QUEUE_NUM];
- u8 aifs[QOS_QUEUE_NUM];
- u8 flag[QOS_QUEUE_NUM];
- __le16 tx_op_limit[QOS_QUEUE_NUM];
-} __packed;
-
-struct libipw_qos_data {
- struct libipw_qos_parameters parameters;
- int active;
- int supported;
- u8 param_count;
- u8 old_param_count;
-};
-
-struct libipw_tim_parameters {
- u8 tim_count;
- u8 tim_period;
-} __packed;
-
-/*******************************************************/
-
-struct libipw_tpc_report {
- u8 transmit_power;
- u8 link_margin;
-} __packed;
-
-struct libipw_channel_map {
- u8 channel;
- u8 map;
-} __packed;
-
-struct libipw_ibss_dfs {
- struct libipw_info_element ie;
- u8 owner[ETH_ALEN];
- u8 recovery_interval;
- struct libipw_channel_map channel_map[];
-};
-
-struct libipw_csa {
- u8 mode;
- u8 channel;
- u8 count;
-} __packed;
-
-struct libipw_quiet {
- u8 count;
- u8 period;
- u8 duration;
- u8 offset;
-} __packed;
-
-struct libipw_network {
- /* These entries are used to identify a unique network */
- u8 bssid[ETH_ALEN];
- u8 channel;
- /* Ensure null-terminated for any debug msgs */
- u8 ssid[IW_ESSID_MAX_SIZE + 1];
- u8 ssid_len;
-
- struct libipw_qos_data qos_data;
-
- /* These are network statistics */
- struct libipw_rx_stats stats;
- u16 capability;
- u8 rates[MAX_RATES_LENGTH];
- u8 rates_len;
- u8 rates_ex[MAX_RATES_EX_LENGTH];
- u8 rates_ex_len;
- unsigned long last_scanned;
- u8 mode;
- u32 flags;
- u32 last_associate;
- u32 time_stamp[2];
- u16 beacon_interval;
- u16 listen_interval;
- u16 atim_window;
- u8 erp_value;
- u8 wpa_ie[MAX_WPA_IE_LEN];
- size_t wpa_ie_len;
- u8 rsn_ie[MAX_WPA_IE_LEN];
- size_t rsn_ie_len;
- struct libipw_tim_parameters tim;
-
- /* 802.11h info */
-
- /* Power Constraint - mandatory if spctrm mgmt required */
- u8 power_constraint;
-
- /* TPC Report - mandatory if spctrm mgmt required */
- struct libipw_tpc_report tpc_report;
-
- /* Channel Switch Announcement - optional if spctrm mgmt required */
- struct libipw_csa csa;
-
- /* Quiet - optional if spctrm mgmt required */
- struct libipw_quiet quiet;
-
- struct list_head list;
-};
-
-enum libipw_state {
- LIBIPW_UNINITIALIZED = 0,
- LIBIPW_INITIALIZED,
- LIBIPW_ASSOCIATING,
- LIBIPW_ASSOCIATED,
- LIBIPW_AUTHENTICATING,
- LIBIPW_AUTHENTICATED,
- LIBIPW_SHUTDOWN
-};
-
-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
-#define DEFAULT_FTS 2346
-
-#define CFG_LIBIPW_RESERVE_FCS (1<<0)
-#define CFG_LIBIPW_COMPUTE_FCS (1<<1)
-#define CFG_LIBIPW_RTS (1<<2)
-
-#define LIBIPW_24GHZ_MIN_CHANNEL 1
-#define LIBIPW_24GHZ_MAX_CHANNEL 14
-#define LIBIPW_24GHZ_CHANNELS (LIBIPW_24GHZ_MAX_CHANNEL - \
- LIBIPW_24GHZ_MIN_CHANNEL + 1)
-
-#define LIBIPW_52GHZ_MIN_CHANNEL 34
-#define LIBIPW_52GHZ_MAX_CHANNEL 165
-#define LIBIPW_52GHZ_CHANNELS (LIBIPW_52GHZ_MAX_CHANNEL - \
- LIBIPW_52GHZ_MIN_CHANNEL + 1)
-
-enum {
- LIBIPW_CH_PASSIVE_ONLY = (1 << 0),
- LIBIPW_CH_80211H_RULES = (1 << 1),
- LIBIPW_CH_B_ONLY = (1 << 2),
- LIBIPW_CH_NO_IBSS = (1 << 3),
- LIBIPW_CH_UNIFORM_SPREADING = (1 << 4),
- LIBIPW_CH_RADAR_DETECT = (1 << 5),
- LIBIPW_CH_INVALID = (1 << 6),
-};
-
-struct libipw_channel {
- u32 freq; /* in MHz */
- u8 channel;
- u8 flags;
- u8 max_power; /* in dBm */
-};
-
-struct libipw_geo {
- u8 name[4];
- u8 bg_channels;
- u8 a_channels;
- struct libipw_channel bg[LIBIPW_24GHZ_CHANNELS];
- struct libipw_channel a[LIBIPW_52GHZ_CHANNELS];
-};
-
-struct libipw_device {
- struct net_device *dev;
- struct wireless_dev wdev;
- struct libipw_security sec;
-
- /* Bookkeeping structures */
- struct libipw_stats ieee_stats;
-
- struct libipw_geo geo;
- struct ieee80211_supported_band bg_band;
- struct ieee80211_supported_band a_band;
-
- /* Probe / Beacon management */
- struct list_head network_free_list;
- struct list_head network_list;
- struct libipw_network *networks[MAX_NETWORK_COUNT];
- int scans;
- int scan_age;
-
- int iw_mode; /* operating mode (IW_MODE_*) */
- struct iw_spy_data spy_data; /* iwspy support */
-
- spinlock_t lock;
-
- int tx_headroom; /* Set to size of any additional room needed at front
- * of allocated Tx SKBs */
- u32 config;
-
- /* WEP and other encryption related settings at the device level */
- int open_wep; /* Set to 1 to allow unencrypted frames */
-
- /* If the host performs {en,de}cryption, then set to 1 */
- int host_encrypt;
- int host_encrypt_msdu;
- int host_decrypt;
- /* host performs multicast decryption */
- int host_mc_decrypt;
-
- /* host should strip IV and ICV from protected frames */
- /* meaningful only when hardware decryption is being used */
- int host_strip_iv_icv;
-
- int host_open_frag;
- int ieee802_1x; /* is IEEE 802.1X used */
-
- /* WPA data */
- int wpa_enabled;
- int drop_unencrypted;
- int privacy_invoked;
- size_t wpa_ie_len;
- u8 *wpa_ie;
-
- struct lib80211_crypt_info crypt_info;
-
- int bcrx_sta_key; /* use individual keys to override default keys even
- * with RX of broad/multicast frames */
-
- /* Fragmentation structures */
- struct libipw_frag_entry frag_cache[LIBIPW_FRAG_CACHE_LEN];
- unsigned int frag_next_idx;
- u16 fts; /* Fragmentation Threshold */
- u16 rts; /* RTS threshold */
-
- /* Association info */
- u8 bssid[ETH_ALEN];
-
- enum libipw_state state;
-
- int mode; /* A, B, G */
- int modulation; /* CCK, OFDM */
- int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */
- int abg_true; /* ABG flag */
-
- int perfect_rssi;
- int worst_rssi;
-
- u16 prev_seq_ctl; /* used to drop duplicate frames */
-
- /* Callback functions */
- void (*set_security) (struct net_device * dev,
- struct libipw_security * sec);
- netdev_tx_t (*hard_start_xmit) (struct libipw_txb * txb,
- struct net_device * dev, int pri);
- int (*is_queue_full) (struct net_device * dev, int pri);
-
- int (*handle_management) (struct net_device * dev,
- struct libipw_network * network, u16 type);
- int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
-
- /* Typical STA methods */
- int (*handle_auth) (struct net_device * dev,
- struct libipw_auth * auth);
- int (*handle_deauth) (struct net_device * dev,
- struct libipw_deauth * auth);
- int (*handle_action) (struct net_device * dev,
- struct libipw_action * action,
- struct libipw_rx_stats * stats);
- int (*handle_disassoc) (struct net_device * dev,
- struct libipw_disassoc * assoc);
- int (*handle_beacon) (struct net_device * dev,
- struct libipw_beacon * beacon,
- struct libipw_network * network);
- int (*handle_probe_response) (struct net_device * dev,
- struct libipw_probe_response * resp,
- struct libipw_network * network);
- int (*handle_probe_request) (struct net_device * dev,
- struct libipw_probe_request * req,
- struct libipw_rx_stats * stats);
- int (*handle_assoc_response) (struct net_device * dev,
- struct libipw_assoc_response * resp,
- struct libipw_network * network);
-
- /* Typical AP methods */
- int (*handle_assoc_request) (struct net_device * dev);
- int (*handle_reassoc_request) (struct net_device * dev,
- struct libipw_reassoc_request * req);
-
- /* This must be the last item so that it points to the data
- * allocated beyond this structure by alloc_libipw */
- u8 priv[];
-};
-
-#define IEEE_A (1<<0)
-#define IEEE_B (1<<1)
-#define IEEE_G (1<<2)
-#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
-
-static inline void *libipw_priv(struct net_device *dev)
-{
- return ((struct libipw_device *)netdev_priv(dev))->priv;
-}
-
-static inline int libipw_is_valid_mode(struct libipw_device *ieee,
- int mode)
-{
- /*
- * It is possible for both access points and our device to support
- * combinations of modes, so as long as there is one valid combination
- * of ap/device supported modes, then return success
- *
- */
- if ((mode & IEEE_A) &&
- (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
- (ieee->freq_band & LIBIPW_52GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_G) &&
- (ieee->modulation & LIBIPW_OFDM_MODULATION) &&
- (ieee->freq_band & LIBIPW_24GHZ_BAND))
- return 1;
-
- if ((mode & IEEE_B) &&
- (ieee->modulation & LIBIPW_CCK_MODULATION) &&
- (ieee->freq_band & LIBIPW_24GHZ_BAND))
- return 1;
-
- return 0;
-}
-
-static inline int libipw_get_hdrlen(u16 fc)
-{
- int hdrlen = LIBIPW_3ADDR_LEN;
- u16 stype = WLAN_FC_GET_STYPE(fc);
-
- switch (WLAN_FC_GET_TYPE(fc)) {
- case IEEE80211_FTYPE_DATA:
- if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
- hdrlen = LIBIPW_4ADDR_LEN;
- if (stype & IEEE80211_STYPE_QOS_DATA)
- hdrlen += 2;
- break;
- case IEEE80211_FTYPE_CTL:
- switch (WLAN_FC_GET_STYPE(fc)) {
- case IEEE80211_STYPE_CTS:
- case IEEE80211_STYPE_ACK:
- hdrlen = LIBIPW_1ADDR_LEN;
- break;
- default:
- hdrlen = LIBIPW_2ADDR_LEN;
- break;
- }
- break;
- }
-
- return hdrlen;
-}
-
-static inline u8 *libipw_get_payload(struct ieee80211_hdr *hdr)
-{
- switch (libipw_get_hdrlen(le16_to_cpu(hdr->frame_control))) {
- case LIBIPW_1ADDR_LEN:
- return ((struct libipw_hdr_1addr *)hdr)->payload;
- case LIBIPW_2ADDR_LEN:
- return ((struct libipw_hdr_2addr *)hdr)->payload;
- case LIBIPW_3ADDR_LEN:
- return ((struct libipw_hdr_3addr *)hdr)->payload;
- case LIBIPW_4ADDR_LEN:
- return ((struct libipw_hdr_4addr *)hdr)->payload;
- }
- return NULL;
-}
-
-static inline int libipw_is_ofdm_rate(u8 rate)
-{
- switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
- case LIBIPW_OFDM_RATE_6MB:
- case LIBIPW_OFDM_RATE_9MB:
- case LIBIPW_OFDM_RATE_12MB:
- case LIBIPW_OFDM_RATE_18MB:
- case LIBIPW_OFDM_RATE_24MB:
- case LIBIPW_OFDM_RATE_36MB:
- case LIBIPW_OFDM_RATE_48MB:
- case LIBIPW_OFDM_RATE_54MB:
- return 1;
- }
- return 0;
-}
-
-static inline int libipw_is_cck_rate(u8 rate)
-{
- switch (rate & ~LIBIPW_BASIC_RATE_MASK) {
- case LIBIPW_CCK_RATE_1MB:
- case LIBIPW_CCK_RATE_2MB:
- case LIBIPW_CCK_RATE_5MB:
- case LIBIPW_CCK_RATE_11MB:
- return 1;
- }
- return 0;
-}
-
-/* libipw.c */
-void free_libipw(struct net_device *dev, int monitor);
-struct net_device *alloc_libipw(int sizeof_priv, int monitor);
-
-void libipw_networks_age(struct libipw_device *ieee, unsigned long age_secs);
-
-int libipw_set_encryption(struct libipw_device *ieee);
-
-/* libipw_tx.c */
-netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev);
-void libipw_txb_free(struct libipw_txb *);
-
-/* libipw_rx.c */
-void libipw_rx_any(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *stats);
-int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats);
-/* make sure to set stats->len */
-void libipw_rx_mgt(struct libipw_device *ieee, struct libipw_hdr_4addr *header,
- struct libipw_rx_stats *stats);
-
-/* libipw_geo.c */
-const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee);
-void libipw_set_geo(struct libipw_device *ieee, const struct libipw_geo *geo);
-
-int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel);
-int libipw_channel_to_index(struct libipw_device *ieee, u8 channel);
-u8 libipw_freq_to_channel(struct libipw_device *ieee, u32 freq);
-u8 libipw_get_channel_flags(struct libipw_device *ieee, u8 channel);
-const struct libipw_channel *libipw_get_channel(struct libipw_device *ieee,
- u8 channel);
-u32 libipw_channel_to_freq(struct libipw_device *ieee, u8 channel);
-
-/* libipw_wx.c */
-int libipw_wx_get_scan(struct libipw_device *ieee, struct iw_request_info *info,
- union iwreq_data *wrqu, char *key);
-int libipw_wx_set_encode(struct libipw_device *ieee,
- struct iw_request_info *info, union iwreq_data *wrqu,
- char *key);
-int libipw_wx_get_encode(struct libipw_device *ieee,
- struct iw_request_info *info, union iwreq_data *wrqu,
- char *key);
-int libipw_wx_set_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-int libipw_wx_get_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra);
-
-static inline void libipw_increment_scans(struct libipw_device *ieee)
-{
- ieee->scans++;
-}
-
-static inline int libipw_get_scans(struct libipw_device *ieee)
-{
- return ieee->scans;
-}
-
-#endif /* LIBIPW_H */
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
deleted file mode 100644
index f2ae3f8f2f5cb..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c
+++ /dev/null
@@ -1,179 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2005 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-
-#include "libipw.h"
-
-int libipw_is_valid_channel(struct libipw_device *ieee, u8 channel)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- /* NOTE: If G mode is currently supported but
- * this is a B only channel, we don't see it
- * as valid. */
- if ((ieee->geo.bg[i].channel == channel) &&
- !(ieee->geo.bg[i].flags & LIBIPW_CH_INVALID) &&
- (!(ieee->mode & IEEE_G) ||
- !(ieee->geo.bg[i].flags & LIBIPW_CH_B_ONLY)))
- return LIBIPW_24GHZ_BAND;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if ((ieee->geo.a[i].channel == channel) &&
- !(ieee->geo.a[i].flags & LIBIPW_CH_INVALID))
- return LIBIPW_52GHZ_BAND;
-
- return 0;
-}
-
-int libipw_channel_to_index(struct libipw_device *ieee, u8 channel)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return -1;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- if (ieee->geo.bg[i].channel == channel)
- return i;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if (ieee->geo.a[i].channel == channel)
- return i;
-
- return -1;
-}
-
-u32 libipw_channel_to_freq(struct libipw_device * ieee, u8 channel)
-{
- const struct libipw_channel * ch;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- ch = libipw_get_channel(ieee, channel);
- if (!ch->channel)
- return 0;
- return ch->freq;
-}
-
-u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq)
-{
- int i;
-
- /* Driver needs to initialize the geography map before using
- * these helper functions */
- if (ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0)
- return 0;
-
- freq /= 100000;
-
- if (ieee->freq_band & LIBIPW_24GHZ_BAND)
- for (i = 0; i < ieee->geo.bg_channels; i++)
- if (ieee->geo.bg[i].freq == freq)
- return ieee->geo.bg[i].channel;
-
- if (ieee->freq_band & LIBIPW_52GHZ_BAND)
- for (i = 0; i < ieee->geo.a_channels; i++)
- if (ieee->geo.a[i].freq == freq)
- return ieee->geo.a[i].channel;
-
- return 0;
-}
-
-void libipw_set_geo(struct libipw_device *ieee,
- const struct libipw_geo *geo)
-{
- memcpy(ieee->geo.name, geo->name, 3);
- ieee->geo.name[3] = '\0';
- ieee->geo.bg_channels = geo->bg_channels;
- ieee->geo.a_channels = geo->a_channels;
- memcpy(ieee->geo.bg, geo->bg, geo->bg_channels *
- sizeof(struct libipw_channel));
- memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
- sizeof(struct libipw_channel));
-}
-
-const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee)
-{
- return &ieee->geo;
-}
-
-u8 libipw_get_channel_flags(struct libipw_device * ieee, u8 channel)
-{
- int index = libipw_channel_to_index(ieee, channel);
-
- if (index == -1)
- return LIBIPW_CH_INVALID;
-
- if (channel <= LIBIPW_24GHZ_CHANNELS)
- return ieee->geo.bg[index].flags;
-
- return ieee->geo.a[index].flags;
-}
-
-static const struct libipw_channel bad_channel = {
- .channel = 0,
- .flags = LIBIPW_CH_INVALID,
- .max_power = 0,
-};
-
-const struct libipw_channel *libipw_get_channel(struct libipw_device
- *ieee, u8 channel)
-{
- int index = libipw_channel_to_index(ieee, channel);
-
- if (index == -1)
- return &bad_channel;
-
- if (channel <= LIBIPW_24GHZ_CHANNELS)
- return &ieee->geo.bg[index];
-
- return &ieee->geo.a[index];
-}
-
-EXPORT_SYMBOL(libipw_get_channel);
-EXPORT_SYMBOL(libipw_get_channel_flags);
-EXPORT_SYMBOL(libipw_is_valid_channel);
-EXPORT_SYMBOL(libipw_freq_to_channel);
-EXPORT_SYMBOL(libipw_channel_to_freq);
-EXPORT_SYMBOL(libipw_channel_to_index);
-EXPORT_SYMBOL(libipw_set_geo);
-EXPORT_SYMBOL(libipw_get_geo);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c
deleted file mode 100644
index 43bab92a4148f..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c
+++ /dev/null
@@ -1,297 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*******************************************************************************
-
- Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
-
- Portions of this file are based on the WEP enablement code provided by the
- Host AP project hostap-drivers v0.1.3
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <j at w1.fi>
- Copyright (c) 2002-2003, Jouni Malinen <j at w1.fi>
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-*******************************************************************************/
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <net/net_namespace.h>
-#include <net/arp.h>
-
-#include "libipw.h"
-
-#define DRV_DESCRIPTION "802.11 data/management/control stack"
-#define DRV_NAME "libipw"
-#define DRV_PROCNAME "ieee80211"
-#define DRV_VERSION LIBIPW_VERSION
-#define DRV_COPYRIGHT "Copyright (C) 2004-2005 Intel Corporation <jketreno at linux.intel.com>"
-
-MODULE_VERSION(DRV_VERSION);
-MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_AUTHOR(DRV_COPYRIGHT);
-MODULE_LICENSE("GPL");
-
-static struct cfg80211_ops libipw_config_ops = { };
-static void *libipw_wiphy_privid = &libipw_wiphy_privid;
-
-static int libipw_networks_allocate(struct libipw_device *ieee)
-{
- int i, j;
-
- for (i = 0; i < MAX_NETWORK_COUNT; i++) {
- ieee->networks[i] = kzalloc(sizeof(struct libipw_network),
- GFP_KERNEL);
- if (!ieee->networks[i]) {
- LIBIPW_ERROR("Out of memory allocating beacons\n");
- for (j = 0; j < i; j++)
- kfree(ieee->networks[j]);
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-
-static inline void libipw_networks_free(struct libipw_device *ieee)
-{
- int i;
-
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- kfree(ieee->networks[i]);
-}
-
-void libipw_networks_age(struct libipw_device *ieee,
- unsigned long age_secs)
-{
- struct libipw_network *network = NULL;
- unsigned long flags;
- unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
-
- spin_lock_irqsave(&ieee->lock, flags);
- list_for_each_entry(network, &ieee->network_list, list) {
- network->last_scanned -= age_jiffies;
- }
- spin_unlock_irqrestore(&ieee->lock, flags);
-}
-EXPORT_SYMBOL(libipw_networks_age);
-
-static void libipw_networks_initialize(struct libipw_device *ieee)
-{
- int i;
-
- INIT_LIST_HEAD(&ieee->network_free_list);
- INIT_LIST_HEAD(&ieee->network_list);
- for (i = 0; i < MAX_NETWORK_COUNT; i++)
- list_add_tail(&ieee->networks[i]->list,
- &ieee->network_free_list);
-}
-
-struct net_device *alloc_libipw(int sizeof_priv, int monitor)
-{
- struct libipw_device *ieee;
- struct net_device *dev;
- int err;
-
- LIBIPW_DEBUG_INFO("Initializing...\n");
-
- dev = alloc_etherdev(sizeof(struct libipw_device) + sizeof_priv);
- if (!dev)
- goto failed;
-
- ieee = netdev_priv(dev);
-
- ieee->dev = dev;
-
- if (!monitor) {
- ieee->wdev.wiphy = wiphy_new(&libipw_config_ops, 0);
- if (!ieee->wdev.wiphy) {
- LIBIPW_ERROR("Unable to allocate wiphy.\n");
- goto failed_free_netdev;
- }
-
- ieee->dev->ieee80211_ptr = &ieee->wdev;
- ieee->wdev.iftype = NL80211_IFTYPE_STATION;
-
- /* Fill-out wiphy structure bits we know... Not enough info
- here to call set_wiphy_dev or set MAC address or channel info
- -- have to do that in ->ndo_init... */
- ieee->wdev.wiphy->privid = libipw_wiphy_privid;
-
- ieee->wdev.wiphy->max_scan_ssids = 1;
- ieee->wdev.wiphy->max_scan_ie_len = 0;
- ieee->wdev.wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION)
- | BIT(NL80211_IFTYPE_ADHOC);
- }
-
- err = libipw_networks_allocate(ieee);
- if (err) {
- LIBIPW_ERROR("Unable to allocate beacon storage: %d\n", err);
- goto failed_free_wiphy;
- }
- libipw_networks_initialize(ieee);
-
- /* Default fragmentation threshold is maximum payload size */
- ieee->fts = DEFAULT_FTS;
- ieee->rts = DEFAULT_FTS;
- ieee->scan_age = DEFAULT_MAX_SCAN_AGE;
- ieee->open_wep = 1;
-
- /* Default to enabling full open WEP with host based encrypt/decrypt */
- ieee->host_encrypt = 1;
- ieee->host_decrypt = 1;
- ieee->host_mc_decrypt = 1;
-
- /* Host fragmentation in Open mode. Default is enabled.
- * Note: host fragmentation is always enabled if host encryption
- * is enabled. For cards can do hardware encryption, they must do
- * hardware fragmentation as well. So we don't need a variable
- * like host_enc_frag. */
- ieee->host_open_frag = 1;
- ieee->ieee802_1x = 1; /* Default to supporting 802.1x */
-
- spin_lock_init(&ieee->lock);
-
- lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock);
-
- ieee->wpa_enabled = 0;
- ieee->drop_unencrypted = 0;
- ieee->privacy_invoked = 0;
-
- return dev;
-
-failed_free_wiphy:
- if (!monitor)
- wiphy_free(ieee->wdev.wiphy);
-failed_free_netdev:
- free_netdev(dev);
-failed:
- return NULL;
-}
-EXPORT_SYMBOL(alloc_libipw);
-
-void free_libipw(struct net_device *dev, int monitor)
-{
- struct libipw_device *ieee = netdev_priv(dev);
-
- lib80211_crypt_info_free(&ieee->crypt_info);
-
- libipw_networks_free(ieee);
-
- /* free cfg80211 resources */
- if (!monitor)
- wiphy_free(ieee->wdev.wiphy);
-
- free_netdev(dev);
-}
-EXPORT_SYMBOL(free_libipw);
-
-#ifdef CONFIG_LIBIPW_DEBUG
-
-static int debug = 0;
-u32 libipw_debug_level = 0;
-EXPORT_SYMBOL_GPL(libipw_debug_level);
-static struct proc_dir_entry *libipw_proc = NULL;
-
-static int debug_level_proc_show(struct seq_file *m, void *v)
-{
- seq_printf(m, "0x%08X\n", libipw_debug_level);
- return 0;
-}
-
-static int debug_level_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, debug_level_proc_show, NULL);
-}
-
-static ssize_t debug_level_proc_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *pos)
-{
- char buf[] = "0x00000000\n";
- size_t len = min(sizeof(buf) - 1, count);
- unsigned long val;
-
- if (copy_from_user(buf, buffer, len))
- return count;
- buf[len] = 0;
- if (sscanf(buf, "%li", &val) != 1)
- printk(KERN_INFO DRV_NAME
- ": %s is not in hex or decimal form.\n", buf);
- else
- libipw_debug_level = val;
-
- return strnlen(buf, len);
-}
-
-static const struct proc_ops debug_level_proc_ops = {
- .proc_open = debug_level_proc_open,
- .proc_read = seq_read,
- .proc_lseek = seq_lseek,
- .proc_release = single_release,
- .proc_write = debug_level_proc_write,
-};
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-static int __init libipw_init(void)
-{
-#ifdef CONFIG_LIBIPW_DEBUG
- struct proc_dir_entry *e;
-
- libipw_debug_level = debug;
- libipw_proc = proc_mkdir(DRV_PROCNAME, init_net.proc_net);
- if (libipw_proc == NULL) {
- LIBIPW_ERROR("Unable to create " DRV_PROCNAME
- " proc directory\n");
- return -EIO;
- }
- e = proc_create("debug_level", 0644, libipw_proc,
- &debug_level_proc_ops);
- if (!e) {
- remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
- libipw_proc = NULL;
- return -EIO;
- }
-#endif /* CONFIG_LIBIPW_DEBUG */
-
- printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
- printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
-
- return 0;
-}
-
-static void __exit libipw_exit(void)
-{
-#ifdef CONFIG_LIBIPW_DEBUG
- if (libipw_proc) {
- remove_proc_entry("debug_level", libipw_proc);
- remove_proc_entry(DRV_PROCNAME, init_net.proc_net);
- libipw_proc = NULL;
- }
-#endif /* CONFIG_LIBIPW_DEBUG */
-}
-
-#ifdef CONFIG_LIBIPW_DEBUG
-#include <linux/moduleparam.h>
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "debug output mask");
-#endif /* CONFIG_LIBIPW_DEBUG */
-
-module_exit(libipw_exit);
-module_init(libipw_init);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
deleted file mode 100644
index 48d6870bbf4e2..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c
+++ /dev/null
@@ -1,1737 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Original code based Host AP (software wireless LAN access point) driver
- * for Intersil Prism2/2.5/3 - hostap.o module, common routines
- *
- * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- * <j at w1.fi>
- * Copyright (c) 2002-2003, Jouni Malinen <j at w1.fi>
- * Copyright (c) 2004-2005, Intel Corporation
- */
-
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/gfp.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-#include <linux/ctype.h>
-
-#include <net/lib80211.h>
-
-#include "libipw.h"
-
-static void libipw_monitor_rx(struct libipw_device *ieee,
- struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats)
-{
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- u16 fc = le16_to_cpu(hdr->frame_control);
-
- skb->dev = ieee->dev;
- skb_reset_mac_header(skb);
- skb_pull(skb, libipw_get_hdrlen(fc));
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_80211_RAW);
- memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
-}
-
-/* Called only as a tasklet (software IRQ) */
-static struct libipw_frag_entry *libipw_frag_cache_find(struct
- libipw_device
- *ieee,
- unsigned int seq,
- unsigned int frag,
- u8 * src,
- u8 * dst)
-{
- struct libipw_frag_entry *entry;
- int i;
-
- for (i = 0; i < LIBIPW_FRAG_CACHE_LEN; i++) {
- entry = &ieee->frag_cache[i];
- if (entry->skb != NULL &&
- time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
- LIBIPW_DEBUG_FRAG("expiring fragment cache entry "
- "seq=%u last_frag=%u\n",
- entry->seq, entry->last_frag);
- dev_kfree_skb_any(entry->skb);
- entry->skb = NULL;
- }
-
- if (entry->skb != NULL && entry->seq == seq &&
- (entry->last_frag + 1 == frag || frag == -1) &&
- ether_addr_equal(entry->src_addr, src) &&
- ether_addr_equal(entry->dst_addr, dst))
- return entry;
- }
-
- return NULL;
-}
-
-/* Called only as a tasklet (software IRQ) */
-static struct sk_buff *libipw_frag_cache_get(struct libipw_device *ieee,
- struct libipw_hdr_4addr *hdr)
-{
- struct sk_buff *skb = NULL;
- u16 sc;
- unsigned int frag, seq;
- struct libipw_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctl);
- frag = WLAN_GET_SEQ_FRAG(sc);
- seq = WLAN_GET_SEQ_SEQ(sc);
-
- if (frag == 0) {
- /* Reserve enough space to fit maximum frame length */
- skb = dev_alloc_skb(ieee->dev->mtu +
- sizeof(struct libipw_hdr_4addr) +
- 8 /* LLC */ +
- 2 /* alignment */ +
- 8 /* WEP */ + ETH_ALEN /* WDS */ );
- if (skb == NULL)
- return NULL;
-
- entry = &ieee->frag_cache[ieee->frag_next_idx];
- ieee->frag_next_idx++;
- if (ieee->frag_next_idx >= LIBIPW_FRAG_CACHE_LEN)
- ieee->frag_next_idx = 0;
-
- if (entry->skb != NULL)
- dev_kfree_skb_any(entry->skb);
-
- entry->first_frag_time = jiffies;
- entry->seq = seq;
- entry->last_frag = frag;
- entry->skb = skb;
- memcpy(entry->src_addr, hdr->addr2, ETH_ALEN);
- memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN);
- } else {
- /* received a fragment of a frame for which the head fragment
- * should have already been received */
- entry = libipw_frag_cache_find(ieee, seq, frag, hdr->addr2,
- hdr->addr1);
- if (entry != NULL) {
- entry->last_frag = frag;
- skb = entry->skb;
- }
- }
-
- return skb;
-}
-
-/* Called only as a tasklet (software IRQ) */
-static int libipw_frag_cache_invalidate(struct libipw_device *ieee,
- struct libipw_hdr_4addr *hdr)
-{
- u16 sc;
- unsigned int seq;
- struct libipw_frag_entry *entry;
-
- sc = le16_to_cpu(hdr->seq_ctl);
- seq = WLAN_GET_SEQ_SEQ(sc);
-
- entry = libipw_frag_cache_find(ieee, seq, -1, hdr->addr2,
- hdr->addr1);
-
- if (entry == NULL) {
- LIBIPW_DEBUG_FRAG("could not invalidate fragment cache "
- "entry (seq=%u)\n", seq);
- return -1;
- }
-
- entry->skb = NULL;
- return 0;
-}
-
-#ifdef NOT_YET
-/* libipw_rx_frame_mgtmt
- *
- * Responsible for handling management control frames
- *
- * Called by libipw_rx */
-static int
-libipw_rx_frame_mgmt(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats, u16 type,
- u16 stype)
-{
- if (ieee->iw_mode == IW_MODE_MASTER) {
- printk(KERN_DEBUG "%s: Master mode not yet supported.\n",
- ieee->dev->name);
- return 0;
-/*
- hostap_update_sta_ps(ieee, (struct hostap_libipw_hdr_4addr *)
- skb->data);*/
- }
-
- if (ieee->hostapd && type == WLAN_FC_TYPE_MGMT) {
- if (stype == WLAN_FC_STYPE_BEACON &&
- ieee->iw_mode == IW_MODE_MASTER) {
- struct sk_buff *skb2;
- /* Process beacon frames also in kernel driver to
- * update STA(AP) table statistics */
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2)
- hostap_rx(skb2->dev, skb2, rx_stats);
- }
-
- /* send management frames to the user space daemon for
- * processing */
- ieee->apdevstats.rx_packets++;
- ieee->apdevstats.rx_bytes += skb->len;
- prism2_rx_80211(ieee->apdev, skb, rx_stats, PRISM2_RX_MGMT);
- return 0;
- }
-
- if (ieee->iw_mode == IW_MODE_MASTER) {
- if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) {
- printk(KERN_DEBUG "%s: unknown management frame "
- "(type=0x%02x, stype=0x%02x) dropped\n",
- skb->dev->name, type, stype);
- return -1;
- }
-
- hostap_rx(skb->dev, skb, rx_stats);
- return 0;
- }
-
- printk(KERN_DEBUG "%s: hostap_rx_frame_mgmt: management frame "
- "received in non-Host AP mode\n", skb->dev->name);
- return -1;
-}
-#endif
-
-/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
-/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
-static unsigned char libipw_rfc1042_header[] =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
-
-/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
-static unsigned char libipw_bridge_tunnel_header[] =
- { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-/* No encapsulation header if EtherType < 0x600 (=length) */
-
-/* Called by libipw_rx_frame_decrypt */
-static int libipw_is_eapol_frame(struct libipw_device *ieee,
- struct sk_buff *skb)
-{
- struct net_device *dev = ieee->dev;
- u16 fc, ethertype;
- struct libipw_hdr_3addr *hdr;
- u8 *pos;
-
- if (skb->len < 24)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
-
- /* check that the frame is unicast frame to us */
- if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr) &&
- ether_addr_equal(hdr->addr3, dev->dev_addr)) {
- /* ToDS frame with own addr BSSID and DA */
- } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS &&
- ether_addr_equal(hdr->addr1, dev->dev_addr)) {
- /* FromDS frame with own addr as DA */
- } else
- return 0;
-
- if (skb->len < 24 + 8)
- return 0;
-
- /* check for port access entity Ethernet type */
- pos = skb->data + 24;
- ethertype = (pos[6] << 8) | pos[7];
- if (ethertype == ETH_P_PAE)
- return 1;
-
- return 0;
-}
-
-/* Called only as a tasklet (software IRQ), by libipw_rx */
-static int
-libipw_rx_frame_decrypt(struct libipw_device *ieee, struct sk_buff *skb,
- struct lib80211_crypt_data *crypt)
-{
- struct libipw_hdr_3addr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- LIBIPW_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n",
- hdr->addr2, res);
- if (res == -2)
- LIBIPW_DEBUG_DROP("Decryption failed ICV "
- "mismatch (key %d)\n",
- skb->data[hdrlen + 3] >> 6);
- ieee->ieee_stats.rx_discards_undecryptable++;
- return -1;
- }
-
- return res;
-}
-
-/* Called only as a tasklet (software IRQ), by libipw_rx */
-static int
-libipw_rx_frame_decrypt_msdu(struct libipw_device *ieee,
- struct sk_buff *skb, int keyidx,
- struct lib80211_crypt_data *crypt)
-{
- struct libipw_hdr_3addr *hdr;
- int res, hdrlen;
-
- if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
- return 0;
-
- hdr = (struct libipw_hdr_3addr *)skb->data;
- hdrlen = libipw_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
-
- atomic_inc(&crypt->refcnt);
- res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2,
- keyidx);
- return -1;
- }
-
- return 0;
-}
-
-/* All received frames are sent to this function. @skb contains the frame in
- * IEEE 802.11 format, i.e., in the format it was sent over air.
- * This function is called only as a tasklet (software IRQ). */
-int libipw_rx(struct libipw_device *ieee, struct sk_buff *skb,
- struct libipw_rx_stats *rx_stats)
-{
- struct net_device *dev = ieee->dev;
- struct libipw_hdr_4addr *hdr;
- size_t hdrlen;
- u16 fc, type, stype, sc;
- unsigned int frag;
- u8 *payload;
- u16 ethertype;
-#ifdef NOT_YET
- struct net_device *wds = NULL;
- struct sk_buff *skb2 = NULL;
- struct net_device *wds = NULL;
- int frame_authorized = 0;
- int from_assoc_ap = 0;
- void *sta = NULL;
-#endif
- u8 dst[ETH_ALEN];
- u8 src[ETH_ALEN];
- struct lib80211_crypt_data *crypt = NULL;
- int keyidx = 0;
- int can_be_decrypted = 0;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- if (skb->len < 10) {
- printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
- goto rx_dropped;
- }
-
- fc = le16_to_cpu(hdr->frame_ctl);
- type = WLAN_FC_GET_TYPE(fc);
- stype = WLAN_FC_GET_STYPE(fc);
- sc = le16_to_cpu(hdr->seq_ctl);
- frag = WLAN_GET_SEQ_FRAG(sc);
- hdrlen = libipw_get_hdrlen(fc);
-
- if (skb->len < hdrlen) {
- printk(KERN_INFO "%s: invalid SKB length %d\n",
- dev->name, skb->len);
- goto rx_dropped;
- }
-
- /* Put this code here so that we avoid duplicating it in all
- * Rx paths. - Jean II */
-#ifdef CONFIG_WIRELESS_EXT
-#ifdef IW_WIRELESS_SPY /* defined in iw_handler.h */
- /* If spy monitoring on */
- if (ieee->spy_data.spy_number > 0) {
- struct iw_quality wstats;
-
- wstats.updated = 0;
- if (rx_stats->mask & LIBIPW_STATMASK_RSSI) {
- wstats.level = rx_stats->signal;
- wstats.updated |= IW_QUAL_LEVEL_UPDATED;
- } else
- wstats.updated |= IW_QUAL_LEVEL_INVALID;
-
- if (rx_stats->mask & LIBIPW_STATMASK_NOISE) {
- wstats.noise = rx_stats->noise;
- wstats.updated |= IW_QUAL_NOISE_UPDATED;
- } else
- wstats.updated |= IW_QUAL_NOISE_INVALID;
-
- if (rx_stats->mask & LIBIPW_STATMASK_SIGNAL) {
- wstats.qual = rx_stats->signal;
- wstats.updated |= IW_QUAL_QUAL_UPDATED;
- } else
- wstats.updated |= IW_QUAL_QUAL_INVALID;
-
- /* Update spy records */
- wireless_spy_update(ieee->dev, hdr->addr2, &wstats);
- }
-#endif /* IW_WIRELESS_SPY */
-#endif /* CONFIG_WIRELESS_EXT */
-
-#ifdef NOT_YET
- hostap_update_rx_stats(local->ap, hdr, rx_stats);
-#endif
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
- libipw_monitor_rx(ieee, skb, rx_stats);
- return 1;
- }
-
- can_be_decrypted = (is_multicast_ether_addr(hdr->addr1) ||
- is_broadcast_ether_addr(hdr->addr2)) ?
- ieee->host_mc_decrypt : ieee->host_decrypt;
-
- if (can_be_decrypted) {
- if (skb->len >= hdrlen + 3) {
- /* Top two-bits of byte 3 are the key index */
- keyidx = skb->data[hdrlen + 3] >> 6;
- }
-
- /* ieee->crypt[] is WEP_KEY (4) in length. Given that keyidx
- * is only allowed 2-bits of storage, no value of keyidx can
- * be provided via above code that would result in keyidx
- * being out of range */
- crypt = ieee->crypt_info.crypt[keyidx];
-
-#ifdef NOT_YET
- sta = NULL;
-
- /* Use station specific key to override default keys if the
- * receiver address is a unicast address ("individual RA"). If
- * bcrx_sta_key parameter is set, station specific key is used
- * even with broad/multicast targets (this is against IEEE
- * 802.11, but makes it easier to use different keys with
- * stations that do not support WEP key mapping). */
-
- if (is_unicast_ether_addr(hdr->addr1) || local->bcrx_sta_key)
- (void)hostap_handle_sta_crypto(local, hdr, &crypt,
- &sta);
-#endif
-
- /* allow NULL decrypt to indicate an station specific override
- * for default encryption */
- if (crypt && (crypt->ops == NULL ||
- crypt->ops->decrypt_mpdu == NULL))
- crypt = NULL;
-
- if (!crypt && (fc & IEEE80211_FCTL_PROTECTED)) {
- /* This seems to be triggered by some (multicast?)
- * frames from other than current BSS, so just drop the
- * frames silently instead of filling system log with
- * these reports. */
- LIBIPW_DEBUG_DROP("Decryption failed (not set)"
- " (SA=%pM)\n", hdr->addr2);
- ieee->ieee_stats.rx_discards_undecryptable++;
- goto rx_dropped;
- }
- }
-#ifdef NOT_YET
- if (type != WLAN_FC_TYPE_DATA) {
- if (type == WLAN_FC_TYPE_MGMT && stype == WLAN_FC_STYPE_AUTH &&
- fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt &&
- (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) {
- printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
- "from %pM\n", dev->name, hdr->addr2);
- /* TODO: could inform hostapd about this so that it
- * could send auth failure report */
- goto rx_dropped;
- }
-
- if (libipw_rx_frame_mgmt(ieee, skb, rx_stats, type, stype))
- goto rx_dropped;
- else
- goto rx_exit;
- }
-#endif
- /* drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.29) */
- if (sc == ieee->prev_seq_ctl)
- goto rx_dropped;
- else
- ieee->prev_seq_ctl = sc;
-
- /* Data frame - extract src/dst addresses */
- if (skb->len < LIBIPW_3ADDR_LEN)
- goto rx_dropped;
-
- switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
- case IEEE80211_FCTL_FROMDS:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr3, ETH_ALEN);
- break;
- case IEEE80211_FCTL_TODS:
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
- if (skb->len < LIBIPW_4ADDR_LEN)
- goto rx_dropped;
- memcpy(dst, hdr->addr3, ETH_ALEN);
- memcpy(src, hdr->addr4, ETH_ALEN);
- break;
- default:
- memcpy(dst, hdr->addr1, ETH_ALEN);
- memcpy(src, hdr->addr2, ETH_ALEN);
- break;
- }
-
-#ifdef NOT_YET
- if (hostap_rx_frame_wds(ieee, hdr, fc, &wds))
- goto rx_dropped;
- if (wds) {
- skb->dev = dev = wds;
- stats = hostap_get_stats(dev);
- }
-
- if (ieee->iw_mode == IW_MODE_MASTER && !wds &&
- (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_FROMDS && ieee->stadev &&
- ether_addr_equal(hdr->addr2, ieee->assoc_ap_addr)) {
- /* Frame from BSSID of the AP for which we are a client */
- skb->dev = dev = ieee->stadev;
- stats = hostap_get_stats(dev);
- from_assoc_ap = 1;
- }
-#endif
-
-#ifdef NOT_YET
- if ((ieee->iw_mode == IW_MODE_MASTER ||
- ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) {
- switch (hostap_handle_sta_rx(ieee, dev, skb, rx_stats,
- wds != NULL)) {
- case AP_RX_CONTINUE_NOT_AUTHORIZED:
- frame_authorized = 0;
- break;
- case AP_RX_CONTINUE:
- frame_authorized = 1;
- break;
- case AP_RX_DROP:
- goto rx_dropped;
- case AP_RX_EXIT:
- goto rx_exit;
- }
- }
-#endif
-
- /* Nullfunc frames may have PS-bit set, so they must be passed to
- * hostap_handle_sta_rx() before being dropped here. */
-
- stype &= ~IEEE80211_STYPE_QOS_DATA;
-
- if (stype != IEEE80211_STYPE_DATA &&
- stype != IEEE80211_STYPE_DATA_CFACK &&
- stype != IEEE80211_STYPE_DATA_CFPOLL &&
- stype != IEEE80211_STYPE_DATA_CFACKPOLL) {
- if (stype != IEEE80211_STYPE_NULLFUNC)
- LIBIPW_DEBUG_DROP("RX: dropped data frame "
- "with no data (type=0x%02x, "
- "subtype=0x%02x, len=%d)\n",
- type, stype, skb->len);
- goto rx_dropped;
- }
-
- /* skb: hdr + (possibly fragmented, possibly encrypted) payload */
-
- if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- (keyidx = libipw_rx_frame_decrypt(ieee, skb, crypt)) < 0)
- goto rx_dropped;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
-
- /* skb: hdr + (possibly fragmented) plaintext payload */
- // PR: FIXME: hostap has additional conditions in the "if" below:
- // ieee->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
- if ((frag != 0) || (fc & IEEE80211_FCTL_MOREFRAGS)) {
- int flen;
- struct sk_buff *frag_skb = libipw_frag_cache_get(ieee, hdr);
- LIBIPW_DEBUG_FRAG("Rx Fragment received (%u)\n", frag);
-
- if (!frag_skb) {
- LIBIPW_DEBUG(LIBIPW_DL_RX | LIBIPW_DL_FRAG,
- "Rx cannot get skb from fragment "
- "cache (morefrag=%d seq=%u frag=%u)\n",
- (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
- WLAN_GET_SEQ_SEQ(sc), frag);
- goto rx_dropped;
- }
-
- flen = skb->len;
- if (frag != 0)
- flen -= hdrlen;
-
- if (frag_skb->tail + flen > frag_skb->end) {
- printk(KERN_WARNING "%s: host decrypted and "
- "reassembled frame did not fit skb\n",
- dev->name);
- libipw_frag_cache_invalidate(ieee, hdr);
- goto rx_dropped;
- }
-
- if (frag == 0) {
- /* copy first fragment (including full headers) into
- * beginning of the fragment cache skb */
- skb_copy_from_linear_data(skb, skb_put(frag_skb, flen), flen);
- } else {
- /* append frame payload to the end of the fragment
- * cache skb */
- skb_copy_from_linear_data_offset(skb, hdrlen,
- skb_put(frag_skb, flen), flen);
- }
- dev_kfree_skb_any(skb);
- skb = NULL;
-
- if (fc & IEEE80211_FCTL_MOREFRAGS) {
- /* more fragments expected - leave the skb in fragment
- * cache for now; it will be delivered to upper layers
- * after all fragments have been received */
- goto rx_exit;
- }
-
- /* this was the last fragment and the frame will be
- * delivered, so remove skb from fragment cache */
- skb = frag_skb;
- hdr = (struct libipw_hdr_4addr *)skb->data;
- libipw_frag_cache_invalidate(ieee, hdr);
- }
-
- /* skb: hdr + (possible reassembled) full MSDU payload; possibly still
- * encrypted/authenticated */
- if ((fc & IEEE80211_FCTL_PROTECTED) && can_be_decrypted &&
- libipw_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt))
- goto rx_dropped;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep) {
- if ( /*ieee->ieee802_1x && */
- libipw_is_eapol_frame(ieee, skb)) {
- /* pass unencrypted EAPOL frames even if encryption is
- * configured */
- } else {
- LIBIPW_DEBUG_DROP("encryption configured, but RX "
- "frame not encrypted (SA=%pM)\n",
- hdr->addr2);
- goto rx_dropped;
- }
- }
-
- if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep &&
- !libipw_is_eapol_frame(ieee, skb)) {
- LIBIPW_DEBUG_DROP("dropped unencrypted RX data "
- "frame from %pM (drop_unencrypted=1)\n",
- hdr->addr2);
- goto rx_dropped;
- }
-
- /* If the frame was decrypted in hardware, we may need to strip off
- * any security data (IV, ICV, etc) that was left behind */
- if (!can_be_decrypted && (fc & IEEE80211_FCTL_PROTECTED) &&
- ieee->host_strip_iv_icv) {
- int trimlen = 0;
-
- /* Top two-bits of byte 3 are the key index */
- if (skb->len >= hdrlen + 3)
- keyidx = skb->data[hdrlen + 3] >> 6;
-
- /* To strip off any security data which appears before the
- * payload, we simply increase hdrlen (as the header gets
- * chopped off immediately below). For the security data which
- * appears after the payload, we use skb_trim. */
-
- switch (ieee->sec.encode_alg[keyidx]) {
- case SEC_ALG_WEP:
- /* 4 byte IV */
- hdrlen += 4;
- /* 4 byte ICV */
- trimlen = 4;
- break;
- case SEC_ALG_TKIP:
- /* 4 byte IV, 4 byte ExtIV */
- hdrlen += 8;
- /* 8 byte MIC, 4 byte ICV */
- trimlen = 12;
- break;
- case SEC_ALG_CCMP:
- /* 8 byte CCMP header */
- hdrlen += 8;
- /* 8 byte MIC */
- trimlen = 8;
- break;
- }
-
- if (skb->len < trimlen)
- goto rx_dropped;
-
- __skb_trim(skb, skb->len - trimlen);
-
- if (skb->len < hdrlen)
- goto rx_dropped;
- }
-
- /* skb: hdr + (possible reassembled) full plaintext payload */
-
- payload = skb->data + hdrlen;
- ethertype = (payload[6] << 8) | payload[7];
-
-#ifdef NOT_YET
- /* If IEEE 802.1X is used, check whether the port is authorized to send
- * the received frame. */
- if (ieee->ieee802_1x && ieee->iw_mode == IW_MODE_MASTER) {
- if (ethertype == ETH_P_PAE) {
- printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n",
- dev->name);
- if (ieee->hostapd && ieee->apdev) {
- /* Send IEEE 802.1X frames to the user
- * space daemon for processing */
- prism2_rx_80211(ieee->apdev, skb, rx_stats,
- PRISM2_RX_MGMT);
- ieee->apdevstats.rx_packets++;
- ieee->apdevstats.rx_bytes += skb->len;
- goto rx_exit;
- }
- } else if (!frame_authorized) {
- printk(KERN_DEBUG "%s: dropped frame from "
- "unauthorized port (IEEE 802.1X): "
- "ethertype=0x%04x\n", dev->name, ethertype);
- goto rx_dropped;
- }
- }
-#endif
-
- /* convert hdr + possible LLC headers into Ethernet header */
- if (skb->len - hdrlen >= 8 &&
- ((memcmp(payload, libipw_rfc1042_header, SNAP_SIZE) == 0 &&
- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- memcmp(payload, libipw_bridge_tunnel_header, SNAP_SIZE) == 0)) {
- /* remove RFC1042 or Bridge-Tunnel encapsulation and
- * replace EtherType */
- skb_pull(skb, hdrlen + SNAP_SIZE);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- } else {
- __be16 len;
- /* Leave Ethernet header part of hdr and full payload */
- skb_pull(skb, hdrlen);
- len = htons(skb->len);
- memcpy(skb_push(skb, 2), &len, 2);
- memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
- memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
- }
-
-#ifdef NOT_YET
- if (wds && ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
- IEEE80211_FCTL_TODS) && skb->len >= ETH_HLEN + ETH_ALEN) {
- /* Non-standard frame: get addr4 from its bogus location after
- * the payload */
- skb_copy_to_linear_data_offset(skb, ETH_ALEN,
- skb->data + skb->len - ETH_ALEN,
- ETH_ALEN);
- skb_trim(skb, skb->len - ETH_ALEN);
- }
-#endif
-
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += skb->len;
-
-#ifdef NOT_YET
- if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
- if (is_multicast_ether_addr(dst)) {
- /* copy multicast frame both to the higher layers and
- * to the wireless media */
- ieee->ap->bridged_multicast++;
- skb2 = skb_clone(skb, GFP_ATOMIC);
- if (skb2 == NULL)
- printk(KERN_DEBUG "%s: skb_clone failed for "
- "multicast frame\n", dev->name);
- } else if (hostap_is_sta_assoc(ieee->ap, dst)) {
- /* send frame directly to the associated STA using
- * wireless media and not passing to higher layers */
- ieee->ap->bridged_unicast++;
- skb2 = skb;
- skb = NULL;
- }
- }
-
- if (skb2 != NULL) {
- /* send to wireless media */
- skb2->dev = dev;
- skb2->protocol = htons(ETH_P_802_3);
- skb_reset_mac_header(skb2);
- skb_reset_network_header(skb2);
- /* skb2->network_header += ETH_HLEN; */
- dev_queue_xmit(skb2);
- }
-#endif
-
- if (skb) {
- skb->protocol = eth_type_trans(skb, dev);
- memset(skb->cb, 0, sizeof(skb->cb));
- skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */
- if (netif_rx(skb) == NET_RX_DROP) {
- /* netif_rx always succeeds, but it might drop
- * the packet. If it drops the packet, we log that
- * in our stats. */
- LIBIPW_DEBUG_DROP
- ("RX: netif_rx dropped the packet\n");
- dev->stats.rx_dropped++;
- }
- }
-
- rx_exit:
-#ifdef NOT_YET
- if (sta)
- hostap_handle_sta_release(sta);
-#endif
- return 1;
-
- rx_dropped:
- dev->stats.rx_dropped++;
-
- /* Returning 0 indicates to caller that we have not handled the SKB--
- * so it is still allocated and can be used again by underlying
- * hardware as a DMA target */
- return 0;
-}
-
-/* Filter out unrelated packets, call libipw_rx[_mgt]
- * This function takes over the skb, it should not be used again after calling
- * this function. */
-void libipw_rx_any(struct libipw_device *ieee,
- struct sk_buff *skb, struct libipw_rx_stats *stats)
-{
- struct libipw_hdr_4addr *hdr;
- int is_packet_for_us;
- u16 fc;
-
- if (ieee->iw_mode == IW_MODE_MONITOR) {
- if (!libipw_rx(ieee, skb, stats))
- dev_kfree_skb_irq(skb);
- return;
- }
-
- if (skb->len < sizeof(struct ieee80211_hdr))
- goto drop_free;
-
- hdr = (struct libipw_hdr_4addr *)skb->data;
- fc = le16_to_cpu(hdr->frame_ctl);
-
- if ((fc & IEEE80211_FCTL_VERS) != 0)
- goto drop_free;
-
- switch (fc & IEEE80211_FCTL_FTYPE) {
- case IEEE80211_FTYPE_MGMT:
- if (skb->len < sizeof(struct libipw_hdr_3addr))
- goto drop_free;
- libipw_rx_mgt(ieee, hdr, stats);
- dev_kfree_skb_irq(skb);
- return;
- case IEEE80211_FTYPE_DATA:
- break;
- case IEEE80211_FTYPE_CTL:
- return;
- default:
- return;
- }
-
- is_packet_for_us = 0;
- switch (ieee->iw_mode) {
- case IW_MODE_ADHOC:
- /* our BSS and not from/to DS */
- if (ether_addr_equal(hdr->addr3, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == 0) {
- /* promisc: get all */
- if (ieee->dev->flags & IFF_PROMISC)
- is_packet_for_us = 1;
- /* to us */
- else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- /* mcast */
- else if (is_multicast_ether_addr(hdr->addr1))
- is_packet_for_us = 1;
- }
- break;
- case IW_MODE_INFRA:
- /* our BSS (== from our AP) and from DS */
- if (ether_addr_equal(hdr->addr2, ieee->bssid))
- if ((fc & (IEEE80211_FCTL_TODS+IEEE80211_FCTL_FROMDS)) == IEEE80211_FCTL_FROMDS) {
- /* promisc: get all */
- if (ieee->dev->flags & IFF_PROMISC)
- is_packet_for_us = 1;
- /* to us */
- else if (ether_addr_equal(hdr->addr1, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- /* mcast */
- else if (is_multicast_ether_addr(hdr->addr1)) {
- /* not our own packet bcasted from AP */
- if (!ether_addr_equal(hdr->addr3, ieee->dev->dev_addr))
- is_packet_for_us = 1;
- }
- }
- break;
- default:
- /* ? */
- break;
- }
-
- if (is_packet_for_us)
- if (!libipw_rx(ieee, skb, stats))
- dev_kfree_skb_irq(skb);
- return;
-
-drop_free:
- dev_kfree_skb_irq(skb);
- ieee->dev->stats.rx_dropped++;
-}
-
-#define MGMT_FRAME_FIXED_PART_LENGTH 0x24
-
-static u8 qos_oui[QOS_OUI_LEN] = { 0x00, 0x50, 0xF2 };
-
-/*
-* Make the structure we read from the beacon packet to have
-* the right values
-*/
-static int libipw_verify_qos_info(struct libipw_qos_information_element
- *info_element, int sub_type)
-{
- if (info_element->elementID != QOS_ELEMENT_ID)
- return -1;
- if (info_element->qui_subtype != sub_type)
- return -1;
- if (memcmp(info_element->qui, qos_oui, QOS_OUI_LEN))
- return -1;
- if (info_element->qui_type != QOS_OUI_TYPE)
- return -1;
- if (info_element->version != QOS_VERSION_1)
- return -1;
-
- return 0;
-}
-
-/*
- * Parse a QoS parameter element
- */
-static int libipw_read_qos_param_element(
- struct libipw_qos_parameter_info *element_param,
- struct libipw_info_element *info_element)
-{
- size_t size = sizeof(*element_param);
-
- if (!element_param || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_param, info_element, size);
- return libipw_verify_qos_info(&element_param->info_element,
- QOS_OUI_PARAM_SUB_TYPE);
-}
-
-/*
- * Parse a QoS information element
- */
-static int libipw_read_qos_info_element(
- struct libipw_qos_information_element *element_info,
- struct libipw_info_element *info_element)
-{
- size_t size = sizeof(struct libipw_qos_information_element) - 2;
-
- if (!element_info || !info_element || info_element->len != size - 2)
- return -1;
-
- memcpy(element_info, info_element, size);
- return libipw_verify_qos_info(element_info, QOS_OUI_INFO_SUB_TYPE);
-}
-
-/*
- * Write QoS parameters from the ac parameters.
- */
-static void libipw_qos_convert_ac_to_parameters(struct
- libipw_qos_parameter_info
- *param_elm, struct
- libipw_qos_parameters
- *qos_param)
-{
- int i;
- struct libipw_qos_ac_parameter *ac_params;
- u32 txop;
- u8 cw_min;
- u8 cw_max;
-
- for (i = 0; i < QOS_QUEUE_NUM; i++) {
- ac_params = &(param_elm->ac_params_record[i]);
-
- qos_param->aifs[i] = (ac_params->aci_aifsn) & 0x0F;
- qos_param->aifs[i] -= (qos_param->aifs[i] < 2) ? 0 : 2;
-
- cw_min = ac_params->ecw_min_max & 0x0F;
- qos_param->cw_min[i] = cpu_to_le16((1 << cw_min) - 1);
-
- cw_max = (ac_params->ecw_min_max & 0xF0) >> 4;
- qos_param->cw_max[i] = cpu_to_le16((1 << cw_max) - 1);
-
- qos_param->flag[i] =
- (ac_params->aci_aifsn & 0x10) ? 0x01 : 0x00;
-
- txop = le16_to_cpu(ac_params->tx_op_limit) * 32;
- qos_param->tx_op_limit[i] = cpu_to_le16(txop);
- }
-}
-
-/*
- * we have a generic data element which it may contain QoS information or
- * parameters element. check the information element length to decide
- * which type to read
- */
-static int libipw_parse_qos_info_param_IE(struct libipw_info_element
- *info_element,
- struct libipw_network *network)
-{
- int rc = 0;
- struct libipw_qos_parameters *qos_param = NULL;
- struct libipw_qos_information_element qos_info_element;
-
- rc = libipw_read_qos_info_element(&qos_info_element, info_element);
-
- if (rc == 0) {
- network->qos_data.param_count = qos_info_element.ac_info & 0x0F;
- network->flags |= NETWORK_HAS_QOS_INFORMATION;
- } else {
- struct libipw_qos_parameter_info param_element;
-
- rc = libipw_read_qos_param_element(¶m_element,
- info_element);
- if (rc == 0) {
- qos_param = &(network->qos_data.parameters);
- libipw_qos_convert_ac_to_parameters(¶m_element,
- qos_param);
- network->flags |= NETWORK_HAS_QOS_PARAMETERS;
- network->qos_data.param_count =
- param_element.info_element.ac_info & 0x0F;
- }
- }
-
- if (rc == 0) {
- LIBIPW_DEBUG_QOS("QoS is supported\n");
- network->qos_data.supported = 1;
- }
- return rc;
-}
-
-#ifdef CONFIG_LIBIPW_DEBUG
-#define MFIE_STRING(x) case WLAN_EID_ ##x: return #x
-
-static const char *get_info_element_string(u16 id)
-{
- switch (id) {
- MFIE_STRING(SSID);
- MFIE_STRING(SUPP_RATES);
- MFIE_STRING(FH_PARAMS);
- MFIE_STRING(DS_PARAMS);
- MFIE_STRING(CF_PARAMS);
- MFIE_STRING(TIM);
- MFIE_STRING(IBSS_PARAMS);
- MFIE_STRING(COUNTRY);
- MFIE_STRING(REQUEST);
- MFIE_STRING(CHALLENGE);
- MFIE_STRING(PWR_CONSTRAINT);
- MFIE_STRING(PWR_CAPABILITY);
- MFIE_STRING(TPC_REQUEST);
- MFIE_STRING(TPC_REPORT);
- MFIE_STRING(SUPPORTED_CHANNELS);
- MFIE_STRING(CHANNEL_SWITCH);
- MFIE_STRING(MEASURE_REQUEST);
- MFIE_STRING(MEASURE_REPORT);
- MFIE_STRING(QUIET);
- MFIE_STRING(IBSS_DFS);
- MFIE_STRING(ERP_INFO);
- MFIE_STRING(RSN);
- MFIE_STRING(EXT_SUPP_RATES);
- MFIE_STRING(VENDOR_SPECIFIC);
- MFIE_STRING(QOS_PARAMETER);
- default:
- return "UNKNOWN";
- }
-}
-#endif
-
-static int libipw_parse_info_param(struct libipw_info_element
- *info_element, u16 length,
- struct libipw_network *network)
-{
- u8 i;
-#ifdef CONFIG_LIBIPW_DEBUG
- char rates_str[64];
- char *p;
-#endif
-
- while (length >= sizeof(*info_element)) {
- if (sizeof(*info_element) + info_element->len > length) {
- LIBIPW_DEBUG_MGMT("Info elem: parse failed: "
- "info_element->len + 2 > left : "
- "info_element->len+2=%zd left=%d, id=%d.\n",
- info_element->len +
- sizeof(*info_element),
- length, info_element->id);
- /* We stop processing but don't return an error here
- * because some misbehaviour APs break this rule. ie.
- * Orinoco AP1000. */
- break;
- }
-
- switch (info_element->id) {
- case WLAN_EID_SSID:
- network->ssid_len = min(info_element->len,
- (u8) IW_ESSID_MAX_SIZE);
- memcpy(network->ssid, info_element->data,
- network->ssid_len);
- if (network->ssid_len < IW_ESSID_MAX_SIZE)
- memset(network->ssid + network->ssid_len, 0,
- IW_ESSID_MAX_SIZE - network->ssid_len);
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_SSID: '%*pE' len=%d.\n",
- network->ssid_len, network->ssid,
- network->ssid_len);
- break;
-
- case WLAN_EID_SUPP_RATES:
-#ifdef CONFIG_LIBIPW_DEBUG
- p = rates_str;
-#endif
- network->rates_len = min(info_element->len,
- MAX_RATES_LENGTH);
- for (i = 0; i < network->rates_len; i++) {
- network->rates[i] = info_element->data[i];
-#ifdef CONFIG_LIBIPW_DEBUG
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates[i]);
-#endif
- if (libipw_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- LIBIPW_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
- }
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n",
- rates_str, network->rates_len);
- break;
-
- case WLAN_EID_EXT_SUPP_RATES:
-#ifdef CONFIG_LIBIPW_DEBUG
- p = rates_str;
-#endif
- network->rates_ex_len = min(info_element->len,
- MAX_RATES_EX_LENGTH);
- for (i = 0; i < network->rates_ex_len; i++) {
- network->rates_ex[i] = info_element->data[i];
-#ifdef CONFIG_LIBIPW_DEBUG
- p += scnprintf(p, sizeof(rates_str) -
- (p - rates_str), "%02X ",
- network->rates_ex[i]);
-#endif
- if (libipw_is_ofdm_rate
- (info_element->data[i])) {
- network->flags |= NETWORK_HAS_OFDM;
- if (info_element->data[i] &
- LIBIPW_BASIC_RATE_MASK)
- network->flags &=
- ~NETWORK_HAS_CCK;
- }
- }
-
- LIBIPW_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n",
- rates_str, network->rates_ex_len);
- break;
-
- case WLAN_EID_DS_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n",
- info_element->data[0]);
- network->channel = info_element->data[0];
- break;
-
- case WLAN_EID_FH_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n");
- break;
-
- case WLAN_EID_CF_PARAMS:
- LIBIPW_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n");
- break;
-
- case WLAN_EID_TIM:
- network->tim.tim_count = info_element->data[0];
- network->tim.tim_period = info_element->data[1];
- LIBIPW_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n");
- break;
-
- case WLAN_EID_ERP_INFO:
- network->erp_value = info_element->data[0];
- network->flags |= NETWORK_HAS_ERP_VALUE;
- LIBIPW_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
- network->erp_value);
- break;
-
- case WLAN_EID_IBSS_PARAMS:
- network->atim_window = info_element->data[0];
- LIBIPW_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n",
- network->atim_window);
- break;
-
- case WLAN_EID_CHALLENGE:
- LIBIPW_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
- break;
-
- case WLAN_EID_VENDOR_SPECIFIC:
- LIBIPW_DEBUG_MGMT("WLAN_EID_VENDOR_SPECIFIC: %d bytes\n",
- info_element->len);
- if (!libipw_parse_qos_info_param_IE(info_element,
- network))
- break;
-
- if (info_element->len >= 4 &&
- info_element->data[0] == 0x00 &&
- info_element->data[1] == 0x50 &&
- info_element->data[2] == 0xf2 &&
- info_element->data[3] == 0x01) {
- network->wpa_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->wpa_ie, info_element,
- network->wpa_ie_len);
- }
- break;
-
- case WLAN_EID_RSN:
- LIBIPW_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n",
- info_element->len);
- network->rsn_ie_len = min(info_element->len + 2,
- MAX_WPA_IE_LEN);
- memcpy(network->rsn_ie, info_element,
- network->rsn_ie_len);
- break;
-
- case WLAN_EID_QOS_PARAMETER:
- printk(KERN_ERR
- "QoS Error need to parse QOS_PARAMETER IE\n");
- break;
- /* 802.11h */
- case WLAN_EID_PWR_CONSTRAINT:
- network->power_constraint = info_element->data[0];
- network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
- break;
-
- case WLAN_EID_CHANNEL_SWITCH:
- network->power_constraint = info_element->data[0];
- network->flags |= NETWORK_HAS_CSA;
- break;
-
- case WLAN_EID_QUIET:
- network->quiet.count = info_element->data[0];
- network->quiet.period = info_element->data[1];
- network->quiet.duration = info_element->data[2];
- network->quiet.offset = info_element->data[3];
- network->flags |= NETWORK_HAS_QUIET;
- break;
-
- case WLAN_EID_IBSS_DFS:
- network->flags |= NETWORK_HAS_IBSS_DFS;
- break;
-
- case WLAN_EID_TPC_REPORT:
- network->tpc_report.transmit_power =
- info_element->data[0];
- network->tpc_report.link_margin = info_element->data[1];
- network->flags |= NETWORK_HAS_TPC_REPORT;
- break;
-
- default:
- LIBIPW_DEBUG_MGMT
- ("Unsupported info element: %s (%d)\n",
- get_info_element_string(info_element->id),
- info_element->id);
- break;
- }
-
- length -= sizeof(*info_element) + info_element->len;
- info_element =
- (struct libipw_info_element *)&info_element->
- data[info_element->len];
- }
-
- return 0;
-}
-
-static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_assoc_response
- *frame, struct libipw_rx_stats *stats)
-{
- struct libipw_network network_resp = { };
- struct libipw_network *network = &network_resp;
- struct net_device *dev = ieee->dev;
-
- network->flags = 0;
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- network->qos_data.param_count = 0;
- network->qos_data.old_param_count = 0;
-
- //network->atim_window = le16_to_cpu(frame->aid) & (0x3FFF);
- network->atim_window = le16_to_cpu(frame->aid);
- network->listen_interval = le16_to_cpu(frame->status);
- memcpy(network->bssid, frame->header.addr3, ETH_ALEN);
- network->capability = le16_to_cpu(frame->capability);
- network->last_scanned = jiffies;
- network->rates_len = network->rates_ex_len = 0;
- network->last_associate = 0;
- network->ssid_len = 0;
- network->erp_value =
- (network->capability & WLAN_CAPABILITY_IBSS) ? 0x3 : 0x0;
-
- if (stats->freq == LIBIPW_52GHZ_BAND) {
- /* for A band (No DS info) */
- network->channel = stats->received_channel;
- } else
- network->flags |= NETWORK_HAS_CCK;
-
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-
- if (libipw_parse_info_param((void *)frame->variable,
- stats->len - sizeof(*frame), network))
- return 1;
-
- network->mode = 0;
- if (stats->freq == LIBIPW_52GHZ_BAND)
- network->mode = IEEE_A;
- else {
- if (network->flags & NETWORK_HAS_OFDM)
- network->mode |= IEEE_G;
- if (network->flags & NETWORK_HAS_CCK)
- network->mode |= IEEE_B;
- }
-
- memcpy(&network->stats, stats, sizeof(network->stats));
-
- if (ieee->handle_assoc_response != NULL)
- ieee->handle_assoc_response(dev, frame, network);
-
- return 0;
-}
-
-/***************************************************/
-
-static int libipw_network_init(struct libipw_device *ieee, struct libipw_probe_response
- *beacon,
- struct libipw_network *network,
- struct libipw_rx_stats *stats)
-{
- network->qos_data.active = 0;
- network->qos_data.supported = 0;
- network->qos_data.param_count = 0;
- network->qos_data.old_param_count = 0;
-
- /* Pull out fixed field data */
- memcpy(network->bssid, beacon->header.addr3, ETH_ALEN);
- network->capability = le16_to_cpu(beacon->capability);
- network->last_scanned = jiffies;
- network->time_stamp[0] = le32_to_cpu(beacon->time_stamp[0]);
- network->time_stamp[1] = le32_to_cpu(beacon->time_stamp[1]);
- network->beacon_interval = le16_to_cpu(beacon->beacon_interval);
- /* Where to pull this? beacon->listen_interval; */
- network->listen_interval = 0x0A;
- network->rates_len = network->rates_ex_len = 0;
- network->last_associate = 0;
- network->ssid_len = 0;
- network->flags = 0;
- network->atim_window = 0;
- network->erp_value = (network->capability & WLAN_CAPABILITY_IBSS) ?
- 0x3 : 0x0;
-
- if (stats->freq == LIBIPW_52GHZ_BAND) {
- /* for A band (No DS info) */
- network->channel = stats->received_channel;
- } else
- network->flags |= NETWORK_HAS_CCK;
-
- network->wpa_ie_len = 0;
- network->rsn_ie_len = 0;
-
- if (libipw_parse_info_param((void *)beacon->variable,
- stats->len - sizeof(*beacon), network))
- return 1;
-
- network->mode = 0;
- if (stats->freq == LIBIPW_52GHZ_BAND)
- network->mode = IEEE_A;
- else {
- if (network->flags & NETWORK_HAS_OFDM)
- network->mode |= IEEE_G;
- if (network->flags & NETWORK_HAS_CCK)
- network->mode |= IEEE_B;
- }
-
- if (network->mode == 0) {
- LIBIPW_DEBUG_SCAN("Filtered out '%*pE (%pM)' network.\n",
- network->ssid_len, network->ssid,
- network->bssid);
- return 1;
- }
-
- memcpy(&network->stats, stats, sizeof(network->stats));
-
- return 0;
-}
-
-static inline int is_same_network(struct libipw_network *src,
- struct libipw_network *dst)
-{
- /* A network is only a duplicate if the channel, BSSID, and ESSID
- * all match. We treat all <hidden> with the same BSSID and channel
- * as one network */
- return ((src->ssid_len == dst->ssid_len) &&
- (src->channel == dst->channel) &&
- ether_addr_equal_64bits(src->bssid, dst->bssid) &&
- !memcmp(src->ssid, dst->ssid, src->ssid_len));
-}
-
-static void update_network(struct libipw_network *dst,
- struct libipw_network *src)
-{
- int qos_active;
- u8 old_param;
-
- /* We only update the statistics if they were created by receiving
- * the network information on the actual channel the network is on.
- *
- * This keeps beacons received on neighbor channels from bringing
- * down the signal level of an AP. */
- if (dst->channel == src->stats.received_channel)
- memcpy(&dst->stats, &src->stats,
- sizeof(struct libipw_rx_stats));
- else
- LIBIPW_DEBUG_SCAN("Network %pM info received "
- "off channel (%d vs. %d)\n", src->bssid,
- dst->channel, src->stats.received_channel);
-
- dst->capability = src->capability;
- memcpy(dst->rates, src->rates, src->rates_len);
- dst->rates_len = src->rates_len;
- memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len);
- dst->rates_ex_len = src->rates_ex_len;
-
- dst->mode = src->mode;
- dst->flags = src->flags;
- dst->time_stamp[0] = src->time_stamp[0];
- dst->time_stamp[1] = src->time_stamp[1];
-
- dst->beacon_interval = src->beacon_interval;
- dst->listen_interval = src->listen_interval;
- dst->atim_window = src->atim_window;
- dst->erp_value = src->erp_value;
- dst->tim = src->tim;
-
- memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len);
- dst->wpa_ie_len = src->wpa_ie_len;
- memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len);
- dst->rsn_ie_len = src->rsn_ie_len;
-
- dst->last_scanned = jiffies;
- qos_active = src->qos_data.active;
- old_param = dst->qos_data.old_param_count;
- if (dst->flags & NETWORK_HAS_QOS_MASK)
- memcpy(&dst->qos_data, &src->qos_data,
- sizeof(struct libipw_qos_data));
- else {
- dst->qos_data.supported = src->qos_data.supported;
- dst->qos_data.param_count = src->qos_data.param_count;
- }
-
- if (dst->qos_data.supported == 1) {
- if (dst->ssid_len)
- LIBIPW_DEBUG_QOS
- ("QoS the network %s is QoS supported\n",
- dst->ssid);
- else
- LIBIPW_DEBUG_QOS
- ("QoS the network is QoS supported\n");
- }
- dst->qos_data.active = qos_active;
- dst->qos_data.old_param_count = old_param;
-
- /* dst->last_associate is not overwritten */
-}
-
-static inline int is_beacon(__le16 fc)
-{
- return (WLAN_FC_GET_STYPE(le16_to_cpu(fc)) == IEEE80211_STYPE_BEACON);
-}
-
-static void libipw_process_probe_response(struct libipw_device
- *ieee, struct
- libipw_probe_response
- *beacon, struct libipw_rx_stats
- *stats)
-{
- struct net_device *dev = ieee->dev;
- struct libipw_network network = { };
- struct libipw_network *target;
- struct libipw_network *oldest = NULL;
-#ifdef CONFIG_LIBIPW_DEBUG
- struct libipw_info_element *info_element = (void *)beacon->variable;
-#endif
- unsigned long flags;
-
- LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n",
- info_element->len, info_element->data,
- beacon->header.addr3,
- (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xc)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xb)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0xa)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x9)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x8)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x7)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x6)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x5)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x4)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x3)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x2)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x1)) ? '1' : '0',
- (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0');
-
- if (libipw_network_init(ieee, beacon, &network, stats)) {
- LIBIPW_DEBUG_SCAN("Dropped '%*pE' (%pM) via %s.\n",
- info_element->len, info_element->data,
- beacon->header.addr3,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
- return;
- }
-
- /* The network parsed correctly -- so now we scan our known networks
- * to see if we can find it in our list.
- *
- * NOTE: This search is definitely not optimized. Once its doing
- * the "right thing" we'll optimize it for efficiency if
- * necessary */
-
- /* Search for this entry in the list and update it if it is
- * already there. */
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(target, &ieee->network_list, list) {
- if (is_same_network(target, &network))
- break;
-
- if ((oldest == NULL) ||
- time_before(target->last_scanned, oldest->last_scanned))
- oldest = target;
- }
-
- /* If we didn't find a match, then get a new network slot to initialize
- * with this beacon's information */
- if (&target->list == &ieee->network_list) {
- if (list_empty(&ieee->network_free_list)) {
- /* If there are no more slots, expire the oldest */
- list_del(&oldest->list);
- target = oldest;
- LIBIPW_DEBUG_SCAN("Expired '%*pE' (%pM) from network list.\n",
- target->ssid_len, target->ssid,
- target->bssid);
- } else {
- /* Otherwise just pull from the free list */
- target = list_entry(ieee->network_free_list.next,
- struct libipw_network, list);
- list_del(ieee->network_free_list.next);
- }
-
-#ifdef CONFIG_LIBIPW_DEBUG
- LIBIPW_DEBUG_SCAN("Adding '%*pE' (%pM) via %s.\n",
- network.ssid_len, network.ssid,
- network.bssid,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
-#endif
- memcpy(target, &network, sizeof(*target));
- list_add_tail(&target->list, &ieee->network_list);
- } else {
- LIBIPW_DEBUG_SCAN("Updating '%*pE' (%pM) via %s.\n",
- target->ssid_len, target->ssid,
- target->bssid,
- is_beacon(beacon->header.frame_ctl) ?
- "BEACON" : "PROBE RESPONSE");
- update_network(target, &network);
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- if (is_beacon(beacon->header.frame_ctl)) {
- if (ieee->handle_beacon != NULL)
- ieee->handle_beacon(dev, beacon, target);
- } else {
- if (ieee->handle_probe_response != NULL)
- ieee->handle_probe_response(dev, beacon, target);
- }
-}
-
-void libipw_rx_mgt(struct libipw_device *ieee,
- struct libipw_hdr_4addr *header,
- struct libipw_rx_stats *stats)
-{
- switch (WLAN_FC_GET_STYPE(le16_to_cpu(header->frame_ctl))) {
- case IEEE80211_STYPE_ASSOC_RESP:
- LIBIPW_DEBUG_MGMT("received ASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- libipw_handle_assoc_resp(ieee,
- (struct libipw_assoc_response *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_REASSOC_RESP:
- LIBIPW_DEBUG_MGMT("received REASSOCIATION RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- break;
-
- case IEEE80211_STYPE_PROBE_REQ:
- LIBIPW_DEBUG_MGMT("received auth (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- if (ieee->handle_probe_request != NULL)
- ieee->handle_probe_request(ieee->dev,
- (struct
- libipw_probe_request *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_PROBE_RESP:
- LIBIPW_DEBUG_MGMT("received PROBE RESPONSE (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_SCAN("Probe response\n");
- libipw_process_probe_response(ieee,
- (struct
- libipw_probe_response *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_BEACON:
- LIBIPW_DEBUG_MGMT("received BEACON (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_SCAN("Beacon\n");
- libipw_process_probe_response(ieee,
- (struct
- libipw_probe_response *)
- header, stats);
- break;
- case IEEE80211_STYPE_AUTH:
-
- LIBIPW_DEBUG_MGMT("received auth (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- if (ieee->handle_auth != NULL)
- ieee->handle_auth(ieee->dev,
- (struct libipw_auth *)header);
- break;
-
- case IEEE80211_STYPE_DISASSOC:
- if (ieee->handle_disassoc != NULL)
- ieee->handle_disassoc(ieee->dev,
- (struct libipw_disassoc *)
- header);
- break;
-
- case IEEE80211_STYPE_ACTION:
- LIBIPW_DEBUG_MGMT("ACTION\n");
- if (ieee->handle_action)
- ieee->handle_action(ieee->dev,
- (struct libipw_action *)
- header, stats);
- break;
-
- case IEEE80211_STYPE_REASSOC_REQ:
- LIBIPW_DEBUG_MGMT("received reassoc (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- LIBIPW_DEBUG_MGMT("%s: LIBIPW_REASSOC_REQ received\n",
- ieee->dev->name);
- if (ieee->handle_reassoc_request != NULL)
- ieee->handle_reassoc_request(ieee->dev,
- (struct libipw_reassoc_request *)
- header);
- break;
-
- case IEEE80211_STYPE_ASSOC_REQ:
- LIBIPW_DEBUG_MGMT("received assoc (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
-
- LIBIPW_DEBUG_MGMT("%s: LIBIPW_ASSOC_REQ received\n",
- ieee->dev->name);
- if (ieee->handle_assoc_request != NULL)
- ieee->handle_assoc_request(ieee->dev);
- break;
-
- case IEEE80211_STYPE_DEAUTH:
- LIBIPW_DEBUG_MGMT("DEAUTH\n");
- if (ieee->handle_deauth != NULL)
- ieee->handle_deauth(ieee->dev,
- (struct libipw_deauth *)
- header);
- break;
- default:
- LIBIPW_DEBUG_MGMT("received UNKNOWN (%d)\n",
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- LIBIPW_DEBUG_MGMT("%s: Unknown management packet: %d\n",
- ieee->dev->name,
- WLAN_FC_GET_STYPE(le16_to_cpu
- (header->frame_ctl)));
- break;
- }
-}
-
-EXPORT_SYMBOL_GPL(libipw_rx_any);
-EXPORT_SYMBOL(libipw_rx_mgt);
-EXPORT_SYMBOL(libipw_rx);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
deleted file mode 100644
index 4aec1fce1ae29..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c
+++ /dev/null
@@ -1,519 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved.
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-#include <linux/compiler.h>
-#include <linux/errno.h>
-#include <linux/if_arp.h>
-#include <linux/in6.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/proc_fs.h>
-#include <linux/skbuff.h>
-#include <linux/slab.h>
-#include <linux/tcp.h>
-#include <linux/types.h>
-#include <linux/wireless.h>
-#include <linux/etherdevice.h>
-#include <linux/uaccess.h>
-
-#include "libipw.h"
-
-/*
-
-802.11 Data Frame
-
- ,-------------------------------------------------------------------.
-Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
- |------|------|---------|---------|---------|------|---------|------|
-Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs |
- | | tion | (BSSID) | | | ence | data | |
- `--------------------------------------------------| |------'
-Total: 28 non-data bytes `----.----'
- |
- .- 'Frame data' expands, if WEP enabled, to <----------'
- |
- V
- ,-----------------------.
-Bytes | 4 | 0-2296 | 4 |
- |-----|-----------|-----|
-Desc. | IV | Encrypted | ICV |
- | | Packet | |
- `-----| |-----'
- `-----.-----'
- |
- .- 'Encrypted Packet' expands to
- |
- V
- ,---------------------------------------------------.
-Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 |
- |------|------|---------|----------|------|---------|
-Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP |
- | DSAP | SSAP | | | | Packet |
- | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | |
- `----------------------------------------------------
-Total: 8 non-data bytes
-
-802.3 Ethernet Data Frame
-
- ,-----------------------------------------.
-Bytes | 6 | 6 | 2 | Variable | 4 |
- |-------|-------|------|-----------|------|
-Desc. | Dest. | Source| Type | IP Packet | fcs |
- | MAC | MAC | | | |
- `-----------------------------------------'
-Total: 18 non-data bytes
-
-In the event that fragmentation is required, the incoming payload is split into
-N parts of size ieee->fts. The first fragment contains the SNAP header and the
-remaining packets are just data.
-
-If encryption is enabled, each fragment payload size is reduced by enough space
-to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP)
-So if you have 1500 bytes of payload with ieee->fts set to 500 without
-encryption it will take 3 frames. With WEP it will take 4 frames as the
-payload of each frame is reduced to 492 bytes.
-
-* SKB visualization
-*
-* ,- skb->data
-* |
-* | ETHERNET HEADER ,-<-- PAYLOAD
-* | | 14 bytes from skb->data
-* | 2 bytes for Type --> ,T. | (sizeof ethhdr)
-* | | | |
-* |,-Dest.--. ,--Src.---. | | |
-* | 6 bytes| | 6 bytes | | | |
-* v | | | | | |
-* 0 | v 1 | v | v 2
-* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
-* ^ | ^ | ^ |
-* | | | | | |
-* | | | | `T' <---- 2 bytes for Type
-* | | | |
-* | | '---SNAP--' <-------- 6 bytes for SNAP
-* | |
-* `-IV--' <-------------------- 4 bytes for IV (WEP)
-*
-* SNAP HEADER
-*
-*/
-
-static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
-static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
-
-static int libipw_copy_snap(u8 * data, __be16 h_proto)
-{
- struct libipw_snap_hdr *snap;
- u8 *oui;
-
- snap = (struct libipw_snap_hdr *)data;
- snap->dsap = 0xaa;
- snap->ssap = 0xaa;
- snap->ctrl = 0x03;
-
- if (h_proto == htons(ETH_P_AARP) || h_proto == htons(ETH_P_IPX))
- oui = P802_1H_OUI;
- else
- oui = RFC1042_OUI;
- snap->oui[0] = oui[0];
- snap->oui[1] = oui[1];
- snap->oui[2] = oui[2];
-
- memcpy(data + SNAP_SIZE, &h_proto, sizeof(u16));
-
- return SNAP_SIZE + sizeof(u16);
-}
-
-static int libipw_encrypt_fragment(struct libipw_device *ieee,
- struct sk_buff *frag, int hdr_len)
-{
- struct lib80211_crypt_data *crypt =
- ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
- int res;
-
- if (crypt == NULL)
- return -1;
-
- /* To encrypt, frame format is:
- * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) */
- atomic_inc(&crypt->refcnt);
- res = 0;
- if (crypt->ops && crypt->ops->encrypt_mpdu)
- res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv);
-
- atomic_dec(&crypt->refcnt);
- if (res < 0) {
- printk(KERN_INFO "%s: Encryption failed: len=%d.\n",
- ieee->dev->name, frag->len);
- ieee->ieee_stats.tx_discards++;
- return -1;
- }
-
- return 0;
-}
-
-void libipw_txb_free(struct libipw_txb *txb)
-{
- int i;
- if (unlikely(!txb))
- return;
- for (i = 0; i < txb->nr_frags; i++)
- if (txb->fragments[i])
- dev_kfree_skb_any(txb->fragments[i]);
- kfree(txb);
-}
-
-static struct libipw_txb *libipw_alloc_txb(int nr_frags, int txb_size,
- int headroom, gfp_t gfp_mask)
-{
- struct libipw_txb *txb;
- int i;
-
- txb = kmalloc(struct_size(txb, fragments, nr_frags), gfp_mask);
- if (!txb)
- return NULL;
-
- memset(txb, 0, sizeof(struct libipw_txb));
- txb->nr_frags = nr_frags;
- txb->frag_size = txb_size;
-
- for (i = 0; i < nr_frags; i++) {
- txb->fragments[i] = __dev_alloc_skb(txb_size + headroom,
- gfp_mask);
- if (unlikely(!txb->fragments[i])) {
- i--;
- break;
- }
- skb_reserve(txb->fragments[i], headroom);
- }
- if (unlikely(i != nr_frags)) {
- while (i >= 0)
- dev_kfree_skb_any(txb->fragments[i--]);
- kfree(txb);
- return NULL;
- }
- return txb;
-}
-
-static int libipw_classify(struct sk_buff *skb)
-{
- struct ethhdr *eth;
- struct iphdr *ip;
-
- eth = (struct ethhdr *)skb->data;
- if (eth->h_proto != htons(ETH_P_IP))
- return 0;
-
- ip = ip_hdr(skb);
- switch (ip->tos & 0xfc) {
- case 0x20:
- return 2;
- case 0x40:
- return 1;
- case 0x60:
- return 3;
- case 0x80:
- return 4;
- case 0xa0:
- return 5;
- case 0xc0:
- return 6;
- case 0xe0:
- return 7;
- default:
- return 0;
- }
-}
-
-/* Incoming skb is converted to a txb which consists of
- * a block of 802.11 fragment packets (stored as skbs) */
-netdev_tx_t libipw_xmit(struct sk_buff *skb, struct net_device *dev)
-{
- struct libipw_device *ieee = netdev_priv(dev);
- struct libipw_txb *txb = NULL;
- struct libipw_hdr_3addrqos *frag_hdr;
- int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
- rts_required;
- unsigned long flags;
- int encrypt, host_encrypt, host_encrypt_msdu;
- __be16 ether_type;
- int bytes, fc, hdr_len;
- struct sk_buff *skb_frag;
- struct libipw_hdr_3addrqos header = {/* Ensure zero initialized */
- .duration_id = 0,
- .seq_ctl = 0,
- .qos_ctl = 0
- };
- u8 dest[ETH_ALEN], src[ETH_ALEN];
- struct lib80211_crypt_data *crypt;
- int priority = skb->priority;
- int snapped = 0;
-
- if (ieee->is_queue_full && (*ieee->is_queue_full) (dev, priority))
- return NETDEV_TX_BUSY;
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- /* If there is no driver handler to take the TXB, dont' bother
- * creating it... */
- if (!ieee->hard_start_xmit) {
- printk(KERN_WARNING "%s: No xmit handler.\n", ieee->dev->name);
- goto success;
- }
-
- if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) {
- printk(KERN_WARNING "%s: skb too small (%d).\n",
- ieee->dev->name, skb->len);
- goto success;
- }
-
- ether_type = ((struct ethhdr *)skb->data)->h_proto;
-
- crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx];
-
- encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) &&
- ieee->sec.encrypt;
-
- host_encrypt = ieee->host_encrypt && encrypt && crypt;
- host_encrypt_msdu = ieee->host_encrypt_msdu && encrypt && crypt;
-
- if (!encrypt && ieee->ieee802_1x &&
- ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
- dev->stats.tx_dropped++;
- goto success;
- }
-
- /* Save source and destination addresses */
- skb_copy_from_linear_data(skb, dest, ETH_ALEN);
- skb_copy_from_linear_data_offset(skb, ETH_ALEN, src, ETH_ALEN);
-
- if (host_encrypt)
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA |
- IEEE80211_FCTL_PROTECTED;
- else
- fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA;
-
- if (ieee->iw_mode == IW_MODE_INFRA) {
- fc |= IEEE80211_FCTL_TODS;
- /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */
- memcpy(header.addr1, ieee->bssid, ETH_ALEN);
- memcpy(header.addr2, src, ETH_ALEN);
- memcpy(header.addr3, dest, ETH_ALEN);
- } else if (ieee->iw_mode == IW_MODE_ADHOC) {
- /* not From/To DS: Addr1 = DA, Addr2 = SA, Addr3 = BSSID */
- memcpy(header.addr1, dest, ETH_ALEN);
- memcpy(header.addr2, src, ETH_ALEN);
- memcpy(header.addr3, ieee->bssid, ETH_ALEN);
- }
- hdr_len = LIBIPW_3ADDR_LEN;
-
- if (ieee->is_qos_active && ieee->is_qos_active(dev, skb)) {
- fc |= IEEE80211_STYPE_QOS_DATA;
- hdr_len += 2;
-
- skb->priority = libipw_classify(skb);
- header.qos_ctl |= cpu_to_le16(skb->priority & LIBIPW_QCTL_TID);
- }
- header.frame_ctl = cpu_to_le16(fc);
-
- /* Advance the SKB to the start of the payload */
- skb_pull(skb, sizeof(struct ethhdr));
-
- /* Determine total amount of storage required for TXB packets */
- bytes = skb->len + SNAP_SIZE + sizeof(u16);
-
- /* Encrypt msdu first on the whole data packet. */
- if ((host_encrypt || host_encrypt_msdu) &&
- crypt && crypt->ops && crypt->ops->encrypt_msdu) {
- int res = 0;
- int len = bytes + hdr_len + crypt->ops->extra_msdu_prefix_len +
- crypt->ops->extra_msdu_postfix_len;
- struct sk_buff *skb_new = dev_alloc_skb(len);
-
- if (unlikely(!skb_new))
- goto failed;
-
- skb_reserve(skb_new, crypt->ops->extra_msdu_prefix_len);
- skb_put_data(skb_new, &header, hdr_len);
- snapped = 1;
- libipw_copy_snap(skb_put(skb_new, SNAP_SIZE + sizeof(u16)),
- ether_type);
- skb_copy_from_linear_data(skb, skb_put(skb_new, skb->len), skb->len);
- res = crypt->ops->encrypt_msdu(skb_new, hdr_len, crypt->priv);
- if (res < 0) {
- LIBIPW_ERROR("msdu encryption failed\n");
- dev_kfree_skb_any(skb_new);
- goto failed;
- }
- dev_kfree_skb_any(skb);
- skb = skb_new;
- bytes += crypt->ops->extra_msdu_prefix_len +
- crypt->ops->extra_msdu_postfix_len;
- skb_pull(skb, hdr_len);
- }
-
- if (host_encrypt || ieee->host_open_frag) {
- /* Determine fragmentation size based on destination (multicast
- * and broadcast are not fragmented) */
- if (is_multicast_ether_addr(dest) ||
- is_broadcast_ether_addr(dest))
- frag_size = MAX_FRAG_THRESHOLD;
- else
- frag_size = ieee->fts;
-
- /* Determine amount of payload per fragment. Regardless of if
- * this stack is providing the full 802.11 header, one will
- * eventually be affixed to this fragment -- so we must account
- * for it when determining the amount of payload space. */
- bytes_per_frag = frag_size - hdr_len;
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- bytes_per_frag -= LIBIPW_FCS_LEN;
-
- /* Each fragment may need to have room for encryption
- * pre/postfix */
- if (host_encrypt && crypt && crypt->ops)
- bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
- crypt->ops->extra_mpdu_postfix_len;
-
- /* Number of fragments is the total
- * bytes_per_frag / payload_per_fragment */
- nr_frags = bytes / bytes_per_frag;
- bytes_last_frag = bytes % bytes_per_frag;
- if (bytes_last_frag)
- nr_frags++;
- else
- bytes_last_frag = bytes_per_frag;
- } else {
- nr_frags = 1;
- bytes_per_frag = bytes_last_frag = bytes;
- frag_size = bytes + hdr_len;
- }
-
- rts_required = (frag_size > ieee->rts
- && ieee->config & CFG_LIBIPW_RTS);
- if (rts_required)
- nr_frags++;
-
- /* When we allocate the TXB we allocate enough space for the reserve
- * and full fragment bytes (bytes_per_frag doesn't include prefix,
- * postfix, header, FCS, etc.) */
- txb = libipw_alloc_txb(nr_frags, frag_size,
- ieee->tx_headroom, GFP_ATOMIC);
- if (unlikely(!txb)) {
- printk(KERN_WARNING "%s: Could not allocate TXB\n",
- ieee->dev->name);
- goto failed;
- }
- txb->encrypted = encrypt;
- if (host_encrypt)
- txb->payload_size = frag_size * (nr_frags - 1) +
- bytes_last_frag;
- else
- txb->payload_size = bytes;
-
- if (rts_required) {
- skb_frag = txb->fragments[0];
- frag_hdr = skb_put(skb_frag, hdr_len);
-
- /*
- * Set header frame_ctl to the RTS.
- */
- header.frame_ctl =
- cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
- memcpy(frag_hdr, &header, hdr_len);
-
- /*
- * Restore header frame_ctl to the original data setting.
- */
- header.frame_ctl = cpu_to_le16(fc);
-
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- skb_put(skb_frag, 4);
-
- txb->rts_included = 1;
- i = 1;
- } else
- i = 0;
-
- for (; i < nr_frags; i++) {
- skb_frag = txb->fragments[i];
-
- if (host_encrypt)
- skb_reserve(skb_frag,
- crypt->ops->extra_mpdu_prefix_len);
-
- frag_hdr = skb_put_data(skb_frag, &header, hdr_len);
-
- /* If this is not the last fragment, then add the MOREFRAGS
- * bit to the frame control */
- if (i != nr_frags - 1) {
- frag_hdr->frame_ctl =
- cpu_to_le16(fc | IEEE80211_FCTL_MOREFRAGS);
- bytes = bytes_per_frag;
- } else {
- /* The last fragment takes the remaining length */
- bytes = bytes_last_frag;
- }
-
- if (i == 0 && !snapped) {
- libipw_copy_snap(skb_put
- (skb_frag, SNAP_SIZE + sizeof(u16)),
- ether_type);
- bytes -= SNAP_SIZE + sizeof(u16);
- }
-
- skb_copy_from_linear_data(skb, skb_put(skb_frag, bytes), bytes);
-
- /* Advance the SKB... */
- skb_pull(skb, bytes);
-
- /* Encryption routine will move the header forward in order
- * to insert the IV between the header and the payload */
- if (host_encrypt)
- libipw_encrypt_fragment(ieee, skb_frag, hdr_len);
-
- if (ieee->config &
- (CFG_LIBIPW_COMPUTE_FCS | CFG_LIBIPW_RESERVE_FCS))
- skb_put(skb_frag, 4);
- }
-
- success:
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- dev_kfree_skb_any(skb);
-
- if (txb) {
- netdev_tx_t ret = (*ieee->hard_start_xmit)(txb, dev, priority);
- if (ret == NETDEV_TX_OK) {
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += txb->payload_size;
- return NETDEV_TX_OK;
- }
-
- libipw_txb_free(txb);
- }
-
- return NETDEV_TX_OK;
-
- failed:
- spin_unlock_irqrestore(&ieee->lock, flags);
- netif_stop_queue(dev);
- dev->stats.tx_errors++;
- return NETDEV_TX_BUSY;
-}
-EXPORT_SYMBOL(libipw_xmit);
-
-EXPORT_SYMBOL(libipw_txb_free);
diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c b/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
deleted file mode 100644
index 903de34028efb..0000000000000
--- a/drivers/net/wireless/intel/ipw2x00/libipw_wx.c
+++ /dev/null
@@ -1,726 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/******************************************************************************
-
- Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
-
- Portions of this file are based on the WEP enablement code provided by the
- Host AP project hostap-drivers v0.1.3
- Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
- <j at w1.fi>
- Copyright (c) 2002-2003, Jouni Malinen <j at w1.fi>
-
-
- Contact Information:
- Intel Linux Wireless <ilw at linux.intel.com>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
-
-******************************************************************************/
-
-#include <linux/hardirq.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/jiffies.h>
-
-#include <net/lib80211.h>
-#include <linux/wireless.h>
-
-#include "libipw.h"
-
-static const char *libipw_modes[] = {
- "?", "a", "b", "ab", "g", "ag", "bg", "abg"
-};
-
-static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
-{
- unsigned long end = jiffies;
-
- if (end >= start)
- return jiffies_to_msecs(end - start);
-
- return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
-}
-
-#define MAX_CUSTOM_LEN 64
-static char *libipw_translate_scan(struct libipw_device *ieee,
- char *start, char *stop,
- struct libipw_network *network,
- struct iw_request_info *info)
-{
- char custom[MAX_CUSTOM_LEN];
- char *p;
- struct iw_event iwe;
- int i, j;
- char *current_val; /* For rates */
- u8 rate;
-
- /* First entry *MUST* be the AP MAC address */
- iwe.cmd = SIOCGIWAP;
- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
- memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
-
- /* Remaining entries will be displayed in the order we provide them */
-
- /* Add the ESSID */
- iwe.cmd = SIOCGIWESSID;
- iwe.u.data.flags = 1;
- iwe.u.data.length = min(network->ssid_len, (u8) 32);
- start = iwe_stream_add_point(info, start, stop,
- &iwe, network->ssid);
-
- /* Add the protocol name */
- iwe.cmd = SIOCGIWNAME;
- snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
- libipw_modes[network->mode]);
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
-
- /* Add mode */
- iwe.cmd = SIOCGIWMODE;
- if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
- if (network->capability & WLAN_CAPABILITY_ESS)
- iwe.u.mode = IW_MODE_MASTER;
- else
- iwe.u.mode = IW_MODE_ADHOC;
-
- start = iwe_stream_add_event(info, start, stop,
- &iwe, IW_EV_UINT_LEN);
- }
-
- /* Add channel and frequency */
- /* Note : userspace automatically computes channel using iwrange */
- iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel);
- iwe.u.freq.e = 6;
- iwe.u.freq.i = 0;
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
-
- /* Add encryption capability */
- iwe.cmd = SIOCGIWENCODE;
- if (network->capability & WLAN_CAPABILITY_PRIVACY)
- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
- else
- iwe.u.data.flags = IW_ENCODE_DISABLED;
- iwe.u.data.length = 0;
- start = iwe_stream_add_point(info, start, stop,
- &iwe, network->ssid);
-
- /* Add basic and extended rates */
- /* Rate : stuffing multiple values in a single event require a bit
- * more of magic - Jean II */
- current_val = start + iwe_stream_lcp_len(info);
- iwe.cmd = SIOCGIWRATE;
- /* Those two flags are ignored... */
- iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
-
- for (i = 0, j = 0; i < network->rates_len;) {
- if (j < network->rates_ex_len &&
- ((network->rates_ex[j] & 0x7F) <
- (network->rates[i] & 0x7F)))
- rate = network->rates_ex[j++] & 0x7F;
- else
- rate = network->rates[i++] & 0x7F;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- for (; j < network->rates_ex_len; j++) {
- rate = network->rates_ex[j] & 0x7F;
- /* Bit rate given in 500 kb/s units (+ 0x80) */
- iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
- /* Add new value to event */
- current_val = iwe_stream_add_value(info, start, current_val,
- stop, &iwe, IW_EV_PARAM_LEN);
- }
- /* Check if we added any rate */
- if ((current_val - start) > iwe_stream_lcp_len(info))
- start = current_val;
-
- /* Add quality statistics */
- iwe.cmd = IWEVQUAL;
- iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED;
-
- if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) {
- iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
- IW_QUAL_LEVEL_INVALID;
- iwe.u.qual.qual = 0;
- } else {
- if (ieee->perfect_rssi == ieee->worst_rssi)
- iwe.u.qual.qual = 100;
- else
- iwe.u.qual.qual =
- (100 *
- (ieee->perfect_rssi - ieee->worst_rssi) *
- (ieee->perfect_rssi - ieee->worst_rssi) -
- (ieee->perfect_rssi - network->stats.rssi) *
- (15 * (ieee->perfect_rssi - ieee->worst_rssi) +
- 62 * (ieee->perfect_rssi -
- network->stats.rssi))) /
- ((ieee->perfect_rssi -
- ieee->worst_rssi) * (ieee->perfect_rssi -
- ieee->worst_rssi));
- if (iwe.u.qual.qual > 100)
- iwe.u.qual.qual = 100;
- else if (iwe.u.qual.qual < 1)
- iwe.u.qual.qual = 0;
- }
-
- if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) {
- iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
- iwe.u.qual.noise = 0;
- } else {
- iwe.u.qual.noise = network->stats.noise;
- }
-
- if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) {
- iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
- iwe.u.qual.level = 0;
- } else {
- iwe.u.qual.level = network->stats.signal;
- }
-
- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
-
- iwe.cmd = IWEVCUSTOM;
- p = custom;
-
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- memset(&iwe, 0, sizeof(iwe));
- if (network->wpa_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, network->wpa_ie, network->wpa_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->wpa_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- memset(&iwe, 0, sizeof(iwe));
- if (network->rsn_ie_len) {
- char buf[MAX_WPA_IE_LEN];
- memcpy(buf, network->rsn_ie, network->rsn_ie_len);
- iwe.cmd = IWEVGENIE;
- iwe.u.data.length = network->rsn_ie_len;
- start = iwe_stream_add_point(info, start, stop, &iwe, buf);
- }
-
- /* Add EXTRA: Age to display seconds since last beacon/probe response
- * for given network. */
- iwe.cmd = IWEVCUSTOM;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom),
- " Last beacon: %ums ago",
- elapsed_jiffies_msecs(network->last_scanned));
- iwe.u.data.length = p - custom;
- if (iwe.u.data.length)
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
-
- /* Add spectrum management information */
- iwe.cmd = -1;
- p = custom;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
-
- if (libipw_get_channel_flags(ieee, network->channel) &
- LIBIPW_CH_INVALID) {
- iwe.cmd = IWEVCUSTOM;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
- }
-
- if (libipw_get_channel_flags(ieee, network->channel) &
- LIBIPW_CH_RADAR_DETECT) {
- iwe.cmd = IWEVCUSTOM;
- p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
- }
-
- if (iwe.cmd == IWEVCUSTOM) {
- iwe.u.data.length = p - custom;
- start = iwe_stream_add_point(info, start, stop, &iwe, custom);
- }
-
- return start;
-}
-
-#define SCAN_ITEM_SIZE 128
-
-int libipw_wx_get_scan(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct libipw_network *network;
- unsigned long flags;
- int err = 0;
-
- char *ev = extra;
- char *stop = ev + wrqu->data.length;
- int i = 0;
-
- LIBIPW_DEBUG_WX("Getting scan\n");
-
- spin_lock_irqsave(&ieee->lock, flags);
-
- list_for_each_entry(network, &ieee->network_list, list) {
- i++;
- if (stop - ev < SCAN_ITEM_SIZE) {
- err = -E2BIG;
- break;
- }
-
- if (ieee->scan_age == 0 ||
- time_after(network->last_scanned + ieee->scan_age, jiffies))
- ev = libipw_translate_scan(ieee, ev, stop, network,
- info);
- else {
- LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n",
- network->ssid_len, network->ssid,
- network->bssid,
- elapsed_jiffies_msecs(
- network->last_scanned));
- }
- }
-
- spin_unlock_irqrestore(&ieee->lock, flags);
-
- wrqu->data.length = ev - extra;
- wrqu->data.flags = 0;
-
- LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i);
-
- return err;
-}
-
-int libipw_wx_set_encode(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &(wrqu->encoding);
- struct net_device *dev = ieee->dev;
- struct libipw_security sec = {
- .flags = 0
- };
- int i, key, key_provided, len;
- struct lib80211_crypt_data **crypt;
- int host_crypto = ieee->host_encrypt || ieee->host_decrypt;
-
- LIBIPW_DEBUG_WX("SET_ENCODE\n");
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > WEP_KEYS)
- return -EINVAL;
- key--;
- key_provided = 1;
- } else {
- key_provided = 0;
- key = ieee->crypt_info.tx_keyidx;
- }
-
- LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
- "provided" : "default");
-
- crypt = &ieee->crypt_info.crypt[key];
-
- if (erq->flags & IW_ENCODE_DISABLED) {
- if (key_provided && *crypt) {
- LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
- key);
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- } else
- LIBIPW_DEBUG_WX("Disabling encryption.\n");
-
- /* Check all the keys to see if any are still configured,
- * and if no key index was provided, de-init them all */
- for (i = 0; i < WEP_KEYS; i++) {
- if (ieee->crypt_info.crypt[i] != NULL) {
- if (key_provided)
- break;
- lib80211_crypt_delayed_deinit(&ieee->crypt_info,
- &ieee->crypt_info.crypt[i]);
- }
- }
-
- if (i == WEP_KEYS) {
- sec.enabled = 0;
- sec.encrypt = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
- }
-
- goto done;
- }
-
- sec.enabled = 1;
- sec.encrypt = 1;
- sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
-
- if (*crypt != NULL && (*crypt)->ops != NULL &&
- strcmp((*crypt)->ops->name, "WEP") != 0) {
- /* changing to use WEP; deinit previously used algorithm
- * on this key */
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
- }
-
- if (*crypt == NULL && host_crypto) {
- struct lib80211_crypt_data *new_crypt;
-
- /* take WEP into use */
- new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
- GFP_KERNEL);
- if (new_crypt == NULL)
- return -ENOMEM;
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- if (!new_crypt->ops) {
- request_module("lib80211_crypt_wep");
- new_crypt->ops = lib80211_get_crypto_ops("WEP");
- }
-
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(key);
-
- if (!new_crypt->ops || !new_crypt->priv) {
- kfree(new_crypt);
- new_crypt = NULL;
-
- printk(KERN_WARNING "%s: could not initialize WEP: "
- "load module lib80211_crypt_wep\n", dev->name);
- return -EOPNOTSUPP;
- }
- *crypt = new_crypt;
- }
-
- /* If a new key was provided, set it up */
- if (erq->length > 0) {
- len = erq->length <= 5 ? 5 : 13;
- memcpy(sec.keys[key], keybuf, erq->length);
- if (len > erq->length)
- memset(sec.keys[key] + erq->length, 0,
- len - erq->length);
- LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n",
- key, len, sec.keys[key],
- erq->length, len);
- sec.key_sizes[key] = len;
- if (*crypt)
- (*crypt)->ops->set_key(sec.keys[key], len, NULL,
- (*crypt)->priv);
- sec.flags |= (1 << key);
- /* This ensures a key will be activated if no key is
- * explicitly set */
- if (key == sec.active_key)
- sec.flags |= SEC_ACTIVE_KEY;
-
- } else {
- if (host_crypto) {
- len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
- NULL, (*crypt)->priv);
- if (len == 0) {
- /* Set a default key of all 0 */
- LIBIPW_DEBUG_WX("Setting key %d to all "
- "zero.\n", key);
- memset(sec.keys[key], 0, 13);
- (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
- (*crypt)->priv);
- sec.key_sizes[key] = 13;
- sec.flags |= (1 << key);
- }
- }
- /* No key data - just set the default TX key index */
- if (key_provided) {
- LIBIPW_DEBUG_WX("Setting key %d to default Tx "
- "key.\n", key);
- ieee->crypt_info.tx_keyidx = key;
- sec.active_key = key;
- sec.flags |= SEC_ACTIVE_KEY;
- }
- }
- if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
- ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
- sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
- WLAN_AUTH_SHARED_KEY;
- sec.flags |= SEC_AUTH_MODE;
- LIBIPW_DEBUG_WX("Auth: %s\n",
- sec.auth_mode == WLAN_AUTH_OPEN ?
- "OPEN" : "SHARED KEY");
- }
-
- /* For now we just support WEP, so only set that security level...
- * TODO: When WPA is added this is one place that needs to change */
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
- sec.encode_alg[key] = SEC_ALG_WEP;
-
- done:
- if (ieee->set_security)
- ieee->set_security(dev, &sec);
-
- return 0;
-}
-
-int libipw_wx_get_encode(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *keybuf)
-{
- struct iw_point *erq = &(wrqu->encoding);
- int len, key;
- struct libipw_security *sec = &ieee->sec;
-
- LIBIPW_DEBUG_WX("GET_ENCODE\n");
-
- key = erq->flags & IW_ENCODE_INDEX;
- if (key) {
- if (key > WEP_KEYS)
- return -EINVAL;
- key--;
- } else
- key = ieee->crypt_info.tx_keyidx;
-
- erq->flags = key + 1;
-
- if (!sec->enabled) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- len = sec->key_sizes[key];
- memcpy(keybuf, sec->keys[key], len);
-
- erq->length = len;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (ieee->open_wep)
- erq->flags |= IW_ENCODE_OPEN;
- else
- erq->flags |= IW_ENCODE_RESTRICTED;
-
- return 0;
-}
-
-int libipw_wx_set_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct net_device *dev = ieee->dev;
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- int i, idx, ret = 0;
- int group_key = 0;
- const char *alg, *module;
- struct lib80211_crypto_ops *ops;
- struct lib80211_crypt_data **crypt;
-
- struct libipw_security sec = {
- .flags = 0,
- };
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
- return -EINVAL;
- idx--;
- } else
- idx = ieee->crypt_info.tx_keyidx;
-
- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
- crypt = &ieee->crypt_info.crypt[idx];
- group_key = 1;
- } else {
- /* some Cisco APs use idx>0 for unicast in dynamic WEP */
- if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
- return -EINVAL;
- if (ieee->iw_mode == IW_MODE_INFRA)
- crypt = &ieee->crypt_info.crypt[idx];
- else
- return -EINVAL;
- }
-
- sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
- if ((encoding->flags & IW_ENCODE_DISABLED) ||
- ext->alg == IW_ENCODE_ALG_NONE) {
- if (*crypt)
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- for (i = 0; i < WEP_KEYS; i++)
- if (ieee->crypt_info.crypt[i] != NULL)
- break;
-
- if (i == WEP_KEYS) {
- sec.enabled = 0;
- sec.encrypt = 0;
- sec.level = SEC_LEVEL_0;
- sec.flags |= SEC_LEVEL;
- }
- goto done;
- }
-
- sec.enabled = 1;
- sec.encrypt = 1;
-
- if (group_key ? !ieee->host_mc_decrypt :
- !(ieee->host_encrypt || ieee->host_decrypt ||
- ieee->host_encrypt_msdu))
- goto skip_host_crypt;
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_WEP:
- alg = "WEP";
- module = "lib80211_crypt_wep";
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = "TKIP";
- module = "lib80211_crypt_tkip";
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = "CCMP";
- module = "lib80211_crypt_ccmp";
- break;
- default:
- LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
- dev->name, ext->alg);
- ret = -EINVAL;
- goto done;
- }
-
- ops = lib80211_get_crypto_ops(alg);
- if (ops == NULL) {
- request_module(module);
- ops = lib80211_get_crypto_ops(alg);
- }
- if (ops == NULL) {
- LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
- dev->name, ext->alg);
- ret = -EINVAL;
- goto done;
- }
-
- if (*crypt == NULL || (*crypt)->ops != ops) {
- struct lib80211_crypt_data *new_crypt;
-
- lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
-
- new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
- if (new_crypt == NULL) {
- ret = -ENOMEM;
- goto done;
- }
- new_crypt->ops = ops;
- if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
- new_crypt->priv = new_crypt->ops->init(idx);
- if (new_crypt->priv == NULL) {
- kfree(new_crypt);
- ret = -EINVAL;
- goto done;
- }
- *crypt = new_crypt;
- }
-
- if (ext->key_len > 0 && (*crypt)->ops->set_key &&
- (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
- (*crypt)->priv) < 0) {
- LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name);
- ret = -EINVAL;
- goto done;
- }
-
- skip_host_crypt:
- if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
- ieee->crypt_info.tx_keyidx = idx;
- sec.active_key = idx;
- sec.flags |= SEC_ACTIVE_KEY;
- }
-
- if (ext->alg != IW_ENCODE_ALG_NONE) {
- int key_len = clamp_val(ext->key_len, 0, SCM_KEY_LEN);
-
- memcpy(sec.keys[idx], ext->key, key_len);
- sec.key_sizes[idx] = key_len;
- sec.flags |= (1 << idx);
- if (ext->alg == IW_ENCODE_ALG_WEP) {
- sec.encode_alg[idx] = SEC_ALG_WEP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
- sec.encode_alg[idx] = SEC_ALG_TKIP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_2;
- } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
- sec.encode_alg[idx] = SEC_ALG_CCMP;
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_3;
- }
- /* Don't set sec level for group keys. */
- if (group_key)
- sec.flags &= ~SEC_LEVEL;
- }
- done:
- if (ieee->set_security)
- ieee->set_security(dev, &sec);
-
- return ret;
-}
-
-int libipw_wx_get_encodeext(struct libipw_device *ieee,
- struct iw_request_info *info,
- union iwreq_data *wrqu, char *extra)
-{
- struct iw_point *encoding = &wrqu->encoding;
- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
- struct libipw_security *sec = &ieee->sec;
- int idx, max_key_len;
-
- max_key_len = encoding->length - sizeof(*ext);
- if (max_key_len < 0)
- return -EINVAL;
-
- idx = encoding->flags & IW_ENCODE_INDEX;
- if (idx) {
- if (idx < 1 || idx > WEP_KEYS)
- return -EINVAL;
- idx--;
- } else
- idx = ieee->crypt_info.tx_keyidx;
-
- if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
- ext->alg != IW_ENCODE_ALG_WEP)
- if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
- return -EINVAL;
-
- encoding->flags = idx + 1;
- memset(ext, 0, sizeof(*ext));
-
- if (!sec->enabled) {
- ext->alg = IW_ENCODE_ALG_NONE;
- ext->key_len = 0;
- encoding->flags |= IW_ENCODE_DISABLED;
- } else {
- if (sec->encode_alg[idx] == SEC_ALG_WEP)
- ext->alg = IW_ENCODE_ALG_WEP;
- else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
- ext->alg = IW_ENCODE_ALG_TKIP;
- else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
- ext->alg = IW_ENCODE_ALG_CCMP;
- else
- return -EINVAL;
-
- ext->key_len = sec->key_sizes[idx];
- memcpy(ext->key, sec->keys[idx], ext->key_len);
- encoding->flags |= IW_ENCODE_ENABLED;
- if (ext->key_len &&
- (ext->alg == IW_ENCODE_ALG_TKIP ||
- ext->alg == IW_ENCODE_ALG_CCMP))
- ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
-
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL(libipw_wx_set_encodeext);
-EXPORT_SYMBOL(libipw_wx_get_encodeext);
-
-EXPORT_SYMBOL(libipw_wx_get_scan);
-EXPORT_SYMBOL(libipw_wx_set_encode);
-EXPORT_SYMBOL(libipw_wx_get_encode);
--
2.39.2
More information about the Linuxppc-dev
mailing list