You can import this changeset into BK by piping this whole message to: '| bk receive [path to repository]' or apply the patch as usual. =================================================================== ChangeSet@1.1597, 2003-07-30 16:56:40-07:00, acme@rth.ninka.net o atheros: port the driver to 2.6 . use workqueues . use irqreturn_t . use kbuild 2.6 . move static inits to 0 to bss . s/return EFOOBAR/return -EFOOBAR/g . use SET_MODULE_OWNER . use NEW_MODULE_CODE stuff . move the BSD compat cruft to bsdcompat subdirectory (will be killed) . use standard min/max macros in Linux ChangeSet@1.1596, 2003-07-30 03:00:45-03:00, acme@conectiva.com.br o atheros: new wireless driver, original sources for 2.4 Kconfig | 8 Makefile | 1 atheros/COPYRIGHT | 40 atheros/Makefile | 1 atheros/ath_hal/COPYRIGHT | 42 atheros/ath_hal/Makefile | 8 atheros/ath_hal/README | 64 atheros/ath_hal/ah.h | 526 +++++ atheros/ath_hal/ah_desc.h | 172 + atheros/ath_hal/ah_devid.h | 62 atheros/ath_hal/ah_osdep.c | 441 ++++ atheros/ath_hal/ah_osdep.h | 131 + atheros/ath_hal/i386-elf.hal.o.uu | 2586 +++++++++++++++++++++++++ atheros/ath_hal/opt_ah.h | 3 atheros/ath_hal/version.h | 38 atheros/bsdcompat/compat.h | 71 atheros/bsdcompat/queue.h | 530 +++++ atheros/driver/Makefile | 5 atheros/driver/if_ath.c | 2610 ++++++++++++++++++++++++++ atheros/driver/if_ath_pci.c | 287 ++ atheros/driver/if_athvar.h | 316 +++ atheros/driver/version.h | 38 atheros/release.h | 38 atheros/wlan/Makefile | 5 atheros/wlan/if_ethersubr.h | 62 atheros/wlan/if_ieee80211.h | 728 +++++++ atheros/wlan/if_ieee80211ioctl.h | 54 atheros/wlan/if_ieee80211subr.c | 3609 ++++++++++++++++++++++++++++++++++++ atheros/wlan/if_ieee80211wireless.c | 1117 +++++++++++ atheros/wlan/if_llc.h | 198 + atheros/wlan/if_media.c | 520 +++++ atheros/wlan/if_media.h | 474 ++++ atheros/wlan/if_wavelan_ieee.h | 748 +++++++ atheros/wlan/rc4.c | 104 + atheros/wlan/rc4.h | 54 atheros/wlan/version.h | 38 36 files changed, 15729 insertions(+) diff -Nru a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig --- a/drivers/net/wireless/Kconfig Wed Jul 30 18:20:27 2003 +++ b/drivers/net/wireless/Kconfig Wed Jul 30 18:20:27 2003 @@ -167,6 +167,14 @@ The driver can be compiled as a module and will be named "airo". +config ATHEROS + tristate "Atheros MiniPCI and CardBus based cards" + depends on NET_RADIO && PCI + ---help--- + Atheros MiniPCI and CardBus based cards. + + The driver can be compiled as a module and will be named "ath_pci". + config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA) diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- a/drivers/net/wireless/Makefile Wed Jul 30 18:20:27 2003 +++ b/drivers/net/wireless/Makefile Wed Jul 30 18:20:27 2003 @@ -17,6 +17,7 @@ obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o +obj-$(CONFIG_ATHEROS) += atheros/ obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o diff -Nru a/drivers/net/wireless/atheros/COPYRIGHT b/drivers/net/wireless/atheros/COPYRIGHT --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/COPYRIGHT Wed Jul 30 18:20:27 2003 @@ -0,0 +1,40 @@ +All files contained in this distribution are covered by the following +copyright unless explicitly identified otherwise. + +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: COPYRIGHT,v 1.3 2003/05/16 20:23:23 sam Exp $ + */ diff -Nru a/drivers/net/wireless/atheros/Makefile b/drivers/net/wireless/atheros/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/Makefile Wed Jul 30 18:20:27 2003 @@ -0,0 +1 @@ +obj-$(CONFIG_ATHEROS) += wlan/ driver/ ath_hal/ diff -Nru a/drivers/net/wireless/atheros/ath_hal/COPYRIGHT b/drivers/net/wireless/atheros/ath_hal/COPYRIGHT --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/COPYRIGHT Wed Jul 30 18:20:27 2003 @@ -0,0 +1,42 @@ +All files contained in this distribution are covered by the following +copyright unless explicitly identified otherwise. Note that this +copyright does _NOT_ contain a "or GPL" clause and does _NOT_ permit +redistribution with changes. + +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting, Atheros + * Communications, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * $Id: COPYRIGHT,v 1.2 2003/06/25 04:50:21 sam Exp $ + */ diff -Nru a/drivers/net/wireless/atheros/ath_hal/Makefile b/drivers/net/wireless/atheros/ath_hal/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/Makefile Wed Jul 30 18:20:27 2003 @@ -0,0 +1,8 @@ +EXTRA_CFLAGS += -I$(obj)/.. + +obj-$(CONFIG_ATHEROS) += ath_hal.o + +ath_hal-objs := ah_osdep.o hal.o + +$(obj)/hal.o: $(src)/i386-elf.hal.o.uu + uudecode < $(src)/i386-elf.hal.o.uu diff -Nru a/drivers/net/wireless/atheros/ath_hal/README b/drivers/net/wireless/atheros/ath_hal/README --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/README Wed Jul 30 18:20:27 2003 @@ -0,0 +1,64 @@ +$Id: README,v 1.2 2003/07/02 01:55:27 sam Exp $ + + +WARNING: THIS IS A BETA DISTRIBUTION. THIS SOFTWARE HAS KNOWN PROBLEMS AND +WARNING: LIMITATIONS THAT WILL BE CORRECTED BEFORE A PRODUCTION RELEASE. +WARNING: USE AT YOUR OWN RISK! + + +Atheros Hardware Access Layer (HAL) +=================================== + +* Copyright (c) 2002, 2003 Sam Leffler. +* Copyright (c) 2002, 2003 Atheros Communications, Inc. +* All rights reserved. + +Read the file COPYRIGHT for the complete copyright. + +This code manages much of the chip-specific operation of the Atheros driver. +The HAL is provided in a binary-only form in order to comply with FCC +regulations. In particular, a radio transmitter can only be operated at +power levels and on frequency channels for which it is approved. The FCC +requires that a software-defined radio cannot be configured by a user +to operate outside the approved power levels and frequency channels. +This makes it difficult to open-source code that enforces limits on +the power levels, frequency channels and other parameters of the radio +transmitter. See + +http://ftp.fcc.gov/Bureaus/Engineering_Technology/Orders/2001/fcc01264.pdf + +for the specific FCC regulation. Because the module is provided in a +binary-only form it is marked "Proprietary"; this means when you load +it you will see messages that your system is now "tainted". + +If you wish to use this driver on a platform for which an ath_hal +module is not already provided please contact the author. Note that +this is only necessary for new _architectures_; the HAL is not tied to +any specific version of your operating system. + + +Atheros Hardware +================ +There are currently 3 generations of Atheros 802.11 wireless devices: + +5210 supports 11a only +5211 supports both 11a and 11b +5212 supports 11a, 11b, and 11g + +These parts have been incorporated in a variety of retail products +including cardbus cards from DLink, Linksys, Netgear, and Proxim; and +mini-pci cards from some of these same vendors. In addition many +laptop vendors use Atheros mini-pci cards for their builtin wireless +support. An (incomplete) list of products that use Atheros parts is: + +Netgear WAG511 D-Link DWL-AG520 Linksys WPC55AG +Netgear WAB501 D-Link DWL-AG650 Linksys WMP55AG + D-Link DWL-AB650 Linksys WPC51AB + +In general, if a device is identified as ``11a only'' it is almost +certain to contain an Atheros 5210 part in it. All retail a+b +products use the 5211. The latest generation of universal a+b+g +combo products use the 5212. When in doubt check the PCI vendor +id with a tool like lspci, the Atheros vendor id is 0x168c; e.g. + + 00:13.0 Ethernet controller: Unknown device 168c:0012 (rev 01) diff -Nru a/drivers/net/wireless/atheros/ath_hal/ah.h b/drivers/net/wireless/atheros/ath_hal/ah.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/ah.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,526 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting, Atheros + * Communications, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * $Id: ah.h,v 1.34 2003/06/25 04:50:21 sam Exp $ + */ + +#ifndef _ATH_AH_H_ +#define _ATH_AH_H_ +/* + * Atheros Hardware Access Layer + * + * Clients of the HAL call ath_hal_attach to obtain a reference to an ath_hal + * structure for use with the device. Hardware-related operations that + * follow must call back into the HAL through interface, supplying the + * reference as the first parameter. + */ +#include "ah_osdep.h" + +/* + * Status codes that may be returned by the HAL. Note that + * interfaces that return a status code set it only when an + * error occurs--i.e. you cannot check it for success. + */ +typedef enum { + HAL_OK = 0, /* No error */ + HAL_ENXIO, /* No hardware present */ + HAL_ENOMEM, /* Memory allocation failed */ + HAL_EIO, /* Hardware didn't respond as expected */ + HAL_EEMAGIC, /* EEPROM magic number invalid */ + HAL_EEVERSION, /* EEPROM version invalid */ + HAL_EELOCKED, /* EEPROM unreadable */ + HAL_EEBADSUM, /* EEPROM checksum invalid */ + HAL_EEREAD, /* EEPROM read problem */ + HAL_EEBADMAC, /* EEPROM mac address invalid */ + HAL_EESIZE, /* EEPROM size not supported */ + HAL_EEWRITE, /* Attempt to change write-locked EEPROM */ + HAL_EINVAL, /* Invalid parameter to function */ + HAL_ENOTSUPP, /* Hardware revision not supported */ + HAL_ESELFTEST, /* Hardware self-test failed */ + HAL_EINPROGRESS, /* Operation incomplete */ +} HAL_STATUS; + +typedef enum { + AH_FALSE = 0, /* NB: lots of code assumes false is zero */ + AH_TRUE = 1, +} HAL_BOOL; + +/* + * "States" for setting the LED. These correspond to + * the possible 802.11 operational states and there may + * be a many-to-one mapping between these states and the + * actual hardware states for the LED's (i.e. the hardware + * may have fewer states). + */ +typedef enum { + HAL_LED_INIT = 0, + HAL_LED_SCAN = 1, + HAL_LED_AUTH = 2, + HAL_LED_ASSOC = 3, + HAL_LED_RUN = 4 +} HAL_LED_STATE; + +/* + * Transmit queue types/numbers. These are used to tag + * each transmit queue in the hardware and to identify a set + * of transmit queues for operations such as start/stop dma. + */ +typedef enum { + HAL_TX_QUEUE_INACTIVE = 0, /* queue is inactive/unused */ + HAL_TX_QUEUE_DATA, /* data xmit q's */ + HAL_TX_QUEUE_BEACON, /* beacon xmit q */ + HAL_TX_QUEUE_CAB, /* "crap after beacon" xmit q */ + HAL_TX_QUEUE_PSPOLL, /* power-save poll xmit q */ +} HAL_TX_QUEUE; + +#define HAL_NUM_TX_QUEUES 10 /* max possible # of queues */ + +/* + * Transmit packet types. This belongs in ah_desc.h, but + * is here so we can give a proper type to various parameters + * (and not require everyone include the file). + * + * NB: These values are intentionally assigned for + * direct use when setting up h/w descriptors. + */ +typedef enum { + HAL_PKT_TYPE_NORMAL = 0, + HAL_PKT_TYPE_ATIM = 1, + HAL_PKT_TYPE_PSPOLL = 2, + HAL_PKT_TYPE_BEACON = 3, + HAL_PKT_TYPE_PROBE_RESP = 4, +} HAL_PKT_TYPE; + +/* Rx Filter Frame Types */ +typedef enum { + HAL_RX_FILTER_UCAST = 0x00000001, /* Allow unicast frames */ + HAL_RX_FILTER_MCAST = 0x00000002, /* Allow multicast frames */ + HAL_RX_FILTER_BCAST = 0x00000004, /* Allow broadcast frames */ + HAL_RX_FILTER_CONTROL = 0x00000008, /* Allow control frames */ + HAL_RX_FILTER_BEACON = 0x00000010, /* Allow beacon frames */ + HAL_RX_FILTER_PROM = 0x00000020, /* Promiscuous mode */ + HAL_RX_FILTER_PROBEREQ = 0x00000080, /* Allow probe request frames */ + HAL_RX_FILTER_PHYERR = 0x00000100, /* Allow phy errors */ + HAL_RX_FILTER_PHYRADAR = 0x00000200, /* Allow phy radar errors*/ +} HAL_RX_FILTER; + +typedef enum { + HAL_PM_UNDEFINED = 0, + HAL_PM_AUTO = 1, + HAL_PM_AWAKE = 2, + HAL_PM_FULL_SLEEP = 3, + HAL_PM_NETWORK_SLEEP = 4 +} HAL_POWER_MODE; + +/* + * NOTE WELL: + * These are mapped to take advantage of the common locations for many of + * the bits on all of the currently supported MAC chips. This is to make + * the ISR as efficient as possible, while still abstracting HW differences. + * When new hardware breaks this commonality this enumerated type, as well + * as the HAL functions using it, must be modified. All values are directly + * mapped unless commented otherwise. + */ +typedef enum { + HAL_INT_RX = 0x00000001, /* Non-common mapping */ + HAL_INT_RXDESC = 0x00000002, + HAL_INT_RXNOFRM = 0x00000008, + HAL_INT_RXEOL = 0x00000010, + HAL_INT_RXORN = 0x00000020, + HAL_INT_TX = 0x00000040, /* Non-common mapping */ + HAL_INT_TXDESC = 0x00000080, + HAL_INT_TXURN = 0x00000800, + HAL_INT_MIB = 0x00001000, + HAL_INT_RXPHY = 0x00004000, + HAL_INT_RXKCM = 0x00008000, + HAL_INT_SWBA = 0x00010000, + HAL_INT_BMISS = 0x00040000, + HAL_INT_BNR = 0x00100000, /* Non-common mapping */ + HAL_INT_GPIO = 0x01000000, + HAL_INT_FATAL = 0x40000000, /* Non-common mapping */ + HAL_INT_GLOBAL = 0x80000000, /* Set/clear IER */ + + /* Interrupt bits that map directly to ISR/IMR bits */ + HAL_INT_COMMON = HAL_INT_RXNOFRM + | HAL_INT_RXDESC + | HAL_INT_RXEOL + | HAL_INT_RXORN + | HAL_INT_TXURN + | HAL_INT_TXDESC + | HAL_INT_MIB + | HAL_INT_RXPHY + | HAL_INT_RXKCM + | HAL_INT_SWBA + | HAL_INT_BMISS + | HAL_INT_GPIO, + HAL_INT_NOCARD = 0xffffffff /* To signal the card was removed */ +} HAL_INT; + +typedef enum { + HAL_RFGAIN_INACTIVE, + HAL_RFGAIN_READ_REQUESTED, + HAL_RFGAIN_NEED_CHANGE +} HAL_RFGAIN; + +/* + * Channels are specified by frequency. + */ +typedef struct { + u_int16_t channel; /* setting in Mhz */ + u_int16_t channelFlags; /* see below */ +} HAL_CHANNEL; + +#define CHANNEL_RAD_INT 0x0001 /* Radar interference detected on channel */ +#define CHANNEL_CW_INT 0x0002 /* CW interference detected on channel */ +#define CHANNEL_BUSY 0x0004 /* Busy, occupied or overlap with adjoin chan */ +#define CHANNEL_TURBO 0x0010 /* Turbo Channel */ +#define CHANNEL_CCK 0x0020 /* CCK channel */ +#define CHANNEL_OFDM 0x0040 /* OFDM channel */ +#define CHANNEL_2GHZ 0x0080 /* 2 GHz spectrum channel. */ +#define CHANNEL_5GHZ 0x0100 /* 5 GHz spectrum channel */ +#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed in the channel */ +#define CHANNEL_DYN 0x0400 /* dynamic CCK-OFDM channel */ + +#define CHANNEL_A (CHANNEL_5GHZ|CHANNEL_OFDM) +#define CHANNEL_B (CHANNEL_2GHZ|CHANNEL_CCK) +#define CHANNEL_PUREG (CHANNEL_2GHZ|CHANNEL_OFDM) +#ifdef notdef +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_DYN) +#else +#define CHANNEL_G (CHANNEL_2GHZ|CHANNEL_OFDM) +#endif +#define CHANNEL_T (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO) +#define CHANNEL_ALL \ + (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_5GHZ|CHANNEL_2GHZ|CHANNEL_TURBO) +#define CHANNEL_ALL_NOTURBO (CHANNEL_ALL &~ CHANNEL_TURBO) + +typedef struct { + u_int32_t ackrcv_bad; + u_int32_t rts_bad; + u_int32_t rts_good; + u_int32_t fcs_bad; + u_int32_t beacons; +} HAL_MIB_STATS; + +typedef u_int16_t HAL_CTRY_CODE; /* country code */ +typedef u_int16_t HAL_REG_DOMAIN; /* regulatory domain code */ + +enum { + CTRY_DEBUG = 0x1ff, /* debug country code */ + CTRY_DEFAULT = 0 /* default country code */ +}; + +enum { + HAL_MODE_11A = 0x001, + HAL_MODE_TURBO = 0x002, + HAL_MODE_11B = 0x004, + HAL_MODE_PUREG = 0x008, +#ifdef notdef + HAL_MODE_11G = 0x010, +#else + HAL_MODE_11G = 0x008, +#endif + HAL_MODE_ALL = 0xfff +}; + +typedef struct { + u_int16_t rateCount; + u_int8_t rateCodeToIndex[32]; /* back mapping */ + struct { + u_int8_t valid; /* valid for rate control use */ + u_int8_t phy; /* CCK/OFDM/XR */ + u_int16_t rateKbps; /* transfer rate in kbs */ + u_int8_t rateCode; /* rate for h/w descriptors */ + u_int8_t shortPreamble; /* mask for enabling short + * preamble in CCK rate code */ + u_int8_t dot11Rate; /* value for supported rates + * info element of MLME */ + u_int8_t controlRate; /* index of next lower basic + * rate; used for dur. calcs */ + } info[32]; +} HAL_RATE_TABLE; + +typedef struct { + u_int rs_count; /* number of valid entries */ + u_int8_t rs_rates[32]; /* rates */ +} HAL_RATE_SET; + +typedef enum { + HAL_ANT_VARIABLE, /* variable by programming */ + HAL_ANT_FIXED_A, /* fixed to 11a frequencies */ + HAL_ANT_FIXED_B, /* fixed to 11b frequencies */ +} HAL_ANT_SETTING; + +typedef enum { + HAL_M_STA = 1, /* infrastructure station */ + HAL_M_IBSS = 0, /* IBSS (adhoc) station */ + HAL_M_HOSTAP = 6 /* Software Access Point */ +} HAL_OPMODE; + +typedef struct { + int wk_len; + u_int8_t wk_key[16]; /* XXX big enough for WEP */ +} HAL_KEYVAL; + +typedef enum { + HAL_CIPHER_WEP, + HAL_CIPHER_AES_CCM, + HAL_CIPHER_CKIP +} HAL_CIPHER; + +/* + * Per-station beacon timer state. + */ +typedef struct { + u_int32_t bs_nexttbtt; /* next beacon in TU */ + u_int32_t bs_nextdtim; /* next DTIM in TU */ + u_int16_t bs_intval; /* beacon interval/period */ + u_int8_t bs_dtimperiod; + u_int8_t bs_cfpperiod; /* # of DTIMs between CFPs */ + u_int16_t bs_cfpmaxduration; /* max CFP duration in TU */ + u_int16_t bs_cfpduremain; /* remaining CFP duration */ + u_int16_t bs_timoffset; + u_int16_t bs_sleepduration; /* max sleep duration */ + u_int16_t bs_bmissthreshold; /* beacon miss threshold */ +} HAL_BEACON_STATE; + +struct ath_desc; + +/* + * Hardware Access Layer (HAL) API. + * + * Clients of the HAL call ath_hal_attach to obtain a reference to an + * ath_hal structure for use with the device. Hardware-related operations + * that follow must call back into the HAL through interface, supplying + * the reference as the first parameter. + */ +struct ath_hal { + u_int32_t ah_magic; /* consistency check magic number */ + u_int16_t ah_devid; /* PCI device ID */ + u_int16_t ah_subvendorid; /* PCI subvendor ID */ + HAL_SOFTC ah_sc; /* back pointer to driver/os state */ + HAL_BUS_TAG ah_st; /* params for register r+w */ + HAL_BUS_HANDLE ah_sh; + HAL_CTRY_CODE ah_countryCode; + + const HAL_RATE_TABLE *(*ah_getRateTable)(struct ath_hal *, u_int mode); + void (*ah_detach)(struct ath_hal*); + + /* Reset functions */ + HAL_BOOL (*ah_reset)(struct ath_hal *, HAL_OPMODE, + HAL_CHANNEL *, HAL_BOOL bChannelChange, + HAL_STATUS *status); + HAL_BOOL (*ah_setPCUConfig)(struct ath_hal *, HAL_OPMODE); + HAL_BOOL (*ah_perCalibration)(struct ath_hal*, HAL_CHANNEL *); + + /* Transmit functions */ + HAL_BOOL (*ah_updateTxTrigLevel)(struct ath_hal*, + HAL_BOOL incTrigLevel); + int (*ah_setupTxQueue)(struct ath_hal *, HAL_TX_QUEUE type, + HAL_BOOL irq); + HAL_BOOL (*ah_releaseTxQueue)(struct ath_hal *ah, u_int q); + HAL_BOOL (*ah_resetTxQueue)(struct ath_hal *ah, u_int q); + u_int32_t (*ah_getTxDP)(struct ath_hal*, u_int); + HAL_BOOL (*ah_setTxDP)(struct ath_hal*, u_int, u_int32_t txdp); + HAL_BOOL (*ah_startTxDma)(struct ath_hal*, u_int); + HAL_BOOL (*ah_stopTxDma)(struct ath_hal*, u_int); + HAL_BOOL (*ah_setupTxDesc)(struct ath_hal *, struct ath_desc *, + u_int pktLen, u_int hdrLen, + HAL_PKT_TYPE type, u_int txPower, + u_int txRate0, u_int txTries0, + u_int keyIx, u_int antMode, u_int flags, + u_int rtsctsRate, u_int rtsctsDuration); + HAL_BOOL (*ah_setupXTxDesc)(struct ath_hal *, struct ath_desc *, + HAL_BOOL shortPreamble, + u_int txRate1, u_int txTries1, + u_int txRate2, u_int txTries2, + u_int txRate3, u_int txTries3); + HAL_BOOL (*ah_fillTxDesc)(struct ath_hal *, struct ath_desc *, + u_int segLen, HAL_BOOL firstSeg, + HAL_BOOL lastSeg); + HAL_STATUS (*ah_procTxDesc)(struct ath_hal *, struct ath_desc *); + HAL_BOOL (*ah_hasVEOL)(struct ath_hal *); + + /* Receive Functions */ + u_int32_t (*ah_getRxDP)(struct ath_hal*); + void (*ah_setRxDP)(struct ath_hal*, u_int32_t rxdp); + void (*ah_enableReceive)(struct ath_hal*); + HAL_BOOL (*ah_stopDmaReceive)(struct ath_hal*); + void (*ah_startPcuReceive)(struct ath_hal*); + void (*ah_stopPcuReceive)(struct ath_hal*); + void (*ah_setMulticastFilter)(struct ath_hal*, + u_int32_t filter0, u_int32_t filter1); + HAL_BOOL (*ah_setMulticastFilterIndex)(struct ath_hal*, + u_int32_t index); + HAL_BOOL (*ah_clrMulticastFilterIndex)(struct ath_hal*, + u_int32_t index); + u_int32_t (*ah_getRxFilter)(struct ath_hal*); + void (*ah_setRxFilter)(struct ath_hal*, u_int32_t); + HAL_BOOL (*ah_setupRxDesc)(struct ath_hal *, struct ath_desc *, + u_int32_t size, u_int flags); + HAL_STATUS (*ah_procRxDesc)(struct ath_hal *, struct ath_desc *); + void (*ah_rxMonitor)(struct ath_hal *); + + /* Misc Functions */ + void (*ah_dumpState)(struct ath_hal *); + void (*ah_dumpEeprom)(struct ath_hal *); + void (*ah_dumpRfGain)(struct ath_hal *); + void (*ah_dumpAni)(struct ath_hal *); + void (*ah_getMacAddress)(struct ath_hal *, u_int8_t *); + HAL_BOOL (*ah_setRegulatoryDomain)(struct ath_hal*, + u_int16_t, HAL_STATUS *); + void (*ah_setLedState)(struct ath_hal*, HAL_LED_STATE); + void (*ah_writeAssocid)(struct ath_hal*, + const u_int8_t *bssid, u_int16_t assocId, + u_int16_t timOffset); + u_int32_t (*ah_gpioGet)(struct ath_hal*, u_int32_t gpio); + void (*ah_gpioSetIntr)(struct ath_hal*, u_int, u_int32_t); + u_int32_t (*ah_getTsf32)(struct ath_hal*); + u_int64_t (*ah_getTsf64)(struct ath_hal*); + void (*ah_resetTsf)(struct ath_hal*); + u_int16_t (*ah_getRegDomain)(struct ath_hal*); + u_int (*ah_getWirelessModes)(struct ath_hal*); + HAL_BOOL (*ah_getRfKill)(struct ath_hal*); + u_int32_t (*ah_getRandomSeed)(struct ath_hal*); + HAL_BOOL (*ah_detectCardPresent)(struct ath_hal*); + void (*ah_updateMibCounters)(struct ath_hal*, HAL_MIB_STATS*); + HAL_BOOL (*ah_isHwCipherSupported)(struct ath_hal*, HAL_CIPHER); + HAL_RFGAIN (*ah_getRfGain)(struct ath_hal*); +#if 0 + u_int32_t (*ah_getCurRssi)(struct ath_hal*); + u_int32_t (*ah_getDefAntenna)(struct ath_hal*); + void (*ah_setDefAntenna)(struct ath_hal*, u_int32_t antenna); +#endif + + /* Key Cache Functions */ + u_int32_t (*ah_getKeyCacheSize)(struct ath_hal*); + HAL_BOOL (*ah_resetKeyCacheEntry)(struct ath_hal*, u_int16_t); + HAL_BOOL (*ah_isKeyCacheEntryValid)(struct ath_hal *, u_int16_t); + HAL_BOOL (*ah_setKeyCacheEntry)(struct ath_hal*, + u_int16_t, const HAL_KEYVAL *, u_int8_t *, int); + HAL_BOOL (*ah_setKeyCacheEntryMac)(struct ath_hal*, + u_int16_t, u_int8_t *); + + /* Power Management Functions */ + HAL_BOOL (*ah_setPowerMode)(struct ath_hal*, + HAL_POWER_MODE mode, int setChip, + u_int16_t sleepDuration); + HAL_POWER_MODE (*ah_getPowerMode)(struct ath_hal*); + HAL_BOOL (*ah_queryPSPollSupport)(struct ath_hal*); + HAL_BOOL (*ah_initPSPoll)(struct ath_hal*); + HAL_BOOL (*ah_enablePSPoll)(struct ath_hal *, + u_int8_t *, u_int16_t); + HAL_BOOL (*ah_disablePSPoll)(struct ath_hal *); + + /* Beacon Management Functions */ + void (*ah_beaconInit)(struct ath_hal *, HAL_OPMODE, + u_int32_t, u_int32_t); + void (*ah_setStationBeaconTimers)(struct ath_hal*, + const HAL_BEACON_STATE *, u_int32_t tsf, + u_int32_t dtimCount, u_int32_t cfpCcount); + void (*ah_resetStationBeaconTimers)(struct ath_hal*); + HAL_BOOL (*ah_waitForBeaconDone)(struct ath_hal *, + HAL_BUS_ADDR); + + /* Interrupt functions */ + HAL_BOOL (*ah_isInterruptPending)(struct ath_hal*); + HAL_BOOL (*ah_getPendingInterrupts)(struct ath_hal*, HAL_INT *); + HAL_INT (*ah_getInterrupts)(struct ath_hal*); + HAL_INT (*ah_setInterrupts)(struct ath_hal*, HAL_INT); +}; + +/* + * Check the PCI vendor ID and device ID against Atheros' values + * and return a printable description for any Atheros hardware. + * AH_NULL is returned if the ID's do not describe Atheros hardware. + */ +extern const char *ath_hal_probe(u_int16_t vendorid, u_int16_t devid); + +/* + * Attach the HAL for use with the specified device. The device is + * defined by the PCI device ID. The caller provides an opaque pointer + * to an upper-layer data structure (HAL_SOFTC) that is stored in the + * HAL state block for later use. Hardware register accesses are done + * using the specified bus tag and handle. On successful return a + * reference to a state block is returned that must be supplied in all + * subsequent HAL calls. Storage associated with this reference is + * dynamically allocated and must be freed by calling the ah_detach + * method when the client is done. If the attach operation fails a + * null (AH_NULL) reference will be returned and a status code will + * be returned if the status parameter is non-zero. + */ +extern struct ath_hal *ath_hal_attach(u_int16_t devid, HAL_SOFTC, + HAL_BUS_TAG, HAL_BUS_HANDLE, HAL_STATUS* status); + +/* + * Return a list of channels available for use with the hardware. + * The list is based on what the hardware is capable of, the specified + * country code, the modeSelect mask, and whether or not outdoor + * channels are to be permitted. + * + * The channel list is returned in the supplied array. maxchans + * defines the maximum size of this array. nchans contains the actual + * number of channels returned. If a problem occurred or there were + * no channels that met the criteria then AH_FALSE is returned. + */ +extern HAL_BOOL ath_hal_init_channels(struct ath_hal *, + HAL_CHANNEL *chans, u_int maxchans, u_int *nchans, + HAL_CTRY_CODE cc, u_int16_t modeSelect, int enableOutdoor); + +/* + * Return bit mask of wireless modes supported by the hardware. + */ +extern u_int ath_hal_getwirelessmodes(struct ath_hal *ah, HAL_CTRY_CODE cc); + +/* + * Return rate table for specified mode (11a, 11b, 11g, etc). + */ +extern const HAL_RATE_TABLE *ath_hal_getratetable(struct ath_hal *, + u_int mode); + +/* + * Calculate the transmit duration of a frame. + */ +extern u_int16_t ath_hal_computetxtime(struct ath_hal *, + const HAL_RATE_TABLE *rates, u_int32_t frameLen, + u_int16_t rateix, HAL_BOOL shortPreamble); + +/* + * Convert between IEEE channel number and channel frequency + * using the specified channel flags; e.g. CHANNEL_2GHZ. + */ +extern u_int ath_hal_mhz2ieee(u_int mhz, u_int flags); +extern u_int ath_hal_ieee2mhz(u_int ieee, u_int flags); +#endif /* _ATH_AH_H_ */ diff -Nru a/drivers/net/wireless/atheros/ath_hal/ah_desc.h b/drivers/net/wireless/atheros/ath_hal/ah_desc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/ah_desc.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,172 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting, Atheros + * Communications, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * $Id: ah_desc.h,v 1.11 2003/06/25 04:50:22 sam Exp $ + */ + +#ifndef _DEV_ATH_DESC_H +#define _DEV_ATH_DESC_H + +/* + * Transmit descriptor status. This structure is filled + * in only after the tx descriptor process method finds a + * ``done'' descriptor; at which point it returns something + * other than HAL_EINPROGRESS. + * + * Note that ts_antenna may not be valid for all h/w. It + * should be used only if non-zero. + */ +struct ath_tx_status { + u_int16_t ts_seqnum; /* h/w assigned sequence number */ + u_int16_t ts_tstamp; /* h/w assigned timestamp */ + u_int8_t ts_status; /* frame status, 0 => xmit ok */ + u_int8_t ts_rate; /* h/w transmit rate index */ + int8_t ts_rssi; /* tx ack RSSI */ + u_int8_t ts_shortretry; /* # short retries */ + u_int8_t ts_longretry; /* # long retries */ + u_int8_t ts_virtcol; /* virtual collision count */ + u_int8_t ts_antenna; /* antenna information */ +}; + +#define HAL_TXERR_XRETRY 0x01 /* excessive retries */ +#define HAL_TXERR_FILT 0x02 /* blocked by tx filtering */ +#define HAL_TXERR_FIFO 0x04 /* fifo underrun */ + +/* + * Receive descriptor status. This structure is filled + * in only after the rx descriptor process method finds a + * ``done'' descriptor; at which point it returns something + * other than HAL_EINPROGRESS. + * + * If rx_status is zero, then the frame was received ok; + * otherwise the error information is indicated and rs_phyerr + * contains a phy error code if HAL_RXERR_PHY is set. + * + * Note that the receive timestamp is expanded using the TSF to + * a full 16 bits (regardless of what the h/w provides directly). + */ +struct ath_rx_status { + u_int16_t rs_datalen; /* rx frame length */ + u_int16_t rs_tstamp; /* h/w assigned timestamp */ + u_int8_t rs_status; /* rx status, 0 => recv ok */ + u_int8_t rs_phyerr; /* phy error code */ + int8_t rs_rssi; /* rx frame RSSI */ + u_int8_t rs_keyix; /* key cache index */ + u_int8_t rs_rate; /* h/w receive rate index */ + u_int8_t rs_antenna; /* antenna information */ + u_int8_t rs_more; /* more descriptors follow */ +}; + +#define HAL_RXERR_CRC 0x01 /* CRC error on frame */ +#define HAL_RXERR_PHY 0x02 /* PHY error, rs_phyerr is valid */ +#define HAL_RXERR_FIFO 0x04 /* fifo overrun */ +#define HAL_RXERR_DECRYPT 0x08 /* non-Michael decrypt error */ +#define HAL_RXERR_MIC 0x10 /* Michael MIC decrypt error */ + +enum { + HAL_PHYERR_UNDERRUN = 0, /* Transmit underrun */ + HAL_PHYERR_TIMING = 1, /* Timing error */ + HAL_PHYERR_PARITY = 2, /* Illegal parity */ + HAL_PHYERR_RATE = 3, /* Illegal rate */ + HAL_PHYERR_LENGTH = 4, /* Illegal length */ + HAL_PHYERR_RADAR = 5, /* Radar detect */ + HAL_PHYERR_SERVICE = 6, /* Illegal service */ + HAL_PHYERR_TOR = 7, /* Transmit override receive */ + /* NB: these are specific to the 5212 */ + HAL_PHYERR_OFDM_TIMING = 17, /* */ + HAL_PHYERR_OFDM_SIGNAL_PARITY = 18, /* */ + HAL_PHYERR_OFDM_RATE_ILLEGAL = 19, /* */ + HAL_PHYERR_OFDM_LENGTH_ILLEGAL = 20, /* */ + HAL_PHYERR_OFDM_POWER_DROP = 21, /* */ + HAL_PHYERR_OFDM_SERVICE = 22, /* */ + HAL_PHYERR_OFDM_RESTART = 23, /* */ + HAL_PHYERR_CCK_TIMING = 25, /* */ + HAL_PHYERR_CCK_HEADER_CRC = 26, /* */ + HAL_PHYERR_CCK_RATE_ILLEGAL = 27, /* */ + HAL_PHYERR_CCK_SERVICE = 30, /* */ + HAL_PHYERR_CCK_RESTART = 31, /* */ +}; + +/* value found in rs_keyix to mark invalid entries */ +#define HAL_RXKEYIX_INVALID ((u_int8_t) -1) +/* value used to specify no encryption key for xmit */ +#define HAL_TXKEYIX_INVALID ((u_int) -1) + +/* XXX rs_antenna definitions */ + +/* + * Definitions for the software frame/packet descriptors used by + * the Atheros HAL. This definition obscures hardware-specific + * details from the driver. Drivers are expected to fillin the + * portions of a descriptor that are not opaque then use HAL calls + * to complete the work. Status for completed frames is returned + * in a device-independent format. + */ +struct ath_desc { + /* + * The following definitions are passed directly + * the hardware and managed by the HAL. Drivers + * should not touch those elements marked opaque. + */ + u_int32_t ds_link; /* phys address of next descriptor */ + u_int32_t ds_data; /* phys address of data buffer */ + u_int32_t ds_ctl0; /* opaque DMA control 0 */ + u_int32_t ds_ctl1; /* opaque DMA control 1 */ + u_int32_t ds_hw[4]; /* opaque h/w region */ + /* + * The remaining definitions are managed by software; + * these are valid only after the rx/tx process descriptor + * methods return a non-EINPROGRESS code. + */ + union { + struct ath_tx_status tx;/* xmit status */ + struct ath_rx_status rx;/* recv status */ + } ds_us; +} __attribute__((__packed__)); + +#define ds_txstat ds_us.tx +#define ds_rxstat ds_us.rx + +/* flags passed to tx descriptor setup methods */ +#define HAL_TXDESC_CLRDMASK 0x0001 /* clear destination filter mask */ +#define HAL_TXDESC_NOACK 0x0002 /* don't wait for ACK */ +#define HAL_TXDESC_RTSENA 0x0004 /* enable RTS */ +#define HAL_TXDESC_CTSENA 0x0008 /* enable CTS */ +#define HAL_TXDESC_INTREQ 0x0010 /* enable per-descriptor interrupt */ +#define HAL_TXDESC_VEOL 0x0020 /* mark virtual EOL */ + +/* flags passed to rx descriptor setup methods */ +#define HAL_RXDESC_INTREQ 0x0020 /* enable per-descriptor interrupt */ +#endif /* _DEV_ATH_AR521XDMA_H */ diff -Nru a/drivers/net/wireless/atheros/ath_hal/ah_devid.h b/drivers/net/wireless/atheros/ath_hal/ah_devid.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/ah_devid.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting, Atheros + * Communications, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * $Id: ah_devid.h,v 1.6 2003/06/25 04:50:22 sam Exp $ + */ + +#ifndef _DEV_ATH_DEVID_H_ +#define _DEV_ATH_DEVID_H_ + +#define ATHEROS_VENDOR_ID 0x168c /* Atheros PCI vendor ID */ + +/* AR5210 (for reference) */ +#define AR5210_DEFAULT 0x1107 /* No eeprom HW default */ +#define AR5210_PROD 0x0007 /* Final device ID */ +#define AR5210_AP 0x0207 /* Early AP11s */ + +/* AR5211 */ +#define AR5211_DEFAULT 0x1112 /* No eeprom HW default */ +#define AR5311_DEVID 0x0011 /* Final ar5311 devid */ +#define AR5211_DEVID 0x0012 /* Final ar5211 devid */ +#define AR5211_LEGACY 0xff12 /* Original emulation board */ +#define AR5211_FPGA11B 0xf11b /* 11b emulation board */ + +/* AR5212 */ +#define AR5212_DEFAULT 0x1113 /* No eeprom HW default */ +#define AR5212_DEVID 0x0013 /* Final ar5212 devid */ +#define AR5212_FPGA 0xf013 /* Emulation board */ + +#define AR_SUBVENDOR_ID_NOG 0x0e11 /* No 11G subvendor ID */ +#endif /* _DEV_ATH_DEVID_H */ diff -Nru a/drivers/net/wireless/atheros/ath_hal/ah_osdep.c b/drivers/net/wireless/atheros/ath_hal/ah_osdep.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/ah_osdep.c Wed Jul 30 18:20:27 2003 @@ -0,0 +1,441 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting, Atheros + * Communications, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * $Id: ah_osdep.c,v 1.16 2003/06/25 04:50:27 sam Exp $ + */ +#include "opt_ah.h" + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "ah.h" + +#define __MOD_INC_USE_COUNT(_m) \ + if (!try_module_get(_m)) { \ + printk(KERN_WARNING "try_module_get failed\n"); \ + return NULL; \ + } +#define __MOD_DEC_USE_COUNT(_m) module_put(_m) + +#define AH_TIMEOUT 1000 + +#ifdef AH_DEBUG +static int ath_hal_debug = 0; +#endif /* AH_DEBUG */ + +int ath_hal_dma_beacon_response_time = 2; /* in TU's */ +int ath_hal_sw_beacon_response_time = 10; /* in TU's */ +int ath_hal_additional_swba_backoff = 0; /* in TU's */ + +struct ath_hal * +_ath_hal_attach(u_int16_t devid, HAL_SOFTC sc, + HAL_BUS_TAG t, HAL_BUS_HANDLE h, void* s) +{ + HAL_STATUS status; + struct ath_hal *ah = ath_hal_attach(devid, sc, t, h, &status); + + *(HAL_STATUS *)s = status; + if (ah) + __MOD_INC_USE_COUNT(THIS_MODULE); + return ah; +} + +void +ath_hal_detach(struct ath_hal *ah) +{ + (*ah->ah_detach)(ah); + __MOD_DEC_USE_COUNT(THIS_MODULE); +} + +/* + * Print/log message support. + */ + +void +ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap) +{ + char buf[1024]; /* XXX */ + vsnprintf(buf, sizeof(buf), fmt, ap); + printk("%s", buf); +} + +void +ath_hal_printf(struct ath_hal *ah, const char* fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + ath_hal_vprintf(ah, fmt, ap); + va_end(ap); +} + +/* + * Format an Ethernet MAC for printing. + */ +const char* +ath_hal_ether_sprintf(const u_int8_t *mac) +{ + static char etherbuf[18]; + snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return etherbuf; +} + +#ifdef AH_ASSERT +void +ath_hal_assert_failed(const char* filename, int lineno, const char *msg) +{ + printk("Atheros HAL assertion failure: %s: line %u: %s\n", + filename, lineno, msg); + panic("ath_hal_assert"); +} +#endif /* AH_ASSERT */ + +/* + * Memory-mapped device register read/write. These are here + * as routines and not defined in ah_osdep.h to insure the HAL + * uses no GPL-contaminated files. + */ + +#ifdef AH_DEBUG +void +ath_hal_reg_write(struct ath_hal *ah, u_int reg, u_int32_t val) +{ + if (ath_hal_debug > 1) + ath_hal_printf(ah, "WRITE 0x%x <= 0x%x\n", reg, val); + writel(val, ah->ah_sh + reg); +} + +u_int32_t +ath_hal_reg_read(struct ath_hal *ah, u_int reg) +{ + u_int32_t val = readl(ah->ah_sh + reg); + if (ath_hal_debug > 1) + ath_hal_printf(ah, "READ 0x%x => 0x%x\n", reg, val); + return val; +} + +void +HALDEBUG(struct ath_hal *ah, const char* fmt, ...) +{ + if (ath_hal_debug) { + __va_list ap; + va_start(ap, fmt); + ath_hal_vprintf(ah, fmt, ap); + va_end(ap); + } +} + + +void +HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...) +{ + if (ath_hal_debug >= level) { + __va_list ap; + va_start(ap, fmt); + ath_hal_vprintf(ah, fmt, ap); + va_end(ap); + } +} +#endif /* AH_DEBUG */ + +/* + * Delay n microseconds. + */ +void +ath_hal_delay(int n) +{ + udelay(n); +} + +u_int32_t +ath_hal_getuptime(struct ath_hal *ah) +{ + return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ); +} + +/* + * Poll the register looking for a specific value. + */ +HAL_BOOL +ath_hal_wait(struct ath_hal *ah, u_int reg, u_int32_t mask, u_int32_t val) +{ + int i; + + for (i = 0; i < AH_TIMEOUT; i++) { + if ((OS_REG_READ(ah, reg) & mask) == val) + return AH_TRUE; + OS_DELAY(10); + } + ath_hal_printf(ah, "ath_hal_wait: timeout on reg 0x%x: " + "0x%08x & 0x%08x != 0x%08x\n", reg, OS_REG_READ(ah, reg), + mask, val); + return AH_FALSE; +} + +/* + * Allocate/free memory. + */ + +void* +ath_hal_malloc(size_t size) +{ + void *p; + p = kmalloc(size, GFP_KERNEL); + if (p) + OS_MEMZERO(p, size); + return p; + +} + +void +ath_hal_free(void* p) +{ + kfree(p); +} + +#ifdef OS_QSORT +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +static OS_INLINE char *med3(char *, char *, char *, ath_hal_cmp_t *); +static OS_INLINE void swapfunc(char *, char *, int, int); + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static OS_INLINE void +swapfunc(a, b, n, swaptype) + char *a, *b; + int n, swaptype; +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static OS_INLINE char * +med3(a, b, c, cmp) + char *a, *b, *c; + ath_hal_cmp_t *cmp; +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a )) + :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c )); +} + +void +ath_hal_qsort(void *a, size_t n, size_t es, ath_hal_cmp_t *cmp) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; pl > (char *)a && cmp(pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > es) + ath_hal_qsort(a, r / es, es, cmp); + if ((r = pd - pc) > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +} +#endif /* OS_QSORT */ + +/* + * Module glue. + */ +#include "release.h" +#include "version.h" +static char *version = ATH_HAL_VERSION " " RELEASE_TYPE " (Sam Leffler )"; +static char *dev_info = "ath_hal"; + +MODULE_AUTHOR("Errno Consulting, Sam Leffler"); +MODULE_DESCRIPTION("Atheros Hardware Access Layer (HAL)"); +MODULE_SUPPORTED_DEVICE("Atheros WLAN devices"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Proprietary"); +#endif + +EXPORT_SYMBOL(ath_hal_probe); +EXPORT_SYMBOL(_ath_hal_attach); +EXPORT_SYMBOL(ath_hal_detach); +EXPORT_SYMBOL(ath_hal_init_channels); +EXPORT_SYMBOL(ath_hal_getwirelessmodes); +EXPORT_SYMBOL(ath_hal_computetxtime); +EXPORT_SYMBOL(ath_hal_mhz2ieee); +EXPORT_SYMBOL(ath_hal_ieee2mhz); + +static int __init +init_ath_hal(void) +{ + printk(KERN_INFO "%s: %s\n", dev_info, version); + return (0); +} +module_init(init_ath_hal); + +static void __exit +exit_ath_hal(void) +{ + printk(KERN_INFO "%s: driver unloaded\n", dev_info); +} +module_exit(exit_ath_hal); diff -Nru a/drivers/net/wireless/atheros/ath_hal/ah_osdep.h b/drivers/net/wireless/atheros/ath_hal/ah_osdep.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/ah_osdep.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,131 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting, Atheros + * Communications, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * $Id: ah_osdep.h,v 1.10 2003/06/25 04:50:27 sam Exp $ + */ +#ifndef _ATH_AH_OSDEP_H_ +#define _ATH_AH_OSDEP_H_ +/* + * Atheros Hardware Access Layer (HAL) OS Dependent Definitions. + */ + +/* + * When building the HAL proper we use no GPL-contaminated include + * files and must define these types ourself. Beware of these being + * mismatched against the contents of + */ +#ifndef _LINUX_TYPES_H +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +typedef unsigned char u_int8_t; +typedef unsigned short u_int16_t; +typedef unsigned int u_int32_t; +typedef unsigned long long u_int64_t; + +typedef unsigned int size_t; +typedef unsigned int u_int; +typedef void *va_list; +#endif + +/* + * Linux/BSD gcc compatibility shims. + */ +#define __printflike(_a,_b) \ + __attribute__ ((__format__ (__printf__, _a, _b))) +#define __va_list va_list +#define OS_INLINE __inline + +typedef void* HAL_SOFTC; +typedef int HAL_BUS_TAG; +typedef void* HAL_BUS_HANDLE; +typedef u_int32_t HAL_BUS_ADDR; /* XXX architecture dependent */ + +/* + * Delay n microseconds. + */ +extern void ath_hal_delay(int); +#define OS_DELAY(_n) ath_hal_delay(_n) + +/* + * Memory zero, copy (non-overlapped), compare, and sort. + */ +#define OS_MEMZERO(_a, _size) memset((_a), 0, (_size)) +#define OS_MEMCPY(_dst, _src, _size) memcpy((_dst), (_src), (_size)) +#define OS_MACEQU(_a, _b) \ + (memcmp((_a), (_b), IEEE80211_ADDR_LEN) == 0) +#define OS_QSORT(_a, _n, _es, _cmp) \ + ath_hal_qsort((_a), (_n), (_es), (_cmp)) + +typedef int ath_hal_cmp_t(const void *, const void *); +extern void ath_hal_qsort(void *a, size_t n, size_t es, ath_hal_cmp_t *cmp); + +struct ath_hal; +extern u_int32_t ath_hal_getuptime(struct ath_hal *); +#define OS_GETUPTIME(_ah) ath_hal_getuptime(_ah) + +/* + * Register read/write; we assume the registers + * will always be memory-mapped. + */ +#ifndef AH_DEBUG +#define OS_REG_WRITE(_ah, _reg, _val) do { \ + *((volatile u_int32_t *)((_ah)->ah_sh + (_reg))) = (_val); \ +} while (0) +#define OS_REG_READ(_ah, _reg) \ + (*((volatile u_int32_t *)((_ah)->ah_sh + (_reg)))) +#else +#define OS_REG_WRITE(_ah, _reg, _val) ath_hal_reg_write(_ah, _reg, _val) +#define OS_REG_READ(_ah, _reg) ath_hal_reg_read(_ah, _reg) + +extern void ath_hal_reg_write(struct ath_hal *ah, u_int reg, u_int32_t val); +extern u_int32_t ath_hal_reg_read(struct ath_hal *ah, u_int reg); +#endif +#define OS_MARK(_ah, _id, _v) + +/* + * Linux-specific attach/detach methods needed for module reference counting. + * + * XXX We can't use HAL_STATUS because the type isn't defined at this + * point (circular dependency); we wack the type and patch things + * up in the function. + */ +extern struct ath_hal *_ath_hal_attach(u_int16_t devid, HAL_SOFTC, + HAL_BUS_TAG, HAL_BUS_HANDLE, void* status); +extern void ath_hal_detach(struct ath_hal *); + +#endif /* _ATH_AH_OSDEP_H_ */ diff -Nru a/drivers/net/wireless/atheros/ath_hal/i386-elf.hal.o.uu b/drivers/net/wireless/atheros/ath_hal/i386-elf.hal.o.uu --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/i386-elf.hal.o.uu Wed Jul 30 18:20:27 2003 @@ -0,0 +1,2586 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting, Atheros + * Communications, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * $Id: i386-elf.hal.o.uu,v 1.5 2003/06/25 04:50:27 sam Exp $ + */ +begin 644 hal.o +M?T5,1@$!`0````````````$``P`!``````````````"$>`$``````#0````` +M`"@`#P`,`%6)Y0^W10@]!Q$``'1*/0<1``!_&X/X$G\.@_@1?4&#^`=T-.M: +MB?:#^!-T2^M1D#T3$0``=$$]$Q$``'\*/1(1``!T&^LYD#T3\```="$]&_$` +M`'02ZRBX`````.LFD+@-````ZQZ0N!H```#K%I"X+@```.L.D+A"````ZP:0 +MN`````!=PY!5B>6#[`B+10QF@7T(C!9U#X/L#`^WP%#H6____^L&D+@````` +MR<.058GE5U93@^P,BWT,BW40BUT4BTT8BT4(#[?0@?H'`@``#X21````@?H' +M`@``?R&#^A)_$(/Z$7UG@_H'='KIC0```)"#^A-T/^F"````B?:!^A,1``!T +M,('Z$Q$``'\4@?H'$0``=%"!^A(1``!T,.M>B?:!^A/P``!T#('Z&_$``'0< +MZTJ)]H/L#%%35ED&C43Q%;H` +M````]_&-!(4D````ZW"-=@"-#-T`````NM--8A")R/?BB='!Z0:-1/$5N@`` +M``#W\8T$A18```#K1(UV`(T,G0````"ZTTUB$(G(]^*)T<'I!HU$\16Z```` +M`/?QP>`"@?OG`P``=PD%O0```.L/B?:#P%SK"(UV`+@`````#[?`6UY?7<.- +M=@!5B>6+50SV0@(@=`BX`@```.M0D&:+0@(EP````&8]P`!U";@#````ZSF) +M]F:+0@(ET````&8]T`!U";@$````ZR&)]O9"`A!T"K@!````ZQ*-=@"X```` +M`/9"`P@/E<"-!(!=PXUV`%6)Y8M%"(M5#(32>1,]M`D``'0C/;,)``!W3.LJ +MC78`]\(``0``=`B-D'CL___K'3VT"0``=0FX#@```.M6B?8]LPD``'<9C9"9 +M]O__NXM`D` +M`.LL@_@-=PN-!(`%9PD``.L=D(/X&G&(M7$(M$WA2+!!!0_W3>$(M7$(M$W@R+ +M!!!0_W3>"(M7$(M$W@2+!!!0_S3>:,````!J`.C\____@\0P@\,$C4,#.T40 +M.F0````C78`@_@##X6$````BU<0BT3> +M%(L$$%#_=-X0BU<0BT3>#(L$$%#_=-X(BU<0BT3>!(L$$%#_--YH``$``.LE +M@^P(BU<0BT3>#(L$$%#_=-X(BU<0BT3>!(L$$%#_--YH<````&H`Z/S___^# +MQ"#K((UV`(M'$(M4W@2+!`)0_S3>:(8```!J`.C\____@\00C67T6UY?7<.- +M=@!5B>575E.#[`B+10B+=12+30R+51#'1?``````9H$X`3!V!\=%\!8```"[ +M``````^WTHE5[`^W^8M5\`^W!%J+3>P/K\BZ9````"G"B=`/K\M1 +M]^G!^@7!^1\IRF:)%H/&`D.#^PI^RH/$"%M>7UW#B?95B>6+50P/M\)F@?K_ +M`'0^BT4(9H$X`C!W)F:#^CYV$`^WPHT$@`4B%0``ZQZ-=@`/M\*-!("-A`#L +M$P``ZPR0#[?"C02`!<`2```/M\!=PU6)Y8M5#`^WPF:!^O\`=!V+10AF@3@" +M,'<*C8)@"0``ZPB)]HV"_`@```^WP%W#D%6)Y5=64X/L#(M%#&:!.`(P=FV_ +M4`$``+X`````9H.X2@$````/A-\!``")PX/#!H/L!(U%\E`/M\=01_]U"/]5 +M$(/$$(7`#X2C`0``C10V9@^V1?-FB803,`$``&8/MD7R9HF$$S(!``"#Q@*+ +M50P/MX)*`0``.<9\M>F*`0``@^P$C47R4&@``0``OP$!``#_=0C_51"#Q!"% +MP`^$3@$``&:+1?)FP>@)BU4,9HF"-@$``&:+1?)FP>@"@^!_9HF".`$``&:+ +M1?+!X`6#X']FB8(Z`0``@^P$C47R4`^WQU!'_W4(_U40@\00A<`/A/P```!F +MBT7R9L'H"XM5#&8)@CH!``!FBT7R9L'H!(/@?V:)@CP!``!FBT7RP>`#@^!_ +M9HF"/@$``(/L!(U%\E`/M\=01_]U"/]5$(/$$(7`#X2J````9HM%\F;!Z`V+ +M50QF"8(^`0``9HM%\F;!Z`:#X']FB8)``0``9HM%\M'@@^!_9HF"0@$``(/L +M!(U%\E`/M\=01_]U"/]5$(/$$(7`=%UFBT7R9L'H#XM5#&8)@D(!``!F#[9% +M\X/@?V:)@D0!``!FBT7R9M'H@^!_9HF"1@$``&:+1?+!X`:#X']FB8)(`0`` +M@^P$C47R4`^WQU#_=0C_51"#Q!"%P'4*B?:X`````.M?D&:+1?)FP>@*BU4, +M9@F"2`$``+X`````BT4,9H.X2@$```!T-8G'@\<&C78`@^P(C9PV,`$```^W +M!#M0_W4,Z$7]__]FB00[@\001HM5#`^W@DH!```YQGS3N`$```"-9?1;7E]= +MPXGV58GE5U93@^P@!=$># +M?>@!?PV#?>@`=!/IV@$``(GV@WWH`G1>Z1@`#X0B`@``@\A@`#X3R`0``@\=& +M9HN"5`,``&:)1?")TX'#8@,``('"5@,``(E5Y,=%[`````!F@WWP``^$P0$` +M`(U5\HE5X(UV`(M-[(M5Y&:+!$IFB0.#[`3_=>!71_]U"/]5$(/$$(7`#X0& +M`0``9HM%\F;!Z`IFB4,$9HM%\F;!Z`2#X#]FB4,"9HM%\L'@`H/@/V:)0QZ# +M[`3_=>!71_]U"/]5$(/$$(7`#X3$````9HM%\F;!Z`YF"4,>9@^V1?.#X#]F +MB4,@9HM%\F;!Z`*#X#]FB4,B9HM%\L'@!(/@/V:)0R2#[`3_=>!71_]U"/]5 +M$(/$$(7`='IFBT7R9L'H#&8)0R1FBT7R9L'H!H/@/V:)0R9FBT7R@^`_9HE# +M*(/L!/]UX%='_W4(_U40@\00A@*9HE#*F:+1?)FP>@$@^`_ +M9HE#+&:+1?+!X`*#X#]FB4,N@^P$_W7@5T?_=0C_51"#Q!"%P'4-D+@````` +MZ90```")]F:+1?)FP>@.9@E#+F8/MD7S@^`_9HE#,&:+1?)FP>@"@^`_9HE# +M,HU#"%`/MT,$4`^W0P)0_W4,Z$OZ__^#Q!"Y`````&:#>P8`="&-P/MT7P.47L#XQ(_O__ +M_T7H@WWH`@^.8_W__[@!````C67T6UY?7<.)]E6)Y5=64X/L'(M]#,=%Z``` +M``"09H$_`S`9]H/FL('&4`$``(-]Z`%T-H-]Z`%_#(-]Z`!T$NE!`0``D(-] +MZ`)T0NDU`0``D(/&5<=%Y`@```"-GYP$``"-AYH$``#K16:#?Q@`#X2!`0`` +M@\9EQT7D`@```(V?#@4``(V'#`4``.LBD&:#?Q@`#X1=`0``@\9IQT7D`P`` +M`(V?[@0``(V'[`0``(E%X(M%X&;'````QT7L`````.DD`0``@^P$C47R4%9& +M_W4(_U40@\00A<`/A*8```!F@3\",'8'9@^V1?/K"&:+1?)FP>@)9HE#"&:# +M>P@`#X3?````@WWH`'43@^P(#[=#"%!7Z%7Y___K$8UV`(/L"`^W0PA05^B2 +M^?__9HE#"(/$$&:!/P(P=AAFBT7R9L'H`H/@/V:)0P9FBT7RP>`$ZQ9FBT7R +M9L'H`X/@/V:)0P9FBT7RP>`#@^`_9HE#!(/L!(U%\E!61O]U"/]5$(/$$(7` +M=0F0N`````#K>Y!F@3\",'8A9HM%\F;!Z`QF"4,$9HM%\F;!Z`:#X#]FB4," +M9HM%\NLB9HM%\F;!Z`UF"4,$9HM%\F;!Z`>#X#]FB4,"9HM%\F;1Z(/@/V:) +M`XM%X&;_`(/#"O]%[(M%Y#E%[`^,T/[___]%Z(-]Z`(/CAO^__^X`0```(UE +M]%M>7UW#B?95B>575E.#[!R+=0R!QB0%``"+10QF@3@#,!G_@^>P@<>_`0`` +MQT7L`````&:#N-@`````#X0<`P``C57RB57DBTWLBT4,9H.\2-H`````=1=F +M@3@",'8(@\<(Z=T"``"#QP?IU0(``(M5#&:!.@(P#X:B````NP````"0@^P$ +M_W7D5T?_=0C_51"#Q!"%P`^$(P(``&8/MD7S9HD$WF8/MD7R9HE$W@B#PP*# +M^P=^S+L`````C78`@^P$_W7D5T?_=0C_51"#Q!"%P`^$YP$``&8/MD7S@^`_ +M9HE$W@)FBT7R9L'H#H/@`8E$W@1FBT7R@^`_9HE$W@IFBT7R9L'H!H/@`8E$ +MW@R#PP*#^P=^J.G'`0``C78`@^P$_W7D5T?_=0C_51"#Q!"%P`^$AP$``&:+ +M1?)FP>@)9HD&9HM%\F;!Z`*#X']FB48(9HM%\L'@!8/@?V:)1A"#[`3_=>17 +M1_]U"/]5$(/$$(7`#X1&`0``9HM%\F;!Z`MF"4809HM%\F;!Z`2#X']FB488 +M9HM%\L'@`X/@?V:)1B"#[`3_=>171_]U"/]5$(/$$(7`#X0$`0``9HM%\F;! +MZ`UF"48@9HM%\F;!Z`:#X']FB48H9HM%\M'@@^!_9HE&,(/L!/]UY%='_W4( +M_U40@\00A<`/A,,```!FBT7R9L'H#V8)1C!F#[9%\X/@?V:)1CAFBT7R9L'H +M`H/@/V:)1@)FBT7RP>`$@^`_9HE&"H/L!/]UY%='_W4(_U40@\00A6:+ +M1?)FP>@,9@E&"F:+1?)FP>@&@^`_9HE&$F:+1?*#X#]FB48:@^P$_W7D5T?_ +M=0C_51"#Q!"%P'0^9HM%\F;!Z`IFB48B9HM%\F;!Z`2#X#]FB48J9HM%\L'@ +M`H/@/V:)1C*#[`3_=>171_]U"/]5$(/$$(7`=0RX`````.F9````B?9FBT7R +M9L'H#F8)1C)F#[9%\X/@/V:)1CJ[`````(M-[(V,"=````")3>B)]H,\W@!T +M08M5#(M-Z&:+1!$*@^`#=`9F@_@#=12#[`@/MP3>4/]U#.A`]?__ZQ*)]H/L +M"`^W!-Y0_W4,Z'SU__]FB03>@\000X/[!WZS@\9`_T7LBU4,#[>"V````#E% +M[`^,ZOS__[@!````C67T6UY?7<.058GE5U93@^P@/9HE&!F:+1?)FP>@.@^`!9HE&"F:+ +M1?)FP>@+@^`'9HE&#&:+1?)FP>@$@^!_9HE&#F:+1?)FP>@#@^`!9HE&"&:+ +M1?)FP>@"@^`!9HE&&F:+1?)FT>B#X`%FB4889HM%\H/@`6:)1A:#[`2-1?)0 +MBU7L_W($_W4(_U40@\00A<`/A-$%``!F#[9%\XA&'(I%\HA&';\`````C4WR +MB4W@C48*B47HB?:+5>R+7+H(@^P$_W7@4T/_=0C_51"#Q!"%P`^$D`4``(T, +M/XU1(&8/MD7S@^!_9HE$,@AFBT7R9L'H`H/@/V:)1#(.9HM%\L'@!(/@/XM5 +MZ&:)1`I@@^P$_W7@4T/_=0C_51"#Q!"%P`^$0@4``(T4/V:+1?)FP>@,BTWH +M9@E$$6!FBT7R9L'H!H/@/V:)1!%F9HM%\H/@/V:)1!%L@^P$_W7@4T/_=0C_ +M51"#Q!"%P`^$^@0``(T4/V:+1?)FP>@*BTWH9HE$$7)FBT7R9L'H!(/@/V:) +M1!%X9HM%\L'@`H/@/V:)1!%^@^P$_W7@4T/_=0C_51"#Q!"%P`^$KP0``(T4 +M/V:+1?)FP>@.BTWH9@E$$7YF#[9%\X/@/V:)A!&$````9HM%\F;!Z`*#X#]F +MB801B@```&:+1?+!X`2#X#]FB801D````(/L!/]UX%-#_W4(_U40@\00A<`/ +MA$X$``"-%#]FBT7R9L'H#(M-Z&8)A!&0````9HM%\F;!Z`:#X#]FB801E@`` +M`&:+1?*#X#]FB801G````(/L!/]UX%-#_W4(_U40@\00A<`/A/T#``!F#[9% +M\XA$-TR#_P%T3X/_`7\*A?]T#NF%````D(/_`G1?ZWV09HM%\F;!Z`6#X`=F +MB8;$````9HM%\F;!Z`*#X`=FB8;&````9HM%\M'@@^`'9HF&P````.M&B?9F +MBT7R9L'H!(/@!V:)AL@```!FBT7R@^`'9HF&R@```.LBB?9FBT7R9L'H!(/@ +M!V:)ALP```!FBT7R@^`'9HF&S@```(7_=7Z#[`3_=>!30_]U"/]5$(/$$(7` +M#X0_`P``9HM%\F;!Z`]F"8;`````9HM%\F;!Z`R#X`=FB8;"````9HM%\F;! +MZ`F#X`=FB8:\````9HM%\F;!Z`:#X`=FB8:^````9HM%\F;!Z`.#X`=FB8:X +M````9HM%\H/@!V:)AKH```"#[`3_=>!30_]U"/]5$(/$$(7`#X3!`@``C50_ +M,&8/MD7S9HE$,@1F#[9%\HM-Z&:)!`J#[`3_=>!30_]U"/]5$(/$$(7`#X2. +M`@``C50_0&8/MD7S9HD$,F8/MD7R9HE$,@:#[`3_=>!30_]U"/]5$(/$$(7` +M#X1>`@``9@^V1?.(1#=/C4P_4(U6`F8/MD7R9HD$$8`\$0!Y"0T`____9HD$ +M$8/L!/]UX%-#_W4(_U40@\00A<`/A!T"``"-##^-45!FBT7R9L'H!27_```` +M9HE$,@AFBT7R9M'H@^`/9HE$,@YFBT7R@^`!9HE$,61F@3X",`^&F@```(/L +M!/]UX%-#_W4(_U40@\00A<`/A,8!``!FBT7R9L'H!H/@?V:)A'ZL````@_\! +M=!:#_P%_"87_=%7K7HUV`(/_`G0GZU209HM%\H/@!V:)AM````!FBT7R9L'H +M`X/@!V:)AM0```#K,8GV9HM%\H/@!V:)AM(```!FBT7R9L'H`X/@!V:)AM8` +M``#K#8GV9HM%\H/@/V:)1A)F@3X#,'929HM%\F;!Z`UFB81^L@```(/L!/]U +MX%/_=0C_51"#Q!"%P`^$%@$``&:+1?+!X`.#X#AF"81^L@```(/_`G4A9HM% +M\F;!Z`.(1B"$P'42ZPR)]F;'A'ZR````"@#&1B`/1X/_`@^.)/O__V:!/@(P +M=W:#[`2-1?)0:.P```#_=0C_51"#Q!"%P`^$L````&:+1?*#X`=FB8;0```` +M9HM%\F;!Z`.#X`=FB8;4````@^P$C47R4&CM````_W4(_U40@\00A&-`$```0`9L>&,@$` +M``$`9L>&,`$```$`9L>&+@$`````BT7LBU@4OP````!F@[[8`````'14C58* +MB57D@^P$C47R4%-#_W4(_U40@\00A7UW#C78`58GE5U93@^P0BWT(BW4,BUT04U97Z+KX__^#Q!"%P'0V +M@^P$4U97Z"#N__^#Q!"%P'0D@^P$4U97Z&[P__^#Q!"%P'02@^P$4U97Z!CS +M__^#Q!"%P'4)N`````#K#8GV@^P$4U97Z`7U__^-9?1;7E]=PY!5B>564XM= +M#+D`````OEP%``")]@^_T8T$4F8Y'$9U!(G0ZPQ!9H/Y%W;IN/____];7EW# +M58GE5E.+70RY`````+Y<````B?8/O]&)T,'@!68Y'#!U!HG0ZPZ)]D%F@_DG +M=N6X_____UM>7<-5B>575E.#[`R+=0B+10R+?1!FA____B<.#Q!") +M^(3`>1,/O\.-!$`/MX0`8`4``.L1C78`#[_#C01`#[>$`%X%``"-9?1;7E]= +MPXGV58GEBU4,N`4```"$TG@F]\(``0``=!FX`````/?"$`````^5P$B#X.R# +MP"CK!XGVN!0```!=PY!5B>6+50RX!P```(32>"+WP@`!``!T%;@`````]\(0 +M````#Y3`C43``NL&D+@`````7<.058GEBU4,N'('``"$TG@B]\(``0``=!6X +M-@<``/?"$````'4-N.P%``#K!I"X`````%W#D%6)Y5=64X/L%`^W70Q3_W4( +MZ+;___^)QH/$"%/_=0CH=/___XG'@\0,4XM5"`^W0A104NA\_O__B<&Z```` +M`(/$$#GZ?1N)]HT$4HT$@-'@9CD,!G4&C00PZPN00CGZ?.>X[`4``(UE]%M> +M7UW#B?95B>575E.#[!2+=0@/MUT,4U;H1?___XE%\(/$"%-6Z`3___^)QX/$ +M#%,/MT844%;H#_[__XG!N@````"#Q!`Y^GT>#[?9B?:-!%*-!("+=?!F.0Q& +M=06)V.L+D$(Y^GSGN`````"-9?1;7E]=PXGV58GE5E.+30BZ`````+M<```` +MOF0```"0B=#!X`5F.0P8=0F+1`80ZPZ-=@!"@_HG=N:X`````%M>7<.058GE +M5E.+30BZ`````+M<````OF@```"0B=#!X`5F.0P8=0F+1`80ZPZ-=@!"@_HG +M=N:X`````%M>7<.058GEBT4(BU4,#[<`#[<2*=!=PY!5B>575E.#[#2+72"+ +M=1B+11QFB47N#[?&4/]U".C\____B47H9L=%YE@;@\00A=MU#6:!_D@#=09F +MQT7F71;'1>``````O]0)``!F@SW4"0````^$.P$``(UV`&:+1>YF(P=FA<`/ +MA!L!```/MP>%1>@/A`\!``"-1?)0C47P4`^W1P)0_W4(BU4(_Y(X`0``@\00 +MA<`/A.L```"#[`@/MT<"4/]U".CH_?__B47(@\0(#[='`E#_=0CH-?W__V:) +M1=Z#Q`@/MT<"4/]U".@Q_O__9HE%W(/$$+D`````BUW(9H-[`@`/A)H```"# +MPPB)7"+=")1=B) +M]F8Y5?!W168[5?)W/V8[5>9W.8M%$#E%X'->BUW@BW4,9HD4GF:+1P)FB472 +M9HE$G@)F@WW6,'40]D<#`70*#0`"``!FB42>`O]%X&8#5=Z+7 +M=J5!BU7(#[="`CG!#X)M____@\<$9H,_``^%R/[__VA@'0``:@3_=>#_=0SH +M_/___XM%%(M=X(D8@\00N`````"%VP^5P(UE]%M>7UW#D%6)Y5=64X/L'(M% +M"&:#>!0`#X6+`0``@^P,4(G"_Y+,````9HE%[H/$$+@`````9H-][@!X(F:+ +M1>XE_P\``.L7C78`C00^C02`BTWDC01!Z6`!``"-=@!FB47N9H7`#X0]`0`` +MQT7H`````(M5Z(T$4HT$@F:+3>YF.0R%1`@```^%#@$``(U%\E"-1?!0BU4, +M#[="`E#_=0B+30C_D3@!``"#Q!"%P`^$]````(/L"(M5#`^W0@)0_W4(Z-O[ +M__^)1>2#Q`B+30P/MT$"4/]U".A9^___9HE%XH/$"(M5#`^W0@)0_W4(Z'K[ +M__^)1=R^`````(/$$#G&#XV4````C78`C00VB<(!\(T$@+L`````BTWD9H-\ +M00(`=&V)]HT$%HT$@(T46]'BBTWDC01!9HM,`@9F.TP""'")1=B+1>2-5%`(C78`9CE-\'<*9CM-\@^&W/[__V8#3>*+1=AF.PP0 +M=N-#C10VC006C02`BTWD#[=$00(YPWR51CMUW`^,;_____]%Z(-]Z`8/ALK^ +M__^#[`B+50P/MT("4/]U".@;^___C67T6UY?7<.-=@!5B>575E.#[!2+70Q3 +M_W4(Z"O^__^)P6:+&X/$$+H`````9H-Y`@!T28U!!HE%\(UY"`^W<0*)=>R- +M=@"-!%+1X(MU\&8Y'#!W(F8['#AW'`^V1`@+T>"*51`HPHC0#[[`B<+!ZA]* +M(=#K#)!".U7L?,JX`````(UE]%M>7UW#D%6)Y5=64X/L%(M=#%/_=0CHJ_W_ +M_XG!9HL;@\00N@````!F@WD"`'0UC4$&B47PC7D(#[=Q`HEU[(UV`(T$4M'@ +MBW7P9CD<,'<.9CL<.'<(#[9$"`KK#)!".U7L?-ZX!0```(UE]%M>7UW#D%6) +MY8/L$/]U#/]U".A#_?__#[9`!,G#D%6)Y593BT4(BW4,@^P,4/^0T````(G# +M@\00]\,"````=!:#[`P/M\90Z/KZ__^#Q!"%P'4#@^/]]\,(````=!:#[`P/ +MM\90Z*#Z__^#Q!"%P'4#@^/WB=B-9?A;7EW#D%6)Y5=64X'LN````(M%"&:) +MA63___]H3`(``.C\____B85@____@\00NP(```"%P`^$=`8``(N58/___XF5 +M7/___[X`"@``_+E.````B=?SI8N%9/___XN-8/___V:)001FQT$&``"+10R) +M00B+11")00R+112)01#'@3@!``!0*0``QX$\`0```````,>!_`$```````#' +M@2P"````````QX$P`@```````,>!-`(```````#'@3P"```*````QX%``@`` +M`@```&;'@4@"`````(/L"&H`4>C\____@\00NP,```"%P`^$O04``(N58/__ +M_\>"0`$```````"+C5S___^+01"+@"!```!F#[;`9HF"1`$``(M!$(N`&)@` +M`(F"2`$``(M!$,>`T)@``!8<``#'A5C___\`````C78`BY5<____BT(0QX"` +MF``````!`/^%6/___X.]6/___P-VWHM"$(N``)P``,'H'(/L"&H$4.C\____ +M0(N-8/___V:)@48!``"+A5S___^+4!"+@A!```")A5#___^#Q`R#R`&)@A!` +M``"-A6;___]0:CW_M5S____H_/___X/$$+L(````A<`/A,D$``"[!````&:! +MO6;___^E6@^%M00``(/L!(V%9O___U!J/_^U7/___^C\____@\00NP@```"% +MP`^$C@0``&:+A6;___^+E6#___]FB8).`0``@^P$C85F____4&C!````_[5< +M____Z/S___^#Q!"%P`^$500``&:+A6;___]FP>@,BXU@____9HF!3`$``+L% +M````9H/X`0^%+@0``+X`````QX58____`````(V=:/___X/L!(N56/___XT$ +M4U")T`7`````4/^U7/___^C\____@\00A<`/A.D#``"+C5C___\/MP1+,<9! +MB8U8____@_D_=KV[!P```('^__\```^%Q0,``(/L!(V%9O___U!HOP```/^U +M7/___^C\____@\00NP@```"%P`^$FP,``(J%9O___XN58/___XB"5`$``(N% +M;/___V:)@E`!``!FBX5N____9HF"4@$``(J%`0``BH5X____ +M@^`!B()9`0``BX5X____9M'H@^`'B():`0``QX58____`````,>%5/___PD` +M``"-O6C___^)]HN%6/___\'@`RN%6/___XN-6/___XT$@0.%8/___XV87P$` +M`(NU5/___]'F9HL4/F;!Z@J(D%\!``!FBP0^9L'H!(/@/XA#"XH$/L'@`H/@ +M/(U.`F:+%#EFP>H."="(0P&*1#D!@^`_B$,,9HL$.6;!Z`*#X#^(0P**!#G! +MX`2#X#"-3@1FBQ0Y9L'J#`G0B$,-9HL$.6;!Z`:#X#^(0P.*!#F#X#^(0PZ- +M5@9FBP0Z9L'H"HA#!&:+!#IFP>@$@^`_B$,/B@0ZP>`"@^`\C4X(9HL4.6;! +MZ@X)T(A#!8I$.0&#X#^(0Q!FBP0Y9L'H`H/@/XA#!HH$.<'@!(/@,(U."F:+ +M%#EFP>H,"="(0Q%FBP0Y9L'H!H/@/XA#!XH$.8/@/XA#$HU6#&:+!#IFP>@* +MB$,(9HL$.F;!Z`2#X#^(0Q.*!#K!X`*#X#R-3@YFBQ0Y9L'J#@G0B$,)BD0Y +M`8/@/XA#%&:+!#EFP>@"@^`_B$,*B@0YP>`$@^`PC4X09HL4.6;!Z@P)T(A# +M%6:+!#EFP>@&@^`_B$,6B@0Y@^`_B$,7C5829HL$.F;!Z`J(0QAFBP0Z9L'H +M!(/@/XA#&8H$.L'@`H/@/(/&%&:+%#YFP>H."="(0QJ*1#X!@^`_B$,;9HL$ +M/F;!Z`*#X#^(0QS_A5C___^#A53___\+@[U8____!`^&]OW__[X`````QX58 +M____`````(UV`(/L!(V%9O___U"X'P```"N%6/___U#_M5S____H_/___X/$ +M$(7`='@/MX5F____`<:+E5C____1XF8/MH5G____BXU@____B(01\`$``(J% +M9O___XB$$?$!``#_A5C___^#O5C___\"=I:%]G0(@?[]_P(`=0J["0```.LP +MC78`BY5<____BT(0BXU0____B8@00```BX5<____ZT^-=@"["````.L;D+L( +M````BY5<____BT(0BXU0____B8@00```@[U@____`'01@^P,_[5@____Z/S_ +M__^#Q!"#?1@`=`6+11B)&+@`````C67T6UY?7<-5B>6#[!3_=0CH_/___\G# +M58GE7<.-=@!5B>7V10T!=!>+11!FQP``%(M%%&;'`#85N`$```#K!;@````` +M7<.058GE5U93@^P$BUT(BWT,BW40BTT4B5WPBT,0B;`L@```@_\!=#Z+4Q") +M\"L%`````,'@`XF",(```(M3$(GP*P4`````P>`#B8(T@```BU,0BT7P`[`T +M`@``B;(X@```ZRF)]HM#$,>`,(```/____^+0Q#'@#2```#_____BT,0QX`X +M@````0```('A__\``(/_`70*@_\!<@WK$XUV`(')`````>L.@575E.#[`R+=0B+?0R[,@```.LJ +MB?:#[`QJ`>C\____@\002W48BT80B7@$BT80QT`H"@```+@`````ZQV0BU80 +MBT(LJ00```!URXM""*D"````=<&X`0```(UE]%M>7UW#58GEBU4(BT(0QX`L +M@````````(M*$(N!!(````T``!``)?__7_^)@02```"+0A#'@"2```#__P`` +M7<.058GE5U93@^P$BWT(BW4,B7WP@'X+`'1PBU<0BX($@```)?__?_\-```@ +M`(F"!(````^V7@L/MD8*#Z_8#[=&"`^OV(M'$(F8*(```(M7$`^W1@R)@DB` +M```/MD8*BTT8#Z_(`TT4#[=&"`^OR(7)=0*)V8M7$(M%$`'(P>`#B8(T@``` +MZQ:)]HM7$(N"!(```"7__U__B8($@```BU<0BP:)@BR```"+3Q"+@22````E +M``"`_P^W5@@)PF:#?A``=!(/MT80@\`$P>`0)0``?P`)PI")D22```"+1?!F +M@[A$`0```W8K=@;V1A0'=".+3Q"+D1B```"!XO_X__\/MT84P>`()0`'```) +MPHF1&(```(/$!%M>7UW#B?95B>6+10B+0!"+D`A```"X`````(72#Y7`7<.0 +M58GE4XM-#(M="(M#$(M0'(/Z_W4/QP$`````N`````#K.XGVB=`C@_@!```E +MNM@%`8D!]\(@`'``=`<-````0(D!]\(%````=`.#"0'WPD`!``!T`X,)0+@! +M````BQPDR<.)]E6)Y8M%"(N`^`$``%W#B?95B>575E.+70B+30R)WXNS^`$` +M`(7V>0J+0Q#'0"0`````B7UW#58GEN$````!= +MPXGV58GEBT4,9H/X/W<@#[?`P>`%BU4(`T(0BX`0FX`0```.L' +MB?:X`````%W#D%6)Y8M-"(M5#&:#^C\/AXT````/M\+!X`4#01#'@`"0```` +M````#[?"P>`%`T$0QX`$D`````````^WPL'@!0-!$,>`")`````````/M\+! +MX`4#01#'@!"0````````#[?"P>`%`T$0QX`4D`````````^WPL'@!0-!$,>` +M&)`````````/M\+!X`4#01#'@!R0````````N`$```#K!I"X`````%W#D%6) +MY5=64XM]"(M=$(MU#+@`````9H/^/W=QA=MT.@^V4P7!X@@/MD,$"<(/MDL# +MP>$8#[9#`L'@$`G!#[9#`<'@"`G!#[8#"<'1Z8G0P>`?"<'1ZNL,B?:Z```` +M`+D`````#[?&P>`%`T<0B8@8D```#[?&P>`%`T<0@0`````@WT8``^51>3_3>2! +M9>165555@6WD5E5556:#^#]V"[@`````Z5P!``"0N`````"#.P0/CDT!```/ +MMGL$#[9#!<'@"`G'#[9#!L'@$`G'#[9#!\'@&`G',WWD9@^V4PAF#[9#"<'@ +M"`G"#[?2BT7D,<*!XO__``")5>P/MG,*#[9#"\'@"`G&#[9##,'@$`G&#[9# +M#<'@&`G&,W7D9@^V4PYF#[9##\'@"`G"#[?2,U7D@>+__P``#[9+$`^V0Q'! +MX`@)P0^V0Q+!X!`)P0^V0Q/!X!@)P3--Y(,[#7\&@>'_````QT7H`````(,[ +M!7X8QT7H`````(,[#0^?1>B+7>B-7!L!B5WH#[=%\L'@!8M="`-#$(FX`)`` +M``^W1?+!X`4#0Q"+7>R)F`20```/MT7RP>`%BUT(`T,0B;`(D```#[=%\L'@ +M!0-#$(F0#)````^W1?+!X`4#0Q")B!"0```/MT7RP>`%`T,0BU7HB9`4D``` +M@^P$_W44#[=%\E!3Z/S___^-9?1;7E]=PY!5B>6+50B+30R+@O`!``")`6:+ +M@O0!``!FB4$$7<.)]E6)Y5.#[`2+70B+50R+0Q"+A)``8```:@)J`V@`;``` +M4^C\____@\00A53BUT(BTT,BT,0BY`00```A`("<(/MH<&`@``P>`0"<(/MH<'`@``P>`8"<*)D0B```"+3Q!F +M#[:3"`(``&8/MH,)`@``P>`("<(/M]*)\"7_/P``P>`0"<*)D0R```!FA?9T +M3(M'$(N0)(```&:#??(`=`P/MT7R@\`$ZPB-=@"X`````('B__^`_\'@$"4` +M`'\`"<*+1Q")D"2```"#[`1J`&H`5^C\____ZPR-=@"#[`Q7Z/S___^#Q!"- +M9?1;7E]=PU6)Y5.+10B+2!"+@7"```")PK@`````BXEL@```NP`````)R`G: +MBQPDR<.058GEBT4(BT`0BX!L@```7<.-=@!5B>6+10B+4!"+@B2````-```` +M`8F")(```%W#58GEBU4(BT(0BX!DF```B<'!Z1.!X?\!``#WP0`!``!T!H'Q +M`/[__XM2$(N"<(```(N2;(```#'0,6+30B+10R+41"+DIB````!$(M1 +M$(N2E(````%0!(M1$(N2G(````%0#(M1$(N2D(````%0"(M1$(N2H(````%0 +M$%W#B?95B>6X`0```%W#B?95B>6+10B+4!"+@FB```"#X.>)@FB```!=PXGV +M58GEBTT(BT$0BY!H@```9H.Y1`$```5W!X/*$.L%B?:#RAB+01")D&B```!= +MPXGV58GE4XM5"(G3BT(0QT`D`````(N+^`$``(')`$```(F+^`$``(M"$(E( +M((M"$,=`)`$```"+'"3)PXGV58GEN`````!=PXGV58GE7<.-=@!5B>5=PXUV +M`%6)Y5.#[`R+70AH+`(``&H`Z/S___^#Q`AH10(``&H`Z/S___^#Q`QJ/6A` +M"P``4^C\____BUW\R<.)]E6)Y593BW4(BTT,BUT0BU80BX($@```)?__?_\- +M```$`(F"!(```(7)=!&+5A`/M\,-```#`(F"!$```%M>7<-5B>564XMU"(-] +M#`!T7XM&$,>`!$````````"#[`QHT`<``.C\____NPH```"#Q!#K(HGV@^P, +M:,@```#H_/___X/$$(M&$,>`!$````````!+=!"+1A"+@!!```"I```!`'70 +MN`````"%VW09BU80BX($@```)?__>_^)@@2```"X`0```(UE^%M>7<.-=@!5 +MB>53BUT(BTT,BU,0BX($@```)?__?_\-```$`(F"!(```(7)=`V+0Q#'@`1` +M``````$`BQPDR<.-=@!5B>575E.#[`R+50B+70R+31"+112)UK\!````@_L" +M="N#^P)W"H/[`70-ZT.-=@"#^P-T*^LYD(/L!`^WP%!14NBN_O__@\00ZRV0 +M@^P(45+HWO[__XG'@\00ZQN-=@"#[`A14NA:____@\00ZPF0N`````#K"9") +MGOP!``")^(UE]%M>7UW#58GEBT4(BX#\`0``7<.)]E6)Y;@!````7<.)]E6) +MY;@`````7<.)]E6)Y8M%"(M0$(N"!(```"7__V__B8($@```N`$```!=PXUV +M`%6)Y8M%"(M0$(N"!(```"7__W__#0``$`")@@2```"X`0```%W#B?95B>53 +M@^P$BT4,@_@!=`V#^`)T$+@`````ZQR0NP````#K!I"[`````(/L"%/_=0CH +M_/___XG8BUW\R<-5B>6+10B+0!"+0`Q=PXGV58GEBT4(BU4,BT`0B5`,7<.- +M=@!5B>6+10B+0!#'0`@$````7<.)]E6)Y593BW4(BT80QT`((````+L````` +MD(M&$(M`"*D$````=0>X`0```.L;@^P,:@KH_/___X/$$$.!^^<#``!^UK@` +M````C67X6UY=PXGV58GEBT4(BU`0BX)H@```@^"_B8)H@```7<.)]E6)Y8M% +M"(M0$(N":(```(/(0(F":(```%W#B?95B>53BTT(BU4,BUT0BT$0B9!0@``` +MBT$0B9A4@```BQPDR<-5B>53BT4(BTT,@_D_=@FX`````.M#B?:#^1]V'XM0 +M$(N:5(```(/I(+C^____T\`AV(F"5(```.L:B?:+4!"+FE"```"X_O___]/` +M(=B)@E"```"X`0```(L<),G#B?95B>53BT4(BTT,@_D_=@FX`````.M#B?:# +M^1]V'XM0$(N:5(```(/I(+@!````T^`)V(F"5(```.L:B?:+0!"+F%"```"Z +M`0```-/B"=J)D%"```"X`0```(L<),G#B?95B>6+10B+0!"+@$R```!=PXUV +M`%6)Y8M%"(M5#/?"``(``'0)@>+__?__@\H@BT`0B9!,@```7<.-=@!5B>53 +MBUT0BT44BU4,QT((`````(G9@>'_#P``B4H,J2````!T"HG(#0`@``")0@S' +M0A0`````QT(0`````+@`````.5H,#Y3`BQPDR<.)]E6)Y593BUT,B=[V0Q0! +M=0RX#P```.GU````B?9FBT80)?\/``!FB4,@BTX4@>$`@/\/P>D/BT4(BT`0 +MBX!L@```B<+!Z@J!XO__``")T"7_'P``.@3B$,FBT84J0`!``!T#B4`?@``P>@)B$,GZP60QD,G_XM&$"4`@`<`P>@/ +MB$,HBT80P>@.@^`!B$,IBT80P>@,@^`!B$,JN`````!;7EW#D%6)Y5=64X/L +M#(MU"(M=#(GWN@P```"+11#V0`,!#X0%!0``BT80BX`00```@^!@B47P@^P( +M_W405NC\____@\00N@,```"%P`^$V@0``(M.$`^VE_`!```/MH?Q`0``P>`( +M"<(/MH?R`0``P>`0"<(/MH?S`0``P>`8"<*)D0"```"#^P$/A(4```"#^P%R +M3(/[!@^%MP```(M.$&8/MH?T`0``9@^VE_4!``#!X@@)T`^WP`T``%$`B8$$ +M@```BT80QT`H`````(M&$,>`$$```$`0``#I@0```)"+3A!F#[:']`$``&8/ +MMI?U`0``P>(("=`/M\`-``!2`(F!!(```(M&$,=`*`$```#K,HGVBTX09@^V +MA_0!``!F#[:7]0$``,'B"`G0#[?`#0``%`")@02```"+1A#'0"@`````BT80 +MQX`00```)!```.L-D+H,````Z`("<(/MH<&`@``P>`0"<(/MH<'`@``P>`8"<*) +MD0B```"+3A!F#[:7"`(``&8/MH<)`@``P>`("<(/M]*)D0R```"+1A#'```` +M``"+1A#'0`0`````BT80QT`,`````(M&$(M0',=`(`````"+1A#'0"0````` +MQX?X`0```````(M&$(M0+,=`,`4```"+1A#'0#0%````BT80QT!$"````(M& +M$,=`2`@```"+1A#'0%``````BT80QT!,`````(M&$,>`#$````````"+1A#' +M0$``````BT80QX`8@`````<``(M&$,>`2(````````"#[`AJ`%;H_/___X/$ +M$(M&$,>`4(````````"+1A#'@%2`````````BT80QX!8@````````(M&$,>` +M7(````````"+1A#'@&"````!````BT80QX!D@````0```(M&$,>`:(`````` +M``"+1A#'@"B`````````BT80QX`L@````````(M&$,>`;(````````"+1A#' +M@#"```#_____BT80QX`T@```_____XM&$,>`.(````$```"+5A"X`````(E" +M%+L`````BPS=*`T``(-]%`!T#8V!`(#__SW_#P``=@V+5A"+!-TL#0``B001 +M0X'[I@```';0@^P(_W405NC\____@\00N@,```"%P`^$I`$``(M.$(N1*)@` +M`##V#[:'5@$``,'@"`G"B9$HF```BUX0#[:75P$``(G0P>`8P>(0"=`/MH]8 +M`0``B)_P/__9HN'4`$``&;1Z"6` +M/P``"<*)D428``"+3A"+D4B8``"!XO\/_/\/MX=0`0``P>`*)0#P`P`)PHF1 +M2)@``(M.$(N19)@``('B_P_X_P^VAU4!``#!X`PE`/`'``G"B9%DF```BTX0 +MBY$0F0``@^+\9HN'4`$``(/@`P^WP`G"B9$0F0``@^P(_W405NCZ"P``@\00 +MN@,```"%P`^$K@```(M&$,>`')@```$```"#[`QHZ`,``.C\____@\00BU80 +MBX)@F```@\@!B8)@F```:@!J`6A@F```5NC\____@\0(_W405NC\____@\00 +MA7UW#D%6)Y5.+30B+50R+61"+ +M@P2````E__\``(/Z`70G@_H!53@^P$BUT(:@!J`6H"4^C\____@\00 +MA7UW#D%6) +MY5=64X/L&(M]"(MU#(M5$(GSN`````"%VP^5P$@)PXM'$(FP`$```%+H_/__ +M_X/F#X/C#U93:`!```!7Z/S___^-9?1;7E]=PY!5B>564X/L!(M=#(I%$(A% +M][D`````N@H````/ML"-<`&-=@"-1!(#.$7W=0N`/!H_=%GK>8UV`(U$$@,/ +MML`YQG51A=)^38`\&C]T/XU*_X`\&3]T-@^V-!H/M@P9*H&C301B?(/ML+K,[D!````ZPR0@_D! +M=0:`/!H_=0]*>8*Z`````)"`/!H_=`8/M@0:ZPM"@_H*?NZX`0```(/$!%M> +M7<.)]E6)Y5=64X/L$(M=#(I5$+[_____B?>Y`````(U#"XE%\(UV`(`\&3]T +M+CH4&719.A09=@*)SCH4&7,=B<^#_O]U'(U$/P.+512(`HM-\`^V!`_IH@`` +M`)!!@_D*?L:#^0I^#K@_````@_[_#X2(````@_D*?B*-1#8#BU44B`(/MD0> +M"^MSB?:-1`D#BU44B`(/MD09"^MAC40W`XM-%(@!#[;2#[8,'BG*B57HB="- +M%("-%)*-%)+!X@.)5>0/M@0?*0%YP,``(E%Z+K336(0]^+!Z@:(T`($'@^VP(/$$%M>7UW#C78`58GE5U93 +M@^P(1P^+3>B*@5(!``"#X`>( +M1Q!FBP(M,A0``&8]E@!V#;@`````Z9<"``"-=@"^`````(M=Z(J#5`$``#J# +M6P$``'0>B=F#P0N01H/^`W<2BUWHBH-4`0``.H0Q4`$``'7HN`````"#_@0/ +MA%("```/MPJ!Z3(4``"Z9V9F9HG(]^K!^@*)R,'X'XG1*<&#^0MV`4FZJZJJ +MJHG(]^*)T='IC03-`````"G(C02!BU7HC9P07P$``(U.$(U3"8H$$8A'#HI# +M%CH$$78#B@01B$<)C4X0C5,)BD,7.@01=@.*!!&(1PB-3A"-4PF*0Q@Z!!%V +M`XH$$8A'!XU%\U`/MD0>&5!3_W4(Z,[]__^)QHU%\E`/MD<)4%/_=0CHNOW_ +M_XA%YX/$((U%\5`/MD<(4%/_=0CHHOW__XA%YHU%\%`/MD<'4%/_=0CHC?W_ +M_XC"@\0@BTWH9H.Y2`(````/A!@!```/MX%(`@``@_@"=".#^`)_"H/X`701 +MZRN-=@"#^`-T%X/X!'0:ZQR`;?,#ZQ:)]H!M\P;K#HGV@&WS">L&B?;&1?,# +M@^P$#[9%\U!3_W4(Z%O\__^(1PZ-1>]0#[9'#E!3_W4(Z`[]__^)QHI%\X/$ +M(#I%\G8#BD7RB$7R@^P$#[;`4%/_=0CH(_S__XA'"8U%[U`/MD<)4%/_=0CH +MUOS__XA%YXI%\X/$(#I%\78#BD7QB$7Q@^P$#[;`4%/_=0CHZOO__XA'"(U% +M[U`/MD<(4%/_=0CHG?S__XA%YHI%\X/$(#I%\'8#BD7PB$7P@^P$#[;`4%/_ +M=0CHL?O__XA'!XU%[U`/MD<'4%/_=0CH9/S__XC"@\0@#[9%\XM=Z(F#1`(` +M`(I'#HA'"HA'"XA'#(A'#8GP*-"(!XGP*D7FB$>(1P+&1P8`QD<% +M`,9'!`#&1P,`N`$```"-9?1;7E]=PU6)Y5=64X/$@(M5#(V]>/___[Z``P`` +M_+D1````\Z6^8!(``(U]R+D$````\Z6DC47(4%+_=0CHV/S__X/$$(7`=!B* +M1==(/`1W$(I%V$B^`````(U]R#P$=@VX`````.DA`@``C78`@^P(:@4/M]X/ +MM@0[4.C\____B`0[@\001F:#_@9VX;X'````C7W(D(/L"&H&#[?>#[8$.U#H +M_/___X@$.X/$$$9F@_X.=N$/MD7)P>`%)>````"*5/__ +M_P^V5!XH`````/MD7*P>`"@^!\"<**1(#@>+X````BD7.P.@"@^`'"<()58@/ +MME71P>('@>*`````#[9%T-'@@^!^"<**1<_`Z`6#X`$)P@E5C`^V5=+!X@6! +MXN````"*1='0Z(/@'PG""560#[95T\'B`X'B^````(I%TL#H`X/@!PG""564 +M#[95U-'B@^)^BD73P.@%@^`!"<()59@/MD75P>`%)>`````)19P/ME76P>(# +M@>+X````BD75P.@#@^`'"<()5:"*1=;`Z`6#X`$)1:2#[`AJ`P^V1==0Z/S_ +M___!X``"@^`<"4653BUT,BU4(@_L!=!&#^P%R%(/[`W6+10R+50B#^`%W#\'@!(V$$`P"``"#.`!U![@` +M````ZPO'``````"X`0```%W#C78`58GE5U93BUT(BT4,B=Z-DP`"``"#^`%V +M"[@`````Z<\!``"0P>`$C;PP#`(``+@`````@S\`#X2V`0``N`$```"#/P$/ +MA:@!``"#OBP"````=13'AD`"```"````QX8X`@``#P```(N&0`(``(G!`T\$ +M]D("$'1XBT,0QX`0@```X`$``(M#$,>`%(`````(``B+0Q#'@""```#/C]T! +MBU,0C01)C02`P>`0C8````\`#>`!``")@D"```"+0Q#'@$2```#``ZX%BU,0 +MBX)$F```@^"`@\@XB8)$F```BT,0QX`$F```(R``;^MZC78`BT,0QX`0@``` +M:`$``(M#$,>`%(`````$``2+0Q#'@""```"GC]T!BU,0C02)C01!C02!C03% +M,`(``,'@"PTP`@``B8)`@```BT,0QX!$@```F`/7!(M3$(N"1)@``(/@@(/( +M'(F"1)@``(M#$,>`!)@``"`0`&^Z`0```#N6.`(``',4BXXX`@``B?:-!!*) +MPH/*`3G*0J+3PCWV=/JZPR0BD\(C4(!B<+3XDJ#OC`"````=!2+ +MACP"``"#^`]V!;@/````B<;K"K@*````O@H```"+2Q#!XA3!X`0E\`````G" +MB?"#X`\)PH'*`"`(`(F1'(```+@!````6UY?7<.058GEBTT(BT4,B6+30B+10R)RH/X`78(N`````#K5)#! +MX`2+A!`,`@``@_@!=!&#^`%RY(/X`G0K@_@#=`[KV(M!$,=`"`$```#K(HM! +M$,=`"`(```"+01#'0"@.````ZPR)]HM!$,=`*`H```"X`0```%W#C78`58GE +MBTT(BT4,B```==V+1A#'0`@`````N`````"! +M^^<#```/GL#K&(UV`&H`:@1J+%;H_/___^L'B?:X`````(UE^%M>7<-5B>6X +M`````%W#B?95B>575E.+11B+=2B+?3"+30R#?20`=0RX`````.F9````B?:# +M^`)V#X/X!'?JNP````SK"(UV`(G#P>,:BT40)?\/``"+52#!XA()T(M5%,'B +M#('B`/`#``G0"=CWQP$```!T!0T````!B<*#?2P`=`:!R@````*)40B#_O]T +M'(GPP>`-)0#@!P")00R)T`T```!`B4$(ZPJ-=@#'00P`````]\<$````=`N+ +M13@E``#X_PE!#+@!````6UY?7<-5B>6X`0```%W#B?95B>6+11"+50R)P8'A +M_P\``#G!=`>X`````.M"@WT4`'0&"4H,ZPN0QT((`````(E*#(-]&`!T#(%B +M#/_O___K"HUV`(%*#``0``#'0A0`````QT(0`````+@!````7<-5B>6+30R) +MRO9!%`%U"K@/````Z8,```!FBT(4)?X?``!FB4$@#[="$F:)02+&020`BT(0 +MJ0$```!U'ZD"````=`3&020!]D(0"'0$@$DD`O9"$`1T!(!))`2+0@@E```\ +M`,'H$HA!)8M"%"4`X!\`P>@-B$$FBT(0)?````#!Z`2(02>+0A`E``\``,'H +M"(A!*,9!*@"X`````%W#C78`58GE@^P(BTT(BT$0QX#0F```%AP``+H````` +MD(M!$,>`@)@``````0!"@_H'?NV+01"+@`"<``#!Z!B)PL'J!(/@#\'@!`G0 +M@^P(:@A0Z/S____)PXUV`%6)Y5=64X/L.(M%"&:)1>IHN`L``.C\____B<.# +MQ!"%VW4-QT7L`@```.F@!```D(E=Y+Z`$@``_+E.````B=_SI6:+5>IFB5,$ +M9L=#!@``BT4,B4,(BT40B4,,BT44B4,0QX,X`0``B%D``,>#/`$```````#' +M@X0+````````QX.8"P```````,>#<`L```````#'@YP+```*````QX-L"P`` +M`````,>#H`L```H```#'@X`+```"````QX.0"P```````(/L"&H`4^C\____ +M@\00A`0;\74MBT`0QX``H@```````(M5 +MY(M"$,>`?)@``!D```"#[`QHZ`,``.C\____@\00BU7DBT(0BX`@0```#[;0 +MB=#!Z`2)@T`!``"#X@]FB9-$`0``@^@"@_@"#X>@`@``BU7DBT(0BX`8F``` +MB8-,`0``@^P,4NBE`P``@\00A``)@``$<```"#[`QHT`<``.C\ +M____@\0$_W7DZ.C]__]FB8-&`0``)?````"#Q!!F@_@0#X43`@``@^P$C47R +M4&C!````_W7DZ/S___^#Q!"%P`^$T`(``&:!??+_+W<,QT7L!0```.G#`@`` +M9HM%\F:)@U`!``"+5>2+0A"+@!!```")PH/B&,'J`X/Z`G0,QT7L"@```.F3 +M`@``@^P$C47R4&H__W7DZ/S___^#Q!"%P`^$<`(``&:+1?)FB8-2`0``QT7@ +M`````+X`````C7WRB?:#[`17C8;`````4/]UY.C\____@\00A<`/A#8"```/ +MMT7R,47@1H'^/P,``';2@7W@__\``'0-QT7L!P```.D8`@``D&;'@YH"```* +M`&;'@Z0$```#`+X`````C5,2B?:-!':-!(9FQX2"D`(```L`1H/^"7;JO@`` +M``"-0PR)1=R_N!,``(U3!HE5V(U#%(E%U(GVC10VB570B=&!P:`$``!FBP0Z +MBU7<9HD$$8M%T&:+!#B+5=AFB001BT70`?"-!(;!X`*+5=1FQX0"0`4```L` +M9L>$&+@$```+`$:#_@)VL8/L!&@`````C8-0`0``4/]UY.C\____@\00A<`/ +MA$\!``"#NT`!```#=G9F@[MH`0```'1LBU7DBT(0QX``F```!T```(/L#&C0 +M!P``Z/S___^#Q`3_=>3H]/O__V:)@T@!``"+5>2+0A#'@`"8```'````QP0D +MT`<``.C\____9HN#2`$``"7P````@\009H/X('05QT7L#0```.G7````9L># +M:`$`````@^P$C47R4&B_````_W7DZ/S___^#Q!"%P`^$J````&:+1?)FB8-4 +M`0``9H/X`744@^P$C47L4&H0_W7DZ/S___^#Q!"#[`S_=>3H_/___\=%X``` +M``"^`````(/$$(U[!(GV@^P$C47R4+@?````*?!0_W7DZ/S___^#Q!"%P'1& +M#[=%\@%%X(T4-F8/MD7SB(07L`H``(I%\HB$%[$*``!&@_X"=KR#?>``=`F! +M?>#]_P(`=0G'1>P)````ZP^+1>3K+8UV`,=%[`@```"%VW0,@^P,4^C\____ +M@\00@WT8`'0(BT7LBU48B0*X`````(UE]%M>7UW#B?95B>6#[!3_=0CH_/__ +M_\G#58GE5U93@^P\BUT(QT70`(```,=%U""8``"-?=B^Q`,``/RY!````/.E +MQT7$`````(U%T(E%P(U5R(E5O(UV`(M%Q,'@`HM-P(LT"(M3$(L4%HM-O(D4 +M"+D`````C78`BBT7$ +MP>`"BTL0BW7`BQ0PBW6\BP0PB00*_T7$@WW$`0^.;?___X/L#&IDZ/S___^X +M`0```(UE]%M>7UW#B?95B>5=PXUV`%6)Y8M5$(M-%(M%#*D``0``=!%FQP(` +M%&;'`=07N`$```#K*83`>2"+10AF@[AH`0```'039L<";`EFQP&L"K@!```` +MZP>)]K@`````7<.058GE5U93BUT(BW40BTT4B=^+0Q")L"B```"#?0P&=$R+ +M4Q")\"L%`````,'@`XF"+(```(M3$(GP*P4`````P>`#B8(P@```BU,0@[]L +M"P```'0,B?`#AVP+``#K!8GVC48!B8(T@```ZRB0BT,0QX`L@```_____XM# +M$,>`,(```/____^+0Q#'@#2````!````@>'__P``@WT,`701@WT,`7(3@WT, +M!G05ZQF-=@"!R0````'K#H')``"``.L&@564XMU"+L`````ZP^0@^P,:@KH_/___X/$$$.!^^<#``!_$H/L"&H"5NC\ +M____@\00A` +M*(````````"+2A"+@02````-```$`"7__\__B8$$@```BT(0QX`@@```__\` +M`%W#D%6)Y593BW4(BUT,@'L+`'1?BU80BX($@```#0``$`")@@2````/MD,+ +M#[93"@^OP@^W4P@/K\*+5A")@B2```"+5A`/MT,,B8(X@```#[9#"@^O11@# +M110/MU,(#Z_"BU80`T40P>`#B8(P@```ZQ2+5A"+@@2````E___O_XF"!(`` +M`(M6$(L#B8(H@```BTX0BX$@@```)0``@/\/MU,("<)F@WL0`'02#[=#$(/` +M!,'@$"4``'\`"<*0B9$@@```BTX0BY$8@```,/8/MT,4P>`()0#_```)PHF1 +M&(```(M.$(N1!$```('B``#__P^W0Q*-!,7H____)?__```)PHF1!$```%M> +M7<-5B>6+10B+0!"+D`A```"X`````(72#Y7`7<.058GEBT4(BTT,BT`0BY#` +M````@_K_=0W'`0````"X`````.M!B=`ENM@%`8D!]\(```@`=`<-````0(D! +M]\(%````=`.#"0'WPD`!``!T`X,)0/?"(````'0&@0D```!`N`$```!=PY!5 +MB>6+10B+@,`*``!=PXGV58GE5U93BUT(BTT,B=^+L\`*``"%]GD0BT,0QT`D +M`````(M#$(M`)(G*@>*ZV`4!]\%`````=`:!RL`!``#WP0$```!T`X/*!_?! +M````0'0&@ +M7UW#D%6)Y;B`````7<.)]E6)Y8M%#&:#^']W(`^WP,'@!8M5"`-"$(N`'(@` +M`&:%P'D)N`$```#K!XGVN`````!=PY!5B>6+30B+50QF@_I_#X>-````#[?" +MP>`%`T$0QX``B`````````^WPL'@!0-!$,>`!(@````````/M\+!X`4#01#' +M@`B(````````#[?"P>`%`T$0QX`0B`````````^WPL'@!0-!$,>`%(@````` +M```/M\+!X`4#01#'@!B(````````#[?"P>`%`T$0QX`575E.+?0B+71"+=0RX`````&:#_G]W<87;=#H/ME,% +MP>((#[9#!`G"#[9+`\'A&`^V0P+!X!`)P0^V0P'!X`@)P0^V`PG!T>F)T,'@ +M'PG!T>KK#(GVN@````"Y``````^WQL'@!0-'$(F(&(@```^WQL'@!0-'$('* +M`(```(F0'(@``+@!````6UY?7<-5B>575E.#[!R+71"+10QFB47RQT7D```` +M`(-]&``/E47D_TWD@67D5E5558%MY%95555F@_A_=@NX`````.E<`0``D+@` +M````@SL$#XY-`0``#[9[!`^V0P7!X`@)QP^V0P;!X!`)QP^V0P?!X!@)QS-] +MY&8/ME,(9@^V0PG!X`@)P@^WTHM%Y#'"@>+__P``B57L#[9S"@^V0PO!X`@) +MQ@^V0PS!X!`)Q@^V0PW!X!@)QC-UY&8/ME,.9@^V0P_!X`@)P@^WTC-5Y('B +M__\```^V2Q`/MD,1P>`("<$/MD,2P>`0"<$/MD,3P>`8"<$S3>2#.PU_!H'A +M_P```,=%Z`````"#.P5^&,=%Z`````"#.PT/GT7HBUWHC5P;`8E=Z`^W1?+! +MX`6+70@#0Q")N`"(```/MT7RP>`%`T,0BUWLB9@$B```#[=%\L'@!8M="`-# +M$(FP"(@```^W1?+!X`4#0Q")D`R(```/MT7RP>`%`T,0B8@0B```#[=%\L'@ +M!0-#$(M5Z(F0%(@``(/L!/]U%`^W1?)04^C\____C67T6UY?7<.058GEBU4( +MBTT,BX*T"@``B0%FBX*X"@``9HE!!%W#B?95B>53@^P$BUT(BU4,BT,0B9`` +M8```BT,0QX`(8````0```&H":@-H#&```%/H_/___X/$$(7`=0>X`````.L4 +MBT,0BY`$8```BT409HD0N`$```"+7?S)PXUV`%6)Y5.#[`2+30B+70R+51"+ +M01")F`!@``"+01`/M]*)D`1@``"+01#'@`A@```"````:@AJ#&@,8```4>C\ +M____B<*#Q!"X`````(72#Y7`BUW\R<.-=@!5B>53BUT0BT4,BTT(N@P```!F +M.8%4`0``=!:Z`````("Y4@$````/F<*-%-4#````A=MT`HD3N`````"+'"3) +MPXUV`%6)Y8M%"`^W@%0!``!=PY!5B>6+50BX`````&:#NF8!````=`]F@[I6 +M`0````^4P(U$``%F@[IH`0```'0#@\@$7<.058GE4X/L!(M="&:#NUH!```` +M=%2#[`2-1?I0:@]3Z/S___^#Q!"%P'4*N`````#K98UV`&:+1?J#X!QFP>@" +M#[?`B8.H"P``9HM%^H/@`F;1Z`^WP(F#K`L``,>#M`L```$```#K'Y#'@ZP+ +M````````QX.H"P```````,>#M`L```````"X`````&:#NUH!````#Y7`BUW\ +MR<.058GE5E.+70B)WH/L"&H`4^C\____B<&#Q`RX`````(7)#Y3`4&H`4^C\ +M____@\0(_[.H"P``4^C\____BU,0BXH`F```@\0(B<@E_]___XF"`)@``/^V +MJ`L``%/H_/___XF&L`L``(/$#+H`````.X:L"P``#Y7"4O^VJ`L``%/H_/__ +M_XUE^%M>7<-5B>53BT4(BTT,BU@0BY,40```T>&X`P```-/@]]`APK@"```` +MT^`)PHF3%$```+@!````BQPDR<.-=@!5B>53BT4(BTT,BU@0BY,40```T>&X +M`P```-/@]]`APHF3%$```+@!````BQPDR<-5B>53BT4(BTT,BU@0BY,80``` +MN/[____3P"'"BT40@^`!T^`)PHF3&$```+@!````BQPDR<.)]E6)Y8M-#(/Y +M!7<9BT4(BT`0BX`<0```@^`OT^B#X`'K"(UV`+C_____7<.058GE@^P(BTT( +MBT$0BY`40```@>+\?_[_@C\____R<.)]E6)Y8M%"(M($(N!$$```"6?__'_BU4, +M@^('"P25P!,``(F!$$```%W#C78`58GE5U93@^P$BWT(BU4,BW40BT449HE% +M\HG[BP*)A[H*``!FBT($9HF'O@H``(M/$`^VE[H*```/MH>["@``P>`("<(/ +MMH>\"@``P>`0"<(/MH>]"@``P>`8"<*)D0B```"+3Q!F#[:3O`H``&8/MH.] +M"@``P>`("<(/M]*)\"7_/P``P>`0"<*)D0R```!FA?9T.HM'$(N0((```&:# +M??(`=`P/MT7R@\`$ZPB-=@"X`````('B__^`_\'@$"4``'\`"<*+1Q")D""` +M``"#Q`1;7E]=PXGV58GE4XM%"(M($(N!4(```(G"N`````"+B4R```"[```` +M``G("=J+'"3)PY!5B>6+10B+0!"+@$R```!=PXUV`%6)Y8M%"(M0$(N"((`` +M``T````!B8(@@```7<-5B>6+50B+0A"+@&28``")P<'I$X'A_P$``/?!``$` +M`'0&@?$`_O__BU(0BX)0@```BY),@```,=`QR%W#C78`58GE4XM5"(M"$(N` +M($```"7_````B<�^[`````,'H!#F"0`$``'4.9CF*1`$``'4%NP$```") +MV(L<),G#D%6)Y8M-"(M%#(M1$(N2D(````$0BU$0BY*,@````5`$BU$0BY*4 +M@````5`,BU$0BY*(@````5`(BU$0BY*8@````5`07<.)]E6)Y;@`````7<.) +M]E6)Y8/L$(M%"(M0$,>"5)D```$```"+D,`*``"!R@!```!24.C\____R<.0 +M58GEN`````!=PXGV58GE7<.-=@!5B>5=PXUV`%6)Y8M%"(M`$(N`')P``"7_ +M````7<.)]E6)Y8M%"(M`$(N`6(```(/@!UW#58GEBT4(BU`0BT4,@^`'B8)8 +M@```7<.058GE5U93@^P$BWT,BT40BU4(B57P9HM``B7@`0``#[?`/<````!T +M,#W`````?PT]H````'0:Z;(```"0/4`!```/A:8```"X`````.L/B?:X`0`` +M`.L&D+@"````C0P`BU7P@\(*#[>T"K8!```/MX0*O`$``,'@!@G&#[>$"L(! +M``#!X`P)Q@^WA`K(`0``P>`2"<8/MX0*S@$``,'@&`G&#[><"M0!```/MX0* +MV@$``,'@!@G##[>$"N`!``#!X`P)PP^WA`KF`0``P>`2"<,/MX0*[`$``,'@ +M&`G#@_\!=!&#_P%R$H/_`G0+N`````#K*8GSZP*)WHM%\(FX<`L``(M5"(M" +M$(FP8)D``(M"$(F89)D``+@!````@\0$6UY?7<.-=@!5B>575E.#[!1HU0,` +M`&H`Z/S___^#Q`AH[@,``&H`Z/S___^#Q`QJ.FC@$P``_W4(Z/S___^+50B+ +M0A"+@+0```!0BT(0BX"P````4(M"$(N`K````%"+0A"+@*@```!0BT(0BX"D +M````4(M"$(N`H````%!H0`$``&H`Z/S___^+30B+01"+D,````"#Q#"+@-0` +M``!0BT$0BX#0````4(M!$(N`S````%"+01"+@,@```!0BT$0BX#$````4%)H +M@`$``&H`Z/S___^#Q!AH[@,``&H`Z/S___^+50B+0A"+@$`*``!0:/`#``"+ +M0A"+@(`(``!0:/P#``"+0A"+@$`(``!0:`($``!HP`$``&H`Z/S___^#Q#"+ +M30B+01"+@(`)``!0BT$0BX!`"0``4&@``@``:@#H_/___[L`````@\00C78` +MC12=`````(M-"(M!$(N$`@`*``!0BT$0BX0"P`D``%"+01"+A`(`"0``4(M! +M$(N$`L`(``!0BT$0BX0"``@``%!3:$`"``!J`.C\____@\0@0X/["7ZI@^P( +M:.X#``!J`.C\____NP````"#Q!")]H/L#(T4G0````"+30B+01"+A`)`$0`` +M4(M!$(N$`@`1``!0BT$0BX0"P!```%"+01"+A`*`$```4(M!$(N$`D`0``!0 +MBT$0BX0"`!```%!3:(`"``!J`.C\____@\0P0X/["7Z;NP````")]HG:P>(( +MBT4(BT@0BX0*.!```(E%\(G0@\A`B[P(.!```(G0#8````"+M`@X$```@7<-5 +MB>564XMU"(-]#`!T6XM&$,>`!$````````"#[`QJ"NC\____NPH```"#Q!#K +M(9"#[`QHR````.C\____@\00BT80QX`$0````````$MT$(M&$(N`$$```*D` +M``$`=="X`````(7;=!F+5A"+@@2````E___[_XF"!(```+@!````C67X6UY= +MPXUV`%6)Y5.+70B+30R+4Q"+@@2````-```$`(F"!(```(7)=`V+0Q#'@`1` +M``````$`BQPDR<-5B>564XMU"(M-#(M=$(M6$(N"!(````T```0`B8($@``` +MA575E.#[`R+30B+70R+51"+ +M112)SK\!````@_L"="^#^P)W"H/[`701ZUN-=@"#^P-T+X/[!'0ZZTR#[`0/ +MM\!04E'H>O[__X/$$.M!D(/L"%)1Z*K^__^)QX/$$.LOC78`@^P(4E'H(O__ +M_X/$$.L=D(/L!`^WP%!24>A"____@\00ZPF0N`````#K"9")GF@+``")^(UE +M]%M>7UW#58GEBT4(BX!H"P``7<.)]E6)Y;@`````7<.)]E6)Y;@`````7<.) +M]E6)Y;@`````7<.)]E6)Y;@`````7<.)]E6)Y5.#[`2+10R#^`)T)8/X`G<( +M@_@!=`OK(9"#^`1T"^L9D+L`````ZQF0NP````#K$9"[`````.L)D+@````` +MZP^0@^P(4_]U".C\____B=B+7?S)PY!5B>6+10B+0!"+0`Q=PXGV58GEBT4( +MBU4,BT`0B5`,7<.-=@!5B>6+10B+0!#'0`@$````7<.)]E6)Y8/L"(M5"(M" +M$,=`""````!J`&H$:@A2Z/S___^)PH/$$+@`````A=(/E<#)PU6)Y8M%"(M0 +M$(N"2(```(/@WXF"2(```%W#B?95B>6+10B+4!"+@DB```"#R"")@DB```!= +MPXGV58GE4XM-"(M5#(M=$(M!$(F00(```(M!$(F81(```(L<),G#58GE4XM% +M"(M-#(/Y/W8)N`````#K0XGV@_D?=A^+4!"+FD2```"#Z2"X_O___]/`(=B) +M@D2```#K&HGVBU`0BYI`@```N/[____3P"'8B8)`@```N`$```"+'"3)PXGV +M58GE4XM%"(M-#(/Y/W8)N`````#K0XGV@_D?=A^+4!"+FD2```"#Z2"X`0`` +M`-/@"=B)@D2```#K&HGVBT`0BYA`@```N@$```#3X@G:B9!`@```N`$```"+ +M'"3)PXGV58GEBT4(BT`0BX`\@```7<.-=@!5B>6+10B+50R+0!")D#R```!= +MPU6)Y5.+71"+112+50S'0@@`````B=F!X?\/``")2@RI(````'0*B<@-`"`` +M`(E"#,="%`````#'0A``````N``````Y6@P/E,"+'"3)PXGV58GEBTT,B@/9HE!(L9! +M)`"+0A2I`@```'4LJ00```!T!\9!)`'K'Y#V0A00=`:`220(ZQ*`220"BT(4 +M)>````#!Z`6(026+0A`E``#X!\'H$XA!)HM"%*D``0``=`XE`'X``,'H"8A! +M)^L%D,9!)_^+0A`E`(`'`,'H#XA!*(M"$"4````XP>@;B$$IBT(0P>@,@^`! +MB$$JN`````!=PY!5B>575E.#[%R+10B)1;1FQT6J``!FQT6H``#'1:0````` +MQT6@`````(M-$&:+40*)T&;!Z`>#X`'WP@`!``!T!X7`ZQF-=@"+71!FBT," +M9L'H!P^WP(/P`:D!````#X6\!```BT409HM0`HG09L'H!H/@`??"(````'0$ +MA<#K%HM5$&:+0@)FP>@&#[?`@_`!J0$````/A80$``"#?10`=%F+70B+2Q"+ +M@4R```")1:2+@5"```")1:"+5;2#ND`!```#=@Z+@4`1``")1;CK*HUV`+L` +M````C76XBT4(BT@0B?:-%)T`````BX0*0!$``(D$,D.#^PEVZ8M5"(M"$(N` +M6(```(E%G(7`=0?'19P!````BTT(BU$0BX($@```)0````*)1:R+@A!````E +M8`#^`(E%L(/L"(M=$`^W0P)04>C\____@\00N@,```"%P`^$``<``(M5$&:+ +M0@(E\`$```^WP#W`````=$H]P````'\+/:````!T-.M&B?8]0`$``'0)/5`! +M``!T$NLT9L=%J@$`9L=%J`$`ZR:)]F;'1:H"`&;'1:@!`.L6B?9FQT6J`P#K +M!F;'1:H$`&;'1:@"`(M-M(.Y0`$```-V%(M="(M#$,>``)@```<```#K$HGV +MBU4(BT(0QX``F```1P```(M-M(.Y0`$```,/AN(```"+71"`>P(`#XFL```` +M9H&Y4`$````P#X:=````]D,"('06#[>Y(`(```^W@20"``")19CK%XUV`(M5 +MM`^WNB("```/MXHF`@``B4V8@^P(:@-7Z/S___^)QX/$"&H#_W68Z/S___^) +M19@/MTVHP>$"C9DL`0``OJ`'``"+%#.!XC____^)^,'@!B7`````"<*)%#.! +MP3@!``"+'#&#X_")^L'J`H/B`8M%F-'@@^`."<()TXD<,8/$$+L`````OJ`' +M```/MWVHD(T$6XM5"(M*$(L4A@'XBP2&B00*0X/[&W;F@^P(_W40_W4(Z&`, +M``"[`````(/$$+[`%0``#[=]JHUV`(T$FXM5"(M*$(L4A@'XBP2&B00*0X/[ +M(G;FNP````"^U!T```^W?:B-!%N+50B+2A"+%(8!^(L$AHD$"D.#^S]VYKL` +M````OGP8``"+#-Z#?10`=`V-@0"`__\]_P\``'8-BT4(BU`0BT3>!(D$$4.! +M^ZH```!VU(M5M(.Z0`$```-W3(M-"(M1$(N*'(```(G()?__#P`-``#0`8F" +M'(```(M="(M#$,=`7`````"+0Q#'@'B8```(````BU,0BX)(@```#0`$``") +M@DB```"#?10`=%^+50B+0A"+3:2)B$R```"+0A"+7:")F%"```"+1;2#N$`! +M```#=A.+30B+41"+1;B)@D`1``#K)XGVNP````"-=;B-!)T`````BU4(BTH0 +MBQ0PB90(0!$``$.#^PEVXXM="(M+$(M%M`^VD+0*```/MH"U"@``P>`("<*+ +M7;0/MH.V"@``P>`0"<(/MH.W"@``P>`8"<*)D0"```"#?0P!='"#?0P!`@````/____^+30B+41"X```` +M`(E"%(.[0`$```1U&&:#NT0!```!=PZ+41"+0A0-``0``(E"%(M="(M#$,>` +M&(`````'``"#[`C_=1!3Z/S___^#Q!"Z`P```(7`#X1%`@``@^P(_W40_W4( +MZ+,,``"#Q`C_=1#_=0CHL04``(/$$+H#````A<`/A!D"``"+10AF@7@$&_%U +M%HM5$(!Z`@!Y#8M`$,>`"-@```(%``"+30B+01#'@!R8```!````BT$0BX`4 +MF0``B<&!X?\_``"+71#V0P(@=!;!X0*ZHXLNNHG(]^*)T<'I!.L1C78`NLW, +MS,R)R/?BB='!Z0.#[`R-0610Z/S___^#Q!"+30B+41"+@F"8``"#R`&)@F"8 +M``!J`&H!:&"8``!1Z/S___^#Q`C_=1#_=0CH_/___X/$$(7`=2*+71!FBT," +MJ2````!U!X/(`F:)0P*Z`P```.E#`0``C78`BT6T@[AT"P```'0=BU4(BT(0 +MQX`@F0```/`!`(M-M,>!>`L```$```"[`````+X!````D(T\G0````"+10B+ +M4!")\(C9T^")A!<`$```0X/["7[@NP````"-=@"#[`A3_W4(Z/S___^#Q!!# +M@_L)?NN+70B+0Q#'@*0````!``$`BT,0QX"H`````0```(M#$,>`K`````$` +M``"+4Q"+@K`0``")@K`0``"+0Q#'@*````!E"0@`BT6TQX#`"@``90D(`(M3 +M$(N"K`````T```<`B8*L````@WT,!G4ABU,0BX*@````#0`0``")@J````"+ +M5;2!BL`*````$```@^P,_W4(Z/S___^#Q!"%P'0.@^P,_W4(Z/S___^#Q!"+ +M30B+41"+@B"````E__]__HF"((```+@!````ZQ*-=@"+71B#.P!T`HD3N``` +M``"-9?1;7E]=PY!5B>6#[!!J`O]U".@4`P``R<.)]E6)Y5.#[`2+70AJ`&H! +M:@)3Z/S___^#Q!"%P'02@^P(:A-3Z.@"``"#Q!"%P'4)N`````#K%(GV@^P, +M:#0(``#H_/___[@!````BUW\R<.058GE5E.+70B+=0QJ`&H!:@)3Z/S___^# +MQ!"%P`^$9@$``(GP)?`!```]P`````^$B````#W`````?Q4]H````'0^/;`` +M``!T-^D(`0``B?8]0`$```^$I0```#U``0``?PX]T````'13Z>@```")]CU0 +M`0``#X2%````Z=8```"+0Q#'@`28````````BT,0QX``H@```P```(M#$,>` +M?)@``!D```"#[`QH+`$``.C\____@\00Z9H```"+0Q#'@`28````````9H-[ +M!!(/A8(```"+0Q#'@'R8```8````@^P,:"P!``#H_/___X/$$(M#$,>``*(` +M``(```#K5O?&$````'00BT,0QX`$F````P```.L.D(M#$,>`!)@```````!F +M@WL$$G4JBT,0QX!\F```&````(/L#&@L`0``Z/S___^#Q!"+0Q#'@`"B```` +M````@^P(:A-3Z%\!``"#Q!"%P'0@@^P,:#0(``#H_/___VH`:@%J`E/H_/__ +M_X/$((7`=0BX`````.L,D(/L"&H`4^@E`0``C67X6UY=PXGV58GE5U93@^P, +MBWT(@[]X"P````^$A@```(M'$(N`()D``*D```$`=7;'AW@+````````BW<0 +MBYX0G```BX84G```B47LBX88G```B47PB=K1ZHM-[-'I`S!Z0;!Z@>) +M5>AT.(7)=#3WV)GW?>B#X#^)1>R)V)GW^8G!@^E`@^$?BT7LP>`%BY8@F0`` +M"=`)R`T`"```B88@F0``@^P(_W4,5^@]`P``@\00A +M7UW#B?95B>575E.#[!B+?0B+70R)WK@`````A=L/E7UW#58GE5U93@^P, +MBT4(B47LC47R4(U%\%"+50P/MT("4/]U[(M5[/^2.`$``(/$$(M%\(M5#&8[ +M`G<)9HL"9CM%\G8*N`````#I^@```(/L"(M5#`^W0@)0#[<"4.C\____@\00 +MBU4,@'H"`'DX#[_PC1QVP>,"C;.X(0``@^P(:@C_=@3H_/___P^V^,'G!8N# +MN"$``,'@!`G'9HM&"(/$$.L'B?:_`````&8]D`!_!ZD!````=!J#[`AJ")B# +MZ!A0Z/S___\/MMBX`0```.LAD(/L"&H(F(/H&(G"P>H?`=#1^%#H_/___P^V +MV+@`````@\00P>,"T>`)PX'+`00``(M%"(M($(GX)?\```#!X`@/MM,)T(F! +MG)@``(M5"(M*$(GX)0#_```/MM<)T(F!T)@``(M5#(L"BU7LB8*("P``N`$` +M``"-9?1;7E]=PXGV58GE5U93@^P,BWT(BET,BT\0BY%DF```@>(`\/__B=C! +MX`DE``X```G"BT40)?\!``"8"<*)D628``"+5Q"+@F"8``"#R`*)@F"8``"^ +M.````(3;=!$/MO.-!/4`````*?")QL'F";L`````ZQ6)]H/L#%;H_/___X/$ +M$$-F@_L[?Q"+1Q"+@&"8``"I`@```'7=N`````!F@_L[?QZ+1Q"+@&28``#! +MZ!,E_P$``*D``0``=`4U`/[__YB-9?1;7E]=PU6)Y8M%#(M-$(M5"&:+0`(E +MX`$```^WP#W`````=#$]P````'\*/:````!T%^LMD#U``0``=25FBX*B`0`` +M9HD!ZR&09HN"I`$``&:)`>L49HN"I@$``&:)`>L(N`````#K!I"X`0```%W# +MD%6)Y5.#[`B+70B-1?I0_W4,4^A]____@\00A-=@"+0Q"+ +MD&"8``"+@&28``")PL'J$X'B_P$``/?"``$``'0&@?(`_O__N`````!F.U7Z +M#Y[`BUW\R<.-=@!5B>564X/L$(MU"(.^0`$```-W7&:#OE0!``!`=5*#[`2- +M1?90_W4,5N@"____@\00NP````"%P'4*N`````#K1HUV`(/L!&H`#[:#_"(` +M`%!6Z!7^__^#Q!!#@_L"=N2X`````(/[`P^6P.L:C78`BU80BX)@F```@\@" +MB8)@F```N`$```"-9?A;7EW#B?95B>575E.#[$R+30R+10B)1>2X`````(!Y +M`@`/F<"Z`@```&8IPF:)5`!```/M\`]P`````^$NP$``#W````` +M?Q`]H`````^$:0$``.GL`0``/4`!```/A>$!``!FBP$MH0\``&8]Z@1W(XM% +MY&:+@`@"``!FB47$BT7D9HN`"@(``&:)1<+IC@```(GV9HL!+8P4``!F/>\` +M=QZ+1>1FBX`,`@``9HE%Q(M%Y&:+@`X"``!FB47"ZV!FBP$M?!4``&8]X`!W +M'HM%Y&:+@!`"``!FB47$BT7D9HN`$@(``&:)1<+K-&:!.5P6=B&+1>1FBX`4 +M`@``9HE%Q(M%Y&:+@!8"``!FB47"ZP^-=@!FQT7"``!FQT7$``"+5>1FB[JN +M`0``9HN"M`$``&:)1F6````B?:+1>1FBX`8`@``9HE%Q(M%Y&:+@!H"``!FB47"BU7D +M9HNZL`$``&:+@K8!``!FB47(N`````!F@[JV`0```.L^BT7D9HN`'`(``&:) +M1<2+1>1FBX`>`@``9HE%PHM5Y&:+NK(!``!FBX*X`0``9HE%R+@`````9H.Z +MN`$````/E,!FB47&ZPV0N`````#I*@$``(GV@^P(:@0/M_^)?;Q7Z/S___\/ +MMWW`P><"C;>$````N_`(``"+#!Z!X3_____!X`(&"=`EP`````G! +MB0P>@\0(:@3_=;SH_/___XVWD````(L4'H/B^-'H@^`'"<*)%!Z#Q`AJ`P^W +M5<2)5;A2Z/S___^+%!Z!XG_____!X`@\0(:@/_=;CH_/__ +M_XVWG````(L4'H/B_-'H@^`#"<*)%!Z#Q`AJ`P^W1<)0Z/S___^+%!Z#XN/! +MX`*#X!P)PHD4'H''S````(L4'X/B]XM%R,'@`X/@"`G"B10?NP````"#Q!"^ +M\`@```^W?<"0C01;BU4(BTH0BQ2&`?B+!(:)!`I#@_L8=N:+=>3'AHP+```` +M````N`$```"-9?1;7E]=PU6)Y5=64X/L#(M]"(G^BU4,9HM"`B7@`0``#[?` +M/<````!T4#W`````?PD]H````'0VZTP]0`$``'5%QT7P`````(M/$(N11)D` +M`(/BQP^WAH0"``#!X`.#X#@)PHF11)D``.LGC78`QT7P`0```.L;C78`QT7P +M`@```.L/C78`N`````#IYP$``(GV@[Y``0```W<7BU<0BX(0F0``@\@#B8(0 +MF0``ZUN-=@"+3Q"+@1"9```E!OS__XM=\`^WE%ZZ`0``P>($"="#R`&)@1"9 +M``"#[`3_=0S_MG`+``!7Z/S___^#Q!"+5Q!FBX1>H@$``"7_`0``#0`"``"8 +MB8)HF0``BT\0BY%$F```@>)_P/__BUWP#[>$7G@!``#!X`+_#_S_#[>$7GX!``#!X`PE`/`#``G"B9%(F```BU\0 +MBY-0F```@>(``/__BTWP@<&0`0``#[Y$,0_!X`@E`/\```G"#[9$,0P)PHF3 +M4)@``(M?$(M%\(V,`)`!```/MQ0QB=#!X!C!XA`)T`^W3#$&BA`$``,'@"`G"B9$HF```BT\0BY%D +MF```@>+_#_C_#[>$7HH!``#!X`PE`/`'``G"B9%DF```NP(```!F@;Y0`0`` +M`C!W&&:!?P8B$'4UBT4,]D`"0'0LNP@```#K)8M5#&:+`H/@'P^WP(7`=!6# +MZ`J#^`QV#8M-\`^WA$[\`0```<.+3Q"+D229``"!X@'___^-!!LE]P````G" +MB9$DF0``N`$```"-9?1;7E]=PXUV`%6)Y5=64X/L+(M="(M5#&:+0@(EX`$` +M``^WP#W`````=%8]P````'\//:````!T?.FK````C78`/4`!```/A9T```!F +MBX.:`@``9HE%W(V#A@(``(E%V(V#G`(``(E%X`^W@^H%``")1="-D^P%``") +M5=3K=XUV`&:+@Z0$``!FB47#/`8``(E% +MT(V3/@8``(E5U.M"B?9FBX.D!```9HE%W(V#K`0``(E%V(V#3@4``(E%X`^W +M@UP&``")1="-DUX&``")5=3K#HGVN`````#IN@```(GV@^P$BU4,#[<"4(U% +MV%#_=0CHJ@```(/$"/]U#/]U".C\____B<:Y`````(/$$+\`````9H.[*`(` +M``!T4+H@`@``C4,*9H,\`@!T$`^W!`(Y\'4(C;MT!@``ZS%!#[>#*`(``#G! +M?26-E`D@`@``C4,*9H,\`@!TXP^W!`(Y\'7;B$```C``!0_W4,#[=%T%#_==17_W4(Z&T#``"X`0```(UE]%M>7UW# +M58GE5U93@^P)]@^WUHV,$H@```!FBT'^9CN$ +M$H@```!^#&:+A!*(````9HE!_D=F.ST&````M1B<^)V/?IP?H$B=C!^!\IPHT4DHT4DM'B9HE5\&;'1>H``+X````` +M#[_2B57@B=.)V/?IP?H$B=C!^!\IPHG00(7`?BZY(`$``(G8]^_!^@2)V,'X +M'RG"0HGV#[=%ZF:+7>YFB1Q!9O]%ZD8/M\8YT'SHO@````#IX@```(GV9H-% +M\#(/MP4&````B47DBU7P9CN4`(8```!]7@^_RHG/#[?>#[^$&X@```")RBG" +M#[^$&XH````IP0^OT872?CF+3>2XB````(T<2$:+5?!F.U/^?20/M]8/OX02 +MB````(GY*<$/OX02B@```(GZ*<*)T`^OR(7)?]*#[`AJ``^WU@^WA!(*```` +MT>`/M\!0#[>$$@@```#1X`^WP%`/MX02B@```%`/MX02B````%`/MT7P4.CR +M!@``0`^W5>K1XKD@`0``9M'H9HD$"H/$((M=[&8YV'8$9HD<"F;_1>H/MP4& +M````BWWP9CN\`(8````/C`C___]F@WWJ/W!FBU0!_F:) +M%`AF_T7J9H-]ZC]VYKF`H0``O@````"[(`$``(UV``^WQL'@`@^W5`,"P>(8 +M@@^P,C4764(U%U%`/M\-0 +MC4784(M5&`^W`E#H)`8``+L`````@\0@9CGSBW7,9H&^4`$````P=A!FBY9>`0``9CG"=@*)PHG0#[?S#[?(#[=5P`^^ +M1;TIPCG*?@*)RF:)E#:@`0``9H7;=1V+5=#1XF:AH`$``&8IT&:)1;YFA(8N#\```!F +M(P6D`0``P>`0"<*X/P```&8C!:(!```/M\#!X`@)PK@_````9B,%H`$```^W +MP`G"B9$TF0``BTX0NC\```!F(Q6N`0``P>(8N#\```!F(P6L`0``P>`0"<*X +M/P```&8C!:H!```/M\#!X`@)PK@_````9B,%J`$```^WP`G"B9$XF0``BU80 +M#[<%H`$``(F"/)D``(UE]%M>7UW#C78`58GE5U93@^PY0#[=' +M!%#_-P^W]E;H20(``(/$%(U%[%"-1>I05P^W1>Y0#[?;4^@#`P``@\04C47H +M4(U%YE!7#[=%\%!3Z.P"``"#Q""-1>105P^W1>I0#[=%[E#HK0```(U%XE!7 +M#[=%[%`/MT7N4.B9````@\08:@`/MT7B4`^W1>10#[=%[%`/MT7J4%/H^@`` +M`&:)1>"#Q""-1>105P^W1>90#[=%\%#H7P```(U%XE!7#[=%Z%`/MT7P4.A+ +M````@\08:@`/MT7B4`^W1>10#[=%Z%`/MT7F4%/HK````(/$&&H`#[?`4`^W +M1>!0#[=%\%`/MT7N4%;HC@````^WP(UE]%M>7UW#C78`58GE5U93@^P$BT4( +M9HE%\HMU#(M%$(M0"+L`````9CM8!'-/9HM%\F8Y`G4YC4H(N`````!F.T(& +M@Z)]F8Y,747#[?`9HM$1Q"+511FB0*X`0```.L>B?:#P0)`9CM"!G+: +M@\(T0XM%$&8[6`1RL;@`````@\0$6UY?7<-5B>575E.#[`2+10AFB47RBTT, +MBWT0BUT4BW489L=%\&0`#[?##[?6#Z_"AM&C78`9H/X9'X.#[?&@WT<`'0]ZS*-=@`/O\@/M\8/K\&Z +M9````"G*#[?+#Z_1`=`/MU7PB=&9]_GK%9")V(-]'`!T#`^WP(T$@(T$@,'@ +M`@^WP(/$!%M>7UW#D%6)Y5=64XM=#(M]%(MU$`^WQF:+5$/^#[=-"(T$B8T$ +M@(T,A0`````/MP.-!("-!("-!(7V____.<%S#&:+`V:)!V:+`^L]D`^WPHT$ +M@(T$@(T$A0H````YP78P9HD7BT489HD0ZV>09HL$4V:)!V:+!%/K#XUV`&:+ +M!%-FB0=FBT13`HM5&&:)`NM"N@````!FA?9T.`^W]HUV``^W!%.-!("-!(#! +MX`(IR(/`"8/X$G:U#[=$4P*-!("-!("-!(7V____.<%RKT(Y\GS.6UY?7<.0 +M58GE5E.+71"+=0B+30R+4PBX`````&:#>P0`=!AF.0IT$P^W6P2)]H/"-$`Y +MV'T%9CD*=?.#[`S_=1C_=10/MT(&4(U""%`/M\90Z-S^__^-9?A;7EW#D%6) +MY8M5"(V*F`H``*%$(P``B8*8"@``BQ5$(P``C035`````"G0C02%2",``(E! +M&,=!%`$```#'00P4````QT$0(P```%W#D%6)Y5=64XM5#(M%"`6("P``]D`" +M('0EOP````"Y'````+M`````OG(```#'0@P`````QT(0=P```.LCD+\````` +MN3(```"[`````+XR````QT(,%````,="$",```"+4@2X`````#GZ<@0YRG8- +M.=IR!#GR=@6X`0```%M>7UW#58GEBT4(BT@0BY"4"P``P>()@>(`?@``@-GI@*``"X```` +M`(-[%`!T=X.^C`L```%U:(M'$(N`,)D``&:%P'A:P>@9B4,$QX:,"P`````` +M`(/L"%-7Z`#___^#Q!"%P'4Y@^P(4U?H/P```(/$$(7`="B#[`A35^A.```` +M@\00A`I0PB+$XT$U0`````IT(T$A4@C``")0QB+0P@[0Q!R!(72 +M=<.X`0```.F*````D(M#!#M##'=\H4`C``!(.0-U"KC^____ZW"-=@"+0P2) +M0P@[0PQW5*%`(P``2#D#)]K@`````6UY=PXUV`%6)Y8M-"(M5#(-Z%`!T-XM"&&:+`&:) +M@80"``"+0AAFBT`"9HF!@@(``(M"&&:+0`1FB8&``@``BT(89HM`!F:)@7X" +M``!=PU6)Y5W#C78`58GE4XM-"(M5#(M9$(N#!(```"7__P``@_H!=">#^@%R +M$H/Z!G4M#0``@0")@P2```#K*(M1$`T``$(`B8($@```ZQB+41`-```@`(F" +M!(```.L(N`````#K!I"X`0```(L<),G#B?95B>564XMU#(M5"(/^`G08@_X" +M=P>#_@%T)NM2@_X#=`^#_@1T$NM&N0D```#K29"Y"````.M!D+D!````ZSF0 +MN0````"#NL@*````=!N-6@B-=@!!@_D)?P^)R,'@!(.\`\`*````=>N#^0IU +M"KC_____ZT:-=@")R,'@!(FT$,@*``"#?1``=`VX`0```-/@"8+$"@``B6+30R+ +M50BX`````(/Y"7<[B`$QX00 +MR`H```````"X_O___]/`(8+$"@``N`$```!=PU6)Y5=64X/L#(MU"(V6B`L` +M`+@`````@WT,"0^'^0(``(M%#,'@!(V\,,@*``"X`0```(,_``^$W@(``(.^ +MA`L```!U,X72=!MFBT("):````!F/:``=0S'AGP+```?````ZPK'AGP+```/ +M````QX:`"P```@```(N&@`L```-'!(E%\+H!````.Y9\"P``("BT,0 +MQX0"P`D````(``"#OD`!```#=Q2+50S!X@*+0Q#'A`(`$0```````8L'@_@# +M=&R#^`-W"X/X`G06Z?X```"0@_@$#X37````Z>\```")]HM-#,'A`HM%"(M0 +M$(N$$<`)```-H@```(F$$<`)``"#OD`!```$&=N!XP````&!PP``)0"+50S! +MX@*+30B+01")G`(`$0``Z:$```"+30S!X0*+70B+4Q"+A!'`"0``#6("``") +MA!'`"0``H0`````K!0````"+EJ0+``")TRG#*QT`````P>,*BTT,P>$"BT4( +MBU`0B=@-`````8F$$0`)``"#OD`!```$&=N!XP````&!PP``!`"+50S!X@*+ +M30B+01")G`+`"0``ZR"-=@"+30S!X0*+70B+4Q"+A!'`"0``@\@CB801P`D` +M`(M%"(M($(N&Q`H``(G"@>+_`P``P>`0)0``_P,)PHF1I````(M-"(M1$(N& +MQ`H``"7_`P``B8*H````BUT(BTL0BX&L````)0#\__^+EL0*``"!XO\#```) +MT(F!K````+@!````@\0,6UY?7<.)]E6)Y8M%#(/X"78)N/_____K%HGVC12% +M`````(M%"(M`$(N$`@`(``!=PXGV58GE4XM="(M%#(M-$(/X"78*N`````#K +M&8UV`(T4A0````"+0Q")C`(`"```N`$```"+'"3)PY!5B>575E.#[!B+70A3 +MZ/S___^)QX/$""7___]_4%/H_/___XM#$(M0,(G6@>;P`P``P>X$@\00@WT, +M`'0/N"4````I\-'H`<;K'HGV@_X!=@-.ZQ2#[`A74^C\____N`````#K*HUV +M`(M+$('B#_S__XGPP>`$)?`#```)PHE1,(/L"%=3Z/S___^X`0```(UE]%M> +M7UW#D%6)Y8M%"(M-#(/Y"78*N`````#K&(UV`(M0$+@!````T^")@D`(``"X +M`0```%W#D%6)Y5.+70B+30R)VKC_____@_D)=T:)R,'@!(.\$,@*````=0>X +M_____^LPC02-`````(M3$(N$$``*``")PX/C`W46N`$```#3X(N20`@``(7" +M=`6[`0```(G8BQPDR<.-=@!5B>575E.#[`R+?0B+=0R)^K@`````@_X)=W>) +M\,'@!(.\$,@*````=0JX`````.MAC78`BU<0N`$```")\=/@B8*`"```NP`` +M``#K$8UV`(/L#&H*Z/S___^#Q!!#@?L/)P``?Q&#[`A65^C\____@\00A`@`@```````"X`````('[#R<```^>P(UE]%M>7UW#B?95B>6X`0`` +M`%W#B?95B>575E.+=1B+?2B+73"+30RX`````(-])`!T<(/^!'=KBT40)?\/ +M``"+52#!XA()T(M5+,'B&0G0]\,!````=`4-`````??#!````'0%#0``0`") +M00B)\L'B&O?#`@```'0&@6+50R)T?9"%`%U"K@/````Z98```"+010E_A\``-'H +M9HE"(`^W01)FB4(BQD(D`(M!$*D!````=1^I`@```'0$QD(D`?9!$`AT!(!* +M)`+V01`$=`2`2B0$BT$()0``/`#!Z!*(0B6+010E`.`?`,'H#8A")HM!%"7P +M````P>@$B$(GBT$4)0`/``#!Z`B(0BC&0BH`@'HG`'0#_D(G@'HH`'0#_D(H +MN`````!=PU6)Y8/L"(M-"(M!$,>`T)@``!8<``"Z`````)"+01#'@("8```` +M``$`0H/Z!W[MBT$0BX``G```P>@8B<+!Z@2#X`_!X`0)T(/L"&H(4.C\____ +MR<.-=@!5B>575E.#["B+10AFB47P:"`.``#H_/___XG#@\00O@(```"%VP^$ +MH00``(E=[+Y@)```_+E.````B=_SI8M5\&:)4P1FQT,&``"+10R)0PB+11") +M0PR+112)0Q#'@S@!``"8I```QX,\`0```````,:#M`L``!#'@[`+```````` +MQH.U"P``!,>#N`L```````#'@[P+````````QX/("P```````,>#U`L```(` +M``#'@]@+````````QX/<"P```````,>#X`L```H```#'@^0+```*````QX/H +M"P``9````,>#[`L```````#'@_P+```!````QX,`#````0```,:#!`P```"# +M[`AJ`%/H_/___X/$$+X#````A<`/A*H#``"+?>R+1Q"+@"!````/MM")T,'H +M!(F#0`$``(G0@^`/9HF#1`$``+X-````@[M``0``!0^%<@,``(M5[(M"$(N` +M&)@``(F#2`$``(/L#%+HH@,``(/$$+X.````A<`/A$<#``"+?>R+1Q#'@`"8 +M```'````@^P,5^@)_O__9HF#3`$``"7P````@\009H/X$'0/O@T```!F@_@P +M#X4*`P``@^P$C47R4&C!````_W7LZ/S___^#Q!"^"````(7`#X3F`@``O@4` +M``!F@7WR`3`/AM4"``!FBT7R9HF#4`$``(M5[(M"$(N0$$```(/B&,'J`[X* +M````@_H"#X6J`@``@^P$C47R4&H__W7LZ/S___^#Q!"^"````(7`#X2)`@`` +M9HM%\F:)@U(!``#'1>@`````O@````"-??*)]H/L!%>-AL````!0_W7LZ/S_ +M__^#Q!"%P`^$2@(```^W1?(Q1>A&@?X_`P``=M*^!P```(%]Z/__```/A2T" +M``!FQX.:`@``"@!FQX.D!````P"^`````(U3$HGVC01VC02&9L>$@I`"```+ +M`$:#_@EVZKX`````C7L,B7WDC4,&B47@D(T$-HV(H`0``&:+D)@E``"+?>1F +MB10Y9HN0GB4``(M]X&:)%#D!\(T$AL'@`F;'A!A4!0``"P!FQX08N`0```L` +M1H/^`G:Y@^P$:`````"-@U`!``!0_W7LZ/S___^#Q!"^"````(7`#X1[`0`` +M9H.[:`$```!T>V:+@TP!```E\````&:#^!!U:8M5[(M"$,>``)@```=```"# +M[`QHT`<``.C\____@\0$_W7LZ!+\__]FB8-.`0``BWWLBT<0QX``F```!P`` +M`,<$)-`'``#H_/___V:+@TX!```E\````(/$$+X-````9H/X(`^%]@```(/L +M!(U%\E!HOP```/]U[.C\____@\00O@@```"%P`^$T@```&:+1?)FB8-4`0`` +M@^P,_W7LZ/S____'1>@`````O@````"#Q!"->P20@^P$C47R4+@?````*?!0 +M_W7LZ/S___^#Q!"%P`^$@@````^W1?(!1>B-%#9F#[9%\XB$%[`*``"*1?*( +MA!>Q"@``1H/^`G:X@WWH`'0)@7WH_?\"`'4)O@D```#K2XGVBU7L9HN"3`$` +M`"7P````9H/X+W8/QX,$"P```````.L-C78`QX,$"P```````(/L#/]U[.C\ +M____B8,8#```BT7LZR6^"````(7;=`R#[`Q3Z/S___^#Q!"#?1@`=`6+?1B) +M-[@`````C67T6UY?7<.-=@!5B>53@^P0BUT(4^C\____B1PDZ/S___^+7?S) +MPXUV`%6)Y5=64X/L/(M=",=%T`"```#'1=0@F```C7W8OAP*``#\N00```#S +MI<=%Q`````"-1=")1<"-5`0B<()RHM#$(D4!HM#$(L$!CG0=29!@?G_````?MZY +M`````(U]V(GVBQ2/BT,0B10&BT,0BP0&.<)T";@`````ZSR)]D&#^0-^WHM% +MQ,'@`HM+$(MUP(L4,(MUO(L$,(D$"O]%Q(-]Q`$/CFW___^#[`QJ9.C\____ +MN`$```"-9?1;7E]=PXGV58GE7<.-=@!5B>6+51"+312+10RI``$``'019L<" +M.!-FQP'4%[@!````ZRF$P'D@BT4(9H.X:`$```!T$V;'`@@)9L'_ +M_P``@_H!=`R#^@%R*X/Z!G12ZWZ+0Q#'@"R```#__P``BT,0QX`P@```__\' +M`(')`````>M`,(```/__!P"! +MR0``@`#K,8UV`(M3$(GP*P4`````P>`#B8(L@```BU,0B?`K!0````#!X`.) +M@C"```"!R0``@`&+4Q"#O[`+````=`J)\`.'L`L``.L#C48!B8(T@```]\$` +M```!=`V+0Q#'@""````````!BT,0B8@@@```6UY?7<-5B>564XMU"+L````` +MZP^0@^P,:@KH_/___X/$$$.!^^<#``!_$H/L"&H"5NC\____@\00A`*(````````"+2A"+ +M@02````-```$`"7__\__B8$$@```BT(0QX`@@```__\``%W#D%6)Y5=64XM= +M#(!["P!T98M%"(M0$(N"!(````T``!``B8($@```#[9#"P^V4PH/K\(/MU,( +M#Z_"BTT(BU$0B8(D@```BU$0#[=##(F".(````^V0PH/KT48`T44#[=3"`^O +MPHM1$`-%$,'@`XF",(```.L7BT4(BU`0BX($@```)?__[_^)@@2```"+30B+ +M41"+`XF"*(```(M%"(M($(N!((```"4``(#_#[=3"`G"9H-[$`!T$0^W0Q"# +MP`3!X!`E``!_``G"B9$@@```BT4(BT@0BY$8@```,/8/MT,4P>`()0#_```) +MPHF1&(````^W`0"?")@MR```!;7E]=PXGV +M58GEBT4(BT`0BY`(0```N`````"#^@$/E,!=PU6)Y8M%"(M-#(M`$(N0P``` +M`(/Z_W4-QP$`````N`````#K08G0);K8!0&)`??"```(`'0'#0```$")`??" +M!0```'0#@PD!]\)``0``=`.#"4#WPB````!T!H$)````0+@!````7<.058GE +MBT4(BX#`"@``7<.)]E6)Y5=64XM="(M-#(G?B[/`"@``A?9Y$(M#$,=`)``` +M``"+0Q"+0"2)RH'BNM@%`??!0````'0&@0J+0Q#'0"0!````B?!;7E]= +MPY!5B>6X@````%W#B?95B>6+10QF@_A_=R`/M\#!X`6+50@#0A"+@!R(``!F +MA)]K@`````7<.058GEBTT(BU4,9H/Z?P^'C0````^WPL'@ +M!0-!$,>``(@````````/M\+!X`4#01#'@`2(````````#[?"P>`%`T$0QX`( +MB`````````^WPL'@!0-!$,>`$(@````````/M\+!X`4#01#'@!2(```'```` +M#[?"P>`%`T$0QX`8B`````````^WPL'@!0-!$,>`'(@```````"X`0```.L& +MD+@`````7<.058GE5U93BWT(BUT0BW4,N`````!F@_Y_=W&%VW0Z#[93!<'B +M"`^V0P0)P@^V2P/!X1@/MD,"P>`0"<$/MD,!P>`("<$/M@,)P='IB=#!X!\) +MP='JZPR)]KH`````N0`````/M\;!X`4#1Q")B!B(```/M\;!X`4#1Q"!R@"` +M``")D!R(``"X`0```%M>7UW#58GE5U93@^P1655559H/X?W8+N`````#I7`$``)"X```` +M`(,[!`^.30$```^V>P0/MD,%P>`("<`0"<`8"<1F +M#[93"&8/MD,)P>`("<(/M]*+1>0QPH'B__\``(E5[`^V`("<8/ +MMD,,P>`0"<8/MD,-P>`8"<8S=>1F#[93#F8/MD,/P>`("<(/M](S5>2!XO__ +M```/MDL0#[9#$<'@"`G!#[9#$L'@$`G!#[9#$\'@&`G!,TWD@SL-?P:!X?\` +M``#'1>@`````@SL%?AC'1>@`````@SL-#Y]%Z(M=Z(U<&P&)7>@/MT7RP>`% +MBUT(`T,0B;@`B```#[=%\L'@!0-#$(M=[(F8!(@```^W1?+!X`6+70@#0Q") +ML`B(```/MT7RP>`%`T,0B9`,B```#[=%\L'@!0-#$(F($(@```^W1?+!X`4# +M0Q"+5>B)D!2(``"#[`3_=10/MT7R4%/H_/___XUE]%M>7UW#D%6)Y8M5"(M- +M#(N"M`H``(D!9HN"N`H``&:)001=PXGV58GE4X/L!(M="(M5#(M#$(F0`&`` +M`(M#$,>`"&````$```!J`FH#:`Q@``!3Z/S___^#Q!"%P'4'N`````#K%(M# +M$(N0!&```(M%$&:)$+@!````BUW\R<.-=@!5B>53@^P$BTT(BUT,BU40BT$0 +MB9@`8```BT$0#[?2B9`$8```BT$0QX`(8````@```&H(:@QH#&```%'H_/__ +M_XG"@\00N`````"%T@^5P(M=_,G#C78`58GE4XM=$(M%#(M-"+H,````9CF! +M5`$``'06N@````"`N5(!````#YG"C135`P```(7;=`*)$[@`````BQPDR<.- +M=@!5B>6+10@/MX!4`0``7<.058GEBU4(B=&X`````&:#NF8!````=`]F@[I6 +M`0````^4P(U$``%F@[IH`0```'0#@\@$9H.Z:@$```!T"V:!>081#G0#@\@( +M7<.)]E6)Y5.#[`2+70AF@[M:`0```'14@^P$C47Z4&H/4^C\____@\00A@/M\") +M@PP,``#'@Q0,```!````ZQ^0QX,(#````````,>##`P```````#'@Q0,```` +M````N`````!F@[M:`0````^5P(M=_,G#D%6)Y593BUT(B=Z#[`C_LP@,``!3 +MZ/S___^#Q`B+4Q"+@@"8```-`"```(F"`)@``/^V"`P``%/H_/___XF&$`P` +M`(/$#+H`````.X8,#```#Y7"4O^V"`P``%/H_/___XUE^%M>7<.058GE4XM% +M"(M-#(M8$-'AN@,```#3XO?2BX,40```(<*X`@```-/@"<*)DQ1```"X`0`` +M`(L<),G#C78`58GE4XM%"(M-#(M8$-'AN`,```#3X/?0BY,40```(=")@Q1` +M``"X`0```(L<),G#58GE4XM%"(M-#(M8$(N3&$```+C^____T\`APHM%$(/@ +M`=/@"<*)DQA```"X`0```(L<),G#B?95B>6+30R#^05W&8M%"(M`$(N`'$`` +M`(/@+]/H@^`!ZPB-=@"X_____UW#D%6)Y593BW4(BU4,BT80BY@40```C0P2 +MN`,```#3X`T`\`$`]]`AP\'B#`G3@6+10B+2!"+@1!` +M```EG__Q_XM5#(/B!PL$E<`E``")@1!```!=PXUV`%6)Y5=64X/L'(M]"(M5 +M#(MU$(M%%&:)1=B)^XL"B8>Z"@``9HM"!&:)A[X*``"+3Q`/MI>Z"@``#[:' +MNPH``,'@"`G"#[:'O`H``,'@$`G"#[:'O0H``,'@&`G"B9$(@```BT\09@^V +MD[P*``!F#[:#O0H``,'@"`G"#[?2B?`E_S\``,'@$`G"B9$,@```BU<0BX(, +M@```)?__``")@@R```!FA?9T,HM/$(N!((```(G"@>+__X#_9H-]V`!T%(M% +MV,'@$(V````$`"4``'\`"<*0B9$@@```@\0<6UY?7<.)]E6)Y5.+10B+2!"+ +M@5"```")PK@`````BXE,@```NP`````)R`G:BQPDR<.058GEBT4(BT`0BX!, +M@```7<.-=@!5B>53BUT(BTL0BX$@@```B<*!R@````&)D2"```"+4Q`-```` +M`8F"((```(L<),G#C78`58GE5U93BWT(BUT,]H?&"@``('15L`"Y`````#L+ +M7UW#D%6)Y8M5"(M" +M$(N`9)@``(G!P>D3@>'_`0``]\$``0``=`:!\0#^__^+4A"+@E"```"+DDR` +M```QT#'(7<.-=@!5B>53BU4(BT(0BX`@0```)?\```")P8/A#[L`````P>@$ +M.8)``0``=0YF.8I$`0``=06[`0```(G8BQPDR<.058GEBTT(BT4,BU$0BY*0 +M@````1"+41"+DHR````!4`2+41"+DI2````!4`R+41"+DHB````!4`B+41"+ +MDIB````!4!"+01#'@.R`````````BT$0QX#P@````````(M!$,>`](`````` +M``"+01#'@/B`````````7<.)]E6)Y8M%#(/X`70)@_@!6+10B+0!"+@!R<```E +M_P```%W#B?95B>6+10B+0!"+@%B```"#X`==PU6)Y5.+70R+50B+2A")V(/@ +M!XF!6(```(C8@^`'B(+T"P``9L>"]@L`````BQPDR<.-=@!5B>575E.#[`2+ +M?0R+11"+50B)5?!FBT`")>`!```/M\`]P````'0P/<````!_#3V@````=!KI +ML@```)`]0`$```^%I@```+@`````ZP^)]K@!````ZP:0N`(```"-#`"+5?"# +MP@H/M[0*M@$```^WA`J\`0``P>`&"<8/MX0*P@$``,'@#`G&#[>$"L@!``#! +MX!()Q@^WA`K.`0``P>`8"<8/MYP*U`$```^WA`K:`0``P>`&"<,/MX0*X`$` +M`,'@#`G##[>$"N8!``#!X!()PP^WA`KL`0``P>`8"<.#_P%T$8/_`7(2@_\" +M=`NX`````.LIB?/K`HG>BT7PB;BX"P``BU4(BT(0B;!@F0``BT(0B9ADF0`` +MN`$```"#Q`1;7E]=PXUV`%6)Y;@!````7<.)]E6)Y8M-"(M5#&:+@<8*```E +MP````&8]P`!U)CM5$'0AA=)T$(M!$,>`BWL0BX<$@```#[?(@_H!='Z# +M^@%R&8/Z!@^%A````(G(#0``@0")AP2```#K?9"+4Q"+0A2#R"")0A2+4Q") +MR`T``((`B8($@```9HN&Q@H``"7`````9CW``'5.BT,0QX!P$```<`,``,>& +M_`L```````"#[`1J`6H`4^@F____B88`#```@\00ZQ^-=@"+4Q")R`T``"`` +MB8($@```ZPJ)]K@`````ZP:0N`$```"-9?1;7E]=PXUV`%6)Y5=64X/L%&C8 +M!0``:@#H_/___X/$"&CQ!0``:@#H_/___X/$#&I#:.`E``#_=0CH_/___XM5 +M"(M"$(N`M````%"+0A"+@+````!0BT(0BX"L````4(M"$(N`J````%"+0A"+ +M@*0```!0BT(0BX"@````4&@@`P``:@#H_/___XM-"(M!$(N0P````(/$,(N` +MU````%"+01"+@-````!0BT$0BX#,````4(M!$(N`R````%"+01"+@,0```!0 +M4FA@`P``:@#H_/___X/$&&CQ!0``:@#H_/___XM5"(M"$(N`0`H``%!H\P4` +M`(M"$(N`@`@``%!H_P4``(M"$(N`0`@``%!H!08``&B@`P``:@#H_/___X/$ +M,(M-"(M!$(N`@`D``%"+01"+@$`)``!0:.`#``!J`.C\____NP````"#Q!"- +M=@"-%)T`````BTT(BT$0BX0"``H``%"+01"+A`+`"0``4(M!$(N$`@`)``!0 +MBT$0BX0"P`@``%"+01"+A`(`"```4%-H(`0``&H`Z/S___^#Q"!#@_L)?JF# +M[`AH\04``&H`Z/S___^[`````(/$$(GV@^P,C12=`````(M-"(M!$(N$`D`1 +M``!0BT$0BX0"`!$``%"+01"+A`+`$```4(M!$(N$`H`0``!0BT$0BX0"0!`` +M`%"+01"+A`(`$```4%-H8`0``&H`Z/S___^#Q#!#@_L)?IN[`````(GVB=K! +MX@B+10B+2!"+A`HX$```B47PB="#R$"+O`@X$```B=`-@````(NT"#@0``"! +MRL````"+A`HX$```@WWP`'4,A?]U"(7V=02%P'09@^P$4%97_W7P4VC`!``` +M:@#H_/___X/$($.#^PE^DXUE]%M>7UW#C78`58GE7<.-=@!5B>564XMU"(-] +M#`!T6XM&$,>`!$````````"#[`QJ"NC\____NPH```"#Q!#K(9"#[`QHR``` +M`.C\____@\00BT80QX`$0````````$MT$(M&$(N`$$```*D```$`=="X```` +M`(7;=!F+5A"+@@2````E___[_XF"!(```+@!````C67X6UY=PXUV`%6)Y5.+ +M70B+30R+4Q"+@@2````-```$`(F"!(```(7)=`V+0Q#'@`1````!````BQPD +MR<-5B>564XMU"(M-#(M=$(M6$(N"!(````T```0`B8($@```A575E.#[`R+50B+70R+31"+112)UK\!```` +M@_L#="N#^P-W"H/[`G0-ZT.-=@"#^P1T)^LYD(/L"%%2Z,+^__^)QX/$$.LO +MC78`@^P(45+H.O___X/$$.L=D(/L!`^WP%!14NA:____@\00ZPF0N`````#K +M"9")GJP+``")^(UE]%M>7UW#58GEBT4(BT`0BX`$0```)0```P#!Z!!=PXUV +M`%6)Y8M%"(M`$(N`$$```,'H$(/@`5W#D%6)Y;@`````7<.)]E6)Y;@````` +M7<.)]E6)Y;@`````7<.)]E6)Y;@`````7<.)]E6)Y5.#[`2+10Q(@_@?=S#_ +M)(4`*```D+L`````ZRF0NP````#K(9"[`````.L9D+L`````ZQ&0NP````#K +M"9"X`````.L/D(/L"%/_=0CH_/___XG8BUW\R<.058GEBT4(BT`0BT`,7<.) +M]E6)Y8M%"(M5#(M`$(E0#%W#C78`58GEBT4(BT`0QT`(!````%W#B?95B>6# +M[`B+50B+0A#'0`@@````:@!J!&H(4NC\____B<*#Q!"X`````(72#Y7`R<-5 +MB>6#[`B+30B+41"+@DB```"#X-^)@DB```"#N1@,````=`R#[`Q1Z/S___^# +MQ!#)PXGV58GEBT4(BU`0BX)(@```@\@@B8)(@```7<.)]E6)Y5.+30B+50R+ +M71"+01")D$"```"+01")F$2```"+'"3)PU6)Y5.+10B+30R#^3]V";@````` +MZT.)]H/Y'W8?BU`0BYI$@```@^D@N/[____3P"'8B8)$@```ZQJ)]HM0$(N: +M0(```+C^____T\`AV(F"0(```+@!````BQPDR<.)]E6)Y5.+10B+30R#^3]V +M";@`````ZT.)]H/Y'W8?BU`0BYI$@```@^D@N`$```#3X`G8B8)$@```ZQJ) +M]HM`$(N80(```+H!````T^()VHF00(```+@!````BQPDR<.)]E6)Y8M%"(M` +M$(N0/(```(N`#($``*D@````=`:!R@`"``"I```"`G0&@53BUT(BTT,BU,0#[;!B8(\@```N@````#WP0`"``!T!;H@````]\$``0`` +M=`:!R@```@*+0Q")D`R!``"%TG0-BU,0BT(T@\@0ZPZ)]HM3$(M"-(/@[XUV +M`(E"-(L<),G#58GE5E.+30B+=0R-7@CV0PP!=0RX#P```.G`````B?8/MT,( +M)?\/``!FB48@#[=##B7_?P``9HE&(L9&)`"*0PRI`@```'50J00```!T!,9& +M)`'V0PP(=`2`3B0(]D,,$'0K@$XD`@^V1A6(1B6-%(6@#0``@SP*`'03@^P$ +MC48@4/\T"E'H_/___X/$$/9##"!T!(!.)!!FBT,*9L'H!(A&)O9##0%T"XI# +M#=#HB$8GZP60QD8G_XM#",'H#X/@'XA&*(I#"\#H!(A&*8I#"<#H!(/@`8A& +M*K@`````C67X6UY=PXUV`%6)Y593BT4,BW40BTT4C5@(QT`,`````,=`"``` +M``#'0!0`````QT`0`````(GR@>+_#P``9HM#!"4`\```"=!FB4,$]\$@```` +M=`2`2P4@#[=3!('B_P\``+@`````.?(/E,!;7EW#58GE5U93@^PLBWT(B7WP +MO@````"+11!FBU`"B=!FP>@'@^`!]\(``0``=`2%P.L6BU409HM"`F;!Z`P`````BT<0BX!8@```B47HA0QT7<`@```,=%V`$```#K)L=%W`,```#K%HUV +M`,=%W`0```#K"HUV`,=%W`4```#'1=@"````BT<0QX``F```!P```+L````` +MC0Q;B4W,BT\0BT7,BP3%@"@``(E%U(M5S(M%W(T44(L$E8`H``"+5=2)!`I& +M]\8_````=0V#[`QJ`>C\____@\000X/['G:XNP````"-=@"+#-WH+```@WT4 +M`'0-C8$`@/__/?\/``!V(XM7$(L$W>PL``")!!%&]\8_````=0V#[`QJ`>C\ +M____@\000X'[]@```':Z9HN'3`$``"7P````NP````!F@_@O#X;+````C78` +MC0Q;B4W,BT\0BT7,BP3%$"P``(E%U(M5S(M%W(T44(L$E1`L``"+5=2)!`I& +M]\8_````=0V#[`QJ`>C\____@\000X/["':XNP````"-=@"-!-T`````BT\0 +MBY"(-@``BX",-@``B00*1O?&/P```'4-@^P,:@'H_/___X/$$$.#^SIVR[L` +M````B?:-!%N+3Q"+%(7X/````T78BP2%^#P``(D$"D;WQC\```!U#8/L#&H! +MZ/S___^#Q!!#@_L_=LKIPP```)"-#%N)3C\____@\000X/[/';+NP````")]HT$6XM/$(L4A?@Y```#1=B+!(7X +M.0``B00*1O?&/P```'4-@^P,:@'H_/___X/$$$.#^S]VRH/L"/]U$%?H!BD` +M`(/$$(M-\(.Y2`$``$%V1XM'$,>`+)@```+@`@"+1Q#'@$R9``!`#`P`BU<0 +MBX(HH@``#0`"``")@BBB``"+5Q"+@BBB```E_P/^_PT`"```B8(HH@``@^P( +M_W405^A4%```@\00N@,```"%P`^$T`,``(/L!(M=\(N#!`L```^W5=Q2_W40 +M5_]0!(/$$+H#````A<`/A*@#``"+11#V0`)`=`V#[`A05^A-$P``@\00@^P( +M_W405^B"$```@\00N@,```"%P`^$=@,``(-]%`!T#(M'$(M5[(F00!$``(M/ +M$(M=\`^VD[0*```/MH.U"@``P>`("<(/MH.V"@``P>`0"<(/MH.W"@``P>`8 +M"<*)D0"```"#?0P!=&N#?0P!-=@"+1Q"+3?!F#[:1N`H` +M`&8/MHFY"@``P>$("`Y(```/____^+5Q"+@A!````+1>2)@A!```"+1Q"+ +M5>B)D%B```"+3Q"+7?`/MI.Z"@``#[:#NPH``,'@"`G"#[:#O`H``,'@$`G" +M#[:#O0H``,'@&`G"B9$(@```BT\09@^VD[X*``!F#[:#OPH``,'@"`G"#[?2 +MB9$,@```BT<0QX"`````_____XM7$+@`````B4(4BT<0QX`8@`````<``(/L +M"(N#!`L``/]U$%?_$(/$$+H#````A<`/A+`!``"+1Q"+@%B```"+5?"(@O0+ +M``!FQX+V"P````"+1Q"+@`BB``#!Z`V#X`&)@O`+``"+1Q#'@!R8```!```` +MBT<0BX`4F0``B<&!X?\_``"+71#V0P(@=!7!X0*ZHXLNNHG(]^*)T<'I!.L0 +MB?:ZS6#[!!J`O]U +M".C(`@``R<.)]E6)Y5.#[`2+70AJ`&H!:@)3Z/S___^#Q!"%P'4'N`````#K +M"X/L"&H34^B5`@``BUW\R<-5B>564XM="(MU#(/L"&H34^AZ`@``@\00A`!```/M\`]P`````^$@0```#W`````?PX]H``` +M`'17Z;,```")]CU``0``#X6F````BT,0QX!\F```J@```(/L#&@L`0``Z/S_ +M__^#Q!"+0Q#'@`"B````````BU,0N`````#V1@(0#Y7`C01`B8($F```ZV*0 +MBT,0QX`$F````````(M#$,>``*(```,```#K*(M3$+@`````]D8"$`^5P(T$ +M0(F"!)@``(M#$,>``*(```8```"-=@"+0Q#'@'R8``"K````@^P,:"P!``#H +M_/___X/$$+@!````C67X6UY=PXUV`%6)Y5=64X/L#(M%"(.XO`L````/A($` +M``"+0!"+@""9``"I```!`'5QBU4(QX*\"P```````(MR$(N>$)P``(N&%)P` +M`(N^&)P``(G:T>J)P='I`N`````"%VP^5P$@)PXM'$(M0#(FP`$```&H/Z/S_ +M__^#Y@-6@^,#4V@`0```5^C\____C67T6UY?7<-5B>575E.#[`R+10B)1>R- +M1?)0C47P4(M5#`^W0@)0_W7LBUWL_Y,X`0``@\00BT7PBU4,9CL"=PEFBP)F +M.T7R=@JX`````.DT`0``@^P(BUT,#[=#`E`/MP-0Z/S___^#Q!"`>P(`>6L/ +MO_"-'';!XP*-LT1,``"#[`AJ"/]V!.C\____#[;XP><%BX-$3```P>`$"<=F +MBTX(BT4(BU`0BX($H@``@\00BUT,9H$[M`EU#8/($(F"!*(``.L=B?:+70B+ +M4Q"#X.^)@@2B``#K"HUV`(G!OP````!F@?F0`'\(]\$!````=!Z#[`AJ"`^_ +MP8/H&%#H_/___P^VV+@!````ZR6-=@"#[`AJ"`^_P8/H&(G"P>H?`=#1^%#H +M_/___P^VV+@`````@\00P>,"T>`)PX'+`00``(M%"(M($(GX)?\```#!X`@/ +MMM,)T(F!G)@``(M5"(M*$(GX)0#_```/MM<)T(F!T)@``(M=#(L#BU7LB8+$ +M"@``N`$```"-9?1;7E]=PU6)Y8M%"(M`$(N`9)@``,'H$R7_`0``J0`!``!T +M!34`_O__F%W#B?95B>575E.#[`R+?0B*70R+3Q"+D628``"!X@#P__^)V,'@ +M"24`#@``"<*+11`E_P$``)@)PHF19)@``(M7$(N"8)@``(/(`HF"8)@``+XX +M````A-MT$0^V\XT$]0`````I\(G&P>8)NP````#K%(GV@^P,5NC\____@\00 +M0X/[.W\0BT<0BX!@F```J0(```!UWK@`````@_L[?PJ#[`Q7Z#/___^8C67T +M6UY?7<.)]E6)Y8M%#(M-$(M5"&:+0`(EX`$```^WP#W`````=#$]P````'\* +M/:````!T%^LMD#U``0``=25FBX*B`0``9HD!ZR&09HN"I`$``&:)`>L49HN" +MI@$``&:)`>L(N`````#K!I"X`0```%W#D%6)Y5.#[`2+70B+0Q"+@&"8``"I +M`@```'0*N`$```#K/8UV`(/L!(U%^E#_=0Q3Z&#___^#Q!"%P'4)N`````#K +M'(GV@^P,4^AO_O__B<*#Q!"X`````&8[5?H/GL"+7?S)PY!5B>564X/L$(MU +M"(.^0`$```-W7&:#OE0!``!`=5*#[`2-1?90_W4,5N@"____@\00NP````"% +MP'4*N`````#K1HUV`(/L!&H`#[:#B$T``%!6Z"G^__^#Q!!#@_L"=N2X```` +M`(/[`P^6P.L:C78`BU80BX)@F```@\@"B8)@F```N`$```"-9?A;7EW#B?95 +MB>575E.#['R+11!FB466BWT(QX5\____`````(M5#&:+0@(E\`$```^WP#W` +M````#X2-`0``/<````!_$CV@````#X07`0``Z=H!``")]CU``0``=`L]4`$` +M``^%Q@$``(M5#&:+`BVA#P``9CWJ!'<=9HN'"`(``&:)18QFBX<*`@``9HE% +MBNF*````B?:+50QFBP(MC!0``&8][P!W&V:+APP"``!FB46,9HN'#@(``&:) +M18KK7XUV`(M5#&:+`BU\%0``9CW@`'<;9HN'$`(``&:)18QFBX<2`@``9HE% +MBNLSC78`BU4,9H$Z7!9V&F:+AQ0"``!FB46,9HN'%@(``&:)18KK#HGV9L=% +MB@``9L=%C```QT6``````,=%A`````!FBX>N`0``9HE%E&:+A[0!``!FB462 +MN`````!F@[^T`0````^4P&:)19!FBX<"`@``9HE%CNG4````9HN'&`(``&:) +M18QFBX<:`@``9HE%B@^WER`"``")580/MXV`0``9HE%DK@`````9H._M@$````/E,!FB4609HN'!`(``&:)18[K')@(``(E%@&:+ +MA[(!``!FB4649HN'N`$``&:)19*X`````&:#O[@!````#Y3`9HE%D&:+AP8" +M``!FB46.ZP^-=@"X`````.D?`P``B?:[`````(U-F`^W59:^8#@``(UV`(T$ +M6XT$0HL$AHD$F4.#^Q!V[HM5#(!Z`@!Y*H/L#&H`:G=J`_]UA(U=F%/HY`(` +M`(/$%&H`:GIJ`_]U@%/HT@(``(/$(+L`````B?:-!%N+50B+2A"+%,5@.``` +MC468BP28B00*_X5\____]X5\____/P```'4-@^P,:@'H_/___X/$$$.#^Q!V +MPKL`````OO@_``"-!-T`````BU4(BTH0BQ0PBT0&!(D$"O^%?/____>%?/__ +M_S\```!U#8/L#&H!Z/S___^#Q!!#=,>^`````(GVC11VBT4(BU@0BPS5"$`` +M``^W19:-%%"+!)4(0```B009_X5\____]X5\____/P```'4-@^P,:@'H_/__ +M_X/$$$9TO;X`````C11VBT4(BU@0BPS5.$````^W19:-%%"+!)4X0```B009 +M_X5\____]X5\____/P```'4-@^P,:@'H_/___X/$$$9TO;L`````C4V8#[=5 +MEKYH0```C01;C01"BP2&B0290X/[$';NBU4,9HM"`B5``0``9CU``74T@^P, +M:@-J,VH!#[>'@`(``%"-79A3Z&8!``"#Q!1J`VHM:@$/MX>"`@``4%/H3P$` +M`(/$((/L#&H`:E]J`0^W19!0C5V84^@U`0``@\04:@!J8&H$#[=%E%!3Z"$! +M``"#Q!1J`&IH:@,/MT6,4%/H#0$``(/$%&H`:FMJ`P^W18I04^CY````NP`` +M``"#Q""0C01;BU4(BTH0BQ3%:$```(U%F(L$F(D$"O^%?/____>%?/___S\` +M``!U#8/L#&H!Z/S___^#Q!!#@_L0=L*[`````(U-F`^W59:^4$D``)"-!%N- +M!$*+!(:)!)E#@_L'=NZ#[`QJ`&H=:@8/MT6.4(U=F%/H=P```(/$%&H`:@1J +M`0^W19)04^AC````NP````"#Q""-=@"-!%N+50B+2A"+%,5020``C468BP28 +MB00*_X5\____]X5\____/P```'4-@^P,:@'H_/___X/$$$.#^P=VPL>'Q`L` +M``````"X`0```(UE]%M>7UW#C78`58GE5U93@^P4BW40BUT45O]U#.C\____ +MB47PC7O_P>\#2X/C!X/$$(7V?FZ+11C!X`.)1>R-=@"-#!Z#^0A^!;D(```` +MN@$```#3XDJX`0```(C9T^!(,<**3>S3XHG1]]&+10@C#+B)3>B+1?"(V=/@ +MBDWLT^`AT`M%Z(M5"(D$NHUT,_BY"````"G9TVWPNP````!'A?9_GHUE]%M> +M7UW#B?95B>575E.#[`R+=0B+10QFBU`"B=!FP>@'B<�&)3?")T"7P`0`` +M/=````!T;3W0````?Q(]H````'17/<````!T6.M>B?8]4`$``'08/5`!``!_ +M"CU``0``=`KK19`]0`D``'4]OP````"+10B+2!"+D429``"#XL`#@^`X"<*)D429``#K'HGVOP$```#K%9"_`@```.L-D+@`````Z08"``") +M]HM5"(M*$(N!$)D``"4&_/__#[>4?KH!``#!X@0)T(/(`8F!$)D``(/L!/]U +M#/^VN`L``/]U".C\____@\00BTT(BU$09HN$?J(!```E_P$```T``@``F(F" +M:)D``(M%"(M($(N11)@``('B?\#__P^WA'YX`0``P>`')8`_```)PHF11)@` +M`(M5"(M*$(N12)@``('B_P_\_P^WA'Y^`0``P>`,)0#P`P`)PHF12)@``(M- +M"(M9$(N+4)@``('A``#__XV7D`$```^^1#(/P>`()0#_```/ME0R#`G0"<&) +MBU"8``"+10B+6!"-C#^0`0``#[<4,8G0P>`8P>(0"=`/MTPQ!HG*P>(("=`) +MR(F#-)@``(M5"(M*$(N1*)@``##V#[>$?H0!``#!X`@)PHF1*)@``(M%"(M( +M$(N19)@``('B_P_X_P^WA'Z*`0``P>`,)0#P!P`)PHF19)@``+L"````9H&^ +M4`$```(P=QV+50AF@7H&(A!U,(M-#/9!`D!T)[L(````ZR")]HM5#&:+`H/@ +M'W03@^@*9H/X#'8*#[>$?OP!```!PXM%"(M($(N1))D``('B`?___XT$&R7W +M````"<*)D229``"+50B+6A"+3?#1X8'!8`(```^W1#$*P>`%BY,@F0``"=`/ +MMU0Q#@G0#0`(``")@R"9``"X`0```(UE]%M>7UW#58GE5U93BWT(BU4,N``` +M``#V0@(0#Y7`2(/@V(V$@)`!``#!X!B)QM'N#[<2B?")T;H`````]_&)QKL? +M````N`````"%P'402W0-B?"(V=/HJ0$```!T\+@F````*=B)P[D7````*=FZ +M`0```-/BC10RN1@````IV=/JC4OPBU\0BX,4F```)?__`0#!XA$)T(F#%)@` +M`(M7$(N"%)@``"7_'_[_P>$-@>$`X`$`"575E.! +M[,0```"+=0R+70B-O6C____\N`````"Y(````/.KC;U(____N0@```#SJXV% +M1O___U"-A43___]0BU4(BX+("P``#[>$`(Q-``!05HV%2/___U!2Z*0&``"# +MQ""%P'0L@^P,BY,$"P``5HV%1O___U"-A43___]0C85H____4/]U"/]2"(/$ +M((7`=0VX`````.G'`0``C78`@[M(`0``07="9HM&`B7`````9CW``'4S#[:+ +M<`$``+IG9F9FB(8BX54____@^`_P>`0"<)F +MBX52____@^`_#[?`P>`("<*+A5#___^#X#\/M\`)PHF1.)D``(M%"(M($(N5 +M7/___X/B/\'B&&:+A5K___^#X#_!X!`)PF:+A6;___^#X#\/M\#!X`@)PHN% +M6/___X/@/P^WP`G"B9$TH@``BU4(BTH0BY5D____@^(_P>(89HN%8O___X/@ +M/\'@$`G"BX5@____@^`_#[?`P>`("<)FBX5>____@^`_#[?`"<*)D3BB``"+ +M50B+0A#'@#R9```\````N`$```"-9?1;7E]=PU6)Y5=64X'L7`$``(M5"&;' +MA;[^__\``&;'A;S^__\_`(M-&&:+00(E\`$```^WP#W0````#X21````/=`` +M``!_%CV@````=%L]P````'1\Z9\```"-=@`]4`$``'06:+@IH"``!FB87,_O__C8*&`@``B87(_O__C8*< +M`@``B870_O__ZUV09HN"I`0``&:)A#^S]^ +M[V:)O=[^__]FQX7:_O__`0!FQX7<_O__/P"_`````&:#O=[^__\`=#:-=@"# +M[`3_M;3^__^+C<3^__\/MP1Y4(M5&`^W`E#H3`H``&:)!'Z#Q!!'#[>%WO[_ +M_SG'?,UFBPX/MX7>_O__9HM$1OYFB87"_O__OP````#K%HT47F:+0OYF.P1> +M?@AFBP1>9HE"_D_O__.<=](V8[#'Y\"V:+#'YFB;V^_O__B?CWT&8# +MA=[^__\/M]B%VW6\OP````!F@[W>_O__`'0M#[>=WO[__XGV9HN%PO[__V8[ +M!'Y]$F:+!'YFB87"_O__9HF]O/[__T)^/?IP?H$B?C!^!\IPHG00#G#?36X'X7K4??OP?H$B?C!^!\I +MPD*)]@^WA;K^__]FB[V^_O__BTT,9HD\06;_A;K^__]#.=-\W[L`````#[>% +MWO[__XG"BXW`_O__9CM,1O[IZ0```)!F@X7`_O__,HG0B86L_O__B[W`_O__ +M9CM\1OY]6`^_UXG7#[\$7HG1*<$/OT1>`BG"#Z_*A`HGY*<&)R`^O +MT(72?].#[`R+O<3^__\/MT1?`M'@#[?`4`^W!%_1X`^WP%`/MT1>`E`/MP1> +M4`^WA<#^__]0Z#T&``!`#[>5NO[__V;1Z(M-#&:)!%&#Q""+O;S^__]F.?AV +M!&:)/%%F_X6Z_O__#[>5WO[__XN%P/[__V8[1%;^?2QF@[VZ_O__/P^&"/__ +M_^L7UW#C78`58GE5U93BW4,BUT(N@````!F@[LH`@```'1)C4,*B<$/ +MMX`@`@``.?!T.0^WNR@"``")]@^WA%$@`@``.?!U$(G0P>`&C808=`8``.L; +MB?9".?I]#XU+"@^WA%$@`@``.?!UT+@`````6UY?7<.)]E6)Y5=64X/L1(MU +M#(M%%&:)1<:+?0C_=1!7Z/S____1X&:)1<2+51QFQP+._XM-&&;'`3(`@\0( +M_W405^C\____B,.#Q`@/ML-05^A`____@\00A'/`8``%"-ASX&``!04NL:D(/L#(U%V%`/MX?J!0``4(V'[`4``%#_ +M=1#_=0CH:P0``(/$(&:+1<)F.T7>=@1FBT7>9HD&BTT0]D$"$'0<9H&_4`$` +M```P=A%FBY=>`0``9CG"=@*)PF:)%@^W#@^W5<0/OD7!*<(YRGX"B!F*<*)T&:%P'X'9HD&ZP>)]F;'!@$`9HL&9HE&"&:)1@9FB48$9HE&`HM% +MW&8[!G8#9HL&9HE&"F:+1=IF.P9V`V:+!F:)1@R+1=AF.P9V`V:+!F:)1@YF +MBP9FB48>9HM&#HM5&&:)`F:+!HM-'&:)`0^W!HF'S`L``(M%$&:+4`*)T"7` +M````9CW``'01B=`EH````&8]H``/A'7`8``%"-AUX& +M``!0_W40_W4(Z%D#``")V(/$(&8[109L=&$`$`BT7,9CM&$'8$ +M9HM&$&:)1A)FB4849HM%RF8[1A!V!&:+1A!FB4869HE&&(M%R&8[1A!V!&:+ +M1A!FB48:9HE&'`^WT(M-&`^_`3G"?0=FBT8:9HD!#[=6$HM-'`^_`3G"?@=F +MBT829HD!BU409HM"`B6@````9CV@`'4*#[=&$(F'S`L``+@!````C67T6UY? +M7<-5B>575E.#[$R-?.-=@"+1;QF@SP#`'D&9L<$`P`` +M9H-]Q`AU"6;'1<0/`.M5D(M]N-'GC77(#[\4-P^W3<2+10P/MP1(.<)U-8M5 +M#&:#/$H`=0=F_P0WZQB09H-]PC)V"8M%O&;_!`/K!XM5O&;_#!-FQT7$``!F +M_T7"ZP609O]%Q&:#?<0/=H4/MT7&T>"-57UW#C78`58GE5U93@^P$ +MBT4(9HE%\HM-#(M]$(M=%(MU&`^WPP^WU@^OPH7`=0>X`````.ME9CG/=%L/ +MMT7R#[?)*UFB572@^P,#[=UTHTTMM'FBU40#[=$,@90 +M#[??C1R;T>,/MT0:!E`/MT764`^W1=10BWT,#[<'4.B8_O__BU489HE"!H/$ +M%(M]$`^W1#<$4`^W1!\$4`^W1=90#[=%U%"+50P/MP)0Z&G^__^+?1AFB4<$ +M@\04BU40#[=$,@)0#[=$&@)0#[=%UE`/MT744(M]#`^W!U#H.O[__XM5&&:) +M0@*#Q!2+?1`/MP0W4`^W!!]0#[=%UE`/MT744(M5#`^W`E#H#?[__XM]&&:) +M!XUE]%M>7UW#C78`58GE5U93@^PY0#[='!%#_-P^W]E;H>0$` +M`(/$%(U%[%"-1>I05P^W1>Y0#[?;4^@/`@``@\04C47H4(U%YE!7#[=%\%!3 +MZ/@!``"#Q""-1>105P^W1>I0#[=%[E#HI0```(U%XE!7#[=%[%`/MT7N4.B1 +M````@\04#[=%XE`/MT7D4`^W1>Q0#[=%ZE!3Z#3]__]FB47@@\0@C47D4%)05P^W1>A0#[=%\%#H10```(/$%`^W1>)0#[=% +MY%`/MT7H4`^W1>904^CH_/__@\04#[?`4`^W1>!0#[=%\%`/MT7N4%;HS/S_ +M_P^WP(UE]%M>7UW#D%6)Y5=64X/L"(M%"&:)1?*+?0R+51"+2@B^`````&:# +M>@0`=%J-=@!FBT7R9CD!=3^-60BZ`````&:#>08`=#"-00Z)1>R)]F8Y.W47 +MBTWL9HM$41"+511FB0*X`0```.LBB?:#PP)"#[=!!CG"?-B#P31&BU40#[=" +M!#G&?*FX`````(/$"%M>7UW#58GE5U93BU4,BWT4BW48#[=-"(T$B8T$@(T, +MA0`````/MT40C1Q"#[<"C02`C02`C02%]O___SG!564XM=$(MU"(M-#(M3"+@`````9H-[!`!T&&8Y +M"G03#[=;!(GV@\(T0#G8?05F.0IU\X/L#/]U&/]U%`^W0@90C4((4`^WQE#H +M`/___XUE^%M>7<.058GEBU4(C8J8"@``H:1-``")@I@*``"+%:1-``"-!-4` +M````*="-!(6H30``B4$8QT$4`0```,=!#!0```#'01`C````7<.058GE5U93 +MBU4,BT4(!<0*``#V0`(@="6_`````+D<````NT````"^<@```,="#`````#' +M0A!W````ZR.0OP````"Y,@```+L`````OC(```#'0@P4````QT(0(P```(M2 +M!+@`````.?IR!#G*=@TYVG($.?)V!;@!````6UY?7<-5B>6+10B+2!"+D,P+ +M``#!X@F!X@!^``"!R@"```")D3"9``#'@,0+```!````7<-5B>575E.#[`R+ +M=0B)]XV>F`H``+@`````@WL4`'1W@[[$"P```75HBT<0BX`PF0``9H7`>%K! +MZ!F)0P3'AL0+````````@^P(4U?H`/___X/$$(7`=3F#[`A35^@_````@\00 +MA&Q`L```(```"#Q!"+ +MAL0+``"-9?1;7E]=PXGV58GEBTT,N`````"+400[40QV!3M1$'(%N`$```!= +MPY!5B>564XM=#+C_____@WL4``^$$@$``(L#C13%`````"G"C125J$T``(E3 +M&(M#!#M#$')LN/____^#.P`/A.<```"+0P2)0P@[0Q!R2(,[`'1#OK!-``"0 +MBP-(B0.-%,4`````*<*+2QB+!)8K00C1X"E#"(L3C035`````"G0C02%J$T` +M`(E#&(M#"#M#$'($A=)UP[@!````Z8H```"0BT,$.T,,=WRAH$T``$@Y`W4* +MN/[____K<(UV`(M#!(E#"#M##'=4H:!-``!(.0-S2KZP30``B?:+`T")`XT4 +MQ0`````IPHM+&(L$EBM!"-'@*4,(BQ.-!-4`````*="-!(6H30``B4,8BT,( +M.T,,=PJAH$T``$@YPG*]N`(```#K!XGVN`````!;7EW#C78`58GEBTT(BU4, +M@WH4`'0WBT(89HL`9HF!A`(``(M"&&:+0`)FB8&"`@``BT(89HM`!&:)@8`" +M``"+0AAFBT`&9HF!?@(``%W#58GE5U93@^P4N`````"+50SV0@(0#Y3`2(/@ +MXH/`(%#_=0CH_/___XG&@\00OP````!F@SX`=$"#[`QJ`(T<_2`````/MD0S +M"5!J#E;_=0CH_/___P^V5#,&P>("BUT(BTL0#[?`B80*`(<``(/$($-'(.#[`QJ`0^V1#() +M4&H.5E'H_/___XM-"(M1$`^WP(D$$X/$($575E.#[!2+70B+@\`*```E____?U!3Z/S___^)1?"+0Q"+4#")UH'F\`,` +M`,'N!(GW@\00@WT,`'0/N"4````I\-'HC3PPZP>0@_X!=@%/.?=T&(M+$('B +M#_S__XGXP>`$)?`#```)PHE1,(/L"/]U\%/H_/___X/$$+@`````.?564XMU#(M5"(/^`G08@_X"=P>#_@%T)NM2@_X#=`^#_@1T +M$NM&N0D```#K29"Y"````.M!D+D!````ZSF0N0````"#N@P+````=!N-6@R- +M=@!!@_D)?P^)R,'@!(.\`P`+````=>N#^0IU"KC_____ZT:-=@")R,'@!(FT +M$`P+``"#?1``=`VX`0```-/@"8(("P``B6+30R+50BX`````(/Y"7<[B`$QX00#`L```````"X_O___]/`(8(( +M"P``N`$```!=PU6)Y5=64X/L$(MU"(V6Q`H``+@`````@WT,"0^'S0(``(M% +M#,'@!(V\,`P+``"X`0```(,_``^$L@(``(.^V`L```!U,X72=!MFBT("):`` +M``!F/:``=0S'AM`+```?````ZPK'AM`+```/````QX;4"P```@```(N&U`L` +M``-'!(E%\+H!````.Y;0"P```*BTT,P>$"BUT( +MBU,0#0````&)A!$`"0``BTT,P>$"BU,0BX01`!$```T```0`B801`!$``.L= +MBTT,P>$"BT4(BU`0BX01P`D``(/(((F$$<`)``"+50B+2A"+A@@+``")PH'B +M_P,``,'@$"4``/\#"<*)D:0```"+30B+41"+A@@+```E_P,``(F"J````(M= +M"(M+$(N!K````"4`_/__BY8("P``@>+_`P``"=")@:P```"X`0```(/$$%M> +M7UW#B?95B>6+10R#^`EV";C_____ZQ:)]HT4A0````"+10B+0!"+A`(`"``` +M7<.)]E6)Y593BUT(BU4,BW40B=FX`````(/Z"77<.)]E6)Y5.+70B+30R)VK@` +M````@_D)=RN)R,'@!(.\$`P+````=0>X`````.L5BU,0N`$```#3X(F"0`@` +M`+@!````BQPDR<.)]E6)Y5.+70B+30R)VK@`````@_D)=T:)R,'@!(.\$`P+ +M````=0>X`````.LPC02-`````(M3$(N$$``*``")PX/C`W46N`$```#3X(N2 +M0`@``(7"=`6[`0```(G8BQPDR<.-=@!5B>575E.#[`R+?0B+=0R)^K@````` +M@_X)=V^)\,'@!(.\$`P+````=0JX`````.M9C78`BU<0N`$```")\=/@B8*` +M"```N^@#``#K$8UV`(/L#&IDZ/S___^#Q!!+A=MT$8/L"%97Z/S___^#Q!"% +MP'7=BT<0QX"`"````````+@`````A=L/E<"-9?1;7E]=PXGV58GEN`$```!= +MPXGV58GE5U93BW4PBUT,@\,(N`````"#?20`#X2?`0``N!\```"*31C3^*D! +M````#X1,`0``N`#_`'^*32#3^*D!````#X0W`0``B?"#X`R#^`P/A"D!``#\ +MN`````"Y!@```(G?\ZN+51"!XO\/``!FBP,E`/````G09HD#BDT<@^$_BD," +M@^!`B?+!Z@7!X@<)R`G0B$,"B?�&*4P.!XN````"*12R#X`_1X`G*"<*) +M\,'H!(/@`<'@!8C1@^'?"<&(2P.#?2C_=!^+12B#X'_!X`V+4P2!XO\?\/\) +MPHE3!(C(@\A`B$,#BE48P>($BD,&@^`/"="(0P:)\-'HB,*#X@&*0P +M7UW#B?95B>575E.#[`2+712+51B+=2"+?2B+10R#P`B)1?"%TG0XN`#_`'^( +MV=/XJ0$```!T?<'B!(M-\(I!"H/@#PG0B$$*B=J#XA_!X@5FBT$,)1_\```) +MT&:)00R%]G0\N`#_`'^*31S3^*D!````=$")\H/B#XM-\(I!"R7P````"="( +M00N*51R#XA_!X@**00TE@P````G0B$$-A?]T0[@`_P!_BDTDT_BI`0```'4) +MN`````#K,(GVB?K!X@2+3?"*00N#X`\)T(A!"XM5)(/B'\'B#XM!#"7_?_#_ +M"=")00RX`0```(/$!%M>7UW#B?95B>53BUT,C4L(@WT4`'4($BD$%)>\````)T(A!!<=#'`````#'0Q@`````N`$` +M``"+'"3)PXGV58GEBTT,C5$(]D(4`74-N`\```#IO@```(UV`&:+0A1FT>@E +M_P\``&:)02`/MT(29HE!(L9!)`#V0A`!=1[V0A`"=`3&020!]D(0"'0$@$DD +M`O9"$`1T!(!))`2*0A;`Z`6#X`.#^`%T(H/X`7\)ALWC78`@_@"=!N# +M^`-T'NLH#[9"#.LL0B?:*0@W`Z`+K!HM"#,'H#X/@'XA! +M)8M"%,'H#8A!)HI"$,#H!(A!)P^V0A&#X`^(02B*0A>#X`%`B$$JN`````!= +MPXUV`%6)Y5.#[!"+70AH+"<``.C\____B8/D#0``QP0D+"<``.C\____B8,$ +M#@``N`````"#Q!"#N^0-````=`Z#NP0.````=`6X`0```(M=_,G#58GE5U93 +M@^P,BW4(OP````"-=@"-'+V@#0``@SPS`'05@^P,_S0SZ/S____'!#,````` +M@\001X/_'W;8C67T6UY?7<-5B>575E.#[`R+=0B)=?"-OL0*``"+GAP,``"% +MVW0M9HL#9CN&Q`H``'4AB=CIA@```(GVB9X<#```B=CK>HGVBP>)@B`,``") +MV.MLN0````"-=@"-!$F-!(:-F"`,``!FBX`@#```9CL'=,A!@_D?=N*Y```` +M`)"-!$F-%(:-FB`,``!F@[H@#````'2R08/Y'W;D@^P,#[='`E`/MP=0:`L& +M``!H``4``/]U\.C\____C88@#```C67T6UY?7<-5B>575E.![,P```"+50RX +M`````(/Z!0^'Z@,``/\DE)_@/__C46(BP28P>`')8!_```)PHF17)@` +M`(M%"(M($(N17)@``('B_W_`_XU%J(L$F,'@#R4`@#\`"<*)D5R8``"+50B+ +M2A"+D5B8``"!XO__`_R-A6C___^+!)C!X!(E``#\`^F7`@``C78`QX5D____ +M`````,>%8/___W\```"-A6#____'0`0R````QX58____?P```,>%7/___R@` +M``#'A5#___]_````QX54____30```,>%2/___W\```#'A4S___]`````QX5` +M____'P```,>%1/___Q````#'A3C___\_````QX4\____,````,>%,/___P(` +M``#'A33___\"````N0````"#?1``#Y7!BU4(BUH0BY-LF```@>+_/^#_BP2( +MP>`.)0#`'P`)PHF3;)@``(M%"(M8$(N3;)@``('B__\?\(V%6/___XL$B,'@ +M%24``.`/"<*)DVR8``"+50B+6A"+DVB8``"!XO__`?^-A5#___^+!(C!X!$E +M``#^``G"B9-HF```BT4(BU@0BY-HF```@>+___^`C85(____BP2(P>`8)0`` +M`'\)PHF3:)@``(M5"(M:$(N#:)@``(/@X(V50/___XL4BH/B'PG0B8-HF``` +MBT4(BU@0BY-LF```@>+_P/__C84X____BP2(P>`()0`_```)PHF3;)@``(M5 +M"(M:$(N3))D``('B`?___XV%,/___XL$B-'@)?X````)PHF3))D``(7)=!V+ +M10B+4!"+@FR8``"#R`&)@FR8``#I"0$``(UV`(M%"(M0$(N";)@``(/@_HF" +M;)@``.GL````B?;'A2S___\`````QX4H____"````(V=*/___\=#!`8```"Z +M`````(-]$``/E<*+10B+2!"+@0BB``"#X,"+%).#XC\)T(F!"*(``.F;```` +MD(V]:/___[[D$```_+D#````\Z6+71"X`````(/[`G=_BU4(BTH0BY%8F``` +M@>+_#_S_C85H____BP28P>`,)0#P`P"0"<*)D5B8``#K3(GVC;UH____OO`0 +M``#\N0@```#SI8M=$+@`````@_L'=R^+10B+2!"+D229``"!X@'___^-A6C_ +M__^+!)C1X"7^````"<*)D229``"X`0```('$S````%M>7UW#B?95B>574XM] +M#(M5$*$`````C02`C02`C02`C02`P>`#B0>A`````(T$@(T$@(T$@(T$@(T$ +M@(T$@,'@!HE'!(G0@ST``````'0'#Z\%`````(E'",='#`````"#[`S_=0CH +M_/___XG#BU<$N=--8A")T/?AP>H&B=@IT(E'$,='%`````#'1Q@`````BT<( +M@\<<_(T4A0````"[`````(G1P>D"B=CSJXG0@^`"AP<`=#Z`>P4`=3B#[`3& +M0P<`:@%J`E?H_/____^&Y`H``(/$#/Y#!0^V0P50:@57Z/S_____AMP*``#I +MM````(UV`(![!`!T'H/L!/Y+!`^V0P10:@%7Z/S_____AM@*``#IC0```(![ +M!@!T'H/L!/Y+!@^V0P90:@17Z/S_____AO@*``#K;(UV`(!["`!T&H/L!,9# +M"`!J`&H#5^C\_____X;P"@``ZTJ0@'L%`'0BQD,)`8/L!/Y+!0^V0P50:@57 +MZ/S_____AN`*``#K)(UV`(![!P!T2,9#"0&#[`3&0P<`:@%J`E?H_/____^& +MY`H``(/$$(/L!/\U`````/^VY`T``%?HL_S__X/$#/\U`````/^V!`X``%?H +MGOS__XUE]%M>7UW#B?95B>575E.#[!B+?0B)_E?HK/?__XG#_X?("@``@\00 +M@'L$`'4G@'L)`'4A@^P$QD,$!&H$:@%7Z/S_____AM`*``"#Q!#I;@$``(GV +M@'L$`WPD`=`K&0PD`Z2#___^0 +M@^P(C8;$"@``4%?H_/___X/$$(/X`W=,@_@"`>P@`=1J#[`3&0P@!:@%J +M`U?H_/____^&[`H``(/$$(![!@%W(8/L!/Y#!@^V0P90:@17Z/S_____AO0* +M``"#Q!#K5XUV`,9#"@&#[`Q7Z/S___^#Q`@E__[__U!7Z/S_____AOP*``"# +MQ!"#[`3_-0````#_MN0-``!7Z/;Z__^#Q`S_-0````#_M@0.``!7Z.'Z___K +M+8UV`(/L!/\U`````/^VY`T``%?HQ_K__X/$#/\U`````/^V!`X``%?HLOK_ +M_XUE]%M>7UW#B?95B>575E.#[!B+=0B)]U;HP/7__XG#@\00@'L$`'03@^P$ +M#[9#!%!J`5;H_/___X/$$(![!0!T$X/L!`^V0P50:@56Z/S___^#Q!"`>P<` +M=!N#[`2X`````(![!P`/E,!0:@)6Z/S___^#Q!"`>P@`=!.#[`0/MD,(4&H# +M5NC\____@\00@'L&`'03@^P$#[9#!E!J!%;H_/___X/$$(!["@!T&X/L#%;H +M_/___X/$""7__O__4%;H_/___X/$$(/L!/\U`````/^WY`T``%;HU/G__X/$ +M#/\U`````/^W!`X``%;HO_G__XDT).C\____@\0(#0`!``!05NC\____C67T +M6UY?7<-5B>5=PXUV````!0`*`!0`'@`R`$8`50!:`%\`9`````H`%``>`"@` +M,@`\`$8`4`!:`&0`P@```,0```#%````T````-H```#D````P@```,,```#4 +M````\@````T!```H`0``_P$``$1"`$1%0E5'`````````````````0````$` +M`````!``3D$`3D]?0T]53E1265]3150````!``````````@``P!!3`!!3$)! +M3DE!``````````````$`````````#``#`$1:`$%,1T5224$````````````` +M`0`````````@`%(`05(`05)'14Y424Y!`````````````````````"0`(0!! +M50!!55-44D%,24$```````````$`````````*``V`$%4`$%54U1224$````` +M`````````0`````````X`#``0D4`0D5,1U5)30`````````````!```````` +M`$P`4P!"4@!"4D%:24P`````````````````````````?``@`$-!`$-!3D%$ +M00```````````````0````$```"8`%0`0TP`0TA)3$4````````````````! +M`````````)P`1`!#3@!#2$E.00````````````````$````!````G`!3`$-/ +M`$-/3$]-0DE!`````````````0````````#0`#``1$L`1$5.34%22P`````` +M```````!`````````-H`4@!%0P!%0U5!1$]2``````````````$````!```` +M]@`P`$9)`$9)3DQ!3D0``````````````0````````#Z`#(`1E(`1E)!3D-% +M```````````````!`````````!0!-0!$10!'15)-04Y9``````````````$` +M````````6`$1`$A+`$A/3D=?2T].1P```````````0````$```!T`3``244` +M25)%3$%.1``````````````!`````````'P!-0!)5`!)5$%,60`````````` +M``````$`````````B`%``$I0`$I!4$%.`````````````````0````````": +M`44`2U(`2T]214%?4D5054),24,````!`````0```+X!$0!-3P!-04-!50`` +M``````````````$````!````Y`%3`$U8`$U%6$E#3P```````````````0`` +M``$````0`C8`3DP`3D542$523$%.1%,````````!`````````"H"(0!.6@!. +M15=?6D5!3$%.1`````````$````!````0@(V`$Y/`$Y/4E=!60`````````` +M`````0````````!/`E(`4$$`4$%.04U!```````````````!`````0```%P" +M4@!010!015)5``````````````````$`````````8`(1`%!(`%!(24Q)4%!) +M3D53`````````0````$```!H`C4`4$P`4$],04Y$```````````````!```` +M`````'8"$`!04@!054525$]?4DE#3P````````$````!````O@)"`%-'`%-) +M3D=!4$]210```````````0````$```#P`C``4T4`4U=%1$5.```````````` +M```!`````````/0"-0!#2`!35TE46D523$%.1`````````$`````````G@!# +M`%17`%1!25=!3@```````````````0````$````Z`S``1T(`54Y)5$5$7TM) +M3D=$3TT````!`````````$@#$`!54P!53DE4141?4U1!5$53``````$````! +M````7@-2`%9%`%9%3D5:545,00```````````````````````/\!_P$@`"`! +M$`HA`"`!F0$U`#`"F0$V`#`#F0$R`#`#,`HP`#`!F0$1`!`!F0$0`!`!$`I% +M`%`"F0%2`%`!F0%3`%`!$`I4`%`!4`I$`%`!4`M``$`!0`I"`%`$F0%#`%`# +M$`I@`&``8`!A`&$`80!B`&(`8@!C`&,`8P!D`&0`9`!E`&4`90!F`&8`9@#_ +M`0(`$```%$06!09Q%L$6!08```````````````!0`0$`$`!Q%L$6'@`````` +M``````````````````!0`@$`$`!Q%JT6%P````````````````````````!0 +M`P(`$`",%,@4$09Q%L$6'@8```````````````!0!`(`$``\%'@4%`!Q%L$6 +M%``````````````````P`0(`,``\%,@4%`!\%406&P`````````````````P +M`@$`,``\%,@4$@`````````````````````````P`P$`,``\%,@4%``````` +M```````````````````0`0,`$`",%,@4%P8\%'@4$09Q%L$6'@8````````@ +M`0(`$``\%,@4%P9Q%L$6'@8```````````````!``0$`0``R%&X4%P`````` +M``````````````````#_`0(`$``*%"86!08>%!(6!08````````````````0 +M`0,`$`""%*H4%P9:%%H4$0:`%J@6'@8```````#_`0,`_P!L":@)!0:T";0) +M!0;0":P*!08```````!0"@$`_P!L":@)$0````````````````````````!0 +M"P$`_P!L":@)"`8````````````````````````P"@$`_P"4":@)%``````` +M```````````````````0"@$`_P!L"9X)&P8```````````````````````!` +M"@(`_P!L":@)%`"T";0)%`````````````````"9`0$`_P!L":@)%``````` +M``````````````````!@`````0`````````)````A````(P```"4````G``` +M`*0```"L````M````+P```#$````80``````````````"0```(0```",```` +ME````)P```"D````K````+0```"\````Q````&(````"````<`````D```"$ +M````C````)0```"<````I````*P```"T````O````,0```!C`````0`````` +M```'````A````(P```"4````G````*0```"L````O```````````````9``` +M``$`````````!P```(0```"4````G````*0```"L````M````+P````````` +M`````&4````"````>@````@```"$````C````)0```"<````I````*P```"T +M````O`````````!F`````@```'H````(````A````(P```"4````G````*0` +M``"L````M````+P`````````0`&(`4`!``#,````$`%(`U`!``#6````,`$Z +M`T`!``#B`````@!0`0$`0`$$`*``"`#````````````````````````````` +M```````````D`9@9```````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````````"8"````````(`(```0````=`@``"````!@"```,```` +M%`(``!0````0`@``'`````P"```@````"`(``"0````$`@``*````/X!```P +M````^`$``#0```#S`0``0````.X!``!$````YP$``$@```#@`0``3````-H! +M``!0````U`$``%0```#/`0``6````,P!````0```R`$```1```#``0``"$`` +M`+P!```,0```M0$``!!```"N`0``%$```*D!```@0```H0$```"```"9`0`` +M!(```)$!```(@```B0$```R```"``0``$(```')@` +M``0`````F0````````29````````")D````````,F0````"``!"9```#```` +M`)L````````$FP``(`````B;```0````#)L``#`````0FP``"````!2;```H +M````&)L``"@````)L``"T```!\FP```P```(";```C````A)L``!,` +M``"(FP``,P```(R;```+````D)L``"L```"4FP``!P```)B;```G````G)L` +M`!<```"@FP``-P```*2;```/````J)L``"\```"LFP``+P```+";```O```` +MM)L``"\```"XFP``+P```+R;```O````P)L``"\```#$FP``+P```,B;```O +M````S)L``"\```#0FP``+P```-2;```O````V)L``"\```#`@``*(```-<"```L@```T`(``#"```#)`@``-(```,$"```X@``` +MN`(``#R```"P`@``0(```*@"``!$@```H`(``$B```"8`@``3(```)`"``!0 +M@```AP(``%2```!_`@``6(```'8"``"`@```<@(``(2```!K`@``B(```&(" +M``",@```60(``)"```!0`@``E(```$<"``"8@``````````````````````` +M`#`````5````%0```!T````5````0!````_\+P`/_"\`'_PO``_\+P!$$``` +M#_PO``_\+P`?_"\`#_PO`$@0```/_"\`#_PO`!_\+P`/_"\`3!````_\+P`/ +M_"\`'_PO``_\+P!0$```#_PO``_\+P`?_"\`#_PO`%00```/_"\`#_PO`!_\ +M+P`/_"\`6!````_\+P`/_"\`'_PO``_\+P!<$```#_PO``_\+P`?_"\`#_PO +M`&`0```/_"\`#_PO`!_\+P`/_"\`9!````_\+P`/_"\`'_PO``_\+P!P$``` +M:`$``.`!``"X`0``:`$``#`0```P`@``X`$``+`````P`@``L!```)@-``"` +M$0``2!\``)@-``#P$```X*```&A``0"`6```X*```!2`````!``$``@`"``P +M`"``!``$'(```*>/C0[/CXT.E8]@`:>/C0X$F`````````,````````````` +M`""8`````@("``("`@`"`0(``@("))@```X.```.#@``!P<```X.```HF``` +M`0`""@$``@H```$%`0`""C28```.#@``#@X```X.```.#@``.)@```<````' +M````"P````L```!$F```G!9R$Z467373!O(!#@;X"A``#_%/\%_Q3_!?\4 +M_P7_&?\%U)@``!`````4````$````!`````,`````````"@```"@%J($R8```\88025)@` +M`%D(``!HF```D$&:0&R8``"!L`P%<)@```\```!TF```@````'B8```,```` +M`)D````````$F0````````B9````````#)D`````@``0F0```0```!R9```J +M"0``()D````````DF0``!8H%`"B9```!````+)D````````PF0```````#29 +M````````.)D````````\F0``/P```$"9```$````2)D```````!,F0`````` +M`%"9````````5)D``$SQ4%U8F0``&````%R9``".:DL`A*$``/\%_P:(H0`` +M_P?_!XRA``#_"/\(D*$``/\)_PF4H0``_PK_"IBA``#_"_\+G*$``/\,_PR@ +MH0``_PW_#:2A``#_#O\/J*$``/\2_Q*LH0``_Q/_%+"A``#_%?\6M*$``/\7 +M_QFXH0``_QK_&[RA``#_'?\>P*$``/\@_R/$H0``_R7_)\BA``#_*?\LS*$` +M`/\O_S'0H0``_S3_-]2A``#_.O\ZV*$``/\Z_SK@`` +M`$D```"8F@``A@$``(D```"!0`` +M#(```!4%```0@```#`4``!2````#!0``&(```/X$```<@```]P0``""```#O +M!```)(```.@$```H@```X00``"R```#:!```,(```-,$```T@```RP0``#B` +M``#"!```/(```+H$``!`@```L@0``$2```"J!```2(```*($``!,@```F@0` +M`%"```"1!```5(```(D$``!8@```@`0``("```!\!```A(```'4$``"(@``` +M;`0``(R```!C!```D(```%H$``"4@```400``)B```!*!```U(```$,$``#8 +M@```/`0``-R````T!```X(```"P$``#D@```*`0``.B````@!```#($``!H$ +M``#L@```%`0``/"````.!```](````@$``#X@`````````````!4N@``;+H` +M`'RZ``!"TZ`W@M.@-X+3H#5B8```N#8!^+@V`?BY-Z'XN3>A^+@V`?F"8 +M```0G0``$)T``!B=```0G0``$)T``&28````S@$``,X!``#.`0``S@$``,X! +M`&B8``"009I`D$&:0)!!FD"009I`D$&:0!B9``"X`0``N`$``(0````(`0`` +MN`$``"29```%B@40!8H%$`6*!1`%B@40!8H%$$29```@$+C_(!"X_R`-N/\@ +M$+C_(!"X_X"A``#_%/\0_Q3_$/\0_Q#_&?\0_QG_$#"B```````````````` +M```(`0```````!R```"GCXT2SP^("94/X`2KCXT2SP^("228```.#@``#@X` +M``<'```.#@``#@X``"B8```!``(*`0`""@`!`04!``(*`0`""DB8``!:VA@` +M6MH8`&G*&`!IRA@`:9C9C9C9C^UHAG +M/M"(9S[0B&<^T`RB``!``2QD0`$L9&#!0F1@P4)D8,%"9`P`````````-``` +M``4```!``````````$0````(````2`````@```!,````$````%`````````` +M5````!\`````"`````````0(````````"`@````````,"````````!`(```` +M````%`@````````8"````````!P(````````(`@````````D"````````#`2 +M````````!$```````"X$0```````/@1````````.!(```````!X$@`` +M`````+@2````````^!(````````X$P```````'@3````````N!,```````#X +M$P```````#@4````````>!0```````"X%````````/@4````````.!4````` +M``!X%0```````+@5````````^!4````````X%@```````'@6````````N!8` +M``````#X%@```````#@7````````>!<```````"X%P```````/@7```````` +M/!````````!\$````````+P0````````_!`````````\$0```````'P1```` +M````O!$```````#\$0```````#P2````````?!(```````"\$@```````/P2 +M````````/!,```````!\$P```````+P3````````_!,````````\%``````` +M`'P4````````!(`````````(@`````````R`````````&(`````````@@``` +M`````"2`````````*(```#`````L@```__\'`#"```#___\!-(```#$````X +M@````````#R`````````2(````````!4@````````%B`````````7(```/_' +M__^`@````````(2`````````B(````````",@````````)"`````````E(`` +M``````"8@````````,"````:,((JQ(```.`!W`7(@```$"=`'\R``````/0! +MT(```!P>``#4@```JJH"`-B```!550`"W(````````#@@```_____^2```#_ +M_P``Z(````````#L@````````/"`````````](````````#X@````````/R` +M``"(`````(<````````$AP``C`````B'``#D````#(<``-4"```0AP`````` +M`!2'````````&(<``*`````(<``*(```!\AP````````"!```"``$` +M!($```$````(@0``P`````R!````````$($``&@!```4@0```````,"'```` +M`0(#Q(<```0%!@?(AP``"`D*"\R'```,#0X/T(<``!`1$A/4AP``%!46%]B' +M```8&1H;W(<``!P='A_@AP````$"`^2'```$!08'Z(<```@)"@OLAP``#`T. +M#_"'```0$1(3](<``!05%A?XAP``&!D:&_R'```<'1X?")@````````,F``` +M&8Z$K1"8````X"A]%)@``&N?"IP@%J($R8```\88025)@``%D(````F0````````29````````")D````` +M```,F0````"``!"9```!````')D``"H)```@F0`````0!2B9```!````+)D` +M``0````TF0``(B`?'CB9```-#`L*/)D``#\```!`F0``!````$B9```2LH"2 +M5)D``$SQ4%U8F0``_P```%R9``".:DL`:)D``,X#``!PF0``%;4O&729```` +M````>)D```$```!\F0```````(2A``#_$/\0B*$``/\0_Q",H0``_Q#_$)"A +M``#_$/\0E*$``/\0_Q"8H0``_Q#_$)RA``#_$/\0H*$``/\0_Q"DH0``_Q#_ +M$*BA``#_$/\0K*$``/\0_Q"PH0``_Q#_$+2A``#_$/\0N*$``/\0_Q"\H0`` +M_Q#_$,"A``#_$/\0Q*$``/\0_Q#(H0``_Q#_$,RA``#_$/\0T*$``/\0_Q#4 +MH0``_Q#_$-BA``#_$/\0W*$``/\0_Q#@H0``_Q#_$.2A``#_$/\0Z*$``/\0 +M_Q#LH0``_Q#_$/"A``#_$/\0]*$``/\0_Q#XH0``_Q#_$/RA``#_$/\0!*(` +M```````0H@``,Z.``!2B```0;"``&*(``&!`G``)H``,H!```.````?)H```H```!.````@)H``$H```".````A)H``(H` +M``!>`0``B)H``+H!``">`0``C)H``/H!``#>`0``D)H``#H````)````E)H` +M`'H```!)````F)H``(8!``")````G)H``,8!``!Y`0``H)H```8```"Y`0`` +MI)H``$8```#Y`0``J)H``(8````Y````K)H``,8```!Y````L)H``,8```"Y +M````M)H``,8```"]`0``N)H``,8```#]`0``O)H``,8````]````P)H``,8` +M``!]````Q)H``,8```"]````R)H``,8```#]````S)H``,8```#]````T)H` +M`,8```#]````U)H``,8```#]````V)H``,8```#]````W)H``,8```#]```` +MX)H``,8```#]````Y)H``,8```#]````Z)H``,8```#]````[)H``,8```#] +M````\)H``,8```#]````])H``,8```#]````^)H``,8```#]````_)H``,8` +M``#]`````)H```<````'````!)H``$<```!'````")H``(<```"'````#)H` +M`*`!``"@`0``$)H``.`!``#@`0``%)H``"`````@````&)H``&````!@```` +M')H``*$!``"A`0``()H``.$!``#A`0``))H``"$````A````*)H``&$```!A +M````+)H``&(!``!B`0``,)H``*(!``"B`0``-)H``.(!``#B`0``.)H``"(` +M```B````/)H``&(```!B````0)H``&,!``!C`0``1)H``*,!``"C`0``2)H` +M`.,!``#C`0``3)H``",````C````4)H``&,```!C````5)H``(0!``"$`0`` +M6)H``,0!``#$`0``7)H```0````$````8)H``.H!```+````9)H``"H```!+ +M````:)H``&H```"+````;)H``*H```"L`0``<)H``*L!``#L`0``=)H``.L! +M```L````>)H``"L````2````?)H``&L```!2````@)H``*L```"2````A)H` +M`*P!``"3`0``B)H``.P!``#3`0``C)H``"P````3````D)H``#H```!3```` +ME)H``'H```"3````F)H``+H```"4`0``G)H``+L!``#4`0``H)H``/L!```4 +M````I)H``#L````Z````J)H``'L```!Z````K)H``+L```"Z````L)H``+P! +M``"[`0``M)H``/P!``#[`0``N)H``#P````[````O)H``'P```![````P)H` +M`+P```"[````Q)H``/P```"\`0``R)H``/P```#\`0``S)H``/P````\```` +MT)H``/P```!\````U)H``/P```"\````V)H``/P```#\````W)H``/P```#\ +M````X)H``/P```#\````Y)H``/P```#\````Z)H``/P```#\````[)H``/P` +M``#\````\)H``/P```#\````])H``/P```#\````^)H``/P```#\````_)H` +M`/P```#\````U)@``"````#4F```(````-28```0````%````!`````0```` +M%````-"8```(!`8#"`0'`P@$!@,(!`8#"`0'`]B8``!H$&``:!!@`&@08`!H +M$&``:!!@`-R8``#`P*``P,"@`,#`X`#`P.``P,#@`)R8```````````````` +M`````````````)R8`````````````````````````````)R8```````````` +M`````````````````)R8`````````````````````````````)R8```````` +M`````````````````````)R8```````0````$````!`````0````$)R8```` +M```$````!`````0````$````!)R8`````````````````````````````)R8 +M`````````````````````````````)R8```````````````````````````` +M`)R8``````````````````H``````````)R8``#``#@`@``X`,``.`+``#@` +MP``X`)R8```&``(`!@`"``8````&``(`!@`"`)R8``")````B0```(D```") +M````B0```)R8``"@````H````*````"@````H````)R8```'``0`!P`$``<` +M!``'``0`!P`$`-28```:````&@```!H````:````&@```)R8`````*````"@ +M````H````*````"@`)R8``````H````*````"@````H````*`)R8```````` +M`````````````````````)R8`````````````````````````````)R8```` +M`&8```!F````9@```&8```!F`)R8`````-L```#;````VP```-L```#;`)R8 +M`````/$```#Q````\0```/$```#Q`)R8`````!(````2````$@```!(````2 +M`)R8`````!(````2````$@```!(````2`)R8`````',```!S`````````$```!&````>0`` +M``$```!&````>@````$```!&````>P````$```!&````?`````$```!&```` +M?0````$```!&````?@````$```!&````?P````$```!&````@`````$```!$ +M````?`````$```!&````B`````$```!&````C`````$```!&````D`````$` +M``!&````E`````$```!&````F`````$```!&````G`````$```!&````H``` +M``$```!&````I`````$```!&````J`````$```!&````K`````$```!&```` +ML`````$```!&````M``````"!P````,`!@`)`#P```````````````D````$ +M````!``!``$``0`&````1D"`@ +M)3`T>"`E,#AX"@`E,#1X("4P.'@*`"4M.',@)3`X>"`@)2TX"`@)3`T>"`E,#AX +M("`E,#1X("4P.'@@("4P-'@@)3`X>"`@)3`T>"`E,#AX"@`````````````E +M,#1X("4P.'@@("4P-'@@)3`X>"`@)3`T>"`E,#AX("`E,#1X("4P.'@*```` +M````````````````````````)3`T>"`E,#AX("`E,#1X("4P.'@@("4P-'@@ +M)3`X>`H``````````````````````````````````````````"4M.',@)3`X +M>"`@)2TX`H````````````` +M```````````````E+3AS("4P.'@@("4M.',@)3`X>"`@)2TX"!3,B`E,#AX(%,S("4P.'@@4S0@)3`X>`H````````````` +M`````$E34CH@)3`X>"!3,"`E,#AX(%,Q("4P.'@@4S(@)3`X>"!3,R`E,#AX +M(%,T("4P.'@*```````````````````E+3AS("4P.'@@("4M.',@)3`X>"`@ +M)2TX"!#0E(@)3`X>"!21%E4 +M("4P.'@@34E30R`E,#AX(%-44R`E,#AX"@````````````!$6R5U72!-05-+ +M("4P.'@@2493("4P.'@@4E1262`E,#AX($-(3E0@)3`X>"!-25-#("4P-G@@ +M4T51("4P,W@*``````````````````````````````````````````!$6R5U +M72!834E4($U!4TL@)3`X>"`E,#AX("4P.'@@)3`X>`H````````````````` +M````````````````````24U2.B`E,#AX(%,P("4P.'@@4S$@)3`X>"!3,B`E +M,#AX(%,S("4P.'@@4S0@)3`X>`H``````````````````$E34CH@)3`X>"!3 +M,"`E,#AX(%,Q("4P.'@@4S(@)3`X>"!3,R`E,#AX(%,T("4P.'@*```````` +M```````````E+3AS("4P.'@@("4M.',@)3`X>"`@)2TX"!#0E(@)3`X>"!21%E4("4P.'@@34E30R`E,#AX +M(%-44R`E,#AX"@````````````!$6R5U72!-05-+("4P.'@@2493("4P.'@@ +M4E1262`E,#AX($-(3E0@)3`X>"!-25-#("4P-G@@4T51("4P,W@*```````` +M``````````````````````````````````!$6R5U72!834E4($U!4TL@)3`X +M>"`E,#AX("4P.'@@)3`X>`H````````````````````````````````````` +M)7,Z($]U="!O9B!S<&%C92!I;B!!3DD@=&%B;&4@9F]R(&-H86YN96P@)74O +M,'@E>"$*`````````````````(P4H!2T%,@4/!10%&04>!0``#(41A1:%&X4 +M``!L"84)G@F*":@)``!Q%H46F1:M%L$6``!:%((4JA0``(`6J!8``'P5D!6D +M%;@5S!7@%?05"!8<%C`61!8``'$)=@E["8`)CPF4"9D)HPD``+0)```\%%`4 +M9!1X%```<1:%%ID6K18```$``````````0```!(````$````'`````$````H +M`````@```#0````"````/`````$```!"````!````%H````$````;````#(4 +M1A1:%&X4``!:%((4JA2`%J@6``!\%9`5I!6X%"`W +M+C,@,BXY-BTQ,3`I``!'0T,Z("A'3E4I(#(N.38@,C`P,#`W,S$@*%)E9"!( +M870@3&EN=7@@-RXS(#(N.38M,3$P*0``1T-#.B`H1TY5*2`R+CDV(#(P,#`P +M-S,Q("A2960@2&%T($QI;G5X(#"`W +M+C,@,BXY-BTQ,3`I``!'0T,Z("A'3E4I(#(N.38@,C`P,#`W,S$@*%)E9"!( +M870@3&EN=7@@-RXS(#(N.38M,3$P*0``1T-#.B`H1TY5*2`R+CDV(#(P,#`P +M-S,Q("A2960@2&%T($QI;G5X(#"`W +M+C,@,BXY-BTQ,3`I``!'0T,Z("A'3E4I(#(N.38@,C`P,#`W,S$@*%)E9"!( +M870@3&EN=7@@-RXS(#(N.38M,3$P*0``1T-#.B`H1TY5*2`R+CDV(#(P,#`P +M-S,Q("A2960@2&%T($QI;G5X(#"`W +M+C,@,BXY-BTQ,3`I``!'0T,Z("A'3E4I(#(N.38@,C`P,#`W,S$@*%)E9"!( +M870@3&EN=7@@-RXS(#(N.38M,3$P*0``1T-#.B`H1TY5*2`R+CDV(#(P,#`P +M-S,Q("A2960@2&%T($QI;G5X(#'0`+G)E;"YR;V1A=&$`+G)O9&%T82YS='(Q+C$`+G)O +M9&%T82YS='(Q+C,R`"YR96PN9&%T80`N8G-S`"YC;VUM96YT`"YN;W1E```` +M```````````````````````````````````````````````````?`````0`` +M``8`````````-````&P"`0````````````0`````````&P````D````````` +M`````,"=`0!8$0``#0````$````$````"````"D````!`````@````````"@ +M`@$`X$X`````````````(``````````E````"0``````````````&*\!`!`0 +M```-`````P````0````(````,0````$````R`````````(!1`0`D!@`````` +M```````!`````0```$`````!````,@````````#`5P$`0`4````````````` +M(`````$```!4`````0````,``````````%T!`!`1`````````````"`````` +M````4`````D``````````````"B_`0!(````#0````<````$````"````%H` +M```(`````P`````````@;@$`P`$`````````````(`````````!?`````0`` +M````````````(&X!`$X'``````````````$`````````:`````<````````` +M`````&YU`0"H`@`````````````!`````````!$````#```````````````6 +M>`$`;@```````````````0`````````!`````@``````````````W'H!`)`4 +M```.````"0````0````0````"0````,``````````````&R/`0!1#@`````` +M```````!```````````````````````````````````````````````#``$` +M`````````````````P`#``````````````````,`!0`````````````````# +M``8``````````````````P`'``````````````````,`"0`````````````` +M```#``H``````````````````P`+``$```#860``U````!(``0`,````9$P` +M``H````2``$`%P```'RM``";````$@`!`"(```#@*@``&@$``!(``0`M```` +M5$L```P````1``,`.````(`0```$````$0`'`$,``````0``(@$``!$`!P!. +M````-+L``!H````2``$`60```/PL```S````$@`!`&0```#D(0``%P```!(` +M`0!O````"+,``!8````2``$`>@```.BH```*````$@`!`(4```",$```!``` +M`!$`!P"0````A)T``+`````2``$`FP```)`0```$````$0`'`*8```!````$@`!`,L#``"0\@``P@$``!(``0#6`P``A&P```H````2 +M``$`X0,``+AN``!.````$@`!`.P#```X,0``+0```!(``0#W`P``A*,``!T` +M```2``$``@0``&2:```W````$@`!``T$```(-0``!0```!(``0`8!```A*P` +M`%4````2``$`(P0``!BZ```*````$@`!`"X$`````````````!`````[!``` +MV$P``#$````2``$`1@0``'`Y``!.````$@`!`%$$```XL0``;P```!(``0!< +M!```8`,``)8````2``$`;00``-CM``#V`@``$@`!`'@$```8-```1@```!(` +M`0"#!```M%```*0````2``$`C@0``""S```4````$@`!`)D$``#4.```7@`` +M`!(``0"D!```(*T```\````2``$`KP0``&!=```S````$@`!`+H$``!(>@`` +M&@$``!(``0#%!```V$L``(H````2``$`T`0``(`+```B`0``$0`'`-L$``"T +MO0``:````!(``0#F!```K%H``$T````2``$`\00```AO``#'````$@`!`/P$ +M``"09@``%@```!(``0`'!0``R.P``+\````2``$`$@4``/#W```2!```$@`! +M`!T%``!\+```#@```!(``0`H!0``.%L```P!```2``$`,P4``-RE``!-```` +M$@`!`#X%``"TKP``*0```!(``0!)!0``Z+$``#\````2``$`5`4``,`,```B +M`0``$0`'`%\%``#(FP``F@```!(``0!J!0``;#0``!H````2``$`=04``'!, +M```%````$@`!`(`%```P;0``$@```!(``0"+!0``P#D``!,!```2``$`E@4` +M`."O``#B````$@`!`*$%``!`*@``9````!(``0"L!0``G/8``%`````2``$` +MMP4``'Q````4````$@`!`,(%``"@-P``$0```!(``0#-!0``8#(``/0````2 +M``$`V`4``$@Y```E````$@`!`.,%```8K@``9P```!(``0#N!0``[,<``%`! +M```2``$`^04``/#Q``"2````$@`!``0&```L-P``)@```!(``0`/!@``9)P` +M``H````2``$`&@8``.`#```B`0``$0`'`"4&```\9@``"@```!(``0`P!@`` +M:"X``*!P``,*T``$H````2 +M``$`Z0<``"`%```B`0``$0`'`/0'``"0;@``$0```!(``0#_!P``8%P``&<` +M```2``$`"@@``(@````G````$@`!`!@(``!D`@$`!0```!(``0`C"```(#$` +M`!<````2``$`+@@``$`"```B`0``$0`'`#D(```0-0``.@```!(``0!$"``` +M,&X``%X````2``$`3P@``,A<```.````$@`!`%H(``!,N```!0```!(``0!E +M"```\&```%4````2``$`<`@``/2H```S````$@`!`'L(``!8-@``B````!(` +M`0"&"```?/T``/(!```2``$`D0@```RZ```*````$@`!`)P(``#@-@``#@`` +M`!(``0"G"````+L``#(````2``$`L@@``-#P```J````$@`!`+T(``#0;0`` +M7@```!(``0#("```T+H``#`````2``$`TP@``#2;```O````$@`!`-X(``#8 +M7```>P```!(``0#I"```$)T``',````2``$`]`@``&`&```B`0``$0`'`/\( +M```8.```&@```!(``0`*"0``&"P``&(````2``$`%0D``%0W```\````$@`! +M`"`)```4EP``(@,``!(``0`K"0``G&P```H````2``$`-@D``&BF``!N`0`` +M$@`!`$$)``"D;@``%````!(``0!,"0``^"```'\````2``$`5PD``%"O``!C +M````$@`!`&()``"0;```"@```!(``0!M"0``@*X``#D````2``$`>`D``)`W +M```.````$@`!`(,)``",80``#P```!(``0"."0``A!````0````1``<`F0D` +M`$AF```K````$@`!`*0)``#@YP``1P```!(``0"O"0``^`(``&4````2``$` +MN@D``-RL``!!````$@`!`,4)```@A0``K`$``!(``0#0"0``_"L``!L````2 +M``$`VPD``%3T``#N````$@`!`.8)``!H,0``*P```!(``0#Q"0``O`0``$L! +M```2``$`_`D``-"I``"0````$@`!``<*``#T90``1@```!(``0`2"@``<)P` +M`)(````2``$`'0H`````````````$````#T*``!D!```6````!(``0!("@`` +M,#```$T````2``$`4PH``,`P``!$````$@`!`%X*``#P-@``"@```!(``0!I +M"@``G&$``#,````2``$`=`H``#`M``"G````$@`!`'\*```49```*0```!(` +M`0"*"@``L+4``)D"```2``$`E0H``+QF```7````$@`!`*`*``#,O```Y0`` +M`!(``0"K"@``$#```!X````2``$`M@H`````````````$````,0*``!T8``` +M'@```!(``0#/"@``K&T``"0````2``$`V@H```!!``"T````$@`!`.4*``!0 +M.```)````!(``0#P"@``"*P``!X````2``$`^PH``+RZ```2````$@`!``8+ +M``"<8P``*P```!(``0`1"P``)*\``"L````2``$`'`L``+@T```Z````$@`! +M`"<+``"`,P``$0```!(``0`R"P``M&P``%<````2``$`/0L``%AE```<```` +M$@`!`$@+``!D40``P````!(``0!3"P``E&```%D````2``$`7@L``$`R```@ +M````$@`!`&D+``!X3```70```!(``0!T"P````X``"(!```1``<`?PL``*0J +M```[````$@`!`(H+``",+```9````!(``0"5"P``[*X``#8````2``$`H`L` +M`)"T```*````$@`!`*L+``"T90``/P```!(``0"V"P``J&P```H````2``$` +MP0L``-1K``"@````$@`!`,P+``#0;P``;P@``!(``0#7"P``0`\``"(!```1 +M``<`X@L``,#U``#9````$@`!`.T+``"([0``4````!(``0#X"P``"#<``"$` +M```2``$``PP``+0W```2````$@`!``X,``"8N@``#@```!(``0`9#```R#<` +M`$X````2``$`)`P``(18```0````$@`!`"\,```X3P``3P```!(``0`Z#``` +M=&T``!H````2``$`10P``/0T```*````$@`!`%`,``#\9P``F0(``!(``0!; +M#```Q)8``%`````2``$`9@P``%"[```D````$@`!`'$,``!T'0``PP$``!(` +M`0"'#```-+P``#,````2``$`D@P``$@I```%````$@`!`)T,``!T.```7@`` +M`!(``0"H#```'+X``$<(```2``$`LPP``(`P```^````$@`!`+X,``#TIP`` +M9P```!(``0#)#```9)L``&$````2``$`U`P``)!M```:````$@`!`-\,``"( +M3P``@````!(``0#J#```W!D``',````2``$`]0P``*2R```[````$@`!```- +M``"00```;P```!(``0`+#0``1&T``#`````2``$`%@T``$!X```2````$@`! +M`"$-``!X*0``QP```!(``0`L#0``!#$```\````2``$`-PT``&22``!'```` +M$@`!`$(-``!0N0``B````!(``0!-#0``*+(``'H````2``$`6`T``'1E```] +M````$@`!`&,-``"(4P``^@0``!(``0!N#0``D*0```4````2``$`>0T``*A( +M``".`@``$@`!`(0-```TLP``,0```!(``0"/#0``B!````0````1``<`F@T` +M`#B:```J````$@`!`*4-``!(2P``#````!$``P"P#0``>"$``&L````2``$` +MNPT``*BQ```]````$@`!`,8-```HK```60```!(``0#1#0``K,8``#T!```2 +M``$`W`T``$3Q``!&````$@`!`.<-``#HI```]````!(``0#R#0`````````` +M```0`````0X``!0Q```*````$@`!``P.``!X4```.P```!(``0`7#@``\+`` +M`!$````2``$`(@X``*1X``"B`0``$@`!`"T.``#\(0``7P```!(``0!&#@`` +MC/$``&$````2``$``'IZ,#`U8C4X-#8`>GHP,#)D8C$Q8P!Z>C`P,F1B-#8P +M`'IZ,&(W8C@S-C@`>GHP,#`R9&%F.0!Z>C!C9F$R,#@X`'IZ,#`U8C0P860` +M>GHP-6(Y-#)E9`!Z>C!D.31C9#`T`'IZ,#`Q.68T-S``>GHP,#5B-CDR8@!Z +M>C!B-F0R,S(U`'IZ,#8W9#`T86$`>GHP,#5B.#4S9`!Z>C`S,V4X,C1D`'IZ +M,#`R9&(S,6,`>GHP,F1A8F)A8P!Z>C`P,&(V8S8X`'IZ,#`P8C9B9C@`>GHP +M,F1B-6)F,`!Z>C`Q-F4Q9&9D`'IZ,&(W,&4Y.&,`>GHP8C9C83,R-0!Z>C`P +M-6(V8V9D`'IZ,#$V93!D9F0`>GHP,#!B-F8V.`!Z>C`P-6(T.&%D`'IZ,#`P +M8C9B9F4`>GHP,#5B.#AC8@!Z>C`S,V5C.&)F`&%T:%]H86Q?9&UA7V)E86-O +M;E]R97-P;VYS95]T:6UE`'IZ,#!B-F8Q-C$`>GHP9&,U.#C!D8C`Y +M,3!E`'IZ,#!B-F4R-V$`>GHP,#5B-C1F9`!Z>C`P,&(V9#%D`'IZ,&(V8S(S +M,C4`>GHP,#`U8C8S,@!Z>C`V9&8R9C4W`'IZ,#`Q-F1A-3``871H7VAA;%]W +M86ET`'IZ,#`R9&(U,6,`>GHP,39D83=F,`!Z>C`Q-F1C8F9E`'IZ,#`U8CGHP,#$V9&8R8P!Z>C!B.#$T-C$R`'IZ,#$V9#DY,C``>GHP,#8W9#4T +M-0!Z>C!D8SGHP,#!B-F(Q,`!Z>C`P-6(W,3`S +M`'IZ,#$V9&8X.6(`871H7VAA;%]A='1A8V@`>GHP,39D86(R9`!Z>C`R9&(Q +M,S5D`'IZ,#`P8C9F93@`>GHP,#$V9#DT.`!Z>C`Q-F4R,#EB`'IZ,#`P8C9C +M.60`>GHP,#`U8C5A,@!Z>C`R9&(Q-S!A`&%T:%]H86Q?8V]M<'5T971X=&EM +M90!Z>C`P-6(X,3-D`'IZ,&(V8V4Y.&,`>GHP,#5B-V8Y9`!Z>C`V93`T-C!E +M`'IZ,#)D8C4W-C,`>GHP-F8R,S)C8P!A=&A?:&%L7V=E='5P=&EM90!Z>C!E +M,#GHP,#)D868V,@!Z>C`P,F1A9C8T`'IZ,&(X +M-30V,3(`>GHP,#!B-F(Y,`!Z>C`Q-F0Y969A`'IZ,#`R9&(R-C``>GHP,39D +M93`U,0!Z>C`P,#5B-F(R`'IZ,#,T-S0V8C0`>GHP,#AE9C,P.0!Z>C`P8CGHP,&(W,&8S9`!Z>C`Q-F0X.3(P`'IZ,#`P-6(V +M,C(`>GHP,#!B-F8W.`!Z>C`P,F1A9#8T`'IZ,#!B-F1C-3$`>GHP,#5B-S8S +M,`!A=&A?:&%L7V9R964`>GHP-6(W.6(Q8@!Z>C`P8CC`Q-F4Q.#EB`'IZ,&1C,S0Y-&0`>GHP +M,#)D8S8P8@!Z>C`R9&(S,S5D`'IZ,&8X968S,#@`>GHP,#)D8C1A,`!Z>C!D +M831C9#`T`'IZ,#5B-S0Q93``>GHP,F1A.6)A8P!Z>C`Q-F5C.6%D`'IZ,#!B +M-S$W,V0`>GHP9&,Q,F,Q9@!Z>C`P-6(X-&9D`'IZ,#`U8C8U,F(`>GHP,39E +M,S`Y8@!Z>C`P-6(V,&(R`'IZ,#)D8C$W-C,`>GHP8C=F.#,V.`!Z>C!D8S,R +M8S%F`'IZ,#!B-S`Q-C$`>GHP9&(T.3$P90!Z>C`P-6(T.&5D`'IZ,#`R9&,X +M,&(`>GHP8C8R-&5B-0!Z>C`P-6(V93%C`'IZ,#)D8C,S960`>GHP,#5B.#!F +M9`!Z>C`Q-F4V-#AA`'IZ,&1B9C)C,68`>GHP,#)D869F,@!Z>C`P-6(W-SED +M`'IZ,#`P8C9E93@`>GHP,39E-#0X80!Z>C`P8C9F-F)C`'IZ,#$V9&$Y,C`` +M>GHP-6(W.#%E,`!Z>C`P,F1C83!B`'IZ,#)D8C%B9C``>GHP,#!B-F(W90!Z +M>C`P-6(T-&%D`'IZ,#9D,&1D,#D`>GHP-F1E-#8P90!A=&A?:&%L7W%S;W)T +M`'IZ,#!B-F,V8F,`871H7VAA;%]A9&1I=&EO;F%L7W-W8F%?8F%C:V]F9@!Z +M>C`Q-F4P,V$T`'IZ,#`P,F1B.3(`871H7VAA;%]I965E,FUH>@!Z>C`R9&(W +M.6%E`'IZ,#`Q-F4Q,F,`>GHP,#5B-6-B,@!Z>C`Q-F1A,C4Q`'IZ,#9F83,R +M8V,`>GHP-F4P,F8U-P!Z>C`P-6(V93,P`&%T:%]H86Q?;6%L;&]C`'IZ,#`P +M8C9D9#(`>GHP-6(V8V)D-0!Z>C`Q-F1B,C4Q`'IZ,&4Q-S@S-SD`>GHP,39D +M9#`U,0!Z>C!D83EC-&8V`'IZ,#)D8S$W-C,`>GHP,39D9C`U,0!Z>C`P,39D +M.34P`'IZ,#!B-S`V8F,`>GHP,#$V9#@W,@!Z>C`V9&8T-C!E`'IZ,#`P8C9A +M9F4`>GHP-6(X8S)E9`!Z>C`V9F8Q-V4W`'IZ,&0T968S,#@`>GHP-F,W-&5B +M8@!Z>C`Q-F1B8F9E`'IZ,#$V934T.&$`>GHP,#$V9#@U,`!Z>C`P,&(V9F8X +M`'IZ,#9D8C5E8C8`>GHP,39E8CEA9`!Z>C`P8C9C96)C`'IZ,&0Y8CAB-SD` +M871H7VAA;%]PC`P,F1B,38T`'IZ,#`R9&(P-C``>GHP,39E83EA +M9`!Z>C`P,F1B-S8Q`'IZ,#`P968S,#D`>GHP,F1B,SC`P-6(W-C%C +M`'IZ,#!B-F0T-3$`>GHP9&(T8V0P-`!Z>C`Q-F1F,C4Q`'IZ,#`P8C9C,3`` +M>GHP8CAF83AF.0!Z>C`Q-F0Y,C4Q`'IZ,&(W,C%A960`>GHP,#!B-F-F.`!Z +M>C!C8V5F,S`X`'IZ,#5B.3)A960`>GHP,#5B.&-C8@!Z>C`R9&)F-S8S`'IZ +M,#`U8C8X9F0`>GHP,#5B-#1E9`!Z>C!B-S$Q865D`'IZ,&0X8CAB-SD`>GHP +M,39D.&(R9`!Z>C`Q-F4P.#EB`'IZ,#$V9#DW9C``>GHP8C@S.#,V.`!Z>C`P +M8C9F96)C`'IZ,&4Y.3DS,3,`>GHP,&(V96$W80!Z>C`P-6(W,C,P`'IZ,#)D +M8CDY864`>GHP,#!B-F)E.`!Z>C`P,F1B,F$P`'IZ,&-F83$V86$`>GHP9#DY +M8S1F-@!Z>C!D960X834W`'IZ,#$Y9C-A,#$`>GHP-S`W,3=E-P!Z>C`V93`T +M9&0Q`'IZ,&(V.&4Y.&,`>GHP,39E,F1F9`!Z>C`P,&(V9#(R`'IZ,#!C9F%A +M9#,`>GHP-S`R,S)C8P!Z>C!D8S4T.31D`'IZ,#!B-S!F-V0`871H7VAA;%]S +M=U]B96%C;VY?C`Y9C8Y9#)E`'IZ,#`U8C8U-V$` +M>GHP-F8W,3=E-P!Z>C!B.#=A.&8Y`'IZ,#9D835E8C8`>GHP8C=D-#8Q,@!Z +M>C`P8C9F.38Q`'IZ,#`R9&)B-C$`>GHP,F1B9#,U9`!Z>C`P-6(X.&9D`'IZ +M,#)D869D9F0`871H7VAA;%]D96QA>0!Z>C`R9&(Q9&9D`'IZ,&(X,#GHP,#)D864Y,@!Z>C!B-V,W-S0Q`'IZ,#)D8C-D9F0`>GHP,F1B-3-E9`!Z +M>C`P,&(V9&$R`'IZ,#`P8C9E,C(`>GHP9#@Y8S1F-@!Z>C`P,39D.#0X`'IZ +M,#$V9#EB,F0`>GHP,#$V93`R8P!Z>C`P8CGHP +M,#5B-C4T,@!Z>C`Q-F4Q,#EB`'IZ,#`U8C1A,F0`>GHP9&8W.#,W.0!Z>C`R +M9&)D-S8S`'IZ,#`P8C9E-3(`>GHP8V$U9C,R.0!Z>C!D8C(Y,3!E`'IZ,#)D +M8C-B9C``>GHP,39E,#(U,0!Z>C`P,#)D8F(R`'IZ,#`R9&0X-F0`>GHP,#5B +M.#DS9`!Z>C`U8C@Q8C%B`'IZ,#$V9#@W9C``>GHP,F1B,3-E9`!Z>C`P,&(V +M8V4X`'IZ,#5B.&%A960`>GHP,#`U8C5E,@!Z>C`P,&(V968X`'IZ,&(W,3EA +M960`>GHP,#5B-3AB,@!Z>C`P,F1B.38Q`'IZ,#5B-V1B,6(`>GHP8C@T-SGHP,&(V9#9B8P!Z>C`P-6(V9#`S +M`'IZ,&,T968S,#@`>GHP,#`R9&)D,@!Z>C`P8C9C8S4Q`'IZ,&1A8CAB-SD` +M>GHP,39E,&(X-P!Z>C`U8CDP,F5D`'IZ,&1C,S@W,3@`>GHP86$R965C,0!Z +M>C`V9#AD9#`Y`'IZ,#`P8C9C,60`>GHP-6(X96%E9`!Z>C`P-6(W8CED`'IZ +M,#`U8C4T-#8`>GHP,#)D8C!A,`!Z>C!D9&0X834W`'IZ,#$V93$R-3$`>GHP +M9&,W-#DT9`!Z>C`R9&(S-S!A`'IZ,#`P-6(V-S(`>GHP,#5B-S4P,P!Z>C`V +M9&8T9&0Q`'IZ,#)D8F8S-60`>GHP-C=D,&(T9`!Z>C`P,&(V8SGHP,V4Y-S,U,P!Z>C`R9&(U-S!A`'IZ,#`U8C9D-V$`>GHP,#)D +M8C(Y,@!Z>C`P-6(Y,&-B`'IZ,#`U8C5C-#8`871H7VAA;%]PGHP +M-F0Y-65B-@!Z>C`Q-F1F8C@W`'IZ,#`Q-F1A-#@`>GHP,#)D8C`Y,@!A=&A? +M:&%L7V=E='=IGHP,39E,6(X-P````!9`````0,``&$` +M```!`P``:0````$#``!Q`````0,``'D````!`P``1`$```):``!<`0```C4! +M`'0!```"+P``#@4```$$```5!0```D(!`(8%```!!```C04```)"`0"Y!0`` +M`00``-@%```!`P``WP4```)"`0#Q!0```0,``/@%```"0@$`8P8```$$``!J +M!@```D(!`,X&```!!```]08```$#``#\!@```D(!`!<'```!`P``'@<```)" +M`0!(!P```0(``%8'```!`@``QA(```$"``#;$@```0(``%X:```!`@``DAH` +M``$"```G&P```0(``$<;```!`@``6AL```$"``#;&P```0(``.P;```!`@`` +M^1L```$"``!J'````0(``/8<```!`@``^QP```$"```R'0```0(``#<=```! +M`@``DAT```)'`0"['0```0(``,(=```!`@``"1\```$!```6'P```I4``+4? +M```!`@``>"(```*B``"?(@```0(``-LB```!`0``Y2(```$!`0`U(P```OL` +M`-$C```")@``%"0```+N``!/)````NX``(TD```"[@``]"0```+N``!")0`` +M`NX``&$H```"[@``&2D```)F``!"*0```F8``*4I```!)P``N2D```'L``!> +M*@```O@```,P```"3P``4C````(R``"F,````C(``$8Q```"YP``7#$```)7 +M``#O,0```@L!`#6@```)"`0"]:````00``,1H```"0@$`S&@```$#``#3:````D(!`.5H +M```!`P``]&@```$#```#:0```0,```AI```!!```#VD```)"`0`N:0```00` +M`#5I```"0@$`AVD```$$``".:0```D(!`)]I```!`P``IFD```)"`0`%:@`` +M`00```QJ```"0@$`>6H```$$``"`:@```D(!`/EJ```"^```$6L```+X``#9 +M;````9(``.%L```!T0``Z6P```&Y````;0```NT``%]M```",@``%'$```)& +M`0`G<@```B8``#9R```")@``2W(```$%``"3<@```04``,UR```!`@``^'(` +M``$"```@````O@``+=X```" +M$`$`5'D```+X``".>0```O@``.9Y```"^```%7H```+X```A>@```A`!``)[ +M```"&0``%GL```+X```B>P```AD``)%[```"^```I'L```(R```,?````FH` +M`"=\```!`@``-'P```(F``!`?````0(``'%\```")@``E'P```(F``!U?0`` +M`O@``.!^```!`@``>(````$%``"!@0```B8``).!```!!0``OX$```(F``#G +M@0```B8```J"```")@``+X(```(F``!G@@```04``(6#```",```+(8```(2 +M``"FA@```0(``.6&```!!@``]X8```$&```3AP```08``"*'```!!@``*8<` +M``$&```RAP```08``$"'```!!@``68<```$&``!HAP```08``'.'```!!@`` +M?(<```$&``"#AP```08``(N'```!!@``HH<```$&``"NAP```08``+B'```! +M!@``Q(<```$&``#1AP```08``-N'```!!@``[(<```$&``#ZAP```08```.( +M```!!@``$X@```$&```=B````08``'^(```!!@``P(@```$&``#.B````08` +M`."(```!!@``[(@```$&``#]B````08``!6)```!!@``(8D```$&```^B0`` +M`08``$R)```!!@``6HD```$&``!CB0```08``'J)```!!@``FXD```$&``"F +MB0```08``+B)```!!@``X8D```$&``!UB@```CP!`*^*```"V0``CXP```$" +M``"(C0```08``)B-```!!@``M8T```$&``#'C0```08``-F-```!!@``](T` +M``$&```#C@```08``!2.```!!@``*(X```$&``!"C@```08``%&.```!!@`` +M8HX```$&``!VC@```08``(N.```!!@``<9(```$"``!]D@```0(``(V2```! +M`@``090```$"``!OE````0(``)Z4```!`@``Q90```$"``#DE````0(``.Z4 +M```!`@``'I4```$"```NE0```0(``$B9```![```3ID```$G``!>F0```9<` +M`*J:```"P@``NYH```+/``#VF@```L\``"*;```"SP``'IP```+X```TG``` +M`B```")@``HIX```*B``"\G@```0(``.^>```!`0``^9X```&H``"; +MGP```C\!`%^@```"/@$`O*````(^`0#[H````CX!`'RA```!`@``BJ$```$" +M``"[H0```3X!`,JA```"*@$`$Z(```+X``!!H@```O@``'.B```"/@$`F:(` +M``+A``##H@```CX!`"NC```!#0``.J,```$[`0!%HP```H@``&*C```"80`` +MD*,```)3``"8HP```F8``,*C```!!0``?:0```+X``!'I0```2<``'.E```! +M)P``AZ4```'L``#RI0```O@```FF```"2`$`^ZL```+I``!6K````C(``,&L +M```",@``FZT```(^`0`MK@```C4``%"N```"``$`=*X```+:``"HKP```JD` +M`-&O```!`@``NK4```$#``#!M0```D(!`,FU```!`P``T+4```)"`0#:M0`` +M`0(``.*U```".@``)K8```$$```MM@```D(!`'&V```!!```>+8```)"`0"` +MM@```0,``(>V```"0@$`F;8```$#``"HM@```0,``+>V```!`P``O+8```$$ +M``##M@```D(!`.*V```!!```Z;8```)"`0`[MP```00``$*W```"0@$`4[<` +M``$#``!:MP```D(!`+FW```!!```P+<```)"`0`MN````00``#2X```"0@$` +M=;@```+X``"-N````O@``$^Z```!`@``5;H```$C``!=N@```8```&6Z```! +M"0$`;;H```%T``!UN@```1(!`(RZ```"[0``Z[H```(R```INP```JT``%.] +M```"F```^;X```(_`0#/OP```0(``.*_```!`@``^[\```+X```3P````0(` +M`##````!`@``1L````+X``"#P````0(``);````!`@``K\````+X``#0P``` +M`0(``-;````!`@``[,````+X```)P0```0(``!/!```!`@``*<$```+X``!+ +MP0```0(``%[!```!`@``=\$```+X``"8P0```0(``)[!```!`@``M,$```+X +M``#1P0```0(``-O!```!`@``\<$```+X```>Q0```O@``+;%```":P``!<8` +M``(+```5Q@```HT``"?&```",@``BL8```(R`0#1Q@```C(!`$W'```"^``` +MUL<```+X``#2R````O@``&G)```"^```?,D```(R``#DR0```FH``/S)```! +M`@``"<```$"```)Z````0(``+WI```!`@``Z^D` +M``$"```:Z@```0(``$'J```!`@``8.H```$"``!JZ@```0(``)KJ```!`@`` +MJNH```$"```TZP```D$``&'K```"20``GNL```)!``#9ZP```DD``!+L```" +M20``4NP```*I``"N[````JD``//O```![```^>\```$G```'\````9<``$;R +M```"^```6/(```)(`0"L]@```J(``+[V```"H@``%/<```)F``#1]P```0,` +M`-;W```!!```WO<```)"`0`0^````0(``!CX```!!0``*/@```$%```W^``` +M`04``$GX```!!0``7_L```$%``"O^P```04``!#\```!#@``)OP```$.``!& +M_````0X``%#\```!#@``9?P```)0``#?_````E```)S]```"4```#/X```(A +M`0`;_@```JP``#C^```"X@``7?X```)Z``!V_@```GH``)W^```">@``P?X` +M``)Z``#C_@```GH```G_```">@``+_\```)Z``!!_P```3D!`%;_```!%P`` +MJ/\```)Z``#7_P```GH``/3_```"X@``(P`!``)Z``!+``$``GH``'P``0`" +MX@``H``!``)Z``#"``$``GH``-T``0`"(0$`[``!``*L``#^``$``=\``!,! +M`0`!%0``+0$!``$Y`0!"`0$``1<``(@``H`$!``)Z``#!`0$``GH` +M`-H!`0`">@``\P$!``)Z```%`@$``B$!`!0"`0`"K```(`(!``'?```U`@$` +M`14``$D"`0`"(0$`6`(!``*L``!4"````04``%@(```!!0``7`@```$%``!@ +M"````04``&0(```!!0``:`@```$%``!L"````04``'`(```!!0``=`@```$% +M``"("````04``(P(```!!0``D`@```$%``"4"````04``)@(```!!0``G`@` +M``$%``"@"````04``*0(```!!0``J`@```$%``"T"````04``+P(```!!0`` +MP`@```$%``#$"````04``,@(```!!0``S`@```$%``#0"````04``-0(```! +M!0``V`@```$%``#<"````04``/`(```!!0``]`@```$%``#X"````04``/P( +M```!!0````D```$%```$"0```04```@)```!!0``)`D```$%```H"0```04` +M`"P)```!!0``,`D```$%```T"0```04``#@)```!!0``/`D```$%``!0"0`` +M`04``%@)```!!0``7`D```$%``!@"0```04``&0)```!!0``:`D```$%``!L +M"0```04``'`)```!!0``=`D```$%``"$"0```04``(P)```!!0``D`D```$% +M``"4"0```04``)@)```!!0``G`D```$%``"@"0```04``*0)```!!0``J`D` +M``$%``"X"0```04``,0)```!!0``T`D```$%```8"@```=0``!P*```!1P`` +M(`H```&9```D"@```:<``"@*```!/```+`H```$I`0`P"@```0@!`#0*```! +M9P``.`H```$_```\"@```1L``$`*```!&@$`1`H```$E``!("@```6T``$P* +M```!!0$`4`H```$A``!4"@```2P``%@*```!2@``7`H```&O``!@"@```=T` +M`&0*```!B@``:`H```$6`0!L"@```1@!`'`*```!T@``=`H```&P``!X"@`` +M`?P``'P*```!;P``@`H```$C`0"$"@```98``(@*```!C```C`H```%H``"0 +M"@```84``)0*```!/0``F`H```'```"<"@```2(!`*`*```!@P``I`H```%C +M``"H"@```?<``*P*```![P``L`H```$H``"T"@```8L``+@*```!YP``O`H` +M``%7``#`"@```0(!`,0*```!M@``R`H```$W``#,"@```3`!`-`*```!0P$` +MU`H```&^``#8"@```4@``-P*```!*@``X`H```%L``#D"@```5(``.@*```! +M"@``[`H```$N``#P"@```?(``/0*```!$0``^`H```&4``#\"@```4\````+ +M```!Q@``!`L```')```("P```?````P+```!H0``$`L```$5`0`4"P```9`` +M`!@+```!+P$`'`L```$,```@"P```0H!`"0+```!AP``*`L```'E```L"P`` +M`=,``#`+```!>P``-`L```$+`0!`"P```0,``$@+```!`P``4`L```$#``!8 +M"P```0,``&`+```!`P``:`L```$#``!P"P```0,``'@+```!`P``@`L```$# +M``"("P```0,``)`+```!`P``F`L```$#``"@"P```0,``*@+```!`P``L`L` +M``$#``"X"P```0,``,`+```!`P``R`L```$#``#0"P```0,``-@+```!`P`` +MX`L```$#``#H"P```0,``/`+```!`P``^`L```$#````#````0,```@,```! +M`P``$`P```$#```8#````0,``"`,```!`P``*`P```$#```P#````0,``#@, +M```!`P``0`P```$#``!(#````0,``%`,```!`P``6`P```$#``!@#````0,` +M`&@,```!`P``<`P```$#``!X#````0,``(`,```!`P``B`P```$#``"0#``` +M`0,``)@,```!`P``H`P```$#``"H#````0,``+`,```!`P``N`P```$#``#` +M#````0,``,@,```!`P``T`P```$#``#8#````0,``.`,```!`P``Z`P```$# +M``#P#````0,``/@,```!`P````T```$#```(#0```0,``!`-```!`P``&`T` +M``$#```@#0```0,``)@2```!`P$`G!(```$9`0"@$@```1$!`*02```!60`` +MJ!(```%R``"L$@```2D``+`2```!10``M!(```$>`0"X$@```=4``+P2```! +M.@$`P!(```%B``#$$@```H``&03```!DP``:!,```$8``!L$P```1\``'`3```! +M.```=!,```%Q``!X$P```:X``'P3```!GP``@!,```$0`0"$$P```9X``(@3 +M```!7@``C!,```';``"0$P```=8``)03```!#P$`F!,```$)``"<$P```7P` +M`*`3```!40``I!,```%V``"H$P```4L``*P3```!NP``L!,```'"``"T$P`` +M`<\``.`3```!`P``Z!,```$#``#P$P```0,``/@3```!`P```!0```$#```( +M%````0,``!`4```!`P``&!0```$#```@%````0,``"@4```!`P``,!0```$# +M```X%````0,``$`4```!`P``2!0```$#``!0%````0,``%@4```!`P``8!0` +M``$#``!H%````0,``'`4```!`P``>!0```$#``"`%````0,``(@4```!`P`` +MD!0```$#``"8%````0,``*`4```!`P``J!0```$#``"P%````0,``+@4```! +M`P``P!0```$#``#(%````0,``-`4```!`P``V!0```$#``#@%````0,``.@4 +M```!`P``\!0```$#``#X%````0,````5```!`P``"!4```$#```0%0```0,` +M`!@5```!`P``(!4```$#```H%0```0,``#`5```!`P``.!4```$#``!`%0`` +M`0,``$@5```!`P``4!4```$#``!8%0```0,``&`5```!`P``:!4```$#``!P +M%0```0,``'@5```!`P``@!4```$#``"(%0```0,``)`5```!`P``F!4```$# +M``"@%0```0,``*@5```!`P``$",```$!```4(P```0$``!@C```!`0``'",` +M``$!```@(P```0$``"0C```!`0``*",```$!```L(P```0$``'@D```!00`` +M?"0```%A``"`)````20!`(0D```!J@``B"0```&.``",)````3L``)`D```! +M>0``E"0```$4`0"8)````6L``)PD```!RP``H"0```&W``"D)````4`!`*@D +M```!CP``K"0```%=``"P)````>8``+0D```!(```N"0```$3`0"\)````20` +M`,`D```!%P$`Q"0```%#``#()````?X``,PD```!S0``T"0```'*``#4)``` +M`1```-@D```!'P$`W"0```%<``#@)````;(``.0D```!(0$`Z"0```&L``#L +M)````74``/`D```!]@``]"0```''``#X)````?0``/PD```!-@$``"4```'# +M```$)0```;T```@E```!_0``#"4```'C```0)0```7X``!0E```!A@``&"4` +M``$``0`<)0```=H``"`E```!10$`)"4```$Q```H)0```9P``"PE```!<``` +M,"4```&X```T)0```0L``#@E```!/0$`/"4```%_``!`)0```3,!`$0E```! +M*P$`2"4```$S``!,)0```10``%`E```!50``5"4```'%``!8)0```4T``%PE +M```!Z0``8"4```$R`0!D)0```:4``&@E```!R```;"4```%E``!P)0```30` +M`'0E```!'```>"4```%!`0!\)0```=<``(`E```!I@``A"4```%]``"()0`` +M`1X``(PE```!)@$`D"4```%.``"4)0```:D``.`E```!`P``Z"4```$#``#P +M)0```0,``/@E```!`P```"8```$#```()@```0,``!`F```!`P``&"8```$# +M```@)@```0,``"@F```!`P``,"8```$#```X)@```0,``$`F```!`P``2"8` +M``$#``!0)@```0,``%@F```!`P``8"8```$#``!H)@```0,``'`F```!`P`` +M>"8```$#``"`)@```0,``(@F```!`P``D"8```$#``"8)@```0,``*`F```! +M`P``J"8```$#``"P)@```0,``+@F```!`P``P"8```$#``#()@```0,``-`F +M```!`P``V"8```$#``#@)@```0,``.@F```!`P``\"8```$#``#X)@```0,` +M```G```!`P``""<```$#```0)P```0,``!@G```!`P``("<```$#```H)P`` +M`0,``#`G```!`P``."<```$#``!`)P```0,``$@G```!`P``4"<```$#``!8 +M)P```0,``&`G```!`P``:"<```$#``!P)P```0,``'@G```!`P``@"<```$# +M``"()P```0,``)`G```!`P``F"<```$#``"@)P```0,``*@G```!`P``L"<` +M``$#``"X)P```0,``,`G```!`P``R"<```$#``#0)P```0,``-@G```!`P`` +MX"<```$#``#H)P```0,``/`G```!`P```"@```$!```$*````0$```@H```! +M`0``#"@```$!```0*````0$``!0H```!`0``&"@```$!```<*````0$``"`H +M```!`0``)"@```$!```H*````0$``"PH```!`0``,"@```$!```T*````0$` +M`#@H```!`0``/"@```$!``!`*````0$``$0H```!`0``2"@```$!``!,*``` +M`0$``%`H```!`0``5"@```$!``!8*````0$``%PH```!`0``8"@```$!``!D +M*````0$``&@H```!`0``;"@```$!``!P*````0$``'0H```!`0``>"@```$! +M``!\*````0$``$A+```!`0``3$L```$!``!02P```0$``,!.```!`0``Q$X` +M``$!``#(3@```0$``,Q.```!`0``T$X```$!``#43@```0$``(@````!!0`` +MD`````$%``"8`````04``*`````!!0``J`````$%``"P`````04``+@````! +3!0``P`````$%``#(`````04````` +` +end diff -Nru a/drivers/net/wireless/atheros/ath_hal/opt_ah.h b/drivers/net/wireless/atheros/ath_hal/opt_ah.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/opt_ah.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,3 @@ +#define AH_SUPPORT_AR5210 1 +#define AH_SUPPORT_AR5211 1 +#define AH_SUPPORT_AR5212 1 diff -Nru a/drivers/net/wireless/atheros/ath_hal/version.h b/drivers/net/wireless/atheros/ath_hal/version.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/ath_hal/version.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: version.h,v 1.5 2003/06/20 22:55:13 sam Exp $ + */ +#define ATH_HAL_VERSION "0.9.4.0" diff -Nru a/drivers/net/wireless/atheros/bsdcompat/compat.h b/drivers/net/wireless/atheros/bsdcompat/compat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/bsdcompat/compat.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: compat.h,v 1.5 2003/05/16 20:23:27 sam Exp $ + */ +#ifndef _ATH_COMPAT_H_ +#define _ATH_COMPAT_H_ +/* + * BSD/Linux compatibility shims. These are used mainly to + * minimize differences when importing necesary BSD code. + */ +#define NBBY 8 /* number of bits/byte */ + +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ +#define howmany(x, y) (((x)+((y)-1))/(y)) + +/* Bit map related macros. */ +#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) +#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) +#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) +#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) + +#define __packed __attribute__((__packed__)) +#define __printflike(_a,_b) \ + __attribute__ ((__format__ (__printf__, _a, _b))) + +#ifndef ALIGNED_POINTER +/* + * ALIGNED_POINTER is a boolean macro that checks whether an address + * is valid to fetch data elements of type t from on this architecture. + * This does not reflect the optimal alignment, just the possibility + * (within reasonable limits). + * + */ +#define ALIGNED_POINTER(p,t) 1 +#endif + +#define KASSERT(_condition, _x) +#endif /* _ATH_COMPAT_H_ */ diff -Nru a/drivers/net/wireless/atheros/bsdcompat/queue.h b/drivers/net/wireless/atheros/bsdcompat/queue.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/bsdcompat/queue.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,530 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.54 2002/08/05 05:18:43 alfred Exp $ + * $Id: queue.h,v 1.2 2003/03/15 18:33:44 sam Exp $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +//#include + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_REVERSE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char * lastfile; + int lastline; + char * prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) +#endif /* QUEUE_MACRO_DEBUG */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#ifdef __GNUC__ + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !__GNUC__ */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff -Nru a/drivers/net/wireless/atheros/driver/Makefile b/drivers/net/wireless/atheros/driver/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/driver/Makefile Wed Jul 30 18:20:27 2003 @@ -0,0 +1,5 @@ +EXTRA_CFLAGS += -I$(obj)/../ath_hal -I$(obj)/../wlan -I$(obj)/.. + +obj-$(CONFIG_ATHEROS) += ath_pci.o + +ath_pci-objs := if_ath.o if_ath_pci.o diff -Nru a/drivers/net/wireless/atheros/driver/if_ath.c b/drivers/net/wireless/atheros/driver/if_ath.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/driver/if_ath.c Wed Jul 30 18:20:27 2003 @@ -0,0 +1,2610 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_ath.c,v 1.56 2003/07/02 23:26:57 sam Exp $ + */ + +/* + * Driver for the Atheros Wireless LAN controller. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define AR_DEBUG +#include "if_athvar.h" +#include "if_ethersubr.h" /* for ETHER_IS_MULTICAST */ +#include "ah_desc.h" + +/* unalligned little endian access */ +#define LE_READ_2(p) \ + ((u_int16_t) \ + ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8))) +#define LE_READ_4(p) \ + ((u_int32_t) \ + ((((u_int8_t *)(p))[0] ) | (((u_int8_t *)(p))[1] << 8) | \ + (((u_int8_t *)(p))[2] << 16) | (((u_int8_t *)(p))[3] << 24))) + +static int ath_init(struct net_device *); +static void ath_reset(struct net_device *); +static void ath_fatal_tasklet(void *); +static void ath_rxorn_tasklet(void *); +static void ath_bmiss_tasklet(void *); +static int ath_stop(struct net_device *); +static int ath_media_change(struct net_device *); +static void ath_ratectl(unsigned long); +static void ath_initkeytable(struct ath_softc *); +static void ath_mode_init(struct net_device *); +static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *); +static void ath_beacon_tasklet(void *); +static void ath_beacon_free(struct ath_softc *); +static void ath_beacon_config(struct ath_softc *); +static int ath_desc_alloc(struct ath_softc *); +static void ath_desc_free(struct ath_softc *); +static void ath_node_free(struct ieee80211com *, struct ieee80211_node *); +static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *); +static void ath_rx_tasklet(void *); +static int ath_hardstart(struct sk_buff *, struct net_device *); +static int ath_mgtstart(struct sk_buff *, struct net_device *); +static int ath_tx_start(struct net_device *, struct ieee80211_node *, + struct ath_buf *, struct sk_buff *); +static void ath_tx_tasklet(void *); +static void ath_tx_timeout(struct net_device *); +static int ath_chan_set(struct ath_softc *, struct ieee80211channel *); +static void ath_draintxq(struct ath_softc *); +static void ath_stoprecv(struct ath_softc *); +static int ath_startrecv(struct net_device *); +static void ath_next_scan(unsigned long); +static void ath_calibrate(unsigned long); +static int ath_newstate(void *, enum ieee80211_state); +static struct net_device_stats *ath_getstats(struct net_device *); +static int ath_getchannels(struct net_device *, u_int cc, HAL_BOOL outdoor); + +static int ath_rate_setup(struct net_device *, u_int mode); +static void ath_setcurmode(struct ath_softc *, enum ieee80211_phymode); +static void ath_rate_ctl_reset(struct ath_softc *, enum ieee80211_state); +static void ath_rate_ctl(void *, struct ieee80211_node *); + +static int ath_dwelltime = 200; /* 5 channels/second */ +static int ath_calinterval = 30; /* calibrate every 30 secs */ +static int ath_rateinterval = 1000; /* rate ctl interval (ms) */ +static int ath_bmisshack = 1; /* XXX */ +static int ath_countrycode = CTRY_DEFAULT; /* country code */ +static int ath_regdomain; /* regulatory domain */ +static int ath_outdoor = AH_TRUE; /* enable outdoor use */ + +#ifdef AR_DEBUG +int ath_debug; +#define IFF_DUMPPKTS(_ic) (ath_debug || netif_msg_dumppkts(_ic)) +static void ath_printrxbuf(struct ath_buf *bf, int); +static void ath_printtxbuf(struct ath_buf *bf, int); +#else +#define IFF_DUMPPKTS(_ic) netif_msg_dumppkts(_ic) +#endif + +int +ath_attach(u_int16_t devid, struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah; + int error = 0; + u_int8_t csz; + HAL_STATUS status; + + DPRINTF(("ath_attach: devid 0x%x\n", devid)); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(sc->sc_pdev, PCI_CACHE_LINE_SIZE, &csz); + /* XXX assert csz is non-zero */ + sc->sc_cachelsz = csz << 2; /* convert to bytes */ + + spin_lock_init(&sc->sc_txbuflock); + spin_lock_init(&sc->sc_txqlock); + + INIT_WORK(&sc->sc_rxwk, ath_rx_tasklet, dev); + INIT_WORK(&sc->sc_txwk, ath_tx_tasklet, dev); + INIT_WORK(&sc->sc_swbawk, ath_beacon_tasklet, dev); + INIT_WORK(&sc->sc_bmisswk, ath_bmiss_tasklet, dev); + INIT_WORK(&sc->sc_rxornwk, ath_rxorn_tasklet, dev); + INIT_WORK(&sc->sc_fatalwk, ath_fatal_tasklet, dev); + + ah = _ath_hal_attach(devid, sc, 0, (void *) dev->mem_start, &status); + if (ah == NULL) { + printk(KERN_ERR "%s: unable to attach hardware; HAL status %u\n", + dev->name, status); + error = -ENXIO; + goto bad; + } + sc->sc_ah = ah; + + /* + * Collect the channel list using the default country + * code and including outdoor channels. The 802.11 layer + * is resposible for filtering this list to a set of + * channels that it considers ok to use. + */ + error = ath_getchannels(dev, ath_countrycode, ath_outdoor); + if (error != 0) + goto bad; + ath_regdomain = ath_hal_getregdomain(ah); /* for users */ + + /* + * Setup rate tables for all potential media types. + */ + ath_rate_setup(dev, IEEE80211_MODE_11A); + ath_rate_setup(dev, IEEE80211_MODE_11B); + ath_rate_setup(dev, IEEE80211_MODE_11G); + ath_rate_setup(dev, IEEE80211_MODE_TURBO); + + error = ath_desc_alloc(sc); + if (error != 0) { + printk("%s: failed to allocate descriptors: %d\n", + dev->name, error); + goto bad; + } + + /* + * For now just pre-allocate one data queue and one + * beacon queue. Note that the HAL handles resetting + * them at the needed time. Eventually we'll want to + * allocate more tx queues for splitting management + * frames and for QOS support. + */ + sc->sc_txhalq = ath_hal_setuptxqueue(ah, + HAL_TX_QUEUE_DATA, + AH_TRUE /* enable interrupts */ + ); + if (sc->sc_txhalq == (u_int) -1) { + printk("%s: unable to setup a data xmit queue!\n", dev->name); + goto bad; + } + sc->sc_bhalq = ath_hal_setuptxqueue(ah, + HAL_TX_QUEUE_BEACON, + AH_TRUE /* enable interrupts */ + ); + if (sc->sc_bhalq == (u_int) -1) { + printk("%s: unable to setup a beacon xmit queue!\n", dev->name); + goto bad; + } + + init_timer(&sc->sc_rate_ctl); + sc->sc_rate_ctl.data = (unsigned long) dev; + sc->sc_rate_ctl.function = ath_ratectl; + + init_timer(&sc->sc_scan_ch); + sc->sc_scan_ch.function = ath_next_scan; + sc->sc_scan_ch.data = (unsigned long) dev; + + init_timer(&sc->sc_cal_ch); + sc->sc_cal_ch.function = ath_calibrate; + sc->sc_cal_ch.data = (unsigned long) dev; + + ether_setup(dev); + dev->open = ath_init; + dev->hard_start_xmit = ath_hardstart; + dev->tx_timeout = ath_tx_timeout; + dev->watchdog_timeo = 5 * HZ; /* XXX */ + dev->set_multicast_list = ath_mode_init; + dev->get_stats = ath_getstats; + dev->tx_queue_len = ATH_TXBUF-1; /* 1 for mgmt frame */ + + ic->ic_mgtstart = ath_mgtstart; + ic->ic_init = ath_init; + + ic->ic_newstate = ath_newstate; + /* XXX not right but it's not used anywhere important */ + ic->ic_phytype = IEEE80211_T_OFDM; + ic->ic_opmode = IEEE80211_M_STA; + ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_IBSS | IEEE80211_C_HOSTAP; + /* NB: 11g support is identified when we fetch the channel set */ + if (sc->sc_have11g) + ic->ic_caps |= IEEE80211_C_SHPREAMBLE; + ic->ic_node_privlen = sizeof(struct ath_nodestat); + ic->ic_node_free = ath_node_free; + ic->ic_bss.ni_private = &sc->sc_bss_stat; + + /* get mac address from hardware */ + ath_hal_getmac(ah, dev->dev_addr); + + /* call MI attach routine. */ + ieee80211_ifattach(dev); + ieee80211_media_init(dev, ath_media_change, ieee80211_media_status); + + /* don't accept xmit's until we are associated */ + netif_stop_queue(dev); + + printk("%s: 802.11 address: %s\n", + dev->name, ether_sprintf(dev->dev_addr)); + return 0; +bad: + if (ah) + ath_hal_detach(ah); + sc->sc_invalid = 1; + return error; +} + +int +ath_detach(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + + DPRINTF(("ath_detach flags %x\n", dev->flags)); + sc->sc_invalid = 1; + ath_stop(dev); + ath_desc_free(sc); + ath_hal_detach(sc->sc_ah); + ieee80211_ifdetach(dev); + + return 0; +} + +void +ath_suspend(struct net_device *dev) +{ + DPRINTF(("ath_suspend flags %x\n", dev->flags)); + ath_stop(dev); +} + +void +ath_resume(struct net_device *dev) +{ + DPRINTF(("ath_resume %x\n", dev->flags)); + ath_init(dev); +} + +void +ath_shutdown(struct net_device *dev) +{ + DPRINTF(("ath_shutdown %x\n", dev->flags)); + ath_stop(dev); +} + +/* + * Interrupt handler. All the actual processing is + * deferred to tasklets. + */ +irqreturn_t ath_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct ath_softc *sc = dev->priv; + struct ath_hal *ah = sc->sc_ah; + HAL_INT status; + + if (sc->sc_invalid) { + /* + * The hardware is gone, don't touch anything. + * XXX can this happen? + */ + return IRQ_NONE; + } + if ((dev->flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) { + DPRINTF(("ath_intr: flags 0x%x\n", dev->flags)); + ath_hal_getisr(ah, &status); /* clear ISR */ + ath_hal_intrset(ah, 0); /* disable further intr's */ + return IRQ_HANDLED; + } + ath_hal_getisr(ah, &status); + DPRINTF2(("%s: interrupt, status 0x%x\n", dev->name, status)); +if (ath_bmisshack) status &= ~HAL_INT_BMISS; /*XXX*/ +#ifdef AR_DEBUG + if (ath_debug && + (status & (HAL_INT_FATAL|HAL_INT_RXORN|HAL_INT_BMISS))) { + printk("%s: ath_intr: status 0x%x\n", dev->name, status); + ath_hal_dumpstate(ah); + } +#endif /* AR_DEBUG */ + if (status & HAL_INT_FATAL) { + sc->sc_stats.ast_hardware++; + schedule_work(&sc->sc_fatalwk); + } else if (status & HAL_INT_RXORN) { + sc->sc_stats.ast_rxorn++; + schedule_work(&sc->sc_rxornwk); + } else { + if (status & HAL_INT_RXEOL) { + /* + * XXX The hardware should re-read the link when + * RXE bit is written, but it doesn't work at least + * on older revision of the hardware. + */ + sc->sc_stats.ast_rxeol++; + sc->sc_rxlink = NULL; + } + if (status & HAL_INT_TXURN) { + sc->sc_stats.ast_txurn++; + /* bump tx trigger level */ + ath_hal_updatetxtriglevel(ah, AH_TRUE); + } + if (status & HAL_INT_RX) + schedule_work(&sc->sc_rxwk); + if (status & HAL_INT_TX) + schedule_work(&sc->sc_txwk); + if (status & HAL_INT_SWBA) + schedule_work(&sc->sc_swbawk); + if (status & HAL_INT_BMISS) { + sc->sc_stats.ast_bmiss++; + schedule_work(&sc->sc_bmisswk); + } + } + + return IRQ_HANDLED; +} + +static void +ath_fatal_tasklet(void *data) +{ + struct net_device *dev = data; + + printk("%s: hardware error; resetting\n", dev->name); + ath_reset(dev); +} + +static void +ath_rxorn_tasklet(void *data) +{ + struct net_device *dev = data; + + printk("%s: rx FIFO overrun; resetting\n", dev->name); + ath_reset(dev); +} + +static void +ath_bmiss_tasklet(void *data) +{ + struct net_device *dev = data; + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + + DPRINTF(("ath_bmiss_tasklet\n")); + KASSERT(ic->ic_opmode == IEEE80211_M_STA, + ("unexpect operating mode %u", ic->ic_opmode)); + if (ic->ic_state == IEEE80211_S_RUN) + ieee80211_new_state(dev, IEEE80211_S_SCAN, -1); +} + +static u_int +ath_chan2flags(struct ieee80211com *ic, struct ieee80211channel *chan) +{ + static const u_int modeflags[] = { + 0, /* IEEE80211_MODE_AUTO */ + CHANNEL_A, /* IEEE80211_MODE_11A */ + CHANNEL_B, /* IEEE80211_MODE_11B */ + CHANNEL_PUREG, /* IEEE80211_MODE_11G */ + CHANNEL_T /* IEEE80211_MODE_TURBO */ + }; + return modeflags[ieee80211_chan2mode(ic, chan)]; +} + +static int +ath_init(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + enum ieee80211_phymode mode; + struct ath_hal *ah = sc->sc_ah; + HAL_STATUS status; + HAL_CHANNEL hchan; + + DPRINTF(("ath_init\n")); + /* + * Stop anything previously setup. This is safe + * whether this is the first time through or not. + */ + ath_stop(dev); + + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + hchan.channel = ic->ic_ibss_chan->ic_freq; + hchan.channelFlags = ath_chan2flags(ic, ic->ic_ibss_chan); + if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_FALSE, &status)) { + printk("%s: unable to reset hardware; hal status %u\n", + dev->name, status); + return -EIO; + } + + /* + * Setup the hardware after reset: the key cache + * is filled as needed and the receive engine is + * set going. Frame transmit is handled entirely + * in the frame output path; there's nothing to do + * here except setup the interrupt mask. + */ + if (ic->ic_flags & IEEE80211_F_WEPON) + ath_initkeytable(sc); + if (ath_startrecv(dev) != 0) { + printk("%s: unable to start recv logic\n", dev->name); + return -EIO; + } + + /* + * Enable interrupts. + */ + sc->sc_imask = HAL_INT_RX | HAL_INT_TX + | HAL_INT_RXEOL | HAL_INT_RXORN + | HAL_INT_FATAL | HAL_INT_GLOBAL; + ath_hal_intrset(ah, sc->sc_imask); + + dev->flags |= IFF_RUNNING; + ic->ic_state = IEEE80211_S_INIT; + + /* + * The hardware should be ready to go now so it's safe + * to kick the 802.11 state machine as it's likely to + * immediately call back to us to send mgmt frames. + */ + ni = &ic->ic_bss; + ni->ni_chan = ic->ic_ibss_chan; + mode = ieee80211_chan2mode(ic, ni->ni_chan); + if (mode != sc->sc_curmode) + ath_setcurmode(sc, mode); + ieee80211_new_state(dev, IEEE80211_S_SCAN, -1); + + return 0; +} + +static int +ath_stop(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ath_hal *ah = sc->sc_ah; + + DPRINTF(("ath_stop: invalid %u flags 0x%x\n", + sc->sc_invalid, dev->flags)); + + if (dev->flags & IFF_RUNNING) { + /* + * Shutdown the hardware and driver: + * stop output from above + * disable interrupts + * turn off timers + * clear transmit machinery + * clear receive machinery + * drain and release tx queues + * reclaim beacon resources + * reset 802.11 state machine + * power down hardware + * + * Note that some of this work is not possible if the + * hardware is gone (invalid). + */ + netif_stop_queue(dev); + dev->flags &= ~IFF_RUNNING; + /* XXX how/when to stop ieee80211 timer? */ + if (!sc->sc_invalid) + ath_hal_intrset(ah, 0); + ath_draintxq(sc); + if (!sc->sc_invalid) + ath_stoprecv(sc); + else + sc->sc_rxlink = NULL; + ath_beacon_free(sc); + ieee80211_new_state(dev, IEEE80211_S_INIT, -1); + del_timer(&sc->sc_rate_ctl); + if (!sc->sc_invalid) + ath_hal_setpower(ah, HAL_PM_FULL_SLEEP, 0); + } + + return 0; +} + +/* + * Reset the hardware w/o losing operational state. This is + * basically a more efficient way of doing ath_stop, ath_init, + * followed by state transitions to the current 802.11 + * operational state. Used to recover from errors rx overrun + * and to reset the hardware when rf gain settings must be reset. + */ +static void +ath_reset(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + struct ieee80211channel *c; + HAL_STATUS status; + HAL_CHANNEL hchan; + + /* + * Convert to a HAL channel description with the flags + * constrained to reflect the current operating mode. + */ + c = ic->ic_ibss_chan; + hchan.channel = c->ic_freq; + hchan.channelFlags = ath_chan2flags(ic, c); + + ath_hal_intrset(ah, 0); /* disable interrupts */ + ath_draintxq(sc); /* stop xmit side */ + ath_stoprecv(sc); /* stop recv side */ + /* NB: indicate channel change so we do a full reset */ + if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) + printk("%s: %s: unable to reset hardware; hal status %u\n", + dev->name, __func__, status); + ath_hal_intrset(ah, sc->sc_imask); + if (ath_startrecv(dev) != 0) /* restart recv */ + printk("%s: %s: unable to start recv logic\n", + dev->name, __func__); + if (ic->ic_state == IEEE80211_S_RUN) { + ath_beacon_config(sc); /* restart beacons */ + netif_wake_queue(dev); /* restart xmit */ + } +} + +/* + * Transmit a data packet. On failure caller is + * assumed to reclaim the resources. + */ +static int +ath_hardstart(struct sk_buff *skb, struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct ath_buf *bf = NULL; + struct ieee80211_frame *wh; + int error; + + if ((dev->flags & IFF_RUNNING) == 0 || sc->sc_invalid) { + DPRINTF(("ath_hardstart: discard, invalid %d flags %x\n", + sc->sc_invalid, dev->flags)); + sc->sc_stats.ast_tx_invalid++; + return -ENETDOWN; + } + /* + * No data frames go out unless we're associated; this + * should not happen as the 802.11 layer does not enable + * the xmit queue until we enter the RUN state. + */ + if (ic->ic_state != IEEE80211_S_RUN) { + DPRINTF(("ath_hardstart: discard, state %u\n", ic->ic_state)); + sc->sc_stats.ast_tx_discard++; + /* + * Someone outside the driver started the queue; + * turn it off until we asociate (yech). + */ + netif_stop_queue(dev); + goto bad; + } + /* + * Grab a TX buffer and associated resources. + */ + spin_lock_bh(&sc->sc_txbuflock); + bf = TAILQ_FIRST(&sc->sc_txbuf); + if (bf != NULL) + TAILQ_REMOVE(&sc->sc_txbuf, bf, bf_list); + /* XXX use a counter and leave at least one for mgmt frames */ + if (TAILQ_EMPTY(&sc->sc_txbuf)) { + DPRINTF(("ath_hardstart: stop queue\n")); + sc->sc_stats.ast_tx_qstop++; + netif_stop_queue(dev); + } + spin_unlock_bh(&sc->sc_txbuflock); + if (bf == NULL) { /* NB: should not happen */ + printk("ath_hardstart: discard, no xmit buf\n"); + sc->sc_stats.ast_tx_nobuf++; + goto bad; + } + /* + * Encapsulate the packet for transmission. + */ + skb = ieee80211_encap(dev, skb); + if (skb == NULL) { + DPRINTF(("ath_hardstart: discard, encapsulation failure\n")); + sc->sc_stats.ast_tx_encap++; + goto bad; + } + wh = (struct ieee80211_frame *) skb->data; + if (ic->ic_flags & IEEE80211_F_WEPON) + wh->i_fc[1] |= IEEE80211_FC1_WEP; + + ni = ieee80211_find_node(ic, wh->i_addr1); + if (ni == NULL && + !IEEE80211_IS_MULTICAST(wh->i_addr1) && + ic->ic_opmode != IEEE80211_M_STA) { + DPRINTF(("ath_hardstart: discard, no destination state\n")); + sc->sc_stats.ast_tx_nonode++; + goto bad; + } + if (ni == NULL) + ni = ieee80211_ref_node(&ic->ic_bss); + + /* + * TODO: + * The duration field of 802.11 header should be filled. + * XXX This may be done in the ieee80211 layer, but the upper + * doesn't know the detail of parameters such as IFS + * for now.. + */ + + if (IFF_DUMPPKTS(ic)) + ieee80211_dump_pkt(skb->data, skb->len, + ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL, -1); + + error = ath_tx_start(dev, ni, bf, skb); + ieee80211_unref_node(&ni); + if (error == 0) + return 0; + /* fall thru... */ +bad: + if (bf != NULL) { + spin_lock_bh(&sc->sc_txbuflock); + TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); + spin_unlock_bh(&sc->sc_txbuflock); + } + return 0; /* NB: return !0 only in a ``hard error condition'' */ +} + +/* + * Transmit a management frame. On failure we reclaim the skbuff. + * Note that management frames come directly from the 802.11 layer + * and do not honor the send queue flow control. Need to investigate + * using priority queueing so management frames can bypass data. + */ +static int +ath_mgtstart(struct sk_buff *skb, struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ath_hal *ah = sc->sc_ah; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct ath_buf *bf = NULL; + struct ieee80211_frame *wh; + int error; + + if ((dev->flags & IFF_RUNNING) == 0 || sc->sc_invalid) { + DPRINTF(("ath_mgtstart: discard, invalid %d flags %x\n", + sc->sc_invalid, dev->flags)); + sc->sc_stats.ast_tx_invalid++; + error = -ENETDOWN; + goto bad; + } + /* + * Grab a TX buffer and associated resources. + */ + spin_lock_bh(&sc->sc_txbuflock); + bf = TAILQ_FIRST(&sc->sc_txbuf); + if (bf != NULL) + TAILQ_REMOVE(&sc->sc_txbuf, bf, bf_list); + if (TAILQ_EMPTY(&sc->sc_txbuf)) { + DPRINTF(("ath_hardstart: stop queue\n")); + sc->sc_stats.ast_tx_qstop++; + netif_stop_queue(dev); + } + spin_unlock_bh(&sc->sc_txbuflock); + if (bf == NULL) { + printk("ath_mgtstart: discard, no xmit buf\n"); + sc->sc_stats.ast_tx_nobufmgt++; + error = -ENOBUFS; + goto bad; + } + wh = (struct ieee80211_frame *) skb->data; + if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == + IEEE80211_FC0_SUBTYPE_PROBE_RESP) { + /* fill time stamp */ + u_int64_t tsf; + u_int32_t *tstamp; + + tsf = ath_hal_gettsf64(ah); + /* XXX: adjust 100us delay to xmit */ + tsf += 100; + tstamp = (u_int32_t *)&wh[1]; + tstamp[0] = cpu_to_le32(tsf & 0xffffffff); + tstamp[1] = cpu_to_le32(tsf >> 32); + } + ni = ieee80211_find_node(ic, wh->i_addr1); + if (ni == NULL) + ni = ieee80211_ref_node(&ic->ic_bss); + + /* + * TODO: + * The duration field of 802.11 header should be filled. + * XXX This may be done in the ieee80211 layer, but the upper + * doesn't know the detail of parameters such as IFS + * for now.. + */ + + if (IFF_DUMPPKTS(ic)) + ieee80211_dump_pkt(skb->data, skb->len, + ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL, -1); + + error = ath_tx_start(dev, ni, bf, skb); + ieee80211_unref_node(&ni); + if (error == 0) { + sc->sc_stats.ast_tx_mgmt++; + /* + * XXX probably shouldn't be mucking with this + * stuff, but we need to timeout the xmit. + */ + dev->trans_start = jiffies; + __netdev_watchdog_up(dev); + return 0; + } + /* fall thru... */ +bad: + if (bf != NULL) { + spin_lock_bh(&sc->sc_txbuflock); + TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); + spin_unlock_bh(&sc->sc_txbuflock); + } + dev_kfree_skb(skb); + return error; +} + +static int +ath_media_change(struct net_device *dev) +{ + int error; + + error = ieee80211_media_change(dev); + if (error == ENETRESET) { + if ((dev->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP)) + error = ath_init(dev); + else + error = 0; + } + return error; +} + +/* + * Fill the hardware key cache with key entries. + */ +static void +ath_initkeytable(struct ath_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + int i; + + for (i = 0; i < IEEE80211_WEP_NKID; i++) { + struct ieee80211_wepkey *k = &ic->ic_nw_keys[i]; + if (k->wk_len == 0) + ath_hal_keyreset(ah, i); + else + /* XXX return value */ + ath_hal_keyset(ah, i, (const HAL_KEYVAL *) k); + } +} + +static void +ath_mode_init(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + u_int32_t rfilt, mfilt[2], val; + u_int8_t pos; + struct dev_mc_list *mc; + + /* configure operational mode */ + ath_hal_setopmode(ah, ic->ic_opmode); + + /* receive filter */ + rfilt = (ath_hal_getrxfilter(ah) & HAL_RX_FILTER_PHYERR) + | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; + if (ic->ic_opmode != IEEE80211_M_HOSTAP && (dev->flags & IFF_PROMISC)) + rfilt |= HAL_RX_FILTER_PROM; + if (ic->ic_state == IEEE80211_S_SCAN) + rfilt |= HAL_RX_FILTER_BEACON; + ath_hal_setrxfilter(ah, rfilt); + + /* calculate and install multicast filter */ + if ((dev->flags & IFF_ALLMULTI) == 0) { + mfilt[0] = mfilt[1] = 0; + for (mc = dev->mc_list; mc; mc = mc->next) { + /* calculate XOR of eight 6bit values */ + val = LE_READ_4(mc->dmi_addr + 0); + pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + val = LE_READ_4(mc->dmi_addr + 3); + pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; + pos &= 0x3f; + mfilt[pos / 32] |= (1 << (pos % 32)); + } + } else { + mfilt[0] = mfilt[1] = ~0; + } + ath_hal_setmcastfilter(ah, mfilt[0], mfilt[1]); + DPRINTF(("ath_mode_init: RX filter 0x%x, MC filter %08x:%08x\n", + rfilt, mfilt[0], mfilt[1])); +} + +static struct sk_buff * +ath_alloc_skb(u_int size, u_int align) +{ + struct sk_buff *skb; + u_int off; + + skb = dev_alloc_skb(size + align-1); + if (skb != NULL) { + off = ((unsigned long) skb->data) % align; + if (off != 0) + skb_reserve(skb, align - off); + } + return skb; +} + +static int +ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct net_device *dev = &ic->ic_dev; + struct ath_hal *ah = sc->sc_ah; + struct ieee80211_frame *wh; + struct ath_buf *bf; + struct ath_desc *ds; + struct sk_buff *skb; + int pktlen; + u_int8_t *frm, rate; + u_int16_t capinfo; + const HAL_RATE_TABLE *rt; + + bf = sc->sc_bcbuf; + if (bf->bf_skb != NULL) { + pci_unmap_single(sc->sc_pdev, + bf->bf_skbaddr, bf->bf_skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(bf->bf_skb); + bf->bf_skb = NULL; + bf->bf_node = NULL; + } + pktlen = + 8 + + sizeof(u_int16_t) + + sizeof(u_int16_t) + + 2 + ni->ni_esslen + + 2 + IEEE80211_RATE_SIZE + + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + + 6; + /* + * Beacon frames must be aligned to a 32-bit boundary and + * the buffer length must be a multiple of 4 bytes. Allocate + * an skbuff large enough for us to insure this. + */ + skb = ath_alloc_skb(roundup(sizeof(struct ieee80211_frame)+pktlen, 4), + sizeof(u_int32_t)); + if (skb == NULL) { + DPRINTF(("ath_beacon_alloc: cannot allocate sk_buff; size %u\n", + roundup(sizeof(struct ieee80211_frame)+pktlen, 4))); + sc->sc_stats.ast_be_nobuf++; + return -ENOMEM; + } + + wh = (struct ieee80211_frame *) + skb_put(skb, sizeof(struct ieee80211_frame)); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | + IEEE80211_FC0_SUBTYPE_BEACON; + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + *(u_int16_t *)wh->i_dur = 0; + memcpy(wh->i_addr1, dev->broadcast, IEEE80211_ADDR_LEN); + memcpy(wh->i_addr2, dev->dev_addr, IEEE80211_ADDR_LEN); + memcpy(wh->i_addr3, ni->ni_bssid, IEEE80211_ADDR_LEN); + *(u_int16_t *)wh->i_seq = 0; + + /* + * beacon frame format + * [8] time stamp + * [2] beacon interval + * [2] cabability information + * [tlv] ssid + * [tlv] supported rates + * [tlv] parameter set (IBSS) + * [tlv] extended supported rates + */ + frm = (u_int8_t *) skb_put(skb, pktlen); + memset(frm, 0, 8); /* timestamp is set by hardware */ + frm += 8; + *(u_int16_t *)frm = cpu_to_le16(ni->ni_intval); + frm += 2; + if (ic->ic_opmode == IEEE80211_M_IBSS) + capinfo = IEEE80211_CAPINFO_IBSS; + else + capinfo = IEEE80211_CAPINFO_ESS; + if (ic->ic_flags & IEEE80211_F_WEPON) + capinfo |= IEEE80211_CAPINFO_PRIVACY; + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; + if (ic->ic_flags & IEEE80211_F_SHSLOT) + capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; + *(u_int16_t *)frm = cpu_to_le16(capinfo); + frm += 2; + *frm++ = IEEE80211_ELEMID_SSID; + *frm++ = ni->ni_esslen; + memcpy(frm, ni->ni_essid, ni->ni_esslen); + frm += ni->ni_esslen; + frm = ieee80211_add_rates(frm, &ni->ni_rates); + if (ic->ic_opmode == IEEE80211_M_IBSS) { + *frm++ = IEEE80211_ELEMID_IBSSPARMS; + *frm++ = 2; + *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ + } else { + /* TODO: TIM */ + *frm++ = IEEE80211_ELEMID_TIM; + *frm++ = 4; /* length */ + *frm++ = 0; /* DTIM count */ + *frm++ = 1; /* DTIM period */ + *frm++ = 0; /* bitmap control */ + *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ + } + frm = ieee80211_add_xrates(frm, &ni->ni_rates); + skb_trim(skb, frm - skb->data); + + bf->bf_skbaddr = pci_map_single(sc->sc_pdev, + skb->data, skb->len, PCI_DMA_TODEVICE); + DPRINTF2(("ath_beacon_alloc: skb %p [data %p len %u] skbaddr %p\n", + skb, skb->data, skb->len, (caddr_t) bf->bf_skbaddr)); + bf->bf_skb = skb; + + /* setup descriptors */ + ds = bf->bf_desc; + + ds->ds_link = 0; + ds->ds_data = bf->bf_skbaddr; + /* XXX verify mbuf data area covers this roundup */ + /* + * Calculate rate code. + * XXX everything at min xmit rate + */ + rt = sc->sc_currates; + KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); + if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) == 0) + rate = rt->info[0].rateCode | rt->info[0].shortPreamble; + else + rate = rt->info[0].rateCode; + ath_hal_setuptxdesc(ah, ds + , skb->len + IEEE80211_CRC_LEN /* frame length */ + , sizeof(struct ieee80211_frame)/* header length */ + , HAL_PKT_TYPE_BEACON /* Atheros packet type */ + , 0x20 /* txpower XXX */ + , rate, 1 /* series 0 rate/tries */ + , HAL_TXKEYIX_INVALID /* no encryption */ + , 0 /* antenna mode */ + , HAL_TXDESC_NOACK /* no ack for beacons */ + , 0 /* rts/cts rate */ + , 0 /* rts/cts duration */ + ); + /* NB: beacon's BufLen must be a multiple of 4 bytes */ + ath_hal_filltxdesc(ah, ds + , roundup(skb->len, 4) /* buffer length */ + , AH_TRUE /* first segment */ + , AH_TRUE /* last segment */ + ); + return 0; +} + +static void +ath_beacon_tasklet(void *data) +{ + struct net_device *dev = data; + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ath_buf *bf = sc->sc_bcbuf; + struct ath_hal *ah = sc->sc_ah; + + DPRINTF(("ath_beacon_tasklet\n")); + if (ic->ic_opmode == IEEE80211_M_STA || bf == NULL || bf->bf_skb == NULL) { + DPRINTF(("ath_beacon_int: ic_flags=%x bf=%p bf_m=%p\n", + ic->ic_flags, bf, bf ? bf->bf_skb : NULL)); + return; + } + /* update beacon to reflect PS poll state */ + if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) { + DPRINTF(("%s: beacon queue %u did not stop?", + __func__, sc->sc_bhalq)); + return; /* busy, XXX is this right? */ + } + pci_dma_sync_single(sc->sc_pdev, + bf->bf_skbaddr, bf->bf_skb->len, PCI_DMA_TODEVICE); + + ath_hal_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); + ath_hal_txstart(ah, sc->sc_bhalq); + DPRINTF2(("%s: TXDP%u = %p (%p)\n", __func__, + sc->sc_bhalq, (caddr_t)bf->bf_daddr, bf->bf_desc)); +} + +static void +ath_beacon_free(struct ath_softc *sc) +{ + struct ath_buf *bf = sc->sc_bcbuf; + + if (bf->bf_skb != NULL) { + pci_unmap_single(sc->sc_pdev, + bf->bf_skbaddr, bf->bf_skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(bf->bf_skb); + bf->bf_skb = NULL; + bf->bf_node = NULL; + } +} + +/* + * Configure the beacon and sleep timers. + * + * When operating as an AP this resets the TSF and sets + * up the hardware to notify us when we need to issue beacons. + * + * When operating in station mode this sets up the beacon + * timers according to the timestamp of the last received + * beacon and the current TSF, configures PCF and DTIM + * handling, programs the sleep registers so the hardware + * will wakeup in time to receive beacons, and configures + * the beacon miss handling so we'll receive a BMISS + * interrupt when we stop seeing beacons from the AP + * we've associated with. + */ +static void +ath_beacon_config(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni = &ic->ic_bss; + u_int32_t nexttbtt; + + nexttbtt = (LE_READ_4(ni->ni_tstamp + 4) << 22) | + (LE_READ_4(ni->ni_tstamp) >> 10); + DPRINTF(("%s: nexttbtt=%u\n", __func__, nexttbtt)); + nexttbtt += ni->ni_intval; + if (ic->ic_opmode != IEEE80211_M_HOSTAP) { + HAL_BEACON_STATE bs; + u_int32_t bmisstime; + + /* NB: no PCF support right now */ + memset(&bs, 0, sizeof(bs)); + bs.bs_intval = ni->ni_intval; + bs.bs_nexttbtt = nexttbtt; + bs.bs_dtimperiod = bs.bs_intval; + bs.bs_nextdtim = nexttbtt; + /* + * Calculate the number of consecutive beacons to miss + * before taking a BMISS interrupt. The configuration + * is specified in ms, so we need to convert that to + * TU's and then calculate based on the beacon interval. + * Note that we clamp the result to at most 10 beacons. + */ + bmisstime = (ic->ic_bmisstimeout * 1000) / 1024; + bs.bs_bmissthreshold = howmany(bmisstime,ni->ni_intval); + if (bs.bs_bmissthreshold > 10) + bs.bs_bmissthreshold = 10; + else if (bs.bs_bmissthreshold <= 0) + bs.bs_bmissthreshold = 1; + + /* + * Calculate sleep duration. The configuration is + * given in ms. We insure a multiple of the beacon + * period is used. Also, if the sleep duration is + * greater than the DTIM period then it makes senses + * to make it a multiple of that. + * + * XXX fixed at 100ms + */ + bs.bs_sleepduration = + roundup((100 * 1000) / 1024, bs.bs_intval); + if (bs.bs_sleepduration > bs.bs_dtimperiod) + bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod); + + DPRINTF(("%s: intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u\n" + , __func__ + , bs.bs_intval + , bs.bs_nexttbtt + , bs.bs_dtimperiod + , bs.bs_nextdtim + , bs.bs_bmissthreshold + , bs.bs_sleepduration + )); + ath_hal_intrset(ah, 0); + /* + * Reset our tsf so the hardware will update the + * tsf register to reflect timestamps found in + * received beacons. + */ + ath_hal_resettsf(ah); + ath_hal_beacontimers(ah, &bs, 0/*XXX*/, 0, 0); + sc->sc_imask |= HAL_INT_BMISS; + ath_hal_intrset(ah, sc->sc_imask); + } else { + DPRINTF(("%s: intval %u nexttbtt %u\n", + __func__, ni->ni_intval, nexttbtt)); + ath_hal_intrset(ah, 0); + ath_hal_beaconinit(ah, ic->ic_opmode, + nexttbtt, ni->ni_intval); + sc->sc_imask |= HAL_INT_SWBA; /* beacon prepare */ + ath_hal_intrset(ah, sc->sc_imask); + } +} + +static int +ath_desc_alloc(struct ath_softc *sc) +{ + int i, bsize; + struct ath_desc *ds; + struct ath_buf *bf; + + /* allocate descriptors */ + sc->sc_desc_len = sizeof(struct ath_desc) * + (ATH_TXBUF * ATH_TXDESC + ATH_RXBUF + 1); + sc->sc_desc = pci_alloc_consistent(sc->sc_pdev, + sc->sc_desc_len, &sc->sc_desc_daddr); + if (sc->sc_desc == NULL) + return -ENOMEM; + ds = sc->sc_desc; + DPRINTF(("ath_desc_alloc: DMA map: %p (%d) -> %p\n", + ds, sc->sc_desc_len, (caddr_t) sc->sc_desc_daddr)); + + /* allocate buffers */ + bsize = sizeof(struct ath_buf) * (ATH_TXBUF + ATH_RXBUF + 1); + bf = kmalloc(bsize, GFP_KERNEL); + if (bf == NULL) + goto bad; + memset(bf, 0, bsize); + sc->sc_bufptr = bf; + + TAILQ_INIT(&sc->sc_rxbuf); + for (i = 0; i < ATH_RXBUF; i++, bf++, ds++) { + bf->bf_desc = ds; + bf->bf_daddr = sc->sc_desc_daddr + + ((caddr_t)ds - (caddr_t)sc->sc_desc); + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); + } + + TAILQ_INIT(&sc->sc_txbuf); + for (i = 0; i < ATH_TXBUF; i++, bf++, ds += ATH_TXDESC) { + bf->bf_desc = ds; + bf->bf_daddr = sc->sc_desc_daddr + + ((caddr_t)ds - (caddr_t)sc->sc_desc); + TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); + } + TAILQ_INIT(&sc->sc_txq); + + /* beacon buffer */ + bf->bf_desc = ds; + bf->bf_daddr = sc->sc_desc_daddr + ((caddr_t)ds - (caddr_t)sc->sc_desc); + sc->sc_bcbuf = bf; + return 0; +bad: + pci_free_consistent(sc->sc_pdev, sc->sc_desc_len, + sc->sc_desc, sc->sc_desc_daddr); + sc->sc_desc = NULL; + return -ENOMEM; +} + +static void +ath_desc_free(struct ath_softc *sc) +{ + struct ath_buf *bf; + + TAILQ_FOREACH(bf, &sc->sc_txq, bf_list) { + pci_unmap_single(sc->sc_pdev, + bf->bf_skbaddr, bf->bf_skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(bf->bf_skb); + bf->bf_skb = NULL; + } + TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) + if (bf->bf_skb != NULL) { + pci_unmap_single(sc->sc_pdev, + bf->bf_skbaddr, bf->bf_skb->len, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(bf->bf_skb); + bf->bf_skb = NULL; + } + if (sc->sc_bcbuf != NULL) { + bf = sc->sc_bcbuf; + pci_unmap_single(sc->sc_pdev, bf->bf_skbaddr, + bf->bf_skb->len, PCI_DMA_TODEVICE); + sc->sc_bcbuf = NULL; + } + + pci_free_consistent(sc->sc_pdev, sc->sc_desc_len, + sc->sc_desc, sc->sc_desc_daddr); + + TAILQ_INIT(&sc->sc_rxbuf); + TAILQ_INIT(&sc->sc_txbuf); + TAILQ_INIT(&sc->sc_txq); + kfree(sc->sc_bufptr); + sc->sc_bufptr = NULL; +} + +static void +ath_node_free(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct ath_softc *sc = ic->ic_dev.priv; + struct ath_buf *bf; + + /* XXX do we need to block bh? */ + spin_lock_bh(&sc->sc_txqlock); + TAILQ_FOREACH(bf, &sc->sc_txq, bf_list) { + if (bf->bf_node == ni) + bf->bf_node = NULL; + } + spin_unlock_bh(&sc->sc_txqlock); +} + +static int +ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf) +{ + struct ath_hal *ah = sc->sc_ah; + struct sk_buff *skb; + struct ath_desc *ds; + + skb = bf->bf_skb; + if (skb == NULL) { + /* + * Cache-line-align. This is important (for the 5210 at + * least) as not doing so causes bogus data in rx'd frames. + */ + skb = ath_alloc_skb(sc->sc_rxbufsize, sc->sc_cachelsz); + if (skb == NULL) { + DPRINTF(("ath_rxbuf_init: skbuff allocation failed; " + "size %u\n", sc->sc_rxbufsize)); + sc->sc_stats.ast_rx_nobuf++; + return -ENOMEM; + } + skb->dev = &sc->sc_ic.ic_dev; + bf->bf_skb = skb; + bf->bf_skbaddr = pci_map_single(sc->sc_pdev, + skb->data, skb->len, PCI_DMA_FROMDEVICE); + } + + /* setup descriptors */ + ds = bf->bf_desc; + ds->ds_link = 0; + ds->ds_data = bf->bf_skbaddr; + ath_hal_setuprxdesc(ah, ds + , skb_tailroom(skb) /* buffer size */ + , 0 + ); + + if (sc->sc_rxlink != NULL) + *sc->sc_rxlink = bf->bf_daddr; + sc->sc_rxlink = &ds->ds_link; + return 0; +} + +static void +ath_rx_tasklet(void *data) +{ + struct net_device *dev = data; + struct ath_buf *bf; + struct ath_softc *sc = dev->priv; + struct net_device_stats *stats = &sc->sc_ic.ic_stats; + struct ath_hal *ah = sc->sc_ah; + struct ath_desc *ds; + struct sk_buff *skb; + struct ieee80211_frame *wh, whbuf; + int len; + u_int8_t phyerr; + HAL_STATUS status; + + DPRINTF2(("ath_rx_tasklet\n")); + do { + bf = TAILQ_FIRST(&sc->sc_rxbuf); + if (bf == NULL) { /* XXX ??? can this happen */ + printk("ath_rx_tasklet: no buffer\n"); + break; + } + skb = bf->bf_skb; + if (skb == NULL) { /* XXX ??? can this happen */ + printk("ath_rx_tasklet: no skbuff\n"); + continue; + } + ds = bf->bf_desc; + status = ath_hal_rxprocdesc(ah, ds); +#ifdef AR_DEBUG + if (ath_debug > 1) + ath_printrxbuf(bf, status == HAL_OK); +#endif + if (status == HAL_EINPROGRESS) + break; + TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list); + + if (ds->ds_rxstat.rs_status != 0) { + if (ds->ds_rxstat.rs_status & HAL_RXERR_CRC) { + sc->sc_stats.ast_rx_crcerr++; + /* + * Record the rssi for crc errors; it + * should still be valid. + */ + sc->sc_stats.ast_rx_rssidelta = + ds->ds_rxstat.rs_rssi - + sc->sc_stats.ast_rx_rssi; + sc->sc_stats.ast_rx_rssi = + ds->ds_rxstat.rs_rssi; + } + if (ds->ds_rxstat.rs_status & HAL_RXERR_FIFO) + sc->sc_stats.ast_rx_fifoerr++; + if (ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT) + sc->sc_stats.ast_rx_badcrypt++; + if (ds->ds_rxstat.rs_status & HAL_RXERR_PHY) { + sc->sc_stats.ast_rx_phyerr++; + phyerr = ds->ds_rxstat.rs_phyerr & 0x1f; + sc->sc_stats.ast_rx_phy[phyerr]++; + } + goto rx_next; + } + sc->sc_stats.ast_rx_rssidelta = + ds->ds_rxstat.rs_rssi - sc->sc_stats.ast_rx_rssi; + sc->sc_stats.ast_rx_rssi = ds->ds_rxstat.rs_rssi; + + len = ds->ds_rxstat.rs_datalen; + if (len < sizeof(struct ieee80211_frame)) { + DPRINTF(("%s: ath_rx_tasklet: short packet %d\n", + dev->name, len)); + sc->sc_stats.ast_rx_tooshort++; + goto rx_next; + } + + pci_dma_sync_single(sc->sc_pdev, + bf->bf_skbaddr, len, PCI_DMA_FROMDEVICE); + + wh = (struct ieee80211_frame *) skb->data; + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_CTL) { + /* + * Ignore control frame received in promisc mode. + */ + DPRINTF(("%s: ath_rx_tasklet: discard ctl frame, " + "fc %x\n", dev->name, wh->i_fc[0])); + goto rx_next; + } + pci_unmap_single(sc->sc_pdev, + bf->bf_skbaddr, skb->len, PCI_DMA_FROMDEVICE); + bf->bf_skb = NULL; + skb_put(skb, len); + skb->protocol = ETH_P_CONTROL; /* XXX */ + if (IFF_DUMPPKTS(&sc->sc_ic)) { + struct ieee80211com *ic = &sc->sc_ic; + const HAL_RATE_TABLE *rt = sc->sc_rates[ic->ic_curmode]; + ieee80211_dump_pkt(skb->data, len, + rt->info[rt->rateCodeToIndex[ds->ds_rxstat.rs_rate]].dot11Rate & IEEE80211_RATE_VAL, + ds->ds_rxstat.rs_rssi); + } + skb_trim(skb, skb->len - IEEE80211_CRC_LEN); + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + /* + * WEP is decrypted by hardware. Clear WEP bit + * and trim WEP header for ieee80211_input(). + */ + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + memcpy(&whbuf, wh, sizeof(whbuf)); + skb_pull(skb, IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN); + memcpy(skb->data, &whbuf, sizeof(whbuf)); + /* + * Also trim WEP ICV from the tail. + */ + skb_trim(skb, skb->len - IEEE80211_WEP_CRCLEN); + } + stats->rx_packets++; + stats->rx_bytes += len; + ieee80211_input(dev, skb, + ds->ds_rxstat.rs_rssi, + ds->ds_rxstat.rs_tstamp, + ds->ds_rxstat.rs_antenna); + rx_next: + TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); + } while (ath_rxbuf_init(sc, bf) == 0); + + ath_hal_rxmonitor(ah); /* rx signal state monitoring */ + ath_hal_rxena(ah); /* in case of RXEOL */ +} + +/* + * XXX Size of an ACK control frame in bytes. + */ +#define IEEE80211_ACK_SIZE (2+2+IEEE80211_ADDR_LEN+4) + +static int +ath_tx_start(struct net_device *dev, struct ieee80211_node *ni, struct ath_buf *bf, + struct sk_buff *skb) +{ + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + struct net_device_stats *stats = &ic->ic_stats; + int i, iswep, hdrlen, pktlen; + u_int8_t rix, cix, txrate, ctsrate; + struct ath_desc *ds; + struct ieee80211_frame *wh; + u_int32_t iv; + u_int8_t *ivp; + u_int8_t hdrbuf[sizeof(struct ieee80211_frame) + + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN]; + u_int subtype, flags, ctsduration, antenna; + HAL_PKT_TYPE atype; + const HAL_RATE_TABLE *rt; + HAL_BOOL shortPreamble; + struct ath_nodestat *st; + + wh = (struct ieee80211_frame *) skb->data; + iswep = wh->i_fc[1] & IEEE80211_FC1_WEP; + hdrlen = sizeof(struct ieee80211_frame); + pktlen = skb->len; + + if (iswep) { + memcpy(hdrbuf, skb->data, hdrlen); + skb_pull(skb, hdrlen); + skb_push(skb, sizeof(hdrbuf)); + ivp = hdrbuf + hdrlen; + /* + * XXX + * IV must not duplicate during the lifetime of the key. + * But no mechanism to renew keys is defined in IEEE 802.11 + * WEP. And IV may be duplicated between other stations + * because of the session key itself is shared. + * So we use pseudo random IV for now, though it is not the + * right way. + */ + get_random_bytes(&iv, sizeof(iv)); + for (i = 0; i < IEEE80211_WEP_IVLEN; i++) { + ivp[i] = iv; + iv >>= 8; + } + ivp[i] = sc->sc_ic.ic_wep_txkey << 6; /* Key ID and pad */ + memcpy(skb->data, hdrbuf, sizeof(hdrbuf)); + /* + * The ICV length must be included into hdrlen and pktlen. + */ + hdrlen = sizeof(hdrbuf) + IEEE80211_WEP_CRCLEN; + pktlen += IEEE80211_WEP_CRCLEN; + } + pktlen += IEEE80211_CRC_LEN; + + /* + * Load the DMA map so any coalescing is done. This + * also calculates the number of descriptors we need. + */ + bf->bf_skbaddr = pci_map_single(sc->sc_pdev, + skb->data, skb->len, PCI_DMA_TODEVICE); + DPRINTF2(("ath_tx_start: skb %p [data %p len %u] skbaddr %x\n", + skb, skb->data, skb->len, bf->bf_skbaddr)); + bf->bf_skb = skb; + bf->bf_node = ni; + + /* setup descriptors */ + ds = bf->bf_desc; + rt = sc->sc_currates; + KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode)); + + /* + * Calculate Atheros packet type from IEEE80211 packet header + * and setup for rate calculations. + */ + atype = HAL_PKT_TYPE_NORMAL; /* default */ + switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { + case IEEE80211_FC0_TYPE_MGT: + subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) + atype = HAL_PKT_TYPE_BEACON; + else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) + atype = HAL_PKT_TYPE_PROBE_RESP; + else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM) + atype = HAL_PKT_TYPE_ATIM; + rix = 0; /* XXX lowest rate */ + break; + case IEEE80211_FC0_TYPE_CTL: + subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + if (subtype == IEEE80211_FC0_SUBTYPE_PS_POLL) + atype = HAL_PKT_TYPE_PSPOLL; + rix = 0; /* XXX lowest rate */ + break; + default: + rix = sc->sc_rixmap[ni->ni_rates.rs_rates[ni->ni_txrate] & + IEEE80211_RATE_VAL]; + if (rix == 0xff) { + printk("%s: %s: bogus xmit rate 0x%x\n", + dev->name, __func__, + ni->ni_rates.rs_rates[ni->ni_txrate]); + sc->sc_stats.ast_tx_badrate++; + return -EIO; + } + break; + } + /* + * NB: the 802.11 layer marks whether or not we should + * use short preamble based on the current mode and + * negotiated parameters. + */ + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) { + txrate = rt->info[rix].rateCode | rt->info[rix].shortPreamble; + shortPreamble = AH_TRUE; + sc->sc_stats.ast_tx_shortpre++; + } else { + txrate = rt->info[rix].rateCode; + shortPreamble = AH_FALSE; + } + + /* + * Calculate miscellaneous flags. + */ + flags = HAL_TXDESC_CLRDMASK; /* XXX needed for wep errors */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { + flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */ + sc->sc_stats.ast_tx_noack++; + } else if (pktlen > ic->ic_rtsthreshold) { + flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */ + sc->sc_stats.ast_tx_rts++; + } + + /* + * Calculate RTS/CTS rate and duration if needed. + */ + ctsduration = 0; + if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) { + /* + * CTS transmit rate is derived from the transmit rate + * by looking in the h/w rate table. We must also factor + * in whether or not a short preamble is to be used. + */ + cix = rt->info[rix].controlRate; + ctsrate = rt->info[cix].rateCode; + if (shortPreamble) + ctsrate |= rt->info[cix].shortPreamble; + /* + * Compute the transmit duration based on the size + * of an ACK frame. We call into the HAL to do the + * computation since it depends on the characteristics + * of the actual PHY being used. + */ + if (flags & HAL_TXDESC_RTSENA) { /* SIFS + CTS */ + ctsduration += ath_hal_computetxtime(ah, + rt, IEEE80211_ACK_SIZE, cix, shortPreamble); + } + /* SIFS + data */ + ctsduration += ath_hal_computetxtime(ah, + rt, pktlen, rix, shortPreamble); + if ((flags & HAL_TXDESC_NOACK) == 0) { /* SIFS + ACK */ + ctsduration += ath_hal_computetxtime(ah, + rt, IEEE80211_ACK_SIZE, cix, shortPreamble); + } + } else + ctsrate = 0; + + /* + * For now use the antenna on which the last good + * frame was received on. We assume this field is + * initialized to 0 which gives us ``auto'' or the + * ``default'' antenna. + */ + st = ni->ni_private; + if (st->st_tx_antenna) + antenna = st->st_tx_antenna; + else + antenna = ni->ni_rantenna; + + /* + * Formulate first tx descriptor with tx controls. + */ + /* XXX check return value? */ + ath_hal_setuptxdesc(ah, ds + , pktlen /* packet length */ + , hdrlen /* header length */ + , atype /* Atheros packet type */ + , 60 /* txpower XXX */ + , txrate, 1+10 /* series 0 rate/tries */ + , iswep ? sc->sc_ic.ic_wep_txkey : HAL_TXKEYIX_INVALID + , antenna /* antenna mode */ + , flags /* flags */ + , ctsrate /* rts/cts rate */ + , ctsduration /* rts/cts duration */ + ); +#ifdef notyet + ath_hal_setupxtxdesc(ah, ds + , AH_FALSE /* short preamble */ + , 0, 0 /* series 1 rate/tries */ + , 0, 0 /* series 2 rate/tries */ + , 0, 0 /* series 3 rate/tries */ + ); +#endif + + ds->ds_link = 0; + ds->ds_data = bf->bf_skbaddr; + ath_hal_filltxdesc(ah, ds + , skb->len /* segment length */ + , AH_TRUE /* first segment */ + , AH_TRUE /* last segment */ + ); + DPRINTF2(("ath_tx_start: %d: %08x %08x %08x %08x %08x %08x\n", + 0, ds->ds_link, ds->ds_data, ds->ds_ctl0, ds->ds_ctl1, + ds->ds_hw[0], ds->ds_hw[1])); + + spin_lock_bh(&sc->sc_txqlock); + TAILQ_INSERT_TAIL(&sc->sc_txq, bf, bf_list); + if (sc->sc_txlink == NULL) { + ath_hal_puttxbuf(ah, sc->sc_txhalq, bf->bf_daddr); + DPRINTF2(("ath_tx_start: TXDP0 = %p (%p)\n", + (caddr_t)bf->bf_daddr, bf->bf_desc)); + } else { + *sc->sc_txlink = bf->bf_daddr; + DPRINTF2(("ath_tx_start: link(%p)=%p (%p)\n", + sc->sc_txlink, (caddr_t)bf->bf_daddr, bf->bf_desc)); + } + sc->sc_txlink = &ds->ds_link; + spin_unlock_bh(&sc->sc_txqlock); + + ath_hal_txstart(ah, sc->sc_txhalq); + + stats->tx_packets++; + stats->tx_bytes += pktlen; + + return 0; +} + +static void +ath_tx_tasklet(void *data) +{ + struct net_device *dev = data; + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + struct ath_buf *bf; + struct ath_desc *ds; + struct ieee80211_node *ni; + struct ath_nodestat *st; + int sr, lr; + HAL_STATUS status; + + DPRINTF2(("ath_tx_tasklet: tx queue %p, link %p\n", + (caddr_t) ath_hal_gettxbuf(sc->sc_ah, sc->sc_txhalq), + sc->sc_txlink)); + for (;;) { + spin_lock(&sc->sc_txqlock); + bf = TAILQ_FIRST(&sc->sc_txq); + if (bf == NULL) { + sc->sc_txlink = NULL; + spin_unlock(&sc->sc_txqlock); + break; + } + ds = bf->bf_desc; /* NB: last decriptor */ + status = ath_hal_txprocdesc(ah, ds); +#ifdef AR_DEBUG + if (ath_debug > 1) + ath_printtxbuf(bf, status == HAL_OK); +#endif + if (status == HAL_EINPROGRESS) { + spin_unlock(&sc->sc_txqlock); + break; + } + TAILQ_REMOVE(&sc->sc_txq, bf, bf_list); + spin_unlock(&sc->sc_txqlock); + + ni = bf->bf_node; + if (ni != NULL) { + st = ni->ni_private; + if (ds->ds_txstat.ts_status == 0) { + st->st_tx_ok++; + st->st_tx_antenna = ds->ds_txstat.ts_antenna; + sc->sc_stats.ast_tx_rssidelta = + ds->ds_txstat.ts_rssi - + sc->sc_stats.ast_tx_rssi; + sc->sc_stats.ast_tx_rssi = + ds->ds_txstat.ts_rssi; + } else { + st->st_tx_err++; + if (ds->ds_txstat.ts_status & HAL_TXERR_XRETRY) + sc->sc_stats.ast_tx_xretries++; + if (ds->ds_txstat.ts_status & HAL_TXERR_FIFO) + sc->sc_stats.ast_tx_fifoerr++; + if (ds->ds_txstat.ts_status & HAL_TXERR_FILT) + sc->sc_stats.ast_tx_filtered++; + st->st_tx_antenna = 0; /* invalidate */ + } + sr = ds->ds_txstat.ts_shortretry; + lr = ds->ds_txstat.ts_longretry; + sc->sc_stats.ast_tx_shortretry += sr; + sc->sc_stats.ast_tx_longretry += lr; + if (sr + lr) + st->st_tx_retr++; + } + pci_unmap_single(sc->sc_pdev, + bf->bf_skbaddr, bf->bf_skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(bf->bf_skb); + bf->bf_skb = NULL; + bf->bf_node = NULL; + + spin_lock(&sc->sc_txbuflock); + TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); + spin_unlock(&sc->sc_txbuflock); + } + /* + * Don't wakeup unless we're associated; this insures we don't + * signal the upper layer it's ok to start sending data frames. + */ + /* XXX use a low watermark to reduce wakeups */ + if (ic->ic_state == IEEE80211_S_RUN) + netif_wake_queue(dev); +} + +static void +ath_tx_timeout(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + + sc->sc_stats.ast_watchdog++; + if (ath_debug) + ath_hal_dumpstate(sc->sc_ah); + ath_init(dev); +} + +/* + * Drain the transmit queue and reclaim resources. + */ +static void +ath_draintxq(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + struct ath_buf *bf; + + /* XXX return value */ + if (!sc->sc_invalid) { + (void) ath_hal_stoptxdma(ah, sc->sc_txhalq); + DPRINTF(("ath_draintxq: tx queue %p, link %p\n", + (caddr_t) ath_hal_gettxbuf(ah, sc->sc_txhalq), + sc->sc_txlink)); + (void) ath_hal_stoptxdma(ah, sc->sc_bhalq); + DPRINTF(("ath_draintxq: beacon queue %p\n", + (caddr_t) ath_hal_gettxbuf(ah, sc->sc_bhalq))); + } + for (;;) { + spin_lock_bh(&sc->sc_txqlock); + bf = TAILQ_FIRST(&sc->sc_txq); + if (bf == NULL) { + sc->sc_txlink = NULL; + spin_unlock_bh(&sc->sc_txqlock); + break; + } + TAILQ_REMOVE(&sc->sc_txq, bf, bf_list); + spin_unlock_bh(&sc->sc_txqlock); +#ifdef AR_DEBUG + if (ath_debug) + ath_printtxbuf(bf, + ath_hal_txprocdesc(ah, bf->bf_desc) == HAL_OK); +#endif /* AR_DEBUG */ + pci_unmap_single(sc->sc_pdev, + bf->bf_skbaddr, bf->bf_skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(bf->bf_skb); + bf->bf_skb = NULL; + bf->bf_node = NULL; + + spin_lock_bh(&sc->sc_txbuflock); + TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); + spin_unlock_bh(&sc->sc_txbuflock); + } +} + +/* + * Disable the receive h/w in preparation for a reset. + */ +static void +ath_stoprecv(struct ath_softc *sc) +{ + struct ath_hal *ah = sc->sc_ah; + + ath_hal_stoppcurecv(ah); /* disable PCU */ + ath_hal_setrxfilter(ah, 0); /* clear recv filter */ + ath_hal_stopdmarecv(ah); /* disable DMA engine */ + udelay(3000); /* long enough for 1 frame */ +#ifdef AR_DEBUG + if (ath_debug) { + struct ath_buf *bf; + + printk("ath_stoprecv: rx queue %p, link %p\n", + (caddr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink); + TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { + if (ath_hal_rxprocdesc(ah, bf->bf_desc) == HAL_OK) + ath_printrxbuf(bf, 1); + } + } +#endif + sc->sc_rxlink = NULL; /* just in case */ +} + +/* + * Enable the receive h/w following a reset. + */ +static int +ath_startrecv(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct ath_hal *ah = sc->sc_ah; + struct ath_buf *bf; + + sc->sc_rxbufsize = roundup(dev->mtu + IEEE80211_CRC_LEN + + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + + IEEE80211_WEP_CRCLEN), sc->sc_cachelsz); + DPRINTF(("ath_startrecv: mtu %u cachelsz %u rxbufsize %u\n", + dev->mtu, sc->sc_cachelsz, sc->sc_rxbufsize)); + + sc->sc_rxlink = NULL; + TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { + int error = ath_rxbuf_init(sc, bf); + if (error != 0) + return error; + } + + bf = TAILQ_FIRST(&sc->sc_rxbuf); + ath_hal_putrxbuf(ah, bf->bf_daddr); + ath_hal_rxena(ah); /* enable recv descriptors */ + ath_mode_init(&sc->sc_ic.ic_dev);/* set filters, etc. */ + ath_hal_startpcurecv(ah); /* re-enable PCU/DMA engine */ + return 0; +} + +/* + * Set/change channels. If the channel is really being changed, + * it's done by resetting the chip. To accomplish this we must + * first cleanup any pending DMA, then restart stuff after a la + * ath_init. + */ +static int +ath_chan_set(struct ath_softc *sc, struct ieee80211channel *chan) +{ + struct ath_hal *ah = sc->sc_ah; + struct ieee80211com *ic = &sc->sc_ic; + struct net_device *dev = &ic->ic_dev; + + DPRINTF(("%s: %u (%u MHz) -> %u (%u MHz)\n", __func__, + ieee80211_chan2ieee(ic, ic->ic_ibss_chan), + ic->ic_ibss_chan->ic_freq, + ieee80211_chan2ieee(ic, chan), chan->ic_freq)); + if (chan != ic->ic_ibss_chan) { + HAL_STATUS status; + HAL_CHANNEL hchan; + enum ieee80211_phymode mode; + + /* + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath_hal_intrset(ah, 0); /* disable interrupts */ + ath_draintxq(sc); /* clear pending tx frames */ + ath_stoprecv(sc); /* turn off frame recv */ + /* + * Convert to a HAL channel description with + * the flags constrained to reflect the current + * operating mode. + */ + hchan.channel = chan->ic_freq; + hchan.channelFlags = ath_chan2flags(ic, chan); + if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) { + printk("%s: %s: unable to reset channel %u (%uMhz)\n", + dev->name, __func__, + ieee80211_chan2ieee(ic, chan), chan->ic_freq); + return -EIO; + } + + /* + * Re-enable rx framework. + */ + if (ath_startrecv(dev) != 0) { + printk("%s: %s: unable to restart recv logic\n", + dev->name, __func__); + return -EIO; + } + + /* + * Re-enable interrupts. + */ + ath_hal_intrset(ah, sc->sc_imask); + + /* + * Change channels and update the h/w rate map + * if we're switching; e.g. 11a to 11b/g. + */ + ic->ic_ibss_chan = chan; + mode = ieee80211_chan2mode(ic, chan); + if (mode != sc->sc_curmode) + ath_setcurmode(sc, mode); + } + return 0; +} + +static void +ath_next_scan(unsigned long arg) +{ + struct net_device *dev = (struct net_device *) arg; + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_state == IEEE80211_S_SCAN) + ieee80211_next_scan(dev); +} + +/* + * Periodically recalibrate the PHY to account + * for temperature/environment changes. + */ +static void +ath_calibrate(unsigned long arg) +{ + struct net_device *dev = (struct net_device *) arg; + struct ath_softc *sc = dev->priv; + struct ath_hal *ah = sc->sc_ah; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211channel *c; + HAL_CHANNEL hchan; + + sc->sc_stats.ast_per_cal++; + + /* + * Convert to a HAL channel description with the flags + * constrained to reflect the current operating mode. + */ + c = ic->ic_ibss_chan; + hchan.channel = c->ic_freq; + hchan.channelFlags = ath_chan2flags(ic, c); + + DPRINTF2(("%s: channel %u/%x\n", __func__, c->ic_freq, c->ic_flags)); + + if (ath_hal_getrfgain(ah) == HAL_RFGAIN_NEED_CHANGE) { + /* + * Rfgain is out of bounds, reset the chip + * to load new gain values. + */ + sc->sc_stats.ast_per_rfgain++; + ath_reset(dev); + } + if (!ath_hal_calibrate(ah, &hchan)) { + DPRINTF(("%s: %s: calibration of channel %u failed\n", + dev->name, __func__, c->ic_freq)); + sc->sc_stats.ast_per_calfail++; + } + sc->sc_cal_ch.expires = jiffies + (ath_calinterval * HZ); + add_timer(&sc->sc_cal_ch); +} + +static int +ath_newstate(void *arg, enum ieee80211_state nstate) +{ + struct net_device *dev = (struct net_device *) arg; + struct ath_softc *sc = dev->priv; + struct ath_hal *ah = sc->sc_ah; + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + int i, error; + u_int8_t *bssid; + u_int32_t rfilt; + enum ieee80211_state ostate; +#ifdef AR_DEBUG + static const char *stname[] = + { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; +#endif /* AR_DEBUG */ + static const HAL_LED_STATE leds[] = { + HAL_LED_INIT, /* IEEE80211_S_INIT */ + HAL_LED_SCAN, /* IEEE80211_S_SCAN */ + HAL_LED_AUTH, /* IEEE80211_S_AUTH */ + HAL_LED_ASSOC, /* IEEE80211_S_ASSOC */ + HAL_LED_RUN, /* IEEE80211_S_RUN */ + }; + + ostate = ic->ic_state; + + DPRINTF(("%s: %s -> %s\n", __func__, stname[ostate], stname[nstate])); + + ath_hal_setledstate(ah, leds[nstate]); /* set LED */ + netif_stop_queue(dev); /* before we do anything else */ + + if (nstate == IEEE80211_S_INIT) { + sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); + ath_hal_intrset(ah, sc->sc_imask); + error = 0; /* cheat + use error return */ + goto bad; + } + ni = &ic->ic_bss; + error = ath_chan_set(sc, ni->ni_chan); + if (error != 0) + goto bad; + rfilt = (ath_hal_getrxfilter(ah) & HAL_RX_FILTER_PHYERR) + | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; + if (ic->ic_opmode != IEEE80211_M_HOSTAP && (dev->flags & IFF_PROMISC)) + rfilt |= HAL_RX_FILTER_PROM; + if (nstate == IEEE80211_S_SCAN) { + mod_timer(&sc->sc_scan_ch, + jiffies + ((HZ * ath_dwelltime) / 1000)); + bssid = dev->broadcast; + rfilt |= HAL_RX_FILTER_BEACON; + } else { + del_timer(&sc->sc_scan_ch); + bssid = ni->ni_bssid; + } + ath_hal_setrxfilter(ah, rfilt); + DPRINTF(("%s: RX filter 0x%x bssid %s\n", + __func__, rfilt, ether_sprintf(bssid))); + + if (nstate == IEEE80211_S_RUN && ic->ic_opmode != IEEE80211_M_IBSS) + ath_hal_setassocid(ah, bssid, ni->ni_associd); + else + ath_hal_setassocid(ah, bssid, 0); + if (ic->ic_flags & IEEE80211_F_WEPON) { + for (i = 0; i < IEEE80211_WEP_NKID; i++) + if (ath_hal_keyisvalid(ah, i)) + ath_hal_keysetmac(ah, i, bssid); + } + + if (nstate == IEEE80211_S_RUN) { + DPRINTF(("%s(RUN): ic_flags=0x%08x iv=%d bssid=%s " + "capinfo=0x%04x chan=%d\n" + , __func__ + , ic->ic_flags + , ni->ni_intval + , ether_sprintf(ni->ni_bssid) + , ni->ni_capinfo + , ieee80211_chan2ieee(ic, ni->ni_chan))); + + /* + * Allocate and setup the beacon frame for AP or adhoc mode. + */ + if (ic->ic_opmode != IEEE80211_M_STA) { + error = ath_beacon_alloc(sc, ni); + if (error != 0) + goto bad; + } + + /* + * Configure the beacon and sleep timers. + */ + ath_beacon_config(sc); + + /* start periodic recalibration timer */ + mod_timer(&sc->sc_cal_ch, jiffies + (ath_calinterval * HZ)); + + netif_start_queue(dev); + } else { + sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS); + ath_hal_intrset(ah, sc->sc_imask); + del_timer(&sc->sc_cal_ch); /* no calibration */ + } + /* + * Reset the rate control state. + */ + ath_rate_ctl_reset(sc, nstate); + return 0; +bad: + del_timer(&sc->sc_scan_ch); + del_timer(&sc->sc_cal_ch); + return error; +} + +static int +ath_getchannels(struct net_device *dev, u_int cc, HAL_BOOL outdoor) +{ + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + HAL_CHANNEL *chans; + int i, ix, nchan; + + sc->sc_have11g = 0; + chans = kmalloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL), GFP_KERNEL); + if (chans == NULL) { + printk("%s: unable to allocate channel table\n", dev->name); + return -ENOMEM; + } + if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, + cc, HAL_MODE_ALL, outdoor)) { + printk("%s: unable to collect channel list from hal\n", + dev->name); + kfree(chans); + return -EINVAL; + } + + /* + * Convert HAL channels to ieee80211 ones and insert + * them in the table according to their channel number. + */ + for (i = 0; i < nchan; i++) { + HAL_CHANNEL *c = &chans[i]; + ix = ath_hal_mhz2ieee(c->channel, c->channelFlags); + if (ix > IEEE80211_CHAN_MAX) { + printk("%s: bad hal channel %u (%u/%x) ignored\n", + dev->name, ix, c->channel, c->channelFlags); + continue; + } + /* NB: flags are known to be compatible */ + if (ic->ic_channels[ix].ic_freq == 0) { + ic->ic_channels[ix].ic_freq = c->channel; + ic->ic_channels[ix].ic_flags = c->channelFlags; + } else { + /* channels overlap; e.g. 11g and 11b */ + ic->ic_channels[ix].ic_flags |= c->channelFlags; + } + if ((c->channelFlags & CHANNEL_G) == CHANNEL_G) + sc->sc_have11g = 1; + } + kfree(chans); + return 0; +} + +static int +ath_rate_setup(struct net_device *dev, u_int mode) +{ + struct ath_softc *sc = dev->priv; + struct ath_hal *ah = sc->sc_ah; + struct ieee80211com *ic = &sc->sc_ic; + const HAL_RATE_TABLE *rt; + struct ieee80211_rateset *rs; + int i, maxrates; + + switch (mode) { + case IEEE80211_MODE_11A: + sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11A); + break; + case IEEE80211_MODE_11B: + sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11B); + break; + case IEEE80211_MODE_11G: + sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11G); + break; + case IEEE80211_MODE_TURBO: + sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_TURBO); + break; + default: + DPRINTF(("%s: invalid mode %u\n", __func__, mode)); + return 0; + } + rt = sc->sc_rates[mode]; + if (rt == NULL) + return 0; + if (rt->rateCount > IEEE80211_RATE_MAXSIZE) { + DPRINTF(("%s: rate table too small (%u > %u)\n", + __func__, rt->rateCount, IEEE80211_RATE_MAXSIZE)); + maxrates = IEEE80211_RATE_MAXSIZE; + } else + maxrates = rt->rateCount; + rs = &ic->ic_sup_rates[mode]; + for (i = 0; i < maxrates; i++) + rs->rs_rates[i] = rt->info[i].dot11Rate; + rs->rs_nrates = maxrates; + return 1; +} + +static void +ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode) +{ + const HAL_RATE_TABLE *rt; + int i; + + memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); + rt = sc->sc_rates[mode]; + KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode)); + for (i = 0; i < rt->rateCount; i++) + sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; + sc->sc_currates = rt; + sc->sc_curmode = mode; +} + +/* + * Reset the rate control state for each 802.11 state transition. + */ +static void +ath_rate_ctl_reset(struct ath_softc *sc, enum ieee80211_state state) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ieee80211_node *ni; + struct ath_nodestat *st; + + st = &sc->sc_bss_stat; + st->st_tx_ok = st->st_tx_err = st->st_tx_retr = st->st_tx_upper = 0; + if (ic->ic_opmode == IEEE80211_M_STA) { + ni = &ic->ic_bss; + if (state == IEEE80211_S_RUN) { + /* start with highest negotiated rate */ + KASSERT(ni->ni_rates.rs_nrates > 0, + ("transition to RUN state w/ no rates!")); + ni->ni_txrate = ni->ni_rates.rs_nrates - 1; + } else { + /* use lowest rate */ + ni->ni_txrate = 0; + } + } else { + TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { + ni->ni_txrate = 0; /* use lowest rate */ + st = ni->ni_private; + st->st_tx_ok = st->st_tx_err = st->st_tx_retr = + st->st_tx_upper = 0; + } + } + if (state == IEEE80211_S_RUN && ic->ic_fixed_rate != -1) { + /* + * Start the background rate control thread if we + * are not configured to use a fixed xmit rate. + */ + mod_timer(&sc->sc_rate_ctl, + jiffies + ((HZ * ath_rateinterval) / 1000)); + } +} + +/* + * Examine and potentially adjust the transmit rate. + */ +static void +ath_rate_ctl(void *arg, struct ieee80211_node *ni) +{ + struct ath_softc *sc = arg; + struct ath_nodestat *st = ni->ni_private; + struct ieee80211_rateset *rs = &ni->ni_rates; + int mod = 0, orate, enough; + + /* + * Rate control + * XXX: very primitive version. + */ + sc->sc_stats.ast_rate_calls++; + + enough = (st->st_tx_ok + st->st_tx_err >= 10); + + /* no packet reached -> down */ + if (st->st_tx_err > 0 && st->st_tx_ok == 0) + mod = -1; + + /* all packets needs retry in average -> down */ + if (enough && st->st_tx_ok < st->st_tx_retr) + mod = -1; + + /* no error and less than 10% of packets needs retry -> up */ + if (enough && st->st_tx_err == 0 && st->st_tx_ok > st->st_tx_retr * 10) + mod = 1; + + orate = ni->ni_txrate; + switch (mod) { + case 0: + if (enough && st->st_tx_upper > 0) + st->st_tx_upper--; + break; + case -1: + if (ni->ni_txrate > 0) { + ni->ni_txrate--; + sc->sc_stats.ast_rate_drop++; + } + st->st_tx_upper = 0; + break; + case 1: + if (++st->st_tx_upper < 2) + break; + st->st_tx_upper = 0; + if (ni->ni_txrate + 1 < rs->rs_nrates) { + ni->ni_txrate++; + sc->sc_stats.ast_rate_raise++; + } + break; + } + + if (ni->ni_txrate != orate) { + printk("%s: %dM -> %dM (%d ok, %d err, %d retr)\n", + __func__, + (rs->rs_rates[orate] & IEEE80211_RATE_VAL) / 2, + (rs->rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL) / 2, + st->st_tx_ok, st->st_tx_err, st->st_tx_retr); + } + if (ni->ni_txrate != orate || enough) + st->st_tx_ok = st->st_tx_err = st->st_tx_retr = 0; +} + +static void +ath_ratectl(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct ath_softc *sc = dev->priv; + struct ieee80211com *ic = &sc->sc_ic; + + if (dev->flags & IFF_RUNNING) { + if (ic->ic_opmode == IEEE80211_M_STA) + ath_rate_ctl(sc, &ic->ic_bss); /* NB: no reference */ + else + ieee80211_iterate_nodes(ic, ath_rate_ctl, sc); + } + sc->sc_rate_ctl.expires = jiffies + ((HZ * ath_rateinterval) / 1000); + add_timer(&sc->sc_rate_ctl); +} + +#ifdef AR_DEBUG +static void +ath_printrxbuf(struct ath_buf *bf, int done) +{ + struct ath_desc *ds = bf->bf_desc; + + printk("R (%p %p) %08x %08x %08x %08x %08x %08x %c\n", + ds, (struct ath_desc *)bf->bf_daddr, + ds->ds_link, ds->ds_data, + ds->ds_ctl0, ds->ds_ctl1, + ds->ds_hw[0], ds->ds_hw[1], + !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'); +} + +static void +ath_printtxbuf(struct ath_buf *bf, int done) +{ + struct ath_desc *ds = bf->bf_desc; + + printk("T (%p %p) %08x %08x %08x %08x %08x %08x %08x %08x %c\n", + ds, (struct ath_desc *)bf->bf_daddr, + ds->ds_link, ds->ds_data, + ds->ds_ctl0, ds->ds_ctl1, + ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3], + !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!'); +} +#endif /* AR_DEBUG */ + +/* + * Return netdevice statistics. + */ +static struct net_device_stats * +ath_getstats(struct net_device *dev) +{ + struct ath_softc *sc = dev->priv; + struct net_device_stats *stats = &sc->sc_ic.ic_stats; + + /* update according to private statistics */ + stats->tx_errors = sc->sc_stats.ast_tx_encap + + sc->sc_stats.ast_tx_nonode + + sc->sc_stats.ast_tx_xretries + + sc->sc_stats.ast_tx_fifoerr + + sc->sc_stats.ast_tx_filtered + ; + stats->tx_dropped = sc->sc_stats.ast_tx_nobuf + + sc->sc_stats.ast_tx_nobufmgt; + stats->rx_errors = sc->sc_stats.ast_rx_tooshort + + sc->sc_stats.ast_rx_crcerr + + sc->sc_stats.ast_rx_fifoerr + + sc->sc_stats.ast_rx_badcrypt + + sc->sc_stats.ast_rx_phyerr + ; + stats->rx_length_errors = sc->sc_stats.ast_rx_phy[HAL_PHYERR_LENGTH]; + stats->rx_crc_errors = sc->sc_stats.ast_rx_crcerr; + /* XXX??? */ + stats->rx_fifo_errors = sc->sc_stats.ast_rx_phy[HAL_PHYERR_TIMING]; + /* XXX??? */ + stats->rx_missed_errors = sc->sc_stats.ast_rx_phy[HAL_PHYERR_TOR]; + + return stats; +} + +#ifdef CONFIG_SYSCTL +enum { + ATH_STATS = 1, + ATH_DEBUG = 2, + ATH_DWELLTIME = 3, + ATH_CALIBRATE = 4, + ATH_RATEINTERVAL= 5, + ATH_BMISSHACK = 6, + ATH_DUMP = 8, + ATH_CC = 9, + ATH_OUTDOOR = 10, + ATH_REGDOMAIN = 11, +}; +static char ath_info[512]; +static char ath_dump[10]; + +static int +ath_sysctl_stats(ctl_table *ctl, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + struct net_device *dev; + struct ath_softc *sc; + char *cp = ath_info; + + if (!*lenp || (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + dev = dev_get_by_name("ath0"); /* XXX */ + if (!dev) + return -EINVAL; + sc = dev->priv; +#define STAT(x) do { \ + if (sc->sc_stats.ast_##x != 0) \ + cp += sprintf(cp, #x "=%u\n", sc->sc_stats.ast_##x); \ +} while (0) +#define ISTAT(x) do { \ + cp += sprintf(cp, #x "=%d\n", sc->sc_stats.ast_##x); \ +} while (0) + *cp = '\0'; + STAT(watchdog); STAT(hardware); STAT(bmiss); + STAT(rxorn); STAT(rxeol); + + STAT(tx_mgmt); STAT(tx_qstop); STAT(tx_discard); STAT(tx_invalid); + STAT(tx_encap); STAT(tx_nonode); STAT(tx_nobuf); STAT(tx_nobufmgt); + STAT(tx_xretries);STAT(tx_fifoerr); STAT(tx_filtered); + STAT(tx_shortretry); STAT(tx_longretry); + STAT(tx_badrate); STAT(tx_noack); STAT(tx_rts); STAT(tx_cts); + STAT(tx_shortpre);ISTAT(tx_rssi); ISTAT(tx_rssidelta); + + STAT(rx_orn); STAT(rx_crcerr); STAT(rx_fifoerr); STAT(rx_badcrypt); +#define PHYSTAT(x) do { \ + if (sc->sc_stats.ast_rx_phy[HAL_PHYERR_##x] != 0) \ + cp += sprintf(cp, "PHYERR_" #x "=%u\n", \ + sc->sc_stats.ast_rx_phy[HAL_PHYERR_##x]); \ +} while (0) + PHYSTAT(UNDERRUN); PHYSTAT(TIMING); PHYSTAT(PARITY); + PHYSTAT(RATE); PHYSTAT(LENGTH); PHYSTAT(RADAR); + PHYSTAT(SERVICE); PHYSTAT(TOR); + + PHYSTAT(OFDM_TIMING); + PHYSTAT(OFDM_SIGNAL_PARITY); + PHYSTAT(OFDM_RATE_ILLEGAL); + PHYSTAT(OFDM_LENGTH_ILLEGAL); + PHYSTAT(OFDM_POWER_DROP); + PHYSTAT(OFDM_SERVICE); + PHYSTAT(OFDM_RESTART); + PHYSTAT(CCK_TIMING); + PHYSTAT(CCK_HEADER_CRC); + PHYSTAT(CCK_RATE_ILLEGAL); + PHYSTAT(CCK_SERVICE); + PHYSTAT(CCK_RESTART); + + STAT(rx_nobuf); ISTAT(rx_rssi); ISTAT(rx_rssidelta); + + STAT(be_nobuf); + + STAT(per_cal); STAT(per_rfgain); + STAT(rate_calls); STAT(rate_raise); STAT(rate_drop); + + dev_put(dev); + + return proc_dostring(ctl, write, filp, buffer, lenp); +#undef PHYSTAT +#undef STAT +} + +static int +ath_sysctl_handler(ctl_table *ctl, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int *valp = ctl->data; + int val = *valp; /* save old value */ + int ret = proc_dointvec(ctl, write, filp, buffer, lenp); + if (write && *valp != val) { + /* XXX this is wrong, need to intercept writes */ + switch (ctl->ctl_name) { + case ATH_DWELLTIME: + if (*valp < 100) /* 100ms min */ + *valp = 100; + break; + case ATH_CALIBRATE: + if (*valp < 1) /* 1/second min */ + *valp = 1; + break; + case ATH_RATEINTERVAL: + if (*valp < 500) /* 500ms min */ + *valp = 500; + break; + } + } + return ret; +} + +static int +ath_sysctl_dump(ctl_table *ctl, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + int ret = proc_dostring(ctl, write, filp, buffer, lenp); + /* NB: should always be a write */ + if (ret == 0) { + struct net_device *dev; + struct ath_softc *sc; + + dev = dev_get_by_name("ath0"); /* XXX */ + if (!dev) { + printk("%s: no ath0 device\n", __func__); + return -EINVAL; + } + sc = dev->priv; + if (*lenp >= 3 && strncmp(buffer, "hal", 3) == 0) + ath_hal_dumpstate(sc->sc_ah); + else if (*lenp >= 6 && strncmp(buffer, "eeprom", 6) == 0) + ath_hal_dumpeeprom(sc->sc_ah); + else if (*lenp >= 6 && strncmp(buffer, "rfgain", 6) == 0) + ath_hal_dumprfgain(sc->sc_ah); + else if (*lenp >= 3 && strncmp(buffer, "ani", 3) == 0) + ath_hal_dumpani(sc->sc_ah); + else { + printk("%s: don't grok \"%.*s\"\n", + __func__, *lenp, (char*) buffer); + ret = -EINVAL; + } + dev_put(dev); + } + return ret; +} + +enum { + DEV_ATH = 9, /* XXX */ +}; +static ctl_table ath_sysctls[] = { + { ATH_STATS, "stats", ath_info, + sizeof(ath_info), 0444, NULL, ath_sysctl_stats }, + { ATH_DEBUG, "debug", &ath_debug, + sizeof(ath_dwelltime),0644, NULL, ath_sysctl_handler }, + { ATH_DWELLTIME, "dwelltime", &ath_dwelltime, + sizeof(ath_debug), 0644, NULL, ath_sysctl_handler }, + { ATH_CALIBRATE, "calibrate", &ath_calinterval, + sizeof(ath_calinterval),0644, NULL, ath_sysctl_handler }, + { ATH_RATEINTERVAL, "rateinterval", &ath_rateinterval, + sizeof(ath_rateinterval),0644,NULL, ath_sysctl_handler }, + { ATH_BMISSHACK, "bmisshack", &ath_bmisshack, + sizeof(ath_bmisshack),0644, NULL, ath_sysctl_handler }, + { ATH_DUMP, "dump", ath_dump, + sizeof(ath_dump), 0200, NULL, ath_sysctl_dump }, + { ATH_CC, "countrycode", &ath_countrycode, + sizeof(ath_countrycode),0444, NULL, ath_sysctl_handler }, + { ATH_OUTDOOR, "outdoor", &ath_outdoor, + sizeof(ath_outdoor), 0444, NULL, ath_sysctl_handler }, + { ATH_REGDOMAIN, "regdomain", &ath_regdomain, + sizeof(ath_regdomain),0444, NULL, ath_sysctl_handler }, + { 0 } +}; +static ctl_table ath_ath_table[] = { + { DEV_ATH, "ath", NULL, 0, 055, ath_sysctls }, + { 0 } +}; +static ctl_table ath_root_table[] = { +#ifdef CONFIG_PROC_FS + { CTL_NET, "net", NULL, 0, 0555, ath_ath_table }, +#endif /* CONFIG_PROC_FS */ + { 0 } +}; +static struct ctl_table_header *ath_sysctl_header; + +void +ath_sysctl_register(void) +{ + static int initialized = 0; + + if (!initialized) { + ath_sysctl_header = register_sysctl_table(ath_root_table, 1); + initialized = 1; + } +} + +void +ath_sysctl_unregister(void) +{ + if (ath_sysctl_header) + unregister_sysctl_table(ath_sysctl_header); +} +#endif /* CONFIG_SYSCTL */ diff -Nru a/drivers/net/wireless/atheros/driver/if_ath_pci.c b/drivers/net/wireless/atheros/driver/if_ath_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/driver/if_ath_pci.c Wed Jul 30 18:20:27 2003 @@ -0,0 +1,287 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_ath_pci.c,v 1.18 2003/06/20 22:42:49 sam Exp $ + */ +#include "opt_ah.h" + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "if_athvar.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) +/* + * PCI initialization uses Linux 2.4.x version and + * older kernels do not support this + */ +#error Atheros PCI version requires at least Linux kernel version 2.4.0 +#endif /* kernel < 2.4.0 */ + +struct ath_pci_softc { + struct ath_softc aps_sc; +#ifdef CONFIG_PM + u32 aps_pmstate[16]; +#endif +}; + +/* + * User a static table of PCI id's for now. While this is the + * "new way" to do things, we may want to switch back to having + * the HAL check them by defining a probe method. + */ +static struct pci_device_id ath_pci_id_table[] __devinitdata = { + { 0x168c, 0x0007, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x0012, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x0013, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +static int +ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + unsigned long phymem; + unsigned long mem; + struct ath_pci_softc *sc; + struct net_device *dev; + const char *athname; + u_int8_t csz; + + if (pci_enable_device(pdev)) + return (-EIO); + + /* XXX 32-bit addressing only */ + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_ERR "ath_pci: 32-bit DMA not available\n"); + goto bad; + } + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); + if (csz == 0) { + /* + * Linux 2.4.18 (at least) writes the cache line size + * register as a 16-bit wide register which is wrong. + * We must have this setup properly for rx buffer + * DMA to work so force a reasonable value here if it + * comes up zero. + */ + csz = L1_CACHE_BYTES / sizeof(u_int32_t); + printk("ath_pci: cache line size not set; forcing %u\n", csz); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); + } + /* + * The default setting of latency timer yields poor results, + * set it to the value used by other systems. It may be worth + * tweaking this setting more. + */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); + + pci_set_master(pdev); + + phymem = pci_resource_start(pdev, 0); + if (!request_mem_region(phymem, pci_resource_len(pdev, 0), "ath")) { + printk(KERN_ERR "ath_pci: cannot reserve PCI memory region\n"); + goto bad; + } + + mem = (unsigned long) ioremap(phymem, pci_resource_len(pdev, 0)); + if (!mem) { + printk(KERN_ERR "ath_pci: cannot remap PCI memory region\n") ; + goto bad1; + } + + sc = kmalloc(sizeof(struct ath_pci_softc), GFP_KERNEL); + if (sc == NULL) { + printk(KERN_ERR "ath_pci: no memory for device state\n"); + goto bad2; + } + memset(sc, 0, sizeof(struct ath_pci_softc)); + + dev = &sc->aps_sc.sc_ic.ic_dev; /* XXX blech, violate layering */ + memcpy(dev->name, "ath%d", sizeof("ath%d")); + + dev->irq = pdev->irq; + dev->mem_start = mem; + dev->mem_end = mem + pci_resource_len(pdev, 0); + dev->priv = sc; + SET_MODULE_OWNER(dev); + + sc->aps_sc.sc_pdev = pdev; + + pci_set_drvdata(pdev, dev); + + if (request_irq(dev->irq, ath_intr, SA_SHIRQ, dev->name, dev)) { + printk(KERN_WARNING "%s: request_irq failed\n", dev->name); + goto bad3; + } + + if (ath_attach(id->device, dev) != 0) + goto bad4; + + athname = ath_hal_probe(id->vendor, id->device); + printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n", + dev->name, athname ? athname : "Atheros ???", phymem, dev->irq); + + return 0; +bad4: + free_irq(dev->irq, dev); +bad3: + kfree(sc); +bad2: + iounmap((void *) mem); +bad1: + release_mem_region(phymem, pci_resource_len(pdev, 0)); +bad: + pci_disable_device(pdev); + return (-ENODEV); +} + +static void +ath_pci_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct ath_pci_softc *sc = dev->priv; + + ath_detach(dev); + if (dev->irq) + free_irq(dev->irq, dev); + iounmap((void *) dev->mem_start); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + pci_disable_device(pdev); + kfree(sc); +} + +#ifdef CONFIG_PM +static int +ath_pci_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct ath_pci_softc *sc = dev->priv; + + ath_suspend(dev); + pci_save_state(pdev, sc->aps_pmstate); + pci_disable_device(pdev); + pci_set_power_state(pdev, 3); + + return (0); +} + +static int +ath_pci_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct ath_pci_softc *sc = dev->priv; + + pci_enable_device(pdev); + pci_restore_state(pdev, sc->aps_pmstate); + ath_resume(dev); + + return (0); +} +#endif /* CONFIG_PM */ + +MODULE_DEVICE_TABLE(pci, ath_pci_id_table); + +static struct pci_driver ath_pci_drv_id = { + .name = "ath_pci", + .id_table = ath_pci_id_table, + .probe = ath_pci_probe, + .remove = ath_pci_remove, +#ifdef CONFIG_PM + .suspend = ath_pci_suspend, + .resume = ath_pci_resume, +#endif /* CONFIG_PM */ + /* Linux 2.4.6 has save_state and enable_wake that are not used here */ +}; + +/* + * Module glue. + */ +#include "release.h" +#include "version.h" +static char *version = ATH_PCI_VERSION " " RELEASE_TYPE " (Sam Leffler )"; +static char *dev_info = "ath_pci"; + +MODULE_AUTHOR("Errno Consulting, Sam Leffler"); +MODULE_DESCRIPTION("Support for Atheros 802.11 wireless LAN cards."); +MODULE_SUPPORTED_DEVICE("Atheros WLAN cards"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual BSD/GPL"); +#endif + +static int __init +init_ath_pci(void) +{ + printk(KERN_INFO "%s: %s\n", dev_info, version); + + if (pci_register_driver(&ath_pci_drv_id) <= 0) { + printk("ath_pci: No devices found, driver not installed.\n"); + pci_unregister_driver(&ath_pci_drv_id); + return (-ENODEV); + } +#ifdef CONFIG_SYSCTL + ath_sysctl_register(); +#endif + return (0); +} +module_init(init_ath_pci); + +static void __exit +exit_ath_pci(void) +{ +#ifdef CONFIG_SYSCTL + ath_sysctl_unregister(); +#endif + pci_unregister_driver(&ath_pci_drv_id); + + printk(KERN_INFO "%s: driver unloaded\n", dev_info); +} +module_exit(exit_ath_pci); diff -Nru a/drivers/net/wireless/atheros/driver/if_athvar.h b/drivers/net/wireless/atheros/driver/if_athvar.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/driver/if_athvar.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,316 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_athvar.h,v 1.34 2003/07/02 23:26:57 sam Exp $ + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_ATH_ATHVAR_H +#define _DEV_ATH_ATHVAR_H + +#include "if_ieee80211.h" +#include "ah.h" + +#define ATH_TIMEOUT 1000 + +#define ATH_RXBUF 40 /* number of RX buffers */ +#define ATH_TXBUF 200 /* number of TX buffers */ +#define ATH_TXDESC 1 /* number of descriptors per buffer */ + +/* statistics for node */ +struct ath_nodestat { + u_int st_tx_ok; /* tx ok pkt */ + u_int st_tx_err; /* tx !ok pkt */ + u_int st_tx_retr; /* tx retry count */ + int st_tx_upper; /* tx upper rate req cnt */ + u_int st_tx_antenna; /* antenna for last good frame */ +}; + +struct ath_stats { + u_int32_t ast_watchdog; /* device reset by watchdog */ + u_int32_t ast_hardware; /* fatal hardware error interrupt */ + u_int32_t ast_bmiss; /* beacon miss interrupt */ + u_int32_t ast_rxorn; /* rxorn interrupts */ + u_int32_t ast_rxeol; /* rxeol interrupts */ + u_int32_t ast_txurn; /* tx underrun interrupts */ + u_int32_t ast_tx_mgmt; /* management frames transmitted */ + u_int32_t ast_tx_discard; /* frames discarded prior to assoc */ + u_int32_t ast_tx_invalid; /* frames discarded 'cuz device gone */ + u_int32_t ast_tx_qstop; /* tx queue stopped 'cuz full */ + u_int32_t ast_tx_encap; /* tx encapsulation failed */ + u_int32_t ast_tx_nonode; /* tx failed 'cuz no node */ + u_int32_t ast_tx_nobuf; /* tx failed 'cuz no tx buffer (data) */ + u_int32_t ast_tx_nobufmgt;/* tx failed 'cuz no tx buffer (mgmt)*/ + u_int32_t ast_tx_xretries;/* tx failed 'cuz too many retries */ + u_int32_t ast_tx_fifoerr; /* tx failed 'cuz FIFO underrun */ + u_int32_t ast_tx_filtered;/* tx failed 'cuz xmit filtered */ + u_int32_t ast_tx_shortretry;/* tx on-chip retries (short) */ + u_int32_t ast_tx_longretry;/* tx on-chip retries (long) */ + u_int32_t ast_tx_badrate; /* tx failed 'cuz bogus xmit rate */ + u_int32_t ast_tx_noack; /* tx frames with no ack marked */ + u_int32_t ast_tx_rts; /* tx frames with rts enabled */ + u_int32_t ast_tx_cts; /* tx frames with cts enabled */ + u_int32_t ast_tx_shortpre;/* tx frames with short preamble */ + int16_t ast_tx_rssi; /* tx rssi of last ack */ + int16_t ast_tx_rssidelta;/* tx rssi delta */ + u_int32_t ast_rx_orn; /* rx failed 'cuz of desc overrun */ + u_int32_t ast_rx_tooshort;/* rx failed 'cuz frame too short */ + u_int32_t ast_rx_crcerr; /* rx failed 'cuz of bad CRC */ + u_int32_t ast_rx_fifoerr; /* rx failed 'cuz of FIFO overrun */ + u_int32_t ast_rx_badcrypt;/* rx failed 'cuz decryption */ + u_int32_t ast_rx_phyerr; /* rx PHY error summary count */ + u_int32_t ast_rx_phy[32]; /* rx PHY error per-code counts */ + u_int32_t ast_rx_nobuf; /* rx setup failed 'cuz no skbuff */ + int16_t ast_rx_rssi; /* rx rssi of last recv'd frame */ + int16_t ast_rx_rssidelta;/* rx rssi delta */ + u_int32_t ast_be_nobuf; /* no skbuff available for beacon */ + u_int32_t ast_per_cal; /* periodic calibration calls */ + u_int32_t ast_per_calfail;/* periodic calibration failed */ + u_int32_t ast_per_rfgain; /* periodic calibration rfgain reset */ + u_int32_t ast_rate_calls; /* rate control checks */ + u_int32_t ast_rate_raise; /* rate control raised xmit rate */ + u_int32_t ast_rate_drop; /* rate control dropped xmit rate */ +}; + +struct ath_buf { + TAILQ_ENTRY(ath_buf) bf_list; + struct ath_desc *bf_desc; /* virtual addr of desc */ + dma_addr_t bf_daddr; /* physical addr of desc */ + struct sk_buff *bf_skb; /* skbuff for buf */ + dma_addr_t bf_skbaddr; /* physical addr of skb data */ + struct ieee80211_node *bf_node; /* pointer to the node */ +}; + +struct ath_hal; +struct ath_desc; +struct proc_dir_entry; + +struct ath_softc { + struct ieee80211com sc_ic; /* IEEE 802.11 common */ + struct ath_hal *sc_ah; /* Atheros HAL */ + /* rate tables */ + unsigned int sc_have11g : 1,/* have 11g support */ + sc_probing : 1;/* probing AP on beacon miss */ + const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX]; + const HAL_RATE_TABLE *sc_currates; /* current rate table */ + enum ieee80211_phymode sc_curmode; /* current phy mode */ + u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */ + HAL_INT sc_imask; /* interrupt mask copy */ + + struct pci_dev *sc_pdev; /* associated pci device */ + volatile int sc_invalid; /* being detached */ + struct ath_desc *sc_desc; /* TX/RX descriptors */ + size_t sc_desc_len; /* size of TX/RX descriptors */ + u_int16_t sc_cachelsz; /* cache line size */ + dma_addr_t sc_desc_daddr; /* DMA (physical) address */ + + struct work_struct sc_fatalwk; /* fatal error intr tasklet */ + + int sc_rxbufsize; /* rx size based on mtu */ + TAILQ_HEAD(, ath_buf) sc_rxbuf; /* receive buffer */ + u_int32_t *sc_rxlink; /* link ptr in last RX desc */ + struct work_struct sc_rxwk; /* rx intr tasklet */ + struct work_struct sc_rxornwk; /* rxorn intr tasklet */ + + u_int sc_txhalq; /* HAL q for outgoing frames */ + u_int32_t *sc_txlink; /* link ptr in last TX desc */ + TAILQ_HEAD(, ath_buf) sc_txbuf; /* tx buffer queue */ + spinlock_t sc_txbuflock; /* txbuf lock */ + TAILQ_HEAD(, ath_buf) sc_txq; /* transmit queue */ + spinlock_t sc_txqlock; /* lock on txq and txlink */ + struct work_struct sc_txwk; /* tx intr tasklet */ + + u_int sc_bhalq; /* HAL q for outgoing beacons */ + struct ath_buf *sc_bcbuf; /* beacon buffer */ + struct ath_buf *sc_bufptr; /* allocated buffer ptr */ + struct work_struct sc_swbawk; /* swba intr tasklet */ + struct work_struct sc_bmisswk; /* bmiss intr tasklet */ + + struct timer_list sc_rate_ctl; /* tx rate control timer */ + struct timer_list sc_cal_ch; /* calibration timer */ + struct timer_list sc_scan_ch; /* AP scan timer */ + struct ath_nodestat sc_bss_stat; /* statistics for infra mode */ + struct ath_stats sc_stats; /* interface statistics */ +}; + +#ifdef AR_DEBUG +extern int ath_debug; +#define DPRINTF(X) if (ath_debug) printk X +#define DPRINTF2(X) if (ath_debug > 1) printk X +#else +#define DPRINTF(X) +#define DPRINTF2(X) +#endif + +int ath_attach(u_int16_t, struct net_device *); +int ath_detach(struct net_device *); +void ath_resume(struct net_device *); +void ath_suspend(struct net_device *); +void ath_shutdown(struct net_device *); +irqreturn_t ath_intr(int irq, void *dev_id, struct pt_regs *regs); +#ifdef CONFIG_SYSCTL +void ath_sysctl_register(void); +void ath_sysctl_unregister(void); +#endif /* CONFIG_SYSCTL */ + +/* + * HAL definitions to comply with local coding convention. + */ +#define ath_hal_reset(_ah, _opmode, _chan, _outdoor, _pstatus) \ + ((*(_ah)->ah_reset)((_ah), (_opmode), (_chan), (_outdoor), (_pstatus))) +#define ath_hal_getregdomain(_ah) \ + ((*(_ah)->ah_getRegDomain)((_ah))) +#define ath_hal_getratetable(_ah, _mode) \ + ((*(_ah)->ah_getRateTable)((_ah), (_mode))) +#define ath_hal_getmac(_ah, _mac) \ + ((*(_ah)->ah_getMacAddress)((_ah), (_mac))) +#define ath_hal_intrset(_ah, _mask) \ + ((*(_ah)->ah_setInterrupts)((_ah), (_mask))) +#define ath_hal_intrget(_ah) \ + ((*(_ah)->ah_getInterrupts)((_ah))) +#define ath_hal_intrpend(_ah) \ + ((*(_ah)->ah_isInterruptPending)((_ah))) +#define ath_hal_getisr(_ah, _pmask) \ + ((*(_ah)->ah_getPendingInterrupts)((_ah), (_pmask))) +#define ath_hal_updatetxtriglevel(_ah, _inc) \ + ((*(_ah)->ah_updateTxTrigLevel)((_ah), (_inc))) +#define ath_hal_setpower(_ah, _mode, _sleepduration) \ + ((*(_ah)->ah_setPowerMode)((_ah), (_mode), AH_TRUE, (_sleepduration))) +#define ath_hal_keyreset(_ah, _ix) \ + ((*(_ah)->ah_resetKeyCacheEntry)((_ah), (_ix))) +#define ath_hal_keyset(_ah, _ix, _pk) \ + ((*(_ah)->ah_setKeyCacheEntry)((_ah), (_ix), (_pk), NULL, AH_FALSE)) +#define ath_hal_keyisvalid(_ah, _ix) \ + (((*(_ah)->ah_isKeyCacheEntryValid)((_ah), (_ix)))) +#define ath_hal_keysetmac(_ah, _ix, _mac) \ + ((*(_ah)->ah_setKeyCacheEntryMac)((_ah), (_ix), (_mac))) +#define ath_hal_getrxfilter(_ah) \ + ((*(_ah)->ah_getRxFilter)((_ah))) +#define ath_hal_setrxfilter(_ah, _filter) \ + ((*(_ah)->ah_setRxFilter)((_ah), (_filter))) +#define ath_hal_setmcastfilter(_ah, _mfilt0, _mfilt1) \ + ((*(_ah)->ah_setMulticastFilter)((_ah), (_mfilt0), (_mfilt1))) +#define ath_hal_waitforbeacon(_ah, _bf) \ + ((*(_ah)->ah_waitForBeaconDone)((_ah), (_bf)->bf_daddr)) +#define ath_hal_putrxbuf(_ah, _bufaddr) \ + ((*(_ah)->ah_setRxDP)((_ah), (_bufaddr))) +#define ath_hal_gettsf32(_ah) \ + ((*(_ah)->ah_getTsf32)((_ah))) +#define ath_hal_gettsf64(_ah) \ + ((*(_ah)->ah_getTsf64)((_ah))) +#define ath_hal_resettsf(_ah) \ + ((*(_ah)->ah_resetTsf)((_ah))) +#define ath_hal_rxena(_ah) \ + ((*(_ah)->ah_enableReceive)((_ah))) +#define ath_hal_puttxbuf(_ah, _q, _bufaddr) \ + ((*(_ah)->ah_setTxDP)((_ah), (_q), (_bufaddr))) +#define ath_hal_gettxbuf(_ah, _q) \ + ((*(_ah)->ah_getTxDP)((_ah), (_q))) +#define ath_hal_getrxbuf(_ah) \ + ((*(_ah)->ah_getRxDP)((_ah))) +#define ath_hal_txstart(_ah, _q) \ + ((*(_ah)->ah_startTxDma)((_ah), (_q))) +#define ath_hal_setchannel(_ah, _chan) \ + ((*(_ah)->ah_setChannel)((_ah), (_chan))) +#define ath_hal_calibrate(_ah, _chan) \ + ((*(_ah)->ah_perCalibration)((_ah), (_chan))) +#define ath_hal_setledstate(_ah, _state) \ + ((*(_ah)->ah_setLedState)((_ah), (_state))) +#define ath_hal_beaconinit(_ah, _opmode, _nextb, _bperiod) \ + ((*(_ah)->ah_beaconInit)((_ah), (_opmode), (_nextb), (_bperiod))) +#define ath_hal_beaconreset(_ah) \ + ((*(_ah)->ah_resetStationBeaconTimers)((_ah))) +#define ath_hal_beacontimers(_ah, _bs, _tsf, _dc, _cc) \ + ((*(_ah)->ah_setStationBeaconTimers)((_ah), (_bs), (_tsf), \ + (_dc), (_cc))) +#define ath_hal_setassocid(_ah, _bss, _associd) \ + ((*(_ah)->ah_writeAssocid)((_ah), (_bss), (_associd), 0)) +#define ath_hal_setopmode(_ah, _opmode) \ + ((*(_ah)->ah_setPCUConfig)((_ah), (_opmode))) +#define ath_hal_stoptxdma(_ah, _qnum) \ + ((*(_ah)->ah_stopTxDma)((_ah), (_qnum))) +#define ath_hal_stoppcurecv(_ah) \ + ((*(_ah)->ah_stopPcuReceive)((_ah))) +#define ath_hal_startpcurecv(_ah) \ + ((*(_ah)->ah_startPcuReceive)((_ah))) +#define ath_hal_stopdmarecv(_ah) \ + ((*(_ah)->ah_stopDmaReceive)((_ah))) +#define ath_hal_dumpstate(_ah) \ + ((*(_ah)->ah_dumpState)((_ah))) +#define ath_hal_dumpeeprom(_ah) \ + ((*(_ah)->ah_dumpEeprom)((_ah))) +#define ath_hal_dumprfgain(_ah) \ + ((*(_ah)->ah_dumpRfGain)((_ah))) +#define ath_hal_dumpani(_ah) \ + ((*(_ah)->ah_dumpAni)((_ah))) +#define ath_hal_setuptxqueue(_ah, _type, _irq) \ + ((*(_ah)->ah_setupTxQueue)((_ah), (_type), (_irq))) +#define ath_hal_resettxqueue(_ah, _q) \ + ((*(_ah)->ah_resetTxQueue)((_ah), (_q))) +#define ath_hal_releasetxqueue(_ah, _q) \ + ((*(_ah)->ah_releaseTxQueue)((_ah), (_q))) +#define ath_hal_hasveol(_ah) \ + ((*(_ah)->ah_hasVEOL)((_ah))) +#define ath_hal_getrfgain(_ah) \ + ((*(_ah)->ah_getRfGain)((_ah))) +#define ath_hal_rxmonitor(_ah) \ + ((*(_ah)->ah_rxMonitor)((_ah))) + +#define ath_hal_setupbeacondesc(_ah, _ds, _opmode, _flen, _hlen, \ + _rate, _antmode) \ + ((*(_ah)->ah_setupBeaconDesc)((_ah), (_ds), (_opmode), \ + (_flen), (_hlen), (_rate), (_antmode))) +#define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \ + ((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq))) +#define ath_hal_rxprocdesc(_ah, _ds) \ + ((*(_ah)->ah_procRxDesc)((_ah), (_ds))) +#define ath_hal_setuptxdesc(_ah, _ds, _plen, _hlen, _atype, _txpow, \ + _txr0, _txtr0, _keyix, _ant, _flags, \ + _rtsrate, _rtsdura) \ + ((*(_ah)->ah_setupTxDesc)((_ah), (_ds), (_plen), (_hlen), (_atype), \ + (_txpow), (_txr0), (_txtr0), (_keyix), (_ant), \ + (_flags), (_rtsrate), (_rtsdura))) +#define ath_hal_setupxtxdesc(_ah, _ds, _short, \ + _txr1, _txtr1, _txr2, _txtr2, _txr3, _txtr3) \ + ((*(_ah)->ah_setupXTxDesc)((_ah), (_ds), (_short), \ + (_txr1), (_txtr1), (_txr2), (_txtr2), (_txr3), (_txtr3))) +#define ath_hal_filltxdesc(_ah, _ds, _l, _first, _last) \ + ((*(_ah)->ah_fillTxDesc)((_ah), (_ds), (_l), (_first), (_last))) +#define ath_hal_txprocdesc(_ah, _ds) \ + ((*(_ah)->ah_procTxDesc)((_ah), (_ds))) + +#endif /* _DEV_ATH_ATHVAR_H */ diff -Nru a/drivers/net/wireless/atheros/driver/version.h b/drivers/net/wireless/atheros/driver/version.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/driver/version.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: version.h,v 1.11 2003/07/02 23:27:38 sam Exp $ + */ +#define ATH_PCI_VERSION "0.8.2.1" diff -Nru a/drivers/net/wireless/atheros/release.h b/drivers/net/wireless/atheros/release.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/release.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: release.h,v 1.1 2003/06/20 19:01:59 sam Exp $ + */ +#define RELEASE_TYPE "BETA" diff -Nru a/drivers/net/wireless/atheros/wlan/Makefile b/drivers/net/wireless/atheros/wlan/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/Makefile Wed Jul 30 18:20:27 2003 @@ -0,0 +1,5 @@ +EXTRA_CFLAGS += -I$(obj)/.. + +obj-$(CONFIG_ATHEROS) += wlan.o + +wlan-objs := if_ieee80211subr.o if_ieee80211wireless.o if_media.o rc4.o diff -Nru a/drivers/net/wireless/atheros/wlan/if_ethersubr.h b/drivers/net/wireless/atheros/wlan/if_ethersubr.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_ethersubr.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_ethersubr.h,v 1.3 2003/05/16 20:23:27 sam Exp $ + */ + +#ifndef _NET_IF_ETHERSUBR_H_ +#define _NET_IF_ETHERSUBR_H_ + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ + +/* + * Structure of a 10Mb/s Ethernet header. + */ +struct ether_header { + u_char ether_dhost[ETHER_ADDR_LEN]; + u_char ether_shost[ETHER_ADDR_LEN]; + u_short ether_type; +}; + +/* + * Structure of a 48-bit Ethernet address. + */ +struct ether_addr { + u_char octet[ETHER_ADDR_LEN]; +}; + +#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +#endif /* _NET_IF_ETHERSUBR_H_ */ diff -Nru a/drivers/net/wireless/atheros/wlan/if_ieee80211.h b/drivers/net/wireless/atheros/wlan/if_ieee80211.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_ieee80211.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,728 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_ieee80211.h,v 1.28 2003/05/19 04:44:48 sam Exp $ + * $NetBSD: if_ieee80211.h,v 1.23 2002/10/15 08:51:50 onoe Exp $ + * $FreeBSD: src/sys/net/if_ieee80211.h,v 1.8 2003/01/15 20:01:50 sam Exp $ + */ + +/* + * IEEE 802.11 generic handler definitions. + * + * This code is derived from NetBSD code; their copyright notice follows. + */ + +/*- + * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _NET_IF_IEEE80211_H_ +#define _NET_IF_IEEE80211_H_ + +#include +#include +#include "if_media.h" +#ifdef CONFIG_NET_WIRELESS +#include +#endif +#include "if_ieee80211ioctl.h" + +#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ + +/* IEEE 802.11 PLCP header */ +struct ieee80211_plcp_hdr { + u_int16_t i_sfd; + u_int8_t i_signal; + u_int8_t i_service; + u_int16_t i_length; + u_int16_t i_crc; +} __attribute__((__packed__)); + +/* + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame { + u_int8_t i_fc[2]; + u_int8_t i_dur[2]; + u_int8_t i_addr1[IEEE80211_ADDR_LEN]; + u_int8_t i_addr2[IEEE80211_ADDR_LEN]; + u_int8_t i_addr3[IEEE80211_ADDR_LEN]; + u_int8_t i_seq[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __attribute__((__packed__)); + +struct ieee80211_frame_addr4 { + u_int8_t i_fc[2]; + u_int8_t i_dur[2]; + u_int8_t i_addr1[IEEE80211_ADDR_LEN]; + u_int8_t i_addr2[IEEE80211_ADDR_LEN]; + u_int8_t i_addr3[IEEE80211_ADDR_LEN]; + u_int8_t i_seq[2]; + u_int8_t i_addr4[IEEE80211_ADDR_LEN]; +} __attribute__((__packed__)); + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 +#define IEEE80211_FC0_SUBTYPE_SHIFT 4 +/* for TYPE_MGT */ +#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 +#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 +#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 +#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 +#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 +#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 +#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 +#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 +#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 +#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 +#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 +/* for TYPE_CTL */ +#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 +#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 +#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 +#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 +#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 +/* for TYPE_DATA (bit combination) */ +#define IEEE80211_FC0_SUBTYPE_DATA 0x00 +#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 +#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 +#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 +#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 +#define IEEE80211_FC0_SUBTYPE_CFACK 0x50 +#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60 +#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70 + +#define IEEE80211_FC1_DIR_MASK 0x03 +#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ +#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ +#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ +#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ + +#define IEEE80211_FC1_MORE_FRAG 0x04 +#define IEEE80211_FC1_RETRY 0x08 +#define IEEE80211_FC1_PWR_MGT 0x10 +#define IEEE80211_FC1_MORE_DATA 0x20 +#define IEEE80211_FC1_WEP 0x40 +#define IEEE80211_FC1_ORDER 0x80 + +#define IEEE80211_SEQ_FRAG_MASK 0x000f +#define IEEE80211_SEQ_FRAG_SHIFT 0 +#define IEEE80211_SEQ_SEQ_MASK 0xfff0 +#define IEEE80211_SEQ_SEQ_SHIFT 4 + +#define IEEE80211_NWID_LEN 32 + +/* + * BEACON management packets + * + * octet timestamp[8] + * octet beacon interval[2] + * octet capability information[2] + * information element + * octet elemid + * octet length + * octet information[length] + */ + +typedef uint8_t *ieee80211_mgt_beacon_t; + +#define IEEE80211_BEACON_INTERVAL(beacon) \ + ((beacon)[8] | ((beacon)[9] << 8)) +#define IEEE80211_BEACON_CAPABILITY(beacon) \ + ((beacon)[10] | ((beacon)[11] << 8)) + +#define IEEE80211_CAPINFO_ESS 0x0001 +#define IEEE80211_CAPINFO_IBSS 0x0002 +#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 +#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 +#define IEEE80211_CAPINFO_PRIVACY 0x0010 +#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 +#define IEEE80211_CAPINFO_PBCC 0x0040 +#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 +/* bits 8-9 are reserved */ +#define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 +/* bits 11-12 are reserved */ +#define IEEE80211_CAPINFO_DSSSOFDM 0x2000 +/* bits 14-15 are reserved */ + +/* + * Management information elements + */ + +struct ieee80211_information { + char ssid[IEEE80211_NWID_LEN+1]; + struct rates { + u_int8_t *p; + } rates; + struct fh { + u_int16_t dwell; + u_int8_t set; + u_int8_t pattern; + u_int8_t index; + } fh; + struct ds { + u_int8_t channel; + } ds; + struct cf { + u_int8_t count; + u_int8_t period; + u_int8_t maxdur[2]; + u_int8_t dur[2]; + } cf; + struct tim { + u_int8_t count; + u_int8_t period; + u_int8_t bitctl; + /* u_int8_t pvt[251]; The driver needs to use this. */ + } tim; + struct ibss { + u_int16_t atim; + } ibss; + struct challenge { + u_int8_t *p; + u_int8_t len; + } challenge; + struct erp { + u_int8_t flags; + } erp; +}; + +#define IEEE80211_ELEMID_SSID 0 +#define IEEE80211_ELEMID_RATES 1 +#define IEEE80211_ELEMID_FHPARMS 2 +#define IEEE80211_ELEMID_DSPARMS 3 +#define IEEE80211_ELEMID_CFPARMS 4 +#define IEEE80211_ELEMID_TIM 5 +#define IEEE80211_ELEMID_IBSSPARMS 6 +#define IEEE80211_ELEMID_COUNTRY 7 +#define IEEE80211_ELEMID_CHALLENGE 16 +#define IEEE80211_ELEMID_ERP 42 +#define IEEE80211_ELEMID_XRATES 50 + +#define IEEE80211_RATE_BASIC 0x80 +#define IEEE80211_RATE_VAL 0x7f + +/* EPR information element flags */ +#define IEEE80211_ERP_NON_ERP_PRESENT 0x01 +#define IEEE80211_ERP_USE_PROTECTION 0x02 +#define IEEE80211_ERP_BARKER_MODE 0x04 + +/* + * AUTH management packets + * + * octet algo[2] + * octet seq[2] + * octet status[2] + * octet chal.id + * octet chal.length + * octet chal.text[253] + */ + +typedef u_int8_t *ieee80211_mgt_auth_t; + +#define IEEE80211_AUTH_ALGORITHM(auth) \ + ((auth)[0] | ((auth)[1] << 8)) +#define IEEE80211_AUTH_TRANSACTION(auth) \ + ((auth)[2] | ((auth)[3] << 8)) +#define IEEE80211_AUTH_STATUS(auth) \ + ((auth)[4] | ((auth)[5] << 8)) + +#define IEEE80211_AUTH_ALG_OPEN 0x0000 +#define IEEE80211_AUTH_ALG_SHARED 0x0001 + +#define IEEE80211_AUTH_OPEN_REQUEST 1 +#define IEEE80211_AUTH_OPEN_RESPONSE 2 + +#define IEEE80211_AUTH_SHARED_REQUEST 1 +#define IEEE80211_AUTH_SHARED_CHALLENGE 2 +#define IEEE80211_AUTH_SHARED_RESPONSE 3 +#define IEEE80211_AUTH_SHARED_PASS 4 + +/* + * Reason codes + * + * Unlisted codes are reserved + */ + +#define IEEE80211_REASON_UNSPECIFIED 1 +#define IEEE80211_REASON_AUTH_EXPIRE 2 +#define IEEE80211_REASON_AUTH_LEAVE 3 +#define IEEE80211_REASON_ASSOC_EXPIRE 4 +#define IEEE80211_REASON_ASSOC_TOOMANY 5 +#define IEEE80211_REASON_NOT_AUTHED 6 +#define IEEE80211_REASON_NOT_ASSOCED 7 +#define IEEE80211_REASON_ASSOC_LEAVE 8 +#define IEEE80211_REASON_ASSOC_NOT_AUTHED 9 + +#define IEEE80211_STATUS_SUCCESS 0 +#define IEEE80211_STATUS_UNSPECIFIED 1 +#define IEEE80211_STATUS_CAPINFO 10 +#define IEEE80211_STATUS_NOT_ASSOCED 11 +#define IEEE80211_STATUS_OTHER 12 +#define IEEE80211_STATUS_ALG 13 +#define IEEE80211_STATUS_SEQUENCE 14 +#define IEEE80211_STATUS_CHALLENGE 15 +#define IEEE80211_STATUS_TIMEOUT 16 +#define IEEE80211_STATUS_TOOMANY 17 +#define IEEE80211_STATUS_BASIC_RATE 18 +#define IEEE80211_STATUS_SP_REQUIRED 19 +#define IEEE80211_STATUS_PBCC_REQUIRED 20 +#define IEEE80211_STATUS_CA_REQUIRED 21 +#define IEEE80211_STATUS_TOO_MANY_STATIONS 22 +#define IEEE80211_STATUS_RATES 23 +#define IEEE80211_STATUS_SHORTSLOT_REQUIRED 25 +#define IEEE80211_STATUS_DSSSOFDM_REQUIRED 26 + +#define IEEE80211_WEP_KEYLEN 5 /* 40bit */ +#define IEEE80211_WEP_IVLEN 3 /* 24bit */ +#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ +#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ +#define IEEE80211_WEP_NKID 4 /* number of key ids */ + +#define IEEE80211_CRC_LEN 4 + +#define IEEE80211_MTU 1500 +#define IEEE80211_MAX_LEN (2300 + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) + +/* + * RTS frame length parameters. The default is specified in + * the 802.11 spec. The max may be wrong for jumbo frames. + */ +#define IEEE80211_RTS_DEFAULT 512 +#define IEEE80211_RTS_MIN 1 +#define IEEE80211_RTS_MAX IEEE80211_MAX_LEN + +#define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */ + +#define IEEE80211_AUTH_NONE 0 +#define IEEE80211_AUTH_OPEN 1 +#define IEEE80211_AUTH_SHARED 2 + +#ifdef __KERNEL__ + +#define IEEE80211_PSCAN_WAIT 5 /* passive scan wait */ +#define IEEE80211_TRANS_WAIT 5 /* transition wait */ +#define IEEE80211_INACT_WAIT 5 /* inactivity timer interval */ +#define IEEE80211_INACT_MAX (300/IEEE80211_INACT_WAIT) + +/* + * Structure for IEEE 802.11 drivers. + */ + +#define IEEE80211_CHAN_MAX 255 +#define IEEE80211_CHAN_ANYC \ + ((struct ieee80211channel *) IEEE80211_CHAN_ANY) + +#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ +#define IEEE80211_RATE_MAXSIZE 15 /* max rates we'll handle */ +#define IEEE80211_KEYBUF_SIZE 16 +#define IEEE80211_NODE_HASHSIZE 32 +/* simple hash is enough for variation of macaddr */ +#define IEEE80211_NODE_HASH(addr) \ + (((u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % IEEE80211_NODE_HASHSIZE) + +enum ieee80211_phytype { + IEEE80211_T_DS, /* direct sequence spread spectrum */ + IEEE80211_T_FH, /* frequency hopping */ + IEEE80211_T_OFDM, /* frequency division multiplexing */ + IEEE80211_T_TURBO, /* high rate OFDM, aka turbo mode */ +}; +#define IEEE80211_T_CCK IEEE80211_T_DS /* more common nomenclature */ + +/* XXX not really a mode; there are really multiple PHY's */ +enum ieee80211_phymode { + IEEE80211_MODE_AUTO = 0, /* autoselect */ + IEEE80211_MODE_11A = 1, /* 5GHz, OFDM */ + IEEE80211_MODE_11B = 2, /* 2GHz, CCK */ + IEEE80211_MODE_11G = 3, /* 2GHz, OFDM */ + IEEE80211_MODE_TURBO = 4, /* 5GHz, OFDM, 2x clock */ +}; +#define IEEE80211_MODE_MAX (IEEE80211_MODE_TURBO+1) + +enum ieee80211_opmode { + IEEE80211_M_STA = 1, /* infrastructure station */ + IEEE80211_M_IBSS = 0, /* IBSS (adhoc) station */ + IEEE80211_M_AHDEMO = 3, /* Old lucent compatible adhoc demo */ + IEEE80211_M_HOSTAP = 6 /* Software Access Point */ +}; + +enum ieee80211_state { + IEEE80211_S_INIT, /* default state */ + IEEE80211_S_SCAN, /* scanning */ + IEEE80211_S_AUTH, /* try to authenticate */ + IEEE80211_S_ASSOC, /* try to assoc */ + IEEE80211_S_RUN /* associated */ +}; + +/* + * Channels are specified by frequency and attributes. + */ +/* XXX should be ieee80211_channel but NetBSD took that for an ioctl param */ +struct ieee80211channel { + u_int16_t ic_freq; /* setting in Mhz */ + u_int16_t ic_flags; /* see below */ +}; + +/* bits 0-3 are for private use by drivers */ +/* channel attributes */ +#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ + +/* + * Useful combinations of channel characteristics. + */ +#define IEEE80211_CHAN_A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_B \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) +#define IEEE80211_CHAN_PUREG \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) +#define IEEE80211_CHAN_T \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) + +#define IEEE80211_IS_CHAN_A(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) +#define IEEE80211_IS_CHAN_B(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) +#define IEEE80211_IS_CHAN_PUREG(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) +#define IEEE80211_IS_CHAN_G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) +#define IEEE80211_IS_CHAN_T(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_T) == IEEE80211_CHAN_T) + +#define IEEE80211_IS_CHAN_2GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0) +#define IEEE80211_IS_CHAN_5GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0) +#define IEEE80211_IS_CHAN_OFDM(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_OFDM) != 0) +#define IEEE80211_IS_CHAN_CCK(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0) + +struct ieee80211_rateset { + u_int8_t rs_nrates; + u_int8_t rs_rates[IEEE80211_RATE_MAXSIZE]; +}; + +/* + * Node specific information. + */ +struct ieee80211_node { + TAILQ_ENTRY(ieee80211_node) ni_list; + LIST_ENTRY(ieee80211_node) ni_hash; + atomic_t ni_refcnt; + + /* hardware */ + u_int8_t ni_rssi; /* recv ssi */ + u_int32_t ni_rstamp; /* recv timestamp */ + u_int8_t ni_rantenna; /* recv antenna */ + + /* header */ + u_int8_t ni_macaddr[IEEE80211_ADDR_LEN]; + u_int8_t ni_bssid[IEEE80211_ADDR_LEN]; + + /* beacon, probe response */ + u_int8_t ni_tstamp[8]; /* from last rcv'd beacon */ + u_int16_t ni_intval; /* beacon interval */ + u_int16_t ni_capinfo; /* capabilities */ + u_int8_t ni_esslen; + u_int8_t ni_essid[IEEE80211_NWID_LEN]; + struct ieee80211_rateset ni_rates; /* negotiated rate set */ + u_int8_t *ni_country; /* country information */ + struct ieee80211channel *ni_chan; + u_int16_t ni_fhdwell; /* FH only */ + u_int8_t ni_fhindex; /* FH only */ + u_int8_t ni_erp; /* 11g only */ + + /* DTIM and contention free period (CFP) */ + u_int8_t ni_dtimperiod; + u_int8_t ni_cfpperiod; /* # of DTIMs between CFPs */ + u_int16_t ni_cfpduremain; /* remaining cfp duration */ + u_int16_t ni_cfpmaxduration;/* max CFP duration in TU */ + u_int16_t ni_nextdtim; /* time to next DTIM */ + u_int16_t ni_timoffset; + + /* others */ + u_int16_t ni_associd; /* assoc response */ + u_int16_t ni_txseq; /* seq to be transmitted */ + u_int16_t ni_rxseq; /* seq previous received */ + int ni_fails; /* failure count to associate */ + int ni_inact; /* inactivity mark count */ + int ni_txrate; /* index to ni_rates[] */ + void *ni_private; /* driver private */ +}; + +static inline struct ieee80211_node * +ieee80211_ref_node(struct ieee80211_node *ni) +{ + atomic_inc(&ni->ni_refcnt); + return ni; +} + +static inline void +ieee80211_unref_node(struct ieee80211_node **ni) +{ + atomic_dec(&(*ni)->ni_refcnt); + *ni = NULL; /* guard against use */ +} + +/* ni_chan encoding for FH phy */ +#define IEEE80211_FH_CHANMOD 80 +#define IEEE80211_FH_CHAN(set,pat) (((set)-1)*IEEE80211_FH_CHANMOD+(pat)) +#define IEEE80211_FH_CHANSET(chan) ((chan)/IEEE80211_FH_CHANMOD+1) +#define IEEE80211_FH_CHANPAT(chan) ((chan)%IEEE80211_FH_CHANMOD) + +struct ieee80211_wepkey { + int wk_len; + u_int8_t wk_key[IEEE80211_KEYBUF_SIZE]; +}; + +struct proc_dir_entry; + +struct ieee80211com { + struct net_device ic_dev; /* NB: this must be first */ + struct timer_list ic_slowtimo; /* mgmt/inactivity timer */ + int ic_mgt_timer; /* mgmt timeout */ + int ic_inact_timer; /* inactivity timer wait */ + int (*ic_mgtstart)(struct sk_buff *, + struct net_device *); + int (*ic_init)(struct net_device *); + void (*ic_recv_mgmt[16])(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); + struct net_device_stats ic_stats; /* interface statistics */ + u_int32_t msg_enable; /* interface message flags */ + int (*ic_send_mgmt[16])(struct ieee80211com *, + struct ieee80211_node *, int, int); + int (*ic_newstate)(void *, enum ieee80211_state); + int (*ic_chancheck)(void *, u_char *); + struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; + struct ieee80211channel ic_channels[IEEE80211_CHAN_MAX+1]; + u_char ic_chan_avail[roundup(IEEE80211_CHAN_MAX,NBBY)]; + u_char ic_chan_active[roundup(IEEE80211_CHAN_MAX, NBBY)]; + u_char ic_chan_scan[roundup(IEEE80211_CHAN_MAX,NBBY)]; + u_int32_t ic_flags; /* state flags */ + u_int32_t ic_caps; /* capabilities */ + u_int16_t ic_modecaps; /* set of mode capabilities */ + u_int16_t ic_curmode; /* current mode */ + enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */ + enum ieee80211_opmode ic_opmode; /* operation mode */ + enum ieee80211_state ic_state; /* 802.11 state */ + struct ifmedia ic_media; /* interface media config */ + struct ieee80211_node ic_bss; /* information for this node */ + int ic_node_privlen;/* size for ni_private */ + void (*ic_node_free)(struct ieee80211com *, + struct ieee80211_node *); /* callback */ + struct ieee80211channel *ic_ibss_chan; + int ic_fixed_rate; /* index to ic_sup_rates[] */ + u_int16_t ic_rtsthreshold; + u_int16_t ic_fragthreshold; + rwlock_t ic_nodelock; /* on node table */ + TAILQ_HEAD(, ieee80211_node) ic_node; /* information of all nodes */ + LIST_HEAD(, ieee80211_node) ic_hash[IEEE80211_NODE_HASHSIZE]; + u_int16_t ic_lintval; /* listen interval */ + u_int16_t ic_holdover; /* PM hold over duration */ + u_int16_t ic_txmin; /* min tx retry count */ + u_int16_t ic_txmax; /* max tx retry count */ + u_int16_t ic_txlifetime; /* tx lifetime */ + u_int16_t ic_txpower; /* tx power setting (dbM) */ + u_int16_t ic_bmisstimeout;/* beacon miss threshold (ms) */ + int ic_nicknamelen; + u_int8_t ic_nickname[IEEE80211_NWID_LEN]; + int ic_des_esslen; + u_int8_t ic_des_essid[IEEE80211_NWID_LEN]; + struct ieee80211channel *ic_des_chan; /* desired channel */ + u_int8_t ic_des_bssid[IEEE80211_ADDR_LEN]; + struct ieee80211_wepkey ic_nw_keys[IEEE80211_WEP_NKID]; + int ic_wep_txkey; /* default tx key index */ + void *ic_wep_ctx; /* wep crypt context */ + u_int32_t ic_iv; /* initial vector for wep */ +#ifdef CONFIG_PROC_FS + char ic_procname[12];/* e.g. wlan%d */ + struct proc_dir_entry *ic_proc; /* /proc/net/wlan%d */ +#endif +#ifdef CONFIG_NET_WIRELESS + struct iw_statistics ic_iwstats; /* wireless statistics block */ +#endif +}; + +#define IEEE80211_SEND_MGMT(ic,ni,type,arg) do { \ + if ((ic)->ic_send_mgmt[(type)>>IEEE80211_FC0_SUBTYPE_SHIFT] != NULL) \ + (*(ic)->ic_send_mgmt[(type)>>IEEE80211_FC0_SUBTYPE_SHIFT]) \ + (ic,ni,type,arg); \ +} while (0) + +#define IEEE80211_ADDR_EQ(a1,a2) (memcmp(a1,a2,IEEE80211_ADDR_LEN) == 0) +#define IEEE80211_ADDR_COPY(dst,src) memcpy(dst,src,IEEE80211_ADDR_LEN) + +#define IEEE80211_IS_MULTICAST(a) ETHER_IS_MULTICAST(a) + +/* ic_flags */ +#define IEEE80211_F_ASCAN 0x00000001 /* STATUS: active scan */ +#define IEEE80211_F_SIBSS 0x00000002 /* STATUS: start IBSS */ +#define IEEE80211_F_WEPON 0x00000100 /* CONF: WEP enabled */ +#define IEEE80211_F_IBSSON 0x00000200 /* CONF: IBSS creation enable */ +#define IEEE80211_F_PMGTON 0x00000400 /* CONF: Power mgmt enable */ +#define IEEE80211_F_DESBSSID 0x00000800 /* CONF: des_bssid is set */ +#define IEEE80211_F_SCANAP 0x00001000 /* CONF: Scanning AP */ +#define IEEE80211_F_ROAMING 0x00002000 /* CONF: roaming enabled */ +#define IEEE80211_F_SWRETRY 0x00004000 /* CONF: sw tx retry enabled */ +#define IEEE80211_F_TXPMGT 0x00018000 /* STATUS: tx power */ +#define IEEE80211_F_TXPOW_OFF 0x00000000 /* TX Power: radio disabled */ +#define IEEE80211_F_TXPOW_FIXED 0x00008000 /* TX Power: fixed rate */ +#define IEEE80211_F_TXPOW_AUTO 0x00010000 /* TX Power: undefined */ +#define IEEE80211_F_SHSLOT 0x00020000 /* CONF: short slot time */ +#define IEEE80211_F_SHPREAMBLE 0x00040000 /* CONF: short preamble */ + +/* ic_capabilities */ +#define IEEE80211_C_WEP 0x00000001 /* CAPABILITY: WEP available */ +#define IEEE80211_C_IBSS 0x00000002 /* CAPABILITY: IBSS available */ +#define IEEE80211_C_PMGT 0x00000004 /* CAPABILITY: Power mgmt */ +#define IEEE80211_C_HOSTAP 0x00000008 /* CAPABILITY: HOSTAP avail */ +#define IEEE80211_C_AHDEMO 0x00000010 /* CAPABILITY: Old Adhoc Demo */ +#define IEEE80211_C_SWRETRY 0x00000020 /* CAPABILITY: sw tx retry */ +#define IEEE80211_C_TXPMGT 0x00000040 /* CAPABILITY: tx power mgmt */ +#define IEEE80211_C_SHSLOT 0x00000080 /* CAPABILITY: short slottime */ +#define IEEE80211_C_SHPREAMBLE 0x00000100 /* CAPABILITY: short preamble */ + +/* flags for ieee80211_fix_rate() */ +#define IEEE80211_F_DOSORT 0x00000001 /* sort rate list */ +#define IEEE80211_F_DOFRATE 0x00000002 /* use fixed rate */ +#define IEEE80211_F_DONEGO 0x00000004 /* calc negotiated rate */ +#define IEEE80211_F_DODEL 0x00000008 /* delete ignore rate */ + +/* private extensions to netdevice.h's netif_msg* mechanism */ +#define NETIF_MSG_DEBUG 0x80000000 /* IFF_DEBUG equivalent */ +#define NETIF_MSG_LINK2 0x40000000 /* IFF_LINK2 equivalant */ +#define netif_msg_debug(p) ((p)->msg_enable & NETIF_MSG_DEBUG) +#define netif_msg_dumppkts(p) \ + (((p)->msg_enable & (NETIF_MSG_DEBUG|NETIF_MSG_LINK2)) == \ + (NETIF_MSG_DEBUG|NETIF_MSG_LINK2)) + +int ieee80211_ifattach(struct net_device *); +void ieee80211_ifdetach(struct net_device *); +void ieee80211_input(struct net_device *, struct sk_buff *, + int, u_int32_t, u_int); +int ieee80211_mgmt_output(struct net_device *, struct ieee80211_node *, + struct sk_buff *, int); +struct sk_buff *ieee80211_encap(struct net_device *, struct sk_buff *); +struct sk_buff *ieee80211_decap(struct net_device *, struct sk_buff *); +u_int8_t *ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *); +u_int8_t *ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *); +void ieee80211_media_init(struct net_device *, ifm_change_cb_t, + ifm_stat_cb_t); +int ieee80211_media_change(struct net_device *); +void ieee80211_media_status(struct net_device *, struct ifmediareq *); +void ieee80211_print_essid(u_int8_t *, int); +void ieee80211_dump_pkt(u_int8_t *, int, int, int); +void ieee80211_reset_scan(struct net_device *); +void ieee80211_next_scan(struct net_device *); +void ieee80211_end_scan(struct net_device *); +struct ieee80211_node *ieee80211_alloc_node(struct ieee80211com *, u_int8_t *); +struct ieee80211_node *ieee80211_dup_bss(struct ieee80211com *, u_int8_t *); +struct ieee80211_node *ieee80211_find_node(struct ieee80211com *, u_int8_t *); +struct ieee80211_node * ieee80211_lookup_node(struct ieee80211com *, + u_int8_t *macaddr, struct ieee80211channel *); +void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *); +typedef void ieee80211_iter_func(void *, struct ieee80211_node *); +void ieee80211_iterate_nodes(struct ieee80211com *ic, + ieee80211_iter_func *, void *); +void ieee80211_set_node(struct ieee80211com *, struct ieee80211_node *, + struct ieee80211channel *); +int ieee80211_fix_rate(struct ieee80211com *, struct ieee80211_node *, int); +int ieee80211_new_state(struct net_device *, enum ieee80211_state, int); +struct sk_buff *ieee80211_wep_crypt(struct net_device *, struct sk_buff *, int); +int ieee80211_rate2media(struct ieee80211com *, int, + enum ieee80211_phymode); +int ieee80211_media2rate(int); +u_int ieee80211_mhz2ieee(u_int, u_int); +u_int ieee80211_chan2ieee(struct ieee80211com *, struct ieee80211channel *); +u_int ieee80211_ieee2mhz(u_int, u_int); +int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); +enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *, + struct ieee80211channel *); + +extern const char *ether_sprintf(const u_int8_t *); /* XXX */ + +#endif /* __KERNEL__ */ + +#endif /* _NET_IF_IEEE80211_H_ */ diff -Nru a/drivers/net/wireless/atheros/wlan/if_ieee80211ioctl.h b/drivers/net/wireless/atheros/wlan/if_ieee80211ioctl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_ieee80211ioctl.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_ieee80211ioctl.h,v 1.3 2003/05/16 20:23:27 sam Exp $ + */ +#ifndef _NET_IF_IEEE80211IOCTL_H_ +#define _NET_IF_IEEE80211IOCTL_H_ + +/* + * Wireless Extensions API, private ioctl interfaces. + * + * NB: Even ioctl numbers are privileged! + */ +#define IEEE80211_IOCTL_SETPARAM (SIOCIWFIRSTPRIV+0) +#define IEEE80211_IOCTL_GETPARAM (SIOCIWFIRSTPRIV+1) + +enum { + IEEE80211_PARAM_TURBO = 1, /* turbo mode */ + IEEE80211_PARAM_MODE = 2, /* phy mode (11a, 11b, etc.) */ +}; + +#endif /* _NET_IF_IEEE80211_H_ */ diff -Nru a/drivers/net/wireless/atheros/wlan/if_ieee80211subr.c b/drivers/net/wireless/atheros/wlan/if_ieee80211subr.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_ieee80211subr.c Wed Jul 30 18:20:27 2003 @@ -0,0 +1,3609 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_ieee80211subr.c,v 1.38 2003/06/20 19:02:00 sam Exp $ + */ + +/* + * IEEE 802.11 generic handler + * + * This code is derived from NetBSD code; their copyright notice follows. + */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Atsushi Onoe. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rc4.h" +#define arc4_ctxlen() sizeof (struct rc4_state) +#define arc4_setkey(_c,_k,_l) rc4_init(_c,_k,_l) +#define arc4_encrypt(_c,_d,_s,_l) rc4_crypt(_c,_s,_d,_l) + +#include "if_ieee80211.h" +#include "if_llc.h" +#include "if_ethersubr.h" + +#define __MOD_INC_USE_COUNT(_m) \ + if (!try_module_get(_m)) { \ + printk(KERN_WARNING "%s: try_module_get failed\n", \ + ic->ic_dev.name); \ + return (ENODEV); \ + } +#define __MOD_DEC_USE_COUNT(_m) module_put(_m) + +#define IEEE80211_DEBUG +#ifdef IEEE80211_DEBUG +static int ieee80211_debug = 0; +#define DPRINTF(_ic, X) if (netif_msg_debug(_ic)) printk X +#define DPRINTF2(_ic, X) if (netif_msg_debug(_ic)>1) printk X +#else +#define DPRINTF(_ic, X) +#define DPRINTF2(_ic, X) +#endif + +#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) +#define IEEE80211_IS_SUBTYPE(_fc, _type) \ + (((_fc) & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_##_type) + +static int ieee80211_send_prreq(struct ieee80211com *, + struct ieee80211_node *, int, int); +static int ieee80211_send_prresp(struct ieee80211com *, + struct ieee80211_node *, int, int); +static int ieee80211_send_auth(struct ieee80211com *, + struct ieee80211_node *, int, int); +static int ieee80211_send_deauth(struct ieee80211com *, + struct ieee80211_node *, int, int); +static int ieee80211_send_asreq(struct ieee80211com *, + struct ieee80211_node *, int, int); +static int ieee80211_send_asresp(struct ieee80211com *, + struct ieee80211_node *, int, int); +static int ieee80211_send_disassoc(struct ieee80211com *, + struct ieee80211_node *, int, int); + +static void ieee80211_recv_beacon(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); +static void ieee80211_recv_prreq(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); +static void ieee80211_recv_auth(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); +static void ieee80211_recv_asreq(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); +static void ieee80211_recv_asresp(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); +static void ieee80211_recv_disassoc(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); +static void ieee80211_recv_deauth(struct ieee80211com *, + struct sk_buff *, int, u_int32_t, u_int); + +static void ieee80211_set11gbasicrates(struct ieee80211_rateset *, + enum ieee80211_phymode); +static void ieee80211_crc_init(void); +static u_int32_t ieee80211_crc_update(u_int32_t, u_int8_t *, int); +static struct net_device_stats *ieee80211_getstats(struct net_device *); +static void ieee80211_free_allnodes(struct ieee80211com *); +static void ieee80211_watchdog(unsigned long); +static void ieee80211_timeout_nodes(struct ieee80211com *); +static int ieee80211_setup_rates(struct ieee80211com *, struct ieee80211_node *, + u_int8_t *rates, u_int8_t *xrates, int flags); + +extern int ieee80211_cfgget(struct net_device *, u_long, caddr_t); +extern int ieee80211_cfgset(struct net_device *, u_long, caddr_t); +#ifdef CONFIG_PROC_FS +static void ieee80211_proc_init(struct ieee80211com *); +static void ieee80211_proc_remove(struct ieee80211com *); +#endif /* CONFIG_PROC_FS */ +#ifdef CONFIG_NET_WIRELESS +extern struct iw_statistics *ieee80211_iw_getstats(struct net_device *); +extern const struct iw_handler_def ieee80211_iw_handler_def; +#endif + +static const char *ieee80211_mgt_subtype_name[] = { + "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", + "probe_req", "probe_resp", "reserved#6", "reserved#7", + "beacon", "atim", "disassoc", "auth", + "deauth", "reserved#13", "reserved#14", "reserved#15" +}; +static const char *ieee80211_phymode_name[] = { + "auto", /* IEEE80211_MODE_AUTO */ + "11a", /* IEEE80211_MODE_11A */ + "11b", /* IEEE80211_MODE_11B */ + "11g", /* IEEE80211_MODE_11G */ + "turbo", /* IEEE80211_MODE_TURBO */ +}; + +int +ieee80211_ifattach(struct net_device *dev) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211channel *c; + int i; + + __MOD_INC_USE_COUNT(THIS_MODULE); + + /* + * Register the netdevice early so the device + * name is filled in for any msgs. + * + * NB: The driver is expected to fill in anything + * it cares about; we fillin only default handlers. + */ + if (dev->get_stats == NULL) + dev->get_stats = ieee80211_getstats; +#ifdef CONFIG_NET_WIRELESS + if (dev->get_wireless_stats == NULL) + dev->get_wireless_stats = ieee80211_iw_getstats; + if (dev->wireless_handlers == NULL) + dev->wireless_handlers = + (struct iw_handler_def *) &ieee80211_iw_handler_def; +#endif /* CONFIG_NET_WIRELESS */ + if (register_netdev(&ic->ic_dev)) { + printk(KERN_WARNING "%s: unable to register device\n", + ic->ic_dev.name); + return (EIO); + } + + init_timer(&ic->ic_slowtimo); + ic->ic_slowtimo.data = (unsigned long) ic; + ic->ic_slowtimo.function = ieee80211_watchdog; + ieee80211_watchdog((unsigned long) ic); /* prime timer */ + + /* + * Setup crypto support. + */ + ieee80211_crc_init(); + get_random_bytes(&ic->ic_iv, sizeof(ic->ic_iv)); + + /* + * Fill in 802.11 available channel set, mark + * all available channels as active, and pick + * a default channel if not already specified. + */ + memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); + ic->ic_modecaps |= 1<ic_channels[i]; + if (c->ic_flags) { + /* + * Verify driver passed us valid data. + */ + if (i != ieee80211_chan2ieee(ic, c)) { + printk(KERN_WARNING "%s: bad channel ignored; " + "freq %u flags %x number %u\n", + dev->name, c->ic_freq, c->ic_flags, i); + c->ic_flags = 0; /* NB: remove */ + continue; + } + setbit(ic->ic_chan_avail, i); + /* + * Identify mode capabilities. + */ + if (IEEE80211_IS_CHAN_A(c)) + ic->ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_modecaps |= 1<ic_curmode */ + if ((ic->ic_modecaps & (1<ic_curmode)) == 0) + ic->ic_curmode = IEEE80211_MODE_AUTO; + + (void) ieee80211_setmode(ic, ic->ic_curmode); + +#ifdef notdef + ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; +#else + ic->ic_rtsthreshold = IEEE80211_RTS_MAX; +#endif + ic->ic_fragthreshold = 2346; /* XXX not used yet */ + ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ + ic->ic_fixed_rate = -1; /* no fixed rate */ + if (ic->ic_lintval == 0) + ic->ic_lintval = 100; /* default sleep */ + ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ + + rwlock_init(&ic->ic_nodelock); + TAILQ_INIT(&ic->ic_node); + for (i = 0; i < IEEE80211_NODE_HASHSIZE; i++) + LIST_INIT(&ic->ic_hash[i]); + + /* initialize management frame handlers */ + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_RESP + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_beacon; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_BEACON + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_beacon; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_REQ + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_prreq; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_AUTH + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_auth; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_REQ + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asreq; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asresp; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_asresp; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_DEAUTH + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_deauth; + ic->ic_recv_mgmt[IEEE80211_FC0_SUBTYPE_DISASSOC + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_recv_disassoc; + + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_REQ + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_prreq; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_PROBE_RESP + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_prresp; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_AUTH + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_auth; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_DEAUTH + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_deauth; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_REQ + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_REQ + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asreq; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_ASSOC_RESP + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_REASSOC_RESP + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_asresp; + ic->ic_send_mgmt[IEEE80211_FC0_SUBTYPE_DISASSOC + >> IEEE80211_FC0_SUBTYPE_SHIFT] = ieee80211_send_disassoc; + +#ifdef CONFIG_PROC_FS + ieee80211_proc_init(ic); +#endif + + return (0); +} + +void +ieee80211_ifdetach(struct net_device *dev) +{ + struct ieee80211com *ic = (void *)dev; + + del_timer(&ic->ic_slowtimo); + if (ic->ic_wep_ctx != NULL) { + kfree(ic->ic_wep_ctx); + ic->ic_wep_ctx = NULL; + } + ieee80211_free_allnodes(ic); + ifmedia_removeall(&ic->ic_media); + unregister_netdev(&ic->ic_dev); +#ifdef CONFIG_PROC_FS + ieee80211_proc_remove(ic); +#endif + + __MOD_DEC_USE_COUNT(THIS_MODULE); +} + +/* + * Convert MHz frequency to IEEE channel number. + */ +u_int +ieee80211_mhz2ieee(u_int freq, u_int flags) +{ + if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + else + return 15 + ((freq - 2512) / 20); + } else if (IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ + return (freq - 5000) / 5; + } else { /* either, guess */ + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + if (freq < 5000) + return 15 + ((freq - 2512) / 20); + return (freq - 5000) / 5; + } +} + +/* + * Convert channel to IEEE channel number. + */ +u_int +ieee80211_chan2ieee(struct ieee80211com *ic, struct ieee80211channel *c) +{ + if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX]) + return c - ic->ic_channels; + else if (c == IEEE80211_CHAN_ANYC) + return IEEE80211_CHAN_ANY; + else { + printk(KERN_ERR "wlan: invalid channel freq %u flags %x\n", + c->ic_freq, c->ic_flags); + return 0; /* XXX */ + } +} + +/* + * Convert IEEE channel number to MHz frequency. + */ +u_int +ieee80211_ieee2mhz(u_int chan, u_int flags) +{ + if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ + if (chan == 14) + return 2484; + if (chan < 14) + return 2407 + chan*5; + else + return 2512 + ((chan-15)*20); + } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */ + return 5000 + (chan*5); + } else { /* either, guess */ + if (chan == 14) + return 2484; + if (chan < 14) /* 0-13 */ + return 2407 + chan*5; + if (chan < 27) /* 15-26 */ + return 2512 + ((chan-15)*20); + return 5000 + (chan*5); + } +} + +/* + * Setup the media data structures according to the channel and + * rate tables. This must be called by the driver after + * ieee80211_attach and before most anything else. + */ +void +ieee80211_media_init(struct net_device *dev, + ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) +{ +#define ADD(_ic, _s, _o) \ + ifmedia_add(&(_ic)->ic_media, \ + IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) + struct ieee80211com *ic = (void *)dev; + struct ifmediareq imr; + int i, j, mode, rate, maxrate, mword, mopt, r; + struct ieee80211_rateset *rs; + struct ieee80211_rateset allrates; + + /* + * Fill in media characteristics. + */ + ifmedia_init(&ic->ic_media, 0, media_change, media_stat); + maxrate = 0; + memset(&allrates, 0, sizeof(allrates)); + for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) { + static const u_int mopts[] = { + IFM_AUTO, + IFM_MAKEMODE(IFM_IEEE80211_11A), + IFM_MAKEMODE(IFM_IEEE80211_11B), + IFM_MAKEMODE(IFM_IEEE80211_11G), + IFM_MAKEMODE(IFM_IEEE80211_11A) | IFM_IEEE80211_TURBO, + }; + if ((ic->ic_modecaps & (1<ic_caps & IEEE80211_C_IBSS) + ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC); + if (ic->ic_caps & IEEE80211_C_HOSTAP) + ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); + if (ic->ic_caps & IEEE80211_C_AHDEMO) + ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); + if (mode == IEEE80211_MODE_AUTO) + continue; + printk("%s: %s rates: ", dev->name, + ieee80211_phymode_name[mode]); + rs = &ic->ic_sup_rates[mode]; + for (i = 0; i < rs->rs_nrates; i++) { + rate = rs->rs_rates[i]; + mword = ieee80211_rate2media(ic, rate, mode); + if (mword == 0) + continue; + printk("%s%d%sMbps", (i != 0 ? " " : ""), + (rate & IEEE80211_RATE_VAL) / 2, + ((rate & 0x1) != 0 ? ".5" : "")); + ADD(ic, mword, mopt); + if (ic->ic_caps & IEEE80211_C_IBSS) + ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC); + if (ic->ic_caps & IEEE80211_C_HOSTAP) + ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP); + if (ic->ic_caps & IEEE80211_C_AHDEMO) + ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); + /* + * Add rate to the collection of all rates. + */ + r = rate & IEEE80211_RATE_VAL; + for (j = 0; j < allrates.rs_nrates; j++) + if (allrates.rs_rates[j] == r) + break; + if (j == allrates.rs_nrates) { + /* unique, add to the set */ + allrates.rs_rates[j] = r; + allrates.rs_nrates++; + } + rate = (rate & IEEE80211_RATE_VAL) / 2; + if (rate > maxrate) + maxrate = rate; + } + printk("\n"); + } + for (i = 0; i < allrates.rs_nrates; i++) { + mword = ieee80211_rate2media(ic, allrates.rs_rates[i], + IEEE80211_MODE_AUTO); + if (mword == 0) + continue; + mword = IFM_SUBTYPE(mword); /* remove media options */ + ADD(ic, mword, 0); + if (ic->ic_caps & IEEE80211_C_IBSS) + ADD(ic, mword, IFM_IEEE80211_ADHOC); + if (ic->ic_caps & IEEE80211_C_HOSTAP) + ADD(ic, mword, IFM_IEEE80211_HOSTAP); + if (ic->ic_caps & IEEE80211_C_AHDEMO) + ADD(ic, mword, IFM_IEEE80211_ADHOC | IFM_FLAG0); + } + ieee80211_media_status(dev, &imr); + ifmedia_set(&ic->ic_media, imr.ifm_active); + +#undef ADD +} + +static int +findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) +{ +#define IEEERATE(_ic,_m,_i) \ + ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) + int i, nrates = ic->ic_sup_rates[mode].rs_nrates; + for (i = 0; i < nrates; i++) + if (IEEERATE(ic, mode, i) == rate) + return i; + return -1; +#undef IEEERATE +} + +/* + * Handle a media change request. + */ +int +ieee80211_media_change(struct net_device *dev) +{ + struct ieee80211com *ic = (void *)dev; + struct ifmedia_entry *ime; + enum ieee80211_opmode newopmode; + enum ieee80211_phymode newphymode; + int i, j, newrate, error = 0; + + ime = ic->ic_media.ifm_cur; + /* + * First, identify the phy mode. + */ + switch (IFM_MODE(ime->ifm_media)) { + case IFM_IEEE80211_11A: + newphymode = IEEE80211_MODE_11A; + break; + case IFM_IEEE80211_11B: + newphymode = IEEE80211_MODE_11B; + break; + case IFM_IEEE80211_11G: + newphymode = IEEE80211_MODE_11G; + break; + case IFM_AUTO: + newphymode = IEEE80211_MODE_AUTO; + break; + default: + return EINVAL; + } + /* + * Turbo mode is an ``option''. Eventually it + * needs to be applied to 11g too. + */ + if (ime->ifm_media & IFM_IEEE80211_TURBO) { + if (newphymode != IEEE80211_MODE_11A) + return EINVAL; + newphymode = IEEE80211_MODE_TURBO; + } + /* + * Validate requested mode is available. + */ + if ((ic->ic_modecaps & (1<ifm_media) != IFM_AUTO) { + /* + * Convert media subtype to rate. + */ + newrate = ieee80211_media2rate(ime->ifm_media); + if (newrate == 0) + return EINVAL; + /* + * Check the rate table for the specified/current phy. + */ + if (newphymode == IEEE80211_MODE_AUTO) { + /* + * In autoselect mode search for the rate. + */ + for (j = IEEE80211_MODE_11A; + j < IEEE80211_MODE_MAX; j++) { + if ((ic->ic_modecaps & (1<ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) == + (IFM_IEEE80211_ADHOC|IFM_FLAG0)) + newopmode = IEEE80211_M_AHDEMO; + else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) + newopmode = IEEE80211_M_HOSTAP; + else if (ime->ifm_media & IFM_IEEE80211_ADHOC) + newopmode = IEEE80211_M_IBSS; + else + newopmode = IEEE80211_M_STA; + + /* + * Autoselect doesn't make sense when operating as an AP. + * If no phy mode has been selected, pick one and lock it + * down so rate tables can be used in forming beacon frames + * and the like. + */ + if (newopmode == IEEE80211_M_HOSTAP && + newphymode == IEEE80211_MODE_AUTO) { + for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) + if (ic->ic_modecaps & (1<ic_curmode != newphymode) { /* change phy mode */ + error = ieee80211_setmode(ic, newphymode); + if (error != 0) + return error; + error = ENETRESET; + } + + /* + * Committed to changes, install the rate setting. + */ + if (ic->ic_fixed_rate != i) { + ic->ic_fixed_rate = i; /* set fixed tx rate */ + error = ENETRESET; + } + + /* + * Handle operating mode change. + */ + if (ic->ic_opmode != newopmode) { + ic->ic_opmode = newopmode; + switch (newopmode) { + case IEEE80211_M_AHDEMO: + case IEEE80211_M_HOSTAP: + case IEEE80211_M_STA: + ic->ic_flags &= ~IEEE80211_F_IBSSON; + break; + case IEEE80211_M_IBSS: + ic->ic_flags |= IEEE80211_F_IBSSON; +#ifdef notdef + if (ic->ic_curmode == IEEE80211_MODE_11G) + ieee80211_set11gbasicrates( + &ic->ic_suprates[newphymode], + IEEE80211_MODE_11B); +#endif + break; + } + error = ENETRESET; + } + return error; +} + +void +ieee80211_media_status(struct net_device *dev, struct ifmediareq *imr) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211_node *ni = NULL; + + imr->ifm_status = IFM_AVALID; + imr->ifm_active = IFM_IEEE80211; + if (ic->ic_state == IEEE80211_S_RUN) + imr->ifm_status |= IFM_ACTIVE; + imr->ifm_active |= IFM_AUTO; + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + ni = &ic->ic_bss; + /* calculate rate subtype */ + imr->ifm_active |= ieee80211_rate2media(ic, + ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode); + break; + case IEEE80211_M_IBSS: + imr->ifm_active |= IFM_IEEE80211_ADHOC; + break; + case IEEE80211_M_AHDEMO: + /* should not come here */ + break; + case IEEE80211_M_HOSTAP: + imr->ifm_active |= IFM_IEEE80211_HOSTAP; + break; + } + switch (ic->ic_curmode) { + case IEEE80211_MODE_11A: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A); + break; + case IEEE80211_MODE_11B: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B); + break; + case IEEE80211_MODE_11G: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G); + break; + case IEEE80211_MODE_TURBO: + imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A) + | IFM_IEEE80211_TURBO; + break; + } +} + +void +ieee80211_input(struct net_device *dev, struct sk_buff *skb, + int rssi, u_int32_t rstamp, u_int rantenna) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211_node *ni; + struct ieee80211_frame *wh; + struct ether_header *eh; + void (*rh)(struct ieee80211com *, struct sk_buff *, int, u_int32_t, u_int); + struct sk_buff *skb1; + int len; + u_int8_t dir, subtype; + u_int8_t *bssid; + u_int16_t rxseq; + + wh = (struct ieee80211_frame *) skb->data; + if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != + IEEE80211_FC0_VERSION_0) { + DPRINTF(ic, ("%s: discard packet with wrong version: %x\n", + dev->name, wh->i_fc[0])); + goto err; + } + + dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + + if (ic->ic_state != IEEE80211_S_SCAN) { + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + ni = ieee80211_ref_node(&ic->ic_bss); + if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) { + DPRINTF(ic, ("%s: discard frame from bss %s\n", + dev->name, + ether_sprintf(wh->i_addr2))); + /* not interested in */ + ieee80211_unref_node(&ni); + goto out; + } + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + case IEEE80211_M_HOSTAP: + if (dir == IEEE80211_FC1_DIR_NODS) + bssid = wh->i_addr3; + else + bssid = wh->i_addr1; + if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss.ni_bssid) && + !IEEE80211_ADDR_EQ(bssid, dev->broadcast)) { + /* not interested in */ + DPRINTF2(ic, ("%s: other bss %s\n", __func__, + ether_sprintf(wh->i_addr3))); + goto out; + } + ni = ieee80211_find_node(ic, wh->i_addr2); + if (ni == NULL) { + DPRINTF(ic, ("%s: warning, unknown src %s\n", + __func__, ether_sprintf(wh->i_addr2))); + /* + * NB: Node allocation is handled in the + * management handling routines. Just fake + * up a reference to the hosts's node to do + * the stuff below. + */ + ni = ieee80211_ref_node(&ic->ic_bss); + } + break; + default: + /* XXX catch bad values */ + break; + } + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + ni->ni_rantenna = rantenna; + rxseq = ni->ni_rxseq; + ni->ni_rxseq = + le16_to_cpu(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT; + /* TODO: fragment */ + if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) && + rxseq == ni->ni_rxseq) { + /* duplicate, silently discarded */ + ieee80211_unref_node(&ni); + goto out; + } + ni->ni_inact = 0; + ieee80211_unref_node(&ni); + } + + switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { + case IEEE80211_FC0_TYPE_DATA: + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + if (dir != IEEE80211_FC1_DIR_FROMDS) { + DPRINTF(ic, ("%s:discard frame with invalid " + "direction %x\n", dev->name, dir)); + goto out; + } +#ifdef IFF_SIMPLEX + if ((ifp->if_flags & IFF_SIMPLEX) && + IEEE80211_IS_MULTICAST(wh->i_addr1) && + IEEE80211_ADDR_EQ(wh->i_addr3, dev->dev_addr)) { + /* + * In IEEE802.11 network, multicast packet + * sent from me is broadcasted from AP. + * It should be silently discarded for + * SIMPLEX interface. + */ + DPRINTF(ic, ("%s: discard multicast echo\n", + dev->name)); + goto out; + } +#endif + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + if (dir != IEEE80211_FC1_DIR_NODS) + goto out; + break; + case IEEE80211_M_HOSTAP: + if (dir != IEEE80211_FC1_DIR_TODS) + goto out; + /* check if source STA is associated */ + ni = ieee80211_find_node(ic, wh->i_addr2); + if (ni == NULL) { + DPRINTF(ic, ("%s: data from unknown src %s\n", + __func__, ether_sprintf(wh->i_addr2))); + ni = ieee80211_dup_bss(ic, wh->i_addr2); + if (ni != NULL) { + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_NOT_AUTHED); + ieee80211_free_node(ic, ni); + } + goto err; + } + if (ni->ni_associd == 0) { + DPRINTF(ic, ("%s: data from unassoc src %s\n", + __func__, ether_sprintf(wh->i_addr2))); + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DISASSOC, + IEEE80211_REASON_NOT_ASSOCED); + ieee80211_unref_node(&ni); + goto err; + } + ieee80211_unref_node(&ni); + break; + } + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + if (ic->ic_flags & IEEE80211_F_WEPON) { + skb = ieee80211_wep_crypt(dev, skb, 0); + if (skb == NULL) + goto err; + wh = (struct ieee80211_frame *) skb->data; + } else + goto out; + } + /* copy to listener after decrypt */ + skb = ieee80211_decap(dev, skb); + if (skb == NULL) { + DPRINTF(ic, ("%s: decapsulation failed\n", dev->name)); + goto err; + } + + /* perform as a bridge within the AP */ + skb1 = NULL; + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + eh = (struct ether_header *) skb->data; + if (ETHER_IS_MULTICAST(eh->ether_dhost)) { + skb1 = skb_copy(skb, 0); + } else { + ni = ieee80211_find_node(ic, eh->ether_dhost); + if (ni != NULL) { + if (ni->ni_associd != 0) { + skb1 = skb; + skb = NULL; + } + ieee80211_unref_node(&ni); + } + } + if (skb1 != NULL) { + len = skb1->len; + skb1->dev = dev; + skb1->protocol = __constant_htons(ETH_P_802_2); + dev_queue_xmit(skb1); + } + } + if (skb != NULL) { + dev->last_rx = jiffies; + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + } + return; + + case IEEE80211_FC0_TYPE_MGT: + if (dir != IEEE80211_FC1_DIR_NODS) + goto err; + if (ic->ic_opmode == IEEE80211_M_AHDEMO) + goto out; + subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + /* drop uninteresting frames */ + if (ic->ic_state == IEEE80211_S_SCAN) { + if (subtype != IEEE80211_FC0_SUBTYPE_BEACON && + subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) + goto out; + } else { + if (ic->ic_opmode != IEEE80211_M_IBSS && + subtype == IEEE80211_FC0_SUBTYPE_BEACON) + goto out; + } + + if (netif_msg_debug(ic)) { + /* avoid to print too many frames */ + int doprint = 0; + + switch (subtype) { + case IEEE80211_FC0_SUBTYPE_BEACON: + if (ic->ic_state == IEEE80211_S_SCAN) + doprint = 1; + break; + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + if (ic->ic_opmode == IEEE80211_M_IBSS) + doprint = 1; + break; + default: + doprint = 1; + break; + } +#ifdef IEEE80211_DEBUG + doprint += ieee80211_debug; +#endif + if (doprint) + printk("%s: received %s from %s rssi %d\n", + dev->name, + ieee80211_mgt_subtype_name[subtype + >> IEEE80211_FC0_SUBTYPE_SHIFT], + ether_sprintf(wh->i_addr2), rssi); + } + rh = ic->ic_recv_mgmt[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]; + if (rh != NULL) + (*rh)(ic, skb, rssi, rstamp, rantenna); + goto out; + + case IEEE80211_FC0_TYPE_CTL: + default: + DPRINTF(ic, ("%s: bad type %x\n", __func__, wh->i_fc[0])); + /* should not come here */ + break; + } +err: + ic->ic_stats.rx_errors++; /* XXX */ +out: + if (skb != NULL) + dev_kfree_skb(skb); +} + +int +ieee80211_mgmt_output(struct net_device *dev, struct ieee80211_node *ni, + struct sk_buff *skb, int type) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211_frame *wh; + + /* XXX this probably shouldn't be permitted */ + KASSERT(ni != NULL, ("%s: null node", __func__)); + ni->ni_inact = 0; + + wh = (struct ieee80211_frame *) + skb_push(skb, sizeof(struct ieee80211_frame)); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type; + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + *(u_int16_t *)wh->i_dur = 0; + *(u_int16_t *)wh->i_seq = + cpu_to_le16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); + ni->ni_txseq++; + IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); + IEEE80211_ADDR_COPY(wh->i_addr2, dev->dev_addr); + IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); + + if (netif_msg_debug(ic)) { + /* avoid to print too many frames */ + if (ic->ic_opmode == IEEE80211_M_IBSS || +#ifdef IEEE80211_DEBUG + ieee80211_debug > 1 || +#endif + !IEEE80211_IS_SUBTYPE(type, PROBE_RESP)) + printk("%s: sending %s to %s on channel %u\n", + dev->name, + ieee80211_mgt_subtype_name[ + (type & IEEE80211_FC0_SUBTYPE_MASK) + >> IEEE80211_FC0_SUBTYPE_SHIFT], + ether_sprintf(ni->ni_macaddr), + ieee80211_chan2ieee(ic, ni->ni_chan)); + } + (void) (*ic->ic_mgtstart)(skb, dev); + return 0; +} + +struct sk_buff * +ieee80211_encap(struct net_device *dev, struct sk_buff *skb) +{ + struct ieee80211com *ic = (void *)dev; + struct ether_header eh; + struct ieee80211_frame *wh; + struct llc *llc; + struct ieee80211_node *ni; + + memcpy(&eh, skb->data, sizeof(struct ether_header)); + skb_pull(skb, sizeof(struct ether_header)); + + ni = ieee80211_find_node(ic, eh.ether_dhost); + if (ni == NULL) /* ic_opmode?? XXX*/ + ni = ieee80211_ref_node(&ic->ic_bss); + ni->ni_inact = 0; + + llc = (struct llc *) skb_push(skb, sizeof(struct llc)); + llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; + llc->llc_control = LLC_UI; + llc->llc_snap.org_code[0] = 0; + llc->llc_snap.org_code[1] = 0; + llc->llc_snap.org_code[2] = 0; + llc->llc_snap.ether_type = eh.ether_type; + + /* + * XXX If we're loaded as a module the system may not be + * configured to leave enough headroom for us to push the + * 802.11 frame. In that case fallback on reallocating + * the frame with enough space. Alternatively we can carry + * the frame separately and use s/g support in the hardware. + */ + if (skb_headroom(skb) < sizeof(struct ieee80211_frame) && + pskb_expand_head(skb, sizeof(*wh), 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + ieee80211_unref_node(&ni); + return NULL; + } + wh = (struct ieee80211_frame *) skb_push(skb, sizeof(struct ieee80211_frame)); + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + *(u_int16_t *)wh->i_dur = 0; + *(u_int16_t *)wh->i_seq = + cpu_to_le16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT); + ni->ni_txseq++; + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); + IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); + IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); + break; + case IEEE80211_M_IBSS: + case IEEE80211_M_AHDEMO: + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); + IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); + IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); + break; + case IEEE80211_M_HOSTAP: + wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; + IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); + IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); + IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); + break; + } + ieee80211_unref_node(&ni); + return skb; +} + +struct sk_buff * +ieee80211_decap(struct net_device *dev, struct sk_buff *skb) +{ + struct ether_header *eh; + struct ieee80211_frame wh; + struct llc *llc; + + memcpy(&wh, skb->data, sizeof(struct ieee80211_frame)); + llc = (struct llc *) skb_pull(skb, sizeof(struct ieee80211_frame)); + if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP && + llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 && + llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0) { + skb_pull(skb, sizeof(struct llc)); + llc = NULL; + } + eh = (struct ether_header *) skb_push(skb, sizeof(struct ether_header)); + switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1); + IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2); + break; + case IEEE80211_FC1_DIR_TODS: + IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3); + IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2); + break; + case IEEE80211_FC1_DIR_FROMDS: + IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1); + IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr3); + break; + case IEEE80211_FC1_DIR_DSTODS: + /* not yet supported */ + DPRINTF((struct ieee80211com*) dev, + ("%s: DS to DS\n", __func__)); + dev_kfree_skb(skb); + return NULL; + } + if (!ALIGNED_POINTER(skb->data + sizeof(*eh), u_int32_t)) { + struct sk_buff *n; + + /* XXX does this always work? */ + n = skb_copy(skb, 0); + dev_kfree_skb(skb); + if (n == NULL) + return NULL; + skb = n; + eh = (struct ether_header *) skb->data; + } + if (llc != NULL) + eh->ether_type = htons(skb->len - sizeof(*eh)); + return skb; +} + +void +ieee80211_print_essid(u_int8_t *essid, int len) +{ + int i; + u_int8_t *p; + + if (len > IEEE80211_NWID_LEN) + len = IEEE80211_NWID_LEN; + /* determine printable or not */ + for (i = 0, p = essid; i < len; i++, p++) { + if (*p < ' ' || *p > 0x7e) + break; + } + if (i == len) { + printk("\""); + for (i = 0, p = essid; i < len; i++, p++) + printk("%c", *p); + printk("\""); + } else { + printk("0x"); + for (i = 0, p = essid; i < len; i++, p++) + printk("%02x", *p); + } +} + +void +ieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) +{ + struct ieee80211_frame *wh; + int i; + + wh = (struct ieee80211_frame *)buf; + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + printk("NODS %s", ether_sprintf(wh->i_addr2)); + printk("->%s", ether_sprintf(wh->i_addr1)); + printk("(%s)", ether_sprintf(wh->i_addr3)); + break; + case IEEE80211_FC1_DIR_TODS: + printk("TODS %s", ether_sprintf(wh->i_addr2)); + printk("->%s", ether_sprintf(wh->i_addr3)); + printk("(%s)", ether_sprintf(wh->i_addr1)); + break; + case IEEE80211_FC1_DIR_FROMDS: + printk("FRDS %s", ether_sprintf(wh->i_addr3)); + printk("->%s", ether_sprintf(wh->i_addr1)); + printk("(%s)", ether_sprintf(wh->i_addr2)); + break; + case IEEE80211_FC1_DIR_DSTODS: + printk("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); + printk("->%s", ether_sprintf(wh->i_addr3)); + printk("(%s", ether_sprintf(wh->i_addr2)); + printk("->%s)", ether_sprintf(wh->i_addr1)); + break; + } + switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { + case IEEE80211_FC0_TYPE_DATA: + printk(" data"); + break; + case IEEE80211_FC0_TYPE_MGT: + printk(" %s", ieee80211_mgt_subtype_name[ + (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) + >> IEEE80211_FC0_SUBTYPE_SHIFT]); + break; + default: + printk(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); + break; + } + if (wh->i_fc[1] & IEEE80211_FC1_WEP) + printk(" WEP"); + if (rate >= 0) + printk(" %dM", rate / 2); + if (rssi >= 0) + printk(" +%d", rssi); + printk("\n"); + if (len > 0) { + for (i = 0; i < len; i++) { + if ((i & 1) == 0) + printk(" "); + printk("%02x", buf[i]); + } + printk("\n"); + } +} + +/* + * Once a second "slow timeout" processing. + */ +void +ieee80211_watchdog(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct ieee80211com *ic = (void *)dev; + + if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) + ieee80211_new_state(dev, IEEE80211_S_SCAN, -1); + if (ic->ic_inact_timer && --ic->ic_inact_timer == 0) + ieee80211_timeout_nodes(ic); + + ic->ic_slowtimo.expires = jiffies + HZ; /* once a second */ + add_timer(&ic->ic_slowtimo); +} + +/* + * Mark the basic rates for the 11g rate table based on the + * operating mode. For real 11g we mark all the 11b rates + * and 6, 12, and 24 OFDM. For 11b compatibility we mark only + * 11b rates. There's also a pseudo 11a-mode used to mark only + * the basic OFDM rates. + */ +static void +ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) +{ + static const struct ieee80211_rateset basic[] = { + { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ + { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11B */ + { 7, { 2, 4, 11, 22, 12, 24, 48 } },/* IEEE80211_MODE_11G */ + { 0 }, /* IEEE80211_MODE_TURBO */ + }; + int i, j; + + for (i = 0; i < rs->rs_nrates; i++) { + rs->rs_rates[i] &= IEEE80211_RATE_VAL; + for (j = 0; j < basic[mode].rs_nrates; j++) + if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { + rs->rs_rates[i] |= IEEE80211_RATE_BASIC; + break; + } + } +} + +/* + * Set the current phy mode and recalculate the active channel + * set based on the available channels for this mode. Also + * select a new default/current channel if the current one is + * inappropriate for this mode. + */ +int +ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + static const u_int chanflags[] = { + 0, /* IEEE80211_MODE_AUTO */ + IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ + IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ + IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ + IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */ + }; + struct ieee80211channel *c; + u_int modeflags; + int i; + + /* validate new mode */ + if ((ic->ic_modecaps & (1<ic_modecaps)); + return EINVAL; + } + + /* + * Verify at least one channel is present in the available + * channel list before committing to the new mode. + */ + KASSERT(mode < N(chanflags), ("Unexpected mode %u\n", mode)); + modeflags = chanflags[mode]; + for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { + c = &ic->ic_channels[i]; + if (mode == IEEE80211_MODE_AUTO) { + /* ignore turbo channels for autoselect */ + if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) + break; + } else { + if ((c->ic_flags & modeflags) == modeflags) + break; + } + } + if (i > IEEE80211_CHAN_MAX) { + DPRINTF(ic, ("%s: no channels found for mode %u\n", + __func__, mode)); + return EINVAL; + } + + /* + * Calculate the active channel set. + */ + memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); + for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { + c = &ic->ic_channels[i]; + if (mode == IEEE80211_MODE_AUTO) { + /* take anything but pure turbo channels */ + if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) + setbit(ic->ic_chan_active, i); + } else { + if ((c->ic_flags & modeflags) == modeflags) + setbit(ic->ic_chan_active, i); + } + } + /* + * If no current/default channel is setup or the current + * channel is wrong for the mode then pick the first + * available channel from the active list. This is likely + * not the right one. + */ + if (ic->ic_ibss_chan == NULL || + isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { + for (i = 0; i <= IEEE80211_CHAN_MAX; i++) + if (isset(ic->ic_chan_active, i)) { + ic->ic_ibss_chan = &ic->ic_channels[i]; + break; + } + } + + /* + * Set/reset state flags that influence beacon contents, etc. + * + * XXX what if we have stations already associated??? + * XXX probably not right for autoselect? + */ + if (mode == IEEE80211_MODE_11G) { + if (ic->ic_caps & IEEE80211_C_SHSLOT) + ic->ic_flags |= IEEE80211_F_SHSLOT; + if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) + ic->ic_flags |= IEEE80211_F_SHPREAMBLE; + ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], + IEEE80211_MODE_11G); + } else { + ic->ic_flags &= ~(IEEE80211_F_SHSLOT | IEEE80211_F_SHPREAMBLE); + } + + ic->ic_curmode = mode; + return 0; +#undef N +} + +/* + * AP scanning support. + */ + +/* + * Initialize the active channel set based on the set + * of available channels and the current PHY mode. + */ +void +ieee80211_reset_scan(struct net_device *dev) +{ + struct ieee80211com *ic = (void *)dev; + + memcpy(ic->ic_chan_scan, ic->ic_chan_active, + sizeof(ic->ic_chan_active)); +} + +/* + * Begin an active scan. + */ +void +ieee80211_begin_scan(struct net_device *dev, struct ieee80211_node *ni) +{ + struct ieee80211com *ic = (void *)dev; + + DPRINTF(ic, ("%s: begin %s scan\n", dev->name, + ic->ic_opmode != IEEE80211_M_HOSTAP ? + "active" : "passive")); + + ieee80211_reset_scan(dev); + /* + * Flush any previously seen AP's. Note that this + * assumes we don't act as both an AP and a station, + * otherwise we'll potentially flush state of stations + * associated with us. + */ + ieee80211_free_allnodes(ic); + + clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, ni->ni_chan)); + if (ic->ic_opmode != IEEE80211_M_HOSTAP) { + ic->ic_flags |= IEEE80211_F_ASCAN; + IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); + } +} + +/* + * Switch to the next channel marked for scanning. + */ +void +ieee80211_next_scan(struct net_device *dev) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211channel *chan; + + chan = ic->ic_bss.ni_chan; + for (;;) { + if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX]) + chan = &ic->ic_channels[0]; + if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) { + /* + * Honor channels marked passive-only + * during an active scan. + */ + if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 || + (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) + break; + } + if (chan == ic->ic_bss.ni_chan) { + ieee80211_end_scan(dev); + return; + } + } + clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan)); + DPRINTF(ic, ("%s: chan %d->%d\n", __func__, + ieee80211_chan2ieee(ic, ic->ic_bss.ni_chan), + ieee80211_chan2ieee(ic, chan))); + ic->ic_bss.ni_chan = chan; + ieee80211_new_state(dev, IEEE80211_S_SCAN, -1); +} + +static void +ieee80211_create_ibss(struct net_device* dev, struct ieee80211channel *chan) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211_node *ni; + + ni = &ic->ic_bss; + DPRINTF(ic, ("%s: creating ibss\n", dev->name)); + ic->ic_flags |= IEEE80211_F_SIBSS; + ni->ni_chan = chan; + ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; + IEEE80211_ADDR_COPY(ni->ni_macaddr, dev->dev_addr); + IEEE80211_ADDR_COPY(ni->ni_bssid, dev->dev_addr); + if (ic->ic_opmode == IEEE80211_M_IBSS) + ni->ni_bssid[0] |= 0x02; /* local bit for IBSS */ + ni->ni_esslen = ic->ic_des_esslen; + memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); + ni->ni_rssi = 0; + ni->ni_rstamp = 0; + ni->ni_rantenna = 0; + memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp)); + ni->ni_intval = ic->ic_lintval; + ni->ni_capinfo = IEEE80211_CAPINFO_IBSS; + if (ic->ic_flags & IEEE80211_F_WEPON) + ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; + if (ic->ic_phytype == IEEE80211_T_FH) { + ni->ni_fhdwell = 200; /* XXX */ + ni->ni_fhindex = 1; + } + ieee80211_new_state(dev, IEEE80211_S_RUN, -1); +} + +/* + * Complete a scan of potential channels. + */ +void +ieee80211_end_scan(struct net_device *dev) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211_node *ni, *nextbs, *selbs; + void *p; + u_int8_t rate; + int i, fail; + + ic->ic_flags &= ~IEEE80211_F_ASCAN; + ni = TAILQ_FIRST(&ic->ic_node); + + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + /* XXX off stack? */ + u_char occupied[roundup(IEEE80211_CHAN_MAX, NBBY)]; + /* + * The passive scan to look for existing AP's completed, + * select a channel to camp on. Identify the channels + * that already have one or more AP's and try to locate + * an unnoccupied one. If that fails, pick a random + * channel from the active set. + */ + for (; ni != NULL; ni = nextbs) { + ieee80211_ref_node(ni); + nextbs = TAILQ_NEXT(ni, ni_list); + setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan)); + ieee80211_free_node(ic, ni); + } + for (i = 0; i < IEEE80211_CHAN_MAX; i++) + if (isset(ic->ic_chan_active, i) && isclr(occupied, i)) + break; + if (i == IEEE80211_CHAN_MAX) { + get_random_bytes(&fail, sizeof(fail)); + fail &= 3; /* random 0-3 */ + for (i = 0; i < IEEE80211_CHAN_MAX; i++) + if (isset(ic->ic_chan_active, i) && fail-- == 0) + break; + } + ieee80211_create_ibss(dev, &ic->ic_channels[i]); + return; + } + if (ni == NULL) { + DPRINTF(ic, ("%s: no scan candidate\n", __func__)); + notfound: + if (ic->ic_opmode == IEEE80211_M_IBSS && + (ic->ic_flags & IEEE80211_F_IBSSON) && + ic->ic_des_esslen != 0) { + ieee80211_create_ibss(dev, ic->ic_ibss_chan); + return; + } + /* + * Reset the list of channels to scan and start again. + */ + ieee80211_reset_scan(dev); + ieee80211_next_scan(dev); + return; + } + selbs = NULL; + DPRINTF(ic, ("%s: macaddr bssid chan rssi rate ant flag wep essid\n", dev->name)); + for (; ni != NULL; ni = nextbs) { + ieee80211_ref_node(ni); + nextbs = TAILQ_NEXT(ni, ni_list); + if (ni->ni_fails) { + /* + * The configuration of the access points may change + * during my scan. So delete the entry for the AP + * and retry to associate if there is another beacon. + */ + if (ni->ni_fails++ > 2) + ieee80211_free_node(ic, ni); + continue; + } + fail = 0; + if (ni->ni_chan == NULL || ni->ni_chan->ic_flags == 0) + fail |= 0x01; + if (ic->ic_des_chan != (struct ieee80211channel *) IEEE80211_CHAN_ANY && + ni->ni_chan != ic->ic_des_chan) + fail |= 0x01; + if (ic->ic_opmode == IEEE80211_M_IBSS) { + if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0) + fail |= 0x02; + } else { + if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0) + fail |= 0x02; + } + if (ic->ic_flags & IEEE80211_F_WEPON) { + if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0) + fail |= 0x04; + } else { + if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) + fail |= 0x04; + } + rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO); + if (rate & IEEE80211_RATE_BASIC) + fail |= 0x08; + if (ic->ic_des_esslen != 0 && + (ni->ni_esslen != ic->ic_des_esslen || + memcmp(ni->ni_essid, ic->ic_des_essid, + ic->ic_des_esslen != 0))) + fail |= 0x10; + if ((ic->ic_flags & IEEE80211_F_DESBSSID) && + !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid)) + fail |= 0x20; + if (netif_msg_debug(ic)) { + printk(" %c %s", fail ? '-' : '+', + ether_sprintf(ni->ni_macaddr)); + printk(" %s%c", ether_sprintf(ni->ni_bssid), + fail & 0x20 ? '!' : ' '); + printk(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan), + fail & 0x01 ? '!' : ' '); + printk(" %+4d", ni->ni_rssi); + printk(" %2dM%c", IEEE80211_RATE2MBS(rate), + fail & 0x08 ? '!' : ' '); + printk(" %3d", ni->ni_rantenna); + printk(" %4s%c", + (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" : + (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" : + "????", + fail & 0x02 ? '!' : ' '); + printk(" %3s%c ", + (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ? + "wep" : "no", + fail & 0x04 ? '!' : ' '); + ieee80211_print_essid(ni->ni_essid, ni->ni_esslen); + printk("%s\n", fail & 0x10 ? "!" : ""); + } + if (!fail) { + if (selbs == NULL) + selbs = ni; + else if (ni->ni_rssi > selbs->ni_rssi) { + ieee80211_unref_node(&selbs); + selbs = ni; + } else + ieee80211_unref_node(&ni); + } else { + ieee80211_unref_node(&ni); + } + } + if (selbs == NULL) + goto notfound; + p = ic->ic_bss.ni_private; + ic->ic_bss = *selbs; + ic->ic_bss.ni_private = p; + if (p != NULL && ic->ic_node_privlen) + memcpy(p, selbs->ni_private, ic->ic_node_privlen); + if (ic->ic_opmode == IEEE80211_M_IBSS) { + ieee80211_fix_rate(ic, &ic->ic_bss, IEEE80211_F_DOFRATE | + IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + if (ic->ic_bss.ni_rates.rs_nrates == 0) { + selbs->ni_fails++; + ieee80211_unref_node(&selbs); + goto notfound; + } + ieee80211_unref_node(&selbs); + ieee80211_new_state(dev, IEEE80211_S_RUN, -1); + } else { + ieee80211_unref_node(&selbs); + ieee80211_new_state(dev, IEEE80211_S_AUTH, -1); + } +} + +void +ieee80211_setup_node(struct ieee80211com *ic, + struct ieee80211_node *ni, u_int8_t *macaddr) +{ + int hash; + + IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr); + if (ic->ic_node_privlen) { + ni->ni_private = &ni[1]; + memset(ni->ni_private, 0, ic->ic_node_privlen); + } else + ni->ni_private = NULL; + + hash = IEEE80211_NODE_HASH(macaddr); + write_lock_bh(&ic->ic_nodelock); + atomic_set(&ni->ni_refcnt, 1); /* mark referenced */ + TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list); + LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash); + /* + * Note we don't enable the inactive timer when acting + * as a station. Nodes created in this mode represent + * AP's identified while scanning. If we time them out + * then several things happen: we can't return the data + * to users to show the list of AP's we encountered, and + * more importantly, we'll incorrectly deauthenticate + * ourself because the inactivity timer will kick us off. + */ + if (ic->ic_opmode != IEEE80211_M_STA) + ic->ic_inact_timer = IEEE80211_INACT_WAIT; + write_unlock_bh(&ic->ic_nodelock); +} + +struct ieee80211_node * +ieee80211_alloc_node(struct ieee80211com *ic, u_int8_t *macaddr) +{ + struct ieee80211_node *ni; + + ni = kmalloc(sizeof(struct ieee80211_node) + ic->ic_node_privlen, + GFP_KERNEL); + if (ni != NULL) { + memset(ni, 0, sizeof(struct ieee80211_node)); + ieee80211_setup_node(ic, ni, macaddr); + } + return ni; +} + +struct ieee80211_node * +ieee80211_dup_bss(struct ieee80211com *ic, u_int8_t *macaddr) +{ + struct ieee80211_node *ni; + + ni = kmalloc(sizeof(struct ieee80211_node) + ic->ic_node_privlen, + GFP_KERNEL); + if (ni != NULL) { + memcpy(ni, &ic->ic_bss, sizeof(struct ieee80211_node)); + ieee80211_setup_node(ic, ni, macaddr); + } + return ni; +} + +/* + * Find a node state block given the mac address. Note that + * this returns the first node found with the mac address. + */ +struct ieee80211_node * +ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr) +{ + struct ieee80211_node *ni; + int hash; + + hash = IEEE80211_NODE_HASH(macaddr); + read_lock_bh(&ic->ic_nodelock); + LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { + atomic_inc(&ni->ni_refcnt); /* mark referenced */ + break; + } + } + read_unlock_bh(&ic->ic_nodelock); + return ni; +} + +/* + * Like find but search based on the channel too. + */ +struct ieee80211_node * +ieee80211_lookup_node(struct ieee80211com *ic, + u_int8_t *macaddr, struct ieee80211channel *chan) +{ + struct ieee80211_node *ni; + int hash; + + hash = IEEE80211_NODE_HASH(macaddr); + read_lock_bh(&ic->ic_nodelock); + LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && ni->ni_chan == chan) { + atomic_inc(&ni->ni_refcnt); /* mark referenced */ + break; + } + } + read_unlock_bh(&ic->ic_nodelock); + return ni; +} + +void +_ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + if (atomic_read(&ni->ni_refcnt) != 0) { + struct net_device *dev = &ic->ic_dev; + printk("%s: freeing node %s with non-zero refcnt %u\n", + dev->name, ether_sprintf(ni->ni_macaddr), + atomic_read(&ni->ni_refcnt)); + } + if (ic->ic_node_free != NULL) + (*ic->ic_node_free)(ic, ni); + TAILQ_REMOVE(&ic->ic_node, ni, ni_list); + LIST_REMOVE(ni, ni_hash); + if (TAILQ_EMPTY(&ic->ic_node)) + ic->ic_inact_timer = 0; + kfree(ni); +} + +void +ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + if (atomic_dec_and_test(&ni->ni_refcnt)) { + write_lock_bh(&ic->ic_nodelock); + _ieee80211_free_node(ic, ni); + write_unlock_bh(&ic->ic_nodelock); + } +} + +void +ieee80211_free_allnodes(struct ieee80211com *ic) +{ + struct ieee80211_node *ni; + + write_lock_bh(&ic->ic_nodelock); + while ((ni = TAILQ_FIRST(&ic->ic_node)) != NULL) + _ieee80211_free_node(ic, ni); + write_unlock_bh(&ic->ic_nodelock); +} + +void +ieee80211_timeout_nodes(struct ieee80211com *ic) +{ + struct net_device *dev = &ic->ic_dev; + struct ieee80211_node *ni, *nextbs; + + write_lock(&ic->ic_nodelock); + for (ni = TAILQ_FIRST(&ic->ic_node); ni != NULL;) { + if (++ni->ni_inact <= IEEE80211_INACT_MAX) { + ni = TAILQ_NEXT(ni, ni_list); + continue; + } + /* NB: don't honor reference count */ + DPRINTF(ic, ("%s: station %s timed out " + "due to inactivity (%u secs)\n", + dev->name, + ether_sprintf(ni->ni_macaddr), + ni->ni_inact)); + nextbs = TAILQ_NEXT(ni, ni_list); + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_EXPIRE); + _ieee80211_free_node(ic, ni); + ni = nextbs; + } + if (!TAILQ_EMPTY(&ic->ic_node)) + ic->ic_inact_timer = IEEE80211_INACT_WAIT; + write_unlock(&ic->ic_nodelock); +} + +void +ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, void *arg) +{ + struct ieee80211_node *ni; + + read_lock_bh(&ic->ic_nodelock); + TAILQ_FOREACH(ni, &ic->ic_node, ni_list) + (*f)(arg, ni); + read_unlock_bh(&ic->ic_nodelock); +} + +/* + * Install received rate set information in the node's state block. + */ +static int +ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni, + u_int8_t *rates, u_int8_t *xrates, int flags) +{ + struct ieee80211_rateset *rs = &ni->ni_rates; + + memset(rs, 0, sizeof(*rs)); + rs->rs_nrates = rates[1]; + memcpy(rs->rs_rates, rates + 2, rs->rs_nrates); + if (xrates != NULL) { + u_int8_t nxrates; + /* + * Tack on 11g extended supported rate element. + */ + nxrates = xrates[1]; + if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) { + nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates; + DPRINTF(ic, ("%s: extended rate set too large;" + " only using %u of %u rates\n", + __func__, nxrates, xrates[1])); + } + memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates); + rs->rs_nrates += nxrates; + } + return ieee80211_fix_rate(ic, ni, flags); +} + +int +ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) +{ +#define RV(v) ((v) & IEEE80211_RATE_VAL) + int i, j, ignore, error; + int okrate, badrate; + struct ieee80211_rateset *srs, *nrs; + u_int8_t r; + + error = 0; + okrate = badrate = 0; + srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; + nrs = &ni->ni_rates; + for (i = 0; i < ni->ni_rates.rs_nrates; ) { + ignore = 0; + if (flags & IEEE80211_F_DOSORT) { + /* + * Sort rates. + */ + for (j = i + 1; j < nrs->rs_nrates; j++) { + if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { + r = nrs->rs_rates[i]; + nrs->rs_rates[i] = nrs->rs_rates[j]; + nrs->rs_rates[j] = r; + } + } + } + r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; + badrate = r; + if (flags & IEEE80211_F_DOFRATE) { + /* + * Apply fixed rate constraint. Note that we do + * not apply the constraint to basic rates as + * otherwise we may not be able to associate if + * the rate set we submit to the AP is invalid + * (e.g. fix rate at 36Mb/s which is not a basic + * rate for 11a operation). + */ + if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && + ic->ic_fixed_rate >= 0 && + r != RV(srs->rs_rates[ic->ic_fixed_rate])) + ignore++; + } + if (flags & IEEE80211_F_DONEGO) { + /* + * Check against supported rates. + */ + for (j = 0; j < srs->rs_nrates; j++) { + if (r == RV(srs->rs_rates[j])) + break; + } + if (j == srs->rs_nrates) { + if (nrs->rs_rates[i] & IEEE80211_RATE_BASIC) + error++; + ignore++; + } + } + if (flags & IEEE80211_F_DODEL) { + /* + * Delete unacceptable rates. + */ + if (ignore) { + nrs->rs_nrates--; + for (j = i; j < nrs->rs_nrates; j++) + nrs->rs_rates[j] = nrs->rs_rates[j + 1]; + nrs->rs_rates[j] = 0; + continue; + } + } + if (!ignore) + okrate = nrs->rs_rates[i]; + i++; + } + if (okrate == 0 || error != 0) + return badrate | IEEE80211_RATE_BASIC; + else + return RV(okrate); +#undef RV +} + +/* + * Add a supported rates element id to a frame. + */ +u_int8_t * +ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs) +{ + int nrates; + + *frm++ = IEEE80211_ELEMID_RATES; + nrates = rs->rs_nrates; + if (nrates > IEEE80211_RATE_SIZE) + nrates = IEEE80211_RATE_SIZE; + *frm++ = nrates; + memcpy(frm, rs->rs_rates, nrates); + return frm + nrates; +} + +/* + * Add an extended supported rates element id to a frame. + */ +u_int8_t * +ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs) +{ + /* + * Add an extended supported rates element if operating in 11g mode. + */ + if (rs->rs_nrates > IEEE80211_RATE_SIZE) { + int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; + *frm++ = IEEE80211_ELEMID_XRATES; + *frm++ = nrates; + memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); + frm += nrates; + } + return frm; +} + +/* + * Add an ssid elemet to a frame. + */ +static u_int8_t * +ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len) +{ + *frm++ = IEEE80211_ELEMID_SSID; + *frm++ = len; + memcpy(frm, ssid, len); + return frm + len; +} + +static int +ieee80211_send_prreq(struct ieee80211com *ic, struct ieee80211_node *ni, + int type, int dummy) +{ + int ret, pktlen; + struct sk_buff *skb; + u_int8_t *frm; + enum ieee80211_phymode mode; + + /* + * prreq frame format + * [tlv] ssid + * [tlv] supported rates + * [tlv] extended supported rates + */ + pktlen = 2 + ic->ic_des_esslen + + 2 + IEEE80211_RATE_SIZE + + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + ; + skb = dev_alloc_skb(sizeof(struct ieee80211_frame) + pktlen); + if (skb == NULL) { + DPRINTF(ic, ("ieee80211_send_prreq: no space\n")); + return ENOMEM; + } + skb_reserve(skb, sizeof(struct ieee80211_frame)); + + frm = skb_put(skb, pktlen); + frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen); + mode = ieee80211_chan2mode(ic, ni->ni_chan); + frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); + frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); + skb_trim(skb, frm - skb->data); + + ret = ieee80211_mgmt_output(&ic->ic_dev, ni, skb, type); + ic->ic_mgt_timer = IEEE80211_TRANS_WAIT; + return ret; +} + +static int +ieee80211_send_prresp(struct ieee80211com *ic, struct ieee80211_node *bs0, + int type, int dummy) +{ + struct sk_buff *skb; + u_int8_t *frm; + struct ieee80211_node *ni = &ic->ic_bss; + u_int16_t capinfo; + int pktlen; + + /* + * probe response frame format + * [8] time stamp + * [2] beacon interval + * [2] cabability information + * [tlv] ssid + * [tlv] supported rates + * [tlv] parameter set (IBSS) + * [tlv] extended supported rates + */ + pktlen = 8 + 2 + 2 + 2 + + 2 + ni->ni_esslen + + 2 + IEEE80211_RATE_SIZE + + 6 + + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + ; + skb = dev_alloc_skb(sizeof(struct ieee80211_frame) + pktlen); + if (skb == NULL) + return ENOMEM; + skb_reserve(skb, sizeof(struct ieee80211_frame)); + + frm = skb_put(skb, pktlen); + + memset(frm, 0, 8); /* NB: driver is required to fillin timestamp */ + frm += 8; + + *(u_int16_t *)frm = cpu_to_le16(ni->ni_intval); + frm += 2; + + if (ic->ic_opmode == IEEE80211_M_IBSS) + capinfo = IEEE80211_CAPINFO_IBSS; + else + capinfo = IEEE80211_CAPINFO_ESS; + if (ic->ic_flags & IEEE80211_F_WEPON) + capinfo |= IEEE80211_CAPINFO_PRIVACY; + *(u_int16_t *)frm = cpu_to_le16(capinfo); + frm += 2; + + frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); + frm = ieee80211_add_rates(frm, &ni->ni_rates); + + if (ic->ic_opmode == IEEE80211_M_IBSS) { + *frm++ = IEEE80211_ELEMID_IBSSPARMS; + *frm++ = 2; + *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ + } else { /* IEEE80211_M_HOSTAP */ + /* TODO: TIM */ + *frm++ = IEEE80211_ELEMID_TIM; + *frm++ = 4; /* length */ + *frm++ = 0; /* DTIM count */ + *frm++ = 1; /* DTIM period */ + *frm++ = 0; /* bitmap control */ + *frm++ = 0; /* Partial Virtual Bitmap (variable length) */ + } + frm = ieee80211_add_xrates(frm, &ni->ni_rates); + skb_trim(skb, frm - skb->data); + + return ieee80211_mgmt_output(&ic->ic_dev, bs0, skb, type); +} + +static int +ieee80211_send_auth(struct ieee80211com *ic, struct ieee80211_node *ni, + int type, int seq) +{ + struct sk_buff *skb; + u_int16_t *frm; + int ret, pktlen; + + pktlen = 3*sizeof(u_int16_t); + skb = dev_alloc_skb(sizeof(struct ieee80211_frame) + pktlen); + if (skb == NULL) + return ENOMEM; + skb_reserve(skb, sizeof(struct ieee80211_frame)); + + /* XXX alignment? */ + frm = (u_int16_t *) skb_put(skb, pktlen); + /* TODO: shared key auth */ + frm[0] = cpu_to_le16(IEEE80211_AUTH_ALG_OPEN); + frm[1] = cpu_to_le16(seq); + frm[2] = 0; /* status */ + ret = ieee80211_mgmt_output(&ic->ic_dev, ni, skb, type); + if (ic->ic_opmode == IEEE80211_M_STA) + ic->ic_mgt_timer = IEEE80211_TRANS_WAIT; + return ret; +} + +static int +ieee80211_send_deauth(struct ieee80211com *ic, struct ieee80211_node *ni, + int type, int reason) +{ + struct net_device *dev = &ic->ic_dev; + struct sk_buff *skb; + u_int16_t *frm; + int pktlen; + + DPRINTF(ic, ("%s: station %s deauthenticate (reason %d)\n", + dev->name, ether_sprintf(ni->ni_macaddr), reason)); + pktlen = sizeof(u_int16_t); + skb = dev_alloc_skb(sizeof(struct ieee80211_frame) + pktlen); + if (skb == NULL) + return ENOMEM; + skb_reserve(skb, sizeof(struct ieee80211_frame)); + + /* XXX alignment? */ + frm = (u_int16_t *) skb_put(skb, pktlen); + frm[0] = cpu_to_le16(reason); + + return ieee80211_mgmt_output(&ic->ic_dev, ni, skb, type); +} + +static int +ieee80211_send_asreq(struct ieee80211com *ic, struct ieee80211_node *ni, + int type, int dummy) +{ + struct sk_buff *skb; + u_int8_t *frm; + u_int16_t capinfo = 0; + int ret, pktlen; + + /* + * asreq frame format + * [2] capability information + * [2] listen interval + * [6*] current AP address (reassoc only) + * [tlv] ssid + * [tlv] supported rates + * [tlv] extended supported rates + */ + pktlen = sizeof(capinfo) + + sizeof(u_int16_t) + + IEEE80211_ADDR_LEN + + 2 + ni->ni_esslen + + 2 + IEEE80211_RATE_SIZE + + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + ; + skb = dev_alloc_skb(sizeof(struct ieee80211_frame) + pktlen); + if (skb == NULL) + return ENOMEM; + skb_reserve(skb, sizeof(struct ieee80211_frame)); + + frm = (u_int8_t *) skb_put(skb, pktlen); + + capinfo = 0; + if (ic->ic_opmode == IEEE80211_M_IBSS) + capinfo |= IEEE80211_CAPINFO_IBSS; + else /* IEEE80211_M_STA */ + capinfo |= IEEE80211_CAPINFO_ESS; + if (ic->ic_flags & IEEE80211_F_WEPON) + capinfo |= IEEE80211_CAPINFO_PRIVACY; + if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) + capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; + if (ic->ic_flags & IEEE80211_F_SHSLOT) + capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; + *(u_int16_t *)frm = cpu_to_le16(capinfo); + frm += 2; + + *(u_int16_t *)frm = cpu_to_le16(ic->ic_lintval); + frm += 2; + + if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { + IEEE80211_ADDR_COPY(frm, ic->ic_bss.ni_bssid); + frm += IEEE80211_ADDR_LEN; + } + + frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); + frm = ieee80211_add_rates(frm, &ni->ni_rates); + frm = ieee80211_add_xrates(frm, &ni->ni_rates); + skb_trim(skb, frm - skb->data); + + ret = ieee80211_mgmt_output(&ic->ic_dev, ni, skb, type); + ic->ic_mgt_timer = IEEE80211_TRANS_WAIT; + return ret; +} + +static int +ieee80211_send_asresp(struct ieee80211com *ic, struct ieee80211_node *ni, + int type, int status) +{ + struct sk_buff *skb; + u_int8_t *frm; + u_int16_t capinfo; + int pktlen; + + /* + * asreq frame format + * [2] capability information + * [2] status + * [2] association ID + * [tlv] supported rates + * [tlv] extended supported rates + */ + pktlen = sizeof(capinfo) + + sizeof(u_int16_t) + + sizeof(u_int16_t) + + 2 + IEEE80211_RATE_SIZE + + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) + ; + skb = dev_alloc_skb(sizeof(struct ieee80211_frame) + pktlen); + if (skb == NULL) + return ENOMEM; + skb_reserve(skb, sizeof(struct ieee80211_frame)); + + frm = (u_int8_t *) skb_put(skb, pktlen); + + capinfo = IEEE80211_CAPINFO_ESS; + if (ic->ic_flags & IEEE80211_F_WEPON) + capinfo |= IEEE80211_CAPINFO_PRIVACY; + *(u_int16_t *)frm = cpu_to_le16(capinfo); + frm += 2; + + *(u_int16_t *)frm = cpu_to_le16(status); + frm += 2; + + if (status == IEEE80211_STATUS_SUCCESS && ni != NULL) + *(u_int16_t *)frm = cpu_to_le16(ni->ni_associd); + else + *(u_int16_t *)frm = cpu_to_le16(0); + frm += 2; + + if (ni != NULL) { + frm = ieee80211_add_rates(frm, &ni->ni_rates); + frm = ieee80211_add_xrates(frm, &ni->ni_rates); + } else { + frm = ieee80211_add_rates(frm, &ic->ic_bss.ni_rates); + frm = ieee80211_add_xrates(frm, &ic->ic_bss.ni_rates); + } + skb_trim(skb, frm - skb->data); + + return ieee80211_mgmt_output(&ic->ic_dev, ni, skb, type); +} + +static int +ieee80211_send_disassoc(struct ieee80211com *ic, struct ieee80211_node *ni, + int type, int reason) +{ + struct net_device *dev = &ic->ic_dev; + struct sk_buff *skb; + u_int16_t *frm; + int pktlen; + + DPRINTF(ic, ("%s: station %s disassociate (reason %d)\n", + dev->name, ether_sprintf(ni->ni_macaddr), reason)); + pktlen = sizeof(u_int16_t); + skb = dev_alloc_skb(sizeof(struct ieee80211_frame) + pktlen); + if (skb == NULL) + return ENOMEM; + skb_reserve(skb, sizeof(struct ieee80211_frame)); + + /* XXX alignment? */ + frm = (u_int16_t *) skb_put(skb, pktlen); + frm[0] = cpu_to_le16(reason); + + return ieee80211_mgmt_output(&ic->ic_dev, ni, skb, + IEEE80211_FC0_SUBTYPE_DISASSOC); +} + +/* Verify the existence and length of __elem or get out. */ +#define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen, __wh) do { \ + if ((__elem) == NULL) { \ + DPRINTF(ic, ("%s: no " #__elem "\n", __func__)); \ + return; \ + } \ + if ((__elem)[1] > (__maxlen)) { \ + DPRINTF(ic, ("%s: bad " #__elem " len %d from %s\n", \ + __func__, (__elem)[1], \ + ether_sprintf((__wh)->i_addr2))); \ + return; \ + } \ +} while (0) + +/* + * NB: This handles both beacon and probe response frames. + */ +static void +ieee80211_recv_beacon(struct ieee80211com *ic, struct sk_buff *skb0, int rssi, + u_int32_t rstamp, u_int rantenna) +{ +#define ISPROBE(_wh) IEEE80211_IS_SUBTYPE((_wh)->i_fc[0], PROBE_RESP) + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + u_int8_t *frm, *efrm, *tstamp, *bintval, *capinfo, *ssid; + u_int8_t *rates, *xrates, *country; + u_int8_t chan, bchan, fhindex, erp; + u_int16_t fhdwell; + + if (ic->ic_opmode != IEEE80211_M_IBSS && + ic->ic_state != IEEE80211_S_SCAN) { + /* XXX: may be useful for background scan */ + return; + } + + wh = (struct ieee80211_frame *) skb0->data; + frm = (u_int8_t *)&wh[1]; + efrm = skb0->data + skb0->len; + /* + * beacon frame format + * [8] time stamp + * [2] beacon interval + * [2] cabability information + * [tlv] ssid + * [tlv] supported rates + * [tlv] country information + * [tlv] parameter set (FH/DS) + * [tlv] erp information + * [tlv] extended supported rates + */ + tstamp = frm; frm += 8; + bintval = frm; frm += 2; + capinfo = frm; frm += 2; + ssid = rates = xrates = country = NULL; + bchan = ieee80211_chan2ieee(ic, ic->ic_bss.ni_chan); + chan = bchan; + fhdwell = 0; + fhindex = 0; + erp = 0; + while (frm < efrm) { + switch (*frm) { + case IEEE80211_ELEMID_SSID: + ssid = frm; + break; + case IEEE80211_ELEMID_RATES: + rates = frm; + break; + case IEEE80211_ELEMID_COUNTRY: + country = frm; + break; + case IEEE80211_ELEMID_FHPARMS: + if (ic->ic_phytype == IEEE80211_T_FH) { + fhdwell = (frm[3] << 8) | frm[2]; + chan = IEEE80211_FH_CHAN(frm[4], frm[5]); + fhindex = frm[6]; + } + break; + case IEEE80211_ELEMID_DSPARMS: + /* + * XXX hack this since depending on phytype + * is problematic for multi-mode devices. + */ + if (ic->ic_phytype != IEEE80211_T_FH) + chan = frm[2]; + break; + case IEEE80211_ELEMID_TIM: + break; + case IEEE80211_ELEMID_XRATES: + xrates = frm; + break; + case IEEE80211_ELEMID_ERP: + if (frm[1] != 1) { + DPRINTF(ic, ("%s: invalid ERP element; " + "length %u, expecting 1\n", + __func__, frm[1])); + break; + } + erp = frm[2]; + break; + default: + DPRINTF(ic, ("%s: element id %u/len %u ignored\n", + __func__, *frm, frm[1])); + break; + } + frm += frm[1] + 2; + } + IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_SIZE, wh); + IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, wh); + if (chan > IEEE80211_CHAN_MAX || isclr(ic->ic_chan_active, chan)) { + DPRINTF(ic, ("%s: ignore %s with invalid channel %u\n", + __func__, ISPROBE(wh) ? "probe response" : "beacon", + chan)); + return; + } + if (chan != bchan) { + /* + * Frame was received on a channel different from the + * one indicated in the DS/FH params element id; silently + * discard it. + * + * NB: this can happen due to signal leakage. + */ + DPRINTF(ic, ("%s: ignore %s on channel %u marked for channel %u\n", + __func__, ISPROBE(wh) ? "probe response" : "beacon", + bchan, chan)); + /* XXX statistic */ + return; + } + + /* + * Use mac and channel for lookup so we collect all + * potential AP's when scanning. Otherwise we may + * see the same AP on multiple channels and will only + * record the last one. We could filter APs here based + * on rssi, etc. but leave that to the end of the scan + * so we can keep the selection criteria in one spot. + * This may result in a bloat of the scanned AP list but + * it shouldn't be too much. + */ + ni = ieee80211_lookup_node(ic, wh->i_addr2, &ic->ic_channels[chan]); +#ifdef IEEE80211_DEBUG + if (netif_msg_debug(ic) && + (ni == NULL || ic->ic_state == IEEE80211_S_SCAN)) { + printk("%s: %s%s on chan %u (bss chan %u) ", + __func__, (ni == NULL ? "new " : ""), + ISPROBE(wh) ? "probe response" : "beacon", + chan, bchan); + ieee80211_print_essid(ssid + 2, ssid[1]); + printk(" from %s\n", ether_sprintf(wh->i_addr2)); + printk("%s: caps 0x%x bintval %u erp 0x%x\n", + __func__, le16_to_cpu(*(u_int16_t *)capinfo), + le16_to_cpu(*(u_int16_t *)bintval), erp); +#if 0 + if (country) + printk("%s: country info %*D\n", + __func__, country[1], country+2, " "); +#endif + } +#endif + if (ni == NULL) { + ni = ieee80211_alloc_node(ic, wh->i_addr2); + if (ni == NULL) + return; + ni->ni_esslen = ssid[1]; + memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); + memcpy(ni->ni_essid, ssid + 2, ssid[1]); + } else if (ssid[1] != 0 && ISPROBE(wh)) { + /* + * Update ESSID at probe response to adopt hidden AP by + * Lucent/Cisco, which announces null ESSID in beacon. + */ + ni->ni_esslen = ssid[1]; + memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); + memcpy(ni->ni_essid, ssid + 2, ssid[1]); + } + IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + ni->ni_rantenna = rantenna; + memcpy(ni->ni_tstamp, tstamp, sizeof(ni->ni_tstamp)); + ni->ni_intval = le16_to_cpu(*(u_int16_t *)bintval); + ni->ni_capinfo = le16_to_cpu(*(u_int16_t *)capinfo); + ni->ni_chan = &ic->ic_channels[chan]; + ni->ni_fhdwell = fhdwell; + ni->ni_fhindex = fhindex; + ni->ni_erp = erp; + /* NB: must be after ni_chan is setup */ + ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT); + ieee80211_unref_node(&ni); +#undef ISPROBE +} + +static void +ieee80211_recv_prreq(struct ieee80211com *ic, struct sk_buff *skb0, int rssi, + u_int32_t rstamp, u_int rantenna) +{ + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + u_int8_t *frm, *efrm, *ssid, *rates, *xrates; + u_int8_t rate; + int allocbs; + + if (ic->ic_opmode == IEEE80211_M_STA) + return; + if (ic->ic_state != IEEE80211_S_RUN) + return; + + wh = (struct ieee80211_frame *) skb0->data; + frm = (u_int8_t *)&wh[1]; + efrm = skb0->data + skb0->len; + /* + * prreq frame format + * [tlv] ssid + * [tlv] supported rates + * [tlv] extended supported rates + */ + ssid = rates = xrates = NULL; + while (frm < efrm) { + switch (*frm) { + case IEEE80211_ELEMID_SSID: + ssid = frm; + break; + case IEEE80211_ELEMID_RATES: + rates = frm; + break; + case IEEE80211_ELEMID_XRATES: + xrates = frm; + break; + } + frm += frm[1] + 2; + } + IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_SIZE, wh); + IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, wh); + if (ssid[1] != 0 && + (ssid[1] != ic->ic_bss.ni_esslen || + memcmp(ssid + 2, ic->ic_bss.ni_essid, ic->ic_bss.ni_esslen) != 0)) { + if (netif_msg_debug(ic)) { + printk("%s: ssid unmatch ", __func__); + ieee80211_print_essid(ssid + 2, ssid[1]); + printk(" from %s\n", ether_sprintf(wh->i_addr2)); + } + return; + } + + ni = ieee80211_find_node(ic, wh->i_addr2); + if (ni == NULL) { + ni = ieee80211_dup_bss(ic, wh->i_addr2); + if (ni == NULL) + return; + DPRINTF(ic, ("%s: new req from %s\n", + __func__, ether_sprintf(wh->i_addr2))); + allocbs = 1; + } else + allocbs = 0; + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + ni->ni_rantenna = rantenna; + rate = ieee80211_setup_rates(ic, ni, rates, xrates, + IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE + | IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + if (rate & IEEE80211_RATE_BASIC) { + DPRINTF(ic, ("%s: rate negotiation failed: %s\n", + __func__, ether_sprintf(wh->i_addr2))); + } else { + IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP, + 0); + } + if (allocbs && ic->ic_opmode == IEEE80211_M_HOSTAP) + ieee80211_free_node(ic, ni); + else + ieee80211_unref_node(&ni); +} + +static void +ieee80211_recv_auth(struct ieee80211com *ic, struct sk_buff *skb0, int rssi, + u_int32_t rstamp, u_int rantenna) +{ + struct net_device *dev = &ic->ic_dev; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + u_int8_t *frm, *efrm; + u_int16_t algo, seq, status; + int allocbs; + + wh = (struct ieee80211_frame *) skb0->data; + frm = (u_int8_t *)&wh[1]; + efrm = skb0->data + skb0->len; + /* + * auth frame format + * [2] algorithm + * [2] sequence + * [2] status + * [tlv*] challenge + */ + if (frm + 6 > efrm) { + DPRINTF(ic, ("%s: too short from %s\n", + __func__, ether_sprintf(wh->i_addr2))); + return; + } + algo = le16_to_cpu(*(u_int16_t *)frm); + seq = le16_to_cpu(*(u_int16_t *)(frm + 2)); + status = le16_to_cpu(*(u_int16_t *)(frm + 4)); + if (algo != IEEE80211_AUTH_ALG_OPEN) { + /* TODO: shared key auth */ + DPRINTF(ic, ("%s: unsupported auth %d from %s\n", + __func__, algo, ether_sprintf(wh->i_addr2))); + return; + } + switch (ic->ic_opmode) { + case IEEE80211_M_IBSS: + if (ic->ic_state != IEEE80211_S_RUN || seq != 1) + return; + ieee80211_new_state(&ic->ic_dev, IEEE80211_S_AUTH, + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + break; + + case IEEE80211_M_AHDEMO: + /* should not come here */ + break; + + case IEEE80211_M_HOSTAP: + if (ic->ic_state != IEEE80211_S_RUN || seq != 1) + return; + allocbs = 0; + ni = ieee80211_find_node(ic, wh->i_addr2); + if (ni == NULL) { + ni = ieee80211_alloc_node(ic, wh->i_addr2); + if (ni == NULL) + return; + IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss.ni_bssid); + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + ni->ni_rantenna = rantenna; + ni->ni_chan = ic->ic_bss.ni_chan; + allocbs = 1; + } + IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 2); + DPRINTF(ic, ("%s: station %s %s authenticated\n", + dev->name, + (allocbs ? "newly" : "already"), + ether_sprintf(ni->ni_macaddr))); + ieee80211_unref_node(&ni); + break; + + case IEEE80211_M_STA: + if (ic->ic_state != IEEE80211_S_AUTH || seq != 2) + return; + if (status != 0) { + printk("%s: authentication failed (reason %d) for %s\n", + dev->name, status, + ether_sprintf(wh->i_addr3)); + ni = ieee80211_find_node(ic, wh->i_addr2); + if (ni != NULL) { + ni->ni_fails++; + ieee80211_unref_node(&ni); + } + return; + } + ieee80211_new_state(&ic->ic_dev, IEEE80211_S_ASSOC, + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + break; + } +} + +static void +ieee80211_recv_asreq(struct ieee80211com *ic, struct sk_buff *skb0, int rssi, + u_int32_t rstamp, u_int rantenna) +{ + struct net_device *dev = &ic->ic_dev; + struct ieee80211_frame *wh; + struct ieee80211_node *ni = &ic->ic_bss; + u_int8_t *frm, *efrm, *ssid, *rates, *xrates; + u_int16_t capinfo, bintval; + int reassoc, resp, newassoc; + + if (ic->ic_opmode != IEEE80211_M_HOSTAP || + (ic->ic_state != IEEE80211_S_RUN)) + return; + + wh = (struct ieee80211_frame *) skb0->data; + frm = (u_int8_t *)&wh[1]; + efrm = skb0->data + skb0->len; + if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == + IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { + reassoc = 1; + resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP; + } else { + reassoc = 0; + resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP; + } + /* + * asreq frame format + * [2] capability information + * [2] listen interval + * [6*] current AP address (reassoc only) + * [tlv] ssid + * [tlv] supported rates + * [tlv] extended supported rates + */ + if (frm + (reassoc ? 10 : 4) > efrm) { + DPRINTF(ic, ("%s: too short from %s\n", + __func__, ether_sprintf(wh->i_addr2))); + return; + } + + if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss.ni_bssid)) { + DPRINTF(ic, ("%s: ignore other bss from %s\n", + __func__, ether_sprintf(wh->i_addr2))); + return; + } + capinfo = le16_to_cpu(*(u_int16_t *)frm); frm += 2; + bintval = le16_to_cpu(*(u_int16_t *)frm); frm += 2; + if (reassoc) + frm += 6; /* ignore current AP info */ + ssid = rates = xrates = NULL; + while (frm < efrm) { + switch (*frm) { + case IEEE80211_ELEMID_SSID: + ssid = frm; + break; + case IEEE80211_ELEMID_RATES: + rates = frm; + break; + case IEEE80211_ELEMID_XRATES: + xrates = frm; + break; + } + frm += frm[1] + 2; + } + IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_SIZE, wh); + IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, wh); + if (ssid[1] != ic->ic_bss.ni_esslen || + memcmp(ssid + 2, ic->ic_bss.ni_essid, ssid[1]) != 0) { + if (netif_msg_debug(ic)) { + printk("%s: ssid unmatch ", __func__); + ieee80211_print_essid(ssid + 2, ssid[1]); + printk(" from %s\n", ether_sprintf(wh->i_addr2)); + } + return; + } + ni = ieee80211_find_node(ic, wh->i_addr2); + if (ni == NULL) { + DPRINTF(ic, ("%s: not authenticated for %s\n", + __func__, ether_sprintf(wh->i_addr2))); + ni = ieee80211_dup_bss(ic, wh->i_addr2); + if (ni == NULL) + return; + IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_ASSOC_NOT_AUTHED); + ieee80211_free_node(ic, ni); + return; + } + /* XXX per-node cipher suite */ + /* XXX some stations use the privacy bit for handling APs + that suport both encrypted and unencrypted traffic */ + if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 || + (capinfo & IEEE80211_CAPINFO_PRIVACY) != + ((ic->ic_flags & IEEE80211_F_WEPON) ? + IEEE80211_CAPINFO_PRIVACY : 0)) { + DPRINTF(ic, ("%s: capability unmatch %x for %s\n", + __func__, capinfo, ether_sprintf(wh->i_addr2))); + ni->ni_associd = 0; + IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_CAPINFO); + ieee80211_unref_node(&ni); + return; + } + ieee80211_setup_rates(ic, ni, rates, xrates, + IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | + IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + if (ni->ni_rates.rs_nrates == 0) { + DPRINTF(ic, ("%s: rate unmatch for %s\n", + __func__, ether_sprintf(wh->i_addr2))); + ni->ni_associd = 0; + IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_BASIC_RATE); + ieee80211_unref_node(&ni); + return; + } + ni->ni_rssi = rssi; + ni->ni_rstamp = rstamp; + ni->ni_rantenna = rantenna; + ni->ni_intval = bintval; + ni->ni_capinfo = capinfo; + ni->ni_chan = ic->ic_bss.ni_chan; + ni->ni_fhdwell = ic->ic_bss.ni_fhdwell; + ni->ni_fhindex = ic->ic_bss.ni_fhindex; + if (ni->ni_associd == 0) { + ni->ni_associd = 0xc000 | ic->ic_bss.ni_associd++; + newassoc = 1; + } else + newassoc = 0; + /* XXX for 11g must turn off short slot time if long + slot time sta associates */ + IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS); + DPRINTF(ic, ("%s: station %s %s associated\n", + dev->name, + (newassoc ? "newly" : "already"), + ether_sprintf(ni->ni_macaddr))); + ieee80211_unref_node(&ni); +} + +static void +ieee80211_recv_asresp(struct ieee80211com *ic, struct sk_buff *skb0, int rssi, + u_int32_t rstamp, u_int rantenna) +{ + struct net_device *dev = &ic->ic_dev; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + u_int8_t *frm, *efrm, *rates, *xrates; + int status; + + if (ic->ic_opmode != IEEE80211_M_STA || + ic->ic_state != IEEE80211_S_ASSOC) + return; + + wh = (struct ieee80211_frame *) skb0->data; + frm = (u_int8_t *)&wh[1]; + efrm = skb0->data + skb0->len; + /* + * asresp frame format + * [2] capability information + * [2] status + * [2] association ID + * [tlv] supported rates + * [tlv] extended supported rates + */ + if (frm + 6 > efrm) { + DPRINTF(ic, ("%s: too short from %s\n", + __func__, ether_sprintf(wh->i_addr2))); + return; + } + + ni = &ic->ic_bss; + ni->ni_capinfo = le16_to_cpu(*(u_int16_t *)frm); + frm += 2; + + status = le16_to_cpu(*(u_int16_t *)frm); + frm += 2; + if (status != 0) { + printk("%s: association failed (reason %d) for %s\n", + dev->name, status, ether_sprintf(wh->i_addr3)); + ni = ieee80211_find_node(ic, wh->i_addr2); + if (ni != NULL) { + ni->ni_fails++; + ieee80211_unref_node(&ni); + } + return; + } + ni->ni_associd = le16_to_cpu(*(u_int16_t *)frm); + frm += 2; + + rates = xrates = NULL; + while (frm < efrm) { + switch (*frm) { + case IEEE80211_ELEMID_RATES: + rates = frm; + break; + case IEEE80211_ELEMID_XRATES: + xrates = frm; + break; + } + frm += frm[1] + 2; + } + + IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_SIZE, wh); + ieee80211_setup_rates(ic, ni, rates, xrates, + IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE | + IEEE80211_F_DONEGO | IEEE80211_F_DODEL); + if (ni->ni_rates.rs_nrates != 0) + ieee80211_new_state(&ic->ic_dev, IEEE80211_S_RUN, + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); +} + +static void +ieee80211_recv_disassoc(struct ieee80211com *ic, struct sk_buff *skb0, int rssi, + u_int32_t rstamp, u_int rantenna) +{ + struct net_device *dev = &ic->ic_dev; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + u_int8_t *frm, *efrm; + u_int16_t reason; + + wh = (struct ieee80211_frame *) skb0->data; + frm = (u_int8_t *)&wh[1]; + efrm = skb0->data + skb0->len; + /* + * disassoc frame format + * [2] reason + */ + if (frm + 2 > efrm) { + DPRINTF(ic, ("%s: too short from %s\n", + __func__, ether_sprintf(wh->i_addr2))); + return; + } + reason = le16_to_cpu(*(u_int16_t *)frm); + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + ieee80211_new_state(&ic->ic_dev, IEEE80211_S_ASSOC, + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + break; + case IEEE80211_M_HOSTAP: + if ((ni = ieee80211_find_node(ic, wh->i_addr2)) != NULL) { + DPRINTF(ic, ("%s: station %s disassociated" + " by peer (reason %d)\n", + dev->name, + ether_sprintf(ni->ni_macaddr), reason)); + ni->ni_associd = 0; + ieee80211_unref_node(&ni); + } + break; + default: + break; + } +} + +static void +ieee80211_recv_deauth(struct ieee80211com *ic, struct sk_buff *skb0, int rssi, + u_int32_t rstamp, u_int rantenna) +{ + struct net_device *dev = &ic->ic_dev; + struct ieee80211_frame *wh; + struct ieee80211_node *ni; + u_int8_t *frm, *efrm; + u_int16_t reason; + + wh = (struct ieee80211_frame *) skb0->data; + frm = (u_int8_t *)&wh[1]; + efrm = skb0->data + skb0->len; + /* + * dauth frame format + * [2] reason + */ + if (frm + 2 > efrm) { + DPRINTF(ic, ("%s: too short from %s\n", + __func__, ether_sprintf(wh->i_addr2))); + return; + } + reason = le16_to_cpu(*(u_int16_t *)frm); + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + ieee80211_new_state(&ic->ic_dev, IEEE80211_S_AUTH, + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + break; + case IEEE80211_M_HOSTAP: + if ((ni = ieee80211_find_node(ic, wh->i_addr2)) != NULL) { + DPRINTF(ic, ("%s: station %s deauthenticated" + " by peer (reason %d)\n", + dev->name, + ether_sprintf(ni->ni_macaddr), reason)); + ieee80211_free_node(ic, ni); + } + break; + default: + break; + } +} + +int +ieee80211_new_state(struct net_device *dev, enum ieee80211_state nstate, int mgt) +{ + struct ieee80211com *ic = (void *)dev; + struct ieee80211_node *ni; + int error, ostate; +#ifdef IEEE80211_DEBUG + static const char *stname[] = + { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; +#endif + + ostate = ic->ic_state; + DPRINTF(ic, ("%s: %s -> %s\n", + __func__, stname[ostate], stname[nstate])); + if (ic->ic_newstate) { + error = (*ic->ic_newstate)(dev, nstate); + if (error == EINPROGRESS) + return 0; + if (error != 0) + return error; + } + + /* state transition */ + ic->ic_state = nstate; + ni = &ic->ic_bss; /* NB: no reference held */ + switch (nstate) { + case IEEE80211_S_INIT: + switch (ostate) { + case IEEE80211_S_INIT: + break; + case IEEE80211_S_RUN: + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DISASSOC, + IEEE80211_REASON_ASSOC_LEAVE); + break; + case IEEE80211_M_HOSTAP: + read_lock_bh(&ic->ic_nodelock); + TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { + if (ni->ni_associd == 0) + continue; + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DISASSOC, + IEEE80211_REASON_ASSOC_LEAVE); + } + read_unlock_bh(&ic->ic_nodelock); + break; + default: + break; + } + /* FALLTHRU */ + case IEEE80211_S_ASSOC: + switch (ic->ic_opmode) { + case IEEE80211_M_STA: + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE); + break; + case IEEE80211_M_HOSTAP: + read_lock_bh(&ic->ic_nodelock); + TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_AUTH_LEAVE); + } + read_unlock_bh(&ic->ic_nodelock); + break; + default: + break; + } + /* FALLTHRU */ + case IEEE80211_S_AUTH: + case IEEE80211_S_SCAN: + ic->ic_mgt_timer = 0; + if (ic->ic_wep_ctx != NULL) { + kfree(ic->ic_wep_ctx); + ic->ic_wep_ctx = NULL; + } + ieee80211_free_allnodes(ic); + break; + } + break; + case IEEE80211_S_SCAN: + ic->ic_flags &= ~IEEE80211_F_SIBSS; + /* initialize bss for probe request */ + IEEE80211_ADDR_COPY(ni->ni_macaddr, dev->broadcast); + IEEE80211_ADDR_COPY(ni->ni_bssid, dev->broadcast); + ni->ni_rates = ic->ic_sup_rates[ + ieee80211_chan2mode(ic, ni->ni_chan)]; + ni->ni_associd = 0; + ni->ni_rstamp = 0; + switch (ostate) { + case IEEE80211_S_INIT: + if (ic->ic_opmode == IEEE80211_M_HOSTAP && + ic->ic_des_chan != IEEE80211_CHAN_ANYC) { + /* + * AP operation and we already have a channel; + * bypass the scan and startup immediately. + */ + ieee80211_create_ibss(dev, ic->ic_des_chan); + } else { + ieee80211_begin_scan(dev, ni); + } + break; + case IEEE80211_S_SCAN: + /* scan next */ + if (ic->ic_flags & IEEE80211_F_ASCAN) { + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); + } + break; + case IEEE80211_S_RUN: + /* beacon miss */ + /* XXX bssid clobbered above */ + DPRINTF(ic, ("%s: no recent beacons from %s;" + " rescanning\n", + dev->name, + ether_sprintf(ic->ic_bss.ni_bssid))); + ieee80211_free_allnodes(ic); + /* FALLTHRU */ + case IEEE80211_S_AUTH: + case IEEE80211_S_ASSOC: + /* timeout restart scan */ + ni = ieee80211_find_node(ic, ic->ic_bss.ni_macaddr); + if (ni != NULL) { + ni->ni_fails++; + ieee80211_unref_node(&ni); + } + ieee80211_begin_scan(dev, &ic->ic_bss); + break; + } + break; + case IEEE80211_S_AUTH: + switch (ostate) { + case IEEE80211_S_INIT: + DPRINTF(ic, ("%s: invalid transition\n", __func__)); + break; + case IEEE80211_S_SCAN: + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_AUTH, 1); + break; + case IEEE80211_S_AUTH: + case IEEE80211_S_ASSOC: + switch (mgt) { + case IEEE80211_FC0_SUBTYPE_AUTH: + /* ??? */ + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_AUTH, 2); + break; + case IEEE80211_FC0_SUBTYPE_DEAUTH: + /* ignore and retry scan on timeout */ + break; + } + break; + case IEEE80211_S_RUN: + switch (mgt) { + case IEEE80211_FC0_SUBTYPE_AUTH: + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_AUTH, 2); + ic->ic_state = ostate; /* stay RUN */ + break; + case IEEE80211_FC0_SUBTYPE_DEAUTH: + /* try to reauth */ + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_AUTH, 1); + break; + } + break; + } + break; + case IEEE80211_S_ASSOC: + switch (ostate) { + case IEEE80211_S_INIT: + case IEEE80211_S_SCAN: + case IEEE80211_S_ASSOC: + DPRINTF(ic, ("%s: invalid transition\n", __func__)); + break; + case IEEE80211_S_AUTH: + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); + break; + case IEEE80211_S_RUN: + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); + break; + } + break; + case IEEE80211_S_RUN: + switch (ostate) { + case IEEE80211_S_INIT: + case IEEE80211_S_AUTH: + case IEEE80211_S_RUN: + DPRINTF(ic, ("%s: invalid transition\n", __func__)); + break; + case IEEE80211_S_SCAN: /* adhoc/hostap mode */ + case IEEE80211_S_ASSOC: /* infra mode */ + KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, + ("%s: bogus xmit rate %u setup\n", __func__, + ni->ni_txrate)); + if (netif_msg_debug(ic)) { + printk("%s: ", dev->name); + if (ic->ic_opmode == IEEE80211_M_STA) + printk("associated "); + else + printk("synchronized "); + printk("with %s ssid ", + ether_sprintf(ni->ni_bssid)); + ieee80211_print_essid(ni->ni_essid, + ni->ni_esslen); + printk(" channel %d start %uMb\n", + ieee80211_chan2ieee(ic, ni->ni_chan), + IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); + } + ic->ic_mgt_timer = 0; + break; + } + break; + } + return 0; +} + +struct sk_buff * +ieee80211_wep_crypt(struct net_device *dev, struct sk_buff *skb0, int txflag) +{ + struct ieee80211com *ic = (void *)dev; + struct sk_buff *skb, *n, *n0; + struct ieee80211_frame *wh; + int i, left, len, moff, noff, kid; + u_int32_t iv, crc; + u_int8_t *ivp; + void *ctx; + u_int8_t keybuf[IEEE80211_WEP_IVLEN + IEEE80211_KEYBUF_SIZE]; + u_int8_t crcbuf[IEEE80211_WEP_CRCLEN]; + + n0 = NULL; + if ((ctx = ic->ic_wep_ctx) == NULL) { + ctx = kmalloc(arc4_ctxlen(), GFP_KERNEL); + if (ctx == NULL) + goto fail; + ic->ic_wep_ctx = ctx; + } + skb = skb0; + left = skb->len; + len = IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; + if (txflag) { + n = dev_alloc_skb(skb->len + len); + } else { + n = dev_alloc_skb(skb->len - len); + left -= len; + } + if (n == NULL) + goto fail; + n0 = n; + memcpy(n->data, skb->data, sizeof(struct ieee80211_frame)); + wh = (struct ieee80211_frame *) n->data; + left -= sizeof(struct ieee80211_frame); + moff = sizeof(struct ieee80211_frame); + noff = sizeof(struct ieee80211_frame); + if (txflag) { + kid = ic->ic_wep_txkey; + wh->i_fc[1] |= IEEE80211_FC1_WEP; + iv = ic->ic_iv; + /* + * Skip 'bad' IVs from Fluhrer/Mantin/Shamir: + * (B, 255, N) with 3 <= B < 8 + */ + if (iv >= 0x03ff00 && + (iv & 0xf8ff00) == 0x00ff00) + iv += 0x000100; + ic->ic_iv = iv + 1; + /* put iv in little endian to prepare 802.11i */ + ivp = n->data + noff; + for (i = 0; i < IEEE80211_WEP_IVLEN; i++) { + ivp[i] = iv & 0xff; + iv >>= 8; + } + ivp[IEEE80211_WEP_IVLEN] = kid << 6; /* pad and keyid */ + noff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; + } else { + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + ivp = skb->data + moff; + kid = ivp[IEEE80211_WEP_IVLEN] >> 6; + moff += IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN; + } + memcpy(keybuf, ivp, IEEE80211_WEP_IVLEN); + memcpy(keybuf + IEEE80211_WEP_IVLEN, ic->ic_nw_keys[kid].wk_key, + ic->ic_nw_keys[kid].wk_len); + arc4_setkey(ctx, keybuf, + IEEE80211_WEP_IVLEN + ic->ic_nw_keys[kid].wk_len); + + /* encrypt with calculating CRC */ + crc = ~0; + arc4_encrypt(ctx, n->data + noff, skb->data + moff, left); + if (txflag) { + crc = ieee80211_crc_update(crc, skb->data + moff, left); + moff += left; + } else { + crc = ieee80211_crc_update(crc, n->data + noff, left); + noff += left; + } + crc = ~crc; + if (txflag) { + *(u_int32_t *)crcbuf = cpu_to_le32(crc); + arc4_encrypt(ctx, n->data + noff, crcbuf, sizeof(crcbuf)); + } else { + arc4_encrypt(ctx, crcbuf, skb->data + moff, sizeof(crcbuf)); + if (crc != le32_to_cpu(*(u_int32_t *)crcbuf)) { + if (netif_msg_debug(ic)) { + printk("%s: decrypt CRC error\n", dev->name); + if (ieee80211_debug > 1) + ieee80211_dump_pkt(n0->data, + n0->len, -1, -1); + } + goto fail; + } + } + dev_kfree_skb(skb0); + return n0; + + fail: + dev_kfree_skb(skb0); + dev_kfree_skb(n0); + return NULL; +} + +/* + * Return netdevice statistics. + */ +static struct net_device_stats * +ieee80211_getstats(struct net_device *dev) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + return &ic->ic_stats; +} + +#ifdef CONFIG_PROC_FS +#include +#include + +static int +ieee80211_proc_debug_read(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + if (off != 0) { + *eof = 1; + return 0; + } + return sprintf(page, "%d\n", ieee80211_debug); +} + +static int +ieee80211_proc_debug_write(struct file *file, const char *buf, + unsigned long count, void *data) +{ + struct ieee80211com *ic = data; + int v; + + if (sscanf(buf, "%d", &v) == 1) { + if (v) + ic->msg_enable |= NETIF_MSG_DEBUG; + else + ic->msg_enable &= ~NETIF_MSG_DEBUG; + ieee80211_debug = v; + return count; + } else + return -EINVAL; +} + +static void +ieee80211_proc_init(struct ieee80211com *ic) +{ + struct proc_dir_entry *dp; + const char *cp; + + for (cp = ic->ic_dev.name; *cp && !isdigit(*cp); cp++) + ; + snprintf(ic->ic_procname, sizeof(ic->ic_procname), "wlan%s", cp); + ic->ic_proc = proc_mkdir(ic->ic_procname, proc_net); + if (ic->ic_proc == NULL) { + printk(KERN_INFO "/proc/net/%s: failed to create\n", + ic->ic_procname); + return; + } + dp = create_proc_entry("debug", 0644, ic->ic_proc); + if (dp) { + dp->read_proc = ieee80211_proc_debug_read; + dp->write_proc = ieee80211_proc_debug_write; + dp->data = ic; + } +} + +static void +ieee80211_proc_remove(struct ieee80211com *ic) +{ + if (ic->ic_proc != NULL) { + remove_proc_entry("debug", ic->ic_proc); + remove_proc_entry(ic->ic_procname, proc_net); + ic->ic_proc = NULL; + } +} +#endif /* CONFIG_PROC_FS */ + +/* + * CRC 32 -- routine from RFC 2083 + */ + +/* Table of CRCs of all 8-bit messages */ +static u_int32_t ieee80211_crc_table[256]; + +/* Make the table for a fast CRC. */ +static void +ieee80211_crc_init(void) +{ + u_int32_t c; + int n, k; + + for (n = 0; n < 256; n++) { + c = (u_int32_t)n; + for (k = 0; k < 8; k++) { + if (c & 1) + c = 0xedb88320UL ^ (c >> 1); + else + c = c >> 1; + } + ieee80211_crc_table[n] = c; + } +} + +/* + * Update a running CRC with the bytes buf[0..len-1]--the CRC + * should be initialized to all 1's, and the transmitted value + * is the 1's complement of the final running CRC + */ +static u_int32_t +ieee80211_crc_update(u_int32_t crc, u_int8_t *buf, int len) +{ + u_int8_t *endbuf; + + for (endbuf = buf + len; buf < endbuf; buf++) + crc = ieee80211_crc_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return crc; +} + +/* + * Return the phy mode for with the specified channel so the + * caller can select a rate set. This is problematic and the + * work here assumes how things work elsewhere in this code. + */ +enum ieee80211_phymode +ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211channel *chan) +{ + /* + * NB: this assumes the channel would not be supplied to us + * unless it was already compatible with the current mode. + */ + if (ic->ic_curmode != IEEE80211_MODE_AUTO) + return ic->ic_curmode; + /* + * In autoselect mode; deduce a mode based on the channel + * characteristics. We assume that turbo-only channels + * are not considered when the channel set is constructed. + */ + if (IEEE80211_IS_CHAN_5GHZ(chan)) + return IEEE80211_MODE_11A; + else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) + return IEEE80211_MODE_11G; + else + return IEEE80211_MODE_11B; +} + +/* + * convert IEEE80211 rate value to ifmedia subtype. + * ieee80211 rate is in unit of 0.5Mbps. + */ +int +ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + static const struct { + u_int m; /* rate + mode */ + u_int r; /* if_media rate */ + } rates[] = { + { 2 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS1 }, + { 4 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS2 }, + { 11 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS5 }, + { 22 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS11 }, + { 44 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS22 }, + { 12 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM6 }, + { 18 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM9 }, + { 24 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM12 }, + { 36 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM18 }, + { 48 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM24 }, + { 72 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM36 }, + { 96 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM48 }, + { 108 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM54 }, + { 2 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS1 }, + { 4 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS2 }, + { 11 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS5 }, + { 22 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS11 }, + { 12 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM6 }, + { 18 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM9 }, + { 24 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM12 }, + { 36 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM18 }, + { 48 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM24 }, + { 72 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM36 }, + { 96 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM48 }, + { 108 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM54 }, + /* NB: OFDM72 doesn't realy exist so we don't handle it */ + }; + u_int mask, i; + + mask = rate & IEEE80211_RATE_VAL; + switch (mode) { + case IEEE80211_MODE_11A: + case IEEE80211_MODE_TURBO: + mask |= IFM_MAKEMODE(IFM_IEEE80211_11A); + break; + case IEEE80211_MODE_11B: + mask |= IFM_MAKEMODE(IFM_IEEE80211_11B); + break; + case IEEE80211_MODE_AUTO: + if (ic->ic_phytype == IEEE80211_T_FH) { + /* must handle these specially */ + switch (mask) { + case 2: return IFM_IEEE80211_FH1; + case 4: return IFM_IEEE80211_FH2; + } + return IFM_AUTO; + } + /* NB: hack, 11g matches both 11b+11a rates */ + /* fall thru... */ + case IEEE80211_MODE_11G: + mask |= IFM_MAKEMODE(IFM_IEEE80211_11G); + break; + } + for (i = 0; i < N(rates); i++) + if (rates[i].m == mask) + return rates[i].r; + return IFM_AUTO; +#undef N +} + +int +ieee80211_media2rate(int mword) +{ +#define N(a) (sizeof(a) / sizeof(a[0])) + static const int ieeerates[] = { + -1, /* IFM_AUTO */ + 0, /* IFM_MANUAL */ + 0, /* IFM_NONE */ + 2, /* IFM_IEEE80211_FH1 */ + 4, /* IFM_IEEE80211_FH2 */ + 2, /* IFM_IEEE80211_DS1 */ + 4, /* IFM_IEEE80211_DS2 */ + 11, /* IFM_IEEE80211_DS5 */ + 22, /* IFM_IEEE80211_DS11 */ + 44, /* IFM_IEEE80211_DS22 */ + 12, /* IFM_IEEE80211_OFDM6 */ + 18, /* IFM_IEEE80211_OFDM9 */ + 24, /* IFM_IEEE80211_OFDM12 */ + 36, /* IFM_IEEE80211_OFDM18 */ + 48, /* IFM_IEEE80211_OFDM24 */ + 72, /* IFM_IEEE80211_OFDM36 */ + 96, /* IFM_IEEE80211_OFDM48 */ + 108, /* IFM_IEEE80211_OFDM54 */ + 144, /* IFM_IEEE80211_OFDM72 */ + }; + return IFM_SUBTYPE(mword) < N(ieeerates) ? + ieeerates[IFM_SUBTYPE(mword)] : 0; +#undef N +} + +/* + * Format an Ethernet MAC for printing. + */ +const char* +ether_sprintf(const u_int8_t *mac) +{ + static char etherbuf[18]; + snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + return etherbuf; +} +EXPORT_SYMBOL(ether_sprintf); /* XXX */ + +/* + * Module glue. + */ +#include "release.h" +#include "version.h" +static char *version = WLAN_VERSION " " RELEASE_TYPE " (Sam Leffler )"; +static char *dev_info = "wlan"; + +MODULE_AUTHOR("Errno Consulting, Sam Leffler"); +MODULE_DESCRIPTION("802.11 wireless LAN protocol support"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual BSD/GPL"); /* XXX really BSD only */ +#endif + +EXPORT_SYMBOL(ieee80211_add_rates); +EXPORT_SYMBOL(ieee80211_add_xrates); +EXPORT_SYMBOL(ieee80211_chan2ieee); +EXPORT_SYMBOL(ieee80211_chan2mode); +EXPORT_SYMBOL(ieee80211_decap); +EXPORT_SYMBOL(ieee80211_dump_pkt); +EXPORT_SYMBOL(ieee80211_encap); +EXPORT_SYMBOL(ieee80211_end_scan); +EXPORT_SYMBOL(ieee80211_find_node); +EXPORT_SYMBOL(ieee80211_ieee2mhz); +EXPORT_SYMBOL(ieee80211_ifattach); +EXPORT_SYMBOL(ieee80211_ifdetach); +EXPORT_SYMBOL(ieee80211_input); +EXPORT_SYMBOL(ieee80211_iterate_nodes); +EXPORT_SYMBOL(ieee80211_media_init); +EXPORT_SYMBOL(ieee80211_media_change); +EXPORT_SYMBOL(ieee80211_media_status); +EXPORT_SYMBOL(ieee80211_media2rate); +EXPORT_SYMBOL(ieee80211_mhz2ieee); +EXPORT_SYMBOL(ieee80211_new_state); +EXPORT_SYMBOL(ieee80211_next_scan); +EXPORT_SYMBOL(ieee80211_rate2media); +EXPORT_SYMBOL(ieee80211_setmode); + +static int __init +init_wlan(void) +{ + printk(KERN_INFO "%s: %s\n", dev_info, version); + return 0; +} +module_init(init_wlan); + +static void __exit +exit_wlan(void) +{ + printk(KERN_INFO "%s: driver unloaded\n", dev_info); +} +module_exit(exit_wlan); diff -Nru a/drivers/net/wireless/atheros/wlan/if_ieee80211wireless.c b/drivers/net/wireless/atheros/wlan/if_ieee80211wireless.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_ieee80211wireless.c Wed Jul 30 18:20:27 2003 @@ -0,0 +1,1117 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_ieee80211wireless.c,v 1.20 2003/05/19 04:44:48 sam Exp $ + */ + +/* + * Wireless extensions support for 802.11 common code. + */ +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include /* XXX for ARPHRD_ETHER */ + +#include + +#include + +#include "if_ieee80211.h" + +#ifdef CONFIG_NET_WIRELESS + +struct iw_statistics * +ieee80211_iw_getstats(struct net_device *dev) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + ic->ic_iwstats.qual.qual = 0; + ic->ic_iwstats.qual.level = ic->ic_bss.ni_rssi; + ic->ic_iwstats.qual.noise = 0; + ic->ic_iwstats.qual.updated = 0; + + ic->ic_iwstats.status = ic->ic_state; + ic->ic_iwstats.discard.nwid = 0; + ic->ic_iwstats.discard.code = 0; + ic->ic_iwstats.discard.fragment = 0; + ic->ic_iwstats.discard.retries = 0; + ic->ic_iwstats.discard.misc = 0; + + ic->ic_iwstats.miss.beacon = 0; + + return &ic->ic_iwstats; +} + +int +ieee80211_ioctl_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + /* XXX should use media status but IFM_AUTO case gets tricky */ + switch (ic->ic_curmode) { + case IEEE80211_MODE_11A: + strncpy(name, "IEEE 802.11-OFDM", IFNAMSIZ); + break; + case IEEE80211_MODE_11B: + strncpy(name, "IEEE 802.11-DS", IFNAMSIZ); + break; + case IEEE80211_MODE_11G: + strncpy(name, "IEEE 802.11-OFDM/DS", IFNAMSIZ); + break; + case IEEE80211_MODE_TURBO: + strncpy(name, "IEEE 802.11-TURBO", IFNAMSIZ); + break; + default: + strncpy(name, "IEEE 802.11", IFNAMSIZ); + break; + } + return 0; +} + +int +ieee80211_ioctl_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + int kid, error; + + if (erq->flags & IW_ENCODE_DISABLED) { + ic->ic_flags &= ~IEEE80211_F_WEPON; + error = ENETRESET; + goto done; + } + if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { + error = EOPNOTSUPP; + goto done; + } + + kid = erq->flags & IW_ENCODE_INDEX; + if (kid >= IEEE80211_WEP_NKID) { + error = EINVAL; + goto done; + } + if (erq->length > 0) { + if (erq->length > IEEE80211_KEYBUF_SIZE) { + error = EINVAL; + goto done; + } + memcpy(ic->ic_nw_keys[kid].wk_key, keybuf, erq->length); + memset(ic->ic_nw_keys[kid].wk_key + erq->length, 0, + IEEE80211_KEYBUF_SIZE - erq->length); + ic->ic_nw_keys[kid].wk_len = erq->length; + } + ic->ic_wep_txkey = kid; + ic->ic_flags |= IEEE80211_F_WEPON; + error = ENETRESET; +done: + if (error == ENETRESET) + error = (*ic->ic_init)(dev); /* reset mode */ + return -error; +} + +int +ieee80211_ioctl_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if ((ic->ic_caps & IEEE80211_C_WEP) == 0) { + erq->length = 0; + erq->flags = IW_ENCODE_DISABLED; + } else { + int kid = erq->flags & IW_ENCODE_INDEX; + if (kid >= IEEE80211_WEP_NKID) + return -EINVAL; + erq->flags = kid + 1; + if (erq->length > ic->ic_nw_keys[kid].wk_len) + erq->length = ic->ic_nw_keys[kid].wk_len; + memcpy(key, ic->ic_nw_keys[kid].wk_key, erq->length); + erq->flags |= IW_ENCODE_ENABLED; /* XXX */ + erq->flags |= IW_ENCODE_OPEN; /* XXX */ + } + return 0; +} + +#ifndef ifr_media +#define ifr_media ifr_ifru.ifru_ivalue +#endif + +int +ieee80211_ioctl_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ifmediareq imr; + struct ifreq ifr; + int rate; + + memset(&imr, 0, sizeof(imr)); + (*ic->ic_media.ifm_status)(dev, &imr); + + if (rrq->fixed) { + /* XXX fudge checking rates */ + rate = ieee80211_rate2media(ic, 2 * (rrq->value / 1000000), + ic->ic_curmode); + } else + rate = IFM_AUTO; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_media = (imr.ifm_active & ~IFM_TMASK) | IFM_SUBTYPE(rate); + + return -ifmedia_ioctl(dev, &ifr, &ic->ic_media, SIOCSIFMEDIA); +} + +int +ieee80211_ioctl_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ifmediareq imr; + int rate; + + memset(&imr, 0, sizeof(imr)); + (*ic->ic_media.ifm_status)(dev, &imr); + + rrq->fixed = IFM_SUBTYPE(ic->ic_media.ifm_media) != IFM_AUTO; + /* media status will have the current xmit rate if available */ + rate = ieee80211_media2rate(imr.ifm_active); + if (rate == -1) /* IFM_AUTO */ + rate = 0; + rrq->value = 1000000 * (rate / 2); + + return 0; +} + +int +ieee80211_ioctl_siwsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *sens, char *extra) +{ + return 0; +} + +int +ieee80211_ioctl_giwsens(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *sens, char *extra) +{ + sens->value = 0; + sens->fixed = 1; + + return 0; +} + +int +ieee80211_ioctl_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + u16 val; + + if (rts->disabled) + val = IEEE80211_RTS_MAX; + else if (IEEE80211_RTS_MIN < rts->value || rts->value > IEEE80211_RTS_MAX) + return -EINVAL; + else + val = rts->value; + if (val != ic->ic_rtsthreshold) { + ic->ic_rtsthreshold = val; + return -(*ic->ic_init)(dev); + } else { + return 0; + } +} + +int +ieee80211_ioctl_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + rts->value = ic->ic_rtsthreshold; + rts->disabled = (rts->value == IEEE80211_RTS_MAX); + rts->fixed = 1; + + return 0; +} + + +int +ieee80211_ioctl_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + u16 val; + + if (rts->disabled) + val = __constant_cpu_to_le16(2346); + else if (rts->value < 256 || rts->value > 2346) + return -EINVAL; + else + val = __cpu_to_le16(rts->value & ~0x1); /* even numbers only */ + if (val != ic->ic_fragthreshold) { + ic->ic_fragthreshold = val; + return -(*ic->ic_init)(dev); + } + return 0; +} + +int +ieee80211_ioctl_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + rts->value = ic->ic_fragthreshold; + rts->disabled = (rts->value == 2346); + rts->fixed = 1; + + return 0; +} + +int +ieee80211_ioctl_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + static const u_int8_t zero_bssid[IEEE80211_ADDR_LEN]; + + /* NB: should only be set when in STA mode */ + if (ic->ic_opmode == IEEE80211_M_STA) { + IEEE80211_ADDR_COPY(ic->ic_des_bssid, &ap_addr->sa_data); + /* looks like a zero address disables */ + if (IEEE80211_ADDR_EQ(ic->ic_des_bssid, zero_bssid)) + ic->ic_flags &= ~IEEE80211_F_DESBSSID; + else + ic->ic_flags |= IEEE80211_F_DESBSSID; + return -(*ic->ic_init)(dev); + } else + return -EINVAL; +} + +int +ieee80211_ioctl_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (ic->ic_flags & IEEE80211_F_DESBSSID) + IEEE80211_ADDR_COPY(&ap_addr->sa_data, ic->ic_des_bssid); + else + IEEE80211_ADDR_COPY(&ap_addr->sa_data, ic->ic_bss.ni_bssid); + ap_addr->sa_family = ARPHRD_ETHER; + return 0; +} + +int +ieee80211_ioctl_siwnickn(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *nickname) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (data->length > IEEE80211_NWID_LEN) + return -EINVAL; + + memset(ic->ic_nickname, 0, IEEE80211_NWID_LEN); + memcpy(ic->ic_nickname, nickname, data->length); + ic->ic_nicknamelen = data->length; + + return 0; +} + +int +ieee80211_ioctl_giwnickn(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *nickname) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (data->length > ic->ic_nicknamelen + 1) + data->length = ic->ic_nicknamelen + 1; + if (data->length > 0) { + memcpy(nickname, ic->ic_nickname, data->length-1); + nickname[data->length-1] = '\0'; + } + return 0; +} + +int +ieee80211_ioctl_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ieee80211channel *c; + int i; + + if (freq->e != 1) /* just lazy... */ + return -EINVAL; + i = ieee80211_mhz2ieee(freq->m / 100000, 0); + if (i > IEEE80211_CHAN_MAX || isclr(ic->ic_chan_active, i)) + return -EINVAL; + c = &ic->ic_channels[i]; + if (c == ic->ic_ibss_chan) /* no change, just return */ + return 0; + ic->ic_ibss_chan = ic->ic_des_chan = c; + return -(*ic->ic_init)(dev); +} + +int +ieee80211_ioctl_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (!ic->ic_ibss_chan) + return -EINVAL; + + freq->m = ic->ic_ibss_chan->ic_freq * 100000; + freq->e = 1; + + return 0; +} + +int +ieee80211_ioctl_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (data->flags == 0) { /* ANY */ + memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN); + ic->ic_des_esslen = 0; + } else { + int i, len; + + len = IW_ESSID_MAX_SIZE; + if (len > IEEE80211_NWID_LEN) + len = IEEE80211_NWID_LEN; + memcpy(ic->ic_des_essid, ssid, len); + /* XXX: scan for \0 to calculate the length */ + for (i = 0; i < len && ic->ic_des_essid[i] != '\0'; i++) + ; + ic->ic_des_esslen = i; + } + return -(*ic->ic_init)(dev); +} + +int +ieee80211_ioctl_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *essid) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + data->flags = 1; /* active */ + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + if (data->length > ic->ic_des_esslen) + data->length = ic->ic_des_esslen; + memcpy(essid, ic->ic_des_essid, data->length); + } else { + if (data->length > ic->ic_bss.ni_esslen) + data->length = ic->ic_bss.ni_esslen; + memcpy(essid, ic->ic_bss.ni_essid, data->length); + } + return 0; +} + +int +ieee80211_ioctl_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ieee80211_node *ni = &ic->ic_bss; + struct iw_range *range = (struct iw_range *) extra; + struct ieee80211_rateset *rs; + int i, r; + + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + /* TODO: could fill num_txpower and txpower array with + * something; however, there are 128 different values.. */ + + range->txpower_capa = IW_TXPOW_DBM; + + if (ic->ic_opmode == IEEE80211_M_STA || ic->ic_opmode == IEEE80211_M_IBSS) { + range->min_pmp = 1 * 1024; + range->max_pmp = 65535 * 1024; + range->min_pmt = 1 * 1024; + range->max_pmt = 1000 * 1024; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | + IW_POWER_UNICAST_R | IW_POWER_ALL_R; + } + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 13; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 0; + range->max_retry = 255; + + range->num_channels = IEEE80211_CHAN_MAX; /* XXX */ + + range->num_frequency = 0; + for (i = 0; i <= IEEE80211_CHAN_MAX; i++) + if (isset(ic->ic_chan_active, i)) { + range->freq[range->num_frequency].i = i; + range->freq[range->num_frequency].m = + ic->ic_channels[i].ic_freq * 100000; + range->freq[range->num_frequency].e = 1; + if (++range->num_frequency == IW_MAX_FREQUENCIES) + break; + } + + range->max_qual.qual = 92; /* 0 .. 92 */ + range->max_qual.level = 154; /* 27 .. 154 */ + range->max_qual.noise = 154; /* 27 .. 154 */ + range->sensitivity = 3; + + range->max_encoding_tokens = IEEE80211_WEP_NKID; + range->num_encoding_sizes = 2; + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + + /* XXX this only works for station mode */ + rs = &ni->ni_rates; + range->num_bitrates = rs->rs_nrates; + if (range->num_bitrates > IW_MAX_BITRATES) + range->num_bitrates = IW_MAX_BITRATES; + for (i = 0; i < range->num_bitrates; i++) { + r = rs->rs_rates[i] & IEEE80211_RATE_VAL; + range->bitrate[i] = (r / 2) * 1000000; + } + + /* estimated maximum TCP throughput values (bps) */ + range->throughput = 5500000; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + return 0; +} + +int +ieee80211_ioctl_siwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ifmediareq imr; + struct ifreq ifr; + + memset(&imr, 0, sizeof(imr)); + (*ic->ic_media.ifm_status)(dev, &imr); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_media = imr.ifm_active &~ IFM_OMASK; + switch (*mode) { + case IW_MODE_INFRA: + /* NB: this is the default */ + break; + case IW_MODE_ADHOC: + ifr.ifr_media |= IFM_IEEE80211_IBSS; + break; + case IW_MODE_MASTER: + ifr.ifr_media |= IFM_IEEE80211_HOSTAP; + break; + default: + return -EINVAL; + } + return -ifmedia_ioctl(dev, &ifr, &ic->ic_media, SIOCSIFMEDIA); +} + +int +ieee80211_ioctl_giwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ifmediareq imr; + + memset(&imr, 0, sizeof(imr)); + (*ic->ic_media.ifm_status)(dev, &imr); + + if (imr.ifm_active & IFM_IEEE80211_HOSTAP) + *mode = IW_MODE_MASTER; + else if (imr.ifm_active & IFM_IEEE80211_IBSS) + *mode = IW_MODE_ADHOC; + else + *mode = IW_MODE_INFRA; + return 0; +} + +int +ieee80211_ioctl_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (wrq->disabled) { + if (ic->ic_flags & IEEE80211_F_PMGTON) { + ic->ic_flags &= ~IEEE80211_F_PMGTON; + goto done; + } + return 0; + } + + if ((ic->ic_caps & IEEE80211_C_PMGT) == 0) + return -EOPNOTSUPP; + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + case IW_POWER_ALL_R: + case IW_POWER_ON: + ic->ic_flags |= IEEE80211_F_PMGTON; + break; + default: + return -EINVAL; + } + if (wrq->flags & IW_POWER_TIMEOUT) { + ic->ic_holdover = wrq->value / 1024; + ic->ic_flags |= IEEE80211_F_PMGTON; + } + if (wrq->flags & IW_POWER_PERIOD) { + ic->ic_lintval = wrq->value / 1024; + ic->ic_flags |= IEEE80211_F_PMGTON; + } +done: + return -(*ic->ic_init)(dev); +} + +int +ieee80211_ioctl_giwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + rrq->disabled = (ic->ic_flags & IEEE80211_F_PMGTON) == 0; + if (!rrq->disabled) { + switch (rrq->flags & IW_POWER_TYPE) { + case IW_POWER_TIMEOUT: + rrq->flags = IW_POWER_TIMEOUT; + rrq->value = ic->ic_holdover * 1024; + break; + case IW_POWER_PERIOD: + rrq->flags = IW_POWER_PERIOD; + rrq->value = ic->ic_lintval * 1024; + break; + } + rrq->flags |= IW_POWER_ALL_R; + } + return 0; +} + +int +ieee80211_ioctl_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (rrq->disabled) { + if (ic->ic_flags & IEEE80211_F_SWRETRY) { + ic->ic_flags &= ~IEEE80211_F_SWRETRY; + goto done; + } + return 0; + } + + if ((ic->ic_caps & IEEE80211_C_SWRETRY) == 0) + return -EOPNOTSUPP; + if (rrq->flags == IW_RETRY_LIMIT) { + if (rrq->value >= 0) { + ic->ic_txmin = rrq->value; + ic->ic_txmax = rrq->value; /* XXX */ + ic->ic_txlifetime = 0; /* XXX */ + ic->ic_flags |= IEEE80211_F_SWRETRY; + } else { + ic->ic_flags &= ~IEEE80211_F_SWRETRY; + } + return 0; + } +done: + return -(*ic->ic_init)(dev); +} + +int +ieee80211_ioctl_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + rrq->disabled = (ic->ic_flags & IEEE80211_F_SWRETRY) == 0; + if (!rrq->disabled) { + switch (rrq->flags & IW_RETRY_TYPE) { + case IW_RETRY_LIFETIME: + rrq->flags = IW_RETRY_LIFETIME; + rrq->value = ic->ic_txlifetime * 1024; + break; + case IW_RETRY_LIMIT: + rrq->flags = IW_RETRY_LIMIT; + switch (rrq->flags & IW_RETRY_MODIFIER) { + case IW_RETRY_MIN: + rrq->flags |= IW_RETRY_MAX; + rrq->value = ic->ic_txmin; + break; + case IW_RETRY_MAX: + rrq->flags |= IW_RETRY_MAX; + rrq->value = ic->ic_txmax; + break; + } + break; + } + } + return 0; +} + +int +ieee80211_ioctl_siwtxpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + int curtxpmgt; + + curtxpmgt = ic->ic_flags & IEEE80211_F_TXPMGT; + if (rrq->disabled) { + if (curtxpmgt != IEEE80211_F_TXPOW_OFF) { + if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) + return -EOPNOTSUPP; + ic->ic_flags &= ~IEEE80211_F_TXPMGT; + ic->ic_flags |= IEEE80211_F_TXPOW_OFF; + goto done; + } + return 0; + } + + if (rrq->fixed) { + if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0) + return -EOPNOTSUPP; + if (rrq->flags != IW_TXPOW_DBM) + return -EOPNOTSUPP; + ic->ic_txpower = rrq->value; + if (curtxpmgt != IEEE80211_F_TXPOW_FIXED) { + ic->ic_flags &= ~IEEE80211_F_TXPMGT; + ic->ic_flags |= IEEE80211_F_TXPOW_FIXED; + } + } else { + if (curtxpmgt == IEEE80211_F_TXPOW_AUTO) + return 0; + /* NB: auto is always supported */ + ic->ic_flags &= ~IEEE80211_F_TXPMGT; + ic->ic_flags |= IEEE80211_F_TXPOW_AUTO; + } +done: + return -(*ic->ic_init)(dev); +} + +int +ieee80211_ioctl_giwtxpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rrq, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + u_int32_t curtxmgt = ic->ic_flags & IEEE80211_F_TXPMGT; + + rrq->disabled = (curtxmgt == IEEE80211_F_TXPOW_OFF); + rrq->fixed = (curtxmgt == IEEE80211_F_TXPOW_FIXED); + rrq->flags = IW_TXPOW_DBM; + rrq->value = ic->ic_txpower; + return 0; +} + +int +ieee80211_ioctl_iwaplist(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ieee80211_node *ni; + struct sockaddr addr[IW_MAX_AP]; + struct iw_quality qual[IW_MAX_AP]; + int i; + + i = 0; + /* XXX lock node list */ + TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { + addr[i].sa_family = ARPHRD_ETHER; + if (ic->ic_opmode == IEEE80211_M_HOSTAP) + IEEE80211_ADDR_COPY(addr[i].sa_data, ni->ni_macaddr); + else + IEEE80211_ADDR_COPY(addr[i].sa_data, ni->ni_bssid); + qual[i].qual = ni->ni_rssi; + qual[i].level = 0; + qual[i].noise = 0; + qual[i].updated = jiffies; /* XXX */ + if (++i >= IW_MAX_AP) + break; + } + data->length = i; + memcpy(extra, &addr, i*sizeof(addr[0])); + data->flags = 1; /* signal quality present (sort of) */ + memcpy(extra + i*sizeof(addr[0]), &qual, i*sizeof(qual[i])); + + return 0; + +} + +#ifdef SIOCGIWSCAN +int +ieee80211_ioctl_siwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + + if (ic->ic_opmode != IEEE80211_M_HOSTAP) { + /* just return existing station tables */ + data->length = 0; + } else { +#ifdef notyet + /* XXX honor scan request flags */ + HAL_CHANNEL *c = sc->sc_cur_chan; + ni->ni_chan = ath_hal_ghz2ieee(c->channel, c->channelFlags); + ieee80211_new_state(dev, IEEE80211_S_SCAN, -1); +#endif + } + return 0; +} + +int +ieee80211_ioctl_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ieee80211_node *ni; + char *current_ev = extra; + char *end_buf = extra + IW_SCAN_MAX_DATA; + char *current_val; + struct iw_event iwe; + int j; + + if (ic->ic_state == IEEE80211_S_SCAN && + (ic->ic_flags & (IEEE80211_F_SCANAP | IEEE80211_F_ASCAN))) { + /* + * Still scanning, indicate the caller should try again. + */ + return -EAGAIN; + } + + /* + * Translate data to WE format. + */ + TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { + if (current_ev >= end_buf) + break; + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + if (ic->ic_opmode == IEEE80211_M_HOSTAP) { + IEEE80211_ADDR_COPY(iwe.u.ap_addr.sa_data, + ni->ni_macaddr); + current_ev = iwe_stream_add_event(current_ev, + end_buf, &iwe, IW_EV_ADDR_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = IW_MODE_INFRA; + current_ev = iwe_stream_add_event(current_ev, + end_buf, &iwe, IW_EV_UINT_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = ic->ic_des_esslen; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, + end_buf, &iwe, ic->ic_des_essid); + } else { + IEEE80211_ADDR_COPY(iwe.u.ap_addr.sa_data, + ni->ni_bssid); + current_ev = iwe_stream_add_event(current_ev, + end_buf, &iwe, IW_EV_ADDR_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = IW_MODE_MASTER; + current_ev = iwe_stream_add_event(current_ev, + end_buf, &iwe, IW_EV_UINT_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + iwe.u.data.length = ni->ni_esslen; + if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + current_ev = iwe_stream_add_point(current_ev, + end_buf, &iwe, ni->ni_essid); + } + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + iwe.u.qual.level = ni->ni_rssi; + iwe.u.qual.updated = jiffies; /* XXX */ + current_ev = iwe_stream_add_event(current_ev, + end_buf, &iwe, IW_EV_QUAL_LEN); + + if (ni->ni_capinfo & (IEEE80211_CAPINFO_ESS|IEEE80211_CAPINFO_IBSS)) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = ni->ni_capinfo & IEEE80211_CAPINFO_ESS ? + IW_MODE_MASTER : IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(current_ev, + end_buf, &iwe, IW_EV_UINT_LEN); + } + + /* return essid if present */ + if (ni->ni_essid[0]) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + iwe.u.data.length = strlen(ni->ni_essid); + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, + end_buf, &iwe, ni->ni_essid); + } + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ni->ni_chan->ic_freq * 100000; + iwe.u.freq.e = 1; + current_ev = iwe_stream_add_event(current_ev, + end_buf, &iwe, IW_EV_FREQ_LEN); +#ifdef notdef + ap->interval = ni->ni_intval; +#endif + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWRATE; + current_val = current_ev + IW_EV_LCP_LEN; + for (j = 0; j < ni->ni_rates.rs_nrates; j++) { + if (ni->ni_rates.rs_rates[j]) { + iwe.u.bitrate.value = ((ni->ni_rates.rs_rates[j] & + IEEE80211_RATE_VAL) / 2) * 1000000; + current_val = iwe_stream_add_value(current_ev, + current_val, end_buf, &iwe, + IW_EV_PARAM_LEN); + } + } + if ((current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; + } + data->length = current_ev - extra; + return 0; +} +#endif /* SIOCGIWSCAN */ + +static int +ieee80211_ioctl_setparam(struct net_device *dev, struct iw_request_info *info, + void *w, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + int *i = (int *) extra; + int param = i[0]; /* parameter id is 1st */ + int value = i[1]; /* NB: all values are TYPE_INT */ + struct ifmediareq imr; + struct ifreq ifr; + + memset(&imr, 0, sizeof(imr)); + (*ic->ic_media.ifm_status)(dev, &imr); + + memset(&ifr, 0, sizeof(ifr)); + switch (param) { + case IEEE80211_PARAM_TURBO: + if (value) + imr.ifm_active |= IFM_IEEE80211_TURBO; + else + imr.ifm_active &= ~IFM_IEEE80211_TURBO; + ifr.ifr_media = imr.ifm_active; + break; + case IEEE80211_PARAM_MODE: + ifr.ifr_media = (imr.ifm_active &~ IFM_MMASK) + | IFM_MAKEMODE(value); + break; + default: + return -EOPNOTSUPP; + } + return -ifmedia_ioctl(dev, &ifr, &ic->ic_media, SIOCSIFMEDIA); +} + +static int +ieee80211_ioctl_getparam(struct net_device *dev, struct iw_request_info *info, + void *w, char *extra) +{ + struct ieee80211com *ic = (struct ieee80211com *) dev; + struct ifmediareq imr; + int *param = (int *) extra; + + (*ic->ic_media.ifm_status)(dev, &imr); + switch (param[0]) { + case IEEE80211_PARAM_TURBO: + param[0] = (imr.ifm_active & IFM_IEEE80211_TURBO) != 0; + break; + case IEEE80211_PARAM_MODE: + param[0] = IFM_MODE(imr.ifm_active); + break; + default: + return -EOPNOTSUPP; + } + return 0; +} + +/* Structures to export the Wireless Handlers */ +static const iw_handler ieee80211_handlers[] = { + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */ + (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */ + (iw_handler) ieee80211_ioctl_siwsens, /* SIOCSIWSENS */ + (iw_handler) ieee80211_ioctl_giwsens, /* SIOCGIWSENS */ + (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ + (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */ + (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ + (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ + (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ieee80211_ioctl_iwaplist, /* SIOCGIWAPLIST */ +#ifdef SIOCGIWSCAN + (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */ + (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */ +#else + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ +#endif /* SIOCGIWSCAN */ + (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ + (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ + (iw_handler) ieee80211_ioctl_siwnickn, /* SIOCSIWNICKN */ + (iw_handler) ieee80211_ioctl_giwnickn, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ + (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ + (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ + (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ + (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) ieee80211_ioctl_siwtxpow, /* SIOCSIWTXPOW */ + (iw_handler) ieee80211_ioctl_giwtxpow, /* SIOCGIWTXPOW */ + (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ + (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ + (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ + (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ + (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ + (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ +}; +static const iw_handler ieee80211_priv_handlers[] = { + (iw_handler) ieee80211_ioctl_setparam, /* SIOCWFIRSTPRIV+0 */ + (iw_handler) ieee80211_ioctl_getparam, /* SIOCWFIRSTPRIV+1 */ +}; +static const struct iw_priv_args ieee80211_priv_args[] = { + { IEEE80211_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setparam" }, +#if WIRELESS_EXT >= 12 + /* + * These depends on sub-ioctl support which added in version 12. + */ + { IEEE80211_IOCTL_GETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getparam" }, + /* sub-ioctl handlers */ + { IEEE80211_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" }, + { IEEE80211_IOCTL_GETPARAM, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" }, + /* sub-ioctl definitions */ + { IEEE80211_PARAM_TURBO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "turbo" }, + { IEEE80211_PARAM_TURBO, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_turbo" }, + { IEEE80211_PARAM_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mode" }, + { IEEE80211_PARAM_MODE, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_mode" }, +#endif /* WIRELESS_EXT >= 12 */ +}; + +const struct iw_handler_def ieee80211_iw_handler_def = { +#define N(a) (sizeof (a) / sizeof (a[0])) + .standard = (iw_handler *) ieee80211_handlers, + .num_standard = N(ieee80211_handlers), + .private = (iw_handler *) ieee80211_priv_handlers, + .num_private = N(ieee80211_priv_handlers), + .private_args = (struct iw_priv_args *) ieee80211_priv_args, + .num_private_args = N(ieee80211_priv_args), +#undef N +}; +#endif /* CONFIG_NET_WIRELESS */ diff -Nru a/drivers/net/wireless/atheros/wlan/if_llc.h b/drivers/net/wireless/atheros/wlan/if_llc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_llc.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: if_llc.h,v 1.3 2003/05/16 20:23:28 sam Exp $ + * $NetBSD: if_llc.h,v 1.12 1999/11/19 20:41:19 thorpej Exp $ + * $Id: if_llc.h,v 1.3 2003/05/16 20:23:28 sam Exp $ + */ + +/* + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_llc.h 8.1 (Berkeley) 6/10/93 + * $FreeBSD: src/sys/net/if_llc.h,v 1.9 2002/09/23 06:25:08 alfred Exp $ + */ + +#ifndef _NET_IF_LLC_H_ +#define _NET_IF_LLC_H_ + +/* + * IEEE 802.2 Link Level Control headers, for use in conjunction with + * 802.{3,4,5} media access control methods. + * + * Headers here do not use bit fields due to shortcommings in many + * compilers. + */ + +struct llc { + u_int8_t llc_dsap; + u_int8_t llc_ssap; + union { + struct { + u_int8_t control; + u_int8_t format_id; + u_int8_t class; + u_int8_t window_x2; + } type_u __packed; + struct { + u_int8_t num_snd_x2; + u_int8_t num_rcv_x2; + } type_i __packed; + struct { + u_int8_t control; + u_int8_t num_rcv_x2; + } type_s __packed; + struct { + u_int8_t control; + /* + * We cannot put the following fields in a structure because + * the structure rounding might cause padding. + */ + u_int8_t frmr_rej_pdu0; + u_int8_t frmr_rej_pdu1; + u_int8_t frmr_control; + u_int8_t frmr_control_ext; + u_int8_t frmr_cause; + } type_frmr __packed; + struct { + u_int8_t control; + u_int8_t org_code[3]; + u_int16_t ether_type; + } type_snap __packed; + struct { + u_int8_t control; + u_int8_t control_ext; + } type_raw __packed; + } llc_un /* XXX __packed ??? */; +} __packed; + +struct frmrinfo { + u_int8_t frmr_rej_pdu0; + u_int8_t frmr_rej_pdu1; + u_int8_t frmr_control; + u_int8_t frmr_control_ext; + u_int8_t frmr_cause; +} __packed; + +#define llc_control llc_un.type_u.control +#define llc_control_ext llc_un.type_raw.control_ext +#define llc_fid llc_un.type_u.format_id +#define llc_class llc_un.type_u.class +#define llc_window llc_un.type_u.window_x2 +#define llc_frmrinfo llc_un.type_frmr.frmr_rej_pdu0 +#define llc_frmr_pdu0 llc_un.type_frmr.frmr_rej_pdu0 +#define llc_frmr_pdu1 llc_un.type_frmr.frmr_rej_pdu1 +#define llc_frmr_control llc_un.type_frmr.frmr_control +#define llc_frmr_control_ext llc_un.type_frmr.frmr_control_ext +#define llc_frmr_cause llc_un.type_frmr.frmr_cause +#define llc_snap llc_un.type_snap + +/* + * Don't use sizeof(struct llc_un) for LLC header sizes + */ +#define LLC_ISFRAMELEN 4 +#define LLC_UFRAMELEN 3 +#define LLC_FRMRLEN 7 +#define LLC_SNAPFRAMELEN 8 + +/* + * Unnumbered LLC format commands + */ +#define LLC_UI 0x3 +#define LLC_UI_P 0x13 +#define LLC_DISC 0x43 +#define LLC_DISC_P 0x53 +#define LLC_UA 0x63 +#define LLC_UA_P 0x73 +#define LLC_TEST 0xe3 +#define LLC_TEST_P 0xf3 +#define LLC_FRMR 0x87 +#define LLC_FRMR_P 0x97 +#define LLC_DM 0x0f +#define LLC_DM_P 0x1f +#define LLC_XID 0xaf +#define LLC_XID_P 0xbf +#define LLC_SABME 0x6f +#define LLC_SABME_P 0x7f + +/* + * Supervisory LLC commands + */ +#define LLC_RR 0x01 +#define LLC_RNR 0x05 +#define LLC_REJ 0x09 + +/* + * Info format - dummy only + */ +#define LLC_INFO 0x00 + +/* + * ISO PDTR 10178 contains among others + */ +#define LLC_X25_LSAP 0x7e +#define LLC_SNAP_LSAP 0xaa +#define LLC_ISO_LSAP 0xfe + +#endif /* _NET_IF_LLC_H_ */ diff -Nru a/drivers/net/wireless/atheros/wlan/if_media.c b/drivers/net/wireless/atheros/wlan/if_media.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_media.c Wed Jul 30 18:20:27 2003 @@ -0,0 +1,520 @@ +/* $NetBSD: if_media.c,v 1.1 1997/03/17 02:55:15 thorpej Exp $ */ +/* $FreeBSD: src/sys/net/if_media.c,v 1.17 2002/06/26 03:34:50 ken Exp $ */ +/* $Id: if_media.c,v 1.6 2003/04/30 16:30:38 sam Exp $ */ + +/* + * Copyright (c) 1997 + * Jonathan Stone and Jason R. Thorpe. All rights reserved. + * + * This software is derived from information provided by Matt Thomas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jonathan Stone + * and Jason R. Thorpe for the NetBSD Project. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * BSD/OS-compatible network interface media selection. + * + * Where it is safe to do so, this code strays slightly from the BSD/OS + * design. Software which uses the API (device drivers, basically) + * shouldn't notice any difference. + * + * Many thanks to Matt Thomas for providing the information necessary + * to implement this interface. + */ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifndef ifr_media +#define ifr_media ifr_ifru.ifru_ivalue +#endif + +#include + +#include "if_media.h" + +/* + * Compile-time options: + * IFMEDIA_DEBUG: + * turn on implementation-level debug printfs. + * Useful for debugging newly-ported drivers. + */ + +struct ifmedia_entry *ifmedia_match(struct ifmedia *ifm, int flags, int mask); + +#ifdef IFMEDIA_DEBUG +int ifmedia_debug = 0; +static void ifmedia_printword(int); +#endif + +/* + * Initialize if_media struct for a specific interface instance. + */ +void +ifmedia_init( + struct ifmedia *ifm, + int dontcare_mask, + ifm_change_cb_t change_callback, + ifm_stat_cb_t status_callback) +{ + + LIST_INIT(&ifm->ifm_list); + ifm->ifm_cur = NULL; + ifm->ifm_media = 0; + ifm->ifm_mask = dontcare_mask; /* IF don't-care bits */ + ifm->ifm_change = change_callback; + ifm->ifm_status = status_callback; +} + +void +ifmedia_removeall(struct ifmedia *ifm) +{ + struct ifmedia_entry *entry; + + for (entry = LIST_FIRST(&ifm->ifm_list); entry; + entry = LIST_FIRST(&ifm->ifm_list)) { + LIST_REMOVE(entry, ifm_list); + kfree(entry); + } +} + +/* + * Add a media configuration to the list of supported media + * for a specific interface instance. + */ +void +ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux) +{ + register struct ifmedia_entry *entry; + +#ifdef IFMEDIA_DEBUG + if (ifmedia_debug) { + if (ifm == NULL) { + printk("ifmedia_add: null ifm\n"); + return; + } + printk("Adding entry for "); + ifmedia_printword(mword); + } +#endif + + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (entry == NULL) + panic("ifmedia_add: can't malloc entry"); + + entry->ifm_media = mword; + entry->ifm_data = data; + entry->ifm_aux = aux; + + LIST_INSERT_HEAD(&ifm->ifm_list, entry, ifm_list); +} + +/* + * Add an array of media configurations to the list of + * supported media for a specific interface instance. + */ +void +ifmedia_list_add(struct ifmedia *ifm, struct ifmedia_entry *lp, int count) +{ + int i; + + for (i = 0; i < count; i++) + ifmedia_add(ifm, lp[i].ifm_media, lp[i].ifm_data, + lp[i].ifm_aux); +} + +/* + * Set the default active media. + * + * Called by device-specific code which is assumed to have already + * selected the default media in hardware. We do _not_ call the + * media-change callback. + */ +void +ifmedia_set(struct ifmedia *ifm, int target) + +{ + struct ifmedia_entry *match; + + match = ifmedia_match(ifm, target, ifm->ifm_mask); + + if (match == NULL) { + printk("ifmedia_set: no match for 0x%x/0x%x\n", + target, ~ifm->ifm_mask); + panic("ifmedia_set"); + } + ifm->ifm_cur = match; + +#ifdef IFMEDIA_DEBUG + if (ifmedia_debug) { + printk("ifmedia_set: target "); + ifmedia_printword(target); + printk("ifmedia_set: setting to "); + ifmedia_printword(ifm->ifm_cur->ifm_media); + } +#endif +} + +/* + * Device-independent media ioctl support function. + */ +int +ifmedia_ioctl(struct net_device *dev, struct ifreq *ifr, + struct ifmedia *ifm, u_long cmd) +{ + struct ifmedia_entry *match; + struct ifmediareq *ifmr = (struct ifmediareq *) ifr; + int error = 0, sticky; + + if (dev == NULL || ifr == NULL || ifm == NULL) + return(EINVAL); + + switch (cmd) { + + /* + * Set the current media. + */ + case SIOCSIFMEDIA: + { + struct ifmedia_entry *oldentry; + int oldmedia; + int newmedia = ifr->ifr_media; + + match = ifmedia_match(ifm, newmedia, ifm->ifm_mask); + if (match == NULL) { +#ifdef IFMEDIA_DEBUG + if (ifmedia_debug) { + printk( + "ifmedia_ioctl: no media found for 0x%x\n", + newmedia); + } +#endif + return (ENXIO); + } + + /* + * If no change, we're done. + * XXX Automedia may invole software intervention. + * Keep going in case the the connected media changed. + * Similarly, if best match changed (kernel debugger?). + */ + if ((IFM_SUBTYPE(newmedia) != IFM_AUTO) && + (newmedia == ifm->ifm_media) && + (match == ifm->ifm_cur)) + return 0; + + /* + * We found a match, now make the driver switch to it. + * Make sure to preserve our old media type in case the + * driver can't switch. + */ +#ifdef IFMEDIA_DEBUG + if (ifmedia_debug) { + printk("ifmedia_ioctl: switching %s to ", dev->name); + ifmedia_printword(match->ifm_media); + } +#endif + oldentry = ifm->ifm_cur; + oldmedia = ifm->ifm_media; + ifm->ifm_cur = match; + ifm->ifm_media = newmedia; + error = (*ifm->ifm_change)(dev); + if (error) { + ifm->ifm_cur = oldentry; + ifm->ifm_media = oldmedia; + } + break; + } + + /* + * Get list of available media and current media on interface. + */ + case SIOCGIFMEDIA: + { + struct ifmedia_entry *ep; + int *kptr, count; + int usermax; /* user requested max */ + + kptr = NULL; /* XXX gcc */ + + ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ? + ifm->ifm_cur->ifm_media : IFM_NONE; + ifmr->ifm_mask = ifm->ifm_mask; + ifmr->ifm_status = 0; + (*ifm->ifm_status)(dev, ifmr); + + count = 0; + usermax = 0; + + /* + * If there are more interfaces on the list, count + * them. This allows the caller to set ifmr->ifm_count + * to 0 on the first call to know how much space to + * allocate. + */ + LIST_FOREACH(ep, &ifm->ifm_list, ifm_list) + usermax++; + + /* + * Don't allow the user to ask for too many + * or a negative number. + */ + if (ifmr->ifm_count > usermax) + ifmr->ifm_count = usermax; + else if (ifmr->ifm_count < 0) + return (EINVAL); + + if (ifmr->ifm_count != 0) { + kptr = (int *)kmalloc(ifmr->ifm_count * sizeof(int), + GFP_KERNEL); + + if (kptr == NULL) + return (ENOMEM); + /* + * Get the media words from the interface's list. + */ + ep = LIST_FIRST(&ifm->ifm_list); + for (; ep != NULL && count < ifmr->ifm_count; + ep = LIST_NEXT(ep, ifm_list), count++) + kptr[count] = ep->ifm_media; + + if (ep != NULL) + error = E2BIG; /* oops! */ + } else { + count = usermax; + } + + /* + * We do the copyout on E2BIG, because that's + * just our way of telling userland that there + * are more. This is the behavior I've observed + * under BSD/OS 3.0 + */ + sticky = error; + if ((error == 0 || error == E2BIG) && ifmr->ifm_count != 0) { + error = copy_to_user((caddr_t)ifmr->ifm_ulist, + (caddr_t)kptr, ifmr->ifm_count * sizeof(int)); + } + + if (error == 0) + error = sticky; + + if (ifmr->ifm_count != 0) + kfree(kptr); + + ifmr->ifm_count = count; + break; + } + + default: + return (EINVAL); + } + + return (error); +} + +/* + * Find media entry matching a given ifm word. + * + */ +struct ifmedia_entry * +ifmedia_match(struct ifmedia *ifm, int target, int mask) +{ + struct ifmedia_entry *match, *next; + + match = NULL; + mask = ~mask; + + LIST_FOREACH(next, &ifm->ifm_list, ifm_list) { + if ((next->ifm_media & mask) == (target & mask)) { +#if defined(IFMEDIA_DEBUG) || defined(DIAGNOSTIC) + if (match) { + printk("ifmedia_match: multiple match for " + "0x%x/0x%x\n", target, mask); + } +#endif + match = next; + } + } + + return match; +} + +#ifdef IFMEDIA_DEBUG +struct ifmedia_description ifm_type_descriptions[] = + IFM_TYPE_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_ethernet_descriptions[] = + IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = + IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_tokenring_descriptions[] = + IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = + IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_fddi_descriptions[] = + IFM_SUBTYPE_FDDI_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = + IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = + IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = + IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = + IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; + +struct ifmedia_description ifm_subtype_shared_descriptions[] = + IFM_SUBTYPE_SHARED_DESCRIPTIONS; + +struct ifmedia_description ifm_shared_option_descriptions[] = + IFM_SHARED_OPTION_DESCRIPTIONS; + +struct ifmedia_type_to_subtype { + struct ifmedia_description *subtypes; + struct ifmedia_description *options; + struct ifmedia_description *modes; +}; + +/* must be in the same order as IFM_TYPE_DESCRIPTIONS */ +struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { + { + &ifm_subtype_ethernet_descriptions[0], + &ifm_subtype_ethernet_option_descriptions[0], + NULL, + }, + { + &ifm_subtype_tokenring_descriptions[0], + &ifm_subtype_tokenring_option_descriptions[0], + NULL, + }, + { + &ifm_subtype_fddi_descriptions[0], + &ifm_subtype_fddi_option_descriptions[0], + NULL, + }, + { + &ifm_subtype_ieee80211_descriptions[0], + &ifm_subtype_ieee80211_option_descriptions[0], + &ifm_subtype_ieee80211_mode_descriptions[0] + }, +}; + +/* + * print a media word. + */ +static void +ifmedia_printword(int ifmw) +{ + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; + int seen_option = 0; + + /* Find the top-level interface type. */ + for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; + desc->ifmt_string != NULL; desc++, ttos++) + if (IFM_TYPE(ifmw) == desc->ifmt_word) + break; + if (desc->ifmt_string == NULL) { + printk("\n"); + return; + } + printk(desc->ifmt_string); + + /* Any mode. */ + for (desc = ttos->modes; desc && desc->ifmt_string != NULL; desc++) + if (IFM_MODE(ifmw) == desc->ifmt_word) { + if (desc->ifmt_string != NULL) + printk(" mode %s", desc->ifmt_string); + break; + } + + /* + * Check for the shared subtype descriptions first, then the + * type-specific ones. + */ + for (desc = ifm_subtype_shared_descriptions; + desc->ifmt_string != NULL; desc++) + if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) + goto got_subtype; + + for (desc = ttos->subtypes; desc->ifmt_string != NULL; desc++) + if (IFM_SUBTYPE(ifmw) == desc->ifmt_word) + break; + if (desc->ifmt_string == NULL) { + printk(" \n"); + return; + } + + got_subtype: + printk(" %s", desc->ifmt_string); + + /* + * Look for shared options. + */ + for (desc = ifm_shared_option_descriptions; + desc->ifmt_string != NULL; desc++) { + if (ifmw & desc->ifmt_word) { + if (seen_option == 0) + printk(" <"); + printk("%s%s", seen_option++ ? "," : "", + desc->ifmt_string); + } + } + + /* + * Look for subtype-specific options. + */ + for (desc = ttos->options; desc->ifmt_string != NULL; desc++) { + if (ifmw & desc->ifmt_word) { + if (seen_option == 0) + printk(" <"); + printk("%s%s", seen_option++ ? "," : "", + desc->ifmt_string); + } + } + printk("%s\n", seen_option ? ">" : ""); +} +#endif /* IFMEDIA_DEBUG */ + +EXPORT_SYMBOL(ifmedia_ioctl); diff -Nru a/drivers/net/wireless/atheros/wlan/if_media.h b/drivers/net/wireless/atheros/wlan/if_media.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_media.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,474 @@ +/* $NetBSD: if_media.h,v 1.3 1997/03/26 01:19:27 thorpej Exp $ */ +/* $FreeBSD: src/sys/net/if_media.h,v 1.18 2002/07/14 21:58:19 kbyanc Exp $ */ +/* $Id: if_media.h,v 1.5 2003/04/30 16:30:38 sam Exp $ */ + +/* + * Copyright (c) 1997 + * Jonathan Stone and Jason R. Thorpe. All rights reserved. + * + * This software is derived from information provided by Matt Thomas. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jonathan Stone + * and Jason R. Thorpe for the NetBSD Project. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NET_IF_MEDIA_H_ +#define _NET_IF_MEDIA_H_ + +/* + * Prototypes and definitions for BSD/OS-compatible network interface + * media selection. + * + * Where it is safe to do so, this code strays slightly from the BSD/OS + * design. Software which uses the API (device drivers, basically) + * shouldn't notice any difference. + * + * Many thanks to Matt Thomas for providing the information necessary + * to implement this interface. + */ + +struct ifmediareq { + char ifm_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + int ifm_current; /* current media options */ + int ifm_mask; /* don't care mask */ + int ifm_status; /* media status */ + int ifm_active; /* active options */ + int ifm_count; /* # entries in ifm_ulist array */ + int *ifm_ulist; /* media words */ +}; +#define SIOCSIFMEDIA _IOWR('i', 55, struct ifreq) /* set net media */ +#define SIOCGIFMEDIA _IOWR('i', 56, struct ifmediareq) /* get net media */ + +#ifdef __KERNEL__ + +#include "bsdcompat/queue.h" + +/* + * Driver callbacks for media status and change requests. + */ +struct net_device; +typedef int (*ifm_change_cb_t)(struct net_device *); +typedef void (*ifm_stat_cb_t)(struct net_device *, struct ifmediareq *req); + +/* + * In-kernel representation of a single supported media type. + */ +struct ifmedia_entry { + LIST_ENTRY(ifmedia_entry) ifm_list; + int ifm_media; /* description of this media attachment */ + int ifm_data; /* for driver-specific use */ + void *ifm_aux; /* for driver-specific use */ +}; + +/* + * One of these goes into a network interface's softc structure. + * It is used to keep general media state. + */ +struct ifmedia { + int ifm_mask; /* mask of changes we don't care about */ + int ifm_media; /* current user-set media word */ + struct ifmedia_entry *ifm_cur; /* currently selected media */ + LIST_HEAD(, ifmedia_entry) ifm_list; /* list of all supported media */ + ifm_change_cb_t ifm_change; /* media change driver callback */ + ifm_stat_cb_t ifm_status; /* media status driver callback */ +}; + +/* Initialize an interface's struct if_media field. */ +void ifmedia_init(struct ifmedia *ifm, int dontcare_mask, + ifm_change_cb_t change_callback, ifm_stat_cb_t status_callback); + +/* Remove all mediums from a struct ifmedia. */ +void ifmedia_removeall( struct ifmedia *ifm); + +/* Add one supported medium to a struct ifmedia. */ +void ifmedia_add(struct ifmedia *ifm, int mword, int data, void *aux); + +/* Add an array (of ifmedia_entry) media to a struct ifmedia. */ +void ifmedia_list_add(struct ifmedia *mp, struct ifmedia_entry *lp, + int count); + +/* Set default media type on initialization. */ +void ifmedia_set(struct ifmedia *ifm, int mword); + +/* Common ioctl function for getting/setting media, called by driver. */ +int ifmedia_ioctl(struct net_device *, struct ifreq *ifr, + struct ifmedia *ifm, u_long cmd); + +#endif /*_KERNEL */ + +/* + * if_media Options word: + * Bits Use + * ---- ------- + * 0-4 Media variant + * 5-7 Media type + * 8-15 Type specific options + * 16-18 Mode (for multi-mode devices) + * 19 RFU + * 20-27 Shared (global) options + * 28-31 Instance + */ + +/* + * Ethernet + */ +#define IFM_ETHER 0x00000020 +#define IFM_10_T 3 /* 10BaseT - RJ45 */ +#define IFM_10_2 4 /* 10Base2 - Thinnet */ +#define IFM_10_5 5 /* 10Base5 - AUI */ +#define IFM_100_TX 6 /* 100BaseTX - RJ45 */ +#define IFM_100_FX 7 /* 100BaseFX - Fiber */ +#define IFM_100_T4 8 /* 100BaseT4 - 4 pair cat 3 */ +#define IFM_100_VG 9 /* 100VG-AnyLAN */ +#define IFM_100_T2 10 /* 100BaseT2 */ +#define IFM_1000_SX 11 /* 1000BaseSX - multi-mode fiber */ +#define IFM_10_STP 12 /* 10BaseT over shielded TP */ +#define IFM_10_FL 13 /* 10BaseFL - Fiber */ +#define IFM_1000_LX 14 /* 1000baseLX - single-mode fiber */ +#define IFM_1000_CX 15 /* 1000baseCX - 150ohm STP */ +#define IFM_1000_T 16 /* 1000baseT - 4 pair cat 5 */ +#define IFM_HPNA_1 17 /* HomePNA 1.0 (1Mb/s) */ +/* note 31 is the max! */ + +#define IFM_ETH_MASTER 0x00000100 /* master mode (1000baseT) */ + +/* + * Token ring + */ +#define IFM_TOKEN 0x00000040 +#define IFM_TOK_STP4 3 /* Shielded twisted pair 4m - DB9 */ +#define IFM_TOK_STP16 4 /* Shielded twisted pair 16m - DB9 */ +#define IFM_TOK_UTP4 5 /* Unshielded twisted pair 4m - RJ45 */ +#define IFM_TOK_UTP16 6 /* Unshielded twisted pair 16m - RJ45 */ +#define IFM_TOK_STP100 7 /* Shielded twisted pair 100m - DB9 */ +#define IFM_TOK_UTP100 8 /* Unshielded twisted pair 100m - RJ45 */ +#define IFM_TOK_ETR 0x00000200 /* Early token release */ +#define IFM_TOK_SRCRT 0x00000400 /* Enable source routing features */ +#define IFM_TOK_ALLR 0x00000800 /* All routes / Single route bcast */ +#define IFM_TOK_DTR 0x00002000 /* Dedicated token ring */ +#define IFM_TOK_CLASSIC 0x00004000 /* Classic token ring */ +#define IFM_TOK_AUTO 0x00008000 /* Automatic Dedicate/Classic token ring */ + +/* + * FDDI + */ +#define IFM_FDDI 0x00000060 +#define IFM_FDDI_SMF 3 /* Single-mode fiber */ +#define IFM_FDDI_MMF 4 /* Multi-mode fiber */ +#define IFM_FDDI_UTP 5 /* CDDI / UTP */ +#define IFM_FDDI_DA 0x00000100 /* Dual attach / single attach */ + +/* + * IEEE 802.11 Wireless + */ +#define IFM_IEEE80211 0x00000080 +/* NB: 0,1,2 are auto, manual, none defined below */ +#define IFM_IEEE80211_FH1 3 /* Frequency Hopping 1Mbps */ +#define IFM_IEEE80211_FH2 4 /* Frequency Hopping 2Mbps */ +#define IFM_IEEE80211_DS1 5 /* Direct Sequence 1Mbps */ +#define IFM_IEEE80211_DS2 6 /* Direct Sequence 2Mbps */ +#define IFM_IEEE80211_DS5 7 /* Direct Sequence 5.5Mbps */ +#define IFM_IEEE80211_DS11 8 /* Direct Sequence 11Mbps */ +#define IFM_IEEE80211_DS22 9 /* Direct Sequence 22Mbps */ +#define IFM_IEEE80211_OFDM6 10 /* OFDM 6Mbps */ +#define IFM_IEEE80211_OFDM9 11 /* OFDM 9Mbps */ +#define IFM_IEEE80211_OFDM12 12 /* OFDM 12Mbps */ +#define IFM_IEEE80211_OFDM18 13 /* OFDM 18Mbps */ +#define IFM_IEEE80211_OFDM24 14 /* OFDM 24Mbps */ +#define IFM_IEEE80211_OFDM36 15 /* OFDM 36Mbps */ +#define IFM_IEEE80211_OFDM48 16 /* OFDM 48Mbps */ +#define IFM_IEEE80211_OFDM54 17 /* OFDM 54Mbps */ +#define IFM_IEEE80211_OFDM72 18 /* OFDM 72Mbps */ +#define IFM_IEEE80211_ADHOC 0x00000100 /* Operate in Adhoc mode */ +#define IFM_IEEE80211_HOSTAP 0x00000200 /* Operate in Host AP mode */ +#define IFM_IEEE80211_IBSS 0x00000400 /* Operate in IBSS mode */ +#define IFM_IEEE80211_IBSSMASTER 0x00000800 /* Operate as an IBSS master */ +#define IFM_IEEE80211_TURBO 0x00001000 /* Operate in turbo mode */ +/* operating mode for multi-mode devices */ +#define IFM_IEEE80211_11A 1 /* 5Ghz, OFDM mode */ +#define IFM_IEEE80211_11B 2 /* Direct Sequence mode */ +#define IFM_IEEE80211_11G 3 /* 2Ghz, CCK mode */ + +/* + * Shared media sub-types + */ +#define IFM_AUTO 0 /* Autoselect best media */ +#define IFM_MANUAL 1 /* Jumper/dipswitch selects media */ +#define IFM_NONE 2 /* Deselect all media */ + +/* + * Shared options + */ +#define IFM_FDX 0x00100000 /* Force full duplex */ +#define IFM_HDX 0x00200000 /* Force half duplex */ +#define IFM_FLAG0 0x01000000 /* Driver defined flag */ +#define IFM_FLAG1 0x02000000 /* Driver defined flag */ +#define IFM_FLAG2 0x04000000 /* Driver defined flag */ +#define IFM_LOOP 0x08000000 /* Put hardware in loopback */ + +/* + * Masks + */ +#define IFM_NMASK 0x000000e0 /* Network type */ +#define IFM_TMASK 0x0000001f /* Media sub-type */ +#define IFM_IMASK 0xf0000000 /* Instance */ +#define IFM_ISHIFT 28 /* Instance shift */ +#define IFM_OMASK 0x0000ff00 /* Type specific options */ +#define IFM_MMASK 0x00070000 /* Mode */ +#define IFM_MSHIFT 16 /* Mode shift */ +#define IFM_GMASK 0x0ff00000 /* Global options */ + +/* + * Status bits + */ +#define IFM_AVALID 0x00000001 /* Active bit valid */ +#define IFM_ACTIVE 0x00000002 /* Interface attached to working net */ + +/* + * Macros to extract various bits of information from the media word. + */ +#define IFM_TYPE(x) ((x) & IFM_NMASK) +#define IFM_SUBTYPE(x) ((x) & IFM_TMASK) +#define IFM_TYPE_OPTIONS(x) ((x) & IFM_OMASK) +#define IFM_INST(x) (((x) & IFM_IMASK) >> IFM_ISHIFT) +#define IFM_OPTIONS(x) ((x) & (IFM_OMASK|IFM_GMASK)) +#define IFM_MODE(x) (((x) & IFM_MMASK) >> IFM_MSHIFT) + +#define IFM_INST_MAX IFM_INST(IFM_IMASK) + +/* + * Macro to create a media word. + */ +#define IFM_MAKEWORD(type, subtype, options, instance) \ + ((type) | (subtype) | (options) | ((instance) << IFM_ISHIFT)) +#define IFM_MAKEMODE(mode) \ + (((mode) << IFM_MSHIFT) & IFM_MMASK) + +/* + * NetBSD extension not defined in the BSDI API. This is used in various + * places to get the canonical description for a given type/subtype. + * + * NOTE: all but the top-level type descriptions must contain NO whitespace! + * Otherwise, parsing these in ifconfig(8) would be a nightmare. + */ +struct ifmedia_description { + int ifmt_word; /* word value; may be masked */ + const char *ifmt_string; /* description */ +}; + +#define IFM_TYPE_DESCRIPTIONS { \ + { IFM_ETHER, "Ethernet" }, \ + { IFM_TOKEN, "Token ring" }, \ + { IFM_FDDI, "FDDI" }, \ + { IFM_IEEE80211, "IEEE 802.11 Wireless Ethernet" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_DESCRIPTIONS { \ + { IFM_10_T, "10baseT/UTP" }, \ + { IFM_10_2, "10base2/BNC" }, \ + { IFM_10_5, "10base5/AUI" }, \ + { IFM_100_TX, "100baseTX" }, \ + { IFM_100_FX, "100baseFX" }, \ + { IFM_100_T4, "100baseT4" }, \ + { IFM_100_VG, "100baseVG" }, \ + { IFM_100_T2, "100baseT2" }, \ + { IFM_10_STP, "10baseSTP" }, \ + { IFM_10_FL, "10baseFL" }, \ + { IFM_1000_SX, "1000baseSX" }, \ + { IFM_1000_LX, "1000baseLX" }, \ + { IFM_1000_CX, "1000baseCX" }, \ + { IFM_1000_T, "1000baseTX" }, \ + { IFM_1000_T, "1000baseT" }, \ + { IFM_HPNA_1, "homePNA" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_ALIASES { \ + { IFM_10_T, "UTP" }, \ + { IFM_10_T, "10UTP" }, \ + { IFM_10_2, "BNC" }, \ + { IFM_10_2, "10BNC" }, \ + { IFM_10_5, "AUI" }, \ + { IFM_10_5, "10AUI" }, \ + { IFM_100_TX, "100TX" }, \ + { IFM_100_T4, "100T4" }, \ + { IFM_100_VG, "100VG" }, \ + { IFM_100_T2, "100T2" }, \ + { IFM_10_STP, "10STP" }, \ + { IFM_10_FL, "10FL" }, \ + { IFM_1000_SX, "1000SX" }, \ + { IFM_1000_LX, "1000LX" }, \ + { IFM_1000_CX, "1000CX" }, \ + { IFM_1000_T, "1000TX" }, \ + { IFM_1000_T, "1000T" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS { \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_DESCRIPTIONS { \ + { IFM_TOK_STP4, "DB9/4Mbit" }, \ + { IFM_TOK_STP16, "DB9/16Mbit" }, \ + { IFM_TOK_UTP4, "UTP/4Mbit" }, \ + { IFM_TOK_UTP16, "UTP/16Mbit" }, \ + { IFM_TOK_STP100, "STP/100Mbit" }, \ + { IFM_TOK_UTP100, "UTP/100Mbit" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_ALIASES { \ + { IFM_TOK_STP4, "4STP" }, \ + { IFM_TOK_STP16, "16STP" }, \ + { IFM_TOK_UTP4, "4UTP" }, \ + { IFM_TOK_UTP16, "16UTP" }, \ + { IFM_TOK_STP100, "100STP" }, \ + { IFM_TOK_UTP100, "100UTP" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS { \ + { IFM_TOK_ETR, "EarlyTokenRelease" }, \ + { IFM_TOK_SRCRT, "SourceRouting" }, \ + { IFM_TOK_ALLR, "AllRoutes" }, \ + { IFM_TOK_DTR, "Dedicated" }, \ + { IFM_TOK_CLASSIC,"Classic" }, \ + { IFM_TOK_AUTO, " " }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_DESCRIPTIONS { \ + { IFM_FDDI_SMF, "Single-mode" }, \ + { IFM_FDDI_MMF, "Multi-mode" }, \ + { IFM_FDDI_UTP, "UTP" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_ALIASES { \ + { IFM_FDDI_SMF, "SMF" }, \ + { IFM_FDDI_MMF, "MMF" }, \ + { IFM_FDDI_UTP, "CDDI" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS { \ + { IFM_FDDI_DA, "Dual-attach" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_DESCRIPTIONS { \ + { IFM_IEEE80211_FH1, "FH/1Mbps" }, \ + { IFM_IEEE80211_FH2, "FH/2Mbps" }, \ + { IFM_IEEE80211_DS1, "DS/1Mbps" }, \ + { IFM_IEEE80211_DS2, "DS/2Mbps" }, \ + { IFM_IEEE80211_DS5, "DS/5.5Mbps" }, \ + { IFM_IEEE80211_DS11, "DS/11Mbps" }, \ + { IFM_IEEE80211_DS22, "DS/22Mbps" }, \ + { IFM_IEEE80211_OFDM6, "OFDM/6Mbps" }, \ + { IFM_IEEE80211_OFDM9, "OFDM/9Mbps" }, \ + { IFM_IEEE80211_OFDM12, "OFDM/12Mbps" }, \ + { IFM_IEEE80211_OFDM18, "OFDM/18Mbps" }, \ + { IFM_IEEE80211_OFDM24, "OFDM/24Mbps" }, \ + { IFM_IEEE80211_OFDM36, "OFDM/36Mbps" }, \ + { IFM_IEEE80211_OFDM48, "OFDM/48Mbps" }, \ + { IFM_IEEE80211_OFDM54, "OFDM/54Mbps" }, \ + { IFM_IEEE80211_OFDM72, "OFDM/72Mbps" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_ALIASES { \ + { IFM_IEEE80211_FH1, "FH1" }, \ + { IFM_IEEE80211_FH2, "FH2" }, \ + { IFM_IEEE80211_FH1, "FrequencyHopping/1Mbps" }, \ + { IFM_IEEE80211_FH2, "FrequencyHopping/2Mbps" }, \ + { IFM_IEEE80211_DS1, "DS1" }, \ + { IFM_IEEE80211_DS2, "DS2" }, \ + { IFM_IEEE80211_DS5, "DS5.5" }, \ + { IFM_IEEE80211_DS11, "DS11" }, \ + { IFM_IEEE80211_DS22, "DS22" }, \ + { IFM_IEEE80211_DS1, "DirectSequence/1Mbps" }, \ + { IFM_IEEE80211_DS2, "DirectSequence/2Mbps" }, \ + { IFM_IEEE80211_DS5, "DirectSequence/5.5Mbps" }, \ + { IFM_IEEE80211_DS11, "DirectSequence/11Mbps" }, \ + { IFM_IEEE80211_DS22, "DirectSequence/22Mbps" }, \ + { IFM_IEEE80211_OFDM6, "OFDM6" }, \ + { IFM_IEEE80211_OFDM9, "OFDM9" }, \ + { IFM_IEEE80211_OFDM12, "OFDM12" }, \ + { IFM_IEEE80211_OFDM18, "OFDM18" }, \ + { IFM_IEEE80211_OFDM24, "OFDM24" }, \ + { IFM_IEEE80211_OFDM36, "OFDM36" }, \ + { IFM_IEEE80211_OFDM48, "OFDM48" }, \ + { IFM_IEEE80211_OFDM54, "OFDM54" }, \ + { IFM_IEEE80211_OFDM72, "OFDM72" }, \ + { IFM_IEEE80211_DS1, "CCK1" }, \ + { IFM_IEEE80211_DS2, "CCK2" }, \ + { IFM_IEEE80211_DS5, "CCK5.5" }, \ + { IFM_IEEE80211_DS11, "CCK11" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS { \ + { IFM_IEEE80211_ADHOC, "adhoc" }, \ + { IFM_IEEE80211_HOSTAP, "hostap" }, \ + { IFM_IEEE80211_IBSS, "ibss" }, \ + { IFM_IEEE80211_IBSSMASTER, "ibss-master" }, \ + { IFM_IEEE80211_TURBO, "turbo" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS { \ + { IFM_IEEE80211_11A, "11a" }, \ + { IFM_IEEE80211_11B, "11b" }, \ + { IFM_IEEE80211_11G, "11g" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_SHARED_DESCRIPTIONS { \ + { IFM_AUTO, "autoselect" }, \ + { IFM_MANUAL, "manual" }, \ + { IFM_NONE, "none" }, \ + { 0, NULL }, \ +} + +#define IFM_SUBTYPE_SHARED_ALIASES { \ + { IFM_AUTO, "auto" }, \ + { 0, NULL }, \ +} + +#define IFM_SHARED_OPTION_DESCRIPTIONS { \ + { IFM_FDX, "full-duplex" }, \ + { IFM_HDX, "half-duplex" }, \ + { IFM_FLAG0, "flag0" }, \ + { IFM_FLAG1, "flag1" }, \ + { IFM_FLAG2, "flag2" }, \ + { IFM_LOOP, "hw-loopback" }, \ + { 0, NULL }, \ +} + +#endif /* _NET_IF_MEDIA_H_ */ diff -Nru a/drivers/net/wireless/atheros/wlan/if_wavelan_ieee.h b/drivers/net/wireless/atheros/wlan/if_wavelan_ieee.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/if_wavelan_ieee.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,748 @@ +/* + * Copyright (c) 1997, 1998, 1999 + * Bill Paul . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/dev/wi/if_wavelan_ieee.h,v 1.17 2003/01/15 20:11:31 sam Exp $ + * $Id: if_wavelan_ieee.h,v 1.2 2003/03/15 18:33:37 sam Exp $ + */ + +#ifndef _IF_WAVELAN_IEEE_H +#define _IF_WAVELAN_IEEE_H + +/* + * This header defines a simple command interface to the FreeBSD + * WaveLAN/IEEE driver (wi) driver, which is used to set certain + * device-specific parameters which can't be easily managed through + * ifconfig(8). No, sysctl(2) is not the answer. I said a _simple_ + * interface, didn't I. + */ + +#ifndef SIOCSWAVELAN +#define SIOCSWAVELAN SIOCSIFGENERIC +#endif + +#ifndef SIOCGWAVELAN +#define SIOCGWAVELAN SIOCGIFGENERIC +#endif + +/* + * Technically I don't think there's a limit to a record + * length. The largest record is the one that contains the CIS + * data, which is 240 words long, so 256 should be a safe + * value. + */ +#define WI_MAX_DATALEN 512 + +struct wi_req { + u_int16_t wi_len; + u_int16_t wi_type; + u_int16_t wi_val[WI_MAX_DATALEN]; +}; + +/* + * Private LTV records (interpreted only by the driver). This is + * a minor kludge to allow reading the interface statistics from + * the driver. + */ +#define WI_RID_IFACE_STATS 0x0100 +#define WI_RID_MGMT_XMIT 0x0200 +#define WI_RID_ZERO_CACHE 0x0300 +#define WI_RID_READ_CACHE 0x0400 +#define WI_RID_FWDOWNLOAD 0x0500 +#define WI_RID_MONITOR_MODE 0x0600 +#define WI_RID_MIF 0x0700 +#define WI_RID_SCAN_APS 0x0800 +#define WI_RID_READ_APS 0x0900 + +struct wi_80211_hdr { + u_int16_t frame_ctl; + u_int16_t dur_id; + u_int8_t addr1[6]; + u_int8_t addr2[6]; + u_int8_t addr3[6]; + u_int16_t seq_ctl; + u_int8_t addr4[6]; +}; + +#define WI_FCTL_VERS 0x0002 +#define WI_FCTL_FTYPE 0x000C +#define WI_FCTL_STYPE 0x00F0 +#define WI_FCTL_TODS 0x0100 +#define WI_FCTL_FROMDS 0x0200 +#define WI_FCTL_MOREFRAGS 0x0400 +#define WI_FCTL_RETRY 0x0800 +#define WI_FCTL_PM 0x1000 +#define WI_FCTL_MOREDATA 0x2000 +#define WI_FCTL_WEP 0x4000 +#define WI_FCTL_ORDER 0x8000 + +#define WI_FTYPE_MGMT 0x0000 +#define WI_FTYPE_CTL 0x0004 +#define WI_FTYPE_DATA 0x0008 + +#define WI_STYPE_MGMT_ASREQ 0x0000 /* association request */ +#define WI_STYPE_MGMT_ASRESP 0x0010 /* association response */ +#define WI_STYPE_MGMT_REASREQ 0x0020 /* reassociation request */ +#define WI_STYPE_MGMT_REASRESP 0x0030 /* reassociation response */ +#define WI_STYPE_MGMT_PROBEREQ 0x0040 /* probe request */ +#define WI_STYPE_MGMT_PROBERESP 0x0050 /* probe response */ +#define WI_STYPE_MGMT_BEACON 0x0080 /* beacon */ +#define WI_STYPE_MGMT_ATIM 0x0090 /* announcement traffic ind msg */ +#define WI_STYPE_MGMT_DISAS 0x00A0 /* disassociation */ +#define WI_STYPE_MGMT_AUTH 0x00B0 /* authentication */ +#define WI_STYPE_MGMT_DEAUTH 0x00C0 /* deauthentication */ + +#define WI_STYPE_CTL_PSPOLL 0x00A0 +#define WI_STYPE_CTL_RTS 0x00B0 +#define WI_STYPE_CTL_CTS 0x00C0 +#define WI_STYPE_CTL_ACK 0x00D0 +#define WI_STYPE_CTL_CFEND 0x00E0 +#define WI_STYPE_CTL_CFENDACK 0x00F0 + +struct wi_mgmt_hdr { + u_int16_t frame_ctl; + u_int16_t duration; + u_int8_t dst_addr[6]; + u_int8_t src_addr[6]; + u_int8_t bssid[6]; + u_int16_t seq_ctl; +}; + +/* + * Lucent/wavelan IEEE signal strength cache + * + * driver keeps cache of last + * MAXWICACHE packets to arrive including signal strength info. + * daemons may read this via ioctl + * + * Each entry in the wi_sigcache has a unique macsrc. + */ +struct wi_sigcache { + char macsrc[6]; /* unique MAC address for entry */ + int ipsrc; /* ip address associated with packet */ + int signal; /* signal strength of the packet */ + int noise; /* noise value */ + int quality; /* quality of the packet */ +}; + +/* + * Firmware downloading API. We support downloading into RAM and into + * flash. We copy the entire .hex file for both the primary and secondary + * firmware into the kernel, which is minorly gross, but matches the + * format of the compiled in firmware. + */ +struct wi_fwdownload { + int type; /* What type of download. */ +#define WI_FW_RAM 1 +#define WI_FW_FLASH 2 + size_t pri_len; /* Primary firmware length */ + size_t sec_len; /* Secondary firmware length */ + caddr_t pri_data; /* Pointer (user) to primary data */ + caddr_t sec_data; /* Pointer (user) to secondary data */ +}; + +struct wi_counters { + u_int32_t wi_tx_unicast_frames; + u_int32_t wi_tx_multicast_frames; + u_int32_t wi_tx_fragments; + u_int32_t wi_tx_unicast_octets; + u_int32_t wi_tx_multicast_octets; + u_int32_t wi_tx_deferred_xmits; + u_int32_t wi_tx_single_retries; + u_int32_t wi_tx_multi_retries; + u_int32_t wi_tx_retry_limit; + u_int32_t wi_tx_discards; + u_int32_t wi_rx_unicast_frames; + u_int32_t wi_rx_multicast_frames; + u_int32_t wi_rx_fragments; + u_int32_t wi_rx_unicast_octets; + u_int32_t wi_rx_multicast_octets; + u_int32_t wi_rx_fcs_errors; + u_int32_t wi_rx_discards_nobuf; + u_int32_t wi_tx_discards_wrong_sa; + u_int32_t wi_rx_WEP_cant_decrypt; + u_int32_t wi_rx_msg_in_msg_frags; + u_int32_t wi_rx_msg_in_bad_msg_frags; +}; + +/* + * Network parameters, static configuration entities. + */ +#define WI_RID_PORTTYPE 0xFC00 /* Connection control characteristics */ +#define WI_RID_MAC_NODE 0xFC01 /* MAC address of this station */ +#define WI_RID_DESIRED_SSID 0xFC02 /* Service Set ID for connection */ +#define WI_RID_OWN_CHNL 0xFC03 /* Comm channel for BSS creation */ +#define WI_RID_OWN_SSID 0xFC04 /* IBSS creation ID */ +#define WI_RID_OWN_ATIM_WIN 0xFC05 /* ATIM window time for IBSS creation */ +#define WI_RID_SYSTEM_SCALE 0xFC06 /* scale that specifies AP density */ +#define WI_RID_MAX_DATALEN 0xFC07 /* Max len of MAC frame body data */ +#define WI_RID_MAC_WDS 0xFC08 /* MAC addr of corresponding WDS node */ +#define WI_RID_PM_ENABLED 0xFC09 /* ESS power management enable */ +#define WI_RID_PM_EPS 0xFC0A /* PM EPS/PS mode */ +#define WI_RID_MCAST_RX 0xFC0B /* ESS PM mcast reception */ +#define WI_RID_MAX_SLEEP 0xFC0C /* max sleep time for ESS PM */ +#define WI_RID_HOLDOVER 0xFC0D /* holdover time for ESS PM */ +#define WI_RID_NODENAME 0xFC0E /* ID name of this node for diag */ +#define WI_RID_DTIM_PERIOD 0xFC10 /* beacon interval between DTIMs */ +#define WI_RID_WDS_ADDR1 0xFC11 /* port 1 MAC of WDS link node */ +#define WI_RID_WDS_ADDR2 0xFC12 /* port 1 MAC of WDS link node */ +#define WI_RID_WDS_ADDR3 0xFC13 /* port 1 MAC of WDS link node */ +#define WI_RID_WDS_ADDR4 0xFC14 /* port 1 MAC of WDS link node */ +#define WI_RID_WDS_ADDR5 0xFC15 /* port 1 MAC of WDS link node */ +#define WI_RID_WDS_ADDR6 0xFC16 /* port 1 MAC of WDS link node */ +#define WI_RID_MCAST_PM_BUF 0xFC17 /* PM buffering of mcast */ +#define WI_RID_ENCRYPTION 0xFC20 /* enable/disable WEP */ +#define WI_RID_AUTHTYPE 0xFC21 /* specify authentication type */ +#define WI_RID_P2_TX_CRYPT_KEY 0xFC23 +#define WI_RID_P2_CRYPT_KEY0 0xFC24 +#define WI_RID_P2_CRYPT_KEY1 0xFC25 +#define WI_RID_MICROWAVE_OVEN 0xFC25 +#define WI_RID_P2_CRYPT_KEY2 0xFC26 +#define WI_RID_P2_CRYPT_KEY3 0xFC27 +#define WI_RID_P2_ENCRYPTION 0xFC28 +#define PRIVACY_INVOKED 0x01 +#define EXCLUDE_UNENCRYPTED 0x02 +#define HOST_ENCRYPT 0x10 +#define IV_EVERY_FRAME 0x00 /* IV = Initialization Vector */ +#define IV_EVERY10_FRAME 0x20 /* every 10 frame IV reuse */ +#define IV_EVERY50_FRAME 0x40 /* every 50 frame IV reuse */ +#define IV_EVERY100_FRAME 0x60 /* every 100 frame IV reuse */ +#define HOST_DECRYPT 0x80 +#define WI_RID_WEP_MAPTABLE 0xFC29 +#define WI_RID_CNFAUTHMODE 0xFC2A +#define WI_RID_ROAMING_MODE 0xFC2D +#define WI_RID_OWN_BEACON_INT 0xFC33 /* beacon xmit time for BSS creation */ +#define WI_RID_CNF_DBM_ADJUST 0xFC46 +#define WI_RID_DBM_ADJUST 0xFC46 /* RSSI - WI_RID_DBM_ADJUST ~ dBm */ +#define WI_RID_BASIC_RATE 0xFCB3 +#define WI_RID_SUPPORT_RATE 0xFCB4 + +/* + * Network parameters, dynamic configuration entities + */ +#define WI_RID_MCAST_LIST 0xFC80 /* list of multicast addrs */ +#define WI_RID_CREATE_IBSS 0xFC81 /* create IBSS */ +#define WI_RID_FRAG_THRESH 0xFC82 /* frag len, unicast msg xmit */ +#define WI_RID_RTS_THRESH 0xFC83 /* frame len for RTS/CTS handshake */ +#define WI_RID_TX_RATE 0xFC84 /* data rate for message xmit + * 0 == Fixed 1mbps + * 1 == Fixed 2mbps + * 2 == auto fallback + */ +#define WI_RID_PROMISC 0xFC85 /* enable promisc mode */ +#define WI_RID_FRAG_THRESH0 0xFC90 +#define WI_RID_FRAG_THRESH1 0xFC91 +#define WI_RID_FRAG_THRESH2 0xFC92 +#define WI_RID_FRAG_THRESH3 0xFC93 +#define WI_RID_FRAG_THRESH4 0xFC94 +#define WI_RID_FRAG_THRESH5 0xFC95 +#define WI_RID_FRAG_THRESH6 0xFC96 +#define WI_RID_RTS_THRESH0 0xFC97 +#define WI_RID_RTS_THRESH1 0xFC98 +#define WI_RID_RTS_THRESH2 0xFC99 +#define WI_RID_RTS_THRESH3 0xFC9A +#define WI_RID_RTS_THRESH4 0xFC9B +#define WI_RID_RTS_THRESH5 0xFC9C +#define WI_RID_RTS_THRESH6 0xFC9D +#define WI_RID_TX_RATE0 0xFC9E +#define WI_RID_TX_RATE1 0xFC9F +#define WI_RID_TX_RATE2 0xFCA0 +#define WI_RID_TX_RATE3 0xFCA1 +#define WI_RID_TX_RATE4 0xFCA2 +#define WI_RID_TX_RATE5 0xFCA3 +#define WI_RID_TX_RATE6 0xFCA4 +#define WI_RID_DEFLT_CRYPT_KEYS 0xFCB0 +#define WI_RID_TX_CRYPT_KEY 0xFCB1 +#define WI_RID_TICK_TIME 0xFCE0 + +struct wi_key { + u_int16_t wi_keylen; + u_int8_t wi_keydat[14]; +}; + +#define WI_NLTV_KEYS 4 +struct wi_ltv_keys { + u_int16_t wi_len; + u_int16_t wi_type; + struct wi_key wi_keys[WI_NLTV_KEYS]; +}; + +/* + * NIC information + */ +#define WI_RID_DNLD_BUF 0xFD01 +#define WI_RID_MEMSZ 0xFD02 /* memory size info (XXX Lucent) */ + /* Looks like on lucnet pri firm too */ +#define WI_RID_PRI_IDENTITY 0xFD02 /* primary funcs firmware ident (PRISM2) */ +#define WI_RID_PRI_SUP_RANGE 0xFD03 /* primary supplier compatibility */ +#define WI_RID_CIF_ACT_RANGE 0xFD04 /* controller sup. compatibility */ +#define WI_RID_SERIALNO 0xFD0A /* card serial number */ +#define WI_RID_CARD_ID 0xFD0B /* card identification */ +#define WI_RID_MFI_SUP_RANGE 0xFD0C /* modem supplier compatibility */ +#define WI_RID_CFI_SUP_RANGE 0xFD0D /* controller sup. compatibility */ +#define WI_RID_CHANNEL_LIST 0xFD10 /* allowd comm. frequencies. */ +#define WI_RID_REG_DOMAINS 0xFD11 /* list of intendted regulatory doms */ +#define WI_RID_TEMP_TYPE 0xFD12 /* hw temp range code */ +#define WI_RID_CIS 0xFD13 /* PC card info struct */ +#define WI_RID_STA_IDENTITY 0xFD20 /* station funcs firmware ident */ +#define WI_RID_STA_SUP_RANGE 0xFD21 /* station supplier compat */ +#define WI_RID_MFI_ACT_RANGE 0xFD22 +#define WI_RID_SYMBOL_IDENTITY 0xFD24 +#define WI_RID_CFI_ACT_RANGE 0xFD33 +#define WI_RID_COMMQUAL 0xFD43 +#define WI_RID_SCALETHRESH 0xFD46 +#define WI_RID_PCF 0xFD87 + +/* + * MAC information + */ +#define WI_RID_PORT_STAT 0xFD40 /* actual MAC port con control stat */ +#define WI_RID_CURRENT_SSID 0xFD41 /* ID of actually connected SS */ +#define WI_RID_CURRENT_BSSID 0xFD42 /* ID of actually connected BSS */ +#define WI_RID_COMMS_QUALITY 0xFD43 /* quality of BSS connection */ +#define WI_RID_CUR_TX_RATE 0xFD44 /* current TX rate */ +#define WI_RID_CUR_BEACON_INT 0xFD45 /* current beacon interval */ +#define WI_RID_CUR_SCALE_THRESH 0xFD46 /* actual system scane thresh setting */ +#define WI_RID_PROT_RESP_TIME 0xFD47 /* time to wait for resp to req msg */ +#define WI_RID_SHORT_RTR_LIM 0xFD48 /* max tx attempts for short frames */ +#define WI_RID_LONG_RTS_LIM 0xFD49 /* max tx attempts for long frames */ +#define WI_RID_MAX_TX_LIFE 0xFD4A /* max tx frame handling duration */ +#define WI_RID_MAX_RX_LIFE 0xFD4B /* max rx frame handling duration */ +#define WI_RID_CF_POLL 0xFD4C /* contention free pollable ind */ +#define WI_RID_AUTH_ALGS 0xFD4D /* auth algorithms available */ +#define WI_RID_AUTH_TYPE 0xFD4E /* availanle auth types */ +#define WI_RID_WEP_AVAIL 0xFD4F /* WEP privacy option available */ +#define WI_RID_DBM_COMMS_QUAL 0xFD51 /* CommQuality normalized to dBm */ +#define WI_RID_CUR_TX_RATE1 0xFD80 +#define WI_RID_CUR_TX_RATE2 0xFD81 +#define WI_RID_CUR_TX_RATE3 0xFD82 +#define WI_RID_CUR_TX_RATE4 0xFD83 +#define WI_RID_CUR_TX_RATE5 0xFD84 +#define WI_RID_CUR_TX_RATE6 0xFD85 +#define WI_RID_OWN_MAC 0xFD86 /* unique local MAC addr */ +#define WI_RID_PCI_INFO 0xFD87 /* point coordination func cap */ + +/* + * Scan Information + */ +#define WI_RID_BCAST_SCAN_REQ 0xFCAB /* Broadcast Scan request (Symbol) */ +#define BSCAN_5SEC 0x01 +#define BSCAN_ONETIME 0x02 +#define BSCAN_PASSIVE 0x40 +#define BSCAN_BCAST 0x80 +#define WI_RID_SCAN_REQ 0xFCE1 /* Scan request (STA only) */ +#define WI_RID_JOIN_REQ 0xFCE2 /* Join request (STA only) */ +#define WI_RID_AUTH_STATION 0xFCE3 /* Authenticates Station (AP) */ +#define WI_RID_CHANNEL_REQ 0xFCE4 /* Channel Information Request (AP) */ +#define WI_RID_SCAN_RESULTS 0xFD88 /* Scan Results Table */ + +struct wi_apinfo { + int scanreason; /* ScanReason */ + char bssid[6]; /* BSSID (mac address) */ + int channel; /* Channel */ + int signal; /* Signal level */ + int noise; /* Average Noise Level*/ + int quality; /* Quality */ + int namelen; /* Length of SSID string */ + char name[32]; /* SSID string */ + int capinfo; /* Capability info. */ + int interval; /* BSS Beacon Interval */ + int rate; /* Data Rate */ +}; + +/* + * Modem information + */ +#define WI_RID_PHY_TYPE 0xFDC0 /* phys layer type indication */ +#define WI_RID_CURRENT_CHAN 0xFDC1 /* current frequency */ +#define WI_RID_PWR_STATE 0xFDC2 /* pwr consumption status */ +#define WI_RID_CCA_MODE 0xFDC3 /* clear chan assess mode indication */ +#define WI_RID_CCA_TIME 0xFDC4 /* clear chan assess time */ +#define WI_RID_MAC_PROC_DELAY 0xFDC5 /* MAC processing delay time */ +#define WI_RID_DATA_RATES 0xFDC6 /* supported data rates */ + +/* + * bsd-airtools v0.2 - source-mods v0.2 [common.h] + * by h1kari - (c) Dachb0den Labs 2001 + */ + +/* + * Copyright (c) 2001 Dachb0den Labs. + * David Hulton . All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by David Hulton. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY David Hulton AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL David Hulton OR THE VOICES IN HIS HEAD + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * standard hermes recieve frame used by wavelan/prism2 cards + */ +struct wi_rx_frame { + /* + * hermes prefix header. supplies information on the current status of + * the network and various other statistics gathered from the + * management/control frames as used internally. + */ + u_int16_t wi_status; + u_int16_t wi_ts0; + u_int16_t wi_ts1; + u_int8_t wi_silence; + u_int8_t wi_signal; + u_int8_t wi_rate; + u_int8_t wi_rx_flow; + u_int16_t wi_rsvd0; + u_int16_t wi_rsvd1; + /* + * standard 80211 frame header. all packets have to use this header as + * per the AN9900 from intersil, even management/control. for + * management packets, they just threw the header into the data field, + * but for control packets the headers are lost in translation and + * therefore not all control packet info can be displayed. + */ + u_int16_t wi_frame_ctl; + u_int16_t wi_id; + u_int8_t wi_addr1[6]; + u_int8_t wi_addr2[6]; + u_int8_t wi_addr3[6]; + u_int16_t wi_seq_ctl; + u_int8_t wi_addr4[6]; + u_int16_t wi_dat_len; + /* + * another wierdity with the drivers. they append a 802.3 header which + * is somewhat redundant, since all the same data is provided in the + * 802.11 header. + */ + u_int8_t wi_dst_addr[6]; + u_int8_t wi_src_addr[6]; + u_int16_t wi_len; +}; +#define WI_DATA_HDRLEN WI_802_11_OFFSET +#define WI_MGMT_HDRLEN WI_802_11_OFFSET_RAW +#define WI_CTL_HDRLEN WI_802_11_OFFSET_RAW + + +/* + * all data packets have a snap (sub-network access protocol) header that + * isn't entirely definied, but added for ethernet compatibility. + */ +struct wi_snap_frame { + u_int16_t wi_dat[3]; + u_int16_t wi_type; +}; + + +/* + * management frame headers + * note: all management frames consist of a static header and variable length + * fields. + */ + +/* + * variable length field structure + */ +struct wi_mgmt_var_hdr { + u_int8_t wi_code; + u_int8_t wi_len; + u_int8_t wi_data[256]; +}; + +/* + * management beacon frame prefix + */ +struct wi_mgmt_beacon_hdr { + u_int32_t wi_ts0; + u_int32_t wi_ts1; + u_int16_t wi_interval; + u_int16_t wi_capinfo; +}; + +/* + * ibss announcement traffic indication message (atim) frame + * note: no parameters + */ + +/* + * management disassociation frame + */ +struct wi_mgmt_disas_hdr { + u_int16_t wi_reason; +}; + +/* + * management association request frame prefix + */ +struct wi_mgmt_asreq_hdr { + u_int16_t wi_capinfo; + u_int16_t wi_interval; +}; + +/* + * management association response frame prefix + */ +struct wi_mgmt_asresp_hdr { + u_int16_t wi_capinfo; + u_int16_t wi_status; + u_int16_t wi_aid; +}; + +/* + * management reassociation request frame prefix + */ +struct wi_mgmt_reasreq_hdr { + u_int16_t wi_capinfo; + u_int16_t wi_interval; + u_int8_t wi_currap[6]; +}; + +/* + * management reassociation response frame prefix + */ +struct wi_mgmt_reasresp_hdr { + u_int16_t wi_capinfo; + u_int16_t wi_status; + u_int16_t wi_aid; +}; + +/* + * management probe request frame prefix + * note: no static parameters, only variable length + */ + +/* + * management probe response frame prefix + */ +struct wi_mgmt_proberesp_hdr { + u_int32_t wi_ts0; + u_int32_t wi_ts1; + u_int16_t wi_interval; + u_int16_t wi_capinfo; +}; + +/* + * management authentication frame prefix + */ +struct wi_mgmt_auth_hdr { + u_int16_t wi_algo; + u_int16_t wi_seq; + u_int16_t wi_status; +}; + +/* + * management deauthentication frame + */ +struct wi_mgmt_deauth_hdr { + u_int16_t wi_reason; +}; + + +/* + * rid configuration register definitions + */ +#define WI_RID_SCAN_REQ 0xFCE1 /* scan request information */ +#define WI_RID_SCAN_RES 0xFD88 /* scan result information */ + +#define WI_RID_PROCFRAME 0x3137 /* Return full frame information */ +#define WI_RID_PRISM2 0x3138 /* tell if we're a prism2 card or not */ + + +/* + * 802.11 definitions + */ +#define WI_STAT_BADCRC 0x0001 +#define WI_STAT_UNDECRYPTABLE 0x0002 +#define WI_STAT_ERRSTAT 0x0003 +#define WI_STAT_MAC_PORT 0x0700 +#define WI_STAT_1042 0x2000 +#define WI_STAT_TUNNEL 0x4000 +#define WI_STAT_WMP_MSG 0x6000 +#define WI_RXSTAT_MSG_TYPE 0xE000 + +#define WI_FCTL_OPT_MASK 0xFF00 +#define WI_AID_SET 0xC000 +#define WI_AID_MASK 0x3FFF +#define WI_SCTL_FRAGNUM_MASK 0x000F +#define WI_SCTL_SEQNUM_MASK 0xFFF0 + +#define WI_STAT_UNSPEC_FAIL 1 +#define WI_STAT_CAPINFO_FAIL 10 +#define WI_STAT_REAS_DENY 11 +#define WI_STAT_ASSOC_DENY 12 +#define WI_STAT_ALGO_FAIL 13 +#define WI_STAT_SEQ_FAIL 14 +#define WI_STAT_CHAL_FAIL 15 +#define WI_STAT_TOUT_FAIL 16 +#define WI_STAT_OVERL_DENY 17 +#define WI_STAT_RATE_DENY 18 + +#define WI_FTYPE_MGMT 0x0000 +#define WI_FTYPE_CTL 0x0004 +#define WI_FTYPE_DATA 0x0008 + +#define WI_FCTL_VERS 0x0002 +#define WI_FCTL_FTYPE 0x000C +#define WI_FCTL_STYPE 0x00F0 +#define WI_FCTL_TODS 0x0100 +#define WI_FCTL_FROMDS 0x0200 +#define WI_FCTL_MOREFRAGS 0x0400 +#define WI_FCTL_RETRY 0x0800 +#define WI_FCTL_PM 0x1000 +#define WI_FCTL_MOREDATA 0x2000 +#define WI_FCTL_WEP 0x4000 +#define WI_FCTL_ORDER 0x8000 + +#define WI_FCS_LEN 0x4 /* checksum length */ + + +/* + * management definitions + */ +#define WI_STYPE_MGMT_ASREQ 0x0000 +#define WI_STYPE_MGMT_ASRESP 0x0010 +#define WI_STYPE_MGMT_REASREQ 0x0020 +#define WI_STYPE_MGMT_REASRESP 0x0030 +#define WI_STYPE_MGMT_PROBEREQ 0x0040 +#define WI_STYPE_MGMT_PROBERESP 0x0050 +#define WI_STYPE_MGMT_BEACON 0x0080 +#define WI_STYPE_MGMT_ATIM 0x0090 +#define WI_STYPE_MGMT_DISAS 0x00A0 +#define WI_STYPE_MGMT_AUTH 0x00B0 +#define WI_STYPE_MGMT_DEAUTH 0x00C0 + +#define WI_CAPINFO_ESS 0x01 +#define WI_CAPINFO_IBSS 0x02 +#define WI_CAPINFO_CFPOLL 0x04 +#define WI_CAPINFO_CFPOLLREQ 0x08 +#define WI_CAPINFO_PRIV 0x10 + +#define WI_REASON_UNSPEC 1 +#define WI_REASON_AUTH_INVALID 2 +#define WI_REASON_DEAUTH_LEAVE 3 +#define WI_REASON_DISAS_INACT 4 +#define WI_REASON_DISAS_OVERL 5 +#define WI_REASON_CLASS2 6 +#define WI_REASON_CLASS3 7 +#define WI_REASON_DISAS_LEAVE 8 +#define WI_REASON_NOAUTH 9 + +#define WI_VAR_SSID 0 +#define WI_VAR_SRATES 1 +#define WI_VAR_FH 2 +#define WI_VAR_DS 3 +#define WI_VAR_CF 4 +#define WI_VAR_TIM 5 +#define WI_VAR_IBSS 6 +#define WI_VAR_CHAL 16 + +#define WI_VAR_SRATES_MASK 0x7F + + +/* + * control definitions + */ +#define WI_STYPE_CTL_PSPOLL 0x00A0 +#define WI_STYPE_CTL_RTS 0x00B0 +#define WI_STYPE_CTL_CTS 0x00C0 +#define WI_STYPE_CTL_ACK 0x00D0 +#define WI_STYPE_CTL_CFEND 0x00E0 +#define WI_STYPE_CTL_CFENDCFACK 0x00F0 + + +/* + * ap scanning structures + */ +struct wi_scan_res { + u_int16_t wi_chan; + u_int16_t wi_noise; + u_int16_t wi_signal; + u_int8_t wi_bssid[6]; + u_int16_t wi_interval; + u_int16_t wi_capinfo; + u_int16_t wi_ssid_len; + u_int8_t wi_ssid[32]; + u_int8_t wi_srates[10]; + u_int8_t wi_rate; + u_int8_t wi_rsvd; +}; +#define WI_WAVELAN_RES_SIZE 50 + +struct wi_scan_p2_hdr { + u_int16_t wi_rsvd; + u_int16_t wi_reason; +}; +#define WI_PRISM2_RES_SIZE 62 + + +/* + * prism2 debug mode definitions + */ +#define SIOCSPRISM2DEBUG _IOW('i', 137, struct ifreq) +#define SIOCGPRISM2DEBUG _IOWR('i', 138, struct ifreq) + +#define WI_DEBUG_RESET 0x00 +#define WI_DEBUG_INIT 0x01 +#define WI_DEBUG_SLEEP 0x02 +#define WI_DEBUG_WAKE 0x03 +#define WI_DEBUG_CHAN 0x08 +#define WI_DEBUG_DELAYSUPP 0x09 +#define WI_DEBUG_TXSUPP 0x0A +#define WI_DEBUG_MONITOR 0x0B +#define WI_DEBUG_LEDTEST 0x0C +#define WI_DEBUG_CONTTX 0x0E +#define WI_DEBUG_STOPTEST 0x0F +#define WI_DEBUG_CONTRX 0x10 +#define WI_DEBUG_SIGSTATE 0x11 +#define WI_DEBUG_CALENABLE 0x13 +#define WI_DEBUG_CONFBITS 0x15 + +#endif diff -Nru a/drivers/net/wireless/atheros/wlan/rc4.c b/drivers/net/wireless/atheros/wlan/rc4.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/rc4.c Wed Jul 30 18:20:27 2003 @@ -0,0 +1,104 @@ +/* + * rc4.c + * + * Copyright (c) 1996-2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/crypto/rc4/rc4.c,v 1.4 2003/01/15 19:55:16 sam Exp $ + * $Id: rc4.c,v 1.2 2003/03/15 18:33:37 sam Exp $ + */ + +#include + +#include "rc4.h" + +static __inline void +swap_bytes(u_char *a, u_char *b) +{ + u_char temp; + + temp = *a; + *a = *b; + *b = temp; +} + +/* + * Initialize an RC4 state buffer using the supplied key, + * which can have arbitrary length. + */ +void +rc4_init(struct rc4_state *const state, const u_char *key, int keylen) +{ + u_char j; + int i; + + /* Initialize state with identity permutation */ + for (i = 0; i < 256; i++) + state->perm[i] = (u_char)i; + state->index1 = 0; + state->index2 = 0; + + /* Randomize the permutation using key data */ + for (j = i = 0; i < 256; i++) { + j += state->perm[i] + key[i % keylen]; + swap_bytes(&state->perm[i], &state->perm[j]); + } +} + +/* + * Encrypt some data using the supplied RC4 state buffer. + * The input and output buffers may be the same buffer. + * Since RC4 is a stream cypher, this function is used + * for both encryption and decryption. + */ +void +rc4_crypt(struct rc4_state *const state, + const u_char *inbuf, u_char *outbuf, int buflen) +{ + int i; + u_char j; + + for (i = 0; i < buflen; i++) { + + /* Update modification indicies */ + state->index1++; + state->index2 += state->perm[state->index1]; + + /* Modify permutation */ + swap_bytes(&state->perm[state->index1], + &state->perm[state->index2]); + + /* Encrypt/decrypt next byte */ + j = state->perm[state->index1] + state->perm[state->index2]; + outbuf[i] = inbuf[i] ^ state->perm[j]; + } +} diff -Nru a/drivers/net/wireless/atheros/wlan/rc4.h b/drivers/net/wireless/atheros/wlan/rc4.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/rc4.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,54 @@ +/* + * rc4.h + * + * Copyright (c) 1996-2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * $FreeBSD: src/sys/crypto/rc4/rc4.h,v 1.3 2000/07/16 05:53:14 peter Exp $ + * $Id: rc4.h,v 1.2 2003/03/15 18:33:38 sam Exp $ + */ + +#ifndef _SYS_CRYPTO_RC4_RC4_H_ +#define _SYS_CRYPTO_RC4_RC4_H_ + +struct rc4_state { + u_char perm[256]; + u_char index1; + u_char index2; +}; + +extern void rc4_init(struct rc4_state *state, const u_char *key, int keylen); +extern void rc4_crypt(struct rc4_state *state, + const u_char *inbuf, u_char *outbuf, int buflen); + +#endif + diff -Nru a/drivers/net/wireless/atheros/wlan/version.h b/drivers/net/wireless/atheros/wlan/version.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atheros/wlan/version.h Wed Jul 30 18:20:27 2003 @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $Id: version.h,v 1.7 2003/05/19 04:51:31 sam Exp $ + */ +#define WLAN_VERSION "0.7.0.0"