diff options
author | David S. Miller <davem@davemloft.net> | 2011-02-08 16:52:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-02-08 16:52:31 -0500 |
commit | c0c84ef5c130f8871adbdaac2ba824b9195cb6d9 (patch) | |
tree | d7221b5323d5a4d3d84676d32bdca21d21d85a18 /net/mac80211 | |
parent | 2360d2e8f01043632d6b651672bec66c49892f94 (diff) | |
parent | 3ad97fbcc233a295f2ccc2c6bdeb32323e360a5e (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 26 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 108 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 14 | ||||
-rw-r--r-- | net/mac80211/iface.c | 9 | ||||
-rw-r--r-- | net/mac80211/main.c | 53 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 60 | ||||
-rw-r--r-- | net/mac80211/offchannel.c | 68 | ||||
-rw-r--r-- | net/mac80211/rx.c | 59 | ||||
-rw-r--r-- | net/mac80211/scan.c | 88 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 3 | ||||
-rw-r--r-- | net/mac80211/status.c | 4 | ||||
-rw-r--r-- | net/mac80211/tx.c | 12 | ||||
-rw-r--r-- | net/mac80211/work.c | 66 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 39 |
14 files changed, 458 insertions, 151 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 4bc8a9250cf..845c76d58d2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1215,6 +1215,9 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1215 | { | 1215 | { |
1216 | struct ieee80211_local *local = wiphy_priv(wiphy); | 1216 | struct ieee80211_local *local = wiphy_priv(wiphy); |
1217 | struct ieee80211_sub_if_data *sdata = NULL; | 1217 | struct ieee80211_sub_if_data *sdata = NULL; |
1218 | struct ieee80211_channel *old_oper; | ||
1219 | enum nl80211_channel_type old_oper_type; | ||
1220 | enum nl80211_channel_type old_vif_oper_type= NL80211_CHAN_NO_HT; | ||
1218 | 1221 | ||
1219 | if (netdev) | 1222 | if (netdev) |
1220 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); | 1223 | sdata = IEEE80211_DEV_TO_SUB_IF(netdev); |
@@ -1232,13 +1235,23 @@ static int ieee80211_set_channel(struct wiphy *wiphy, | |||
1232 | break; | 1235 | break; |
1233 | } | 1236 | } |
1234 | 1237 | ||
1235 | local->oper_channel = chan; | 1238 | if (sdata) |
1239 | old_vif_oper_type = sdata->vif.bss_conf.channel_type; | ||
1240 | old_oper_type = local->_oper_channel_type; | ||
1236 | 1241 | ||
1237 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) | 1242 | if (!ieee80211_set_channel_type(local, sdata, channel_type)) |
1238 | return -EBUSY; | 1243 | return -EBUSY; |
1239 | 1244 | ||
1240 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 1245 | old_oper = local->oper_channel; |
1241 | if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) | 1246 | local->oper_channel = chan; |
1247 | |||
1248 | /* Update driver if changes were actually made. */ | ||
1249 | if ((old_oper != local->oper_channel) || | ||
1250 | (old_oper_type != local->_oper_channel_type)) | ||
1251 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
1252 | |||
1253 | if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) && | ||
1254 | old_vif_oper_type != sdata->vif.bss_conf.channel_type) | ||
1242 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); | 1255 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); |
1243 | 1256 | ||
1244 | return 0; | 1257 | return 0; |
@@ -1274,8 +1287,11 @@ static int ieee80211_scan(struct wiphy *wiphy, | |||
1274 | case NL80211_IFTYPE_P2P_GO: | 1287 | case NL80211_IFTYPE_P2P_GO: |
1275 | if (sdata->local->ops->hw_scan) | 1288 | if (sdata->local->ops->hw_scan) |
1276 | break; | 1289 | break; |
1277 | /* FIXME: implement NoA while scanning in software */ | 1290 | /* |
1278 | return -EOPNOTSUPP; | 1291 | * FIXME: implement NoA while scanning in software, |
1292 | * for now fall through to allow scanning only when | ||
1293 | * beaconing hasn't been configured yet | ||
1294 | */ | ||
1279 | case NL80211_IFTYPE_AP: | 1295 | case NL80211_IFTYPE_AP: |
1280 | if (sdata->u.ap.beacon) | 1296 | if (sdata->u.ap.beacon) |
1281 | return -EOPNOTSUPP; | 1297 | return -EOPNOTSUPP; |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 872adb86200..dacace6b139 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c | |||
@@ -36,7 +36,7 @@ static ssize_t ieee80211_if_read( | |||
36 | ret = (*format)(sdata, buf, sizeof(buf)); | 36 | ret = (*format)(sdata, buf, sizeof(buf)); |
37 | read_unlock(&dev_base_lock); | 37 | read_unlock(&dev_base_lock); |
38 | 38 | ||
39 | if (ret != -EINVAL) | 39 | if (ret >= 0) |
40 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); | 40 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); |
41 | 41 | ||
42 | return ret; | 42 | return ret; |
@@ -149,6 +149,7 @@ IEEE80211_IF_FILE(rc_rateidx_mask_5ghz, rc_rateidx_mask[IEEE80211_BAND_5GHZ], | |||
149 | HEX); | 149 | HEX); |
150 | IEEE80211_IF_FILE(flags, flags, HEX); | 150 | IEEE80211_IF_FILE(flags, flags, HEX); |
151 | IEEE80211_IF_FILE(state, state, LHEX); | 151 | IEEE80211_IF_FILE(state, state, LHEX); |
152 | IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC); | ||
152 | 153 | ||
153 | /* STA attributes */ | 154 | /* STA attributes */ |
154 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | 155 | IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); |
@@ -220,6 +221,104 @@ static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata, | |||
220 | 221 | ||
221 | __IEEE80211_IF_FILE_W(smps); | 222 | __IEEE80211_IF_FILE_W(smps); |
222 | 223 | ||
224 | static ssize_t ieee80211_if_fmt_tkip_mic_test( | ||
225 | const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) | ||
226 | { | ||
227 | return -EOPNOTSUPP; | ||
228 | } | ||
229 | |||
230 | static int hwaddr_aton(const char *txt, u8 *addr) | ||
231 | { | ||
232 | int i; | ||
233 | |||
234 | for (i = 0; i < ETH_ALEN; i++) { | ||
235 | int a, b; | ||
236 | |||
237 | a = hex_to_bin(*txt++); | ||
238 | if (a < 0) | ||
239 | return -1; | ||
240 | b = hex_to_bin(*txt++); | ||
241 | if (b < 0) | ||
242 | return -1; | ||
243 | *addr++ = (a << 4) | b; | ||
244 | if (i < 5 && *txt++ != ':') | ||
245 | return -1; | ||
246 | } | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static ssize_t ieee80211_if_parse_tkip_mic_test( | ||
252 | struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) | ||
253 | { | ||
254 | struct ieee80211_local *local = sdata->local; | ||
255 | u8 addr[ETH_ALEN]; | ||
256 | struct sk_buff *skb; | ||
257 | struct ieee80211_hdr *hdr; | ||
258 | __le16 fc; | ||
259 | |||
260 | /* | ||
261 | * Assume colon-delimited MAC address with possible white space | ||
262 | * following. | ||
263 | */ | ||
264 | if (buflen < 3 * ETH_ALEN - 1) | ||
265 | return -EINVAL; | ||
266 | if (hwaddr_aton(buf, addr) < 0) | ||
267 | return -EINVAL; | ||
268 | |||
269 | if (!ieee80211_sdata_running(sdata)) | ||
270 | return -ENOTCONN; | ||
271 | |||
272 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100); | ||
273 | if (!skb) | ||
274 | return -ENOMEM; | ||
275 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
276 | |||
277 | hdr = (struct ieee80211_hdr *) skb_put(skb, 24); | ||
278 | memset(hdr, 0, 24); | ||
279 | fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); | ||
280 | |||
281 | switch (sdata->vif.type) { | ||
282 | case NL80211_IFTYPE_AP: | ||
283 | fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS); | ||
284 | /* DA BSSID SA */ | ||
285 | memcpy(hdr->addr1, addr, ETH_ALEN); | ||
286 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | ||
287 | memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN); | ||
288 | break; | ||
289 | case NL80211_IFTYPE_STATION: | ||
290 | fc |= cpu_to_le16(IEEE80211_FCTL_TODS); | ||
291 | /* BSSID SA DA */ | ||
292 | if (sdata->vif.bss_conf.bssid == NULL) { | ||
293 | dev_kfree_skb(skb); | ||
294 | return -ENOTCONN; | ||
295 | } | ||
296 | memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN); | ||
297 | memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN); | ||
298 | memcpy(hdr->addr3, addr, ETH_ALEN); | ||
299 | break; | ||
300 | default: | ||
301 | dev_kfree_skb(skb); | ||
302 | return -EOPNOTSUPP; | ||
303 | } | ||
304 | hdr->frame_control = fc; | ||
305 | |||
306 | /* | ||
307 | * Add some length to the test frame to make it look bit more valid. | ||
308 | * The exact contents does not matter since the recipient is required | ||
309 | * to drop this because of the Michael MIC failure. | ||
310 | */ | ||
311 | memset(skb_put(skb, 50), 0, 50); | ||
312 | |||
313 | IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE; | ||
314 | |||
315 | ieee80211_tx_skb(sdata, skb); | ||
316 | |||
317 | return buflen; | ||
318 | } | ||
319 | |||
320 | __IEEE80211_IF_FILE_W(tkip_mic_test); | ||
321 | |||
223 | /* AP attributes */ | 322 | /* AP attributes */ |
224 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); | 323 | IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); |
225 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); | 324 | IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); |
@@ -289,6 +388,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) | |||
289 | DEBUGFS_ADD(drop_unencrypted); | 388 | DEBUGFS_ADD(drop_unencrypted); |
290 | DEBUGFS_ADD(flags); | 389 | DEBUGFS_ADD(flags); |
291 | DEBUGFS_ADD(state); | 390 | DEBUGFS_ADD(state); |
391 | DEBUGFS_ADD(channel_type); | ||
292 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | 392 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
293 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 393 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
294 | 394 | ||
@@ -297,6 +397,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) | |||
297 | DEBUGFS_ADD(last_beacon); | 397 | DEBUGFS_ADD(last_beacon); |
298 | DEBUGFS_ADD(ave_beacon); | 398 | DEBUGFS_ADD(ave_beacon); |
299 | DEBUGFS_ADD_MODE(smps, 0600); | 399 | DEBUGFS_ADD_MODE(smps, 0600); |
400 | DEBUGFS_ADD_MODE(tkip_mic_test, 0200); | ||
300 | } | 401 | } |
301 | 402 | ||
302 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) | 403 | static void add_ap_files(struct ieee80211_sub_if_data *sdata) |
@@ -304,12 +405,14 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) | |||
304 | DEBUGFS_ADD(drop_unencrypted); | 405 | DEBUGFS_ADD(drop_unencrypted); |
305 | DEBUGFS_ADD(flags); | 406 | DEBUGFS_ADD(flags); |
306 | DEBUGFS_ADD(state); | 407 | DEBUGFS_ADD(state); |
408 | DEBUGFS_ADD(channel_type); | ||
307 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | 409 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
308 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 410 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
309 | 411 | ||
310 | DEBUGFS_ADD(num_sta_ps); | 412 | DEBUGFS_ADD(num_sta_ps); |
311 | DEBUGFS_ADD(dtim_count); | 413 | DEBUGFS_ADD(dtim_count); |
312 | DEBUGFS_ADD(num_buffered_multicast); | 414 | DEBUGFS_ADD(num_buffered_multicast); |
415 | DEBUGFS_ADD_MODE(tkip_mic_test, 0200); | ||
313 | } | 416 | } |
314 | 417 | ||
315 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) | 418 | static void add_wds_files(struct ieee80211_sub_if_data *sdata) |
@@ -317,6 +420,7 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) | |||
317 | DEBUGFS_ADD(drop_unencrypted); | 420 | DEBUGFS_ADD(drop_unencrypted); |
318 | DEBUGFS_ADD(flags); | 421 | DEBUGFS_ADD(flags); |
319 | DEBUGFS_ADD(state); | 422 | DEBUGFS_ADD(state); |
423 | DEBUGFS_ADD(channel_type); | ||
320 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | 424 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
321 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 425 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
322 | 426 | ||
@@ -328,6 +432,7 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) | |||
328 | DEBUGFS_ADD(drop_unencrypted); | 432 | DEBUGFS_ADD(drop_unencrypted); |
329 | DEBUGFS_ADD(flags); | 433 | DEBUGFS_ADD(flags); |
330 | DEBUGFS_ADD(state); | 434 | DEBUGFS_ADD(state); |
435 | DEBUGFS_ADD(channel_type); | ||
331 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); | 436 | DEBUGFS_ADD(rc_rateidx_mask_2ghz); |
332 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); | 437 | DEBUGFS_ADD(rc_rateidx_mask_5ghz); |
333 | } | 438 | } |
@@ -336,6 +441,7 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata) | |||
336 | { | 441 | { |
337 | DEBUGFS_ADD(flags); | 442 | DEBUGFS_ADD(flags); |
338 | DEBUGFS_ADD(state); | 443 | DEBUGFS_ADD(state); |
444 | DEBUGFS_ADD(channel_type); | ||
339 | } | 445 | } |
340 | 446 | ||
341 | #ifdef CONFIG_MAC80211_MESH | 447 | #ifdef CONFIG_MAC80211_MESH |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c47d7c0e48a..44eea1af155 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -225,6 +225,7 @@ struct ieee80211_if_ap { | |||
225 | struct sk_buff_head ps_bc_buf; | 225 | struct sk_buff_head ps_bc_buf; |
226 | atomic_t num_sta_ps; /* number of stations in PS mode */ | 226 | atomic_t num_sta_ps; /* number of stations in PS mode */ |
227 | int dtim_count; | 227 | int dtim_count; |
228 | bool dtim_bc_mc; | ||
228 | }; | 229 | }; |
229 | 230 | ||
230 | struct ieee80211_if_wds { | 231 | struct ieee80211_if_wds { |
@@ -654,8 +655,6 @@ struct tpt_led_trigger { | |||
654 | * well be on the operating channel | 655 | * well be on the operating channel |
655 | * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to | 656 | * @SCAN_HW_SCANNING: The hardware is scanning for us, we have no way to |
656 | * determine if we are on the operating channel or not | 657 | * determine if we are on the operating channel or not |
657 | * @SCAN_OFF_CHANNEL: We're off our operating channel for scanning, | ||
658 | * gets only set in conjunction with SCAN_SW_SCANNING | ||
659 | * @SCAN_COMPLETED: Set for our scan work function when the driver reported | 658 | * @SCAN_COMPLETED: Set for our scan work function when the driver reported |
660 | * that the scan completed. | 659 | * that the scan completed. |
661 | * @SCAN_ABORTED: Set for our scan work function when the driver reported | 660 | * @SCAN_ABORTED: Set for our scan work function when the driver reported |
@@ -664,7 +663,6 @@ struct tpt_led_trigger { | |||
664 | enum { | 663 | enum { |
665 | SCAN_SW_SCANNING, | 664 | SCAN_SW_SCANNING, |
666 | SCAN_HW_SCANNING, | 665 | SCAN_HW_SCANNING, |
667 | SCAN_OFF_CHANNEL, | ||
668 | SCAN_COMPLETED, | 666 | SCAN_COMPLETED, |
669 | SCAN_ABORTED, | 667 | SCAN_ABORTED, |
670 | }; | 668 | }; |
@@ -1147,10 +1145,14 @@ void ieee80211_rx_bss_put(struct ieee80211_local *local, | |||
1147 | struct ieee80211_bss *bss); | 1145 | struct ieee80211_bss *bss); |
1148 | 1146 | ||
1149 | /* off-channel helpers */ | 1147 | /* off-channel helpers */ |
1150 | void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local); | 1148 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local); |
1151 | void ieee80211_offchannel_stop_station(struct ieee80211_local *local); | 1149 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, |
1150 | bool tell_ap); | ||
1151 | void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, | ||
1152 | bool offchannel_ps_enable); | ||
1152 | void ieee80211_offchannel_return(struct ieee80211_local *local, | 1153 | void ieee80211_offchannel_return(struct ieee80211_local *local, |
1153 | bool enable_beaconing); | 1154 | bool enable_beaconing, |
1155 | bool offchannel_ps_disable); | ||
1154 | void ieee80211_hw_roc_setup(struct ieee80211_local *local); | 1156 | void ieee80211_hw_roc_setup(struct ieee80211_local *local); |
1155 | 1157 | ||
1156 | /* interface handling */ | 1158 | /* interface handling */ |
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8acba456744..5a4e19b8803 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -382,6 +382,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
382 | struct sk_buff *skb, *tmp; | 382 | struct sk_buff *skb, *tmp; |
383 | u32 hw_reconf_flags = 0; | 383 | u32 hw_reconf_flags = 0; |
384 | int i; | 384 | int i; |
385 | enum nl80211_channel_type orig_ct; | ||
385 | 386 | ||
386 | if (local->scan_sdata == sdata) | 387 | if (local->scan_sdata == sdata) |
387 | ieee80211_scan_cancel(local); | 388 | ieee80211_scan_cancel(local); |
@@ -542,8 +543,14 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, | |||
542 | hw_reconf_flags = 0; | 543 | hw_reconf_flags = 0; |
543 | } | 544 | } |
544 | 545 | ||
546 | /* Re-calculate channel-type, in case there are multiple vifs | ||
547 | * on different channel types. | ||
548 | */ | ||
549 | orig_ct = local->_oper_channel_type; | ||
550 | ieee80211_set_channel_type(local, NULL, NL80211_CHAN_NO_HT); | ||
551 | |||
545 | /* do after stop to avoid reconfiguring when we stop anyway */ | 552 | /* do after stop to avoid reconfiguring when we stop anyway */ |
546 | if (hw_reconf_flags) | 553 | if (hw_reconf_flags || (orig_ct != local->_oper_channel_type)) |
547 | ieee80211_hw_config(local, hw_reconf_flags); | 554 | ieee80211_hw_config(local, hw_reconf_flags); |
548 | 555 | ||
549 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); | 556 | spin_lock_irqsave(&local->queue_stop_reason_lock, flags); |
diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 09a27449f3f..c155c0b6942 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c | |||
@@ -98,6 +98,41 @@ static void ieee80211_reconfig_filter(struct work_struct *work) | |||
98 | ieee80211_configure_filter(local); | 98 | ieee80211_configure_filter(local); |
99 | } | 99 | } |
100 | 100 | ||
101 | /* | ||
102 | * Returns true if we are logically configured to be on | ||
103 | * the operating channel AND the hardware-conf is currently | ||
104 | * configured on the operating channel. Compares channel-type | ||
105 | * as well. | ||
106 | */ | ||
107 | bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local) | ||
108 | { | ||
109 | struct ieee80211_channel *chan, *scan_chan; | ||
110 | enum nl80211_channel_type channel_type; | ||
111 | |||
112 | /* This logic needs to match logic in ieee80211_hw_config */ | ||
113 | if (local->scan_channel) { | ||
114 | chan = local->scan_channel; | ||
115 | channel_type = NL80211_CHAN_NO_HT; | ||
116 | } else if (local->tmp_channel) { | ||
117 | chan = scan_chan = local->tmp_channel; | ||
118 | channel_type = local->tmp_channel_type; | ||
119 | } else { | ||
120 | chan = local->oper_channel; | ||
121 | channel_type = local->_oper_channel_type; | ||
122 | } | ||
123 | |||
124 | if (chan != local->oper_channel || | ||
125 | channel_type != local->_oper_channel_type) | ||
126 | return false; | ||
127 | |||
128 | /* Check current hardware-config against oper_channel. */ | ||
129 | if ((local->oper_channel != local->hw.conf.channel) || | ||
130 | (local->_oper_channel_type != local->hw.conf.channel_type)) | ||
131 | return false; | ||
132 | |||
133 | return true; | ||
134 | } | ||
135 | |||
101 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | 136 | int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) |
102 | { | 137 | { |
103 | struct ieee80211_channel *chan, *scan_chan; | 138 | struct ieee80211_channel *chan, *scan_chan; |
@@ -110,21 +145,27 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | |||
110 | 145 | ||
111 | scan_chan = local->scan_channel; | 146 | scan_chan = local->scan_channel; |
112 | 147 | ||
148 | /* If this off-channel logic ever changes, ieee80211_on_oper_channel | ||
149 | * may need to change as well. | ||
150 | */ | ||
113 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | 151 | offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; |
114 | if (scan_chan) { | 152 | if (scan_chan) { |
115 | chan = scan_chan; | 153 | chan = scan_chan; |
116 | channel_type = NL80211_CHAN_NO_HT; | 154 | channel_type = NL80211_CHAN_NO_HT; |
117 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | 155 | } else if (local->tmp_channel) { |
118 | } else if (local->tmp_channel && | ||
119 | local->oper_channel != local->tmp_channel) { | ||
120 | chan = scan_chan = local->tmp_channel; | 156 | chan = scan_chan = local->tmp_channel; |
121 | channel_type = local->tmp_channel_type; | 157 | channel_type = local->tmp_channel_type; |
122 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | ||
123 | } else { | 158 | } else { |
124 | chan = local->oper_channel; | 159 | chan = local->oper_channel; |
125 | channel_type = local->_oper_channel_type; | 160 | channel_type = local->_oper_channel_type; |
126 | local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; | ||
127 | } | 161 | } |
162 | |||
163 | if (chan != local->oper_channel || | ||
164 | channel_type != local->_oper_channel_type) | ||
165 | local->hw.conf.flags |= IEEE80211_CONF_OFFCHANNEL; | ||
166 | else | ||
167 | local->hw.conf.flags &= ~IEEE80211_CONF_OFFCHANNEL; | ||
168 | |||
128 | offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; | 169 | offchannel_flag ^= local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; |
129 | 170 | ||
130 | if (offchannel_flag || chan != local->hw.conf.channel || | 171 | if (offchannel_flag || chan != local->hw.conf.channel || |
@@ -231,7 +272,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | |||
231 | 272 | ||
232 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | 273 | if (changed & BSS_CHANGED_BEACON_ENABLED) { |
233 | if (local->quiescing || !ieee80211_sdata_running(sdata) || | 274 | if (local->quiescing || !ieee80211_sdata_running(sdata) || |
234 | test_bit(SCAN_SW_SCANNING, &local->scanning)) { | 275 | test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) { |
235 | sdata->vif.bss_conf.enable_beacon = false; | 276 | sdata->vif.bss_conf.enable_beacon = false; |
236 | } else { | 277 | } else { |
237 | /* | 278 | /* |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index dfa752e5520..f77adf1a520 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -28,8 +28,15 @@ | |||
28 | #include "rate.h" | 28 | #include "rate.h" |
29 | #include "led.h" | 29 | #include "led.h" |
30 | 30 | ||
31 | #define IEEE80211_MAX_NULLFUNC_TRIES 2 | 31 | static int max_nullfunc_tries = 2; |
32 | #define IEEE80211_MAX_PROBE_TRIES 5 | 32 | module_param(max_nullfunc_tries, int, 0644); |
33 | MODULE_PARM_DESC(max_nullfunc_tries, | ||
34 | "Maximum nullfunc tx tries before disconnecting (reason 4)."); | ||
35 | |||
36 | static int max_probe_tries = 5; | ||
37 | module_param(max_probe_tries, int, 0644); | ||
38 | MODULE_PARM_DESC(max_probe_tries, | ||
39 | "Maximum probe tries before disconnecting (reason 4)."); | ||
33 | 40 | ||
34 | /* | 41 | /* |
35 | * Beacon loss timeout is calculated as N frames times the | 42 | * Beacon loss timeout is calculated as N frames times the |
@@ -51,7 +58,11 @@ | |||
51 | * a probe request because of beacon loss or for | 58 | * a probe request because of beacon loss or for |
52 | * checking the connection still works. | 59 | * checking the connection still works. |
53 | */ | 60 | */ |
54 | #define IEEE80211_PROBE_WAIT (HZ / 2) | 61 | static int probe_wait_ms = 500; |
62 | module_param(probe_wait_ms, int, 0644); | ||
63 | MODULE_PARM_DESC(probe_wait_ms, | ||
64 | "Maximum time(ms) to wait for probe response" | ||
65 | " before disconnecting (reason 4)."); | ||
55 | 66 | ||
56 | /* | 67 | /* |
57 | * Weight given to the latest Beacon frame when calculating average signal | 68 | * Weight given to the latest Beacon frame when calculating average signal |
@@ -161,6 +172,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
161 | struct ieee80211_supported_band *sband; | 172 | struct ieee80211_supported_band *sband; |
162 | struct sta_info *sta; | 173 | struct sta_info *sta; |
163 | u32 changed = 0; | 174 | u32 changed = 0; |
175 | int hti_cfreq; | ||
164 | u16 ht_opmode; | 176 | u16 ht_opmode; |
165 | bool enable_ht = true; | 177 | bool enable_ht = true; |
166 | enum nl80211_channel_type prev_chantype; | 178 | enum nl80211_channel_type prev_chantype; |
@@ -174,10 +186,27 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
174 | if (!sband->ht_cap.ht_supported) | 186 | if (!sband->ht_cap.ht_supported) |
175 | enable_ht = false; | 187 | enable_ht = false; |
176 | 188 | ||
177 | /* check that channel matches the right operating channel */ | 189 | if (enable_ht) { |
178 | if (local->hw.conf.channel->center_freq != | 190 | hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan, |
179 | ieee80211_channel_to_frequency(hti->control_chan, sband->band)) | 191 | sband->band); |
180 | enable_ht = false; | 192 | /* check that channel matches the right operating channel */ |
193 | if (local->hw.conf.channel->center_freq != hti_cfreq) { | ||
194 | /* Some APs mess this up, evidently. | ||
195 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
196 | * the actual channel, for instance. | ||
197 | */ | ||
198 | printk(KERN_DEBUG | ||
199 | "%s: Wrong control channel in association" | ||
200 | " response: configured center-freq: %d" | ||
201 | " hti-cfreq: %d hti->control_chan: %d" | ||
202 | " band: %d. Disabling HT.\n", | ||
203 | sdata->name, | ||
204 | local->hw.conf.channel->center_freq, | ||
205 | hti_cfreq, hti->control_chan, | ||
206 | sband->band); | ||
207 | enable_ht = false; | ||
208 | } | ||
209 | } | ||
181 | 210 | ||
182 | if (enable_ht) { | 211 | if (enable_ht) { |
183 | channel_type = NL80211_CHAN_HT20; | 212 | channel_type = NL80211_CHAN_HT20; |
@@ -1098,7 +1127,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1098 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1127 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1099 | const u8 *ssid; | 1128 | const u8 *ssid; |
1100 | u8 *dst = ifmgd->associated->bssid; | 1129 | u8 *dst = ifmgd->associated->bssid; |
1101 | u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3); | 1130 | u8 unicast_limit = max(1, max_probe_tries - 3); |
1102 | 1131 | ||
1103 | /* | 1132 | /* |
1104 | * Try sending broadcast probe requests for the last three | 1133 | * Try sending broadcast probe requests for the last three |
@@ -1124,7 +1153,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1124 | } | 1153 | } |
1125 | 1154 | ||
1126 | ifmgd->probe_send_count++; | 1155 | ifmgd->probe_send_count++; |
1127 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | 1156 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
1128 | run_again(ifmgd, ifmgd->probe_timeout); | 1157 | run_again(ifmgd, ifmgd->probe_timeout); |
1129 | } | 1158 | } |
1130 | 1159 | ||
@@ -1225,7 +1254,8 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1225 | 1254 | ||
1226 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 1255 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1227 | 1256 | ||
1228 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | 1257 | printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n", |
1258 | sdata->name, bssid); | ||
1229 | 1259 | ||
1230 | ieee80211_set_disassoc(sdata, true, true); | 1260 | ieee80211_set_disassoc(sdata, true, true); |
1231 | mutex_unlock(&ifmgd->mtx); | 1261 | mutex_unlock(&ifmgd->mtx); |
@@ -1970,9 +2000,9 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1970 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 2000 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1971 | 2001 | ||
1972 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 2002 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
1973 | max_tries = IEEE80211_MAX_NULLFUNC_TRIES; | 2003 | max_tries = max_nullfunc_tries; |
1974 | else | 2004 | else |
1975 | max_tries = IEEE80211_MAX_PROBE_TRIES; | 2005 | max_tries = max_probe_tries; |
1976 | 2006 | ||
1977 | /* ACK received for nullfunc probing frame */ | 2007 | /* ACK received for nullfunc probing frame */ |
1978 | if (!ifmgd->probe_send_count) | 2008 | if (!ifmgd->probe_send_count) |
@@ -2004,7 +2034,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2004 | "%s: Failed to send nullfunc to AP %pM" | 2034 | "%s: Failed to send nullfunc to AP %pM" |
2005 | " after %dms, disconnecting.\n", | 2035 | " after %dms, disconnecting.\n", |
2006 | sdata->name, | 2036 | sdata->name, |
2007 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2037 | bssid, probe_wait_ms); |
2008 | #endif | 2038 | #endif |
2009 | ieee80211_sta_connection_lost(sdata, bssid); | 2039 | ieee80211_sta_connection_lost(sdata, bssid); |
2010 | } else if (ifmgd->probe_send_count < max_tries) { | 2040 | } else if (ifmgd->probe_send_count < max_tries) { |
@@ -2013,7 +2043,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2013 | "%s: No probe response from AP %pM" | 2043 | "%s: No probe response from AP %pM" |
2014 | " after %dms, try %d/%i\n", | 2044 | " after %dms, try %d/%i\n", |
2015 | sdata->name, | 2045 | sdata->name, |
2016 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ, | 2046 | bssid, probe_wait_ms, |
2017 | ifmgd->probe_send_count, max_tries); | 2047 | ifmgd->probe_send_count, max_tries); |
2018 | #endif | 2048 | #endif |
2019 | ieee80211_mgd_probe_ap_send(sdata); | 2049 | ieee80211_mgd_probe_ap_send(sdata); |
@@ -2026,7 +2056,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2026 | "%s: No probe response from AP %pM" | 2056 | "%s: No probe response from AP %pM" |
2027 | " after %dms, disconnecting.\n", | 2057 | " after %dms, disconnecting.\n", |
2028 | sdata->name, | 2058 | sdata->name, |
2029 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2059 | bssid, probe_wait_ms); |
2030 | 2060 | ||
2031 | ieee80211_sta_connection_lost(sdata, bssid); | 2061 | ieee80211_sta_connection_lost(sdata, bssid); |
2032 | } | 2062 | } |
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index b4e52676f3f..13427b194ce 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c | |||
@@ -17,10 +17,14 @@ | |||
17 | #include "driver-trace.h" | 17 | #include "driver-trace.h" |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * inform AP that we will go to sleep so that it will buffer the frames | 20 | * Tell our hardware to disable PS. |
21 | * while we scan | 21 | * Optionally inform AP that we will go to sleep so that it will buffer |
22 | * the frames while we are doing off-channel work. This is optional | ||
23 | * because we *may* be doing work on-operating channel, and want our | ||
24 | * hardware unconditionally awake, but still let the AP send us normal frames. | ||
22 | */ | 25 | */ |
23 | static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) | 26 | static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata, |
27 | bool tell_ap) | ||
24 | { | 28 | { |
25 | struct ieee80211_local *local = sdata->local; | 29 | struct ieee80211_local *local = sdata->local; |
26 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 30 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -41,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) | |||
41 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 45 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
42 | } | 46 | } |
43 | 47 | ||
44 | if (!(local->offchannel_ps_enabled) || | 48 | if (tell_ap && (!local->offchannel_ps_enabled || |
45 | !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) | 49 | !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))) |
46 | /* | 50 | /* |
47 | * If power save was enabled, no need to send a nullfunc | 51 | * If power save was enabled, no need to send a nullfunc |
48 | * frame because AP knows that we are sleeping. But if the | 52 | * frame because AP knows that we are sleeping. But if the |
@@ -77,6 +81,9 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) | |||
77 | * we are sleeping, let's just enable power save mode in | 81 | * we are sleeping, let's just enable power save mode in |
78 | * hardware. | 82 | * hardware. |
79 | */ | 83 | */ |
84 | /* TODO: Only set hardware if CONF_PS changed? | ||
85 | * TODO: Should we set offchannel_ps_enabled to false? | ||
86 | */ | ||
80 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 87 | local->hw.conf.flags |= IEEE80211_CONF_PS; |
81 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 88 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
82 | } else if (local->hw.conf.dynamic_ps_timeout > 0) { | 89 | } else if (local->hw.conf.dynamic_ps_timeout > 0) { |
@@ -95,63 +102,61 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) | |||
95 | ieee80211_sta_reset_conn_monitor(sdata); | 102 | ieee80211_sta_reset_conn_monitor(sdata); |
96 | } | 103 | } |
97 | 104 | ||
98 | void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) | 105 | void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, |
106 | bool offchannel_ps_enable) | ||
99 | { | 107 | { |
100 | struct ieee80211_sub_if_data *sdata; | 108 | struct ieee80211_sub_if_data *sdata; |
101 | 109 | ||
110 | /* | ||
111 | * notify the AP about us leaving the channel and stop all | ||
112 | * STA interfaces. | ||
113 | */ | ||
102 | mutex_lock(&local->iflist_mtx); | 114 | mutex_lock(&local->iflist_mtx); |
103 | list_for_each_entry(sdata, &local->interfaces, list) { | 115 | list_for_each_entry(sdata, &local->interfaces, list) { |
104 | if (!ieee80211_sdata_running(sdata)) | 116 | if (!ieee80211_sdata_running(sdata)) |
105 | continue; | 117 | continue; |
106 | 118 | ||
107 | /* disable beaconing */ | 119 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) |
120 | set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
121 | |||
122 | /* Check to see if we should disable beaconing. */ | ||
108 | if (sdata->vif.type == NL80211_IFTYPE_AP || | 123 | if (sdata->vif.type == NL80211_IFTYPE_AP || |
109 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | 124 | sdata->vif.type == NL80211_IFTYPE_ADHOC || |
110 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | 125 | sdata->vif.type == NL80211_IFTYPE_MESH_POINT) |
111 | ieee80211_bss_info_change_notify( | 126 | ieee80211_bss_info_change_notify( |
112 | sdata, BSS_CHANGED_BEACON_ENABLED); | 127 | sdata, BSS_CHANGED_BEACON_ENABLED); |
113 | 128 | ||
114 | /* | 129 | if (sdata->vif.type != NL80211_IFTYPE_MONITOR) { |
115 | * only handle non-STA interfaces here, STA interfaces | ||
116 | * are handled in ieee80211_offchannel_stop_station(), | ||
117 | * e.g., from the background scan state machine. | ||
118 | * | ||
119 | * In addition, do not stop monitor interface to allow it to be | ||
120 | * used from user space controlled off-channel operations. | ||
121 | */ | ||
122 | if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||
123 | sdata->vif.type != NL80211_IFTYPE_MONITOR) { | ||
124 | set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | ||
125 | netif_tx_stop_all_queues(sdata->dev); | 130 | netif_tx_stop_all_queues(sdata->dev); |
131 | if (offchannel_ps_enable && | ||
132 | (sdata->vif.type == NL80211_IFTYPE_STATION) && | ||
133 | sdata->u.mgd.associated) | ||
134 | ieee80211_offchannel_ps_enable(sdata, true); | ||
126 | } | 135 | } |
127 | } | 136 | } |
128 | mutex_unlock(&local->iflist_mtx); | 137 | mutex_unlock(&local->iflist_mtx); |
129 | } | 138 | } |
130 | 139 | ||
131 | void ieee80211_offchannel_stop_station(struct ieee80211_local *local) | 140 | void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local, |
141 | bool tell_ap) | ||
132 | { | 142 | { |
133 | struct ieee80211_sub_if_data *sdata; | 143 | struct ieee80211_sub_if_data *sdata; |
134 | 144 | ||
135 | /* | ||
136 | * notify the AP about us leaving the channel and stop all STA interfaces | ||
137 | */ | ||
138 | mutex_lock(&local->iflist_mtx); | 145 | mutex_lock(&local->iflist_mtx); |
139 | list_for_each_entry(sdata, &local->interfaces, list) { | 146 | list_for_each_entry(sdata, &local->interfaces, list) { |
140 | if (!ieee80211_sdata_running(sdata)) | 147 | if (!ieee80211_sdata_running(sdata)) |
141 | continue; | 148 | continue; |
142 | 149 | ||
143 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 150 | if (sdata->vif.type == NL80211_IFTYPE_STATION && |
144 | set_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | 151 | sdata->u.mgd.associated) |
145 | netif_tx_stop_all_queues(sdata->dev); | 152 | ieee80211_offchannel_ps_enable(sdata, tell_ap); |
146 | if (sdata->u.mgd.associated) | ||
147 | ieee80211_offchannel_ps_enable(sdata); | ||
148 | } | ||
149 | } | 153 | } |
150 | mutex_unlock(&local->iflist_mtx); | 154 | mutex_unlock(&local->iflist_mtx); |
151 | } | 155 | } |
152 | 156 | ||
153 | void ieee80211_offchannel_return(struct ieee80211_local *local, | 157 | void ieee80211_offchannel_return(struct ieee80211_local *local, |
154 | bool enable_beaconing) | 158 | bool enable_beaconing, |
159 | bool offchannel_ps_disable) | ||
155 | { | 160 | { |
156 | struct ieee80211_sub_if_data *sdata; | 161 | struct ieee80211_sub_if_data *sdata; |
157 | 162 | ||
@@ -161,7 +166,8 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
161 | continue; | 166 | continue; |
162 | 167 | ||
163 | /* Tell AP we're back */ | 168 | /* Tell AP we're back */ |
164 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | 169 | if (offchannel_ps_disable && |
170 | sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
165 | if (sdata->u.mgd.associated) | 171 | if (sdata->u.mgd.associated) |
166 | ieee80211_offchannel_ps_disable(sdata); | 172 | ieee80211_offchannel_ps_disable(sdata); |
167 | } | 173 | } |
@@ -181,7 +187,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local, | |||
181 | netif_tx_wake_all_queues(sdata->dev); | 187 | netif_tx_wake_all_queues(sdata->dev); |
182 | } | 188 | } |
183 | 189 | ||
184 | /* re-enable beaconing */ | 190 | /* Check to see if we should re-enable beaconing */ |
185 | if (enable_beaconing && | 191 | if (enable_beaconing && |
186 | (sdata->vif.type == NL80211_IFTYPE_AP || | 192 | (sdata->vif.type == NL80211_IFTYPE_AP || |
187 | sdata->vif.type == NL80211_IFTYPE_ADHOC || | 193 | sdata->vif.type == NL80211_IFTYPE_ADHOC || |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7185c9316be..045b2fe4a41 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -142,11 +142,8 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, | |||
142 | /* IEEE80211_RADIOTAP_RATE */ | 142 | /* IEEE80211_RADIOTAP_RATE */ |
143 | if (status->flag & RX_FLAG_HT) { | 143 | if (status->flag & RX_FLAG_HT) { |
144 | /* | 144 | /* |
145 | * TODO: add following information into radiotap header once | 145 | * MCS information is a separate field in radiotap, |
146 | * suitable fields are defined for it: | 146 | * added below. |
147 | * - MCS index (status->rate_idx) | ||
148 | * - HT40 (status->flag & RX_FLAG_40MHZ) | ||
149 | * - short-GI (status->flag & RX_FLAG_SHORT_GI) | ||
150 | */ | 147 | */ |
151 | *pos = 0; | 148 | *pos = 0; |
152 | } else { | 149 | } else { |
@@ -409,16 +406,10 @@ ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) | |||
409 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) | 406 | if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN))) |
410 | return RX_CONTINUE; | 407 | return RX_CONTINUE; |
411 | 408 | ||
412 | if (test_bit(SCAN_HW_SCANNING, &local->scanning)) | 409 | if (test_bit(SCAN_HW_SCANNING, &local->scanning) || |
410 | test_bit(SCAN_SW_SCANNING, &local->scanning)) | ||
413 | return ieee80211_scan_rx(rx->sdata, skb); | 411 | return ieee80211_scan_rx(rx->sdata, skb); |
414 | 412 | ||
415 | if (test_bit(SCAN_SW_SCANNING, &local->scanning)) { | ||
416 | /* drop all the other packets during a software scan anyway */ | ||
417 | if (ieee80211_scan_rx(rx->sdata, skb) != RX_QUEUED) | ||
418 | dev_kfree_skb(skb); | ||
419 | return RX_QUEUED; | ||
420 | } | ||
421 | |||
422 | /* scanning finished during invoking of handlers */ | 413 | /* scanning finished during invoking of handlers */ |
423 | I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); | 414 | I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); |
424 | return RX_DROP_UNUSABLE; | 415 | return RX_DROP_UNUSABLE; |
@@ -815,7 +806,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) | |||
815 | rx->local->dot11FrameDuplicateCount++; | 806 | rx->local->dot11FrameDuplicateCount++; |
816 | rx->sta->num_duplicates++; | 807 | rx->sta->num_duplicates++; |
817 | } | 808 | } |
818 | return RX_DROP_MONITOR; | 809 | return RX_DROP_UNUSABLE; |
819 | } else | 810 | } else |
820 | rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl; | 811 | rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl; |
821 | } | 812 | } |
@@ -1105,7 +1096,8 @@ static void ap_sta_ps_start(struct sta_info *sta) | |||
1105 | 1096 | ||
1106 | atomic_inc(&sdata->bss->num_sta_ps); | 1097 | atomic_inc(&sdata->bss->num_sta_ps); |
1107 | set_sta_flags(sta, WLAN_STA_PS_STA); | 1098 | set_sta_flags(sta, WLAN_STA_PS_STA); |
1108 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | 1099 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
1100 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | ||
1109 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1101 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
1110 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", | 1102 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", |
1111 | sdata->name, sta->sta.addr, sta->sta.aid); | 1103 | sdata->name, sta->sta.addr, sta->sta.aid); |
@@ -1134,6 +1126,27 @@ static void ap_sta_ps_end(struct sta_info *sta) | |||
1134 | ieee80211_sta_ps_deliver_wakeup(sta); | 1126 | ieee80211_sta_ps_deliver_wakeup(sta); |
1135 | } | 1127 | } |
1136 | 1128 | ||
1129 | int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) | ||
1130 | { | ||
1131 | struct sta_info *sta_inf = container_of(sta, struct sta_info, sta); | ||
1132 | bool in_ps; | ||
1133 | |||
1134 | WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS)); | ||
1135 | |||
1136 | /* Don't let the same PS state be set twice */ | ||
1137 | in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA); | ||
1138 | if ((start && in_ps) || (!start && !in_ps)) | ||
1139 | return -EINVAL; | ||
1140 | |||
1141 | if (start) | ||
1142 | ap_sta_ps_start(sta_inf); | ||
1143 | else | ||
1144 | ap_sta_ps_end(sta_inf); | ||
1145 | |||
1146 | return 0; | ||
1147 | } | ||
1148 | EXPORT_SYMBOL(ieee80211_sta_ps_transition); | ||
1149 | |||
1137 | static ieee80211_rx_result debug_noinline | 1150 | static ieee80211_rx_result debug_noinline |
1138 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | 1151 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) |
1139 | { | 1152 | { |
@@ -1178,7 +1191,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1178 | * Change STA power saving mode only at the end of a frame | 1191 | * Change STA power saving mode only at the end of a frame |
1179 | * exchange sequence. | 1192 | * exchange sequence. |
1180 | */ | 1193 | */ |
1181 | if (!ieee80211_has_morefrags(hdr->frame_control) && | 1194 | if (!(sta->local->hw.flags & IEEE80211_HW_AP_LINK_PS) && |
1195 | !ieee80211_has_morefrags(hdr->frame_control) && | ||
1182 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | 1196 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && |
1183 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | 1197 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || |
1184 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { | 1198 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { |
@@ -1929,7 +1943,10 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) | |||
1929 | dev->stats.rx_bytes += rx->skb->len; | 1943 | dev->stats.rx_bytes += rx->skb->len; |
1930 | 1944 | ||
1931 | if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 && | 1945 | if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 && |
1932 | !is_multicast_ether_addr(((struct ethhdr *)rx->skb->data)->h_dest)) { | 1946 | !is_multicast_ether_addr( |
1947 | ((struct ethhdr *)rx->skb->data)->h_dest) && | ||
1948 | (!local->scanning && | ||
1949 | !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) { | ||
1933 | mod_timer(&local->dynamic_ps_timer, jiffies + | 1950 | mod_timer(&local->dynamic_ps_timer, jiffies + |
1934 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | 1951 | msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); |
1935 | } | 1952 | } |
@@ -2626,7 +2643,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
2626 | return 0; | 2643 | return 0; |
2627 | if (!multicast && | 2644 | if (!multicast && |
2628 | compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { | 2645 | compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) { |
2629 | if (!(sdata->dev->flags & IFF_PROMISC)) | 2646 | if (!(sdata->dev->flags & IFF_PROMISC) || |
2647 | sdata->u.mgd.use_4addr) | ||
2630 | return 0; | 2648 | return 0; |
2631 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 2649 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2632 | } | 2650 | } |
@@ -2675,7 +2693,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, | |||
2675 | return 0; | 2693 | return 0; |
2676 | } else if (!ieee80211_bssid_match(bssid, | 2694 | } else if (!ieee80211_bssid_match(bssid, |
2677 | sdata->vif.addr)) { | 2695 | sdata->vif.addr)) { |
2678 | if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) | 2696 | if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && |
2697 | !ieee80211_is_beacon(hdr->frame_control)) | ||
2679 | return 0; | 2698 | return 0; |
2680 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; | 2699 | status->rx_flags &= ~IEEE80211_RX_RA_MATCH; |
2681 | } | 2700 | } |
@@ -2766,7 +2785,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2766 | local->dot11ReceivedFragmentCount++; | 2785 | local->dot11ReceivedFragmentCount++; |
2767 | 2786 | ||
2768 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || | 2787 | if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || |
2769 | test_bit(SCAN_OFF_CHANNEL, &local->scanning))) | 2788 | test_bit(SCAN_SW_SCANNING, &local->scanning))) |
2770 | status->rx_flags |= IEEE80211_RX_IN_SCAN; | 2789 | status->rx_flags |= IEEE80211_RX_IN_SCAN; |
2771 | 2790 | ||
2772 | if (ieee80211_is_mgmt(fc)) | 2791 | if (ieee80211_is_mgmt(fc)) |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1ef73be76b2..0ea6adae3e0 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -212,6 +212,14 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) | |||
212 | if (bss) | 212 | if (bss) |
213 | ieee80211_rx_bss_put(sdata->local, bss); | 213 | ieee80211_rx_bss_put(sdata->local, bss); |
214 | 214 | ||
215 | /* If we are on-operating-channel, and this packet is for the | ||
216 | * current channel, pass the pkt on up the stack so that | ||
217 | * the rest of the stack can make use of it. | ||
218 | */ | ||
219 | if (ieee80211_cfg_on_oper_channel(sdata->local) | ||
220 | && (channel == sdata->local->oper_channel)) | ||
221 | return RX_CONTINUE; | ||
222 | |||
215 | dev_kfree_skb(skb); | 223 | dev_kfree_skb(skb); |
216 | return RX_QUEUED; | 224 | return RX_QUEUED; |
217 | } | 225 | } |
@@ -293,15 +301,31 @@ static void __ieee80211_scan_completed_finish(struct ieee80211_hw *hw, | |||
293 | bool was_hw_scan) | 301 | bool was_hw_scan) |
294 | { | 302 | { |
295 | struct ieee80211_local *local = hw_to_local(hw); | 303 | struct ieee80211_local *local = hw_to_local(hw); |
304 | bool on_oper_chan; | ||
305 | bool enable_beacons = false; | ||
306 | |||
307 | mutex_lock(&local->mtx); | ||
308 | on_oper_chan = ieee80211_cfg_on_oper_channel(local); | ||
309 | |||
310 | if (was_hw_scan || !on_oper_chan) { | ||
311 | if (WARN_ON(local->scan_channel)) | ||
312 | local->scan_channel = NULL; | ||
313 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
314 | } | ||
296 | 315 | ||
297 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
298 | if (!was_hw_scan) { | 316 | if (!was_hw_scan) { |
317 | bool on_oper_chan2; | ||
299 | ieee80211_configure_filter(local); | 318 | ieee80211_configure_filter(local); |
300 | drv_sw_scan_complete(local); | 319 | drv_sw_scan_complete(local); |
301 | ieee80211_offchannel_return(local, true); | 320 | on_oper_chan2 = ieee80211_cfg_on_oper_channel(local); |
321 | /* We should always be on-channel at this point. */ | ||
322 | WARN_ON(!on_oper_chan2); | ||
323 | if (on_oper_chan2 && (on_oper_chan != on_oper_chan2)) | ||
324 | enable_beacons = true; | ||
325 | |||
326 | ieee80211_offchannel_return(local, enable_beacons, true); | ||
302 | } | 327 | } |
303 | 328 | ||
304 | mutex_lock(&local->mtx); | ||
305 | ieee80211_recalc_idle(local); | 329 | ieee80211_recalc_idle(local); |
306 | mutex_unlock(&local->mtx); | 330 | mutex_unlock(&local->mtx); |
307 | 331 | ||
@@ -341,13 +365,15 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
341 | */ | 365 | */ |
342 | drv_sw_scan_start(local); | 366 | drv_sw_scan_start(local); |
343 | 367 | ||
344 | ieee80211_offchannel_stop_beaconing(local); | ||
345 | |||
346 | local->leave_oper_channel_time = 0; | 368 | local->leave_oper_channel_time = 0; |
347 | local->next_scan_state = SCAN_DECISION; | 369 | local->next_scan_state = SCAN_DECISION; |
348 | local->scan_channel_idx = 0; | 370 | local->scan_channel_idx = 0; |
349 | 371 | ||
350 | drv_flush(local, false); | 372 | /* We always want to use off-channel PS, even if we |
373 | * are not really leaving oper-channel. Don't | ||
374 | * tell the AP though, as long as we are on-channel. | ||
375 | */ | ||
376 | ieee80211_offchannel_enable_all_ps(local, false); | ||
351 | 377 | ||
352 | ieee80211_configure_filter(local); | 378 | ieee80211_configure_filter(local); |
353 | 379 | ||
@@ -487,7 +513,21 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
487 | } | 513 | } |
488 | mutex_unlock(&local->iflist_mtx); | 514 | mutex_unlock(&local->iflist_mtx); |
489 | 515 | ||
490 | if (local->scan_channel) { | 516 | next_chan = local->scan_req->channels[local->scan_channel_idx]; |
517 | |||
518 | if (ieee80211_cfg_on_oper_channel(local)) { | ||
519 | /* We're currently on operating channel. */ | ||
520 | if ((next_chan == local->oper_channel) && | ||
521 | (local->_oper_channel_type == NL80211_CHAN_NO_HT)) | ||
522 | /* We don't need to move off of operating channel. */ | ||
523 | local->next_scan_state = SCAN_SET_CHANNEL; | ||
524 | else | ||
525 | /* | ||
526 | * We do need to leave operating channel, as next | ||
527 | * scan is somewhere else. | ||
528 | */ | ||
529 | local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL; | ||
530 | } else { | ||
491 | /* | 531 | /* |
492 | * we're currently scanning a different channel, let's | 532 | * we're currently scanning a different channel, let's |
493 | * see if we can scan another channel without interfering | 533 | * see if we can scan another channel without interfering |
@@ -503,7 +543,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
503 | * | 543 | * |
504 | * Otherwise switch back to the operating channel. | 544 | * Otherwise switch back to the operating channel. |
505 | */ | 545 | */ |
506 | next_chan = local->scan_req->channels[local->scan_channel_idx]; | ||
507 | 546 | ||
508 | bad_latency = time_after(jiffies + | 547 | bad_latency = time_after(jiffies + |
509 | ieee80211_scan_get_channel_time(next_chan), | 548 | ieee80211_scan_get_channel_time(next_chan), |
@@ -521,12 +560,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
521 | local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; | 560 | local->next_scan_state = SCAN_ENTER_OPER_CHANNEL; |
522 | else | 561 | else |
523 | local->next_scan_state = SCAN_SET_CHANNEL; | 562 | local->next_scan_state = SCAN_SET_CHANNEL; |
524 | } else { | ||
525 | /* | ||
526 | * we're on the operating channel currently, let's | ||
527 | * leave that channel now to scan another one | ||
528 | */ | ||
529 | local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL; | ||
530 | } | 563 | } |
531 | 564 | ||
532 | *next_delay = 0; | 565 | *next_delay = 0; |
@@ -535,9 +568,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
535 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, | 568 | static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, |
536 | unsigned long *next_delay) | 569 | unsigned long *next_delay) |
537 | { | 570 | { |
538 | ieee80211_offchannel_stop_station(local); | 571 | /* PS will already be in off-channel mode, |
539 | 572 | * we do that once at the beginning of scanning. | |
540 | __set_bit(SCAN_OFF_CHANNEL, &local->scanning); | 573 | */ |
574 | ieee80211_offchannel_stop_vifs(local, false); | ||
541 | 575 | ||
542 | /* | 576 | /* |
543 | * What if the nullfunc frames didn't arrive? | 577 | * What if the nullfunc frames didn't arrive? |
@@ -560,15 +594,15 @@ static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *loca | |||
560 | { | 594 | { |
561 | /* switch back to the operating channel */ | 595 | /* switch back to the operating channel */ |
562 | local->scan_channel = NULL; | 596 | local->scan_channel = NULL; |
563 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 597 | if (!ieee80211_cfg_on_oper_channel(local)) |
598 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||
564 | 599 | ||
565 | /* | 600 | /* |
566 | * Only re-enable station mode interface now; beaconing will be | 601 | * Re-enable vifs and beaconing. Leave PS |
567 | * re-enabled once the full scan has been completed. | 602 | * in off-channel state..will put that back |
603 | * on-channel at the end of scanning. | ||
568 | */ | 604 | */ |
569 | ieee80211_offchannel_return(local, false); | 605 | ieee80211_offchannel_return(local, true, false); |
570 | |||
571 | __clear_bit(SCAN_OFF_CHANNEL, &local->scanning); | ||
572 | 606 | ||
573 | *next_delay = HZ / 5; | 607 | *next_delay = HZ / 5; |
574 | local->next_scan_state = SCAN_DECISION; | 608 | local->next_scan_state = SCAN_DECISION; |
@@ -584,8 +618,12 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local, | |||
584 | chan = local->scan_req->channels[local->scan_channel_idx]; | 618 | chan = local->scan_req->channels[local->scan_channel_idx]; |
585 | 619 | ||
586 | local->scan_channel = chan; | 620 | local->scan_channel = chan; |
587 | if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) | 621 | |
588 | skip = 1; | 622 | /* Only call hw-config if we really need to change channels. */ |
623 | if ((chan != local->hw.conf.channel) || | ||
624 | (local->hw.conf.channel_type != NL80211_CHAN_NO_HT)) | ||
625 | if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL)) | ||
626 | skip = 1; | ||
589 | 627 | ||
590 | /* advance state machine to next channel/band */ | 628 | /* advance state machine to next channel/band */ |
591 | local->scan_channel_idx++; | 629 | local->scan_channel_idx++; |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c426504ed1c..5a11078827a 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -899,7 +899,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
899 | struct ieee80211_local *local = sdata->local; | 899 | struct ieee80211_local *local = sdata->local; |
900 | int sent, buffered; | 900 | int sent, buffered; |
901 | 901 | ||
902 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | 902 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
903 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | ||
903 | 904 | ||
904 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 905 | if (!skb_queue_empty(&sta->ps_tx_buf)) |
905 | sta_info_clear_tim_bit(sta); | 906 | sta_info_clear_tim_bit(sta); |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 38a797217a9..ffb0de9bc2f 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -98,6 +98,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
98 | * (b) always process RX events before TX status events if ordering | 98 | * (b) always process RX events before TX status events if ordering |
99 | * can be unknown, for example with different interrupt status | 99 | * can be unknown, for example with different interrupt status |
100 | * bits. | 100 | * bits. |
101 | * (c) if PS mode transitions are manual (i.e. the flag | ||
102 | * %IEEE80211_HW_AP_LINK_PS is set), always process PS state | ||
103 | * changes before calling TX status events if ordering can be | ||
104 | * unknown. | ||
101 | */ | 105 | */ |
102 | if (test_sta_flags(sta, WLAN_STA_PS_STA) && | 106 | if (test_sta_flags(sta, WLAN_STA_PS_STA) && |
103 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { | 107 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ffc67491c38..38e59393972 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -257,7 +257,8 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) | |||
257 | if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) | 257 | if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) |
258 | return TX_CONTINUE; | 258 | return TX_CONTINUE; |
259 | 259 | ||
260 | if (unlikely(test_bit(SCAN_OFF_CHANNEL, &tx->local->scanning)) && | 260 | if (unlikely(test_bit(SCAN_SW_SCANNING, &tx->local->scanning)) && |
261 | test_bit(SDATA_STATE_OFFCHANNEL, &tx->sdata->state) && | ||
261 | !ieee80211_is_probe_req(hdr->frame_control) && | 262 | !ieee80211_is_probe_req(hdr->frame_control) && |
262 | !ieee80211_is_nullfunc(hdr->frame_control)) | 263 | !ieee80211_is_nullfunc(hdr->frame_control)) |
263 | /* | 264 | /* |
@@ -1394,7 +1395,8 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1394 | /* handlers after fragment must be aware of tx info fragmentation! */ | 1395 | /* handlers after fragment must be aware of tx info fragmentation! */ |
1395 | CALL_TXH(ieee80211_tx_h_stats); | 1396 | CALL_TXH(ieee80211_tx_h_stats); |
1396 | CALL_TXH(ieee80211_tx_h_encrypt); | 1397 | CALL_TXH(ieee80211_tx_h_encrypt); |
1397 | CALL_TXH(ieee80211_tx_h_calculate_duration); | 1398 | if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) |
1399 | CALL_TXH(ieee80211_tx_h_calculate_duration); | ||
1398 | #undef CALL_TXH | 1400 | #undef CALL_TXH |
1399 | 1401 | ||
1400 | txh_done: | 1402 | txh_done: |
@@ -2178,6 +2180,8 @@ static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, | |||
2178 | if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) | 2180 | if (bss->dtim_count == 0 && !skb_queue_empty(&bss->ps_bc_buf)) |
2179 | aid0 = 1; | 2181 | aid0 = 1; |
2180 | 2182 | ||
2183 | bss->dtim_bc_mc = aid0 == 1; | ||
2184 | |||
2181 | if (have_bits) { | 2185 | if (have_bits) { |
2182 | /* Find largest even number N1 so that bits numbered 1 through | 2186 | /* Find largest even number N1 so that bits numbered 1 through |
2183 | * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits | 2187 | * (N1 x 8) - 1 in the bitmap are 0 and number N2 so that bits |
@@ -2241,7 +2245,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | |||
2241 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | 2245 | if (sdata->vif.type == NL80211_IFTYPE_AP) { |
2242 | ap = &sdata->u.ap; | 2246 | ap = &sdata->u.ap; |
2243 | beacon = rcu_dereference(ap->beacon); | 2247 | beacon = rcu_dereference(ap->beacon); |
2244 | if (ap && beacon) { | 2248 | if (beacon) { |
2245 | /* | 2249 | /* |
2246 | * headroom, head length, | 2250 | * headroom, head length, |
2247 | * tail length and maximum TIM length | 2251 | * tail length and maximum TIM length |
@@ -2548,7 +2552,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, | |||
2548 | if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head) | 2552 | if (sdata->vif.type != NL80211_IFTYPE_AP || !beacon || !beacon->head) |
2549 | goto out; | 2553 | goto out; |
2550 | 2554 | ||
2551 | if (bss->dtim_count != 0) | 2555 | if (bss->dtim_count != 0 || !bss->dtim_bc_mc) |
2552 | goto out; /* send buffered bc/mc only after DTIM beacon */ | 2556 | goto out; /* send buffered bc/mc only after DTIM beacon */ |
2553 | 2557 | ||
2554 | while (1) { | 2558 | while (1) { |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 36305e0d06e..6bf787a5b38 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -924,18 +924,44 @@ static void ieee80211_work_work(struct work_struct *work) | |||
924 | } | 924 | } |
925 | 925 | ||
926 | if (!started && !local->tmp_channel) { | 926 | if (!started && !local->tmp_channel) { |
927 | /* | 927 | bool on_oper_chan; |
928 | * TODO: could optimize this by leaving the | 928 | bool tmp_chan_changed = false; |
929 | * station vifs in awake mode if they | 929 | bool on_oper_chan2; |
930 | * happen to be on the same channel as | 930 | on_oper_chan = ieee80211_cfg_on_oper_channel(local); |
931 | * the requested channel | 931 | if (local->tmp_channel) |
932 | */ | 932 | if ((local->tmp_channel != wk->chan) || |
933 | ieee80211_offchannel_stop_beaconing(local); | 933 | (local->tmp_channel_type != wk->chan_type)) |
934 | ieee80211_offchannel_stop_station(local); | 934 | tmp_chan_changed = true; |
935 | 935 | ||
936 | local->tmp_channel = wk->chan; | 936 | local->tmp_channel = wk->chan; |
937 | local->tmp_channel_type = wk->chan_type; | 937 | local->tmp_channel_type = wk->chan_type; |
938 | ieee80211_hw_config(local, 0); | 938 | /* |
939 | * Leave the station vifs in awake mode if they | ||
940 | * happen to be on the same channel as | ||
941 | * the requested channel. | ||
942 | */ | ||
943 | on_oper_chan2 = ieee80211_cfg_on_oper_channel(local); | ||
944 | if (on_oper_chan != on_oper_chan2) { | ||
945 | if (on_oper_chan2) { | ||
946 | /* going off oper channel, PS too */ | ||
947 | ieee80211_offchannel_stop_vifs(local, | ||
948 | true); | ||
949 | ieee80211_hw_config(local, 0); | ||
950 | } else { | ||
951 | /* going on channel, but leave PS | ||
952 | * off-channel. */ | ||
953 | ieee80211_hw_config(local, 0); | ||
954 | ieee80211_offchannel_return(local, | ||
955 | true, | ||
956 | false); | ||
957 | } | ||
958 | } else if (tmp_chan_changed) | ||
959 | /* Still off-channel, but on some other | ||
960 | * channel, so update hardware. | ||
961 | * PS should already be off-channel. | ||
962 | */ | ||
963 | ieee80211_hw_config(local, 0); | ||
964 | |||
939 | started = true; | 965 | started = true; |
940 | wk->timeout = jiffies; | 966 | wk->timeout = jiffies; |
941 | } | 967 | } |
@@ -1011,9 +1037,27 @@ static void ieee80211_work_work(struct work_struct *work) | |||
1011 | } | 1037 | } |
1012 | 1038 | ||
1013 | if (!remain_off_channel && local->tmp_channel) { | 1039 | if (!remain_off_channel && local->tmp_channel) { |
1040 | bool on_oper_chan = ieee80211_cfg_on_oper_channel(local); | ||
1014 | local->tmp_channel = NULL; | 1041 | local->tmp_channel = NULL; |
1015 | ieee80211_hw_config(local, 0); | 1042 | /* If tmp_channel wasn't operating channel, then |
1016 | ieee80211_offchannel_return(local, true); | 1043 | * we need to go back on-channel. |
1044 | * NOTE: If we can ever be here while scannning, | ||
1045 | * or if the hw_config() channel config logic changes, | ||
1046 | * then we may need to do a more thorough check to see if | ||
1047 | * we still need to do a hardware config. Currently, | ||
1048 | * we cannot be here while scanning, however. | ||
1049 | */ | ||
1050 | if (ieee80211_cfg_on_oper_channel(local) && !on_oper_chan) | ||
1051 | ieee80211_hw_config(local, 0); | ||
1052 | |||
1053 | /* At the least, we need to disable offchannel_ps, | ||
1054 | * so just go ahead and run the entire offchannel | ||
1055 | * return logic here. We *could* skip enabling | ||
1056 | * beaconing if we were already on-oper-channel | ||
1057 | * as a future optimization. | ||
1058 | */ | ||
1059 | ieee80211_offchannel_return(local, true, true); | ||
1060 | |||
1017 | /* give connection some time to breathe */ | 1061 | /* give connection some time to breathe */ |
1018 | run_again(local, jiffies + HZ/2); | 1062 | run_again(local, jiffies + HZ/2); |
1019 | } | 1063 | } |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index bee230d8fd1..f1765de2f4b 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -26,13 +26,12 @@ | |||
26 | ieee80211_tx_result | 26 | ieee80211_tx_result |
27 | ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | 27 | ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) |
28 | { | 28 | { |
29 | u8 *data, *key, *mic, key_offset; | 29 | u8 *data, *key, *mic; |
30 | size_t data_len; | 30 | size_t data_len; |
31 | unsigned int hdrlen; | 31 | unsigned int hdrlen; |
32 | struct ieee80211_hdr *hdr; | 32 | struct ieee80211_hdr *hdr; |
33 | struct sk_buff *skb = tx->skb; | 33 | struct sk_buff *skb = tx->skb; |
34 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 34 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
35 | int authenticator; | ||
36 | int tail; | 35 | int tail; |
37 | 36 | ||
38 | hdr = (struct ieee80211_hdr *)skb->data; | 37 | hdr = (struct ieee80211_hdr *)skb->data; |
@@ -47,6 +46,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
47 | data = skb->data + hdrlen; | 46 | data = skb->data + hdrlen; |
48 | data_len = skb->len - hdrlen; | 47 | data_len = skb->len - hdrlen; |
49 | 48 | ||
49 | if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) { | ||
50 | /* Need to use software crypto for the test */ | ||
51 | info->control.hw_key = NULL; | ||
52 | } | ||
53 | |||
50 | if (info->control.hw_key && | 54 | if (info->control.hw_key && |
51 | !(tx->flags & IEEE80211_TX_FRAGMENTED) && | 55 | !(tx->flags & IEEE80211_TX_FRAGMENTED) && |
52 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { | 56 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { |
@@ -62,17 +66,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
62 | skb_headroom(skb) < TKIP_IV_LEN)) | 66 | skb_headroom(skb) < TKIP_IV_LEN)) |
63 | return TX_DROP; | 67 | return TX_DROP; |
64 | 68 | ||
65 | #if 0 | 69 | key = &tx->key->conf.key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]; |
66 | authenticator = fc & IEEE80211_FCTL_FROMDS; /* FIX */ | ||
67 | #else | ||
68 | authenticator = 1; | ||
69 | #endif | ||
70 | key_offset = authenticator ? | ||
71 | NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY : | ||
72 | NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; | ||
73 | key = &tx->key->conf.key[key_offset]; | ||
74 | mic = skb_put(skb, MICHAEL_MIC_LEN); | 70 | mic = skb_put(skb, MICHAEL_MIC_LEN); |
75 | michael_mic(key, hdr, data, data_len, mic); | 71 | michael_mic(key, hdr, data, data_len, mic); |
72 | if (unlikely(info->flags & IEEE80211_TX_INTFL_TKIP_MIC_FAILURE)) | ||
73 | mic[0]++; | ||
76 | 74 | ||
77 | return TX_CONTINUE; | 75 | return TX_CONTINUE; |
78 | } | 76 | } |
@@ -81,14 +79,13 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
81 | ieee80211_rx_result | 79 | ieee80211_rx_result |
82 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | 80 | ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) |
83 | { | 81 | { |
84 | u8 *data, *key = NULL, key_offset; | 82 | u8 *data, *key = NULL; |
85 | size_t data_len; | 83 | size_t data_len; |
86 | unsigned int hdrlen; | 84 | unsigned int hdrlen; |
87 | u8 mic[MICHAEL_MIC_LEN]; | 85 | u8 mic[MICHAEL_MIC_LEN]; |
88 | struct sk_buff *skb = rx->skb; | 86 | struct sk_buff *skb = rx->skb; |
89 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 87 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
90 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 88 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
91 | int authenticator = 1, wpa_test = 0; | ||
92 | 89 | ||
93 | /* No way to verify the MIC if the hardware stripped it */ | 90 | /* No way to verify the MIC if the hardware stripped it */ |
94 | if (status->flag & RX_FLAG_MMIC_STRIPPED) | 91 | if (status->flag & RX_FLAG_MMIC_STRIPPED) |
@@ -106,17 +103,9 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) | |||
106 | data = skb->data + hdrlen; | 103 | data = skb->data + hdrlen; |
107 | data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; | 104 | data_len = skb->len - hdrlen - MICHAEL_MIC_LEN; |
108 | 105 | ||
109 | #if 0 | 106 | key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]; |
110 | authenticator = fc & IEEE80211_FCTL_TODS; /* FIX */ | ||
111 | #else | ||
112 | authenticator = 1; | ||
113 | #endif | ||
114 | key_offset = authenticator ? | ||
115 | NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY : | ||
116 | NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; | ||
117 | key = &rx->key->conf.key[key_offset]; | ||
118 | michael_mic(key, hdr, data, data_len, mic); | 107 | michael_mic(key, hdr, data, data_len, mic); |
119 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { | 108 | if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) { |
120 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) | 109 | if (!(status->rx_flags & IEEE80211_RX_RA_MATCH)) |
121 | return RX_DROP_UNUSABLE; | 110 | return RX_DROP_UNUSABLE; |
122 | 111 | ||
@@ -208,7 +197,7 @@ ieee80211_rx_result | |||
208 | ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) | 197 | ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) |
209 | { | 198 | { |
210 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; | 199 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; |
211 | int hdrlen, res, hwaccel = 0, wpa_test = 0; | 200 | int hdrlen, res, hwaccel = 0; |
212 | struct ieee80211_key *key = rx->key; | 201 | struct ieee80211_key *key = rx->key; |
213 | struct sk_buff *skb = rx->skb; | 202 | struct sk_buff *skb = rx->skb; |
214 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); | 203 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
@@ -235,7 +224,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) | |||
235 | hdr->addr1, hwaccel, rx->queue, | 224 | hdr->addr1, hwaccel, rx->queue, |
236 | &rx->tkip_iv32, | 225 | &rx->tkip_iv32, |
237 | &rx->tkip_iv16); | 226 | &rx->tkip_iv16); |
238 | if (res != TKIP_DECRYPT_OK || wpa_test) | 227 | if (res != TKIP_DECRYPT_OK) |
239 | return RX_DROP_UNUSABLE; | 228 | return RX_DROP_UNUSABLE; |
240 | 229 | ||
241 | /* Trim ICV */ | 230 | /* Trim ICV */ |