diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 143 |
1 files changed, 112 insertions, 31 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a3a9421555af..794807914940 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -28,13 +28,19 @@ | |||
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 | #define IEEE80211_MAX_PROBE_TRIES 5 | 32 | #define IEEE80211_MAX_PROBE_TRIES 5 |
32 | 33 | ||
33 | /* | 34 | /* |
34 | * beacon loss detection timeout | 35 | * Beacon loss timeout is calculated as N frames times the |
35 | * XXX: should depend on beacon interval | 36 | * advertised beacon interval. This may need to be somewhat |
37 | * higher than what hardware might detect to account for | ||
38 | * delays in the host processing frames. But since we also | ||
39 | * probe on beacon miss before declaring the connection lost | ||
40 | * default to what we want. | ||
36 | */ | 41 | */ |
37 | #define IEEE80211_BEACON_LOSS_TIME (2 * HZ) | 42 | #define IEEE80211_BEACON_LOSS_COUNT 7 |
43 | |||
38 | /* | 44 | /* |
39 | * Time the connection can be idle before we probe | 45 | * Time the connection can be idle before we probe |
40 | * it to see if we can still talk to the AP. | 46 | * it to see if we can still talk to the AP. |
@@ -121,7 +127,7 @@ void ieee80211_sta_reset_beacon_monitor(struct ieee80211_sub_if_data *sdata) | |||
121 | return; | 127 | return; |
122 | 128 | ||
123 | mod_timer(&sdata->u.mgd.bcn_mon_timer, | 129 | mod_timer(&sdata->u.mgd.bcn_mon_timer, |
124 | round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME)); | 130 | round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout)); |
125 | } | 131 | } |
126 | 132 | ||
127 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) | 133 | void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata) |
@@ -871,6 +877,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
871 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 877 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
872 | cbss->capability, bss->has_erp_value, bss->erp_value); | 878 | cbss->capability, bss->has_erp_value, bss->erp_value); |
873 | 879 | ||
880 | sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( | ||
881 | IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); | ||
882 | |||
874 | sdata->u.mgd.associated = cbss; | 883 | sdata->u.mgd.associated = cbss; |
875 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); | 884 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); |
876 | 885 | ||
@@ -1026,6 +1035,51 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1026 | ieee80211_sta_reset_conn_monitor(sdata); | 1035 | ieee80211_sta_reset_conn_monitor(sdata); |
1027 | } | 1036 | } |
1028 | 1037 | ||
1038 | static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) | ||
1039 | { | ||
1040 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1041 | |||
1042 | if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
1043 | IEEE80211_STA_CONNECTION_POLL))) | ||
1044 | return; | ||
1045 | |||
1046 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1047 | IEEE80211_STA_BEACON_POLL); | ||
1048 | mutex_lock(&sdata->local->iflist_mtx); | ||
1049 | ieee80211_recalc_ps(sdata->local, -1); | ||
1050 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1051 | |||
1052 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
1053 | return; | ||
1054 | |||
1055 | /* | ||
1056 | * We've received a probe response, but are not sure whether | ||
1057 | * we have or will be receiving any beacons or data, so let's | ||
1058 | * schedule the timers again, just in case. | ||
1059 | */ | ||
1060 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
1061 | |||
1062 | mod_timer(&ifmgd->conn_mon_timer, | ||
1063 | round_jiffies_up(jiffies + | ||
1064 | IEEE80211_CONNECTION_IDLE_TIME)); | ||
1065 | } | ||
1066 | |||
1067 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | ||
1068 | struct ieee80211_hdr *hdr) | ||
1069 | { | ||
1070 | if (!ieee80211_is_data(hdr->frame_control) && | ||
1071 | !ieee80211_is_nullfunc(hdr->frame_control)) | ||
1072 | return; | ||
1073 | |||
1074 | ieee80211_sta_reset_conn_monitor(sdata); | ||
1075 | |||
1076 | if (ieee80211_is_nullfunc(hdr->frame_control) && | ||
1077 | sdata->u.mgd.probe_send_count > 0) { | ||
1078 | sdata->u.mgd.probe_send_count = 0; | ||
1079 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||
1080 | } | ||
1081 | } | ||
1082 | |||
1029 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | 1083 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
1030 | { | 1084 | { |
1031 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1085 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1041,8 +1095,19 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1041 | if (ifmgd->probe_send_count >= unicast_limit) | 1095 | if (ifmgd->probe_send_count >= unicast_limit) |
1042 | dst = NULL; | 1096 | dst = NULL; |
1043 | 1097 | ||
1044 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1098 | /* |
1045 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | 1099 | * When the hardware reports an accurate Tx ACK status, it's |
1100 | * better to send a nullfunc frame instead of a probe request, | ||
1101 | * as it will kick us off the AP quickly if we aren't associated | ||
1102 | * anymore. The timeout will be reset if the frame is ACKed by | ||
1103 | * the AP. | ||
1104 | */ | ||
1105 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
1106 | ieee80211_send_nullfunc(sdata->local, sdata, 0); | ||
1107 | else { | ||
1108 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | ||
1109 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | ||
1110 | } | ||
1046 | 1111 | ||
1047 | ifmgd->probe_send_count++; | 1112 | ifmgd->probe_send_count++; |
1048 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | 1113 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; |
@@ -1108,6 +1173,30 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
1108 | mutex_unlock(&ifmgd->mtx); | 1173 | mutex_unlock(&ifmgd->mtx); |
1109 | } | 1174 | } |
1110 | 1175 | ||
1176 | struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | ||
1177 | struct ieee80211_vif *vif) | ||
1178 | { | ||
1179 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1180 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1181 | struct sk_buff *skb; | ||
1182 | const u8 *ssid; | ||
1183 | |||
1184 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
1185 | return NULL; | ||
1186 | |||
1187 | ASSERT_MGD_MTX(ifmgd); | ||
1188 | |||
1189 | if (!ifmgd->associated) | ||
1190 | return NULL; | ||
1191 | |||
1192 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | ||
1193 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | ||
1194 | ssid + 2, ssid[1], NULL, 0); | ||
1195 | |||
1196 | return skb; | ||
1197 | } | ||
1198 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | ||
1199 | |||
1111 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | 1200 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) |
1112 | { | 1201 | { |
1113 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1202 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1485,29 +1574,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, | |||
1485 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); | 1574 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1486 | 1575 | ||
1487 | if (ifmgd->associated && | 1576 | if (ifmgd->associated && |
1488 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && | 1577 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) |
1489 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1578 | ieee80211_reset_ap_probe(sdata); |
1490 | IEEE80211_STA_CONNECTION_POLL)) { | ||
1491 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1492 | IEEE80211_STA_BEACON_POLL); | ||
1493 | mutex_lock(&sdata->local->iflist_mtx); | ||
1494 | ieee80211_recalc_ps(sdata->local, -1); | ||
1495 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1496 | |||
1497 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
1498 | return; | ||
1499 | |||
1500 | /* | ||
1501 | * We've received a probe response, but are not sure whether | ||
1502 | * we have or will be receiving any beacons or data, so let's | ||
1503 | * schedule the timers again, just in case. | ||
1504 | */ | ||
1505 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
1506 | |||
1507 | mod_timer(&ifmgd->conn_mon_timer, | ||
1508 | round_jiffies_up(jiffies + | ||
1509 | IEEE80211_CONNECTION_IDLE_TIME)); | ||
1510 | } | ||
1511 | } | 1579 | } |
1512 | 1580 | ||
1513 | /* | 1581 | /* |
@@ -1857,12 +1925,23 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1857 | IEEE80211_STA_CONNECTION_POLL) && | 1925 | IEEE80211_STA_CONNECTION_POLL) && |
1858 | ifmgd->associated) { | 1926 | ifmgd->associated) { |
1859 | u8 bssid[ETH_ALEN]; | 1927 | u8 bssid[ETH_ALEN]; |
1928 | int max_tries; | ||
1860 | 1929 | ||
1861 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 1930 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1862 | if (time_is_after_jiffies(ifmgd->probe_timeout)) | 1931 | |
1932 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) | ||
1933 | max_tries = IEEE80211_MAX_NULLFUNC_TRIES; | ||
1934 | else | ||
1935 | max_tries = IEEE80211_MAX_PROBE_TRIES; | ||
1936 | |||
1937 | /* ACK received for nullfunc probing frame */ | ||
1938 | if (!ifmgd->probe_send_count) | ||
1939 | ieee80211_reset_ap_probe(sdata); | ||
1940 | |||
1941 | else if (time_is_after_jiffies(ifmgd->probe_timeout)) | ||
1863 | run_again(ifmgd, ifmgd->probe_timeout); | 1942 | run_again(ifmgd, ifmgd->probe_timeout); |
1864 | 1943 | ||
1865 | else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { | 1944 | else if (ifmgd->probe_send_count < max_tries) { |
1866 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 1945 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1867 | wiphy_debug(local->hw.wiphy, | 1946 | wiphy_debug(local->hw.wiphy, |
1868 | "%s: No probe response from AP %pM" | 1947 | "%s: No probe response from AP %pM" |
@@ -1988,6 +2067,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
1988 | add_timer(&ifmgd->timer); | 2067 | add_timer(&ifmgd->timer); |
1989 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | 2068 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) |
1990 | add_timer(&ifmgd->chswitch_timer); | 2069 | add_timer(&ifmgd->chswitch_timer); |
2070 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
2071 | ieee80211_restart_sta_timer(sdata); | ||
1991 | } | 2072 | } |
1992 | #endif | 2073 | #endif |
1993 | 2074 | ||