diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2005-08-24 22:25:16 -0400 |
---|---|---|
committer | James Ketrenos <jketreno@linux.intel.com> | 2005-11-07 18:49:50 -0500 |
commit | ea2b26e0a0264650e13acac8e66d315bb818897c (patch) | |
tree | a2045d043ca6e09722d23518170900c1cc4dcc6d /drivers/net/wireless/ipw2200.c | |
parent | a1e695adca76f5729224242e4f2f9f6ceb6863d1 (diff) |
Catch ipw2200 up to equivelancy with v1.0.1
This commit contains the following fixes:
Fixed #559: iwconfig rate support (thanks to Florian Hackenberger)
Improved link signal quality calculation (thanks to Bill Moss)
Fixed a problem with sensitivity threshold during association
Added iwpriv for turning forcing long preamble support:
% iwpriv eth1 set_preamble 1|0
Fixed #542 and #377 support for short preamble
Fixed locked BSSID reporting channel number (thanks to Pedro
Ramalhais)
Fixed type-o with scan watchdog timeout message (thanks to Pedro
Ramalhais)
Changed logic for displaying get_mode output so the code is easier to
follow (thanks to Pedro Ramalhais)
Added initial support for WPA (thanks to Yi Zhu) -- tested with
wpa_supplicant (either tip w/ ipw driver, or with -Dipw2100) with
both CCMP and TKIP
Fixed problem with CCMP not working due to uninitialized 802.11
header fields (thanks to Pedro Ramalhais)
Bug references are to defects stored on http://bughost.org
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 | 1496 |
1 files changed, 1133 insertions, 363 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 3db0c32afe82..ddbee3edcd8c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #include "ipw2200.h" | 33 | #include "ipw2200.h" |
34 | 34 | ||
35 | #define IPW2200_VERSION "1.0.0" | 35 | #define IPW2200_VERSION "1.0.1" |
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 |
@@ -44,7 +44,6 @@ MODULE_LICENSE("GPL"); | |||
44 | 44 | ||
45 | static int debug = 0; | 45 | static int debug = 0; |
46 | static int channel = 0; | 46 | static int channel = 0; |
47 | static char *ifname; | ||
48 | static int mode = 0; | 47 | static int mode = 0; |
49 | 48 | ||
50 | static u32 ipw_debug_level; | 49 | static u32 ipw_debug_level; |
@@ -289,32 +288,33 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, | |||
289 | { | 288 | { |
290 | u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; | 289 | u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; |
291 | u32 dif_len = addr - aligned_addr; | 290 | u32 dif_len = addr - aligned_addr; |
292 | u32 aligned_len; | ||
293 | u32 i; | 291 | u32 i; |
294 | 292 | ||
295 | IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); | 293 | IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); |
296 | 294 | ||
295 | if (num <= 0) { | ||
296 | return; | ||
297 | } | ||
298 | |||
297 | /* Read the first nibble byte by byte */ | 299 | /* Read the first nibble byte by byte */ |
298 | if (unlikely(dif_len)) { | 300 | if (unlikely(dif_len)) { |
299 | /* Start reading at aligned_addr + dif_len */ | ||
300 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | 301 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); |
301 | for (i = dif_len; i < 4; i++, buf++) | 302 | /* Start reading at aligned_addr + dif_len */ |
302 | *buf = _ipw_read8(priv, CX2_INDIRECT_DATA + i); | 303 | for (i = dif_len; ((i < 4) && (num > 0)); i++, num--) |
303 | num -= dif_len; | 304 | *buf++ = _ipw_read8(priv, CX2_INDIRECT_DATA + i); |
304 | aligned_addr += 4; | 305 | aligned_addr += 4; |
305 | } | 306 | } |
306 | 307 | ||
307 | /* Read DWs through autoinc register */ | ||
308 | _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); | 308 | _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); |
309 | aligned_len = num & CX2_INDIRECT_ADDR_MASK; | 309 | for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) |
310 | for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) | 310 | *(u32 *) buf = _ipw_read32(priv, CX2_AUTOINC_DATA); |
311 | *(u32 *) buf = ipw_read32(priv, CX2_AUTOINC_DATA); | ||
312 | 311 | ||
313 | /* Copy the last nibble */ | 312 | /* Copy the last nibble */ |
314 | dif_len = num - aligned_len; | 313 | if (unlikely(num)) { |
315 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | 314 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); |
316 | for (i = 0; i < dif_len; i++, buf++) | 315 | for (i = 0; num > 0; i++, num--) |
317 | *buf = ipw_read8(priv, CX2_INDIRECT_DATA + i); | 316 | *buf++ = ipw_read8(priv, CX2_INDIRECT_DATA + i); |
317 | } | ||
318 | } | 318 | } |
319 | 319 | ||
320 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, | 320 | static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, |
@@ -322,32 +322,33 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, | |||
322 | { | 322 | { |
323 | u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; | 323 | u32 aligned_addr = addr & CX2_INDIRECT_ADDR_MASK; |
324 | u32 dif_len = addr - aligned_addr; | 324 | u32 dif_len = addr - aligned_addr; |
325 | u32 aligned_len; | ||
326 | u32 i; | 325 | u32 i; |
327 | 326 | ||
328 | IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); | 327 | IPW_DEBUG_IO("addr = %i, buf = %p, num = %i\n", addr, buf, num); |
329 | 328 | ||
329 | if (num <= 0) { | ||
330 | return; | ||
331 | } | ||
332 | |||
330 | /* Write the first nibble byte by byte */ | 333 | /* Write the first nibble byte by byte */ |
331 | if (unlikely(dif_len)) { | 334 | if (unlikely(dif_len)) { |
332 | /* Start writing at aligned_addr + dif_len */ | ||
333 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | 335 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); |
334 | for (i = dif_len; i < 4; i++, buf++) | 336 | /* Start reading at aligned_addr + dif_len */ |
337 | for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) | ||
335 | _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); | 338 | _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); |
336 | num -= dif_len; | ||
337 | aligned_addr += 4; | 339 | aligned_addr += 4; |
338 | } | 340 | } |
339 | 341 | ||
340 | /* Write DWs through autoinc register */ | ||
341 | _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); | 342 | _ipw_write32(priv, CX2_AUTOINC_ADDR, aligned_addr); |
342 | aligned_len = num & CX2_INDIRECT_ADDR_MASK; | 343 | for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) |
343 | for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) | ||
344 | _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf); | 344 | _ipw_write32(priv, CX2_AUTOINC_DATA, *(u32 *) buf); |
345 | 345 | ||
346 | /* Copy the last nibble */ | 346 | /* Copy the last nibble */ |
347 | dif_len = num - aligned_len; | 347 | if (unlikely(num)) { |
348 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); | 348 | _ipw_write32(priv, CX2_INDIRECT_ADDR, aligned_addr); |
349 | for (i = 0; i < dif_len; i++, buf++) | 349 | for (i = 0; num > 0; i++, num--, buf++) |
350 | _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); | 350 | _ipw_write8(priv, CX2_INDIRECT_DATA + i, *buf); |
351 | } | ||
351 | } | 352 | } |
352 | 353 | ||
353 | static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, | 354 | static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, |
@@ -945,7 +946,7 @@ static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, | |||
945 | static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) | 946 | static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) |
946 | { | 947 | { |
947 | if ((disable_radio ? 1 : 0) == | 948 | if ((disable_radio ? 1 : 0) == |
948 | (priv->status & STATUS_RF_KILL_SW ? 1 : 0)) | 949 | ((priv->status & STATUS_RF_KILL_SW) ? 1 : 0)) |
949 | return 0; | 950 | return 0; |
950 | 951 | ||
951 | IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", | 952 | IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", |
@@ -987,6 +988,17 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, | |||
987 | 988 | ||
988 | static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); | 989 | static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); |
989 | 990 | ||
991 | static void notify_wx_assoc_event(struct ipw_priv *priv) | ||
992 | { | ||
993 | union iwreq_data wrqu; | ||
994 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
995 | if (priv->status & STATUS_ASSOCIATED) | ||
996 | memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); | ||
997 | else | ||
998 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
999 | wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); | ||
1000 | } | ||
1001 | |||
990 | static void ipw_irq_tasklet(struct ipw_priv *priv) | 1002 | static void ipw_irq_tasklet(struct ipw_priv *priv) |
991 | { | 1003 | { |
992 | u32 inta, inta_mask, handled = 0; | 1004 | u32 inta, inta_mask, handled = 0; |
@@ -1071,6 +1083,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1071 | wake_up_interruptible(&priv->wait_command_queue); | 1083 | wake_up_interruptible(&priv->wait_command_queue); |
1072 | netif_carrier_off(priv->net_dev); | 1084 | netif_carrier_off(priv->net_dev); |
1073 | netif_stop_queue(priv->net_dev); | 1085 | netif_stop_queue(priv->net_dev); |
1086 | priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); | ||
1087 | notify_wx_assoc_event(priv); | ||
1074 | cancel_delayed_work(&priv->request_scan); | 1088 | cancel_delayed_work(&priv->request_scan); |
1075 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); | 1089 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); |
1076 | handled |= CX2_INTA_BIT_RF_KILL_DONE; | 1090 | handled |= CX2_INTA_BIT_RF_KILL_DONE; |
@@ -1162,7 +1176,7 @@ static char *get_cmd_string(u8 cmd) | |||
1162 | return "UNKNOWN"; | 1176 | return "UNKNOWN"; |
1163 | } | 1177 | } |
1164 | } | 1178 | } |
1165 | #endif /* CONFIG_IPW_DEBUG */ | 1179 | #endif |
1166 | 1180 | ||
1167 | #define HOST_COMPLETE_TIMEOUT HZ | 1181 | #define HOST_COMPLETE_TIMEOUT HZ |
1168 | static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) | 1182 | static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) |
@@ -2445,10 +2459,10 @@ static int ipw_load(struct ipw_priv *priv) | |||
2445 | rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss")); | 2459 | rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss")); |
2446 | break; | 2460 | break; |
2447 | 2461 | ||
2448 | #ifdef CONFIG_IPW_PROMISC | 2462 | #ifdef CONFIG_IPW_MONITOR |
2449 | case IW_MODE_MONITOR: | 2463 | case IW_MODE_MONITOR: |
2450 | rc = ipw_get_fw(priv, &ucode, | 2464 | rc = ipw_get_fw(priv, &ucode, |
2451 | IPW_FW_NAME("ibss_ucode")); | 2465 | IPW_FW_NAME("sniffer_ucode")); |
2452 | if (rc) | 2466 | if (rc) |
2453 | goto error; | 2467 | goto error; |
2454 | 2468 | ||
@@ -2929,17 +2943,6 @@ static void ipw_disassociate(void *data) | |||
2929 | ipw_send_disassociate(data, 0); | 2943 | ipw_send_disassociate(data, 0); |
2930 | } | 2944 | } |
2931 | 2945 | ||
2932 | static void notify_wx_assoc_event(struct ipw_priv *priv) | ||
2933 | { | ||
2934 | union iwreq_data wrqu; | ||
2935 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
2936 | if (priv->status & STATUS_ASSOCIATED) | ||
2937 | memcpy(wrqu.ap_addr.sa_data, priv->bssid, ETH_ALEN); | ||
2938 | else | ||
2939 | memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); | ||
2940 | wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); | ||
2941 | } | ||
2942 | |||
2943 | struct ipw_status_code { | 2946 | struct ipw_status_code { |
2944 | u16 status; | 2947 | u16 status; |
2945 | const char *reason; | 2948 | const char *reason; |
@@ -2997,7 +3000,7 @@ static const char *ipw_get_status_code(u16 status) | |||
2997 | { | 3000 | { |
2998 | int i; | 3001 | int i; |
2999 | for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++) | 3002 | for (i = 0; i < ARRAY_SIZE(ipw_status_codes); i++) |
3000 | if (ipw_status_codes[i].status == status) | 3003 | if (ipw_status_codes[i].status == (status & 0xff)) |
3001 | return ipw_status_codes[i].reason; | 3004 | return ipw_status_codes[i].reason; |
3002 | return "Unknown status value."; | 3005 | return "Unknown status value."; |
3003 | } | 3006 | } |
@@ -3076,18 +3079,30 @@ static inline u32 ipw_get_max_rate(struct ipw_priv *priv) | |||
3076 | while (i && !(mask & i)) | 3079 | while (i && !(mask & i)) |
3077 | i >>= 1; | 3080 | i >>= 1; |
3078 | switch (i) { | 3081 | switch (i) { |
3079 | case IEEE80211_CCK_RATE_1MB_MASK: return 1000000; | 3082 | case IEEE80211_CCK_RATE_1MB_MASK: |
3080 | case IEEE80211_CCK_RATE_2MB_MASK: return 2000000; | 3083 | return 1000000; |
3081 | case IEEE80211_CCK_RATE_5MB_MASK: return 5500000; | 3084 | case IEEE80211_CCK_RATE_2MB_MASK: |
3082 | case IEEE80211_OFDM_RATE_6MB_MASK: return 6000000; | 3085 | return 2000000; |
3083 | case IEEE80211_OFDM_RATE_9MB_MASK: return 9000000; | 3086 | case IEEE80211_CCK_RATE_5MB_MASK: |
3084 | case IEEE80211_CCK_RATE_11MB_MASK: return 11000000; | 3087 | return 5500000; |
3085 | case IEEE80211_OFDM_RATE_12MB_MASK: return 12000000; | 3088 | case IEEE80211_OFDM_RATE_6MB_MASK: |
3086 | case IEEE80211_OFDM_RATE_18MB_MASK: return 18000000; | 3089 | return 6000000; |
3087 | case IEEE80211_OFDM_RATE_24MB_MASK: return 24000000; | 3090 | case IEEE80211_OFDM_RATE_9MB_MASK: |
3088 | case IEEE80211_OFDM_RATE_36MB_MASK: return 36000000; | 3091 | return 9000000; |
3089 | case IEEE80211_OFDM_RATE_48MB_MASK: return 48000000; | 3092 | case IEEE80211_CCK_RATE_11MB_MASK: |
3090 | case IEEE80211_OFDM_RATE_54MB_MASK: return 54000000; | 3093 | return 11000000; |
3094 | case IEEE80211_OFDM_RATE_12MB_MASK: | ||
3095 | return 12000000; | ||
3096 | case IEEE80211_OFDM_RATE_18MB_MASK: | ||
3097 | return 18000000; | ||
3098 | case IEEE80211_OFDM_RATE_24MB_MASK: | ||
3099 | return 24000000; | ||
3100 | case IEEE80211_OFDM_RATE_36MB_MASK: | ||
3101 | return 36000000; | ||
3102 | case IEEE80211_OFDM_RATE_48MB_MASK: | ||
3103 | return 48000000; | ||
3104 | case IEEE80211_OFDM_RATE_54MB_MASK: | ||
3105 | return 54000000; | ||
3091 | } | 3106 | } |
3092 | 3107 | ||
3093 | if (priv->ieee->mode == IEEE_B) | 3108 | if (priv->ieee->mode == IEEE_B) |
@@ -3115,24 +3130,36 @@ static u32 ipw_get_current_rate(struct ipw_priv *priv) | |||
3115 | return ipw_get_max_rate(priv); | 3130 | return ipw_get_max_rate(priv); |
3116 | 3131 | ||
3117 | switch (rate) { | 3132 | switch (rate) { |
3118 | case IPW_TX_RATE_1MB: return 1000000; | 3133 | case IPW_TX_RATE_1MB: |
3119 | case IPW_TX_RATE_2MB: return 2000000; | 3134 | return 1000000; |
3120 | case IPW_TX_RATE_5MB: return 5500000; | 3135 | case IPW_TX_RATE_2MB: |
3121 | case IPW_TX_RATE_6MB: return 6000000; | 3136 | return 2000000; |
3122 | case IPW_TX_RATE_9MB: return 9000000; | 3137 | case IPW_TX_RATE_5MB: |
3123 | case IPW_TX_RATE_11MB: return 11000000; | 3138 | return 5500000; |
3124 | case IPW_TX_RATE_12MB: return 12000000; | 3139 | case IPW_TX_RATE_6MB: |
3125 | case IPW_TX_RATE_18MB: return 18000000; | 3140 | return 6000000; |
3126 | case IPW_TX_RATE_24MB: return 24000000; | 3141 | case IPW_TX_RATE_9MB: |
3127 | case IPW_TX_RATE_36MB: return 36000000; | 3142 | return 9000000; |
3128 | case IPW_TX_RATE_48MB: return 48000000; | 3143 | case IPW_TX_RATE_11MB: |
3129 | case IPW_TX_RATE_54MB: return 54000000; | 3144 | return 11000000; |
3145 | case IPW_TX_RATE_12MB: | ||
3146 | return 12000000; | ||
3147 | case IPW_TX_RATE_18MB: | ||
3148 | return 18000000; | ||
3149 | case IPW_TX_RATE_24MB: | ||
3150 | return 24000000; | ||
3151 | case IPW_TX_RATE_36MB: | ||
3152 | return 36000000; | ||
3153 | case IPW_TX_RATE_48MB: | ||
3154 | return 48000000; | ||
3155 | case IPW_TX_RATE_54MB: | ||
3156 | return 54000000; | ||
3130 | } | 3157 | } |
3131 | 3158 | ||
3132 | return 0; | 3159 | return 0; |
3133 | } | 3160 | } |
3134 | 3161 | ||
3135 | #define PERFECT_RSSI (-50) | 3162 | #define PERFECT_RSSI (-20) |
3136 | #define WORST_RSSI (-85) | 3163 | #define WORST_RSSI (-85) |
3137 | #define IPW_STATS_INTERVAL (2 * HZ) | 3164 | #define IPW_STATS_INTERVAL (2 * HZ) |
3138 | static void ipw_gather_stats(struct ipw_priv *priv) | 3165 | static void ipw_gather_stats(struct ipw_priv *priv) |
@@ -3145,6 +3172,7 @@ static void ipw_gather_stats(struct ipw_priv *priv) | |||
3145 | s16 rssi; | 3172 | s16 rssi; |
3146 | u32 beacon_quality, signal_quality, tx_quality, rx_quality, | 3173 | u32 beacon_quality, signal_quality, tx_quality, rx_quality, |
3147 | rate_quality; | 3174 | rate_quality; |
3175 | u32 max_rate; | ||
3148 | 3176 | ||
3149 | if (!(priv->status & STATUS_ASSOCIATED)) { | 3177 | if (!(priv->status & STATUS_ASSOCIATED)) { |
3150 | priv->quality = 0; | 3178 | priv->quality = 0; |
@@ -3201,7 +3229,8 @@ static void ipw_gather_stats(struct ipw_priv *priv) | |||
3201 | beacon_quality, missed_beacons_percent); | 3229 | beacon_quality, missed_beacons_percent); |
3202 | 3230 | ||
3203 | priv->last_rate = ipw_get_current_rate(priv); | 3231 | priv->last_rate = ipw_get_current_rate(priv); |
3204 | rate_quality = priv->last_rate * 40 / priv->last_rate + 60; | 3232 | max_rate = ipw_get_max_rate(priv); |
3233 | rate_quality = priv->last_rate * 40 / max_rate + 60; | ||
3205 | IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n", | 3234 | IPW_DEBUG_STATS("Rate quality : %3d%% (%dMbs)\n", |
3206 | rate_quality, priv->last_rate / 1000000); | 3235 | rate_quality, priv->last_rate / 1000000); |
3207 | 3236 | ||
@@ -3226,9 +3255,16 @@ static void ipw_gather_stats(struct ipw_priv *priv) | |||
3226 | signal_quality = 100; | 3255 | signal_quality = 100; |
3227 | else if (rssi < WORST_RSSI) | 3256 | else if (rssi < WORST_RSSI) |
3228 | signal_quality = 0; | 3257 | signal_quality = 0; |
3229 | else | 3258 | else /* qual = 100a^2 - 15ab + 62b^2 / a^2 */ |
3230 | signal_quality = (rssi - WORST_RSSI) * 100 / | 3259 | signal_quality = |
3231 | (PERFECT_RSSI - WORST_RSSI); | 3260 | (100 * |
3261 | (PERFECT_RSSI - WORST_RSSI) * | ||
3262 | (PERFECT_RSSI - WORST_RSSI) - | ||
3263 | (PERFECT_RSSI - rssi) * | ||
3264 | (15 * (PERFECT_RSSI - WORST_RSSI) + | ||
3265 | 62 * (PERFECT_RSSI - rssi))) / | ||
3266 | ((PERFECT_RSSI - WORST_RSSI) * (PERFECT_RSSI - WORST_RSSI)); | ||
3267 | |||
3232 | IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", | 3268 | IPW_DEBUG_STATS("Signal level : %3d%% (%d dBm)\n", |
3233 | signal_quality, rssi); | 3269 | signal_quality, rssi); |
3234 | 3270 | ||
@@ -3257,6 +3293,62 @@ static void ipw_gather_stats(struct ipw_priv *priv) | |||
3257 | IPW_STATS_INTERVAL); | 3293 | IPW_STATS_INTERVAL); |
3258 | } | 3294 | } |
3259 | 3295 | ||
3296 | static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, | ||
3297 | int missed_count) | ||
3298 | { | ||
3299 | priv->notif_missed_beacons = missed_count; | ||
3300 | |||
3301 | if (missed_count > priv->missed_beacon_threshold && | ||
3302 | priv->status & STATUS_ASSOCIATED) { | ||
3303 | /* If associated and we've hit the missed | ||
3304 | * beacon threshold, disassociate, turn | ||
3305 | * off roaming, and abort any active scans */ | ||
3306 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | | ||
3307 | IPW_DL_STATE, | ||
3308 | "Missed beacon: %d - disassociate\n", missed_count); | ||
3309 | priv->status &= ~STATUS_ROAMING; | ||
3310 | if (priv->status & STATUS_SCANNING) | ||
3311 | queue_work(priv->workqueue, &priv->abort_scan); | ||
3312 | queue_work(priv->workqueue, &priv->disassociate); | ||
3313 | return; | ||
3314 | } | ||
3315 | |||
3316 | if (priv->status & STATUS_ROAMING) { | ||
3317 | /* If we are currently roaming, then just | ||
3318 | * print a debug statement... */ | ||
3319 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, | ||
3320 | "Missed beacon: %d - roam in progress\n", | ||
3321 | missed_count); | ||
3322 | return; | ||
3323 | } | ||
3324 | |||
3325 | if (missed_count > priv->roaming_threshold) { | ||
3326 | /* If we are not already roaming, set the ROAM | ||
3327 | * bit in the status and kick off a scan */ | ||
3328 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, | ||
3329 | "Missed beacon: %d - initiate " | ||
3330 | "roaming\n", missed_count); | ||
3331 | if (!(priv->status & STATUS_ROAMING)) { | ||
3332 | priv->status |= STATUS_ROAMING; | ||
3333 | if (!(priv->status & STATUS_SCANNING)) | ||
3334 | queue_work(priv->workqueue, | ||
3335 | &priv->request_scan); | ||
3336 | } | ||
3337 | return; | ||
3338 | } | ||
3339 | |||
3340 | if (priv->status & STATUS_SCANNING) { | ||
3341 | /* Stop scan to keep fw from getting | ||
3342 | * stuck (only if we aren't roaming -- | ||
3343 | * otherwise we'll never scan more than 2 or 3 | ||
3344 | * channels..) */ | ||
3345 | queue_work(priv->workqueue, &priv->abort_scan); | ||
3346 | } | ||
3347 | |||
3348 | IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); | ||
3349 | |||
3350 | } | ||
3351 | |||
3260 | /** | 3352 | /** |
3261 | * Handle host notification packet. | 3353 | * Handle host notification packet. |
3262 | * Called from interrupt routine | 3354 | * Called from interrupt routine |
@@ -3383,6 +3475,24 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3383 | } | 3475 | } |
3384 | 3476 | ||
3385 | case CMAS_INIT:{ | 3477 | case CMAS_INIT:{ |
3478 | if (priv->status & STATUS_AUTH) { | ||
3479 | struct | ||
3480 | ieee80211_assoc_response | ||
3481 | *resp; | ||
3482 | resp = | ||
3483 | (struct | ||
3484 | ieee80211_assoc_response | ||
3485 | *)¬if->u.raw; | ||
3486 | IPW_DEBUG(IPW_DL_NOTIF | | ||
3487 | IPW_DL_STATE | | ||
3488 | IPW_DL_ASSOC, | ||
3489 | "association failed (0x%04X): %s\n", | ||
3490 | ntohs(resp->status), | ||
3491 | ipw_get_status_code | ||
3492 | (ntohs | ||
3493 | (resp->status))); | ||
3494 | } | ||
3495 | |||
3386 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | | 3496 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | |
3387 | IPW_DL_ASSOC, | 3497 | IPW_DL_ASSOC, |
3388 | "disassociated: '%s' " MAC_FMT | 3498 | "disassociated: '%s' " MAC_FMT |
@@ -3629,36 +3739,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3629 | break; | 3739 | break; |
3630 | } | 3740 | } |
3631 | 3741 | ||
3632 | if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) { | 3742 | if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) |
3633 | if (priv->status & STATUS_SCANNING) { | 3743 | ipw_handle_missed_beacon(priv, x->number); |
3634 | /* Stop scan to keep fw from getting | ||
3635 | * stuck... */ | ||
3636 | queue_work(priv->workqueue, | ||
3637 | &priv->abort_scan); | ||
3638 | } | ||
3639 | |||
3640 | if (x->number > priv->missed_beacon_threshold && | ||
3641 | priv->status & STATUS_ASSOCIATED) { | ||
3642 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | | ||
3643 | IPW_DL_STATE, | ||
3644 | "Missed beacon: %d - disassociate\n", | ||
3645 | x->number); | ||
3646 | queue_work(priv->workqueue, | ||
3647 | &priv->disassociate); | ||
3648 | } else if (x->number > priv->roaming_threshold) { | ||
3649 | IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, | ||
3650 | "Missed beacon: %d - initiate " | ||
3651 | "roaming\n", x->number); | ||
3652 | queue_work(priv->workqueue, | ||
3653 | &priv->roam); | ||
3654 | } else { | ||
3655 | IPW_DEBUG_NOTIF("Missed beacon: %d\n", | ||
3656 | x->number); | ||
3657 | } | ||
3658 | |||
3659 | priv->notif_missed_beacons = x->number; | ||
3660 | |||
3661 | } | ||
3662 | 3744 | ||
3663 | break; | 3745 | break; |
3664 | } | 3746 | } |
@@ -4137,6 +4219,13 @@ static int ipw_compatible_rates(struct ipw_priv *priv, | |||
4137 | for (i = 0; i < num_rates; i++) { | 4219 | for (i = 0; i < num_rates; i++) { |
4138 | if (!ipw_is_rate_in_mask | 4220 | if (!ipw_is_rate_in_mask |
4139 | (priv, network->mode, network->rates[i])) { | 4221 | (priv, network->mode, network->rates[i])) { |
4222 | if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { | ||
4223 | IPW_DEBUG_SCAN | ||
4224 | ("Basic rate %02X masked: 0x%08X\n", | ||
4225 | network->rates[i], priv->rates_mask); | ||
4226 | return 0; | ||
4227 | } | ||
4228 | |||
4140 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", | 4229 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", |
4141 | network->rates[i], priv->rates_mask); | 4230 | network->rates[i], priv->rates_mask); |
4142 | continue; | 4231 | continue; |
@@ -4150,6 +4239,13 @@ static int ipw_compatible_rates(struct ipw_priv *priv, | |||
4150 | for (i = 0; i < num_rates; i++) { | 4239 | for (i = 0; i < num_rates; i++) { |
4151 | if (!ipw_is_rate_in_mask | 4240 | if (!ipw_is_rate_in_mask |
4152 | (priv, network->mode, network->rates_ex[i])) { | 4241 | (priv, network->mode, network->rates_ex[i])) { |
4242 | if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { | ||
4243 | IPW_DEBUG_SCAN | ||
4244 | ("Basic rate %02X masked: 0x%08X\n", | ||
4245 | network->rates_ex[i], priv->rates_mask); | ||
4246 | return 0; | ||
4247 | } | ||
4248 | |||
4153 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", | 4249 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", |
4154 | network->rates_ex[i], priv->rates_mask); | 4250 | network->rates_ex[i], priv->rates_mask); |
4155 | continue; | 4251 | continue; |
@@ -4159,7 +4255,7 @@ static int ipw_compatible_rates(struct ipw_priv *priv, | |||
4159 | network->rates_ex[i]; | 4255 | network->rates_ex[i]; |
4160 | } | 4256 | } |
4161 | 4257 | ||
4162 | return rates->num_rates; | 4258 | return 1; |
4163 | } | 4259 | } |
4164 | 4260 | ||
4165 | static inline void ipw_copy_rates(struct ipw_supported_rates *dest, | 4261 | static inline void ipw_copy_rates(struct ipw_supported_rates *dest, |
@@ -4322,7 +4418,7 @@ static int ipw_best_network(struct ipw_priv *priv, | |||
4322 | /* If this network has already had an association attempt within the | 4418 | /* If this network has already had an association attempt within the |
4323 | * last 3 seconds, do not try and associate again... */ | 4419 | * last 3 seconds, do not try and associate again... */ |
4324 | if (network->last_associate && | 4420 | if (network->last_associate && |
4325 | time_after(network->last_associate + (HZ * 5UL), jiffies)) { | 4421 | time_after(network->last_associate + (HZ * 3UL), jiffies)) { |
4326 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | 4422 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " |
4327 | "because of storming (%lu since last " | 4423 | "because of storming (%lu since last " |
4328 | "assoc attempt).\n", | 4424 | "assoc attempt).\n", |
@@ -4334,7 +4430,7 @@ static int ipw_best_network(struct ipw_priv *priv, | |||
4334 | 4430 | ||
4335 | /* Now go through and see if the requested network is valid... */ | 4431 | /* Now go through and see if the requested network is valid... */ |
4336 | if (priv->ieee->scan_age != 0 && | 4432 | if (priv->ieee->scan_age != 0 && |
4337 | jiffies - network->last_scanned > priv->ieee->scan_age) { | 4433 | time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { |
4338 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | 4434 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " |
4339 | "because of age: %lums.\n", | 4435 | "because of age: %lums.\n", |
4340 | escape_essid(network->ssid, network->ssid_len), | 4436 | escape_essid(network->ssid, network->ssid_len), |
@@ -4386,7 +4482,17 @@ static int ipw_best_network(struct ipw_priv *priv, | |||
4386 | return 0; | 4482 | return 0; |
4387 | } | 4483 | } |
4388 | 4484 | ||
4389 | ipw_compatible_rates(priv, network, &rates); | 4485 | /* Ensure that the rates supported by the driver are compatible with |
4486 | * this AP, including verification of basic rates (mandatory) */ | ||
4487 | if (!ipw_compatible_rates(priv, network, &rates)) { | ||
4488 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | ||
4489 | "because configured rate mask excludes " | ||
4490 | "AP mandatory rate.\n", | ||
4491 | escape_essid(network->ssid, network->ssid_len), | ||
4492 | MAC_ARG(network->bssid)); | ||
4493 | return 0; | ||
4494 | } | ||
4495 | |||
4390 | if (rates.num_rates == 0) { | 4496 | if (rates.num_rates == 0) { |
4391 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " | 4497 | IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " |
4392 | "because of no compatible rates.\n", | 4498 | "because of no compatible rates.\n", |
@@ -4448,6 +4554,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv, | |||
4448 | memcpy(network->ssid, priv->essid, priv->essid_len); | 4554 | memcpy(network->ssid, priv->essid, priv->essid_len); |
4449 | memset(&network->stats, 0, sizeof(network->stats)); | 4555 | memset(&network->stats, 0, sizeof(network->stats)); |
4450 | network->capability = WLAN_CAPABILITY_IBSS; | 4556 | network->capability = WLAN_CAPABILITY_IBSS; |
4557 | if (!(priv->config & CFG_PREAMBLE_LONG)) | ||
4558 | network->capability |= WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
4451 | if (priv->capability & CAP_PRIVACY_ON) | 4559 | if (priv->capability & CAP_PRIVACY_ON) |
4452 | network->capability |= WLAN_CAPABILITY_PRIVACY; | 4560 | network->capability |= WLAN_CAPABILITY_PRIVACY; |
4453 | network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH); | 4561 | network->rates_len = min(priv->rates.num_rates, MAX_RATES_LENGTH); |
@@ -4530,7 +4638,8 @@ static void ipw_debug_config(struct ipw_priv *priv) | |||
4530 | else | 4638 | else |
4531 | IPW_DEBUG_INFO("ESSID unlocked.\n"); | 4639 | IPW_DEBUG_INFO("ESSID unlocked.\n"); |
4532 | if (priv->config & CFG_STATIC_BSSID) | 4640 | if (priv->config & CFG_STATIC_BSSID) |
4533 | IPW_DEBUG_INFO("BSSID locked to %d\n", priv->channel); | 4641 | IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n", |
4642 | MAC_ARG(priv->bssid)); | ||
4534 | else | 4643 | else |
4535 | IPW_DEBUG_INFO("BSSID unlocked.\n"); | 4644 | IPW_DEBUG_INFO("BSSID unlocked.\n"); |
4536 | if (priv->capability & CAP_PRIVACY_ON) | 4645 | if (priv->capability & CAP_PRIVACY_ON) |
@@ -4561,6 +4670,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, | |||
4561 | /* IEEE_A */ | 4670 | /* IEEE_A */ |
4562 | if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { | 4671 | if (priv->rates_mask & ~IEEE80211_OFDM_RATES_MASK) { |
4563 | /* Invalid fixed rate mask */ | 4672 | /* Invalid fixed rate mask */ |
4673 | IPW_DEBUG_WX | ||
4674 | ("invalid fixed rate mask in ipw_set_fixed_rate\n"); | ||
4564 | fr.tx_rates = 0; | 4675 | fr.tx_rates = 0; |
4565 | break; | 4676 | break; |
4566 | } | 4677 | } |
@@ -4573,6 +4684,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, | |||
4573 | if (network->mode == IEEE_B) { | 4684 | if (network->mode == IEEE_B) { |
4574 | if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { | 4685 | if (fr.tx_rates & ~IEEE80211_CCK_RATES_MASK) { |
4575 | /* Invalid fixed rate mask */ | 4686 | /* Invalid fixed rate mask */ |
4687 | IPW_DEBUG_WX | ||
4688 | ("invalid fixed rate mask in ipw_set_fixed_rate\n"); | ||
4576 | fr.tx_rates = 0; | 4689 | fr.tx_rates = 0; |
4577 | } | 4690 | } |
4578 | break; | 4691 | break; |
@@ -4582,6 +4695,8 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, | |||
4582 | if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | | 4695 | if (fr.tx_rates & ~(IEEE80211_CCK_RATES_MASK | |
4583 | IEEE80211_OFDM_RATES_MASK)) { | 4696 | IEEE80211_OFDM_RATES_MASK)) { |
4584 | /* Invalid fixed rate mask */ | 4697 | /* Invalid fixed rate mask */ |
4698 | IPW_DEBUG_WX | ||
4699 | ("invalid fixed rate mask in ipw_set_fixed_rate\n"); | ||
4585 | fr.tx_rates = 0; | 4700 | fr.tx_rates = 0; |
4586 | break; | 4701 | break; |
4587 | } | 4702 | } |
@@ -4609,6 +4724,597 @@ static inline void ipw_set_fixed_rate(struct ipw_priv *priv, | |||
4609 | ipw_write_reg32(priv, reg, *(u32 *) & fr); | 4724 | ipw_write_reg32(priv, reg, *(u32 *) & fr); |
4610 | } | 4725 | } |
4611 | 4726 | ||
4727 | static void ipw_abort_scan(struct ipw_priv *priv) | ||
4728 | { | ||
4729 | int err; | ||
4730 | |||
4731 | if (priv->status & STATUS_SCAN_ABORTING) { | ||
4732 | IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n"); | ||
4733 | return; | ||
4734 | } | ||
4735 | priv->status |= STATUS_SCAN_ABORTING; | ||
4736 | |||
4737 | err = ipw_send_scan_abort(priv); | ||
4738 | if (err) | ||
4739 | IPW_DEBUG_HC("Request to abort scan failed.\n"); | ||
4740 | } | ||
4741 | |||
4742 | static int ipw_request_scan(struct ipw_priv *priv) | ||
4743 | { | ||
4744 | struct ipw_scan_request_ext scan; | ||
4745 | int channel_index = 0; | ||
4746 | int i, err, scan_type; | ||
4747 | |||
4748 | if (priv->status & STATUS_EXIT_PENDING) { | ||
4749 | IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n"); | ||
4750 | priv->status |= STATUS_SCAN_PENDING; | ||
4751 | return 0; | ||
4752 | } | ||
4753 | |||
4754 | if (priv->status & STATUS_SCANNING) { | ||
4755 | IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); | ||
4756 | priv->status |= STATUS_SCAN_PENDING; | ||
4757 | ipw_abort_scan(priv); | ||
4758 | return 0; | ||
4759 | } | ||
4760 | |||
4761 | if (priv->status & STATUS_SCAN_ABORTING) { | ||
4762 | IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); | ||
4763 | priv->status |= STATUS_SCAN_PENDING; | ||
4764 | return 0; | ||
4765 | } | ||
4766 | |||
4767 | if (priv->status & STATUS_RF_KILL_MASK) { | ||
4768 | IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); | ||
4769 | priv->status |= STATUS_SCAN_PENDING; | ||
4770 | return 0; | ||
4771 | } | ||
4772 | |||
4773 | memset(&scan, 0, sizeof(scan)); | ||
4774 | |||
4775 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20; | ||
4776 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20; | ||
4777 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20; | ||
4778 | |||
4779 | scan.full_scan_index = ieee80211_get_scans(priv->ieee); | ||
4780 | |||
4781 | #ifdef CONFIG_IPW_MONITOR | ||
4782 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | ||
4783 | u8 band = 0, channel = priv->channel; | ||
4784 | |||
4785 | if (is_valid_channel(IEEE_A, channel)) | ||
4786 | band = (u8) (IPW_A_MODE << 6) | 1; | ||
4787 | |||
4788 | if (is_valid_channel(IEEE_B | IEEE_G, channel)) | ||
4789 | band = (u8) (IPW_B_MODE << 6) | 1; | ||
4790 | |||
4791 | if (band == 0) { | ||
4792 | band = (u8) (IPW_B_MODE << 6) | 1; | ||
4793 | channel = 9; | ||
4794 | } | ||
4795 | |||
4796 | scan.channels_list[channel_index++] = band; | ||
4797 | scan.channels_list[channel_index] = channel; | ||
4798 | ipw_set_scan_type(&scan, channel_index, | ||
4799 | IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); | ||
4800 | |||
4801 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 2000; | ||
4802 | } else { | ||
4803 | #endif /* CONFIG_IPW_MONITOR */ | ||
4804 | /* If we are roaming, then make this a directed scan for the current | ||
4805 | * network. Otherwise, ensure that every other scan is a fast | ||
4806 | * channel hop scan */ | ||
4807 | if ((priv->status & STATUS_ROAMING) | ||
4808 | || (!(priv->status & STATUS_ASSOCIATED) | ||
4809 | && (priv->config & CFG_STATIC_ESSID) | ||
4810 | && (scan.full_scan_index % 2))) { | ||
4811 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); | ||
4812 | if (err) { | ||
4813 | IPW_DEBUG_HC | ||
4814 | ("Attempt to send SSID command failed.\n"); | ||
4815 | return err; | ||
4816 | } | ||
4817 | |||
4818 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; | ||
4819 | } else { | ||
4820 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; | ||
4821 | } | ||
4822 | |||
4823 | if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { | ||
4824 | int start = channel_index; | ||
4825 | for (i = 0; i < MAX_A_CHANNELS; i++) { | ||
4826 | if (band_a_active_channel[i] == 0) | ||
4827 | break; | ||
4828 | if ((priv->status & STATUS_ASSOCIATED) && | ||
4829 | band_a_active_channel[i] == priv->channel) | ||
4830 | continue; | ||
4831 | channel_index++; | ||
4832 | scan.channels_list[channel_index] = | ||
4833 | band_a_active_channel[i]; | ||
4834 | ipw_set_scan_type(&scan, channel_index, | ||
4835 | scan_type); | ||
4836 | } | ||
4837 | |||
4838 | if (start != channel_index) { | ||
4839 | scan.channels_list[start] = | ||
4840 | (u8) (IPW_A_MODE << 6) | (channel_index - | ||
4841 | start); | ||
4842 | channel_index++; | ||
4843 | } | ||
4844 | } | ||
4845 | |||
4846 | if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { | ||
4847 | int start = channel_index; | ||
4848 | for (i = 0; i < MAX_B_CHANNELS; i++) { | ||
4849 | if (band_b_active_channel[i] == 0) | ||
4850 | break; | ||
4851 | if ((priv->status & STATUS_ASSOCIATED) && | ||
4852 | band_b_active_channel[i] == priv->channel) | ||
4853 | continue; | ||
4854 | channel_index++; | ||
4855 | scan.channels_list[channel_index] = | ||
4856 | band_b_active_channel[i]; | ||
4857 | ipw_set_scan_type(&scan, channel_index, | ||
4858 | scan_type); | ||
4859 | } | ||
4860 | |||
4861 | if (start != channel_index) { | ||
4862 | scan.channels_list[start] = | ||
4863 | (u8) (IPW_B_MODE << 6) | (channel_index - | ||
4864 | start); | ||
4865 | } | ||
4866 | } | ||
4867 | #ifdef CONFIG_IPW_MONITOR | ||
4868 | } | ||
4869 | #endif | ||
4870 | |||
4871 | err = ipw_send_scan_request_ext(priv, &scan); | ||
4872 | if (err) { | ||
4873 | IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); | ||
4874 | return -EIO; | ||
4875 | } | ||
4876 | |||
4877 | priv->status |= STATUS_SCANNING; | ||
4878 | priv->status &= ~STATUS_SCAN_PENDING; | ||
4879 | |||
4880 | return 0; | ||
4881 | } | ||
4882 | |||
4883 | /* Support for wpa_supplicant. Will be replaced with WEXT once | ||
4884 | * they get WPA support. */ | ||
4885 | #ifdef CONFIG_IEEE80211_WPA | ||
4886 | |||
4887 | /* following definitions must match definitions in driver_ipw.c */ | ||
4888 | |||
4889 | #define IPW_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 | ||
4890 | |||
4891 | #define IPW_CMD_SET_WPA_PARAM 1 | ||
4892 | #define IPW_CMD_SET_WPA_IE 2 | ||
4893 | #define IPW_CMD_SET_ENCRYPTION 3 | ||
4894 | #define IPW_CMD_MLME 4 | ||
4895 | |||
4896 | #define IPW_PARAM_WPA_ENABLED 1 | ||
4897 | #define IPW_PARAM_TKIP_COUNTERMEASURES 2 | ||
4898 | #define IPW_PARAM_DROP_UNENCRYPTED 3 | ||
4899 | #define IPW_PARAM_PRIVACY_INVOKED 4 | ||
4900 | #define IPW_PARAM_AUTH_ALGS 5 | ||
4901 | #define IPW_PARAM_IEEE_802_1X 6 | ||
4902 | |||
4903 | #define IPW_MLME_STA_DEAUTH 1 | ||
4904 | #define IPW_MLME_STA_DISASSOC 2 | ||
4905 | |||
4906 | #define IPW_CRYPT_ERR_UNKNOWN_ALG 2 | ||
4907 | #define IPW_CRYPT_ERR_UNKNOWN_ADDR 3 | ||
4908 | #define IPW_CRYPT_ERR_CRYPT_INIT_FAILED 4 | ||
4909 | #define IPW_CRYPT_ERR_KEY_SET_FAILED 5 | ||
4910 | #define IPW_CRYPT_ERR_TX_KEY_SET_FAILED 6 | ||
4911 | #define IPW_CRYPT_ERR_CARD_CONF_FAILED 7 | ||
4912 | |||
4913 | #define IPW_CRYPT_ALG_NAME_LEN 16 | ||
4914 | |||
4915 | struct ipw_param { | ||
4916 | u32 cmd; | ||
4917 | u8 sta_addr[ETH_ALEN]; | ||
4918 | union { | ||
4919 | struct { | ||
4920 | u8 name; | ||
4921 | u32 value; | ||
4922 | } wpa_param; | ||
4923 | struct { | ||
4924 | u32 len; | ||
4925 | u8 *data; | ||
4926 | } wpa_ie; | ||
4927 | struct { | ||
4928 | int command; | ||
4929 | int reason_code; | ||
4930 | } mlme; | ||
4931 | struct { | ||
4932 | u8 alg[IPW_CRYPT_ALG_NAME_LEN]; | ||
4933 | u8 set_tx; | ||
4934 | u32 err; | ||
4935 | u8 idx; | ||
4936 | u8 seq[8]; /* sequence counter (set: RX, get: TX) */ | ||
4937 | u16 key_len; | ||
4938 | u8 key[0]; | ||
4939 | } crypt; | ||
4940 | |||
4941 | } u; | ||
4942 | }; | ||
4943 | |||
4944 | /* end of driver_ipw.c code */ | ||
4945 | |||
4946 | static int ipw_wpa_enable(struct ipw_priv *priv, int value) | ||
4947 | { | ||
4948 | struct ieee80211_device *ieee = priv->ieee; | ||
4949 | struct ieee80211_security sec = { | ||
4950 | .flags = SEC_LEVEL | SEC_ENABLED, | ||
4951 | }; | ||
4952 | int ret = 0; | ||
4953 | |||
4954 | ieee->wpa_enabled = value; | ||
4955 | |||
4956 | if (value) { | ||
4957 | sec.level = SEC_LEVEL_3; | ||
4958 | sec.enabled = 1; | ||
4959 | } else { | ||
4960 | sec.level = SEC_LEVEL_0; | ||
4961 | sec.enabled = 0; | ||
4962 | } | ||
4963 | |||
4964 | if (ieee->set_security) | ||
4965 | ieee->set_security(ieee->dev, &sec); | ||
4966 | else | ||
4967 | ret = -EOPNOTSUPP; | ||
4968 | |||
4969 | return ret; | ||
4970 | } | ||
4971 | |||
4972 | #define AUTH_ALG_OPEN_SYSTEM 0x1 | ||
4973 | #define AUTH_ALG_SHARED_KEY 0x2 | ||
4974 | |||
4975 | static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) | ||
4976 | { | ||
4977 | struct ieee80211_device *ieee = priv->ieee; | ||
4978 | struct ieee80211_security sec = { | ||
4979 | .flags = SEC_AUTH_MODE, | ||
4980 | }; | ||
4981 | int ret = 0; | ||
4982 | |||
4983 | if (value & AUTH_ALG_SHARED_KEY) { | ||
4984 | sec.auth_mode = WLAN_AUTH_SHARED_KEY; | ||
4985 | ieee->open_wep = 0; | ||
4986 | } else { | ||
4987 | sec.auth_mode = WLAN_AUTH_OPEN; | ||
4988 | ieee->open_wep = 1; | ||
4989 | } | ||
4990 | |||
4991 | if (ieee->set_security) | ||
4992 | ieee->set_security(ieee->dev, &sec); | ||
4993 | else | ||
4994 | ret = -EOPNOTSUPP; | ||
4995 | |||
4996 | return ret; | ||
4997 | } | ||
4998 | |||
4999 | static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) | ||
5000 | { | ||
5001 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5002 | int ret = 0; | ||
5003 | |||
5004 | switch (name) { | ||
5005 | case IPW_PARAM_WPA_ENABLED: | ||
5006 | ret = ipw_wpa_enable(priv, value); | ||
5007 | break; | ||
5008 | |||
5009 | case IPW_PARAM_TKIP_COUNTERMEASURES: | ||
5010 | priv->ieee->tkip_countermeasures = value; | ||
5011 | break; | ||
5012 | |||
5013 | case IPW_PARAM_DROP_UNENCRYPTED: | ||
5014 | priv->ieee->drop_unencrypted = value; | ||
5015 | break; | ||
5016 | |||
5017 | case IPW_PARAM_PRIVACY_INVOKED: | ||
5018 | priv->ieee->privacy_invoked = value; | ||
5019 | break; | ||
5020 | |||
5021 | case IPW_PARAM_AUTH_ALGS: | ||
5022 | ret = ipw_wpa_set_auth_algs(priv, value); | ||
5023 | break; | ||
5024 | |||
5025 | case IPW_PARAM_IEEE_802_1X: | ||
5026 | priv->ieee->ieee802_1x = value; | ||
5027 | break; | ||
5028 | |||
5029 | default: | ||
5030 | IPW_ERROR("%s: Unknown WPA param: %d\n", dev->name, name); | ||
5031 | ret = -EOPNOTSUPP; | ||
5032 | } | ||
5033 | |||
5034 | return ret; | ||
5035 | } | ||
5036 | |||
5037 | static int ipw_wpa_mlme(struct net_device *dev, int command, int reason) | ||
5038 | { | ||
5039 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5040 | int ret = 0; | ||
5041 | |||
5042 | switch (command) { | ||
5043 | case IPW_MLME_STA_DEAUTH: | ||
5044 | // silently ignore | ||
5045 | break; | ||
5046 | |||
5047 | case IPW_MLME_STA_DISASSOC: | ||
5048 | ipw_disassociate(priv); | ||
5049 | break; | ||
5050 | |||
5051 | default: | ||
5052 | IPW_ERROR("%s: Unknown MLME request: %d\n", dev->name, command); | ||
5053 | ret = -EOPNOTSUPP; | ||
5054 | } | ||
5055 | |||
5056 | return ret; | ||
5057 | } | ||
5058 | |||
5059 | static int ipw_set_rsn_capa(struct ipw_priv *priv, | ||
5060 | char *capabilities, int length) | ||
5061 | { | ||
5062 | struct host_cmd cmd = { | ||
5063 | .cmd = IPW_CMD_RSN_CAPABILITIES, | ||
5064 | .len = length, | ||
5065 | }; | ||
5066 | |||
5067 | IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); | ||
5068 | |||
5069 | memcpy(&cmd.param, capabilities, length); | ||
5070 | if (ipw_send_cmd(priv, &cmd)) { | ||
5071 | IPW_ERROR("failed to send HOST_CMD_RSN_CAPABILITIES command\n"); | ||
5072 | return -1; | ||
5073 | } | ||
5074 | return 0; | ||
5075 | } | ||
5076 | |||
5077 | void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) | ||
5078 | { | ||
5079 | /* make sure WPA is enabled */ | ||
5080 | ipw_wpa_enable(priv, 1); | ||
5081 | |||
5082 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) | ||
5083 | ipw_disassociate(priv); | ||
5084 | } | ||
5085 | |||
5086 | static int ipw_wpa_set_wpa_ie(struct net_device *dev, | ||
5087 | struct ipw_param *param, int plen) | ||
5088 | { | ||
5089 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5090 | struct ieee80211_device *ieee = priv->ieee; | ||
5091 | u8 *buf; | ||
5092 | |||
5093 | if (!ieee->wpa_enabled) | ||
5094 | return -EOPNOTSUPP; | ||
5095 | |||
5096 | if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || | ||
5097 | (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) | ||
5098 | return -EINVAL; | ||
5099 | |||
5100 | if (param->u.wpa_ie.len) { | ||
5101 | buf = kmalloc(param->u.wpa_ie.len, GFP_KERNEL); | ||
5102 | if (buf == NULL) | ||
5103 | return -ENOMEM; | ||
5104 | |||
5105 | memcpy(buf, param->u.wpa_ie.data, param->u.wpa_ie.len); | ||
5106 | kfree(ieee->wpa_ie); | ||
5107 | ieee->wpa_ie = buf; | ||
5108 | ieee->wpa_ie_len = param->u.wpa_ie.len; | ||
5109 | } else { | ||
5110 | kfree(ieee->wpa_ie); | ||
5111 | ieee->wpa_ie = NULL; | ||
5112 | ieee->wpa_ie_len = 0; | ||
5113 | } | ||
5114 | |||
5115 | ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); | ||
5116 | return 0; | ||
5117 | } | ||
5118 | |||
5119 | /* implementation borrowed from hostap driver */ | ||
5120 | |||
5121 | static int ipw_wpa_set_encryption(struct net_device *dev, | ||
5122 | struct ipw_param *param, int param_len) | ||
5123 | { | ||
5124 | int ret = 0; | ||
5125 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
5126 | struct ieee80211_device *ieee = priv->ieee; | ||
5127 | struct ieee80211_crypto_ops *ops; | ||
5128 | struct ieee80211_crypt_data **crypt; | ||
5129 | |||
5130 | struct ieee80211_security sec = { | ||
5131 | .flags = 0, | ||
5132 | }; | ||
5133 | |||
5134 | param->u.crypt.err = 0; | ||
5135 | param->u.crypt.alg[IPW_CRYPT_ALG_NAME_LEN - 1] = '\0'; | ||
5136 | |||
5137 | if (param_len != | ||
5138 | (int)((char *)param->u.crypt.key - (char *)param) + | ||
5139 | param->u.crypt.key_len) { | ||
5140 | IPW_DEBUG_INFO("Len mismatch %d, %d\n", param_len, | ||
5141 | param->u.crypt.key_len); | ||
5142 | return -EINVAL; | ||
5143 | } | ||
5144 | if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && | ||
5145 | param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && | ||
5146 | param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { | ||
5147 | if (param->u.crypt.idx >= WEP_KEYS) | ||
5148 | return -EINVAL; | ||
5149 | crypt = &ieee->crypt[param->u.crypt.idx]; | ||
5150 | } else { | ||
5151 | return -EINVAL; | ||
5152 | } | ||
5153 | |||
5154 | if (strcmp(param->u.crypt.alg, "none") == 0) { | ||
5155 | if (crypt) { | ||
5156 | sec.enabled = 0; | ||
5157 | sec.level = SEC_LEVEL_0; | ||
5158 | sec.flags |= SEC_ENABLED | SEC_LEVEL; | ||
5159 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
5160 | } | ||
5161 | goto done; | ||
5162 | } | ||
5163 | sec.enabled = 1; | ||
5164 | sec.flags |= SEC_ENABLED; | ||
5165 | |||
5166 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
5167 | if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { | ||
5168 | request_module("ieee80211_crypt_wep"); | ||
5169 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
5170 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { | ||
5171 | request_module("ieee80211_crypt_tkip"); | ||
5172 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
5173 | } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { | ||
5174 | request_module("ieee80211_crypt_ccmp"); | ||
5175 | ops = ieee80211_get_crypto_ops(param->u.crypt.alg); | ||
5176 | } | ||
5177 | if (ops == NULL) { | ||
5178 | IPW_DEBUG_INFO("%s: unknown crypto alg '%s'\n", | ||
5179 | dev->name, param->u.crypt.alg); | ||
5180 | param->u.crypt.err = IPW_CRYPT_ERR_UNKNOWN_ALG; | ||
5181 | ret = -EINVAL; | ||
5182 | goto done; | ||
5183 | } | ||
5184 | |||
5185 | if (*crypt == NULL || (*crypt)->ops != ops) { | ||
5186 | struct ieee80211_crypt_data *new_crypt; | ||
5187 | |||
5188 | ieee80211_crypt_delayed_deinit(ieee, crypt); | ||
5189 | |||
5190 | new_crypt = (struct ieee80211_crypt_data *) | ||
5191 | kmalloc(sizeof(*new_crypt), GFP_KERNEL); | ||
5192 | if (new_crypt == NULL) { | ||
5193 | ret = -ENOMEM; | ||
5194 | goto done; | ||
5195 | } | ||
5196 | memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); | ||
5197 | new_crypt->ops = ops; | ||
5198 | if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) | ||
5199 | new_crypt->priv = | ||
5200 | new_crypt->ops->init(param->u.crypt.idx); | ||
5201 | |||
5202 | if (new_crypt->priv == NULL) { | ||
5203 | kfree(new_crypt); | ||
5204 | param->u.crypt.err = IPW_CRYPT_ERR_CRYPT_INIT_FAILED; | ||
5205 | ret = -EINVAL; | ||
5206 | goto done; | ||
5207 | } | ||
5208 | |||
5209 | *crypt = new_crypt; | ||
5210 | } | ||
5211 | |||
5212 | if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && | ||
5213 | (*crypt)->ops->set_key(param->u.crypt.key, | ||
5214 | param->u.crypt.key_len, param->u.crypt.seq, | ||
5215 | (*crypt)->priv) < 0) { | ||
5216 | IPW_DEBUG_INFO("%s: key setting failed\n", dev->name); | ||
5217 | param->u.crypt.err = IPW_CRYPT_ERR_KEY_SET_FAILED; | ||
5218 | ret = -EINVAL; | ||
5219 | goto done; | ||
5220 | } | ||
5221 | |||
5222 | if (param->u.crypt.set_tx) { | ||
5223 | ieee->tx_keyidx = param->u.crypt.idx; | ||
5224 | sec.active_key = param->u.crypt.idx; | ||
5225 | sec.flags |= SEC_ACTIVE_KEY; | ||
5226 | } | ||
5227 | |||
5228 | if (ops->name != NULL) { | ||
5229 | if (strcmp(ops->name, "WEP") == 0) { | ||
5230 | memcpy(sec.keys[param->u.crypt.idx], | ||
5231 | param->u.crypt.key, param->u.crypt.key_len); | ||
5232 | sec.key_sizes[param->u.crypt.idx] = | ||
5233 | param->u.crypt.key_len; | ||
5234 | sec.flags |= (1 << param->u.crypt.idx); | ||
5235 | sec.flags |= SEC_LEVEL; | ||
5236 | sec.level = SEC_LEVEL_1; | ||
5237 | } else if (strcmp(ops->name, "TKIP") == 0) { | ||
5238 | sec.flags |= SEC_LEVEL; | ||
5239 | sec.level = SEC_LEVEL_2; | ||
5240 | } else if (strcmp(ops->name, "CCMP") == 0) { | ||
5241 | sec.flags |= SEC_LEVEL; | ||
5242 | sec.level = SEC_LEVEL_3; | ||
5243 | } | ||
5244 | } | ||
5245 | done: | ||
5246 | if (ieee->set_security) | ||
5247 | ieee->set_security(ieee->dev, &sec); | ||
5248 | |||
5249 | /* Do not reset port if card is in Managed mode since resetting will | ||
5250 | * generate new IEEE 802.11 authentication which may end up in looping | ||
5251 | * with IEEE 802.1X. If your hardware requires a reset after WEP | ||
5252 | * configuration (for example... Prism2), implement the reset_port in | ||
5253 | * the callbacks structures used to initialize the 802.11 stack. */ | ||
5254 | if (ieee->reset_on_keychange && | ||
5255 | ieee->iw_mode != IW_MODE_INFRA && | ||
5256 | ieee->reset_port && ieee->reset_port(dev)) { | ||
5257 | IPW_DEBUG_INFO("%s: reset_port failed\n", dev->name); | ||
5258 | param->u.crypt.err = IPW_CRYPT_ERR_CARD_CONF_FAILED; | ||
5259 | return -EINVAL; | ||
5260 | } | ||
5261 | |||
5262 | return ret; | ||
5263 | } | ||
5264 | |||
5265 | static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) | ||
5266 | { | ||
5267 | struct ipw_param *param; | ||
5268 | int ret = 0; | ||
5269 | |||
5270 | IPW_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length); | ||
5271 | |||
5272 | if (p->length < sizeof(struct ipw_param) || !p->pointer) | ||
5273 | return -EINVAL; | ||
5274 | |||
5275 | param = (struct ipw_param *)kmalloc(p->length, GFP_KERNEL); | ||
5276 | if (param == NULL) | ||
5277 | return -ENOMEM; | ||
5278 | |||
5279 | if (copy_from_user(param, p->pointer, p->length)) { | ||
5280 | kfree(param); | ||
5281 | return -EFAULT; | ||
5282 | } | ||
5283 | |||
5284 | switch (param->cmd) { | ||
5285 | |||
5286 | case IPW_CMD_SET_WPA_PARAM: | ||
5287 | ret = ipw_wpa_set_param(dev, param->u.wpa_param.name, | ||
5288 | param->u.wpa_param.value); | ||
5289 | break; | ||
5290 | |||
5291 | case IPW_CMD_SET_WPA_IE: | ||
5292 | ret = ipw_wpa_set_wpa_ie(dev, param, p->length); | ||
5293 | break; | ||
5294 | |||
5295 | case IPW_CMD_SET_ENCRYPTION: | ||
5296 | ret = ipw_wpa_set_encryption(dev, param, p->length); | ||
5297 | break; | ||
5298 | |||
5299 | case IPW_CMD_MLME: | ||
5300 | ret = ipw_wpa_mlme(dev, param->u.mlme.command, | ||
5301 | param->u.mlme.reason_code); | ||
5302 | break; | ||
5303 | |||
5304 | default: | ||
5305 | IPW_ERROR("%s: Unknown WPA supplicant request: %d\n", | ||
5306 | dev->name, param->cmd); | ||
5307 | ret = -EOPNOTSUPP; | ||
5308 | } | ||
5309 | |||
5310 | if (ret == 0 && copy_to_user(p->pointer, param, p->length)) | ||
5311 | ret = -EFAULT; | ||
5312 | |||
5313 | kfree(param); | ||
5314 | return ret; | ||
5315 | } | ||
5316 | #endif /* CONFIG_IEEE80211_WPA */ | ||
5317 | |||
4612 | static int ipw_associate_network(struct ipw_priv *priv, | 5318 | static int ipw_associate_network(struct ipw_priv *priv, |
4613 | struct ieee80211_network *network, | 5319 | struct ieee80211_network *network, |
4614 | struct ipw_supported_rates *rates, int roaming) | 5320 | struct ipw_supported_rates *rates, int roaming) |
@@ -4640,6 +5346,14 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
4640 | if (priv->capability & CAP_PRIVACY_ON) | 5346 | if (priv->capability & CAP_PRIVACY_ON) |
4641 | ipw_send_wep_keys(priv); | 5347 | ipw_send_wep_keys(priv); |
4642 | 5348 | ||
5349 | #ifdef CONFIG_IEEE80211_WPA | ||
5350 | if (priv->ieee->wpa_enabled) { | ||
5351 | priv->assoc_request.policy_support = 0x02; /* RSN active */ | ||
5352 | ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, | ||
5353 | priv->ieee->wpa_ie_len); | ||
5354 | } | ||
5355 | #endif | ||
5356 | |||
4643 | /* | 5357 | /* |
4644 | * It is valid for our ieee device to support multiple modes, but | 5358 | * It is valid for our ieee device to support multiple modes, but |
4645 | * when it comes to associating to a given network we have to choose | 5359 | * when it comes to associating to a given network we have to choose |
@@ -4652,13 +5366,29 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
4652 | else if (network->mode & priv->ieee->mode & IEEE_B) | 5366 | else if (network->mode & priv->ieee->mode & IEEE_B) |
4653 | priv->assoc_request.ieee_mode = IPW_B_MODE; | 5367 | priv->assoc_request.ieee_mode = IPW_B_MODE; |
4654 | 5368 | ||
5369 | priv->assoc_request.capability = network->capability; | ||
5370 | if ((network->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) | ||
5371 | && !(priv->config & CFG_PREAMBLE_LONG)) { | ||
5372 | priv->assoc_request.preamble_length = DCT_FLAG_SHORT_PREAMBLE; | ||
5373 | } else { | ||
5374 | priv->assoc_request.preamble_length = DCT_FLAG_LONG_PREAMBLE; | ||
5375 | |||
5376 | /* Clear the short preamble if we won't be supporting it */ | ||
5377 | priv->assoc_request.capability &= | ||
5378 | ~WLAN_CAPABILITY_SHORT_PREAMBLE; | ||
5379 | } | ||
5380 | |||
4655 | IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " | 5381 | IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " |
4656 | "802.11%c [%d], enc=%s%s%s%c%c\n", | 5382 | "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", |
4657 | roaming ? "Rea" : "A", | 5383 | roaming ? "Rea" : "A", |
4658 | escape_essid(priv->essid, priv->essid_len), | 5384 | escape_essid(priv->essid, priv->essid_len), |
4659 | network->channel, | 5385 | network->channel, |
4660 | ipw_modes[priv->assoc_request.ieee_mode], | 5386 | ipw_modes[priv->assoc_request.ieee_mode], |
4661 | rates->num_rates, | 5387 | rates->num_rates, |
5388 | (priv->assoc_request.preamble_length == | ||
5389 | DCT_FLAG_LONG_PREAMBLE) ? "long" : "short", | ||
5390 | network->capability & | ||
5391 | WLAN_CAPABILITY_SHORT_PREAMBLE ? "short" : "long", | ||
4662 | priv->capability & CAP_PRIVACY_ON ? "on " : "off", | 5392 | priv->capability & CAP_PRIVACY_ON ? "on " : "off", |
4663 | priv->capability & CAP_PRIVACY_ON ? | 5393 | priv->capability & CAP_PRIVACY_ON ? |
4664 | (priv->capability & CAP_SHARED_KEY ? "(shared)" : | 5394 | (priv->capability & CAP_SHARED_KEY ? "(shared)" : |
@@ -4693,7 +5423,6 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
4693 | priv->assoc_request.atim_window = 0; | 5423 | priv->assoc_request.atim_window = 0; |
4694 | } | 5424 | } |
4695 | 5425 | ||
4696 | priv->assoc_request.capability = network->capability; | ||
4697 | priv->assoc_request.listen_interval = network->listen_interval; | 5426 | priv->assoc_request.listen_interval = network->listen_interval; |
4698 | 5427 | ||
4699 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); | 5428 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); |
@@ -4717,7 +5446,7 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
4717 | } | 5446 | } |
4718 | 5447 | ||
4719 | IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi); | 5448 | IPW_DEBUG_ASSOC("Association sensitivity: %d\n", network->stats.rssi); |
4720 | err = ipw_set_sensitivity(priv, network->stats.rssi); | 5449 | err = ipw_set_sensitivity(priv, network->stats.rssi + IPW_RSSI_TO_DBM); |
4721 | if (err) { | 5450 | if (err) { |
4722 | IPW_DEBUG_HC("Attempt to send associate command failed.\n"); | 5451 | IPW_DEBUG_HC("Attempt to send associate command failed.\n"); |
4723 | return err; | 5452 | return err; |
@@ -4899,6 +5628,32 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv, | |||
4899 | rxb->skb = NULL; | 5628 | rxb->skb = NULL; |
4900 | } | 5629 | } |
4901 | 5630 | ||
5631 | static inline int is_network_packet(struct ipw_priv *priv, | ||
5632 | struct ieee80211_hdr_4addr *header) | ||
5633 | { | ||
5634 | /* Filter incoming packets to determine if they are targetted toward | ||
5635 | * this network, discarding packets coming from ourselves */ | ||
5636 | switch (priv->ieee->iw_mode) { | ||
5637 | case IW_MODE_ADHOC: | ||
5638 | if (is_broadcast_ether_addr(header->addr1) || | ||
5639 | is_multicast_ether_addr(header->addr1)) | ||
5640 | return !memcmp(header->addr3, priv->bssid, ETH_ALEN); | ||
5641 | else | ||
5642 | return memcmp(header->addr1, priv->net_dev->dev_addr, | ||
5643 | ETH_ALEN); | ||
5644 | break; | ||
5645 | case IW_MODE_INFRA: | ||
5646 | if (is_broadcast_ether_addr(header->addr3) || | ||
5647 | is_multicast_ether_addr(header->addr3)) | ||
5648 | return !memcmp(header->addr1, priv->bssid, ETH_ALEN); | ||
5649 | else | ||
5650 | return memcmp(header->addr3, priv->net_dev->dev_addr, | ||
5651 | ETH_ALEN); | ||
5652 | break; | ||
5653 | } | ||
5654 | return 1; | ||
5655 | } | ||
5656 | |||
4902 | /* | 5657 | /* |
4903 | * Main entry function for recieving a packet with 80211 headers. This | 5658 | * Main entry function for recieving a packet with 80211 headers. This |
4904 | * should be called when ever the FW has notified us that there is a new | 5659 | * should be called when ever the FW has notified us that there is a new |
@@ -4962,7 +5717,7 @@ static void ipw_rx(struct ipw_priv *priv) | |||
4962 | 5717 | ||
4963 | priv->rx_packets++; | 5718 | priv->rx_packets++; |
4964 | 5719 | ||
4965 | #ifdef CONFIG_IPW_PROMISC | 5720 | #ifdef CONFIG_IPW_MONITOR |
4966 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 5721 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
4967 | ipw_handle_data_packet(priv, rxb, | 5722 | ipw_handle_data_packet(priv, rxb, |
4968 | &stats); | 5723 | &stats); |
@@ -4979,35 +5734,9 @@ static void ipw_rx(struct ipw_priv *priv) | |||
4979 | * correctly -- we should probably use the | 5734 | * correctly -- we should probably use the |
4980 | * frame control of the packet and disregard | 5735 | * frame control of the packet and disregard |
4981 | * the current iw_mode */ | 5736 | * the current iw_mode */ |
4982 | switch (priv->ieee->iw_mode) { | ||
4983 | case IW_MODE_ADHOC: | ||
4984 | network_packet = | ||
4985 | !memcmp(header->addr1, | ||
4986 | priv->net_dev->dev_addr, | ||
4987 | ETH_ALEN) || | ||
4988 | !memcmp(header->addr3, | ||
4989 | priv->bssid, ETH_ALEN) || | ||
4990 | is_broadcast_ether_addr(header-> | ||
4991 | addr1) | ||
4992 | || is_multicast_ether_addr(header-> | ||
4993 | addr1); | ||
4994 | break; | ||
4995 | |||
4996 | case IW_MODE_INFRA: | ||
4997 | default: | ||
4998 | network_packet = | ||
4999 | !memcmp(header->addr3, | ||
5000 | priv->bssid, ETH_ALEN) || | ||
5001 | !memcmp(header->addr1, | ||
5002 | priv->net_dev->dev_addr, | ||
5003 | ETH_ALEN) || | ||
5004 | is_broadcast_ether_addr(header-> | ||
5005 | addr1) | ||
5006 | || is_multicast_ether_addr(header-> | ||
5007 | addr1); | ||
5008 | break; | ||
5009 | } | ||
5010 | 5737 | ||
5738 | network_packet = | ||
5739 | is_network_packet(priv, header); | ||
5011 | if (network_packet && priv->assoc_network) { | 5740 | if (network_packet && priv->assoc_network) { |
5012 | priv->assoc_network->stats.rssi = | 5741 | priv->assoc_network->stats.rssi = |
5013 | stats.rssi; | 5742 | stats.rssi; |
@@ -5108,130 +5837,6 @@ static void ipw_rx(struct ipw_priv *priv) | |||
5108 | ipw_rx_queue_restock(priv); | 5837 | ipw_rx_queue_restock(priv); |
5109 | } | 5838 | } |
5110 | 5839 | ||
5111 | static void ipw_abort_scan(struct ipw_priv *priv) | ||
5112 | { | ||
5113 | int err; | ||
5114 | |||
5115 | if (priv->status & STATUS_SCAN_ABORTING) { | ||
5116 | IPW_DEBUG_HC("Ignoring concurrent scan abort request.\n"); | ||
5117 | return; | ||
5118 | } | ||
5119 | priv->status |= STATUS_SCAN_ABORTING; | ||
5120 | |||
5121 | err = ipw_send_scan_abort(priv); | ||
5122 | if (err) | ||
5123 | IPW_DEBUG_HC("Request to abort scan failed.\n"); | ||
5124 | } | ||
5125 | |||
5126 | static int ipw_request_scan(struct ipw_priv *priv) | ||
5127 | { | ||
5128 | struct ipw_scan_request_ext scan; | ||
5129 | int channel_index = 0; | ||
5130 | int i, err, scan_type; | ||
5131 | |||
5132 | if (priv->status & STATUS_EXIT_PENDING) { | ||
5133 | IPW_DEBUG_SCAN("Aborting scan due to device shutdown\n"); | ||
5134 | priv->status |= STATUS_SCAN_PENDING; | ||
5135 | return 0; | ||
5136 | } | ||
5137 | |||
5138 | if (priv->status & STATUS_SCANNING) { | ||
5139 | IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); | ||
5140 | priv->status |= STATUS_SCAN_PENDING; | ||
5141 | ipw_abort_scan(priv); | ||
5142 | return 0; | ||
5143 | } | ||
5144 | |||
5145 | if (priv->status & STATUS_SCAN_ABORTING) { | ||
5146 | IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); | ||
5147 | priv->status |= STATUS_SCAN_PENDING; | ||
5148 | return 0; | ||
5149 | } | ||
5150 | |||
5151 | if (priv->status & STATUS_RF_KILL_MASK) { | ||
5152 | IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); | ||
5153 | priv->status |= STATUS_SCAN_PENDING; | ||
5154 | return 0; | ||
5155 | } | ||
5156 | |||
5157 | memset(&scan, 0, sizeof(scan)); | ||
5158 | |||
5159 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20; | ||
5160 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20; | ||
5161 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20; | ||
5162 | |||
5163 | scan.full_scan_index = ieee80211_get_scans(priv->ieee); | ||
5164 | /* If we are roaming, then make this a directed scan for the current | ||
5165 | * network. Otherwise, ensure that every other scan is a fast | ||
5166 | * channel hop scan */ | ||
5167 | if ((priv->status & STATUS_ROAMING) | ||
5168 | || (!(priv->status & STATUS_ASSOCIATED) | ||
5169 | && (priv->config & CFG_STATIC_ESSID) | ||
5170 | && (scan.full_scan_index % 2))) { | ||
5171 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); | ||
5172 | if (err) { | ||
5173 | IPW_DEBUG_HC("Attempt to send SSID command failed.\n"); | ||
5174 | return err; | ||
5175 | } | ||
5176 | |||
5177 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; | ||
5178 | } else { | ||
5179 | scan_type = IPW_SCAN_ACTIVE_BROADCAST_SCAN; | ||
5180 | } | ||
5181 | |||
5182 | if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { | ||
5183 | int start = channel_index; | ||
5184 | for (i = 0; i < MAX_A_CHANNELS; i++) { | ||
5185 | if (band_a_active_channel[i] == 0) | ||
5186 | break; | ||
5187 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5188 | band_a_active_channel[i] == priv->channel) | ||
5189 | continue; | ||
5190 | channel_index++; | ||
5191 | scan.channels_list[channel_index] = | ||
5192 | band_a_active_channel[i]; | ||
5193 | ipw_set_scan_type(&scan, channel_index, scan_type); | ||
5194 | } | ||
5195 | |||
5196 | if (start != channel_index) { | ||
5197 | scan.channels_list[start] = (u8) (IPW_A_MODE << 6) | | ||
5198 | (channel_index - start); | ||
5199 | channel_index++; | ||
5200 | } | ||
5201 | } | ||
5202 | |||
5203 | if (priv->ieee->freq_band & IEEE80211_24GHZ_BAND) { | ||
5204 | int start = channel_index; | ||
5205 | for (i = 0; i < MAX_B_CHANNELS; i++) { | ||
5206 | if (band_b_active_channel[i] == 0) | ||
5207 | break; | ||
5208 | if ((priv->status & STATUS_ASSOCIATED) && | ||
5209 | band_b_active_channel[i] == priv->channel) | ||
5210 | continue; | ||
5211 | channel_index++; | ||
5212 | scan.channels_list[channel_index] = | ||
5213 | band_b_active_channel[i]; | ||
5214 | ipw_set_scan_type(&scan, channel_index, scan_type); | ||
5215 | } | ||
5216 | |||
5217 | if (start != channel_index) { | ||
5218 | scan.channels_list[start] = (u8) (IPW_B_MODE << 6) | | ||
5219 | (channel_index - start); | ||
5220 | } | ||
5221 | } | ||
5222 | |||
5223 | err = ipw_send_scan_request_ext(priv, &scan); | ||
5224 | if (err) { | ||
5225 | IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); | ||
5226 | return -EIO; | ||
5227 | } | ||
5228 | |||
5229 | priv->status |= STATUS_SCANNING; | ||
5230 | priv->status &= ~STATUS_SCAN_PENDING; | ||
5231 | |||
5232 | return 0; | ||
5233 | } | ||
5234 | |||
5235 | /* | 5840 | /* |
5236 | * This file defines the Wireless Extension handlers. It does not | 5841 | * This file defines the Wireless Extension handlers. It does not |
5237 | * define any methods of hardware manipulation and relies on the | 5842 | * define any methods of hardware manipulation and relies on the |
@@ -5357,7 +5962,7 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
5357 | return 0; | 5962 | return 0; |
5358 | 5963 | ||
5359 | switch (wrqu->mode) { | 5964 | switch (wrqu->mode) { |
5360 | #ifdef CONFIG_IPW_PROMISC | 5965 | #ifdef CONFIG_IPW_MONITOR |
5361 | case IW_MODE_MONITOR: | 5966 | case IW_MODE_MONITOR: |
5362 | #endif | 5967 | #endif |
5363 | case IW_MODE_ADHOC: | 5968 | case IW_MODE_ADHOC: |
@@ -5370,13 +5975,13 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
5370 | return -EINVAL; | 5975 | return -EINVAL; |
5371 | } | 5976 | } |
5372 | 5977 | ||
5373 | #ifdef CONFIG_IPW_PROMISC | 5978 | #ifdef CONFIG_IPW_MONITOR |
5374 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) | 5979 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) |
5375 | priv->net_dev->type = ARPHRD_ETHER; | 5980 | priv->net_dev->type = ARPHRD_ETHER; |
5376 | 5981 | ||
5377 | if (wrqu->mode == IW_MODE_MONITOR) | 5982 | if (wrqu->mode == IW_MODE_MONITOR) |
5378 | priv->net_dev->type = ARPHRD_IEEE80211; | 5983 | priv->net_dev->type = ARPHRD_IEEE80211; |
5379 | #endif /* CONFIG_IPW_PROMISC */ | 5984 | #endif /* CONFIG_IPW_MONITOR */ |
5380 | 5985 | ||
5381 | #ifdef CONFIG_PM | 5986 | #ifdef CONFIG_PM |
5382 | /* Free the existing firmware and reset the fw_loaded | 5987 | /* Free the existing firmware and reset the fw_loaded |
@@ -5680,8 +6285,111 @@ static int ipw_wx_set_rate(struct net_device *dev, | |||
5680 | struct iw_request_info *info, | 6285 | struct iw_request_info *info, |
5681 | union iwreq_data *wrqu, char *extra) | 6286 | union iwreq_data *wrqu, char *extra) |
5682 | { | 6287 | { |
5683 | IPW_DEBUG_WX("0x%p, 0x%p, 0x%p\n", dev, info, wrqu); | 6288 | /* TODO: We should use semaphores or locks for access to priv */ |
5684 | return -EOPNOTSUPP; | 6289 | struct ipw_priv *priv = ieee80211_priv(dev); |
6290 | u32 target_rate = wrqu->bitrate.value; | ||
6291 | u32 fixed, mask; | ||
6292 | |||
6293 | /* value = -1, fixed = 0 means auto only, so we should use all rates offered by AP */ | ||
6294 | /* value = X, fixed = 1 means only rate X */ | ||
6295 | /* value = X, fixed = 0 means all rates lower equal X */ | ||
6296 | |||
6297 | if (target_rate == -1) { | ||
6298 | fixed = 0; | ||
6299 | mask = IEEE80211_DEFAULT_RATES_MASK; | ||
6300 | /* Now we should reassociate */ | ||
6301 | goto apply; | ||
6302 | } | ||
6303 | |||
6304 | mask = 0; | ||
6305 | fixed = wrqu->bitrate.fixed; | ||
6306 | |||
6307 | if (target_rate == 1000000 || !fixed) | ||
6308 | mask |= IEEE80211_CCK_RATE_1MB_MASK; | ||
6309 | if (target_rate == 1000000) | ||
6310 | goto apply; | ||
6311 | |||
6312 | if (target_rate == 2000000 || !fixed) | ||
6313 | mask |= IEEE80211_CCK_RATE_2MB_MASK; | ||
6314 | if (target_rate == 2000000) | ||
6315 | goto apply; | ||
6316 | |||
6317 | if (target_rate == 5500000 || !fixed) | ||
6318 | mask |= IEEE80211_CCK_RATE_5MB_MASK; | ||
6319 | if (target_rate == 5500000) | ||
6320 | goto apply; | ||
6321 | |||
6322 | if (target_rate == 6000000 || !fixed) | ||
6323 | mask |= IEEE80211_OFDM_RATE_6MB_MASK; | ||
6324 | if (target_rate == 6000000) | ||
6325 | goto apply; | ||
6326 | |||
6327 | if (target_rate == 9000000 || !fixed) | ||
6328 | mask |= IEEE80211_OFDM_RATE_9MB_MASK; | ||
6329 | if (target_rate == 9000000) | ||
6330 | goto apply; | ||
6331 | |||
6332 | if (target_rate == 11000000 || !fixed) | ||
6333 | mask |= IEEE80211_CCK_RATE_11MB_MASK; | ||
6334 | if (target_rate == 11000000) | ||
6335 | goto apply; | ||
6336 | |||
6337 | if (target_rate == 12000000 || !fixed) | ||
6338 | mask |= IEEE80211_OFDM_RATE_12MB_MASK; | ||
6339 | if (target_rate == 12000000) | ||
6340 | goto apply; | ||
6341 | |||
6342 | if (target_rate == 18000000 || !fixed) | ||
6343 | mask |= IEEE80211_OFDM_RATE_18MB_MASK; | ||
6344 | if (target_rate == 18000000) | ||
6345 | goto apply; | ||
6346 | |||
6347 | if (target_rate == 24000000 || !fixed) | ||
6348 | mask |= IEEE80211_OFDM_RATE_24MB_MASK; | ||
6349 | if (target_rate == 24000000) | ||
6350 | goto apply; | ||
6351 | |||
6352 | if (target_rate == 36000000 || !fixed) | ||
6353 | mask |= IEEE80211_OFDM_RATE_36MB_MASK; | ||
6354 | if (target_rate == 36000000) | ||
6355 | goto apply; | ||
6356 | |||
6357 | if (target_rate == 48000000 || !fixed) | ||
6358 | mask |= IEEE80211_OFDM_RATE_48MB_MASK; | ||
6359 | if (target_rate == 48000000) | ||
6360 | goto apply; | ||
6361 | |||
6362 | if (target_rate == 54000000 || !fixed) | ||
6363 | mask |= IEEE80211_OFDM_RATE_54MB_MASK; | ||
6364 | if (target_rate == 54000000) | ||
6365 | goto apply; | ||
6366 | |||
6367 | IPW_DEBUG_WX("invalid rate specified, returning error\n"); | ||
6368 | return -EINVAL; | ||
6369 | |||
6370 | apply: | ||
6371 | IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", | ||
6372 | mask, fixed ? "fixed" : "sub-rates"); | ||
6373 | |||
6374 | if (mask == IEEE80211_DEFAULT_RATES_MASK) | ||
6375 | priv->config &= ~CFG_FIXED_RATE; | ||
6376 | else | ||
6377 | priv->config |= CFG_FIXED_RATE; | ||
6378 | |||
6379 | if (priv->rates_mask != mask) { | ||
6380 | priv->rates_mask = mask; | ||
6381 | /* If we are already associated or are currently trying to | ||
6382 | * associate, disassociate and try again */ | ||
6383 | if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { | ||
6384 | IPW_DEBUG_ASSOC("Disassociating due to RATE change.\n"); | ||
6385 | ipw_disassociate(priv); | ||
6386 | } | ||
6387 | } else { | ||
6388 | /* We are not yet associated, so kick one off... */ | ||
6389 | ipw_associate(priv); | ||
6390 | } | ||
6391 | |||
6392 | return 0; | ||
5685 | } | 6393 | } |
5686 | 6394 | ||
5687 | static int ipw_wx_get_rate(struct net_device *dev, | 6395 | static int ipw_wx_get_rate(struct net_device *dev, |
@@ -5888,7 +6596,6 @@ static int ipw_wx_set_power(struct net_device *dev, | |||
5888 | IPW_DEBUG_WX("failed setting power mode.\n"); | 6596 | IPW_DEBUG_WX("failed setting power mode.\n"); |
5889 | return err; | 6597 | return err; |
5890 | } | 6598 | } |
5891 | |||
5892 | IPW_DEBUG_WX("SET Power Management Mode -> off\n"); | 6599 | IPW_DEBUG_WX("SET Power Management Mode -> off\n"); |
5893 | 6600 | ||
5894 | return 0; | 6601 | return 0; |
@@ -6069,37 +6776,30 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, | |||
6069 | { | 6776 | { |
6070 | struct ipw_priv *priv = ieee80211_priv(dev); | 6777 | struct ipw_priv *priv = ieee80211_priv(dev); |
6071 | 6778 | ||
6072 | switch (priv->ieee->freq_band) { | 6779 | switch (priv->ieee->mode) { |
6073 | case IEEE80211_24GHZ_BAND: | 6780 | case IEEE_A: |
6074 | switch (priv->ieee->modulation) { | ||
6075 | case IEEE80211_CCK_MODULATION: | ||
6076 | strncpy(extra, "802.11b (2)", MAX_WX_STRING); | ||
6077 | break; | ||
6078 | case IEEE80211_OFDM_MODULATION: | ||
6079 | strncpy(extra, "802.11g (4)", MAX_WX_STRING); | ||
6080 | break; | ||
6081 | default: | ||
6082 | strncpy(extra, "802.11bg (6)", MAX_WX_STRING); | ||
6083 | break; | ||
6084 | } | ||
6085 | break; | ||
6086 | |||
6087 | case IEEE80211_52GHZ_BAND: | ||
6088 | strncpy(extra, "802.11a (1)", MAX_WX_STRING); | 6781 | strncpy(extra, "802.11a (1)", MAX_WX_STRING); |
6089 | break; | 6782 | break; |
6090 | 6783 | case IEEE_B: | |
6091 | default: /* Mixed Band */ | 6784 | strncpy(extra, "802.11b (2)", MAX_WX_STRING); |
6092 | switch (priv->ieee->modulation) { | 6785 | break; |
6093 | case IEEE80211_CCK_MODULATION: | 6786 | case IEEE_A | IEEE_B: |
6094 | strncpy(extra, "802.11ab (3)", MAX_WX_STRING); | 6787 | strncpy(extra, "802.11ab (3)", MAX_WX_STRING); |
6095 | break; | 6788 | break; |
6096 | case IEEE80211_OFDM_MODULATION: | 6789 | case IEEE_G: |
6097 | strncpy(extra, "802.11ag (5)", MAX_WX_STRING); | 6790 | strncpy(extra, "802.11g (4)", MAX_WX_STRING); |
6098 | break; | 6791 | break; |
6099 | default: | 6792 | case IEEE_A | IEEE_G: |
6100 | strncpy(extra, "802.11abg (7)", MAX_WX_STRING); | 6793 | strncpy(extra, "802.11ag (5)", MAX_WX_STRING); |
6101 | break; | 6794 | break; |
6102 | } | 6795 | case IEEE_B | IEEE_G: |
6796 | strncpy(extra, "802.11bg (6)", MAX_WX_STRING); | ||
6797 | break; | ||
6798 | case IEEE_A | IEEE_B | IEEE_G: | ||
6799 | strncpy(extra, "802.11abg (7)", MAX_WX_STRING); | ||
6800 | break; | ||
6801 | default: | ||
6802 | strncpy(extra, "unknown", MAX_WX_STRING); | ||
6103 | break; | 6803 | break; |
6104 | } | 6804 | } |
6105 | 6805 | ||
@@ -6110,8 +6810,55 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, | |||
6110 | return 0; | 6810 | return 0; |
6111 | } | 6811 | } |
6112 | 6812 | ||
6113 | #ifdef CONFIG_IPW_PROMISC | 6813 | static int ipw_wx_set_preamble(struct net_device *dev, |
6114 | static int ipw_wx_set_promisc(struct net_device *dev, | 6814 | struct iw_request_info *info, |
6815 | union iwreq_data *wrqu, char *extra) | ||
6816 | { | ||
6817 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6818 | int mode = *(int *)extra; | ||
6819 | |||
6820 | /* Switching from SHORT -> LONG requires a disassociation */ | ||
6821 | if (mode == 1) { | ||
6822 | if (!(priv->config & CFG_PREAMBLE_LONG)) { | ||
6823 | priv->config |= CFG_PREAMBLE_LONG; | ||
6824 | if (priv->status & | ||
6825 | (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | ||
6826 | IPW_DEBUG_ASSOC | ||
6827 | ("Disassociating due to preamble " | ||
6828 | "change.\n"); | ||
6829 | ipw_disassociate(priv); | ||
6830 | } | ||
6831 | } | ||
6832 | goto done; | ||
6833 | } | ||
6834 | |||
6835 | if (mode == 0) { | ||
6836 | priv->config &= ~CFG_PREAMBLE_LONG; | ||
6837 | goto done; | ||
6838 | } | ||
6839 | |||
6840 | return -EINVAL; | ||
6841 | |||
6842 | done: | ||
6843 | return 0; | ||
6844 | } | ||
6845 | |||
6846 | static int ipw_wx_get_preamble(struct net_device *dev, | ||
6847 | struct iw_request_info *info, | ||
6848 | union iwreq_data *wrqu, char *extra) | ||
6849 | { | ||
6850 | struct ipw_priv *priv = ieee80211_priv(dev); | ||
6851 | |||
6852 | if (priv->config & CFG_PREAMBLE_LONG) | ||
6853 | snprintf(wrqu->name, IFNAMSIZ, "long (1)"); | ||
6854 | else | ||
6855 | snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); | ||
6856 | |||
6857 | return 0; | ||
6858 | } | ||
6859 | |||
6860 | #ifdef CONFIG_IPW_MONITOR | ||
6861 | static int ipw_wx_set_monitor(struct net_device *dev, | ||
6115 | struct iw_request_info *info, | 6862 | struct iw_request_info *info, |
6116 | union iwreq_data *wrqu, char *extra) | 6863 | union iwreq_data *wrqu, char *extra) |
6117 | { | 6864 | { |
@@ -6119,7 +6866,7 @@ static int ipw_wx_set_promisc(struct net_device *dev, | |||
6119 | int *parms = (int *)extra; | 6866 | int *parms = (int *)extra; |
6120 | int enable = (parms[0] > 0); | 6867 | int enable = (parms[0] > 0); |
6121 | 6868 | ||
6122 | IPW_DEBUG_WX("SET PROMISC: %d %d\n", enable, parms[1]); | 6869 | IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); |
6123 | if (enable) { | 6870 | if (enable) { |
6124 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { | 6871 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { |
6125 | priv->net_dev->type = ARPHRD_IEEE80211; | 6872 | priv->net_dev->type = ARPHRD_IEEE80211; |
@@ -6145,47 +6892,49 @@ static int ipw_wx_reset(struct net_device *dev, | |||
6145 | ipw_adapter_restart(priv); | 6892 | ipw_adapter_restart(priv); |
6146 | return 0; | 6893 | return 0; |
6147 | } | 6894 | } |
6148 | #endif // CONFIG_IPW_PROMISC | 6895 | #endif // CONFIG_IPW_MONITOR |
6149 | 6896 | ||
6150 | /* Rebase the WE IOCTLs to zero for the handler array */ | 6897 | /* Rebase the WE IOCTLs to zero for the handler array */ |
6151 | #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] | 6898 | #define IW_IOCTL(x) [(x)-SIOCSIWCOMMIT] |
6152 | static iw_handler ipw_wx_handlers[] = { | 6899 | static iw_handler ipw_wx_handlers[] = { |
6153 | IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, | 6900 | IW_IOCTL(SIOCGIWNAME) = ipw_wx_get_name, |
6154 | IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, | 6901 | IW_IOCTL(SIOCSIWFREQ) = ipw_wx_set_freq, |
6155 | IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, | 6902 | IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, |
6156 | IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, | 6903 | IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, |
6157 | IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, | 6904 | IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, |
6158 | IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, | 6905 | IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, |
6159 | IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, | 6906 | IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, |
6160 | IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, | 6907 | IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, |
6161 | IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, | 6908 | IW_IOCTL(SIOCSIWSCAN) = ipw_wx_set_scan, |
6162 | IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, | 6909 | IW_IOCTL(SIOCGIWSCAN) = ipw_wx_get_scan, |
6163 | IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, | 6910 | IW_IOCTL(SIOCSIWESSID) = ipw_wx_set_essid, |
6164 | IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, | 6911 | IW_IOCTL(SIOCGIWESSID) = ipw_wx_get_essid, |
6165 | IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, | 6912 | IW_IOCTL(SIOCSIWNICKN) = ipw_wx_set_nick, |
6166 | IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, | 6913 | IW_IOCTL(SIOCGIWNICKN) = ipw_wx_get_nick, |
6167 | IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, | 6914 | IW_IOCTL(SIOCSIWRATE) = ipw_wx_set_rate, |
6168 | IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, | 6915 | IW_IOCTL(SIOCGIWRATE) = ipw_wx_get_rate, |
6169 | IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, | 6916 | IW_IOCTL(SIOCSIWRTS) = ipw_wx_set_rts, |
6170 | IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, | 6917 | IW_IOCTL(SIOCGIWRTS) = ipw_wx_get_rts, |
6171 | IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, | 6918 | IW_IOCTL(SIOCSIWFRAG) = ipw_wx_set_frag, |
6172 | IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, | 6919 | IW_IOCTL(SIOCGIWFRAG) = ipw_wx_get_frag, |
6173 | IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, | 6920 | IW_IOCTL(SIOCSIWTXPOW) = ipw_wx_set_txpow, |
6174 | IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, | 6921 | IW_IOCTL(SIOCGIWTXPOW) = ipw_wx_get_txpow, |
6175 | IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, | 6922 | IW_IOCTL(SIOCSIWRETRY) = ipw_wx_set_retry, |
6176 | IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, | 6923 | IW_IOCTL(SIOCGIWRETRY) = ipw_wx_get_retry, |
6177 | IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, | 6924 | IW_IOCTL(SIOCSIWENCODE) = ipw_wx_set_encode, |
6178 | IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, | 6925 | IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, |
6179 | IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, | 6926 | IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, |
6180 | IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, | 6927 | IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, |
6181 | }; | 6928 | }; |
6182 | 6929 | ||
6183 | #define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV | 6930 | #define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV |
6184 | #define IPW_PRIV_GET_POWER SIOCIWFIRSTPRIV+1 | 6931 | #define IPW_PRIV_GET_POWER SIOCIWFIRSTPRIV+1 |
6185 | #define IPW_PRIV_SET_MODE SIOCIWFIRSTPRIV+2 | 6932 | #define IPW_PRIV_SET_MODE SIOCIWFIRSTPRIV+2 |
6186 | #define IPW_PRIV_GET_MODE SIOCIWFIRSTPRIV+3 | 6933 | #define IPW_PRIV_GET_MODE SIOCIWFIRSTPRIV+3 |
6187 | #define IPW_PRIV_SET_PROMISC SIOCIWFIRSTPRIV+4 | 6934 | #define IPW_PRIV_SET_PREAMBLE SIOCIWFIRSTPRIV+4 |
6188 | #define IPW_PRIV_RESET SIOCIWFIRSTPRIV+5 | 6935 | #define IPW_PRIV_GET_PREAMBLE SIOCIWFIRSTPRIV+5 |
6936 | #define IPW_PRIV_SET_MONITOR SIOCIWFIRSTPRIV+6 | ||
6937 | #define IPW_PRIV_RESET SIOCIWFIRSTPRIV+7 | ||
6189 | 6938 | ||
6190 | static struct iw_priv_args ipw_priv_args[] = { | 6939 | static struct iw_priv_args ipw_priv_args[] = { |
6191 | { | 6940 | { |
@@ -6204,14 +6953,22 @@ static struct iw_priv_args ipw_priv_args[] = { | |||
6204 | .cmd = IPW_PRIV_GET_MODE, | 6953 | .cmd = IPW_PRIV_GET_MODE, |
6205 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, | 6954 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, |
6206 | .name = "get_mode"}, | 6955 | .name = "get_mode"}, |
6207 | #ifdef CONFIG_IPW_PROMISC | ||
6208 | { | 6956 | { |
6209 | IPW_PRIV_SET_PROMISC, | 6957 | .cmd = IPW_PRIV_SET_PREAMBLE, |
6958 | .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
6959 | .name = "set_preamble"}, | ||
6960 | { | ||
6961 | .cmd = IPW_PRIV_GET_PREAMBLE, | ||
6962 | .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | IFNAMSIZ, | ||
6963 | .name = "get_preamble"}, | ||
6964 | #ifdef CONFIG_IPW_MONITOR | ||
6965 | { | ||
6966 | IPW_PRIV_SET_MONITOR, | ||
6210 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, | 6967 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "monitor"}, |
6211 | { | 6968 | { |
6212 | IPW_PRIV_RESET, | 6969 | IPW_PRIV_RESET, |
6213 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, | 6970 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 0, 0, "reset"}, |
6214 | #endif /* CONFIG_IPW_PROMISC */ | 6971 | #endif /* CONFIG_IPW_MONITOR */ |
6215 | }; | 6972 | }; |
6216 | 6973 | ||
6217 | static iw_handler ipw_priv_handler[] = { | 6974 | static iw_handler ipw_priv_handler[] = { |
@@ -6219,19 +6976,21 @@ static iw_handler ipw_priv_handler[] = { | |||
6219 | ipw_wx_get_powermode, | 6976 | ipw_wx_get_powermode, |
6220 | ipw_wx_set_wireless_mode, | 6977 | ipw_wx_set_wireless_mode, |
6221 | ipw_wx_get_wireless_mode, | 6978 | ipw_wx_get_wireless_mode, |
6222 | #ifdef CONFIG_IPW_PROMISC | 6979 | ipw_wx_set_preamble, |
6223 | ipw_wx_set_promisc, | 6980 | ipw_wx_get_preamble, |
6981 | #ifdef CONFIG_IPW_MONITOR | ||
6982 | ipw_wx_set_monitor, | ||
6224 | ipw_wx_reset, | 6983 | ipw_wx_reset, |
6225 | #endif | 6984 | #endif |
6226 | }; | 6985 | }; |
6227 | 6986 | ||
6228 | static struct iw_handler_def ipw_wx_handler_def = { | 6987 | static struct iw_handler_def ipw_wx_handler_def = { |
6229 | .standard = ipw_wx_handlers, | 6988 | .standard = ipw_wx_handlers, |
6230 | .num_standard = ARRAY_SIZE(ipw_wx_handlers), | 6989 | .num_standard = ARRAY_SIZE(ipw_wx_handlers), |
6231 | .num_private = ARRAY_SIZE(ipw_priv_handler), | 6990 | .num_private = ARRAY_SIZE(ipw_priv_handler), |
6232 | .num_private_args = ARRAY_SIZE(ipw_priv_args), | 6991 | .num_private_args = ARRAY_SIZE(ipw_priv_args), |
6233 | .private = ipw_priv_handler, | 6992 | .private = ipw_priv_handler, |
6234 | .private_args = ipw_priv_args, | 6993 | .private_args = ipw_priv_args, |
6235 | }; | 6994 | }; |
6236 | 6995 | ||
6237 | /* | 6996 | /* |
@@ -6246,7 +7005,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) | |||
6246 | 7005 | ||
6247 | wstats = &priv->wstats; | 7006 | wstats = &priv->wstats; |
6248 | 7007 | ||
6249 | /* if hw is disabled, then ipw2100_get_ordinal() can't be called. | 7008 | /* if hw is disabled, then ipw_get_ordinal() can't be called. |
6250 | * ipw2100_wx_wireless_stats seems to be called before fw is | 7009 | * ipw2100_wx_wireless_stats seems to be called before fw is |
6251 | * initialized. STATUS_ASSOCIATED will only be set if the hw is up | 7010 | * initialized. STATUS_ASSOCIATED will only be set if the hw is up |
6252 | * and associated; if not associcated, the values are all meaningless | 7011 | * and associated; if not associcated, the values are all meaningless |
@@ -6384,8 +7143,8 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
6384 | else | 7143 | else |
6385 | tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM; | 7144 | tfd->u.data.tx_flags_ext = DCT_FLAG_EXT_MODE_OFDM; |
6386 | 7145 | ||
6387 | if (priv->config & CFG_PREAMBLE) | 7146 | if (priv->assoc_request.preamble_length == DCT_FLAG_SHORT_PREAMBLE) |
6388 | tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREMBL; | 7147 | tfd->u.data.tx_flags |= DCT_FLAG_SHORT_PREAMBLE; |
6389 | 7148 | ||
6390 | memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); | 7149 | memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); |
6391 | 7150 | ||
@@ -6568,11 +7327,11 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, | |||
6568 | } | 7327 | } |
6569 | 7328 | ||
6570 | static struct ethtool_ops ipw_ethtool_ops = { | 7329 | static struct ethtool_ops ipw_ethtool_ops = { |
6571 | .get_link = ipw_ethtool_get_link, | 7330 | .get_link = ipw_ethtool_get_link, |
6572 | .get_drvinfo = ipw_ethtool_get_drvinfo, | 7331 | .get_drvinfo = ipw_ethtool_get_drvinfo, |
6573 | .get_eeprom_len = ipw_ethtool_get_eeprom_len, | 7332 | .get_eeprom_len = ipw_ethtool_get_eeprom_len, |
6574 | .get_eeprom = ipw_ethtool_get_eeprom, | 7333 | .get_eeprom = ipw_ethtool_get_eeprom, |
6575 | .set_eeprom = ipw_ethtool_set_eeprom, | 7334 | .set_eeprom = ipw_ethtool_set_eeprom, |
6576 | }; | 7335 | }; |
6577 | 7336 | ||
6578 | static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) | 7337 | static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs) |
@@ -6918,6 +7677,25 @@ static void ipw_down(struct ipw_priv *priv) | |||
6918 | ipw_stop_nic(priv); | 7677 | ipw_stop_nic(priv); |
6919 | } | 7678 | } |
6920 | 7679 | ||
7680 | static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
7681 | { | ||
7682 | #ifdef CONFIG_IEEE80211_WPA | ||
7683 | struct iwreq *wrq = (struct iwreq *)rq; | ||
7684 | int ret = -1; | ||
7685 | switch (cmd) { | ||
7686 | case IPW_IOCTL_WPA_SUPPLICANT: | ||
7687 | ret = ipw_wpa_supplicant(dev, &wrq->u.data); | ||
7688 | return ret; | ||
7689 | |||
7690 | default: | ||
7691 | return -EOPNOTSUPP; | ||
7692 | } | ||
7693 | |||
7694 | #endif /* CONFIG_IEEE80211_WPA */ | ||
7695 | |||
7696 | return -EOPNOTSUPP; | ||
7697 | } | ||
7698 | |||
6921 | /* Called by register_netdev() */ | 7699 | /* Called by register_netdev() */ |
6922 | static int ipw_net_init(struct net_device *dev) | 7700 | static int ipw_net_init(struct net_device *dev) |
6923 | { | 7701 | { |
@@ -7065,9 +7843,6 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7065 | } | 7843 | } |
7066 | 7844 | ||
7067 | /* Initialize module parameter values here */ | 7845 | /* Initialize module parameter values here */ |
7068 | if (ifname) | ||
7069 | strncpy(net_dev->name, ifname, IFNAMSIZ); | ||
7070 | |||
7071 | if (associate) | 7846 | if (associate) |
7072 | priv->config |= CFG_ASSOCIATE; | 7847 | priv->config |= CFG_ASSOCIATE; |
7073 | else | 7848 | else |
@@ -7095,7 +7870,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7095 | case 1: | 7870 | case 1: |
7096 | priv->ieee->iw_mode = IW_MODE_ADHOC; | 7871 | priv->ieee->iw_mode = IW_MODE_ADHOC; |
7097 | break; | 7872 | break; |
7098 | #ifdef CONFIG_IPW_PROMISC | 7873 | #ifdef CONFIG_IPW_MONITOR |
7099 | case 2: | 7874 | case 2: |
7100 | priv->ieee->iw_mode = IW_MODE_MONITOR; | 7875 | priv->ieee->iw_mode = IW_MODE_MONITOR; |
7101 | break; | 7876 | break; |
@@ -7164,6 +7939,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7164 | net_dev->open = ipw_net_open; | 7939 | net_dev->open = ipw_net_open; |
7165 | net_dev->stop = ipw_net_stop; | 7940 | net_dev->stop = ipw_net_stop; |
7166 | net_dev->init = ipw_net_init; | 7941 | net_dev->init = ipw_net_init; |
7942 | net_dev->do_ioctl = ipw_ioctl; | ||
7167 | net_dev->get_stats = ipw_net_get_stats; | 7943 | net_dev->get_stats = ipw_net_get_stats; |
7168 | net_dev->set_multicast_list = ipw_net_set_multicast_list; | 7944 | net_dev->set_multicast_list = ipw_net_set_multicast_list; |
7169 | net_dev->set_mac_address = ipw_net_set_mac_address; | 7945 | net_dev->set_mac_address = ipw_net_set_mac_address; |
@@ -7287,13 +8063,10 @@ static int ipw_pci_resume(struct pci_dev *pdev) | |||
7287 | 8063 | ||
7288 | printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); | 8064 | printk(KERN_INFO "%s: Coming out of suspend...\n", dev->name); |
7289 | 8065 | ||
7290 | pci_set_power_state(pdev, 0); | 8066 | pci_set_power_state(pdev, PCI_D0); |
7291 | pci_enable_device(pdev); | 8067 | pci_enable_device(pdev); |
7292 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) | ||
7293 | pci_restore_state(pdev, priv->pm_state); | ||
7294 | #else | ||
7295 | pci_restore_state(pdev); | 8068 | pci_restore_state(pdev); |
7296 | #endif | 8069 | |
7297 | /* | 8070 | /* |
7298 | * Suspend/Resume resets the PCI configuration space, so we have to | 8071 | * Suspend/Resume resets the PCI configuration space, so we have to |
7299 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries | 8072 | * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries |
@@ -7371,10 +8144,7 @@ MODULE_PARM_DESC(debug, "debug output mask"); | |||
7371 | module_param(channel, int, 0444); | 8144 | module_param(channel, int, 0444); |
7372 | MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); | 8145 | MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); |
7373 | 8146 | ||
7374 | module_param(ifname, charp, 0444); | 8147 | #ifdef CONFIG_IPW_MONITOR |
7375 | MODULE_PARM_DESC(ifname, "network device name (default eth%d)"); | ||
7376 | |||
7377 | #ifdef CONFIG_IPW_PROMISC | ||
7378 | module_param(mode, int, 0444); | 8148 | module_param(mode, int, 0444); |
7379 | MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); | 8149 | MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); |
7380 | #else | 8150 | #else |