diff options
Diffstat (limited to 'net/mac80211/scan.c')
-rw-r--r-- | net/mac80211/scan.c | 136 |
1 files changed, 56 insertions, 80 deletions
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 8ed83dcc149f..43a45cf00e06 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -27,22 +27,15 @@ | |||
27 | 27 | ||
28 | #define IEEE80211_PROBE_DELAY (HZ / 33) | 28 | #define IEEE80211_PROBE_DELAY (HZ / 33) |
29 | #define IEEE80211_CHANNEL_TIME (HZ / 33) | 29 | #define IEEE80211_CHANNEL_TIME (HZ / 33) |
30 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8) | 30 | #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 9) |
31 | |||
32 | static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) | ||
33 | { | ||
34 | struct ieee80211_bss *bss = (void *)cbss->priv; | ||
35 | |||
36 | kfree(bss_mesh_id(bss)); | ||
37 | kfree(bss_mesh_cfg(bss)); | ||
38 | } | ||
39 | 31 | ||
40 | void ieee80211_rx_bss_put(struct ieee80211_local *local, | 32 | void ieee80211_rx_bss_put(struct ieee80211_local *local, |
41 | struct ieee80211_bss *bss) | 33 | struct ieee80211_bss *bss) |
42 | { | 34 | { |
43 | if (!bss) | 35 | if (!bss) |
44 | return; | 36 | return; |
45 | cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); | 37 | cfg80211_put_bss(local->hw.wiphy, |
38 | container_of((void *)bss, struct cfg80211_bss, priv)); | ||
46 | } | 39 | } |
47 | 40 | ||
48 | static bool is_uapsd_supported(struct ieee802_11_elems *elems) | 41 | static bool is_uapsd_supported(struct ieee802_11_elems *elems) |
@@ -65,12 +58,11 @@ static bool is_uapsd_supported(struct ieee802_11_elems *elems) | |||
65 | struct ieee80211_bss * | 58 | struct ieee80211_bss * |
66 | ieee80211_bss_info_update(struct ieee80211_local *local, | 59 | ieee80211_bss_info_update(struct ieee80211_local *local, |
67 | struct ieee80211_rx_status *rx_status, | 60 | struct ieee80211_rx_status *rx_status, |
68 | struct ieee80211_mgmt *mgmt, | 61 | struct ieee80211_mgmt *mgmt, size_t len, |
69 | size_t len, | ||
70 | struct ieee802_11_elems *elems, | 62 | struct ieee802_11_elems *elems, |
71 | struct ieee80211_channel *channel, | 63 | struct ieee80211_channel *channel) |
72 | bool beacon) | ||
73 | { | 64 | { |
65 | bool beacon = ieee80211_is_beacon(mgmt->frame_control); | ||
74 | struct cfg80211_bss *cbss; | 66 | struct cfg80211_bss *cbss; |
75 | struct ieee80211_bss *bss; | 67 | struct ieee80211_bss *bss; |
76 | int clen, srlen; | 68 | int clen, srlen; |
@@ -86,10 +78,12 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
86 | if (!cbss) | 78 | if (!cbss) |
87 | return NULL; | 79 | return NULL; |
88 | 80 | ||
89 | cbss->free_priv = ieee80211_rx_bss_free; | ||
90 | bss = (void *)cbss->priv; | 81 | bss = (void *)cbss->priv; |
91 | 82 | ||
92 | bss->device_ts = rx_status->device_timestamp; | 83 | if (beacon) |
84 | bss->device_ts_beacon = rx_status->device_timestamp; | ||
85 | else | ||
86 | bss->device_ts_presp = rx_status->device_timestamp; | ||
93 | 87 | ||
94 | if (elems->parse_error) { | 88 | if (elems->parse_error) { |
95 | if (beacon) | 89 | if (beacon) |
@@ -113,18 +107,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
113 | bss->valid_data |= IEEE80211_BSS_VALID_ERP; | 107 | bss->valid_data |= IEEE80211_BSS_VALID_ERP; |
114 | } | 108 | } |
115 | 109 | ||
116 | if (elems->tim && (!elems->parse_error || | ||
117 | !(bss->valid_data & IEEE80211_BSS_VALID_DTIM))) { | ||
118 | struct ieee80211_tim_ie *tim_ie = elems->tim; | ||
119 | bss->dtim_period = tim_ie->dtim_period; | ||
120 | if (!elems->parse_error) | ||
121 | bss->valid_data |= IEEE80211_BSS_VALID_DTIM; | ||
122 | } | ||
123 | |||
124 | /* If the beacon had no TIM IE, or it was invalid, use 1 */ | ||
125 | if (beacon && !bss->dtim_period) | ||
126 | bss->dtim_period = 1; | ||
127 | |||
128 | /* replace old supported rates if we get new values */ | 110 | /* replace old supported rates if we get new values */ |
129 | if (!elems->parse_error || | 111 | if (!elems->parse_error || |
130 | !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) { | 112 | !(bss->valid_data & IEEE80211_BSS_VALID_RATES)) { |
@@ -159,9 +141,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
159 | bss->valid_data |= IEEE80211_BSS_VALID_WMM; | 141 | bss->valid_data |= IEEE80211_BSS_VALID_WMM; |
160 | } | 142 | } |
161 | 143 | ||
162 | if (!beacon) | ||
163 | bss->last_probe_resp = jiffies; | ||
164 | |||
165 | return bss; | 144 | return bss; |
166 | } | 145 | } |
167 | 146 | ||
@@ -215,7 +194,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) | |||
215 | 194 | ||
216 | bss = ieee80211_bss_info_update(local, rx_status, | 195 | bss = ieee80211_bss_info_update(local, rx_status, |
217 | mgmt, skb->len, &elems, | 196 | mgmt, skb->len, &elems, |
218 | channel, beacon); | 197 | channel); |
219 | if (bss) | 198 | if (bss) |
220 | ieee80211_rx_bss_put(local, bss); | 199 | ieee80211_rx_bss_put(local, bss); |
221 | } | 200 | } |
@@ -304,7 +283,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, | |||
304 | if (!was_hw_scan) { | 283 | if (!was_hw_scan) { |
305 | ieee80211_configure_filter(local); | 284 | ieee80211_configure_filter(local); |
306 | drv_sw_scan_complete(local); | 285 | drv_sw_scan_complete(local); |
307 | ieee80211_offchannel_return(local, true); | 286 | ieee80211_offchannel_return(local); |
308 | } | 287 | } |
309 | 288 | ||
310 | ieee80211_recalc_idle(local); | 289 | ieee80211_recalc_idle(local); |
@@ -353,7 +332,10 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
353 | local->next_scan_state = SCAN_DECISION; | 332 | local->next_scan_state = SCAN_DECISION; |
354 | local->scan_channel_idx = 0; | 333 | local->scan_channel_idx = 0; |
355 | 334 | ||
356 | ieee80211_offchannel_stop_vifs(local, true); | 335 | ieee80211_offchannel_stop_vifs(local); |
336 | |||
337 | /* ensure nullfunc is transmitted before leaving operating channel */ | ||
338 | drv_flush(local, false); | ||
357 | 339 | ||
358 | ieee80211_configure_filter(local); | 340 | ieee80211_configure_filter(local); |
359 | 341 | ||
@@ -369,6 +351,9 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | |||
369 | static bool ieee80211_can_scan(struct ieee80211_local *local, | 351 | static bool ieee80211_can_scan(struct ieee80211_local *local, |
370 | struct ieee80211_sub_if_data *sdata) | 352 | struct ieee80211_sub_if_data *sdata) |
371 | { | 353 | { |
354 | if (local->radar_detect_enabled) | ||
355 | return false; | ||
356 | |||
372 | if (!list_empty(&local->roc_list)) | 357 | if (!list_empty(&local->roc_list)) |
373 | return false; | 358 | return false; |
374 | 359 | ||
@@ -403,6 +388,11 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
403 | int i; | 388 | int i; |
404 | struct ieee80211_sub_if_data *sdata; | 389 | struct ieee80211_sub_if_data *sdata; |
405 | enum ieee80211_band band = local->hw.conf.channel->band; | 390 | enum ieee80211_band band = local->hw.conf.channel->band; |
391 | u32 tx_flags; | ||
392 | |||
393 | tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK; | ||
394 | if (local->scan_req->no_cck) | ||
395 | tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE; | ||
406 | 396 | ||
407 | sdata = rcu_dereference_protected(local->scan_sdata, | 397 | sdata = rcu_dereference_protected(local->scan_sdata, |
408 | lockdep_is_held(&local->mtx)); | 398 | lockdep_is_held(&local->mtx)); |
@@ -414,8 +404,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, | |||
414 | local->scan_req->ssids[i].ssid_len, | 404 | local->scan_req->ssids[i].ssid_len, |
415 | local->scan_req->ie, local->scan_req->ie_len, | 405 | local->scan_req->ie, local->scan_req->ie_len, |
416 | local->scan_req->rates[band], false, | 406 | local->scan_req->rates[band], false, |
417 | local->scan_req->no_cck, | 407 | tx_flags, local->hw.conf.channel, true); |
418 | local->hw.conf.channel, true); | ||
419 | 408 | ||
420 | /* | 409 | /* |
421 | * After sending probe requests, wait for probe responses | 410 | * After sending probe requests, wait for probe responses |
@@ -559,8 +548,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
559 | bool associated = false; | 548 | bool associated = false; |
560 | bool tx_empty = true; | 549 | bool tx_empty = true; |
561 | bool bad_latency; | 550 | bool bad_latency; |
562 | bool listen_int_exceeded; | ||
563 | unsigned long min_beacon_int = 0; | ||
564 | struct ieee80211_sub_if_data *sdata; | 551 | struct ieee80211_sub_if_data *sdata; |
565 | struct ieee80211_channel *next_chan; | 552 | struct ieee80211_channel *next_chan; |
566 | enum mac80211_scan_state next_scan_state; | 553 | enum mac80211_scan_state next_scan_state; |
@@ -579,11 +566,6 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
579 | if (sdata->u.mgd.associated) { | 566 | if (sdata->u.mgd.associated) { |
580 | associated = true; | 567 | associated = true; |
581 | 568 | ||
582 | if (sdata->vif.bss_conf.beacon_int < | ||
583 | min_beacon_int || min_beacon_int == 0) | ||
584 | min_beacon_int = | ||
585 | sdata->vif.bss_conf.beacon_int; | ||
586 | |||
587 | if (!qdisc_all_tx_empty(sdata->dev)) { | 569 | if (!qdisc_all_tx_empty(sdata->dev)) { |
588 | tx_empty = false; | 570 | tx_empty = false; |
589 | break; | 571 | break; |
@@ -600,34 +582,19 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local, | |||
600 | * see if we can scan another channel without interfering | 582 | * see if we can scan another channel without interfering |
601 | * with the current traffic situation. | 583 | * with the current traffic situation. |
602 | * | 584 | * |
603 | * Since we don't know if the AP has pending frames for us | 585 | * Keep good latency, do not stay off-channel more than 125 ms. |
604 | * we can only check for our tx queues and use the current | ||
605 | * pm_qos requirements for rx. Hence, if no tx traffic occurs | ||
606 | * at all we will scan as many channels in a row as the pm_qos | ||
607 | * latency allows us to. Additionally we also check for the | ||
608 | * currently negotiated listen interval to prevent losing | ||
609 | * frames unnecessarily. | ||
610 | * | ||
611 | * Otherwise switch back to the operating channel. | ||
612 | */ | 586 | */ |
613 | 587 | ||
614 | bad_latency = time_after(jiffies + | 588 | bad_latency = time_after(jiffies + |
615 | ieee80211_scan_get_channel_time(next_chan), | 589 | ieee80211_scan_get_channel_time(next_chan), |
616 | local->leave_oper_channel_time + | 590 | local->leave_oper_channel_time + HZ / 8); |
617 | usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY))); | ||
618 | |||
619 | listen_int_exceeded = time_after(jiffies + | ||
620 | ieee80211_scan_get_channel_time(next_chan), | ||
621 | local->leave_oper_channel_time + | ||
622 | usecs_to_jiffies(min_beacon_int * 1024) * | ||
623 | local->hw.conf.listen_interval); | ||
624 | 591 | ||
625 | if (associated && !tx_empty) { | 592 | if (associated && !tx_empty) { |
626 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) | 593 | if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) |
627 | next_scan_state = SCAN_ABORT; | 594 | next_scan_state = SCAN_ABORT; |
628 | else | 595 | else |
629 | next_scan_state = SCAN_SUSPEND; | 596 | next_scan_state = SCAN_SUSPEND; |
630 | } else if (associated && (bad_latency || listen_int_exceeded)) { | 597 | } else if (associated && bad_latency) { |
631 | next_scan_state = SCAN_SUSPEND; | 598 | next_scan_state = SCAN_SUSPEND; |
632 | } else { | 599 | } else { |
633 | next_scan_state = SCAN_SET_CHANNEL; | 600 | next_scan_state = SCAN_SET_CHANNEL; |
@@ -690,12 +657,8 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, | |||
690 | local->scan_channel = NULL; | 657 | local->scan_channel = NULL; |
691 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | 658 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); |
692 | 659 | ||
693 | /* | 660 | /* disable PS */ |
694 | * Re-enable vifs and beaconing. Leave PS | 661 | ieee80211_offchannel_return(local); |
695 | * in off-channel state..will put that back | ||
696 | * on-channel at the end of scanning. | ||
697 | */ | ||
698 | ieee80211_offchannel_return(local, false); | ||
699 | 662 | ||
700 | *next_delay = HZ / 5; | 663 | *next_delay = HZ / 5; |
701 | /* afterwards, resume scan & go to next channel */ | 664 | /* afterwards, resume scan & go to next channel */ |
@@ -705,8 +668,7 @@ static void ieee80211_scan_state_suspend(struct ieee80211_local *local, | |||
705 | static void ieee80211_scan_state_resume(struct ieee80211_local *local, | 668 | static void ieee80211_scan_state_resume(struct ieee80211_local *local, |
706 | unsigned long *next_delay) | 669 | unsigned long *next_delay) |
707 | { | 670 | { |
708 | /* PS already is in off-channel mode */ | 671 | ieee80211_offchannel_stop_vifs(local); |
709 | ieee80211_offchannel_stop_vifs(local, false); | ||
710 | 672 | ||
711 | if (local->ops->flush) { | 673 | if (local->ops->flush) { |
712 | drv_flush(local, false); | 674 | drv_flush(local, false); |
@@ -832,9 +794,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | |||
832 | return res; | 794 | return res; |
833 | } | 795 | } |
834 | 796 | ||
835 | int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | 797 | int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, |
836 | const u8 *ssid, u8 ssid_len, | 798 | const u8 *ssid, u8 ssid_len, |
837 | struct ieee80211_channel *chan) | 799 | struct ieee80211_channel *chan) |
838 | { | 800 | { |
839 | struct ieee80211_local *local = sdata->local; | 801 | struct ieee80211_local *local = sdata->local; |
840 | int ret = -EBUSY; | 802 | int ret = -EBUSY; |
@@ -848,22 +810,36 @@ int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata, | |||
848 | 810 | ||
849 | /* fill internal scan request */ | 811 | /* fill internal scan request */ |
850 | if (!chan) { | 812 | if (!chan) { |
851 | int i, nchan = 0; | 813 | int i, max_n; |
814 | int n_ch = 0; | ||
852 | 815 | ||
853 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | 816 | for (band = 0; band < IEEE80211_NUM_BANDS; band++) { |
854 | if (!local->hw.wiphy->bands[band]) | 817 | if (!local->hw.wiphy->bands[band]) |
855 | continue; | 818 | continue; |
856 | for (i = 0; | 819 | |
857 | i < local->hw.wiphy->bands[band]->n_channels; | 820 | max_n = local->hw.wiphy->bands[band]->n_channels; |
858 | i++) { | 821 | for (i = 0; i < max_n; i++) { |
859 | local->int_scan_req->channels[nchan] = | 822 | struct ieee80211_channel *tmp_ch = |
860 | &local->hw.wiphy->bands[band]->channels[i]; | 823 | &local->hw.wiphy->bands[band]->channels[i]; |
861 | nchan++; | 824 | |
825 | if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS | | ||
826 | IEEE80211_CHAN_DISABLED)) | ||
827 | continue; | ||
828 | |||
829 | local->int_scan_req->channels[n_ch] = tmp_ch; | ||
830 | n_ch++; | ||
862 | } | 831 | } |
863 | } | 832 | } |
864 | 833 | ||
865 | local->int_scan_req->n_channels = nchan; | 834 | if (WARN_ON_ONCE(n_ch == 0)) |
835 | goto unlock; | ||
836 | |||
837 | local->int_scan_req->n_channels = n_ch; | ||
866 | } else { | 838 | } else { |
839 | if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS | | ||
840 | IEEE80211_CHAN_DISABLED))) | ||
841 | goto unlock; | ||
842 | |||
867 | local->int_scan_req->channels[0] = chan; | 843 | local->int_scan_req->channels[0] = chan; |
868 | local->int_scan_req->n_channels = 1; | 844 | local->int_scan_req->n_channels = 1; |
869 | } | 845 | } |