diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2005-08-25 01:05:33 -0400 |
---|---|---|
committer | James Ketrenos <jketreno@linux.intel.com> | 2005-11-07 18:50:11 -0500 |
commit | afbf30a2b78cac38e6ddae10a73063943b4783ee (patch) | |
tree | 24c583520cdb77e22631741358831e10c865bde0 /drivers/net/wireless/ipw2200.c | |
parent | e4cc28998724661c19cd979a78eaf9a424da52ef (diff) |
Catch ipw2200 up to equivelancy with v1.0.5
* Fixed #452 problem with setting retry limit (thanks to Hong Liu)
* Fixed #592 race condition during association causing firmware errors
* Fixed #602 problem with building in 64-bit environment
* Fixed #625 problem with SCAN_REQUEST_EXT sometimes failing
* Fixed #645 problem with bit rate not decreasing when moving laptop
farther from AP
* Fixed #656 problem with 'iwconfig eth1 mode auto' and 'modprobe'
locking the system
* Fixed #667 problem with "No space for Tx" for hwcrypto=1
* Fixed #685 kernel panic in rmmod caused by led work is still queued
* Fixed #695 problem with network doesn't reassociate after suspend/resume
* Fixed #701 problem with 'iwprvi sw_reset' not resetting the card from
monitor mode
* Fixed #710 problem with monitor mode being used after a WEP key has
been configured
* Fixed network->mode vs. priv->ieee->iw_mode checking (thanks to Ben Cahill)
* Fixed "Unknown management packet %d" warning
* Fixed setting channels multiple times in monitor mode causes scan stopped
* Fixed ipw_wx_sw_reset doesn't switch firmware if mode is changed.
* Add duplicate packet checking code (kill ping DUP! and TKIP replay warning)
* Fix hardware encryption (both WEP and AES) doesn't work with fragmentation.
Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
Diffstat (limited to 'drivers/net/wireless/ipw2200.c')
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 1508 |
1 files changed, 1083 insertions, 425 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 0a583afbcddf..1b6f0277a3e9 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /****************************************************************************** | 1 | /****************************************************************************** |
2 | 2 | ||
3 | Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. | 3 | Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. |
4 | 4 | ||
5 | 802.11 status code portion of this file from ethereal-0.10.6: | 5 | 802.11 status code portion of this file from ethereal-0.10.6: |
6 | Copyright 2000, Axis Communications AB | 6 | Copyright 2000, Axis Communications AB |
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #include "ipw2200.h" | 33 | #include "ipw2200.h" |
34 | 34 | ||
35 | #define IPW2200_VERSION "1.0.4" | 35 | #define IPW2200_VERSION "1.0.5" |
36 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" | 36 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" |
37 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" | 37 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" |
38 | #define DRV_VERSION IPW2200_VERSION | 38 | #define DRV_VERSION IPW2200_VERSION |
@@ -273,14 +273,14 @@ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) | |||
273 | 273 | ||
274 | static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); | 274 | static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); |
275 | #define ipw_read_indirect(a, b, c, d) \ | 275 | #define ipw_read_indirect(a, b, c, d) \ |
276 | IPW_DEBUG_IO("%s %d: read_inddirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ | 276 | IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ |
277 | _ipw_read_indirect(a, b, c, d) | 277 | _ipw_read_indirect(a, b, c, d) |
278 | 278 | ||
279 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, | 279 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, |
280 | int num); | 280 | int num); |
281 | #define ipw_write_indirect(a, b, c, d) \ | 281 | #define ipw_write_indirect(a, b, c, d) \ |
282 | IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ | 282 | IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ |
283 | _ipw_write_indirect(a, b, c, d) | 283 | _ipw_write_indirect(a, b, c, d) |
284 | 284 | ||
285 | /* indirect write s */ | 285 | /* indirect write s */ |
286 | static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) | 286 | static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) |
@@ -295,8 +295,6 @@ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) | |||
295 | IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); | 295 | IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); |
296 | _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); | 296 | _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); |
297 | _ipw_write8(priv, IPW_INDIRECT_DATA, value); | 297 | _ipw_write8(priv, IPW_INDIRECT_DATA, value); |
298 | IPW_DEBUG_IO(" reg = 0x%8lX : value = 0x%8X\n", | ||
299 | (unsigned long)(priv->hw_base + IPW_INDIRECT_DATA), value); | ||
300 | } | 298 | } |
301 | 299 | ||
302 | static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) | 300 | static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) |
@@ -1015,12 +1013,12 @@ void ipw_led_init(struct ipw_priv *priv) | |||
1015 | 1013 | ||
1016 | void ipw_led_shutdown(struct ipw_priv *priv) | 1014 | void ipw_led_shutdown(struct ipw_priv *priv) |
1017 | { | 1015 | { |
1018 | cancel_delayed_work(&priv->led_link_on); | ||
1019 | cancel_delayed_work(&priv->led_link_off); | ||
1020 | cancel_delayed_work(&priv->led_act_off); | ||
1021 | ipw_led_activity_off(priv); | 1016 | ipw_led_activity_off(priv); |
1022 | ipw_led_link_off(priv); | 1017 | ipw_led_link_off(priv); |
1023 | ipw_led_band_off(priv); | 1018 | ipw_led_band_off(priv); |
1019 | cancel_delayed_work(&priv->led_link_on); | ||
1020 | cancel_delayed_work(&priv->led_link_off); | ||
1021 | cancel_delayed_work(&priv->led_act_off); | ||
1024 | } | 1022 | } |
1025 | 1023 | ||
1026 | /* | 1024 | /* |
@@ -1296,6 +1294,7 @@ static ssize_t show_indirect_dword(struct device *d, | |||
1296 | { | 1294 | { |
1297 | u32 reg = 0; | 1295 | u32 reg = 0; |
1298 | struct ipw_priv *priv = d->driver_data; | 1296 | struct ipw_priv *priv = d->driver_data; |
1297 | |||
1299 | if (priv->status & STATUS_INDIRECT_DWORD) | 1298 | if (priv->status & STATUS_INDIRECT_DWORD) |
1300 | reg = ipw_read_reg32(priv, priv->indirect_dword); | 1299 | reg = ipw_read_reg32(priv, priv->indirect_dword); |
1301 | else | 1300 | else |
@@ -1322,6 +1321,7 @@ static ssize_t show_indirect_byte(struct device *d, | |||
1322 | { | 1321 | { |
1323 | u8 reg = 0; | 1322 | u8 reg = 0; |
1324 | struct ipw_priv *priv = d->driver_data; | 1323 | struct ipw_priv *priv = d->driver_data; |
1324 | |||
1325 | if (priv->status & STATUS_INDIRECT_BYTE) | 1325 | if (priv->status & STATUS_INDIRECT_BYTE) |
1326 | reg = ipw_read_reg8(priv, priv->indirect_byte); | 1326 | reg = ipw_read_reg8(priv, priv->indirect_byte); |
1327 | else | 1327 | else |
@@ -1509,8 +1509,8 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, | |||
1509 | return count; | 1509 | return count; |
1510 | } | 1510 | } |
1511 | 1511 | ||
1512 | static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, show_net_stats, | 1512 | static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, |
1513 | store_net_stats); | 1513 | show_net_stats, store_net_stats); |
1514 | 1514 | ||
1515 | static void notify_wx_assoc_event(struct ipw_priv *priv) | 1515 | static void notify_wx_assoc_event(struct ipw_priv *priv) |
1516 | { | 1516 | { |
@@ -1630,6 +1630,11 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1630 | /* Keep the restart process from trying to send host | 1630 | /* Keep the restart process from trying to send host |
1631 | * commands by clearing the INIT status bit */ | 1631 | * commands by clearing the INIT status bit */ |
1632 | priv->status &= ~STATUS_INIT; | 1632 | priv->status &= ~STATUS_INIT; |
1633 | |||
1634 | /* Cancel currently queued command. */ | ||
1635 | priv->status &= ~STATUS_HCMD_ACTIVE; | ||
1636 | wake_up_interruptible(&priv->wait_command_queue); | ||
1637 | |||
1633 | queue_work(priv->workqueue, &priv->adapter_restart); | 1638 | queue_work(priv->workqueue, &priv->adapter_restart); |
1634 | handled |= IPW_INTA_BIT_FATAL_ERROR; | 1639 | handled |= IPW_INTA_BIT_FATAL_ERROR; |
1635 | } | 1640 | } |
@@ -1796,7 +1801,7 @@ static int ipw_send_system_config(struct ipw_priv *priv, | |||
1796 | return -1; | 1801 | return -1; |
1797 | } | 1802 | } |
1798 | 1803 | ||
1799 | memcpy(&cmd.param, config, sizeof(*config)); | 1804 | memcpy(cmd.param, config, sizeof(*config)); |
1800 | if (ipw_send_cmd(priv, &cmd)) { | 1805 | if (ipw_send_cmd(priv, &cmd)) { |
1801 | IPW_ERROR("failed to send SYSTEM_CONFIG command\n"); | 1806 | IPW_ERROR("failed to send SYSTEM_CONFIG command\n"); |
1802 | return -1; | 1807 | return -1; |
@@ -1817,7 +1822,7 @@ static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) | |||
1817 | return -1; | 1822 | return -1; |
1818 | } | 1823 | } |
1819 | 1824 | ||
1820 | memcpy(&cmd.param, ssid, cmd.len); | 1825 | memcpy(cmd.param, ssid, cmd.len); |
1821 | if (ipw_send_cmd(priv, &cmd)) { | 1826 | if (ipw_send_cmd(priv, &cmd)) { |
1822 | IPW_ERROR("failed to send SSID command\n"); | 1827 | IPW_ERROR("failed to send SSID command\n"); |
1823 | return -1; | 1828 | return -1; |
@@ -1841,8 +1846,7 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) | |||
1841 | IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", | 1846 | IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", |
1842 | priv->net_dev->name, MAC_ARG(mac)); | 1847 | priv->net_dev->name, MAC_ARG(mac)); |
1843 | 1848 | ||
1844 | memcpy(&cmd.param, mac, ETH_ALEN); | 1849 | memcpy(cmd.param, mac, ETH_ALEN); |
1845 | |||
1846 | if (ipw_send_cmd(priv, &cmd)) { | 1850 | if (ipw_send_cmd(priv, &cmd)) { |
1847 | IPW_ERROR("failed to send ADAPTER_ADDRESS command\n"); | 1851 | IPW_ERROR("failed to send ADAPTER_ADDRESS command\n"); |
1848 | return -1; | 1852 | return -1; |
@@ -1873,11 +1877,6 @@ static void ipw_adapter_restart(void *adapter) | |||
1873 | IPW_ERROR("Failed to up device\n"); | 1877 | IPW_ERROR("Failed to up device\n"); |
1874 | return; | 1878 | return; |
1875 | } | 1879 | } |
1876 | |||
1877 | if ((priv->capability & CAP_PRIVACY_ON) && | ||
1878 | (priv->ieee->sec.level == SEC_LEVEL_1) && | ||
1879 | !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) | ||
1880 | ipw_set_hwcrypto_keys(priv); | ||
1881 | } | 1880 | } |
1882 | 1881 | ||
1883 | static void ipw_bg_adapter_restart(void *data) | 1882 | static void ipw_bg_adapter_restart(void *data) |
@@ -1917,14 +1916,12 @@ static int ipw_send_scan_request_ext(struct ipw_priv *priv, | |||
1917 | .len = sizeof(*request) | 1916 | .len = sizeof(*request) |
1918 | }; | 1917 | }; |
1919 | 1918 | ||
1920 | memcpy(&cmd.param, request, sizeof(*request)); | 1919 | memcpy(cmd.param, request, sizeof(*request)); |
1921 | if (ipw_send_cmd(priv, &cmd)) { | 1920 | if (ipw_send_cmd(priv, &cmd)) { |
1922 | IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n"); | 1921 | IPW_ERROR("failed to send SCAN_REQUEST_EXT command\n"); |
1923 | return -1; | 1922 | return -1; |
1924 | } | 1923 | } |
1925 | 1924 | ||
1926 | queue_delayed_work(priv->workqueue, &priv->scan_check, | ||
1927 | IPW_SCAN_CHECK_WATCHDOG); | ||
1928 | return 0; | 1925 | return 0; |
1929 | } | 1926 | } |
1930 | 1927 | ||
@@ -1991,7 +1988,7 @@ static int ipw_send_associate(struct ipw_priv *priv, | |||
1991 | return -1; | 1988 | return -1; |
1992 | } | 1989 | } |
1993 | 1990 | ||
1994 | memcpy(&cmd.param, &tmp_associate, sizeof(*associate)); | 1991 | memcpy(cmd.param, &tmp_associate, sizeof(*associate)); |
1995 | if (ipw_send_cmd(priv, &cmd)) { | 1992 | if (ipw_send_cmd(priv, &cmd)) { |
1996 | IPW_ERROR("failed to send ASSOCIATE command\n"); | 1993 | IPW_ERROR("failed to send ASSOCIATE command\n"); |
1997 | return -1; | 1994 | return -1; |
@@ -2013,7 +2010,7 @@ static int ipw_send_supported_rates(struct ipw_priv *priv, | |||
2013 | return -1; | 2010 | return -1; |
2014 | } | 2011 | } |
2015 | 2012 | ||
2016 | memcpy(&cmd.param, rates, sizeof(*rates)); | 2013 | memcpy(cmd.param, rates, sizeof(*rates)); |
2017 | if (ipw_send_cmd(priv, &cmd)) { | 2014 | if (ipw_send_cmd(priv, &cmd)) { |
2018 | IPW_ERROR("failed to send SUPPORTED_RATES command\n"); | 2015 | IPW_ERROR("failed to send SUPPORTED_RATES command\n"); |
2019 | return -1; | 2016 | return -1; |
@@ -2078,7 +2075,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) | |||
2078 | return -1; | 2075 | return -1; |
2079 | } | 2076 | } |
2080 | 2077 | ||
2081 | memcpy(&cmd.param, power, sizeof(*power)); | 2078 | memcpy(cmd.param, power, sizeof(*power)); |
2082 | if (ipw_send_cmd(priv, &cmd)) { | 2079 | if (ipw_send_cmd(priv, &cmd)) { |
2083 | IPW_ERROR("failed to send TX_POWER command\n"); | 2080 | IPW_ERROR("failed to send TX_POWER command\n"); |
2084 | return -1; | 2081 | return -1; |
@@ -2102,7 +2099,7 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) | |||
2102 | return -1; | 2099 | return -1; |
2103 | } | 2100 | } |
2104 | 2101 | ||
2105 | memcpy(&cmd.param, &rts_threshold, sizeof(rts_threshold)); | 2102 | memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold)); |
2106 | if (ipw_send_cmd(priv, &cmd)) { | 2103 | if (ipw_send_cmd(priv, &cmd)) { |
2107 | IPW_ERROR("failed to send RTS_THRESHOLD command\n"); | 2104 | IPW_ERROR("failed to send RTS_THRESHOLD command\n"); |
2108 | return -1; | 2105 | return -1; |
@@ -2126,7 +2123,7 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) | |||
2126 | return -1; | 2123 | return -1; |
2127 | } | 2124 | } |
2128 | 2125 | ||
2129 | memcpy(&cmd.param, &frag_threshold, sizeof(frag_threshold)); | 2126 | memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold)); |
2130 | if (ipw_send_cmd(priv, &cmd)) { | 2127 | if (ipw_send_cmd(priv, &cmd)) { |
2131 | IPW_ERROR("failed to send FRAG_THRESHOLD command\n"); | 2128 | IPW_ERROR("failed to send FRAG_THRESHOLD command\n"); |
2132 | return -1; | 2129 | return -1; |
@@ -2170,6 +2167,31 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) | |||
2170 | return 0; | 2167 | return 0; |
2171 | } | 2168 | } |
2172 | 2169 | ||
2170 | static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) | ||
2171 | { | ||
2172 | struct ipw_retry_limit retry_limit = { | ||
2173 | .short_retry_limit = slimit, | ||
2174 | .long_retry_limit = llimit | ||
2175 | }; | ||
2176 | struct host_cmd cmd = { | ||
2177 | .cmd = IPW_CMD_RETRY_LIMIT, | ||
2178 | .len = sizeof(retry_limit) | ||
2179 | }; | ||
2180 | |||
2181 | if (!priv) { | ||
2182 | IPW_ERROR("Invalid args\n"); | ||
2183 | return -1; | ||
2184 | } | ||
2185 | |||
2186 | memcpy(cmd.param, &retry_limit, sizeof(retry_limit)); | ||
2187 | if (ipw_send_cmd(priv, &cmd)) { | ||
2188 | IPW_ERROR("failed to send RETRY_LIMIT command\n"); | ||
2189 | return -1; | ||
2190 | } | ||
2191 | |||
2192 | return 0; | ||
2193 | } | ||
2194 | |||
2173 | /* | 2195 | /* |
2174 | * The IPW device contains a Microwire compatible EEPROM that stores | 2196 | * The IPW device contains a Microwire compatible EEPROM that stores |
2175 | * various data like the MAC address. Usually the firmware has exclusive | 2197 | * various data like the MAC address. Usually the firmware has exclusive |
@@ -2269,8 +2291,7 @@ static u16 eeprom_read_u16(struct ipw_priv *priv, u8 addr) | |||
2269 | /* data's copy of the eeprom data */ | 2291 | /* data's copy of the eeprom data */ |
2270 | static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) | 2292 | static void eeprom_parse_mac(struct ipw_priv *priv, u8 * mac) |
2271 | { | 2293 | { |
2272 | u8 *ee = (u8 *) priv->eeprom; | 2294 | memcpy(mac, &priv->eeprom[EEPROM_MAC_ADDRESS], 6); |
2273 | memcpy(mac, &ee[EEPROM_MAC_ADDRESS], 6); | ||
2274 | } | 2295 | } |
2275 | 2296 | ||
2276 | /* | 2297 | /* |
@@ -2680,8 +2701,7 @@ struct fw_chunk { | |||
2680 | #define IPW_FW_MINOR(x) ((x & 0xff) >> 8) | 2701 | #define IPW_FW_MINOR(x) ((x & 0xff) >> 8) |
2681 | #define IPW_FW_MAJOR(x) (x & 0xff) | 2702 | #define IPW_FW_MAJOR(x) (x & 0xff) |
2682 | 2703 | ||
2683 | #define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | \ | 2704 | #define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION) |
2684 | IPW_FW_MAJOR_VERSION) | ||
2685 | 2705 | ||
2686 | #define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \ | 2706 | #define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \ |
2687 | "." __stringify(IPW_FW_MINOR_VERSION) "-" | 2707 | "." __stringify(IPW_FW_MINOR_VERSION) "-" |
@@ -2952,6 +2972,8 @@ static int ipw_reset_nic(struct ipw_priv *priv) | |||
2952 | /* Clear the 'host command active' bit... */ | 2972 | /* Clear the 'host command active' bit... */ |
2953 | priv->status &= ~STATUS_HCMD_ACTIVE; | 2973 | priv->status &= ~STATUS_HCMD_ACTIVE; |
2954 | wake_up_interruptible(&priv->wait_command_queue); | 2974 | wake_up_interruptible(&priv->wait_command_queue); |
2975 | priv->status &= ~(STATUS_SCANNING | STATUS_SCAN_ABORTING); | ||
2976 | wake_up_interruptible(&priv->wait_state); | ||
2955 | spin_unlock_irqrestore(&priv->lock, flags); | 2977 | spin_unlock_irqrestore(&priv->lock, flags); |
2956 | 2978 | ||
2957 | IPW_DEBUG_TRACE("<<\n"); | 2979 | IPW_DEBUG_TRACE("<<\n"); |
@@ -3027,6 +3049,19 @@ static int fw_loaded = 0; | |||
3027 | static const struct firmware *bootfw = NULL; | 3049 | static const struct firmware *bootfw = NULL; |
3028 | static const struct firmware *firmware = NULL; | 3050 | static const struct firmware *firmware = NULL; |
3029 | static const struct firmware *ucode = NULL; | 3051 | static const struct firmware *ucode = NULL; |
3052 | |||
3053 | static void free_firmware(void) | ||
3054 | { | ||
3055 | if (fw_loaded) { | ||
3056 | release_firmware(bootfw); | ||
3057 | release_firmware(ucode); | ||
3058 | release_firmware(firmware); | ||
3059 | bootfw = ucode = firmware = NULL; | ||
3060 | fw_loaded = 0; | ||
3061 | } | ||
3062 | } | ||
3063 | #else | ||
3064 | #define free_firmware() do {} while (0) | ||
3030 | #endif | 3065 | #endif |
3031 | 3066 | ||
3032 | static int ipw_load(struct ipw_priv *priv) | 3067 | static int ipw_load(struct ipw_priv *priv) |
@@ -3915,13 +3950,13 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, | |||
3915 | { | 3950 | { |
3916 | priv->notif_missed_beacons = missed_count; | 3951 | priv->notif_missed_beacons = missed_count; |
3917 | 3952 | ||
3918 | if (missed_count > priv->missed_beacon_threshold && | 3953 | if (missed_count > priv->disassociate_threshold && |
3919 | priv->status & STATUS_ASSOCIATED) { | 3954 | priv->status & STATUS_ASSOCIATED) { |
3920 | /* If associated and we've hit the missed | 3955 | /* If associated and we've hit the missed |
3921 | * beacon threshold, disassociate, turn | 3956 | * beacon threshold, disassociate, turn |
3922 | * off roaming, and abort any active scans */ | 3957 | * off roaming, and abort any active scans */ |
3923 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | | 3958 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | |
3924 | IPW_DL_STATE, | 3959 | IPW_DL_STATE | IPW_DL_ASSOC, |
3925 | "Missed beacon: %d - disassociate\n", missed_count); | 3960 | "Missed beacon: %d - disassociate\n", missed_count); |
3926 | priv->status &= ~STATUS_ROAMING; | 3961 | priv->status &= ~STATUS_ROAMING; |
3927 | if (priv->status & STATUS_SCANNING) { | 3962 | if (priv->status & STATUS_SCANNING) { |
@@ -4027,7 +4062,11 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
4027 | priv->status |= STATUS_ASSOCIATED; | 4062 | priv->status |= STATUS_ASSOCIATED; |
4028 | 4063 | ||
4029 | #ifdef CONFIG_IPW_QOS | 4064 | #ifdef CONFIG_IPW_QOS |
4030 | if (priv->status & STATUS_AUTH) { | 4065 | #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ |
4066 | le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl)) | ||
4067 | if ((priv->status & STATUS_AUTH) && | ||
4068 | (IPW_GET_PACKET_STYPE(¬if->u.raw) | ||
4069 | == IEEE80211_STYPE_ASSOC_RESP)) { | ||
4031 | if ((sizeof | 4070 | if ((sizeof |
4032 | (struct | 4071 | (struct |
4033 | ieee80211_assoc_response_frame) | 4072 | ieee80211_assoc_response_frame) |
@@ -4287,10 +4326,12 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
4287 | 4326 | ||
4288 | #ifdef CONFIG_IPW2200_MONITOR | 4327 | #ifdef CONFIG_IPW2200_MONITOR |
4289 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 4328 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
4329 | priv->status |= STATUS_SCAN_FORCED; | ||
4290 | queue_work(priv->workqueue, | 4330 | queue_work(priv->workqueue, |
4291 | &priv->request_scan); | 4331 | &priv->request_scan); |
4292 | break; | 4332 | break; |
4293 | } | 4333 | } |
4334 | priv->status &= ~STATUS_SCAN_FORCED; | ||
4294 | #endif /* CONFIG_IPW2200_MONITOR */ | 4335 | #endif /* CONFIG_IPW2200_MONITOR */ |
4295 | 4336 | ||
4296 | if (!(priv->status & (STATUS_ASSOCIATED | | 4337 | if (!(priv->status & (STATUS_ASSOCIATED | |
@@ -4330,6 +4371,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
4330 | case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{ | 4371 | case HOST_NOTIFICATION_STATUS_LINK_DETERIORATION:{ |
4331 | struct notif_link_deterioration *x = | 4372 | struct notif_link_deterioration *x = |
4332 | ¬if->u.link_deterioration; | 4373 | ¬if->u.link_deterioration; |
4374 | |||
4333 | if (notif->size == sizeof(*x)) { | 4375 | if (notif->size == sizeof(*x)) { |
4334 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, | 4376 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, |
4335 | "link deterioration: '%s' " MAC_FMT | 4377 | "link deterioration: '%s' " MAC_FMT |
@@ -5027,6 +5069,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, | |||
5027 | memcmp(network->ssid, priv->essid, | 5069 | memcmp(network->ssid, priv->essid, |
5028 | min(network->ssid_len, priv->essid_len)))) { | 5070 | min(network->ssid_len, priv->essid_len)))) { |
5029 | char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; | 5071 | char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; |
5072 | |||
5030 | strncpy(escaped, | 5073 | strncpy(escaped, |
5031 | escape_essid(network->ssid, network->ssid_len), | 5074 | escape_essid(network->ssid, network->ssid_len), |
5032 | sizeof(escaped)); | 5075 | sizeof(escaped)); |
@@ -5043,16 +5086,16 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, | |||
5043 | * testing everything else. */ | 5086 | * testing everything else. */ |
5044 | 5087 | ||
5045 | if (network->time_stamp[0] < match->network->time_stamp[0]) { | 5088 | if (network->time_stamp[0] < match->network->time_stamp[0]) { |
5046 | IPW_DEBUG_MERGE | 5089 | IPW_DEBUG_MERGE("Network '%s excluded because newer than " |
5047 | ("Network '%s excluded because newer than current network.\n", | 5090 | "current network.\n", |
5048 | escape_essid(match->network->ssid, | 5091 | escape_essid(match->network->ssid, |
5049 | match->network->ssid_len)); | 5092 | match->network->ssid_len)); |
5050 | return 0; | 5093 | return 0; |
5051 | } else if (network->time_stamp[1] < match->network->time_stamp[1]) { | 5094 | } else if (network->time_stamp[1] < match->network->time_stamp[1]) { |
5052 | IPW_DEBUG_MERGE | 5095 | IPW_DEBUG_MERGE("Network '%s excluded because newer than " |
5053 | ("Network '%s excluded because newer than current network.\n", | 5096 | "current network.\n", |
5054 | escape_essid(match->network->ssid, | 5097 | escape_essid(match->network->ssid, |
5055 | match->network->ssid_len)); | 5098 | match->network->ssid_len)); |
5056 | return 0; | 5099 | return 0; |
5057 | } | 5100 | } |
5058 | 5101 | ||
@@ -5063,7 +5106,7 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, | |||
5063 | "because of age: %lums.\n", | 5106 | "because of age: %lums.\n", |
5064 | escape_essid(network->ssid, network->ssid_len), | 5107 | escape_essid(network->ssid, network->ssid_len), |
5065 | MAC_ARG(network->bssid), | 5108 | MAC_ARG(network->bssid), |
5066 | (jiffies - network->last_scanned) / (HZ / 100)); | 5109 | 1000 * (jiffies - network->last_scanned) / HZ); |
5067 | return 0; | 5110 | return 0; |
5068 | } | 5111 | } |
5069 | 5112 | ||
@@ -5084,10 +5127,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, | |||
5084 | "because of privacy mismatch: %s != %s.\n", | 5127 | "because of privacy mismatch: %s != %s.\n", |
5085 | escape_essid(network->ssid, network->ssid_len), | 5128 | escape_essid(network->ssid, network->ssid_len), |
5086 | MAC_ARG(network->bssid), | 5129 | MAC_ARG(network->bssid), |
5087 | priv->capability & CAP_PRIVACY_ON ? "on" : | 5130 | priv-> |
5088 | "off", | 5131 | capability & CAP_PRIVACY_ON ? "on" : "off", |
5089 | network->capability & | 5132 | network-> |
5090 | WLAN_CAPABILITY_PRIVACY ? "on" : "off"); | 5133 | capability & WLAN_CAPABILITY_PRIVACY ? "on" : |
5134 | "off"); | ||
5091 | return 0; | 5135 | return 0; |
5092 | } | 5136 | } |
5093 | 5137 | ||
@@ -5151,8 +5195,8 @@ static void ipw_merge_adhoc_network(void *data) | |||
5151 | .network = priv->assoc_network | 5195 | .network = priv->assoc_network |
5152 | }; | 5196 | }; |
5153 | 5197 | ||
5154 | if ((priv->status & STATUS_ASSOCIATED) | 5198 | if ((priv->status & STATUS_ASSOCIATED) && |
5155 | && (priv->ieee->iw_mode == IW_MODE_ADHOC)) { | 5199 | (priv->ieee->iw_mode == IW_MODE_ADHOC)) { |
5156 | /* First pass through ROAM process -- look for a better | 5200 | /* First pass through ROAM process -- look for a better |
5157 | * network */ | 5201 | * network */ |
5158 | unsigned long flags; | 5202 | unsigned long flags; |
@@ -5184,7 +5228,6 @@ static void ipw_merge_adhoc_network(void *data) | |||
5184 | up(&priv->sem); | 5228 | up(&priv->sem); |
5185 | return; | 5229 | return; |
5186 | } | 5230 | } |
5187 | |||
5188 | } | 5231 | } |
5189 | 5232 | ||
5190 | static int ipw_best_network(struct ipw_priv *priv, | 5233 | static int ipw_best_network(struct ipw_priv *priv, |
@@ -5270,7 +5313,7 @@ static int ipw_best_network(struct ipw_priv *priv, | |||
5270 | if (network->last_associate && | 5313 | if (network->last_associate && |
5271 | time_after(network->last_associate + (HZ * 3UL), jiffies)) { | 5314 | time_after(network->last_associate + (HZ * 3UL), jiffies)) { |
5272 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | 5315 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " |
5273 | "because of storming (%lu since last " | 5316 | "because of storming (%lus since last " |
5274 | "assoc attempt).\n", | 5317 | "assoc attempt).\n", |
5275 | escape_essid(network->ssid, network->ssid_len), | 5318 | escape_essid(network->ssid, network->ssid_len), |
5276 | MAC_ARG(network->bssid), | 5319 | MAC_ARG(network->bssid), |
@@ -5285,7 +5328,7 @@ static int ipw_best_network(struct ipw_priv *priv, | |||
5285 | "because of age: %lums.\n", | 5328 | "because of age: %lums.\n", |
5286 | escape_essid(network->ssid, network->ssid_len), | 5329 | escape_essid(network->ssid, network->ssid_len), |
5287 | MAC_ARG(network->bssid), | 5330 | MAC_ARG(network->bssid), |
5288 | (jiffies - network->last_scanned) / (HZ / 100)); | 5331 | 1000 * (jiffies - network->last_scanned) / HZ); |
5289 | return 0; | 5332 | return 0; |
5290 | } | 5333 | } |
5291 | 5334 | ||
@@ -5369,6 +5412,9 @@ static int ipw_best_network(struct ipw_priv *priv, | |||
5369 | static void ipw_adhoc_create(struct ipw_priv *priv, | 5412 | static void ipw_adhoc_create(struct ipw_priv *priv, |
5370 | struct ieee80211_network *network) | 5413 | struct ieee80211_network *network) |
5371 | { | 5414 | { |
5415 | const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); | ||
5416 | int i; | ||
5417 | |||
5372 | /* | 5418 | /* |
5373 | * For the purposes of scanning, we can set our wireless mode | 5419 | * For the purposes of scanning, we can set our wireless mode |
5374 | * to trigger scans across combinations of bands, but when it | 5420 | * to trigger scans across combinations of bands, but when it |
@@ -5379,9 +5425,28 @@ static void ipw_adhoc_create(struct ipw_priv *priv, | |||
5379 | * chossen band. Attempting to create a new ad-hoc network | 5425 | * chossen band. Attempting to create a new ad-hoc network |
5380 | * with an invalid channel for wireless mode will trigger a | 5426 | * with an invalid channel for wireless mode will trigger a |
5381 | * FW fatal error. | 5427 | * FW fatal error. |
5428 | * | ||
5382 | */ | 5429 | */ |
5383 | if (!ieee80211_is_valid_channel(priv->ieee, priv->channel)) { | 5430 | switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { |
5384 | const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); | 5431 | case IEEE80211_52GHZ_BAND: |
5432 | network->mode = IEEE_A; | ||
5433 | i = ieee80211_channel_to_index(priv->ieee, priv->channel); | ||
5434 | if (i == -1) | ||
5435 | BUG(); | ||
5436 | if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { | ||
5437 | IPW_WARNING("Overriding invalid channel\n"); | ||
5438 | priv->channel = geo->a[0].channel; | ||
5439 | } | ||
5440 | break; | ||
5441 | |||
5442 | case IEEE80211_24GHZ_BAND: | ||
5443 | if (priv->ieee->mode & IEEE_G) | ||
5444 | network->mode = IEEE_G; | ||
5445 | else | ||
5446 | network->mode = IEEE_B; | ||
5447 | break; | ||
5448 | |||
5449 | default: | ||
5385 | IPW_WARNING("Overriding invalid channel\n"); | 5450 | IPW_WARNING("Overriding invalid channel\n"); |
5386 | if (priv->ieee->mode & IEEE_A) { | 5451 | if (priv->ieee->mode & IEEE_A) { |
5387 | network->mode = IEEE_A; | 5452 | network->mode = IEEE_A; |
@@ -5393,8 +5458,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv, | |||
5393 | network->mode = IEEE_B; | 5458 | network->mode = IEEE_B; |
5394 | priv->channel = geo->bg[0].channel; | 5459 | priv->channel = geo->bg[0].channel; |
5395 | } | 5460 | } |
5396 | } else | 5461 | break; |
5397 | network->mode = priv->ieee->mode; | 5462 | } |
5398 | 5463 | ||
5399 | network->channel = priv->channel; | 5464 | network->channel = priv->channel; |
5400 | priv->config |= CFG_ADHOC_PERSIST; | 5465 | priv->config |= CFG_ADHOC_PERSIST; |
@@ -5488,10 +5553,11 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) | |||
5488 | { | 5553 | { |
5489 | switch (priv->ieee->sec.level) { | 5554 | switch (priv->ieee->sec.level) { |
5490 | case SEC_LEVEL_3: | 5555 | case SEC_LEVEL_3: |
5491 | if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) | 5556 | if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) |
5492 | ipw_send_tgi_tx_key(priv, | 5557 | break; |
5493 | DCT_FLAG_EXT_SECURITY_CCM, | 5558 | |
5494 | priv->ieee->sec.active_key); | 5559 | ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_CCM, |
5560 | priv->ieee->sec.active_key); | ||
5495 | ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); | 5561 | ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_CCM); |
5496 | 5562 | ||
5497 | priv->sys_config.disable_unicast_decryption = 0; | 5563 | priv->sys_config.disable_unicast_decryption = 0; |
@@ -5502,10 +5568,11 @@ static void ipw_set_hwcrypto_keys(struct ipw_priv *priv) | |||
5502 | 5568 | ||
5503 | break; | 5569 | break; |
5504 | case SEC_LEVEL_2: | 5570 | case SEC_LEVEL_2: |
5505 | if (priv->ieee->sec.flags & SEC_ACTIVE_KEY) | 5571 | if (!(priv->ieee->sec.flags & SEC_ACTIVE_KEY)) |
5506 | ipw_send_tgi_tx_key(priv, | 5572 | break; |
5507 | DCT_FLAG_EXT_SECURITY_TKIP, | 5573 | |
5508 | priv->ieee->sec.active_key); | 5574 | ipw_send_tgi_tx_key(priv, DCT_FLAG_EXT_SECURITY_TKIP, |
5575 | priv->ieee->sec.active_key); | ||
5509 | 5576 | ||
5510 | priv->sys_config.disable_unicast_decryption = 1; | 5577 | priv->sys_config.disable_unicast_decryption = 1; |
5511 | priv->sys_config.disable_multicast_decryption = 1; | 5578 | priv->sys_config.disable_multicast_decryption = 1; |
@@ -5534,9 +5601,12 @@ static void ipw_adhoc_check(void *data) | |||
5534 | { | 5601 | { |
5535 | struct ipw_priv *priv = data; | 5602 | struct ipw_priv *priv = data; |
5536 | 5603 | ||
5537 | if (priv->missed_adhoc_beacons++ > priv->missed_beacon_threshold && | 5604 | if (priv->missed_adhoc_beacons++ > priv->disassociate_threshold && |
5538 | !(priv->config & CFG_ADHOC_PERSIST)) { | 5605 | !(priv->config & CFG_ADHOC_PERSIST)) { |
5539 | IPW_DEBUG_SCAN("Disassociating due to missed beacons\n"); | 5606 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | |
5607 | IPW_DL_STATE | IPW_DL_ASSOC, | ||
5608 | "Missed beacon: %d - disassociate\n", | ||
5609 | priv->missed_adhoc_beacons); | ||
5540 | ipw_remove_current_network(priv); | 5610 | ipw_remove_current_network(priv); |
5541 | ipw_disassociate(priv); | 5611 | ipw_disassociate(priv); |
5542 | return; | 5612 | return; |
@@ -5669,27 +5739,110 @@ static void ipw_abort_scan(struct ipw_priv *priv) | |||
5669 | IPW_DEBUG_HC("Request to abort scan failed.\n"); | 5739 | IPW_DEBUG_HC("Request to abort scan failed.\n"); |
5670 | } | 5740 | } |
5671 | 5741 | ||
5672 | static int ipw_request_scan(struct ipw_priv *priv) | 5742 | static void ipw_add_scan_channels(struct ipw_priv *priv, |
5743 | struct ipw_scan_request_ext *scan, | ||
5744 | int scan_type) | ||
5673 | { | 5745 | { |
5674 | struct ipw_scan_request_ext scan; | ||
5675 | int channel_index = 0; | 5746 | int channel_index = 0; |
5676 | int i, err = 0, scan_type; | ||
5677 | const struct ieee80211_geo *geo; | 5747 | const struct ieee80211_geo *geo; |
5678 | #ifdef CONFIG_IPW2200_MONITOR | 5748 | int i; |
5679 | u8 channel; | ||
5680 | #endif | ||
5681 | |||
5682 | down(&priv->sem); | ||
5683 | 5749 | ||
5684 | geo = ieee80211_get_geo(priv->ieee); | 5750 | geo = ieee80211_get_geo(priv->ieee); |
5685 | 5751 | ||
5752 | if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { | ||
5753 | int start = channel_index; | ||
5754 | for (i = 0; i < geo->a_channels; i++) { | ||
5755 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5756 | geo->a[i].channel == priv->channel) | ||
5757 | continue; | ||
5758 | channel_index++; | ||
5759 | scan->channels_list[channel_index] = geo->a[i].channel; | ||
5760 | ipw_set_scan_type(scan, channel_index, scan_type); | ||
5761 | } | ||
5762 | |||
5763 | if (start != channel_index) { | ||
5764 | scan->channels_list[start] = (u8) (IPW_A_MODE << 6) | | ||
5765 | (channel_index - start); | ||
5766 | channel_index++; | ||
5767 | } | ||
5768 | } | ||
5769 | |||
5770 | if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { | ||
5771 | int start = channel_index; | ||
5772 | if (priv->config & CFG_SPEED_SCAN) { | ||
5773 | u8 channels[IEEE80211_24GHZ_CHANNELS] = { | ||
5774 | /* nop out the list */ | ||
5775 | [0] = 0 | ||
5776 | }; | ||
5777 | |||
5778 | u8 channel; | ||
5779 | while (channel_index < IPW_SCAN_CHANNELS) { | ||
5780 | channel = | ||
5781 | priv->speed_scan[priv->speed_scan_pos]; | ||
5782 | if (channel == 0) { | ||
5783 | priv->speed_scan_pos = 0; | ||
5784 | channel = priv->speed_scan[0]; | ||
5785 | } | ||
5786 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5787 | channel == priv->channel) { | ||
5788 | priv->speed_scan_pos++; | ||
5789 | continue; | ||
5790 | } | ||
5791 | |||
5792 | /* If this channel has already been | ||
5793 | * added in scan, break from loop | ||
5794 | * and this will be the first channel | ||
5795 | * in the next scan. | ||
5796 | */ | ||
5797 | if (channels[channel - 1] != 0) | ||
5798 | break; | ||
5799 | |||
5800 | channels[channel - 1] = 1; | ||
5801 | priv->speed_scan_pos++; | ||
5802 | channel_index++; | ||
5803 | scan->channels_list[channel_index] = channel; | ||
5804 | ipw_set_scan_type(scan, channel_index, | ||
5805 | scan_type); | ||
5806 | } | ||
5807 | } else { | ||
5808 | for (i = 0; i < geo->bg_channels; i++) { | ||
5809 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5810 | geo->bg[i].channel == priv->channel) | ||
5811 | continue; | ||
5812 | channel_index++; | ||
5813 | scan->channels_list[channel_index] = | ||
5814 | geo->bg[i].channel; | ||
5815 | ipw_set_scan_type(scan, channel_index, | ||
5816 | scan_type); | ||
5817 | } | ||
5818 | } | ||
5819 | |||
5820 | if (start != channel_index) { | ||
5821 | scan->channels_list[start] = (u8) (IPW_B_MODE << 6) | | ||
5822 | (channel_index - start); | ||
5823 | } | ||
5824 | } | ||
5825 | } | ||
5826 | |||
5827 | static int ipw_request_scan(struct ipw_priv *priv) | ||
5828 | { | ||
5829 | struct ipw_scan_request_ext scan; | ||
5830 | int err = 0, scan_type; | ||
5831 | |||
5832 | if (!(priv->status & STATUS_INIT) || | ||
5833 | (priv->status & STATUS_EXIT_PENDING)) | ||
5834 | return 0; | ||
5835 | |||
5836 | down(&priv->sem); | ||
5837 | |||
5686 | if (priv->status & STATUS_SCANNING) { | 5838 | if (priv->status & STATUS_SCANNING) { |
5687 | IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); | 5839 | IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); |
5688 | priv->status |= STATUS_SCAN_PENDING; | 5840 | priv->status |= STATUS_SCAN_PENDING; |
5689 | goto done; | 5841 | goto done; |
5690 | } | 5842 | } |
5691 | 5843 | ||
5692 | if (priv->status & STATUS_SCAN_ABORTING) { | 5844 | if (!(priv->status & STATUS_SCAN_FORCED) && |
5845 | priv->status & STATUS_SCAN_ABORTING) { | ||
5693 | IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); | 5846 | IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); |
5694 | priv->status |= STATUS_SCAN_PENDING; | 5847 | priv->status |= STATUS_SCAN_PENDING; |
5695 | goto done; | 5848 | goto done; |
@@ -5718,6 +5871,7 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
5718 | 5871 | ||
5719 | #ifdef CONFIG_IPW2200_MONITOR | 5872 | #ifdef CONFIG_IPW2200_MONITOR |
5720 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 5873 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
5874 | u8 channel; | ||
5721 | u8 band = 0; | 5875 | u8 band = 0; |
5722 | 5876 | ||
5723 | switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { | 5877 | switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { |
@@ -5768,91 +5922,10 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
5768 | } | 5922 | } |
5769 | 5923 | ||
5770 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; | 5924 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; |
5771 | } else { | 5925 | } else |
5772 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; | 5926 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; |
5773 | } | ||
5774 | 5927 | ||
5775 | /* Add channels to the scan list */ | 5928 | ipw_add_scan_channels(priv, &scan, scan_type); |
5776 | if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { | ||
5777 | int start = channel_index; | ||
5778 | for (i = 0; i < geo->a_channels; i++) { | ||
5779 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5780 | geo->a[i].channel == priv->channel) | ||
5781 | continue; | ||
5782 | channel_index++; | ||
5783 | scan.channels_list[channel_index] = | ||
5784 | geo->a[i].channel; | ||
5785 | ipw_set_scan_type(&scan, channel_index, | ||
5786 | scan_type); | ||
5787 | } | ||
5788 | |||
5789 | if (start != channel_index) { | ||
5790 | scan.channels_list[start] = | ||
5791 | (u8) (IPW_A_MODE << 6) | (channel_index - | ||
5792 | start); | ||
5793 | channel_index++; | ||
5794 | } | ||
5795 | } | ||
5796 | |||
5797 | if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { | ||
5798 | int start = channel_index; | ||
5799 | if (priv->config & CFG_SPEED_SCAN) { | ||
5800 | u8 channels[IEEE80211_24GHZ_CHANNELS] = { | ||
5801 | /* nop out the list */ | ||
5802 | [0] = 0 | ||
5803 | }; | ||
5804 | |||
5805 | u8 channel; | ||
5806 | while (channel_index < IPW_SCAN_CHANNELS) { | ||
5807 | channel = | ||
5808 | priv->speed_scan[priv-> | ||
5809 | speed_scan_pos]; | ||
5810 | if (channel == 0) { | ||
5811 | priv->speed_scan_pos = 0; | ||
5812 | channel = priv->speed_scan[0]; | ||
5813 | } | ||
5814 | if ((priv->status & STATUS_ASSOCIATED) | ||
5815 | && channel == priv->channel) { | ||
5816 | priv->speed_scan_pos++; | ||
5817 | continue; | ||
5818 | } | ||
5819 | |||
5820 | /* If this channel has already been | ||
5821 | * added in scan, break from loop | ||
5822 | * and this will be the first channel | ||
5823 | * in the next scan. | ||
5824 | */ | ||
5825 | if (channels[channel - 1] != 0) | ||
5826 | break; | ||
5827 | |||
5828 | channels[channel - 1] = 1; | ||
5829 | priv->speed_scan_pos++; | ||
5830 | channel_index++; | ||
5831 | scan.channels_list[channel_index] = | ||
5832 | channel; | ||
5833 | ipw_set_scan_type(&scan, channel_index, | ||
5834 | scan_type); | ||
5835 | } | ||
5836 | } else { | ||
5837 | for (i = 0; i < geo->bg_channels; i++) { | ||
5838 | if ((priv->status & STATUS_ASSOCIATED) | ||
5839 | && geo->bg[i].channel == | ||
5840 | priv->channel) | ||
5841 | continue; | ||
5842 | channel_index++; | ||
5843 | scan.channels_list[channel_index] = | ||
5844 | geo->bg[i].channel; | ||
5845 | ipw_set_scan_type(&scan, channel_index, | ||
5846 | scan_type); | ||
5847 | } | ||
5848 | } | ||
5849 | |||
5850 | if (start != channel_index) { | ||
5851 | scan.channels_list[start] = | ||
5852 | (u8) (IPW_B_MODE << 6) | (channel_index - | ||
5853 | start); | ||
5854 | } | ||
5855 | } | ||
5856 | #ifdef CONFIG_IPW2200_MONITOR | 5929 | #ifdef CONFIG_IPW2200_MONITOR |
5857 | } | 5930 | } |
5858 | #endif | 5931 | #endif |
@@ -5865,7 +5938,8 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
5865 | 5938 | ||
5866 | priv->status |= STATUS_SCANNING; | 5939 | priv->status |= STATUS_SCANNING; |
5867 | priv->status &= ~STATUS_SCAN_PENDING; | 5940 | priv->status &= ~STATUS_SCAN_PENDING; |
5868 | 5941 | queue_delayed_work(priv->workqueue, &priv->scan_check, | |
5942 | IPW_SCAN_CHECK_WATCHDOG); | ||
5869 | done: | 5943 | done: |
5870 | up(&priv->sem); | 5944 | up(&priv->sem); |
5871 | return err; | 5945 | return err; |
@@ -5879,8 +5953,8 @@ static void ipw_bg_abort_scan(void *data) | |||
5879 | up(&priv->sem); | 5953 | up(&priv->sem); |
5880 | } | 5954 | } |
5881 | 5955 | ||
5882 | /* Support for wpa_supplicant. Will be replaced with WEXT once | 5956 | #if WIRELESS_EXT < 18 |
5883 | * they get WPA support. */ | 5957 | /* Support for wpa_supplicant before WE-18, deprecated. */ |
5884 | 5958 | ||
5885 | /* following definitions must match definitions in driver_ipw.c */ | 5959 | /* following definitions must match definitions in driver_ipw.c */ |
5886 | 5960 | ||
@@ -5924,8 +5998,8 @@ struct ipw_param { | |||
5924 | u8 data[0]; | 5998 | u8 data[0]; |
5925 | } wpa_ie; | 5999 | } wpa_ie; |
5926 | struct { | 6000 | struct { |
5927 | int command; | 6001 | u32 command; |
5928 | int reason_code; | 6002 | u32 reason_code; |
5929 | } mlme; | 6003 | } mlme; |
5930 | struct { | 6004 | struct { |
5931 | u8 alg[IPW_CRYPT_ALG_NAME_LEN]; | 6005 | u8 alg[IPW_CRYPT_ALG_NAME_LEN]; |
@@ -5941,6 +6015,7 @@ struct ipw_param { | |||
5941 | }; | 6015 | }; |
5942 | 6016 | ||
5943 | /* end of driver_ipw.c code */ | 6017 | /* end of driver_ipw.c code */ |
6018 | #endif | ||
5944 | 6019 | ||
5945 | static int ipw_wpa_enable(struct ipw_priv *priv, int value) | 6020 | static int ipw_wpa_enable(struct ipw_priv *priv, int value) |
5946 | { | 6021 | { |
@@ -5949,8 +6024,10 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) | |||
5949 | return 0; | 6024 | return 0; |
5950 | } | 6025 | } |
5951 | 6026 | ||
5952 | #define AUTH_ALG_OPEN_SYSTEM 0x1 | 6027 | #if WIRELESS_EXT < 18 |
5953 | #define AUTH_ALG_SHARED_KEY 0x2 | 6028 | #define IW_AUTH_ALG_OPEN_SYSTEM 0x1 |
6029 | #define IW_AUTH_ALG_SHARED_KEY 0x2 | ||
6030 | #endif | ||
5954 | 6031 | ||
5955 | static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) | 6032 | static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) |
5956 | { | 6033 | { |
@@ -5960,13 +6037,14 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) | |||
5960 | }; | 6037 | }; |
5961 | int ret = 0; | 6038 | int ret = 0; |
5962 | 6039 | ||
5963 | if (value & AUTH_ALG_SHARED_KEY) { | 6040 | if (value & IW_AUTH_ALG_SHARED_KEY) { |
5964 | sec.auth_mode = WLAN_AUTH_SHARED_KEY; | 6041 | sec.auth_mode = WLAN_AUTH_SHARED_KEY; |
5965 | ieee->open_wep = 0; | 6042 | ieee->open_wep = 0; |
5966 | } else { | 6043 | } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { |
5967 | sec.auth_mode = WLAN_AUTH_OPEN; | 6044 | sec.auth_mode = WLAN_AUTH_OPEN; |
5968 | ieee->open_wep = 1; | 6045 | ieee->open_wep = 1; |
5969 | } | 6046 | } else |
6047 | return -EINVAL; | ||
5970 | 6048 | ||
5971 | if (ieee->set_security) | 6049 | if (ieee->set_security) |
5972 | ieee->set_security(ieee->dev, &sec); | 6050 | ieee->set_security(ieee->dev, &sec); |
@@ -5976,6 +6054,33 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) | |||
5976 | return ret; | 6054 | return ret; |
5977 | } | 6055 | } |
5978 | 6056 | ||
6057 | void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) | ||
6058 | { | ||
6059 | /* make sure WPA is enabled */ | ||
6060 | ipw_wpa_enable(priv, 1); | ||
6061 | |||
6062 | ipw_disassociate(priv); | ||
6063 | } | ||
6064 | |||
6065 | static int ipw_set_rsn_capa(struct ipw_priv *priv, | ||
6066 | char *capabilities, int length) | ||
6067 | { | ||
6068 | struct host_cmd cmd = { | ||
6069 | .cmd = IPW_CMD_RSN_CAPABILITIES, | ||
6070 | .len = length, | ||
6071 | }; | ||
6072 | |||
6073 | IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); | ||
6074 | |||
6075 | memcpy(cmd.param, capabilities, length); | ||
6076 | if (ipw_send_cmd(priv, &cmd)) { | ||
6077 | IPW_ERROR("failed to send HOST_CMD_RSN_CAPABILITIES command\n"); | ||
6078 | return -1; | ||
6079 | } | ||
6080 | return 0; | ||
6081 | } | ||
6082 | |||
6083 | #if WIRELESS_EXT < 18 | ||
5979 | static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) | 6084 | static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) |
5980 | { | 6085 | { |
5981 | struct ipw_priv *priv = ieee80211_priv(dev); | 6086 | struct ipw_priv *priv = ieee80211_priv(dev); |
@@ -6081,32 +6186,6 @@ static int ipw_wpa_mlme(struct net_device *dev, int command, int reason) | |||
6081 | return ret; | 6186 | return ret; |
6082 | } | 6187 | } |
6083 | 6188 | ||
6084 | static int ipw_set_rsn_capa(struct ipw_priv *priv, | ||
6085 | char *capabilities, int length) | ||
6086 | { | ||
6087 | struct host_cmd cmd = { | ||
6088 | .cmd = IPW_CMD_RSN_CAPABILITIES, | ||
6089 | .len = length, | ||
6090 | }; | ||
6091 | |||
6092 | IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); | ||
6093 | |||
6094 | memcpy(&cmd.param, capabilities, length); | ||
6095 | if (ipw_send_cmd(priv, &cmd)) { | ||
6096 | IPW_ERROR("failed to send HOST_CMD_RSN_CAPABILITIES command\n"); | ||
6097 | return -1; | ||
6098 | } | ||
6099 | return 0; | ||
6100 | } | ||
6101 | |||
6102 | void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) | ||
6103 | { | ||
6104 | /* make sure WPA is enabled */ | ||
6105 | ipw_wpa_enable(priv, 1); | ||
6106 | |||
6107 | ipw_disassociate(priv); | ||
6108 | } | ||
6109 | |||
6110 | static int ipw_wpa_set_wpa_ie(struct net_device *dev, | 6189 | static int ipw_wpa_set_wpa_ie(struct net_device *dev, |
6111 | struct ipw_param *param, int plen) | 6190 | struct ipw_param *param, int plen) |
6112 | { | 6191 | { |
@@ -6172,23 +6251,26 @@ static int ipw_wpa_set_encryption(struct net_device *dev, | |||
6172 | return -EINVAL; | 6251 | return -EINVAL; |
6173 | } | 6252 | } |
6174 | 6253 | ||
6254 | sec.flags |= SEC_ENABLED | SEC_ENCRYPT; | ||
6175 | if (strcmp(param->u.crypt.alg, "none") == 0) { | 6255 | if (strcmp(param->u.crypt.alg, "none") == 0) { |
6176 | if (crypt) { | 6256 | if (crypt) { |
6177 | sec.enabled = 0; | 6257 | sec.enabled = 0; |
6178 | sec.encrypt = 0; | 6258 | sec.encrypt = 0; |
6179 | sec.level = SEC_LEVEL_0; | 6259 | sec.level = SEC_LEVEL_0; |
6180 | sec.flags |= SEC_ENABLED | SEC_LEVEL; | 6260 | sec.flags |= SEC_LEVEL; |
6181 | ieee80211_crypt_delayed_deinit(ieee, crypt); | 6261 | ieee80211_crypt_delayed_deinit(ieee, crypt); |
6182 | } | 6262 | } |
6183 | goto done; | 6263 | goto done; |
6184 | } | 6264 | } |
6185 | sec.enabled = 1; | 6265 | sec.enabled = 1; |
6186 | sec.encrypt = 1; | 6266 | sec.encrypt = 1; |
6187 | sec.flags |= SEC_ENABLED; | ||
6188 | 6267 | ||
6189 | /* IPW HW cannot build TKIP MIC, host decryption still needed. */ | 6268 | /* IPW HW cannot build TKIP MIC, host decryption still needed. */ |
6190 | if (!(ieee->host_encrypt || ieee->host_decrypt) && | 6269 | if (strcmp(param->u.crypt.alg, "TKIP") == 0) |
6191 | strcmp(param->u.crypt.alg, "TKIP")) | 6270 | ieee->host_encrypt_msdu = 1; |
6271 | |||
6272 | if (!(ieee->host_encrypt || ieee->host_encrypt_msdu || | ||
6273 | ieee->host_decrypt)) | ||
6192 | goto skip_host_crypt; | 6274 | goto skip_host_crypt; |
6193 | 6275 | ||
6194 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | 6276 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); |
@@ -6295,6 +6377,7 @@ static int ipw_wpa_set_encryption(struct net_device *dev, | |||
6295 | static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) | 6377 | static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) |
6296 | { | 6378 | { |
6297 | struct ipw_param *param; | 6379 | struct ipw_param *param; |
6380 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6298 | int ret = 0; | 6381 | int ret = 0; |
6299 | 6382 | ||
6300 | IPW_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); | 6383 | IPW_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); |
@@ -6311,6 +6394,7 @@ static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) | |||
6311 | return -EFAULT; | 6394 | return -EFAULT; |
6312 | } | 6395 | } |
6313 | 6396 | ||
6397 | down(&priv->sem); | ||
6314 | switch (param->cmd) { | 6398 | switch (param->cmd) { |
6315 | 6399 | ||
6316 | case IPW_CMD_SET_WPA_PARAM: | 6400 | case IPW_CMD_SET_WPA_PARAM: |
@@ -6337,12 +6421,313 @@ static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) | |||
6337 | ret = -EOPNOTSUPP; | 6421 | ret = -EOPNOTSUPP; |
6338 | } | 6422 | } |
6339 | 6423 | ||
6424 | up(&priv->sem); | ||
6340 | if (ret == 0 && copy_to_user(p->pointer, param, p->length)) | 6425 | if (ret == 0 && copy_to_user(p->pointer, param, p->length)) |
6341 | ret = -EFAULT; | 6426 | ret = -EFAULT; |
6342 | 6427 | ||
6343 | kfree(param); | 6428 | kfree(param); |
6344 | return ret; | 6429 | return ret; |
6345 | } | 6430 | } |
6431 | #else | ||
6432 | /* | ||
6433 | * WE-18 support | ||
6434 | */ | ||
6435 | |||
6436 | /* SIOCSIWGENIE */ | ||
6437 | static int ipw_wx_set_genie(struct net_device *dev, | ||
6438 | struct iw_request_info *info, | ||
6439 | union iwreq_data *wrqu, char *extra) | ||
6440 | { | ||
6441 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6442 | struct ieee80211_device *ieee = priv->ieee; | ||
6443 | u8 *buf; | ||
6444 | int err = 0; | ||
6445 | |||
6446 | if (wrqu->data.length > MAX_WPA_IE_LEN || | ||
6447 | (wrqu->data.length && extra == NULL)) | ||
6448 | return -EINVAL; | ||
6449 | |||
6450 | //down(&priv->sem); | ||
6451 | |||
6452 | //if (!ieee->wpa_enabled) { | ||
6453 | // err = -EOPNOTSUPP; | ||
6454 | // goto out; | ||
6455 | //} | ||
6456 | |||
6457 | if (wrqu->data.length) { | ||
6458 | buf = kmalloc(wrqu->data.length, GFP_KERNEL); | ||
6459 | if (buf == NULL) { | ||
6460 | err = -ENOMEM; | ||
6461 | goto out; | ||
6462 | } | ||
6463 | |||
6464 | memcpy(buf, extra, wrqu->data.length); | ||
6465 | kfree(ieee->wpa_ie); | ||
6466 | ieee->wpa_ie = buf; | ||
6467 | ieee->wpa_ie_len = wrqu->data.length; | ||
6468 | } else { | ||
6469 | kfree(ieee->wpa_ie); | ||
6470 | ieee->wpa_ie = NULL; | ||
6471 | ieee->wpa_ie_len = 0; | ||
6472 | } | ||
6473 | |||
6474 | ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); | ||
6475 | out: | ||
6476 | //up(&priv->sem); | ||
6477 | return err; | ||
6478 | } | ||
6479 | |||
6480 | /* SIOCGIWGENIE */ | ||
6481 | static int ipw_wx_get_genie(struct net_device *dev, | ||
6482 | struct iw_request_info *info, | ||
6483 | union iwreq_data *wrqu, char *extra) | ||
6484 | { | ||
6485 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6486 | struct ieee80211_device *ieee = priv->ieee; | ||
6487 | int err = 0; | ||
6488 | |||
6489 | //down(&priv->sem); | ||
6490 | |||
6491 | //if (!ieee->wpa_enabled) { | ||
6492 | // err = -EOPNOTSUPP; | ||
6493 | // goto out; | ||
6494 | //} | ||
6495 | |||
6496 | if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) { | ||
6497 | wrqu->data.length = 0; | ||
6498 | goto out; | ||
6499 | } | ||
6500 | |||
6501 | if (wrqu->data.length < ieee->wpa_ie_len) { | ||
6502 | err = -E2BIG; | ||
6503 | goto out; | ||
6504 | } | ||
6505 | |||
6506 | wrqu->data.length = ieee->wpa_ie_len; | ||
6507 | memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); | ||
6508 | |||
6509 | out: | ||
6510 | //up(&priv->sem); | ||
6511 | return err; | ||
6512 | } | ||
6513 | |||
6514 | /* SIOCSIWAUTH */ | ||
6515 | static int ipw_wx_set_auth(struct net_device *dev, | ||
6516 | struct iw_request_info *info, | ||
6517 | union iwreq_data *wrqu, char *extra) | ||
6518 | { | ||
6519 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6520 | struct ieee80211_device *ieee = priv->ieee; | ||
6521 | struct iw_param *param = &wrqu->param; | ||
6522 | struct ieee80211_crypt_data *crypt; | ||
6523 | unsigned long flags; | ||
6524 | int ret = 0; | ||
6525 | |||
6526 | switch (param->flags & IW_AUTH_INDEX) { | ||
6527 | case IW_AUTH_WPA_VERSION: | ||
6528 | case IW_AUTH_CIPHER_PAIRWISE: | ||
6529 | case IW_AUTH_CIPHER_GROUP: | ||
6530 | case IW_AUTH_KEY_MGMT: | ||
6531 | /* | ||
6532 | * ipw2200 does not use these parameters | ||
6533 | */ | ||
6534 | break; | ||
6535 | |||
6536 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
6537 | crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; | ||
6538 | if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { | ||
6539 | IPW_WARNING("Can't set TKIP countermeasures: " | ||
6540 | "crypt not set!\n"); | ||
6541 | break; | ||
6542 | } | ||
6543 | |||
6544 | flags = crypt->ops->get_flags(crypt->priv); | ||
6545 | |||
6546 | if (param->value) | ||
6547 | flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; | ||
6548 | else | ||
6549 | flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; | ||
6550 | |||
6551 | crypt->ops->set_flags(flags, crypt->priv); | ||
6552 | |||
6553 | break; | ||
6554 | |||
6555 | case IW_AUTH_DROP_UNENCRYPTED:{ | ||
6556 | /* HACK: | ||
6557 | * | ||
6558 | * wpa_supplicant calls set_wpa_enabled when the driver | ||
6559 | * is loaded and unloaded, regardless of if WPA is being | ||
6560 | * used. No other calls are made which can be used to | ||
6561 | * determine if encryption will be used or not prior to | ||
6562 | * association being expected. If encryption is not being | ||
6563 | * used, drop_unencrypted is set to false, else true -- we | ||
6564 | * can use this to determine if the CAP_PRIVACY_ON bit should | ||
6565 | * be set. | ||
6566 | */ | ||
6567 | struct ieee80211_security sec = { | ||
6568 | .flags = SEC_ENABLED, | ||
6569 | .enabled = param->value, | ||
6570 | }; | ||
6571 | priv->ieee->drop_unencrypted = param->value; | ||
6572 | /* We only change SEC_LEVEL for open mode. Others | ||
6573 | * are set by ipw_wpa_set_encryption. | ||
6574 | */ | ||
6575 | if (!param->value) { | ||
6576 | sec.flags |= SEC_LEVEL; | ||
6577 | sec.level = SEC_LEVEL_0; | ||
6578 | } else { | ||
6579 | sec.flags |= SEC_LEVEL; | ||
6580 | sec.level = SEC_LEVEL_1; | ||
6581 | } | ||
6582 | if (priv->ieee->set_security) | ||
6583 | priv->ieee->set_security(priv->ieee->dev, &sec); | ||
6584 | break; | ||
6585 | } | ||
6586 | |||
6587 | case IW_AUTH_80211_AUTH_ALG: | ||
6588 | ret = ipw_wpa_set_auth_algs(priv, param->value); | ||
6589 | break; | ||
6590 | |||
6591 | case IW_AUTH_WPA_ENABLED: | ||
6592 | ret = ipw_wpa_enable(priv, param->value); | ||
6593 | break; | ||
6594 | |||
6595 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
6596 | ieee->ieee802_1x = param->value; | ||
6597 | break; | ||
6598 | |||
6599 | //case IW_AUTH_ROAMING_CONTROL: | ||
6600 | case IW_AUTH_PRIVACY_INVOKED: | ||
6601 | ieee->privacy_invoked = param->value; | ||
6602 | break; | ||
6603 | |||
6604 | default: | ||
6605 | return -EOPNOTSUPP; | ||
6606 | } | ||
6607 | return ret; | ||
6608 | } | ||
6609 | |||
6610 | /* SIOCGIWAUTH */ | ||
6611 | static int ipw_wx_get_auth(struct net_device *dev, | ||
6612 | struct iw_request_info *info, | ||
6613 | union iwreq_data *wrqu, char *extra) | ||
6614 | { | ||
6615 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6616 | struct ieee80211_device *ieee = priv->ieee; | ||
6617 | struct ieee80211_crypt_data *crypt; | ||
6618 | struct iw_param *param = &wrqu->param; | ||
6619 | int ret = 0; | ||
6620 | |||
6621 | switch (param->flags & IW_AUTH_INDEX) { | ||
6622 | case IW_AUTH_WPA_VERSION: | ||
6623 | case IW_AUTH_CIPHER_PAIRWISE: | ||
6624 | case IW_AUTH_CIPHER_GROUP: | ||
6625 | case IW_AUTH_KEY_MGMT: | ||
6626 | /* | ||
6627 | * wpa_supplicant will control these internally | ||
6628 | */ | ||
6629 | ret = -EOPNOTSUPP; | ||
6630 | break; | ||
6631 | |||
6632 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
6633 | crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; | ||
6634 | if (!crypt || !crypt->ops->get_flags) { | ||
6635 | IPW_WARNING("Can't get TKIP countermeasures: " | ||
6636 | "crypt not set!\n"); | ||
6637 | break; | ||
6638 | } | ||
6639 | |||
6640 | param->value = (crypt->ops->get_flags(crypt->priv) & | ||
6641 | IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) ? 1 : 0; | ||
6642 | |||
6643 | break; | ||
6644 | |||
6645 | case IW_AUTH_DROP_UNENCRYPTED: | ||
6646 | param->value = ieee->drop_unencrypted; | ||
6647 | break; | ||
6648 | |||
6649 | case IW_AUTH_80211_AUTH_ALG: | ||
6650 | param->value = ieee->sec.auth_mode; | ||
6651 | break; | ||
6652 | |||
6653 | case IW_AUTH_WPA_ENABLED: | ||
6654 | param->value = ieee->wpa_enabled; | ||
6655 | break; | ||
6656 | |||
6657 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
6658 | param->value = ieee->ieee802_1x; | ||
6659 | break; | ||
6660 | |||
6661 | case IW_AUTH_ROAMING_CONTROL: | ||
6662 | case IW_AUTH_PRIVACY_INVOKED: | ||
6663 | param->value = ieee->privacy_invoked; | ||
6664 | break; | ||
6665 | |||
6666 | default: | ||
6667 | return -EOPNOTSUPP; | ||
6668 | } | ||
6669 | return 0; | ||
6670 | } | ||
6671 | |||
6672 | /* SIOCSIWENCODEEXT */ | ||
6673 | static int ipw_wx_set_encodeext(struct net_device *dev, | ||
6674 | struct iw_request_info *info, | ||
6675 | union iwreq_data *wrqu, char *extra) | ||
6676 | { | ||
6677 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6678 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
6679 | |||
6680 | if (hwcrypto) { | ||
6681 | /* IPW HW can't build TKIP MIC, host decryption still needed */ | ||
6682 | if (ext->alg == IW_ENCODE_ALG_TKIP) { | ||
6683 | priv->ieee->host_encrypt = 0; | ||
6684 | priv->ieee->host_encrypt_msdu = 1; | ||
6685 | priv->ieee->host_decrypt = 1; | ||
6686 | } else { | ||
6687 | priv->ieee->host_encrypt = 0; | ||
6688 | priv->ieee->host_encrypt_msdu = 0; | ||
6689 | priv->ieee->host_decrypt = 0; | ||
6690 | } | ||
6691 | } | ||
6692 | |||
6693 | return ieee80211_wx_set_encodeext(priv->ieee, info, wrqu, extra); | ||
6694 | } | ||
6695 | |||
6696 | /* SIOCGIWENCODEEXT */ | ||
6697 | static int ipw_wx_get_encodeext(struct net_device *dev, | ||
6698 | struct iw_request_info *info, | ||
6699 | union iwreq_data *wrqu, char *extra) | ||
6700 | { | ||
6701 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6702 | return ieee80211_wx_get_encodeext(priv->ieee, info, wrqu, extra); | ||
6703 | } | ||
6704 | |||
6705 | /* SIOCSIWMLME */ | ||
6706 | static int ipw_wx_set_mlme(struct net_device *dev, | ||
6707 | struct iw_request_info *info, | ||
6708 | union iwreq_data *wrqu, char *extra) | ||
6709 | { | ||
6710 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6711 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | ||
6712 | u16 reason; | ||
6713 | |||
6714 | reason = cpu_to_le16(mlme->reason_code); | ||
6715 | |||
6716 | switch (mlme->cmd) { | ||
6717 | case IW_MLME_DEAUTH: | ||
6718 | // silently ignore | ||
6719 | break; | ||
6720 | |||
6721 | case IW_MLME_DISASSOC: | ||
6722 | ipw_disassociate(priv); | ||
6723 | break; | ||
6724 | |||
6725 | default: | ||
6726 | return -EOPNOTSUPP; | ||
6727 | } | ||
6728 | return 0; | ||
6729 | } | ||
6730 | #endif | ||
6346 | 6731 | ||
6347 | #ifdef CONFIG_IPW_QOS | 6732 | #ifdef CONFIG_IPW_QOS |
6348 | 6733 | ||
@@ -6377,12 +6762,12 @@ static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, | |||
6377 | { | 6762 | { |
6378 | u32 size = sizeof(struct ieee80211_qos_parameters); | 6763 | u32 size = sizeof(struct ieee80211_qos_parameters); |
6379 | 6764 | ||
6380 | if ((network->capability & WLAN_CAPABILITY_IBSS)) | 6765 | if (network->capability & WLAN_CAPABILITY_IBSS) |
6381 | network->qos_data.active = network->qos_data.supported; | 6766 | network->qos_data.active = network->qos_data.supported; |
6382 | 6767 | ||
6383 | if (network->flags & NETWORK_HAS_QOS_MASK) { | 6768 | if (network->flags & NETWORK_HAS_QOS_MASK) { |
6384 | if (active_network | 6769 | if (active_network && |
6385 | && (network->flags & NETWORK_HAS_QOS_PARAMETERS)) | 6770 | (network->flags & NETWORK_HAS_QOS_PARAMETERS)) |
6386 | network->qos_data.active = network->qos_data.supported; | 6771 | network->qos_data.active = network->qos_data.supported; |
6387 | 6772 | ||
6388 | if ((network->qos_data.active == 1) && (active_network == 1) && | 6773 | if ((network->qos_data.active == 1) && (active_network == 1) && |
@@ -6392,17 +6777,17 @@ static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, | |||
6392 | network->qos_data.old_param_count = | 6777 | network->qos_data.old_param_count = |
6393 | network->qos_data.param_count; | 6778 | network->qos_data.param_count; |
6394 | schedule_work(&priv->qos_activate); | 6779 | schedule_work(&priv->qos_activate); |
6395 | IPW_DEBUG_QOS | 6780 | IPW_DEBUG_QOS("QoS parameters change call " |
6396 | ("QoS parameters change call qos_activate\n"); | 6781 | "qos_activate\n"); |
6397 | } | 6782 | } |
6398 | } else { | 6783 | } else { |
6399 | if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B)) { | 6784 | if ((priv->ieee->mode == IEEE_B) || (network->mode == IEEE_B)) |
6400 | memcpy(&(network->qos_data.parameters), | 6785 | memcpy(&network->qos_data.parameters, |
6401 | &def_parameters_CCK, size); | 6786 | &def_parameters_CCK, size); |
6402 | } else { | 6787 | else |
6403 | memcpy(&(network->qos_data.parameters), | 6788 | memcpy(&network->qos_data.parameters, |
6404 | &def_parameters_OFDM, size); | 6789 | &def_parameters_OFDM, size); |
6405 | } | 6790 | |
6406 | if ((network->qos_data.active == 1) && (active_network == 1)) { | 6791 | if ((network->qos_data.active == 1) && (active_network == 1)) { |
6407 | IPW_DEBUG_QOS("QoS was disabled call qos_activate \n"); | 6792 | IPW_DEBUG_QOS("QoS was disabled call qos_activate \n"); |
6408 | schedule_work(&priv->qos_activate); | 6793 | schedule_work(&priv->qos_activate); |
@@ -6411,24 +6796,19 @@ static int ipw_qos_handle_probe_reponse(struct ipw_priv *priv, | |||
6411 | network->qos_data.active = 0; | 6796 | network->qos_data.active = 0; |
6412 | network->qos_data.supported = 0; | 6797 | network->qos_data.supported = 0; |
6413 | } | 6798 | } |
6414 | if ((priv->status & STATUS_ASSOCIATED) | 6799 | if ((priv->status & STATUS_ASSOCIATED) && |
6415 | && (priv->ieee->iw_mode == IW_MODE_ADHOC) | 6800 | (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { |
6416 | && (active_network == 0)) { | 6801 | if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) |
6417 | 6802 | if ((network->capability & WLAN_CAPABILITY_IBSS) && | |
6418 | if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) { | 6803 | !(network->flags & NETWORK_EMPTY_ESSID)) |
6419 | if ((network->capability & WLAN_CAPABILITY_IBSS) | ||
6420 | && !(network->flags & NETWORK_EMPTY_ESSID)) { | ||
6421 | if ((network->ssid_len == | 6804 | if ((network->ssid_len == |
6422 | priv->assoc_network->ssid_len) | 6805 | priv->assoc_network->ssid_len) && |
6423 | && !memcmp(network->ssid, | 6806 | !memcmp(network->ssid, |
6424 | priv->assoc_network->ssid, | 6807 | priv->assoc_network->ssid, |
6425 | network->ssid_len)) { | 6808 | network->ssid_len)) { |
6426 | queue_work(priv->workqueue, | 6809 | queue_work(priv->workqueue, |
6427 | &priv->merge_networks); | 6810 | &priv->merge_networks); |
6428 | } | 6811 | } |
6429 | |||
6430 | } | ||
6431 | } | ||
6432 | } | 6812 | } |
6433 | 6813 | ||
6434 | return 0; | 6814 | return 0; |
@@ -6463,13 +6843,12 @@ static int ipw_qos_activate(struct ipw_priv *priv, | |||
6463 | } else | 6843 | } else |
6464 | active_one = &def_parameters_OFDM; | 6844 | active_one = &def_parameters_OFDM; |
6465 | 6845 | ||
6466 | memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, | 6846 | memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); |
6467 | size); | ||
6468 | burst_duration = ipw_qos_get_burst_duration(priv); | 6847 | burst_duration = ipw_qos_get_burst_duration(priv); |
6469 | for (i = 0; i < QOS_QUEUE_NUM; i++) | 6848 | for (i = 0; i < QOS_QUEUE_NUM; i++) |
6470 | qos_parameters[QOS_PARAM_SET_ACTIVE]. | 6849 | qos_parameters[QOS_PARAM_SET_ACTIVE].tx_op_limit[i] = |
6471 | tx_op_limit[i] = (u16) burst_duration; | 6850 | (u16) burst_duration; |
6472 | } else if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { | 6851 | } else if (priv->ieee->iw_mode == IW_MODE_ADHOC) { |
6473 | if (type == IEEE_B) { | 6852 | if (type == IEEE_B) { |
6474 | IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", | 6853 | IPW_DEBUG_QOS("QoS activate IBSS nework mode %d\n", |
6475 | type); | 6854 | type); |
@@ -6483,8 +6862,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, | |||
6483 | else | 6862 | else |
6484 | active_one = priv->qos_data.def_qos_parm_OFDM; | 6863 | active_one = priv->qos_data.def_qos_parm_OFDM; |
6485 | } | 6864 | } |
6486 | memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, | 6865 | memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); |
6487 | size); | ||
6488 | } else { | 6866 | } else { |
6489 | unsigned long flags; | 6867 | unsigned long flags; |
6490 | int active; | 6868 | int active; |
@@ -6493,8 +6871,7 @@ static int ipw_qos_activate(struct ipw_priv *priv, | |||
6493 | active_one = &(qos_network_data->parameters); | 6871 | active_one = &(qos_network_data->parameters); |
6494 | qos_network_data->old_param_count = | 6872 | qos_network_data->old_param_count = |
6495 | qos_network_data->param_count; | 6873 | qos_network_data->param_count; |
6496 | memcpy(&(qos_parameters[QOS_PARAM_SET_ACTIVE]), active_one, | 6874 | memcpy(&qos_parameters[QOS_PARAM_SET_ACTIVE], active_one, size); |
6497 | size); | ||
6498 | active = qos_network_data->supported; | 6875 | active = qos_network_data->supported; |
6499 | spin_unlock_irqrestore(&priv->ieee->lock, flags); | 6876 | spin_unlock_irqrestore(&priv->ieee->lock, flags); |
6500 | 6877 | ||
@@ -6507,10 +6884,9 @@ static int ipw_qos_activate(struct ipw_priv *priv, | |||
6507 | } | 6884 | } |
6508 | 6885 | ||
6509 | IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); | 6886 | IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n"); |
6510 | err = | 6887 | err = ipw_send_qos_params_command(priv, |
6511 | ipw_send_qos_params_command(priv, | 6888 | (struct ieee80211_qos_parameters *) |
6512 | (struct ieee80211_qos_parameters *) | 6889 | &(qos_parameters[0])); |
6513 | &(qos_parameters[0])); | ||
6514 | if (err) | 6890 | if (err) |
6515 | IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); | 6891 | IPW_DEBUG_QOS("QoS IPW_CMD_QOS_PARAMETERS failed\n"); |
6516 | 6892 | ||
@@ -6603,21 +6979,19 @@ static int ipw_qos_association_resp(struct ipw_priv *priv, | |||
6603 | u32 size = sizeof(struct ieee80211_qos_parameters); | 6979 | u32 size = sizeof(struct ieee80211_qos_parameters); |
6604 | int set_qos_param = 0; | 6980 | int set_qos_param = 0; |
6605 | 6981 | ||
6606 | if ((priv == NULL) || (network == NULL) | 6982 | if ((priv == NULL) || (network == NULL) || |
6607 | || (priv->assoc_network == NULL)) | 6983 | (priv->assoc_network == NULL)) |
6608 | |||
6609 | return ret; | 6984 | return ret; |
6610 | 6985 | ||
6611 | if (!(priv->status & STATUS_ASSOCIATED)) | 6986 | if (!(priv->status & STATUS_ASSOCIATED)) |
6612 | return ret; | 6987 | return ret; |
6613 | 6988 | ||
6614 | if ((priv->ieee->iw_mode != IW_MODE_INFRA)) { | 6989 | if ((priv->ieee->iw_mode != IW_MODE_INFRA)) |
6615 | return ret; | 6990 | return ret; |
6616 | } | ||
6617 | 6991 | ||
6618 | spin_lock_irqsave(&priv->ieee->lock, flags); | 6992 | spin_lock_irqsave(&priv->ieee->lock, flags); |
6619 | if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { | 6993 | if (network->flags & NETWORK_HAS_QOS_PARAMETERS) { |
6620 | memcpy(&(priv->assoc_network->qos_data), &(network->qos_data), | 6994 | memcpy(&priv->assoc_network->qos_data, &network->qos_data, |
6621 | sizeof(struct ieee80211_qos_data)); | 6995 | sizeof(struct ieee80211_qos_data)); |
6622 | priv->assoc_network->qos_data.active = 1; | 6996 | priv->assoc_network->qos_data.active = 1; |
6623 | if ((network->qos_data.old_param_count != | 6997 | if ((network->qos_data.old_param_count != |
@@ -6628,13 +7002,12 @@ static int ipw_qos_association_resp(struct ipw_priv *priv, | |||
6628 | } | 7002 | } |
6629 | 7003 | ||
6630 | } else { | 7004 | } else { |
6631 | if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B)) { | 7005 | if ((network->mode == IEEE_B) || (priv->ieee->mode == IEEE_B)) |
6632 | memcpy(&(priv->assoc_network->qos_data.parameters), | 7006 | memcpy(&priv->assoc_network->qos_data.parameters, |
6633 | &def_parameters_CCK, size); | 7007 | &def_parameters_CCK, size); |
6634 | } else { | 7008 | else |
6635 | memcpy(&(priv->assoc_network->qos_data.parameters), | 7009 | memcpy(&priv->assoc_network->qos_data.parameters, |
6636 | &def_parameters_OFDM, size); | 7010 | &def_parameters_OFDM, size); |
6637 | } | ||
6638 | priv->assoc_network->qos_data.active = 0; | 7011 | priv->assoc_network->qos_data.active = 0; |
6639 | priv->assoc_network->qos_data.supported = 0; | 7012 | priv->assoc_network->qos_data.supported = 0; |
6640 | set_qos_param = 1; | 7013 | set_qos_param = 1; |
@@ -6655,11 +7028,11 @@ static u32 ipw_qos_get_burst_duration(struct ipw_priv *priv) | |||
6655 | if ((priv == NULL)) | 7028 | if ((priv == NULL)) |
6656 | return 0; | 7029 | return 0; |
6657 | 7030 | ||
6658 | if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) { | 7031 | if (!(priv->ieee->modulation & IEEE80211_OFDM_MODULATION)) |
6659 | ret = priv->qos_data.burst_duration_CCK; | 7032 | ret = priv->qos_data.burst_duration_CCK; |
6660 | } else { | 7033 | else |
6661 | ret = priv->qos_data.burst_duration_OFDM; | 7034 | ret = priv->qos_data.burst_duration_OFDM; |
6662 | } | 7035 | |
6663 | return ret; | 7036 | return ret; |
6664 | } | 7037 | } |
6665 | 7038 | ||
@@ -6736,9 +7109,9 @@ static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv, | |||
6736 | 7109 | ||
6737 | spin_unlock_irqrestore(&priv->ieee->lock, flags); | 7110 | spin_unlock_irqrestore(&priv->ieee->lock, flags); |
6738 | 7111 | ||
6739 | IPW_DEBUG_QOS | 7112 | IPW_DEBUG_QOS("QoS %d network is QoS active %d supported %d " |
6740 | ("QoS %d network is QoS active %d supported %d unicast %d\n", | 7113 | "unicast %d\n", |
6741 | priv->qos_data.qos_enable, active, supported, unicast); | 7114 | priv->qos_data.qos_enable, active, supported, unicast); |
6742 | if (active && priv->qos_data.qos_enable) { | 7115 | if (active && priv->qos_data.qos_enable) { |
6743 | ret = from_priority_to_tx_queue[priority]; | 7116 | ret = from_priority_to_tx_queue[priority]; |
6744 | tx_queue_id = ret - 1; | 7117 | tx_queue_id = ret - 1; |
@@ -6822,8 +7195,7 @@ static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_q | |||
6822 | return -1; | 7195 | return -1; |
6823 | } | 7196 | } |
6824 | 7197 | ||
6825 | memcpy(&cmd.param, qos_param, | 7198 | memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3); |
6826 | (sizeof(struct ieee80211_qos_parameters) * 3)); | ||
6827 | if (ipw_send_cmd(priv, &cmd)) { | 7199 | if (ipw_send_cmd(priv, &cmd)) { |
6828 | IPW_ERROR("failed to send IPW_CMD_QOS_PARAMETERS command\n"); | 7200 | IPW_ERROR("failed to send IPW_CMD_QOS_PARAMETERS command\n"); |
6829 | return -1; | 7201 | return -1; |
@@ -6845,7 +7217,7 @@ static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos | |||
6845 | return -1; | 7217 | return -1; |
6846 | } | 7218 | } |
6847 | 7219 | ||
6848 | memcpy(&cmd.param, qos_param, sizeof(*qos_param)); | 7220 | memcpy(cmd.param, qos_param, sizeof(*qos_param)); |
6849 | if (ipw_send_cmd(priv, &cmd)) { | 7221 | if (ipw_send_cmd(priv, &cmd)) { |
6850 | IPW_ERROR("failed to send CMD_QOS_INFO command\n"); | 7222 | IPW_ERROR("failed to send CMD_QOS_INFO command\n"); |
6851 | return -1; | 7223 | return -1; |
@@ -6919,6 +7291,11 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
6919 | ~WLAN_CAPABILITY_SHORT_PREAMBLE; | 7291 | ~WLAN_CAPABILITY_SHORT_PREAMBLE; |
6920 | } | 7292 | } |
6921 | 7293 | ||
7294 | /* Clear capability bits that aren't used in Ad Hoc */ | ||
7295 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) | ||
7296 | priv->assoc_request.capability &= | ||
7297 | ~WLAN_CAPABILITY_SHORT_SLOT_TIME; | ||
7298 | |||
6922 | IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " | 7299 | IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " |
6923 | "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", | 7300 | "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", |
6924 | roaming ? "Rea" : "A", | 7301 | roaming ? "Rea" : "A", |
@@ -6954,13 +7331,13 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
6954 | priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0]; | 7331 | priv->assoc_request.assoc_tsf_lsw = network->time_stamp[0]; |
6955 | } | 7332 | } |
6956 | 7333 | ||
6957 | memcpy(&priv->assoc_request.bssid, network->bssid, ETH_ALEN); | 7334 | memcpy(priv->assoc_request.bssid, network->bssid, ETH_ALEN); |
6958 | 7335 | ||
6959 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { | 7336 | if (priv->ieee->iw_mode == IW_MODE_ADHOC) { |
6960 | memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); | 7337 | memset(&priv->assoc_request.dest, 0xFF, ETH_ALEN); |
6961 | priv->assoc_request.atim_window = network->atim_window; | 7338 | priv->assoc_request.atim_window = network->atim_window; |
6962 | } else { | 7339 | } else { |
6963 | memcpy(&priv->assoc_request.dest, network->bssid, ETH_ALEN); | 7340 | memcpy(priv->assoc_request.dest, network->bssid, ETH_ALEN); |
6964 | priv->assoc_request.atim_window = 0; | 7341 | priv->assoc_request.atim_window = 0; |
6965 | } | 7342 | } |
6966 | 7343 | ||
@@ -7119,14 +7496,14 @@ static int ipw_associate(void *data) | |||
7119 | } | 7496 | } |
7120 | 7497 | ||
7121 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 7498 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { |
7122 | IPW_DEBUG_ASSOC | 7499 | IPW_DEBUG_ASSOC("Not attempting association (already in " |
7123 | ("Not attempting association (already in progress)\n"); | 7500 | "progress)\n"); |
7124 | return 0; | 7501 | return 0; |
7125 | } | 7502 | } |
7126 | 7503 | ||
7127 | if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { | 7504 | if (!ipw_is_init(priv) || (priv->status & STATUS_SCANNING)) { |
7128 | IPW_DEBUG_ASSOC | 7505 | IPW_DEBUG_ASSOC("Not attempting association (scanning or not " |
7129 | ("Not attempting association (scanning or not initialized)\n"); | 7506 | "initialized)\n"); |
7130 | return 0; | 7507 | return 0; |
7131 | } | 7508 | } |
7132 | 7509 | ||
@@ -7285,9 +7662,8 @@ static inline int is_network_packet(struct ipw_priv *priv, | |||
7285 | if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) | 7662 | if (!memcmp(header->addr2, priv->net_dev->dev_addr, ETH_ALEN)) |
7286 | return 0; | 7663 | return 0; |
7287 | 7664 | ||
7288 | /* {broad,multi}cast packets to our IBSS go through */ | 7665 | /* multicast packets to our IBSS go through */ |
7289 | if (is_broadcast_ether_addr(header->addr1) || | 7666 | if (is_multicast_ether_addr(header->addr1)) |
7290 | is_multicast_ether_addr(header->addr1)) | ||
7291 | return !memcmp(header->addr3, priv->bssid, ETH_ALEN); | 7667 | return !memcmp(header->addr3, priv->bssid, ETH_ALEN); |
7292 | 7668 | ||
7293 | /* packets to our adapter go through */ | 7669 | /* packets to our adapter go through */ |
@@ -7300,8 +7676,7 @@ static inline int is_network_packet(struct ipw_priv *priv, | |||
7300 | return 0; | 7676 | return 0; |
7301 | 7677 | ||
7302 | /* {broad,multi}cast packets to our IBSS go through */ | 7678 | /* {broad,multi}cast packets to our IBSS go through */ |
7303 | if (is_broadcast_ether_addr(header->addr1) || | 7679 | if (is_multicast_ether_addr(header->addr1)) |
7304 | is_multicast_ether_addr(header->addr1)) | ||
7305 | return !memcmp(header->addr2, priv->bssid, ETH_ALEN); | 7680 | return !memcmp(header->addr2, priv->bssid, ETH_ALEN); |
7306 | 7681 | ||
7307 | /* packets to our adapter go through */ | 7682 | /* packets to our adapter go through */ |
@@ -7312,6 +7687,79 @@ static inline int is_network_packet(struct ipw_priv *priv, | |||
7312 | return 1; | 7687 | return 1; |
7313 | } | 7688 | } |
7314 | 7689 | ||
7690 | #define IPW_PACKET_RETRY_TIME HZ | ||
7691 | |||
7692 | static inline int is_duplicate_packet(struct ipw_priv *priv, | ||
7693 | struct ieee80211_hdr_4addr *header) | ||
7694 | { | ||
7695 | u16 fc = le16_to_cpu(header->frame_ctl); | ||
7696 | u16 sc = le16_to_cpu(header->seq_ctl); | ||
7697 | u16 seq = WLAN_GET_SEQ_SEQ(sc); | ||
7698 | u16 frag = WLAN_GET_SEQ_FRAG(sc); | ||
7699 | u16 *last_seq, *last_frag; | ||
7700 | unsigned long *last_time; | ||
7701 | |||
7702 | switch (priv->ieee->iw_mode) { | ||
7703 | case IW_MODE_ADHOC: | ||
7704 | { | ||
7705 | struct list_head *p; | ||
7706 | struct ipw_ibss_seq *entry = NULL; | ||
7707 | u8 *mac = header->addr2; | ||
7708 | int index = mac[5] % IPW_IBSS_MAC_HASH_SIZE; | ||
7709 | |||
7710 | __list_for_each(p, &priv->ibss_mac_hash[index]) { | ||
7711 | entry = | ||
7712 | list_entry(p, struct ipw_ibss_seq, list); | ||
7713 | if (!memcmp(entry->mac, mac, ETH_ALEN)) | ||
7714 | break; | ||
7715 | } | ||
7716 | if (p == &priv->ibss_mac_hash[index]) { | ||
7717 | entry = kmalloc(sizeof(*entry), GFP_ATOMIC); | ||
7718 | if (!entry) { | ||
7719 | IPW_ERROR | ||
7720 | ("Cannot malloc new mac entry\n"); | ||
7721 | return 0; | ||
7722 | } | ||
7723 | memcpy(entry->mac, mac, ETH_ALEN); | ||
7724 | entry->seq_num = seq; | ||
7725 | entry->frag_num = frag; | ||
7726 | entry->packet_time = jiffies; | ||
7727 | list_add(&entry->list, | ||
7728 | &priv->ibss_mac_hash[index]); | ||
7729 | return 0; | ||
7730 | } | ||
7731 | last_seq = &entry->seq_num; | ||
7732 | last_frag = &entry->frag_num; | ||
7733 | last_time = &entry->packet_time; | ||
7734 | break; | ||
7735 | } | ||
7736 | case IW_MODE_INFRA: | ||
7737 | last_seq = &priv->last_seq_num; | ||
7738 | last_frag = &priv->last_frag_num; | ||
7739 | last_time = &priv->last_packet_time; | ||
7740 | break; | ||
7741 | default: | ||
7742 | return 0; | ||
7743 | } | ||
7744 | if ((*last_seq == seq) && | ||
7745 | time_after(*last_time + IPW_PACKET_RETRY_TIME, jiffies)) { | ||
7746 | if (*last_frag == frag) | ||
7747 | goto drop; | ||
7748 | if (*last_frag + 1 != frag) | ||
7749 | /* out-of-order fragment */ | ||
7750 | goto drop; | ||
7751 | *last_frag = frag; | ||
7752 | } else | ||
7753 | *last_seq = seq; | ||
7754 | |||
7755 | *last_time = jiffies; | ||
7756 | return 0; | ||
7757 | |||
7758 | drop: | ||
7759 | BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); | ||
7760 | return 1; | ||
7761 | } | ||
7762 | |||
7315 | static void ipw_handle_mgmt_packet(struct ipw_priv *priv, | 7763 | static void ipw_handle_mgmt_packet(struct ipw_priv *priv, |
7316 | struct ipw_rx_mem_buffer *rxb, | 7764 | struct ipw_rx_mem_buffer *rxb, |
7317 | struct ieee80211_rx_stats *stats) | 7765 | struct ieee80211_rx_stats *stats) |
@@ -7481,7 +7929,10 @@ static void ipw_rx(struct ipw_priv *priv) | |||
7481 | break; | 7929 | break; |
7482 | 7930 | ||
7483 | case IEEE80211_FTYPE_DATA: | 7931 | case IEEE80211_FTYPE_DATA: |
7484 | if (unlikely(!network_packet)) { | 7932 | if (unlikely(!network_packet || |
7933 | is_duplicate_packet(priv, | ||
7934 | header))) | ||
7935 | { | ||
7485 | IPW_DEBUG_DROP("Dropping: " | 7936 | IPW_DEBUG_DROP("Dropping: " |
7486 | MAC_FMT ", " | 7937 | MAC_FMT ", " |
7487 | MAC_FMT ", " | 7938 | MAC_FMT ", " |
@@ -7540,6 +7991,123 @@ static void ipw_rx(struct ipw_priv *priv) | |||
7540 | ipw_rx_queue_restock(priv); | 7991 | ipw_rx_queue_restock(priv); |
7541 | } | 7992 | } |
7542 | 7993 | ||
7994 | #define DEFAULT_RTS_THRESHOLD 2304U | ||
7995 | #define MIN_RTS_THRESHOLD 1U | ||
7996 | #define MAX_RTS_THRESHOLD 2304U | ||
7997 | #define DEFAULT_BEACON_INTERVAL 100U | ||
7998 | #define DEFAULT_SHORT_RETRY_LIMIT 7U | ||
7999 | #define DEFAULT_LONG_RETRY_LIMIT 4U | ||
8000 | |||
8001 | static int ipw_sw_reset(struct ipw_priv *priv, int init) | ||
8002 | { | ||
8003 | int band, modulation; | ||
8004 | int old_mode = priv->ieee->iw_mode; | ||
8005 | |||
8006 | /* Initialize module parameter values here */ | ||
8007 | priv->config = 0; | ||
8008 | |||
8009 | /* We default to disabling the LED code as right now it causes | ||
8010 | * too many systems to lock up... */ | ||
8011 | if (!led) | ||
8012 | priv->config |= CFG_NO_LED; | ||
8013 | |||
8014 | if (associate) | ||
8015 | priv->config |= CFG_ASSOCIATE; | ||
8016 | else | ||
8017 | IPW_DEBUG_INFO("Auto associate disabled.\n"); | ||
8018 | |||
8019 | if (auto_create) | ||
8020 | priv->config |= CFG_ADHOC_CREATE; | ||
8021 | else | ||
8022 | IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); | ||
8023 | |||
8024 | if (disable) { | ||
8025 | priv->status |= STATUS_RF_KILL_SW; | ||
8026 | IPW_DEBUG_INFO("Radio disabled.\n"); | ||
8027 | } | ||
8028 | |||
8029 | if (channel != 0) { | ||
8030 | priv->config |= CFG_STATIC_CHANNEL; | ||
8031 | priv->channel = channel; | ||
8032 | IPW_DEBUG_INFO("Bind to static channel %d\n", channel); | ||
8033 | /* TODO: Validate that provided channel is in range */ | ||
8034 | } | ||
8035 | #ifdef CONFIG_IPW_QOS | ||
8036 | ipw_qos_init(priv, qos_enable, qos_burst_enable, | ||
8037 | burst_duration_CCK, burst_duration_OFDM); | ||
8038 | #endif /* CONFIG_IPW_QOS */ | ||
8039 | |||
8040 | switch (mode) { | ||
8041 | case 1: | ||
8042 | priv->ieee->iw_mode = IW_MODE_ADHOC; | ||
8043 | priv->net_dev->type = ARPHRD_ETHER; | ||
8044 | |||
8045 | break; | ||
8046 | #ifdef CONFIG_IPW2200_MONITOR | ||
8047 | case 2: | ||
8048 | priv->ieee->iw_mode = IW_MODE_MONITOR; | ||
8049 | priv->net_dev->type = ARPHRD_IEEE80211; | ||
8050 | break; | ||
8051 | #endif | ||
8052 | default: | ||
8053 | case 0: | ||
8054 | priv->net_dev->type = ARPHRD_ETHER; | ||
8055 | priv->ieee->iw_mode = IW_MODE_INFRA; | ||
8056 | break; | ||
8057 | } | ||
8058 | |||
8059 | if (hwcrypto) { | ||
8060 | priv->ieee->host_encrypt = 0; | ||
8061 | priv->ieee->host_encrypt_msdu = 0; | ||
8062 | priv->ieee->host_decrypt = 0; | ||
8063 | } | ||
8064 | IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); | ||
8065 | |||
8066 | if ((priv->pci_dev->device == 0x4223) || | ||
8067 | (priv->pci_dev->device == 0x4224)) { | ||
8068 | if (init) | ||
8069 | printk(KERN_INFO DRV_NAME | ||
8070 | ": Detected Intel PRO/Wireless 2915ABG Network " | ||
8071 | "Connection\n"); | ||
8072 | priv->ieee->abg_true = 1; | ||
8073 | band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; | ||
8074 | modulation = IEEE80211_OFDM_MODULATION | | ||
8075 | IEEE80211_CCK_MODULATION; | ||
8076 | priv->adapter = IPW_2915ABG; | ||
8077 | priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; | ||
8078 | } else { | ||
8079 | if (init) | ||
8080 | printk(KERN_INFO DRV_NAME | ||
8081 | ": Detected Intel PRO/Wireless 2200BG Network " | ||
8082 | "Connection\n"); | ||
8083 | |||
8084 | priv->ieee->abg_true = 0; | ||
8085 | band = IEEE80211_24GHZ_BAND; | ||
8086 | modulation = IEEE80211_OFDM_MODULATION | | ||
8087 | IEEE80211_CCK_MODULATION; | ||
8088 | priv->adapter = IPW_2200BG; | ||
8089 | priv->ieee->mode = IEEE_G | IEEE_B; | ||
8090 | } | ||
8091 | |||
8092 | priv->ieee->freq_band = band; | ||
8093 | priv->ieee->modulation = modulation; | ||
8094 | |||
8095 | priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; | ||
8096 | |||
8097 | priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; | ||
8098 | priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; | ||
8099 | |||
8100 | priv->rts_threshold = DEFAULT_RTS_THRESHOLD; | ||
8101 | priv->short_retry_limit = DEFAULT_SHORT_RETRY_LIMIT; | ||
8102 | priv->long_retry_limit = DEFAULT_LONG_RETRY_LIMIT; | ||
8103 | |||
8104 | /* If power management is turned on, default to AC mode */ | ||
8105 | priv->power_mode = IPW_POWER_AC; | ||
8106 | priv->tx_power = IPW_TX_POWER_DEFAULT; | ||
8107 | |||
8108 | return old_mode == priv->ieee->mode; | ||
8109 | } | ||
8110 | |||
7543 | /* | 8111 | /* |
7544 | * This file defines the Wireless Extension handlers. It does not | 8112 | * This file defines the Wireless Extension handlers. It does not |
7545 | * define any methods of hardware manipulation and relies on the | 8113 | * define any methods of hardware manipulation and relies on the |
@@ -7570,8 +8138,6 @@ static int ipw_wx_get_name(struct net_device *dev, | |||
7570 | 8138 | ||
7571 | static int ipw_set_channel(struct ipw_priv *priv, u8 channel) | 8139 | static int ipw_set_channel(struct ipw_priv *priv, u8 channel) |
7572 | { | 8140 | { |
7573 | int i; | ||
7574 | |||
7575 | if (channel == 0) { | 8141 | if (channel == 0) { |
7576 | IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); | 8142 | IPW_DEBUG_INFO("Setting channel to ANY (0)\n"); |
7577 | priv->config &= ~CFG_STATIC_CHANNEL; | 8143 | priv->config &= ~CFG_STATIC_CHANNEL; |
@@ -7594,10 +8160,11 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) | |||
7594 | 8160 | ||
7595 | #ifdef CONFIG_IPW2200_MONITOR | 8161 | #ifdef CONFIG_IPW2200_MONITOR |
7596 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 8162 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
8163 | int i; | ||
7597 | if (priv->status & STATUS_SCANNING) { | 8164 | if (priv->status & STATUS_SCANNING) { |
7598 | IPW_DEBUG_SCAN("scan abort triggered due to " | 8165 | IPW_DEBUG_SCAN("Scan abort triggered due to " |
7599 | "channel change.\n"); | 8166 | "channel change.\n"); |
7600 | queue_work(priv->workqueue, &priv->abort_scan); | 8167 | ipw_abort_scan(priv); |
7601 | } | 8168 | } |
7602 | 8169 | ||
7603 | for (i = 1000; i && (priv->status & STATUS_SCANNING); i--) | 8170 | for (i = 1000; i && (priv->status & STATUS_SCANNING); i--) |
@@ -7626,8 +8193,9 @@ static int ipw_wx_set_freq(struct net_device *dev, | |||
7626 | union iwreq_data *wrqu, char *extra) | 8193 | union iwreq_data *wrqu, char *extra) |
7627 | { | 8194 | { |
7628 | struct ipw_priv *priv = ieee80211_priv(dev); | 8195 | struct ipw_priv *priv = ieee80211_priv(dev); |
8196 | const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); | ||
7629 | struct iw_freq *fwrq = &wrqu->freq; | 8197 | struct iw_freq *fwrq = &wrqu->freq; |
7630 | int ret = 0; | 8198 | int ret = 0, i; |
7631 | u8 channel; | 8199 | u8 channel; |
7632 | 8200 | ||
7633 | if (fwrq->m == 0) { | 8201 | if (fwrq->m == 0) { |
@@ -7637,7 +8205,6 @@ static int ipw_wx_set_freq(struct net_device *dev, | |||
7637 | up(&priv->sem); | 8205 | up(&priv->sem); |
7638 | return ret; | 8206 | return ret; |
7639 | } | 8207 | } |
7640 | |||
7641 | /* if setting by freq convert to channel */ | 8208 | /* if setting by freq convert to channel */ |
7642 | if (fwrq->e == 1) { | 8209 | if (fwrq->e == 1) { |
7643 | channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); | 8210 | channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); |
@@ -7649,6 +8216,16 @@ static int ipw_wx_set_freq(struct net_device *dev, | |||
7649 | if (!ieee80211_is_valid_channel(priv->ieee, channel)) | 8216 | if (!ieee80211_is_valid_channel(priv->ieee, channel)) |
7650 | return -EINVAL; | 8217 | return -EINVAL; |
7651 | 8218 | ||
8219 | if (priv->ieee->iw_mode == IW_MODE_ADHOC && priv->ieee->mode & IEEE_A) { | ||
8220 | i = ieee80211_channel_to_index(priv->ieee, channel); | ||
8221 | if (i == -1) | ||
8222 | return -EINVAL; | ||
8223 | if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { | ||
8224 | IPW_DEBUG_WX("Invalid Ad-Hoc channel for 802.11a\n"); | ||
8225 | return -EINVAL; | ||
8226 | } | ||
8227 | } | ||
8228 | |||
7652 | IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); | 8229 | IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); |
7653 | down(&priv->sem); | 8230 | down(&priv->sem); |
7654 | ret = ipw_set_channel(priv, channel); | 8231 | ret = ipw_set_channel(priv, channel); |
@@ -7704,6 +8281,9 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
7704 | return 0; | 8281 | return 0; |
7705 | 8282 | ||
7706 | down(&priv->sem); | 8283 | down(&priv->sem); |
8284 | |||
8285 | ipw_sw_reset(priv, 0); | ||
8286 | |||
7707 | #ifdef CONFIG_IPW2200_MONITOR | 8287 | #ifdef CONFIG_IPW2200_MONITOR |
7708 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) | 8288 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) |
7709 | priv->net_dev->type = ARPHRD_ETHER; | 8289 | priv->net_dev->type = ARPHRD_ETHER; |
@@ -7712,17 +8292,9 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
7712 | priv->net_dev->type = ARPHRD_IEEE80211; | 8292 | priv->net_dev->type = ARPHRD_IEEE80211; |
7713 | #endif /* CONFIG_IPW2200_MONITOR */ | 8293 | #endif /* CONFIG_IPW2200_MONITOR */ |
7714 | 8294 | ||
7715 | #ifdef CONFIG_PM | ||
7716 | /* Free the existing firmware and reset the fw_loaded | 8295 | /* Free the existing firmware and reset the fw_loaded |
7717 | * flag so ipw_load() will bring in the new firmawre */ | 8296 | * flag so ipw_load() will bring in the new firmawre */ |
7718 | if (fw_loaded) | 8297 | free_firmware(); |
7719 | fw_loaded = 0; | ||
7720 | |||
7721 | release_firmware(bootfw); | ||
7722 | release_firmware(ucode); | ||
7723 | release_firmware(firmware); | ||
7724 | bootfw = ucode = firmware = NULL; | ||
7725 | #endif | ||
7726 | 8298 | ||
7727 | priv->ieee->iw_mode = wrqu->mode; | 8299 | priv->ieee->iw_mode = wrqu->mode; |
7728 | 8300 | ||
@@ -7743,13 +8315,6 @@ static int ipw_wx_get_mode(struct net_device *dev, | |||
7743 | return 0; | 8315 | return 0; |
7744 | } | 8316 | } |
7745 | 8317 | ||
7746 | #define DEFAULT_RTS_THRESHOLD 2304U | ||
7747 | #define MIN_RTS_THRESHOLD 1U | ||
7748 | #define MAX_RTS_THRESHOLD 2304U | ||
7749 | #define DEFAULT_BEACON_INTERVAL 100U | ||
7750 | #define DEFAULT_SHORT_RETRY_LIMIT 7U | ||
7751 | #define DEFAULT_LONG_RETRY_LIMIT 4U | ||
7752 | |||
7753 | /* Values are in microsecond */ | 8318 | /* Values are in microsecond */ |
7754 | static const s32 timeout_duration[] = { | 8319 | static const s32 timeout_duration[] = { |
7755 | 350000, | 8320 | 350000, |
@@ -7900,7 +8465,7 @@ static int ipw_wx_get_wap(struct net_device *dev, | |||
7900 | if (priv->config & CFG_STATIC_BSSID || | 8465 | if (priv->config & CFG_STATIC_BSSID || |
7901 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 8466 | priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { |
7902 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; | 8467 | wrqu->ap_addr.sa_family = ARPHRD_ETHER; |
7903 | memcpy(wrqu->ap_addr.sa_data, &priv->bssid, ETH_ALEN); | 8468 | memcpy(wrqu->ap_addr.sa_data, priv->bssid, ETH_ALEN); |
7904 | } else | 8469 | } else |
7905 | memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); | 8470 | memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); |
7906 | 8471 | ||
@@ -7924,10 +8489,12 @@ static int ipw_wx_set_essid(struct net_device *dev, | |||
7924 | } | 8489 | } |
7925 | if (length == 0) { | 8490 | if (length == 0) { |
7926 | IPW_DEBUG_WX("Setting ESSID to ANY\n"); | 8491 | IPW_DEBUG_WX("Setting ESSID to ANY\n"); |
7927 | priv->config &= ~CFG_STATIC_ESSID; | 8492 | if ((priv->config & CFG_STATIC_ESSID) && |
7928 | if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { | 8493 | !(priv->status & (STATUS_ASSOCIATED | |
8494 | STATUS_ASSOCIATING))) { | ||
7929 | IPW_DEBUG_ASSOC("Attempting to associate with new " | 8495 | IPW_DEBUG_ASSOC("Attempting to associate with new " |
7930 | "parameters.\n"); | 8496 | "parameters.\n"); |
8497 | priv->config &= ~CFG_STATIC_ESSID; | ||
7931 | ipw_associate(priv); | 8498 | ipw_associate(priv); |
7932 | } | 8499 | } |
7933 | up(&priv->sem); | 8500 | up(&priv->sem); |
@@ -8202,7 +8769,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, | |||
8202 | } | 8769 | } |
8203 | 8770 | ||
8204 | if ((wrqu->power.value > IPW_TX_POWER_MAX) || | 8771 | if ((wrqu->power.value > IPW_TX_POWER_MAX) || |
8205 | (wrqu->power.value < -IPW_TX_POWER_MAX) || !wrqu->power.fixed) { | 8772 | (wrqu->power.value < IPW_TX_POWER_MIN)) { |
8206 | up(&priv->sem); | 8773 | up(&priv->sem); |
8207 | return -EINVAL; | 8774 | return -EINVAL; |
8208 | } | 8775 | } |
@@ -8295,23 +8862,149 @@ static int ipw_wx_set_retry(struct net_device *dev, | |||
8295 | struct iw_request_info *info, | 8862 | struct iw_request_info *info, |
8296 | union iwreq_data *wrqu, char *extra) | 8863 | union iwreq_data *wrqu, char *extra) |
8297 | { | 8864 | { |
8298 | IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); | 8865 | struct ipw_priv *priv = ieee80211_priv(dev); |
8299 | return -EOPNOTSUPP; | 8866 | |
8867 | if (wrqu->retry.flags & IW_RETRY_LIFETIME || wrqu->retry.disabled) | ||
8868 | return -EINVAL; | ||
8869 | |||
8870 | if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) | ||
8871 | return 0; | ||
8872 | |||
8873 | if (wrqu->retry.value < 0 || wrqu->retry.value > 255) | ||
8874 | return -EINVAL; | ||
8875 | |||
8876 | down(&priv->sem); | ||
8877 | if (wrqu->retry.flags & IW_RETRY_MIN) | ||
8878 | priv->short_retry_limit = (u8) wrqu->retry.value; | ||
8879 | else if (wrqu->retry.flags & IW_RETRY_MAX) | ||
8880 | priv->long_retry_limit = (u8) wrqu->retry.value; | ||
8881 | else { | ||
8882 | priv->short_retry_limit = (u8) wrqu->retry.value; | ||
8883 | priv->long_retry_limit = (u8) wrqu->retry.value; | ||
8884 | } | ||
8885 | |||
8886 | ipw_send_retry_limit(priv, priv->short_retry_limit, | ||
8887 | priv->long_retry_limit); | ||
8888 | up(&priv->sem); | ||
8889 | IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n", | ||
8890 | priv->short_retry_limit, priv->long_retry_limit); | ||
8891 | return 0; | ||
8300 | } | 8892 | } |
8301 | 8893 | ||
8302 | static int ipw_wx_get_retry(struct net_device *dev, | 8894 | static int ipw_wx_get_retry(struct net_device *dev, |
8303 | struct iw_request_info *info, | 8895 | struct iw_request_info *info, |
8304 | union iwreq_data *wrqu, char *extra) | 8896 | union iwreq_data *wrqu, char *extra) |
8305 | { | 8897 | { |
8306 | IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); | 8898 | struct ipw_priv *priv = ieee80211_priv(dev); |
8307 | return -EOPNOTSUPP; | 8899 | |
8900 | down(&priv->sem); | ||
8901 | wrqu->retry.disabled = 0; | ||
8902 | |||
8903 | if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { | ||
8904 | up(&priv->sem); | ||
8905 | return -EINVAL; | ||
8906 | } | ||
8907 | |||
8908 | if (wrqu->retry.flags & IW_RETRY_MAX) { | ||
8909 | wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
8910 | wrqu->retry.value = priv->long_retry_limit; | ||
8911 | } else if (wrqu->retry.flags & IW_RETRY_MIN) { | ||
8912 | wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; | ||
8913 | wrqu->retry.value = priv->short_retry_limit; | ||
8914 | } else { | ||
8915 | wrqu->retry.flags = IW_RETRY_LIMIT; | ||
8916 | wrqu->retry.value = priv->short_retry_limit; | ||
8917 | } | ||
8918 | up(&priv->sem); | ||
8919 | |||
8920 | IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value); | ||
8921 | |||
8922 | return 0; | ||
8923 | } | ||
8924 | |||
8925 | #if WIRELESS_EXT > 17 | ||
8926 | static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, | ||
8927 | int essid_len) | ||
8928 | { | ||
8929 | struct ipw_scan_request_ext scan; | ||
8930 | int err = 0, scan_type; | ||
8931 | |||
8932 | down(&priv->sem); | ||
8933 | |||
8934 | if (priv->status & STATUS_RF_KILL_MASK) { | ||
8935 | IPW_DEBUG_HC("Aborting scan due to RF kill activation\n"); | ||
8936 | priv->status |= STATUS_SCAN_PENDING; | ||
8937 | goto done; | ||
8938 | } | ||
8939 | |||
8940 | IPW_DEBUG_HC("starting request direct scan!\n"); | ||
8941 | |||
8942 | if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { | ||
8943 | err = wait_event_interruptible(priv->wait_state, | ||
8944 | !(priv-> | ||
8945 | status & (STATUS_SCANNING | | ||
8946 | STATUS_SCAN_ABORTING))); | ||
8947 | if (err) { | ||
8948 | IPW_DEBUG_HC("aborting direct scan"); | ||
8949 | goto done; | ||
8950 | } | ||
8951 | } | ||
8952 | memset(&scan, 0, sizeof(scan)); | ||
8953 | |||
8954 | if (priv->config & CFG_SPEED_SCAN) | ||
8955 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = | ||
8956 | cpu_to_le16(30); | ||
8957 | else | ||
8958 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = | ||
8959 | cpu_to_le16(20); | ||
8960 | |||
8961 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = | ||
8962 | cpu_to_le16(20); | ||
8963 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(20); | ||
8964 | scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); | ||
8965 | |||
8966 | scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); | ||
8967 | |||
8968 | err = ipw_send_ssid(priv, essid, essid_len); | ||
8969 | if (err) { | ||
8970 | IPW_DEBUG_HC("Attempt to send SSID command failed\n"); | ||
8971 | goto done; | ||
8972 | } | ||
8973 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; | ||
8974 | |||
8975 | ipw_add_scan_channels(priv, &scan, scan_type); | ||
8976 | |||
8977 | err = ipw_send_scan_request_ext(priv, &scan); | ||
8978 | if (err) { | ||
8979 | IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); | ||
8980 | goto done; | ||
8981 | } | ||
8982 | |||
8983 | priv->status |= STATUS_SCANNING; | ||
8984 | |||
8985 | done: | ||
8986 | up(&priv->sem); | ||
8987 | return err; | ||
8308 | } | 8988 | } |
8989 | #endif /* WIRELESS_EXT > 17 */ | ||
8309 | 8990 | ||
8310 | static int ipw_wx_set_scan(struct net_device *dev, | 8991 | static int ipw_wx_set_scan(struct net_device *dev, |
8311 | struct iw_request_info *info, | 8992 | struct iw_request_info *info, |
8312 | union iwreq_data *wrqu, char *extra) | 8993 | union iwreq_data *wrqu, char *extra) |
8313 | { | 8994 | { |
8314 | struct ipw_priv *priv = ieee80211_priv(dev); | 8995 | struct ipw_priv *priv = ieee80211_priv(dev); |
8996 | #if WIRELESS_EXT > 17 | ||
8997 | struct iw_scan_req *req = NULL; | ||
8998 | if (wrqu->data.length | ||
8999 | && wrqu->data.length == sizeof(struct iw_scan_req)) { | ||
9000 | req = (struct iw_scan_req *)extra; | ||
9001 | if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { | ||
9002 | ipw_request_direct_scan(priv, req->essid, | ||
9003 | req->essid_len); | ||
9004 | return 0; | ||
9005 | } | ||
9006 | } | ||
9007 | #endif | ||
8315 | IPW_DEBUG_WX("Start scan\n"); | 9008 | IPW_DEBUG_WX("Start scan\n"); |
8316 | 9009 | ||
8317 | queue_work(priv->workqueue, &priv->request_scan); | 9010 | queue_work(priv->workqueue, &priv->request_scan); |
@@ -8332,7 +9025,13 @@ static int ipw_wx_set_encode(struct net_device *dev, | |||
8332 | union iwreq_data *wrqu, char *key) | 9025 | union iwreq_data *wrqu, char *key) |
8333 | { | 9026 | { |
8334 | struct ipw_priv *priv = ieee80211_priv(dev); | 9027 | struct ipw_priv *priv = ieee80211_priv(dev); |
8335 | return ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); | 9028 | int ret; |
9029 | |||
9030 | down(&priv->sem); | ||
9031 | ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); | ||
9032 | up(&priv->sem); | ||
9033 | |||
9034 | return ret; | ||
8336 | } | 9035 | } |
8337 | 9036 | ||
8338 | static int ipw_wx_get_encode(struct net_device *dev, | 9037 | static int ipw_wx_get_encode(struct net_device *dev, |
@@ -8665,110 +9364,6 @@ static int ipw_wx_reset(struct net_device *dev, | |||
8665 | return 0; | 9364 | return 0; |
8666 | } | 9365 | } |
8667 | 9366 | ||
8668 | static void ipw_sw_reset(struct ipw_priv *priv, int init) | ||
8669 | { | ||
8670 | int band, modulation; | ||
8671 | |||
8672 | /* Initialize module parameter values here */ | ||
8673 | priv->config = 0; | ||
8674 | |||
8675 | /* We default to disabling the LED code as right now it causes | ||
8676 | * too many systems to lock up... */ | ||
8677 | if (!led) | ||
8678 | priv->config |= CFG_NO_LED; | ||
8679 | |||
8680 | if (associate) | ||
8681 | priv->config |= CFG_ASSOCIATE; | ||
8682 | else | ||
8683 | IPW_DEBUG_INFO("Auto associate disabled.\n"); | ||
8684 | |||
8685 | if (auto_create) | ||
8686 | priv->config |= CFG_ADHOC_CREATE; | ||
8687 | else | ||
8688 | IPW_DEBUG_INFO("Auto adhoc creation disabled.\n"); | ||
8689 | |||
8690 | if (disable) { | ||
8691 | priv->status |= STATUS_RF_KILL_SW; | ||
8692 | IPW_DEBUG_INFO("Radio disabled.\n"); | ||
8693 | } | ||
8694 | |||
8695 | if (channel != 0) { | ||
8696 | priv->config |= CFG_STATIC_CHANNEL; | ||
8697 | priv->channel = channel; | ||
8698 | IPW_DEBUG_INFO("Bind to static channel %d\n", channel); | ||
8699 | /* TODO: Validate that provided channel is in range */ | ||
8700 | } | ||
8701 | #ifdef CONFIG_IPW_QOS | ||
8702 | ipw_qos_init(priv, qos_enable, qos_burst_enable, | ||
8703 | burst_duration_CCK, burst_duration_OFDM); | ||
8704 | #endif /* CONFIG_IPW_QOS */ | ||
8705 | |||
8706 | switch (mode) { | ||
8707 | case 1: | ||
8708 | priv->ieee->iw_mode = IW_MODE_ADHOC; | ||
8709 | priv->net_dev->type = ARPHRD_ETHER; | ||
8710 | |||
8711 | break; | ||
8712 | #ifdef CONFIG_IPW2200_MONITOR | ||
8713 | case 2: | ||
8714 | priv->ieee->iw_mode = IW_MODE_MONITOR; | ||
8715 | priv->net_dev->type = ARPHRD_IEEE80211; | ||
8716 | break; | ||
8717 | #endif | ||
8718 | default: | ||
8719 | case 0: | ||
8720 | priv->net_dev->type = ARPHRD_ETHER; | ||
8721 | priv->ieee->iw_mode = IW_MODE_INFRA; | ||
8722 | break; | ||
8723 | } | ||
8724 | |||
8725 | if (hwcrypto) { | ||
8726 | priv->ieee->host_encrypt = 0; | ||
8727 | priv->ieee->host_decrypt = 0; | ||
8728 | } | ||
8729 | IPW_DEBUG_INFO("Hardware crypto [%s]\n", hwcrypto ? "on" : "off"); | ||
8730 | |||
8731 | if ((priv->pci_dev->device == 0x4223) || | ||
8732 | (priv->pci_dev->device == 0x4224)) { | ||
8733 | if (init) | ||
8734 | printk(KERN_INFO DRV_NAME | ||
8735 | ": Detected Intel PRO/Wireless 2915ABG Network " | ||
8736 | "Connection\n"); | ||
8737 | priv->ieee->abg_true = 1; | ||
8738 | band = IEEE80211_52GHZ_BAND | IEEE80211_24GHZ_BAND; | ||
8739 | modulation = IEEE80211_OFDM_MODULATION | | ||
8740 | IEEE80211_CCK_MODULATION; | ||
8741 | priv->adapter = IPW_2915ABG; | ||
8742 | priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; | ||
8743 | } else { | ||
8744 | if (init) | ||
8745 | printk(KERN_INFO DRV_NAME | ||
8746 | ": Detected Intel PRO/Wireless 2200BG Network " | ||
8747 | "Connection\n"); | ||
8748 | |||
8749 | priv->ieee->abg_true = 0; | ||
8750 | band = IEEE80211_24GHZ_BAND; | ||
8751 | modulation = IEEE80211_OFDM_MODULATION | | ||
8752 | IEEE80211_CCK_MODULATION; | ||
8753 | priv->adapter = IPW_2200BG; | ||
8754 | priv->ieee->mode = IEEE_G | IEEE_B; | ||
8755 | } | ||
8756 | |||
8757 | priv->ieee->freq_band = band; | ||
8758 | priv->ieee->modulation = modulation; | ||
8759 | |||
8760 | priv->rates_mask = IEEE80211_DEFAULT_RATES_MASK; | ||
8761 | |||
8762 | priv->missed_beacon_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; | ||
8763 | priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; | ||
8764 | |||
8765 | priv->rts_threshold = DEFAULT_RTS_THRESHOLD; | ||
8766 | |||
8767 | /* If power management is turned on, default to AC mode */ | ||
8768 | priv->power_mode = IPW_POWER_AC; | ||
8769 | priv->tx_power = IPW_TX_POWER_DEFAULT; | ||
8770 | } | ||
8771 | |||
8772 | static int ipw_wx_sw_reset(struct net_device *dev, | 9367 | static int ipw_wx_sw_reset(struct net_device *dev, |
8773 | struct iw_request_info *info, | 9368 | struct iw_request_info *info, |
8774 | union iwreq_data *wrqu, char *extra) | 9369 | union iwreq_data *wrqu, char *extra) |
@@ -8779,12 +9374,17 @@ static int ipw_wx_sw_reset(struct net_device *dev, | |||
8779 | .flags = IW_ENCODE_DISABLED, | 9374 | .flags = IW_ENCODE_DISABLED, |
8780 | }, | 9375 | }, |
8781 | }; | 9376 | }; |
9377 | int ret; | ||
8782 | 9378 | ||
8783 | IPW_DEBUG_WX("SW_RESET\n"); | 9379 | IPW_DEBUG_WX("SW_RESET\n"); |
8784 | 9380 | ||
8785 | down(&priv->sem); | 9381 | down(&priv->sem); |
8786 | 9382 | ||
8787 | ipw_sw_reset(priv, 0); | 9383 | ret = ipw_sw_reset(priv, 0); |
9384 | if (!ret) { | ||
9385 | free_firmware(); | ||
9386 | ipw_adapter_restart(priv); | ||
9387 | } | ||
8788 | 9388 | ||
8789 | /* The SW reset bit might have been toggled on by the 'disable' | 9389 | /* The SW reset bit might have been toggled on by the 'disable' |
8790 | * module parameter, so take appropriate action */ | 9390 | * module parameter, so take appropriate action */ |
@@ -8842,6 +9442,15 @@ static iw_handler ipw_wx_handlers[] = { | |||
8842 | IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, | 9442 | IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, |
8843 | IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, | 9443 | IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, |
8844 | IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, | 9444 | IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, |
9445 | #if WIRELESS_EXT > 17 | ||
9446 | IW_IOCTL(SIOCSIWGENIE) = ipw_wx_set_genie, | ||
9447 | IW_IOCTL(SIOCGIWGENIE) = ipw_wx_get_genie, | ||
9448 | IW_IOCTL(SIOCSIWMLME) = ipw_wx_set_mlme, | ||
9449 | IW_IOCTL(SIOCSIWAUTH) = ipw_wx_set_auth, | ||
9450 | IW_IOCTL(SIOCGIWAUTH) = ipw_wx_get_auth, | ||
9451 | IW_IOCTL(SIOCSIWENCODEEXT) = ipw_wx_set_encodeext, | ||
9452 | IW_IOCTL(SIOCGIWENCODEEXT) = ipw_wx_get_encodeext, | ||
9453 | #endif | ||
8845 | }; | 9454 | }; |
8846 | 9455 | ||
8847 | enum { | 9456 | enum { |
@@ -8934,7 +9543,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) | |||
8934 | wstats = &priv->wstats; | 9543 | wstats = &priv->wstats; |
8935 | 9544 | ||
8936 | /* if hw is disabled, then ipw_get_ordinal() can't be called. | 9545 | /* if hw is disabled, then ipw_get_ordinal() can't be called. |
8937 | * ipw2100_wx_wireless_stats seems to be called before fw is | 9546 | * netdev->get_wireless_stats seems to be called before fw is |
8938 | * initialized. STATUS_ASSOCIATED will only be set if the hw is up | 9547 | * initialized. STATUS_ASSOCIATED will only be set if the hw is up |
8939 | * and associated; if not associcated, the values are all meaningless | 9548 | * and associated; if not associcated, the values are all meaningless |
8940 | * anyway, so set them all to NULL and INVALID */ | 9549 | * anyway, so set them all to NULL and INVALID */ |
@@ -9036,8 +9645,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, | |||
9036 | switch (priv->ieee->iw_mode) { | 9645 | switch (priv->ieee->iw_mode) { |
9037 | case IW_MODE_ADHOC: | 9646 | case IW_MODE_ADHOC: |
9038 | hdr_len = IEEE80211_3ADDR_LEN; | 9647 | hdr_len = IEEE80211_3ADDR_LEN; |
9039 | unicast = !is_broadcast_ether_addr(hdr->addr1) && | 9648 | unicast = !is_multicast_ether_addr(hdr->addr1); |
9040 | !is_multicast_ether_addr(hdr->addr1); | ||
9041 | id = ipw_find_station(priv, hdr->addr1); | 9649 | id = ipw_find_station(priv, hdr->addr1); |
9042 | if (id == IPW_INVALID_STATION) { | 9650 | if (id == IPW_INVALID_STATION) { |
9043 | id = ipw_add_station(priv, hdr->addr1); | 9651 | id = ipw_add_station(priv, hdr->addr1); |
@@ -9052,8 +9660,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, | |||
9052 | 9660 | ||
9053 | case IW_MODE_INFRA: | 9661 | case IW_MODE_INFRA: |
9054 | default: | 9662 | default: |
9055 | unicast = !is_broadcast_ether_addr(hdr->addr3) && | 9663 | unicast = !is_multicast_ether_addr(hdr->addr3); |
9056 | !is_multicast_ether_addr(hdr->addr3); | ||
9057 | hdr_len = IEEE80211_3ADDR_LEN; | 9664 | hdr_len = IEEE80211_3ADDR_LEN; |
9058 | id = 0; | 9665 | id = 0; |
9059 | break; | 9666 | break; |
@@ -9176,6 +9783,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, | |||
9176 | tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes); | 9783 | tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes); |
9177 | for (j = i; j < txb->nr_frags; j++) { | 9784 | for (j = i; j < txb->nr_frags; j++) { |
9178 | int size = txb->fragments[j]->len - hdr_len; | 9785 | int size = txb->fragments[j]->len - hdr_len; |
9786 | |||
9179 | printk(KERN_INFO "Adding frag %d %d...\n", | 9787 | printk(KERN_INFO "Adding frag %d %d...\n", |
9180 | j, size); | 9788 | j, size); |
9181 | memcpy(skb_put(skb, size), | 9789 | memcpy(skb_put(skb, size), |
@@ -9307,7 +9915,7 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, | |||
9307 | if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) | 9915 | if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) |
9308 | return -EINVAL; | 9916 | return -EINVAL; |
9309 | down(&p->sem); | 9917 | down(&p->sem); |
9310 | memcpy(bytes, &((u8 *) p->eeprom)[eeprom->offset], eeprom->len); | 9918 | memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len); |
9311 | up(&p->sem); | 9919 | up(&p->sem); |
9312 | return 0; | 9920 | return 0; |
9313 | } | 9921 | } |
@@ -9321,7 +9929,7 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, | |||
9321 | if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) | 9929 | if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) |
9322 | return -EINVAL; | 9930 | return -EINVAL; |
9323 | down(&p->sem); | 9931 | down(&p->sem); |
9324 | memcpy(&((u8 *) p->eeprom)[eeprom->offset], bytes, eeprom->len); | 9932 | memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); |
9325 | for (i = IPW_EEPROM_DATA; | 9933 | for (i = IPW_EEPROM_DATA; |
9326 | i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++) | 9934 | i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++) |
9327 | ipw_write8(p, i, p->eeprom[i]); | 9935 | ipw_write8(p, i, p->eeprom[i]); |
@@ -9427,6 +10035,10 @@ static void ipw_bg_rf_kill(void *data) | |||
9427 | 10035 | ||
9428 | void ipw_link_up(struct ipw_priv *priv) | 10036 | void ipw_link_up(struct ipw_priv *priv) |
9429 | { | 10037 | { |
10038 | priv->last_seq_num = -1; | ||
10039 | priv->last_frag_num = -1; | ||
10040 | priv->last_packet_time = 0; | ||
10041 | |||
9430 | netif_carrier_on(priv->net_dev); | 10042 | netif_carrier_on(priv->net_dev); |
9431 | if (netif_queue_stopped(priv->net_dev)) { | 10043 | if (netif_queue_stopped(priv->net_dev)) { |
9432 | IPW_DEBUG_NOTIF("waking queue\n"); | 10044 | IPW_DEBUG_NOTIF("waking queue\n"); |
@@ -9470,8 +10082,10 @@ void ipw_link_down(struct ipw_priv *priv) | |||
9470 | 10082 | ||
9471 | ipw_reset_stats(priv); | 10083 | ipw_reset_stats(priv); |
9472 | 10084 | ||
9473 | /* Queue up another scan... */ | 10085 | if (!(priv->status & STATUS_EXIT_PENDING)) { |
9474 | queue_work(priv->workqueue, &priv->request_scan); | 10086 | /* Queue up another scan... */ |
10087 | queue_work(priv->workqueue, &priv->request_scan); | ||
10088 | } | ||
9475 | } | 10089 | } |
9476 | 10090 | ||
9477 | static void ipw_bg_link_down(void *data) | 10091 | static void ipw_bg_link_down(void *data) |
@@ -9488,6 +10102,7 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) | |||
9488 | 10102 | ||
9489 | priv->workqueue = create_workqueue(DRV_NAME); | 10103 | priv->workqueue = create_workqueue(DRV_NAME); |
9490 | init_waitqueue_head(&priv->wait_command_queue); | 10104 | init_waitqueue_head(&priv->wait_command_queue); |
10105 | init_waitqueue_head(&priv->wait_state); | ||
9491 | 10106 | ||
9492 | INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); | 10107 | INIT_WORK(&priv->adhoc_check, ipw_bg_adhoc_check, priv); |
9493 | INIT_WORK(&priv->associate, ipw_bg_associate, priv); | 10108 | INIT_WORK(&priv->associate, ipw_bg_associate, priv); |
@@ -9531,9 +10146,9 @@ static void shim__set_security(struct net_device *dev, | |||
9531 | { | 10146 | { |
9532 | struct ipw_priv *priv = ieee80211_priv(dev); | 10147 | struct ipw_priv *priv = ieee80211_priv(dev); |
9533 | int i; | 10148 | int i; |
9534 | down(&priv->sem); | ||
9535 | for (i = 0; i < 4; i++) { | 10149 | for (i = 0; i < 4; i++) { |
9536 | if (sec->flags & (1 << i)) { | 10150 | if (sec->flags & (1 << i)) { |
10151 | priv->ieee->sec.encode_alg[i] = sec->encode_alg[i]; | ||
9537 | priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; | 10152 | priv->ieee->sec.key_sizes[i] = sec->key_sizes[i]; |
9538 | if (sec->key_sizes[i] == 0) | 10153 | if (sec->key_sizes[i] == 0) |
9539 | priv->ieee->sec.flags &= ~(1 << i); | 10154 | priv->ieee->sec.flags &= ~(1 << i); |
@@ -9577,7 +10192,9 @@ static void shim__set_security(struct net_device *dev, | |||
9577 | else | 10192 | else |
9578 | priv->capability &= ~CAP_PRIVACY_ON; | 10193 | priv->capability &= ~CAP_PRIVACY_ON; |
9579 | } | 10194 | } |
9580 | priv->ieee->sec.encrypt = sec->encrypt; | 10195 | |
10196 | if (sec->flags & SEC_ENCRYPT) | ||
10197 | priv->ieee->sec.encrypt = sec->encrypt; | ||
9581 | 10198 | ||
9582 | if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { | 10199 | if (sec->flags & SEC_LEVEL && priv->ieee->sec.level != sec->level) { |
9583 | priv->ieee->sec.level = sec->level; | 10200 | priv->ieee->sec.level = sec->level; |
@@ -9602,7 +10219,6 @@ static void shim__set_security(struct net_device *dev, | |||
9602 | ipw_disassociate(priv); | 10219 | ipw_disassociate(priv); |
9603 | } | 10220 | } |
9604 | #endif | 10221 | #endif |
9605 | up(&priv->sem); | ||
9606 | } | 10222 | } |
9607 | 10223 | ||
9608 | static int init_supported_rates(struct ipw_priv *priv, | 10224 | static int init_supported_rates(struct ipw_priv *priv, |
@@ -9707,6 +10323,24 @@ static int ipw_config(struct ipw_priv *priv) | |||
9707 | return -EIO; | 10323 | return -EIO; |
9708 | } | 10324 | } |
9709 | 10325 | ||
10326 | static const struct ieee80211_geo ipw_geo = { | ||
10327 | "---", | ||
10328 | .bg_channels = 11, | ||
10329 | .bg = {{2412, 1}, {2417, 2}, {2422, 3}, | ||
10330 | {2427, 4}, {2432, 5}, {2437, 6}, | ||
10331 | {2442, 7}, {2447, 8}, {2452, 9}, | ||
10332 | {2457, 10}, {2462, 11}}, | ||
10333 | .a_channels = 8, | ||
10334 | .a = {{5180, 36}, | ||
10335 | {5200, 40}, | ||
10336 | {5220, 44}, | ||
10337 | {5240, 48}, | ||
10338 | {5260, 52, IEEE80211_CH_PASSIVE_ONLY}, | ||
10339 | {5280, 56, IEEE80211_CH_PASSIVE_ONLY}, | ||
10340 | {5300, 60, IEEE80211_CH_PASSIVE_ONLY}, | ||
10341 | {5320, 64, IEEE80211_CH_PASSIVE_ONLY}}, | ||
10342 | }; | ||
10343 | |||
9710 | #define MAX_HW_RESTARTS 5 | 10344 | #define MAX_HW_RESTARTS 5 |
9711 | static int ipw_up(struct ipw_priv *priv) | 10345 | static int ipw_up(struct ipw_priv *priv) |
9712 | { | 10346 | { |
@@ -9729,6 +10363,10 @@ static int ipw_up(struct ipw_priv *priv) | |||
9729 | eeprom_parse_mac(priv, priv->mac_addr); | 10363 | eeprom_parse_mac(priv, priv->mac_addr); |
9730 | memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); | 10364 | memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN); |
9731 | 10365 | ||
10366 | memcpy(priv->country, &priv->eeprom[EEPROM_COUNTRY_CODE], 3); | ||
10367 | priv->country[3] = '\0'; | ||
10368 | ieee80211_set_geo(priv->ieee, &ipw_geo); | ||
10369 | |||
9732 | if (priv->status & STATUS_RF_KILL_SW) { | 10370 | if (priv->status & STATUS_RF_KILL_SW) { |
9733 | IPW_WARNING("Radio disabled by module parameter.\n"); | 10371 | IPW_WARNING("Radio disabled by module parameter.\n"); |
9734 | return 0; | 10372 | return 0; |
@@ -9748,6 +10386,14 @@ static int ipw_up(struct ipw_priv *priv) | |||
9748 | ipw_led_radio_on(priv); | 10386 | ipw_led_radio_on(priv); |
9749 | priv->notif_missed_beacons = 0; | 10387 | priv->notif_missed_beacons = 0; |
9750 | priv->status |= STATUS_INIT; | 10388 | priv->status |= STATUS_INIT; |
10389 | |||
10390 | /* Set hardware WEP key if it is configured. */ | ||
10391 | if ((priv->capability & CAP_PRIVACY_ON) && | ||
10392 | (priv->ieee->sec.level == SEC_LEVEL_1) && | ||
10393 | !(priv->ieee->host_encrypt || | ||
10394 | priv->ieee->host_decrypt)) | ||
10395 | ipw_set_hwcrypto_keys(priv); | ||
10396 | |||
9751 | return 0; | 10397 | return 0; |
9752 | } | 10398 | } |
9753 | 10399 | ||
@@ -9846,6 +10492,7 @@ static void ipw_bg_down(void *data) | |||
9846 | up(&priv->sem); | 10492 | up(&priv->sem); |
9847 | } | 10493 | } |
9848 | 10494 | ||
10495 | #if WIRELESS_EXT < 18 | ||
9849 | static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 10496 | static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
9850 | { | 10497 | { |
9851 | struct iwreq *wrq = (struct iwreq *)rq; | 10498 | struct iwreq *wrq = (struct iwreq *)rq; |
@@ -9861,6 +10508,7 @@ static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
9861 | 10508 | ||
9862 | return -EOPNOTSUPP; | 10509 | return -EOPNOTSUPP; |
9863 | } | 10510 | } |
10511 | #endif | ||
9864 | 10512 | ||
9865 | /* Called by register_netdev() */ | 10513 | /* Called by register_netdev() */ |
9866 | static int ipw_net_init(struct net_device *dev) | 10514 | static int ipw_net_init(struct net_device *dev) |
@@ -9942,6 +10590,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
9942 | void __iomem *base; | 10590 | void __iomem *base; |
9943 | u32 length, val; | 10591 | u32 length, val; |
9944 | struct ipw_priv *priv; | 10592 | struct ipw_priv *priv; |
10593 | int i; | ||
9945 | 10594 | ||
9946 | net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); | 10595 | net_dev = alloc_ieee80211(sizeof(struct ipw_priv)); |
9947 | if (net_dev == NULL) { | 10596 | if (net_dev == NULL) { |
@@ -9958,6 +10607,8 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
9958 | ipw_debug_level = debug; | 10607 | ipw_debug_level = debug; |
9959 | #endif | 10608 | #endif |
9960 | spin_lock_init(&priv->lock); | 10609 | spin_lock_init(&priv->lock); |
10610 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) | ||
10611 | INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); | ||
9961 | 10612 | ||
9962 | init_MUTEX(&priv->sem); | 10613 | init_MUTEX(&priv->sem); |
9963 | if (pci_enable_device(pdev)) { | 10614 | if (pci_enable_device(pdev)) { |
@@ -10035,7 +10686,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
10035 | net_dev->open = ipw_net_open; | 10686 | net_dev->open = ipw_net_open; |
10036 | net_dev->stop = ipw_net_stop; | 10687 | net_dev->stop = ipw_net_stop; |
10037 | net_dev->init = ipw_net_init; | 10688 | net_dev->init = ipw_net_init; |
10689 | #if WIRELESS_EXT < 18 | ||
10038 | net_dev->do_ioctl = ipw_ioctl; | 10690 | net_dev->do_ioctl = ipw_ioctl; |
10691 | #endif | ||
10039 | net_dev->get_stats = ipw_net_get_stats; | 10692 | net_dev->get_stats = ipw_net_get_stats; |
10040 | net_dev->set_multicast_list = ipw_net_set_multicast_list; | 10693 | net_dev->set_multicast_list = ipw_net_set_multicast_list; |
10041 | net_dev->set_mac_address = ipw_net_set_mac_address; | 10694 | net_dev->set_mac_address = ipw_net_set_mac_address; |
@@ -10086,13 +10739,18 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
10086 | static void ipw_pci_remove(struct pci_dev *pdev) | 10739 | static void ipw_pci_remove(struct pci_dev *pdev) |
10087 | { | 10740 | { |
10088 | struct ipw_priv *priv = pci_get_drvdata(pdev); | 10741 | struct ipw_priv *priv = pci_get_drvdata(pdev); |
10742 | struct list_head *p, *q; | ||
10743 | int i; | ||
10089 | 10744 | ||
10090 | if (!priv) | 10745 | if (!priv) |
10091 | return; | 10746 | return; |
10092 | 10747 | ||
10093 | down(&priv->sem); | 10748 | down(&priv->sem); |
10749 | |||
10750 | priv->status |= STATUS_EXIT_PENDING; | ||
10094 | ipw_down(priv); | 10751 | ipw_down(priv); |
10095 | sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); | 10752 | sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); |
10753 | |||
10096 | up(&priv->sem); | 10754 | up(&priv->sem); |
10097 | 10755 | ||
10098 | unregister_netdev(priv->net_dev); | 10756 | unregister_netdev(priv->net_dev); |
@@ -10113,21 +10771,21 @@ static void ipw_pci_remove(struct pci_dev *pdev) | |||
10113 | destroy_workqueue(priv->workqueue); | 10771 | destroy_workqueue(priv->workqueue); |
10114 | priv->workqueue = NULL; | 10772 | priv->workqueue = NULL; |
10115 | 10773 | ||
10774 | /* Free MAC hash list for ADHOC */ | ||
10775 | for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) { | ||
10776 | list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) { | ||
10777 | kfree(list_entry(p, struct ipw_ibss_seq, list)); | ||
10778 | list_del(p); | ||
10779 | } | ||
10780 | } | ||
10781 | |||
10116 | free_irq(pdev->irq, priv); | 10782 | free_irq(pdev->irq, priv); |
10117 | iounmap(priv->hw_base); | 10783 | iounmap(priv->hw_base); |
10118 | pci_release_regions(pdev); | 10784 | pci_release_regions(pdev); |
10119 | pci_disable_device(pdev); | 10785 | pci_disable_device(pdev); |
10120 | pci_set_drvdata(pdev, NULL); | 10786 | pci_set_drvdata(pdev, NULL); |
10121 | free_ieee80211(priv->net_dev); | 10787 | free_ieee80211(priv->net_dev); |
10122 | 10788 | free_firmware(); | |
10123 | #ifdef CONFIG_PM | ||
10124 | if (fw_loaded) { | ||
10125 | release_firmware(bootfw); | ||
10126 | release_firmware(ucode); | ||
10127 | release_firmware(firmware); | ||
10128 | fw_loaded = 0; | ||
10129 | } | ||
10130 | #endif | ||
10131 | } | 10789 | } |
10132 | 10790 | ||
10133 | #ifdef CONFIG_PM | 10791 | #ifdef CONFIG_PM |