diff options
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 227 |
1 files changed, 175 insertions, 52 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a3a9421555af..45fbb9e33746 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) |
@@ -619,11 +625,12 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
619 | /* | 625 | /* |
620 | * Go to full PSM if the user configures a very low | 626 | * Go to full PSM if the user configures a very low |
621 | * latency requirement. | 627 | * latency requirement. |
622 | * The 2 second value is there for compatibility until | 628 | * The 2000 second value is there for compatibility |
623 | * the PM_QOS_NETWORK_LATENCY is configured with real | 629 | * until the PM_QOS_NETWORK_LATENCY is configured |
624 | * values. | 630 | * with real values. |
625 | */ | 631 | */ |
626 | if (latency > 1900000000 && latency != 2000000000) | 632 | if (latency > (1900 * USEC_PER_MSEC) && |
633 | latency != (2000 * USEC_PER_SEC)) | ||
627 | timeout = 0; | 634 | timeout = 0; |
628 | else | 635 | else |
629 | timeout = 100; | 636 | timeout = 100; |
@@ -871,6 +878,9 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
871 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 878 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
872 | cbss->capability, bss->has_erp_value, bss->erp_value); | 879 | cbss->capability, bss->has_erp_value, bss->erp_value); |
873 | 880 | ||
881 | sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( | ||
882 | IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); | ||
883 | |||
874 | sdata->u.mgd.associated = cbss; | 884 | sdata->u.mgd.associated = cbss; |
875 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); | 885 | memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN); |
876 | 886 | ||
@@ -1026,6 +1036,54 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, | |||
1026 | ieee80211_sta_reset_conn_monitor(sdata); | 1036 | ieee80211_sta_reset_conn_monitor(sdata); |
1027 | } | 1037 | } |
1028 | 1038 | ||
1039 | static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) | ||
1040 | { | ||
1041 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1042 | |||
1043 | if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | ||
1044 | IEEE80211_STA_CONNECTION_POLL))) | ||
1045 | return; | ||
1046 | |||
1047 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1048 | IEEE80211_STA_BEACON_POLL); | ||
1049 | mutex_lock(&sdata->local->iflist_mtx); | ||
1050 | ieee80211_recalc_ps(sdata->local, -1); | ||
1051 | mutex_unlock(&sdata->local->iflist_mtx); | ||
1052 | |||
1053 | if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) | ||
1054 | return; | ||
1055 | |||
1056 | /* | ||
1057 | * We've received a probe response, but are not sure whether | ||
1058 | * we have or will be receiving any beacons or data, so let's | ||
1059 | * schedule the timers again, just in case. | ||
1060 | */ | ||
1061 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
1062 | |||
1063 | mod_timer(&ifmgd->conn_mon_timer, | ||
1064 | round_jiffies_up(jiffies + | ||
1065 | IEEE80211_CONNECTION_IDLE_TIME)); | ||
1066 | } | ||
1067 | |||
1068 | void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, | ||
1069 | struct ieee80211_hdr *hdr, bool ack) | ||
1070 | { | ||
1071 | if (!ieee80211_is_data(hdr->frame_control)) | ||
1072 | return; | ||
1073 | |||
1074 | if (ack) | ||
1075 | ieee80211_sta_reset_conn_monitor(sdata); | ||
1076 | |||
1077 | if (ieee80211_is_nullfunc(hdr->frame_control) && | ||
1078 | sdata->u.mgd.probe_send_count > 0) { | ||
1079 | if (ack) | ||
1080 | sdata->u.mgd.probe_send_count = 0; | ||
1081 | else | ||
1082 | sdata->u.mgd.nullfunc_failed = true; | ||
1083 | ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1029 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | 1087 | static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) |
1030 | { | 1088 | { |
1031 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1089 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1041,8 +1099,20 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) | |||
1041 | if (ifmgd->probe_send_count >= unicast_limit) | 1099 | if (ifmgd->probe_send_count >= unicast_limit) |
1042 | dst = NULL; | 1100 | dst = NULL; |
1043 | 1101 | ||
1044 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | 1102 | /* |
1045 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | 1103 | * When the hardware reports an accurate Tx ACK status, it's |
1104 | * better to send a nullfunc frame instead of a probe request, | ||
1105 | * as it will kick us off the AP quickly if we aren't associated | ||
1106 | * anymore. The timeout will be reset if the frame is ACKed by | ||
1107 | * the AP. | ||
1108 | */ | ||
1109 | if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
1110 | ifmgd->nullfunc_failed = false; | ||
1111 | ieee80211_send_nullfunc(sdata->local, sdata, 0); | ||
1112 | } else { | ||
1113 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | ||
1114 | ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); | ||
1115 | } | ||
1046 | 1116 | ||
1047 | ifmgd->probe_send_count++; | 1117 | ifmgd->probe_send_count++; |
1048 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; | 1118 | ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; |
@@ -1108,6 +1178,30 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, | |||
1108 | mutex_unlock(&ifmgd->mtx); | 1178 | mutex_unlock(&ifmgd->mtx); |
1109 | } | 1179 | } |
1110 | 1180 | ||
1181 | struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, | ||
1182 | struct ieee80211_vif *vif) | ||
1183 | { | ||
1184 | struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); | ||
1185 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1186 | struct sk_buff *skb; | ||
1187 | const u8 *ssid; | ||
1188 | |||
1189 | if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) | ||
1190 | return NULL; | ||
1191 | |||
1192 | ASSERT_MGD_MTX(ifmgd); | ||
1193 | |||
1194 | if (!ifmgd->associated) | ||
1195 | return NULL; | ||
1196 | |||
1197 | ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); | ||
1198 | skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, | ||
1199 | ssid + 2, ssid[1], NULL, 0); | ||
1200 | |||
1201 | return skb; | ||
1202 | } | ||
1203 | EXPORT_SYMBOL(ieee80211_ap_probereq_get); | ||
1204 | |||
1111 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) | 1205 | static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) |
1112 | { | 1206 | { |
1113 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | 1207 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |
@@ -1485,29 +1579,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); | 1579 | ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); |
1486 | 1580 | ||
1487 | if (ifmgd->associated && | 1581 | if (ifmgd->associated && |
1488 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && | 1582 | memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0) |
1489 | ifmgd->flags & (IEEE80211_STA_BEACON_POLL | | 1583 | 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 | } | 1584 | } |
1512 | 1585 | ||
1513 | /* | 1586 | /* |
@@ -1845,6 +1918,31 @@ static void ieee80211_sta_timer(unsigned long data) | |||
1845 | ieee80211_queue_work(&local->hw, &sdata->work); | 1918 | ieee80211_queue_work(&local->hw, &sdata->work); |
1846 | } | 1919 | } |
1847 | 1920 | ||
1921 | static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, | ||
1922 | u8 *bssid) | ||
1923 | { | ||
1924 | struct ieee80211_local *local = sdata->local; | ||
1925 | struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||
1926 | |||
1927 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1928 | IEEE80211_STA_BEACON_POLL); | ||
1929 | |||
1930 | ieee80211_set_disassoc(sdata, true, true); | ||
1931 | mutex_unlock(&ifmgd->mtx); | ||
1932 | mutex_lock(&local->mtx); | ||
1933 | ieee80211_recalc_idle(local); | ||
1934 | mutex_unlock(&local->mtx); | ||
1935 | /* | ||
1936 | * must be outside lock due to cfg80211, | ||
1937 | * but that's not a problem. | ||
1938 | */ | ||
1939 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
1940 | IEEE80211_STYPE_DEAUTH, | ||
1941 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
1942 | NULL, true); | ||
1943 | mutex_lock(&ifmgd->mtx); | ||
1944 | } | ||
1945 | |||
1848 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | 1946 | void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) |
1849 | { | 1947 | { |
1850 | struct ieee80211_local *local = sdata->local; | 1948 | struct ieee80211_local *local = sdata->local; |
@@ -1857,12 +1955,49 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1857 | IEEE80211_STA_CONNECTION_POLL) && | 1955 | IEEE80211_STA_CONNECTION_POLL) && |
1858 | ifmgd->associated) { | 1956 | ifmgd->associated) { |
1859 | u8 bssid[ETH_ALEN]; | 1957 | u8 bssid[ETH_ALEN]; |
1958 | int max_tries; | ||
1860 | 1959 | ||
1861 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); | 1960 | memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); |
1862 | if (time_is_after_jiffies(ifmgd->probe_timeout)) | ||
1863 | run_again(ifmgd, ifmgd->probe_timeout); | ||
1864 | 1961 | ||
1865 | else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { | 1962 | if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) |
1963 | max_tries = IEEE80211_MAX_NULLFUNC_TRIES; | ||
1964 | else | ||
1965 | max_tries = IEEE80211_MAX_PROBE_TRIES; | ||
1966 | |||
1967 | /* ACK received for nullfunc probing frame */ | ||
1968 | if (!ifmgd->probe_send_count) | ||
1969 | ieee80211_reset_ap_probe(sdata); | ||
1970 | else if (ifmgd->nullfunc_failed) { | ||
1971 | if (ifmgd->probe_send_count < max_tries) { | ||
1972 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1973 | wiphy_debug(local->hw.wiphy, | ||
1974 | "%s: No ack for nullfunc frame to" | ||
1975 | " AP %pM, try %d\n", | ||
1976 | sdata->name, bssid, | ||
1977 | ifmgd->probe_send_count); | ||
1978 | #endif | ||
1979 | ieee80211_mgd_probe_ap_send(sdata); | ||
1980 | } else { | ||
1981 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1982 | wiphy_debug(local->hw.wiphy, | ||
1983 | "%s: No ack for nullfunc frame to" | ||
1984 | " AP %pM, disconnecting.\n", | ||
1985 | sdata->name, bssid); | ||
1986 | #endif | ||
1987 | ieee80211_sta_connection_lost(sdata, bssid); | ||
1988 | } | ||
1989 | } else if (time_is_after_jiffies(ifmgd->probe_timeout)) | ||
1990 | run_again(ifmgd, ifmgd->probe_timeout); | ||
1991 | else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { | ||
1992 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | ||
1993 | wiphy_debug(local->hw.wiphy, | ||
1994 | "%s: Failed to send nullfunc to AP %pM" | ||
1995 | " after %dms, disconnecting.\n", | ||
1996 | sdata->name, | ||
1997 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | ||
1998 | #endif | ||
1999 | ieee80211_sta_connection_lost(sdata, bssid); | ||
2000 | } else if (ifmgd->probe_send_count < max_tries) { | ||
1866 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 2001 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
1867 | wiphy_debug(local->hw.wiphy, | 2002 | wiphy_debug(local->hw.wiphy, |
1868 | "%s: No probe response from AP %pM" | 2003 | "%s: No probe response from AP %pM" |
@@ -1877,27 +2012,13 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) | |||
1877 | * We actually lost the connection ... or did we? | 2012 | * We actually lost the connection ... or did we? |
1878 | * Let's make sure! | 2013 | * Let's make sure! |
1879 | */ | 2014 | */ |
1880 | ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL | | ||
1881 | IEEE80211_STA_BEACON_POLL); | ||
1882 | wiphy_debug(local->hw.wiphy, | 2015 | wiphy_debug(local->hw.wiphy, |
1883 | "%s: No probe response from AP %pM" | 2016 | "%s: No probe response from AP %pM" |
1884 | " after %dms, disconnecting.\n", | 2017 | " after %dms, disconnecting.\n", |
1885 | sdata->name, | 2018 | sdata->name, |
1886 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); | 2019 | bssid, (1000 * IEEE80211_PROBE_WAIT)/HZ); |
1887 | ieee80211_set_disassoc(sdata, true, true); | 2020 | |
1888 | mutex_unlock(&ifmgd->mtx); | 2021 | ieee80211_sta_connection_lost(sdata, bssid); |
1889 | mutex_lock(&local->mtx); | ||
1890 | ieee80211_recalc_idle(local); | ||
1891 | mutex_unlock(&local->mtx); | ||
1892 | /* | ||
1893 | * must be outside lock due to cfg80211, | ||
1894 | * but that's not a problem. | ||
1895 | */ | ||
1896 | ieee80211_send_deauth_disassoc(sdata, bssid, | ||
1897 | IEEE80211_STYPE_DEAUTH, | ||
1898 | WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, | ||
1899 | NULL, true); | ||
1900 | mutex_lock(&ifmgd->mtx); | ||
1901 | } | 2022 | } |
1902 | } | 2023 | } |
1903 | 2024 | ||
@@ -1988,6 +2109,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) | |||
1988 | add_timer(&ifmgd->timer); | 2109 | add_timer(&ifmgd->timer); |
1989 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) | 2110 | if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running)) |
1990 | add_timer(&ifmgd->chswitch_timer); | 2111 | add_timer(&ifmgd->chswitch_timer); |
2112 | ieee80211_sta_reset_beacon_monitor(sdata); | ||
2113 | ieee80211_restart_sta_timer(sdata); | ||
1991 | } | 2114 | } |
1992 | #endif | 2115 | #endif |
1993 | 2116 | ||