aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2010-11-22 21:10:31 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-11-24 16:19:35 -0500
commit4e5ff37692df35c8826f1291204841b174d3c3ce (patch)
tree2a4cd6250de19b1e7b895e94136c537c78bcd928 /net
parentdd5b4cc71cd09c33e1579cc6d5720656e94e52de (diff)
mac80211: use nullfunc instead of probe request for connection monitoring
nullfunc frames are better for connection monitoring, because probe requests are answered even if the AP has already dropped the connection, whereas nullfunc frames from an unassociated station will trigger a disassoc/deauth frame from the AP (WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA), which allows the station to reconnect immediately instead of waiting until it attempts to transmit the next unicast frame. This only works on hardware with reliable tx ACK reporting, any other hardware needs to fall back to the probe request method. Signed-off-by: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/ieee80211_i.h2
-rw-r--r--net/mac80211/mlme.c92
-rw-r--r--net/mac80211/status.c4
3 files changed, 72 insertions, 26 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ff7bc307827b..5bc0745368fe 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1265,6 +1265,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
1265 int powersave); 1265 int powersave);
1266void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, 1266void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
1267 struct ieee80211_hdr *hdr); 1267 struct ieee80211_hdr *hdr);
1268void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
1269 struct ieee80211_hdr *hdr);
1268void ieee80211_beacon_connection_loss_work(struct work_struct *work); 1270void ieee80211_beacon_connection_loss_work(struct work_struct *work);
1269 1271
1270void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, 1272void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 849d9c639add..33ffce3ec605 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1034,6 +1034,51 @@ void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
1034 ieee80211_sta_reset_conn_monitor(sdata); 1034 ieee80211_sta_reset_conn_monitor(sdata);
1035} 1035}
1036 1036
1037static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
1038{
1039 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1040
1041 if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
1042 IEEE80211_STA_CONNECTION_POLL)))
1043 return;
1044
1045 ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
1046 IEEE80211_STA_BEACON_POLL);
1047 mutex_lock(&sdata->local->iflist_mtx);
1048 ieee80211_recalc_ps(sdata->local, -1);
1049 mutex_unlock(&sdata->local->iflist_mtx);
1050
1051 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
1052 return;
1053
1054 /*
1055 * We've received a probe response, but are not sure whether
1056 * we have or will be receiving any beacons or data, so let's
1057 * schedule the timers again, just in case.
1058 */
1059 ieee80211_sta_reset_beacon_monitor(sdata);
1060
1061 mod_timer(&ifmgd->conn_mon_timer,
1062 round_jiffies_up(jiffies +
1063 IEEE80211_CONNECTION_IDLE_TIME));
1064}
1065
1066void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
1067 struct ieee80211_hdr *hdr)
1068{
1069 if (!ieee80211_is_data(hdr->frame_control) &&
1070 !ieee80211_is_nullfunc(hdr->frame_control))
1071 return;
1072
1073 ieee80211_sta_reset_conn_monitor(sdata);
1074
1075 if (ieee80211_is_nullfunc(hdr->frame_control) &&
1076 sdata->u.mgd.probe_send_count > 0) {
1077 sdata->u.mgd.probe_send_count = 0;
1078 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
1079 }
1080}
1081
1037static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata) 1082static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
1038{ 1083{
1039 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1084 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -1049,8 +1094,19 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
1049 if (ifmgd->probe_send_count >= unicast_limit) 1094 if (ifmgd->probe_send_count >= unicast_limit)
1050 dst = NULL; 1095 dst = NULL;
1051 1096
1052 ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); 1097 /*
1053 ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0); 1098 * When the hardware reports an accurate Tx ACK status, it's
1099 * better to send a nullfunc frame instead of a probe request,
1100 * as it will kick us off the AP quickly if we aren't associated
1101 * anymore. The timeout will be reset if the frame is ACKed by
1102 * the AP.
1103 */
1104 if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
1105 ieee80211_send_nullfunc(sdata->local, sdata, 0);
1106 else {
1107 ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
1108 ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0);
1109 }
1054 1110
1055 ifmgd->probe_send_count++; 1111 ifmgd->probe_send_count++;
1056 ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT; 1112 ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
@@ -1517,29 +1573,8 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
1517 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false); 1573 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
1518 1574
1519 if (ifmgd->associated && 1575 if (ifmgd->associated &&
1520 memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 && 1576 memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0)
1521 ifmgd->flags & (IEEE80211_STA_BEACON_POLL | 1577 ieee80211_reset_ap_probe(sdata);
1522 IEEE80211_STA_CONNECTION_POLL)) {
1523 ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
1524 IEEE80211_STA_BEACON_POLL);
1525 mutex_lock(&sdata->local->iflist_mtx);
1526 ieee80211_recalc_ps(sdata->local, -1);
1527 mutex_unlock(&sdata->local->iflist_mtx);
1528
1529 if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
1530 return;
1531
1532 /*
1533 * We've received a probe response, but are not sure whether
1534 * we have or will be receiving any beacons or data, so let's
1535 * schedule the timers again, just in case.
1536 */
1537 ieee80211_sta_reset_beacon_monitor(sdata);
1538
1539 mod_timer(&ifmgd->conn_mon_timer,
1540 round_jiffies_up(jiffies +
1541 IEEE80211_CONNECTION_IDLE_TIME));
1542 }
1543} 1578}
1544 1579
1545/* 1580/*
@@ -1891,7 +1926,12 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
1891 u8 bssid[ETH_ALEN]; 1926 u8 bssid[ETH_ALEN];
1892 1927
1893 memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); 1928 memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
1894 if (time_is_after_jiffies(ifmgd->probe_timeout)) 1929
1930 /* ACK received for nullfunc probing frame */
1931 if (!ifmgd->probe_send_count)
1932 ieee80211_reset_ap_probe(sdata);
1933
1934 else if (time_is_after_jiffies(ifmgd->probe_timeout))
1895 run_again(ifmgd, ifmgd->probe_timeout); 1935 run_again(ifmgd, ifmgd->probe_timeout);
1896 1936
1897 else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) { 1937 else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 3153c19893b8..8695cd11dfd9 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -155,6 +155,10 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
155 155
156 ieee80211_queue_work(&local->hw, &local->recalc_smps); 156 ieee80211_queue_work(&local->hw, &local->recalc_smps);
157 } 157 }
158
159 if ((sdata->vif.type == NL80211_IFTYPE_STATION) &&
160 (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
161 ieee80211_sta_tx_notify(sdata, (void *) skb->data);
158} 162}
159 163
160void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) 164void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)