diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 138 |
1 files changed, 111 insertions, 27 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 45fbb9e33746..64d92d5a7f40 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 |
@@ -134,6 +145,9 @@ void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) | |||
134 | { | 145 | { |
135 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 146 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
136 | 147 | ||
148 | if (unlikely(!sdata->u.mgd.associated)) | ||
149 | return; | ||
150 | |||
137 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | 151 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) |
138 | return; | 152 | return; |
139 | 153 | ||
@@ -161,6 +175,7 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
161 | struct ieee80211_supported_band *sband; | 175 | struct ieee80211_supported_band *sband; |
162 | struct sta_info *sta; | 176 | struct sta_info *sta; |
163 | u32 changed = 0; | 177 | u32 changed = 0; |
178 | int hti_cfreq; | ||
164 | u16 ht_opmode; | 179 | u16 ht_opmode; |
165 | bool enable_ht = true; | 180 | bool enable_ht = true; |
166 | enum nl80211_channel_type prev_chantype; | 181 | enum nl80211_channel_type prev_chantype; |
@@ -174,10 +189,27 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, | |||
174 | if (!sband->ht_cap.ht_supported) | 189 | if (!sband->ht_cap.ht_supported) |
175 | enable_ht = false; | 190 | enable_ht = false; |
176 | 191 | ||
177 | /* check that channel matches the right operating channel */ | 192 | if (enable_ht) { |
178 | if (local->hw.conf.channel->center_freq != | 193 | hti_cfreq = ieee80211_channel_to_frequency(hti->control_chan, |
179 | ieee80211_channel_to_frequency(hti->control_chan)) | 194 | sband->band); |
180 | enable_ht = false; | 195 | /* check that channel matches the right operating channel */ |
196 | if (local->hw.conf.channel->center_freq != hti_cfreq) { | ||
197 | /* Some APs mess this up, evidently. | ||
198 | * Netgear WNDR3700 sometimes reports 4 higher than | ||
199 | * the actual channel, for instance. | ||
200 | */ | ||
201 | printk(KERN_DEBUG | ||
202 | "%s: Wrong control channel in association" | ||
203 | " response: configured center-freq: %d" | ||
204 | " hti-cfreq: %d hti->control_chan: %d" | ||
205 | " band: %d. Disabling HT.\n", | ||
206 | sdata->name, | ||
207 | local->hw.conf.channel->center_freq, | ||
208 | hti_cfreq, hti->control_chan, | ||
209 | sband->band); | ||
210 | enable_ht = false; | ||
211 | } | ||
212 | } | ||
181 | 213 | ||
182 | if (enable_ht) { | 214 | if (enable_ht) { |
183 | channel_type = NL80211_CHAN_HT20; | 215 | channel_type = NL80211_CHAN_HT20; |
@@ -429,7 +461,8 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
429 | container_of((void *)bss, struct cfg80211_bss, priv); | 461 | container_of((void *)bss, struct cfg80211_bss, priv); |
430 | struct ieee80211_channel *new_ch; | 462 | struct ieee80211_channel *new_ch; |
431 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 463 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
432 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); | 464 | int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num, |
465 | cbss->channel->band); | ||
433 | 466 | ||
434 | ASSERT_MGD_MTX(ifmgd); | 467 | ASSERT_MGD_MTX(ifmgd); |
435 | 468 | ||
@@ -580,6 +613,37 @@ static void ieee80211_change_ps(struct ieee80211_local *local) | |||
580 | } | 613 | } |
581 | } | 614 | } |
582 | 615 | ||
616 | static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) | ||
617 | { | ||
618 | struct ieee80211_if_managed *mgd = &sdata->u.mgd; | ||
619 | struct sta_info *sta = NULL; | ||
620 | u32 sta_flags = 0; | ||
621 | |||
622 | if (!mgd->powersave) | ||
623 | return false; | ||
624 | |||
625 | if (!mgd->associated) | ||
626 | return false; | ||
627 | |||
628 | if (!mgd->associated->beacon_ies) | ||
629 | return false; | ||
630 | |||
631 | if (mgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
632 | IEEE80211_STA_CONNECTION_POLL)) | ||
633 | return false; | ||
634 | |||
635 | rcu_read_lock(); | ||
636 | sta = sta_info_get(sdata, mgd->bssid); | ||
637 | if (sta) | ||
638 | sta_flags = get_sta_flags(sta); | ||
639 | rcu_read_unlock(); | ||
640 | |||
641 | if (!(sta_flags & WLAN_STA_AUTHORIZED)) | ||
642 | return false; | ||
643 | |||
644 | return true; | ||
645 | } | ||
646 | |||
583 | /* need to hold RTNL or interface lock */ | 647 | /* need to hold RTNL or interface lock */ |
584 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | 648 | void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) |
585 | { | 649 | { |
@@ -600,17 +664,21 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
600 | list_for_each_entry(sdata, &local->interfaces, list) { | 664 | list_for_each_entry(sdata, &local->interfaces, list) { |
601 | if (!ieee80211_sdata_running(sdata)) | 665 | if (!ieee80211_sdata_running(sdata)) |
602 | continue; | 666 | continue; |
667 | if (sdata->vif.type == NL80211_IFTYPE_AP) { | ||
668 | /* If an AP vif is found, then disable PS | ||
669 | * by setting the count to zero thereby setting | ||
670 | * ps_sdata to NULL. | ||
671 | */ | ||
672 | count = 0; | ||
673 | break; | ||
674 | } | ||
603 | if (sdata->vif.type != NL80211_IFTYPE_STATION) | 675 | if (sdata->vif.type != NL80211_IFTYPE_STATION) |
604 | continue; | 676 | continue; |
605 | found = sdata; | 677 | found = sdata; |
606 | count++; | 678 | count++; |
607 | } | 679 | } |
608 | 680 | ||
609 | if (count == 1 && found->u.mgd.powersave && | 681 | if (count == 1 && ieee80211_powersave_allowed(found)) { |
610 | found->u.mgd.associated && | ||
611 | found->u.mgd.associated->beacon_ies && | ||
612 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | ||
613 | IEEE80211_STA_CONNECTION_POLL))) { | ||
614 | struct ieee80211_conf *conf = &local->hw.conf; | 682 | struct ieee80211_conf *conf = &local->hw.conf; |
615 | s32 beaconint_us; | 683 | s32 beaconint_us; |
616 | 684 | ||
@@ -700,9 +768,19 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
700 | return; | 768 | return; |
701 | 769 | ||
702 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && | 770 | if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) && |
703 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) | 771 | (!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) { |
772 | netif_tx_stop_all_queues(sdata->dev); | ||
773 | /* | ||
774 | * Flush all the frames queued in the driver before | ||
775 | * going to power save | ||
776 | */ | ||
777 | drv_flush(local, false); | ||
704 | ieee80211_send_nullfunc(local, sdata, 1); | 778 | ieee80211_send_nullfunc(local, sdata, 1); |
705 | 779 | ||
780 | /* Flush once again to get the tx status of nullfunc frame */ | ||
781 | drv_flush(local, false); | ||
782 | } | ||
783 | |||
706 | if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && | 784 | if (!((local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) && |
707 | (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) || | 785 | (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) || |
708 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { | 786 | (ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) { |
@@ -710,6 +788,8 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
710 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 788 | local->hw.conf.flags |= IEEE80211_CONF_PS; |
711 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 789 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |
712 | } | 790 | } |
791 | |||
792 | netif_tx_start_all_queues(sdata->dev); | ||
713 | } | 793 | } |
714 | 794 | ||
715 | void ieee80211_dynamic_ps_timer(unsigned long data) | 795 | void ieee80211_dynamic_ps_timer(unsigned long data) |
@@ -1089,7 +1169,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1089 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1169 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
1090 | const u8 *ssid; | 1170 | const u8 *ssid; |
1091 | u8 *dst = ifmgd->associated->bssid; | 1171 | u8 *dst = ifmgd->associated->bssid; |
1092 | u8 unicast_limit = max(1, IEEE80211_MAX_PROBE_TRIES - 3); | 1172 | u8 unicast_limit = max(1, max_probe_tries - 3); |
1093 | 1173 | ||
1094 | /* | 1174 | /* |
1095 | * Try sending broadcast probe requests for the last three | 1175 | * Try sending broadcast probe requests for the last three |
@@ -1115,7 +1195,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1115 | } | 1195 | } |
1116 | 1196 | ||
1117 | ifmgd->probe_send_count++; | 1197 | ifmgd->probe_send_count++; |
1118 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | 1198 | ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms); |
1119 | run_again(ifmgd, ifmgd->probe_timeout); | 1199 | run_again(ifmgd, ifmgd->probe_timeout); |
1120 | } | 1200 | } |
1121 | 1201 | ||
@@ -1216,7 +1296,8 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | |||
1216 | 1296 | ||
1217 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 1297 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1218 | 1298 | ||
1219 | printk(KERN_DEBUG "Connection to AP %pM lost.\n", bssid); | 1299 | printk(KERN_DEBUG "%s: Connection to AP %pM lost.\n", |
1300 | sdata->name, bssid); | ||
1220 | 1301 | ||
1221 | ieee80211_set_disassoc(sdata, true, true); | 1302 | ieee80211_set_disassoc(sdata, true, true); |
1222 | mutex_unlock(&ifmgd->mtx); | 1303 | mutex_unlock(&ifmgd->mtx); |
@@ -1519,7 +1600,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1519 | } | 1600 | } |
1520 | 1601 | ||
1521 | if (elems->ds_params && elems->ds_params_len == 1) | 1602 | if (elems->ds_params && elems->ds_params_len == 1) |
1522 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | 1603 | freq = ieee80211_channel_to_frequency(elems->ds_params[0], |
1604 | rx_status->band); | ||
1523 | else | 1605 | else |
1524 | freq = rx_status->freq; | 1606 | freq = rx_status->freq; |
1525 | 1607 | ||
@@ -1960,9 +2042,9 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1960 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 2042 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1961 | 2043 | ||
1962 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | 2044 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
1963 | max_tries = IEEE80211_MAX_NULLFUNC_TRIES; | 2045 | max_tries = max_nullfunc_tries; |
1964 | else | 2046 | else |
1965 | max_tries = IEEE80211_MAX_PROBE_TRIES; | 2047 | max_tries = max_probe_tries; |
1966 | 2048 | ||
1967 | /* ACK received for nullfunc probing frame */ | 2049 | /* ACK received for nullfunc probing frame */ |
1968 | if (!ifmgd->probe_send_count) | 2050 | if (!ifmgd->probe_send_count) |
@@ -1972,9 +2054,9 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1972 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2054 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1973 | wiphy_debug(local->hw.wiphy, | 2055 | wiphy_debug(local->hw.wiphy, |
1974 | "%s: No ack for nullfunc frame to" | 2056 | "%s: No ack for nullfunc frame to" |
1975 | " AP %pM, try %d\n", | 2057 | " AP %pM, try %d/%i\n", |
1976 | sdata->name, bssid, | 2058 | sdata->name, bssid, |
1977 | ifmgd->probe_send_count); | 2059 | ifmgd->probe_send_count, max_tries); |
1978 | #endif | 2060 | #endif |
1979 | ieee80211_mgd_probe_ap_send(sdata); | 2061 | ieee80211_mgd_probe_ap_send(sdata); |
1980 | } else { | 2062 | } else { |
@@ -1994,17 +2076,17 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1994 | "%s: Failed to send nullfunc to AP %pM" | 2076 | "%s: Failed to send nullfunc to AP %pM" |
1995 | " after %dms, disconnecting.\n", | 2077 | " after %dms, disconnecting.\n", |
1996 | sdata->name, | 2078 | sdata->name, |
1997 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2079 | bssid, probe_wait_ms); |
1998 | #endif | 2080 | #endif |
1999 | ieee80211_sta_connection_lost(sdata, bssid); | 2081 | ieee80211_sta_connection_lost(sdata, bssid); |
2000 | } else if (ifmgd->probe_send_count < max_tries) { | 2082 | } else if (ifmgd->probe_send_count < max_tries) { |
2001 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2083 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
2002 | wiphy_debug(local->hw.wiphy, | 2084 | wiphy_debug(local->hw.wiphy, |
2003 | "%s: No probe response from AP %pM" | 2085 | "%s: No probe response from AP %pM" |
2004 | " after %dms, try %d\n", | 2086 | " after %dms, try %d/%i\n", |
2005 | sdata->name, | 2087 | sdata->name, |
2006 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ, | 2088 | bssid, probe_wait_ms, |
2007 | ifmgd->probe_send_count); | 2089 | ifmgd->probe_send_count, max_tries); |
2008 | #endif | 2090 | #endif |
2009 | ieee80211_mgd_probe_ap_send(sdata); | 2091 | ieee80211_mgd_probe_ap_send(sdata); |
2010 | } else { | 2092 | } else { |
@@ -2016,7 +2098,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
2016 | "%s: No probe response from AP %pM" | 2098 | "%s: No probe response from AP %pM" |
2017 | " after %dms, disconnecting.\n", | 2099 | " after %dms, disconnecting.\n", |
2018 | sdata->name, | 2100 | sdata->name, |
2019 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2101 | bssid, probe_wait_ms); |
2020 | 2102 | ||
2021 | ieee80211_sta_connection_lost(sdata, bssid); | 2103 | ieee80211_sta_connection_lost(sdata, bssid); |
2022 | } | 2104 | } |
@@ -2254,6 +2336,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, | |||
2254 | else | 2336 | else |
2255 | wk->type = IEEE80211_WORK_DIRECT_PROBE; | 2337 | wk->type = IEEE80211_WORK_DIRECT_PROBE; |
2256 | wk->chan = req->bss->channel; | 2338 | wk->chan = req->bss->channel; |
2339 | wk->chan_type = NL80211_CHAN_NO_HT; | ||
2257 | wk->sdata = sdata; | 2340 | wk->sdata = sdata; |
2258 | wk->done = ieee80211_probe_auth_done; | 2341 | wk->done = ieee80211_probe_auth_done; |
2259 | 2342 | ||
@@ -2403,6 +2486,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, | |||
2403 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); | 2486 | memcpy(wk->assoc.prev_bssid, req->prev_bssid, ETH_ALEN); |
2404 | 2487 | ||
2405 | wk->chan = req->bss->channel; | 2488 | wk->chan = req->bss->channel; |
2489 | wk->chan_type = NL80211_CHAN_NO_HT; | ||
2406 | wk->sdata = sdata; | 2490 | wk->sdata = sdata; |
2407 | wk->done = ieee80211_assoc_done; | 2491 | wk->done = ieee80211_assoc_done; |
2408 | if (!bss->dtim_period && | 2492 | if (!bss->dtim_period && |