mac80211: improve station mode nullfunc probing
[openwrt/openwrt.git] / package / mac80211 / patches / 311-pending_work.patch
1 --- a/drivers/net/wireless/ath/ath9k/mac.c
2 +++ b/drivers/net/wireless/ath/ath9k/mac.c
3 @@ -766,14 +766,6 @@ void ath9k_hw_startpcureceive(struct ath
4 }
5 EXPORT_SYMBOL(ath9k_hw_startpcureceive);
6
7 -void ath9k_hw_stoppcurecv(struct ath_hw *ah)
8 -{
9 - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS);
10 -
11 - ath9k_hw_disable_mib_counters(ah);
12 -}
13 -EXPORT_SYMBOL(ath9k_hw_stoppcurecv);
14 -
15 void ath9k_hw_abortpcurecv(struct ath_hw *ah)
16 {
17 REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS);
18 --- a/drivers/net/wireless/ath/ath9k/mac.h
19 +++ b/drivers/net/wireless/ath/ath9k/mac.h
20 @@ -691,7 +691,6 @@ void ath9k_hw_setuprxdesc(struct ath_hw
21 bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set);
22 void ath9k_hw_putrxbuf(struct ath_hw *ah, u32 rxdp);
23 void ath9k_hw_startpcureceive(struct ath_hw *ah, bool is_scanning);
24 -void ath9k_hw_stoppcurecv(struct ath_hw *ah);
25 void ath9k_hw_abortpcurecv(struct ath_hw *ah);
26 bool ath9k_hw_stopdmarecv(struct ath_hw *ah);
27 int ath9k_hw_beaconq_setup(struct ath_hw *ah);
28 --- a/drivers/net/wireless/ath/ath9k/recv.c
29 +++ b/drivers/net/wireless/ath/ath9k/recv.c
30 @@ -518,7 +518,7 @@ bool ath_stoprecv(struct ath_softc *sc)
31 bool stopped;
32
33 spin_lock_bh(&sc->rx.rxbuflock);
34 - ath9k_hw_stoppcurecv(ah);
35 + ath9k_hw_abortpcurecv(ah);
36 ath9k_hw_setrxfilter(ah, 0);
37 stopped = ath9k_hw_stopdmarecv(ah);
38
39 --- a/drivers/net/wireless/ath/ath9k/xmit.c
40 +++ b/drivers/net/wireless/ath/ath9k/xmit.c
41 @@ -163,6 +163,7 @@ static void ath_tx_flush_tid(struct ath_
42 bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
43 list_move_tail(&bf->list, &bf_head);
44
45 + spin_unlock_bh(&txq->axq_lock);
46 fi = get_frame_info(bf->bf_mpdu);
47 if (fi->retries) {
48 ath_tx_update_baw(sc, tid, fi->seqno);
49 @@ -170,6 +171,7 @@ static void ath_tx_flush_tid(struct ath_
50 } else {
51 ath_tx_send_normal(sc, txq, tid, &bf_head);
52 }
53 + spin_lock_bh(&txq->axq_lock);
54 }
55
56 spin_unlock_bh(&txq->axq_lock);
57 --- a/net/mac80211/ieee80211_i.h
58 +++ b/net/mac80211/ieee80211_i.h
59 @@ -349,6 +349,7 @@ struct ieee80211_if_managed {
60 struct work_struct chswitch_work;
61 struct work_struct beacon_connection_loss_work;
62
63 + unsigned long beacon_timeout;
64 unsigned long probe_timeout;
65 int probe_send_count;
66
67 @@ -1269,6 +1270,8 @@ void ieee80211_send_nullfunc(struct ieee
68 int powersave);
69 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
70 struct ieee80211_hdr *hdr);
71 +void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
72 + struct ieee80211_hdr *hdr);
73 void ieee80211_beacon_connection_loss_work(struct work_struct *work);
74
75 void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
76 --- a/net/mac80211/mlme.c
77 +++ b/net/mac80211/mlme.c
78 @@ -28,13 +28,19 @@
79 #include "rate.h"
80 #include "led.h"
81
82 +#define IEEE80211_MAX_NULLFUNC_TRIES 2
83 #define IEEE80211_MAX_PROBE_TRIES 5
84
85 /*
86 - * beacon loss detection timeout
87 - * XXX: should depend on beacon interval
88 + * Beacon loss timeout is calculated as N frames times the
89 + * advertised beacon interval. This may need to be somewhat
90 + * higher than what hardware might detect to account for
91 + * delays in the host processing frames. But since we also
92 + * probe on beacon miss before declaring the connection lost
93 + * default to what we want.
94 */
95 -#define IEEE80211_BEACON_LOSS_TIME (2 * HZ)
96 +#define IEEE80211_BEACON_LOSS_COUNT 7
97 +
98 /*
99 * Time the connection can be idle before we probe
100 * it to see if we can still talk to the AP.
101 @@ -121,7 +127,7 @@ void ieee80211_sta_reset_beacon_monitor(
102 return;
103
104 mod_timer(&sdata->u.mgd.bcn_mon_timer,
105 - round_jiffies_up(jiffies + IEEE80211_BEACON_LOSS_TIME));
106 + round_jiffies_up(jiffies + sdata->u.mgd.beacon_timeout));
107 }
108
109 void ieee80211_sta_reset_conn_monitor(struct ieee80211_sub_if_data *sdata)
110 @@ -871,6 +877,9 @@ static void ieee80211_set_associated(str
111 bss_info_changed |= ieee80211_handle_bss_capability(sdata,
112 cbss->capability, bss->has_erp_value, bss->erp_value);
113
114 + sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec(
115 + IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int));
116 +
117 sdata->u.mgd.associated = cbss;
118 memcpy(sdata->u.mgd.bssid, cbss->bssid, ETH_ALEN);
119
120 @@ -1026,6 +1035,51 @@ void ieee80211_sta_rx_notify(struct ieee
121 ieee80211_sta_reset_conn_monitor(sdata);
122 }
123
124 +static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
125 +{
126 + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
127 +
128 + if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
129 + IEEE80211_STA_CONNECTION_POLL)))
130 + return;
131 +
132 + ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
133 + IEEE80211_STA_BEACON_POLL);
134 + mutex_lock(&sdata->local->iflist_mtx);
135 + ieee80211_recalc_ps(sdata->local, -1);
136 + mutex_unlock(&sdata->local->iflist_mtx);
137 +
138 + if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
139 + return;
140 +
141 + /*
142 + * We've received a probe response, but are not sure whether
143 + * we have or will be receiving any beacons or data, so let's
144 + * schedule the timers again, just in case.
145 + */
146 + ieee80211_sta_reset_beacon_monitor(sdata);
147 +
148 + mod_timer(&ifmgd->conn_mon_timer,
149 + round_jiffies_up(jiffies +
150 + IEEE80211_CONNECTION_IDLE_TIME));
151 +}
152 +
153 +void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
154 + struct ieee80211_hdr *hdr)
155 +{
156 + if (!ieee80211_is_data(hdr->frame_control) &&
157 + !ieee80211_is_nullfunc(hdr->frame_control))
158 + return;
159 +
160 + ieee80211_sta_reset_conn_monitor(sdata);
161 +
162 + if (ieee80211_is_nullfunc(hdr->frame_control) &&
163 + sdata->u.mgd.probe_send_count > 0) {
164 + sdata->u.mgd.probe_send_count = 0;
165 + ieee80211_queue_work(&sdata->local->hw, &sdata->work);
166 + }
167 +}
168 +
169 static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
170 {
171 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
172 @@ -1041,8 +1095,19 @@ static void ieee80211_mgd_probe_ap_send(
173 if (ifmgd->probe_send_count >= unicast_limit)
174 dst = NULL;
175
176 - ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
177 - ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0);
178 + /*
179 + * When the hardware reports an accurate Tx ACK status, it's
180 + * better to send a nullfunc frame instead of a probe request,
181 + * as it will kick us off the AP quickly if we aren't associated
182 + * anymore. The timeout will be reset if the frame is ACKed by
183 + * the AP.
184 + */
185 + if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
186 + ieee80211_send_nullfunc(sdata->local, sdata, 0);
187 + else {
188 + ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
189 + ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0);
190 + }
191
192 ifmgd->probe_send_count++;
193 ifmgd->probe_timeout = jiffies + IEEE80211_PROBE_WAIT;
194 @@ -1509,29 +1574,8 @@ static void ieee80211_rx_mgmt_probe_resp
195 ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
196
197 if (ifmgd->associated &&
198 - memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0 &&
199 - ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
200 - IEEE80211_STA_CONNECTION_POLL)) {
201 - ifmgd->flags &= ~(IEEE80211_STA_CONNECTION_POLL |
202 - IEEE80211_STA_BEACON_POLL);
203 - mutex_lock(&sdata->local->iflist_mtx);
204 - ieee80211_recalc_ps(sdata->local, -1);
205 - mutex_unlock(&sdata->local->iflist_mtx);
206 -
207 - if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
208 - return;
209 -
210 - /*
211 - * We've received a probe response, but are not sure whether
212 - * we have or will be receiving any beacons or data, so let's
213 - * schedule the timers again, just in case.
214 - */
215 - ieee80211_sta_reset_beacon_monitor(sdata);
216 -
217 - mod_timer(&ifmgd->conn_mon_timer,
218 - round_jiffies_up(jiffies +
219 - IEEE80211_CONNECTION_IDLE_TIME));
220 - }
221 + memcmp(mgmt->bssid, ifmgd->associated->bssid, ETH_ALEN) == 0)
222 + ieee80211_reset_ap_probe(sdata);
223 }
224
225 /*
226 @@ -1881,12 +1925,23 @@ void ieee80211_sta_work(struct ieee80211
227 IEEE80211_STA_CONNECTION_POLL) &&
228 ifmgd->associated) {
229 u8 bssid[ETH_ALEN];
230 + int max_tries;
231 +
232 + if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
233 + max_tries = IEEE80211_MAX_NULLFUNC_TRIES;
234 + else
235 + max_tries = IEEE80211_MAX_PROBE_TRIES;
236
237 memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN);
238 - if (time_is_after_jiffies(ifmgd->probe_timeout))
239 +
240 + /* ACK received for nullfunc probing frame */
241 + if (!ifmgd->probe_send_count)
242 + ieee80211_reset_ap_probe(sdata);
243 +
244 + else if (time_is_after_jiffies(ifmgd->probe_timeout))
245 run_again(ifmgd, ifmgd->probe_timeout);
246
247 - else if (ifmgd->probe_send_count < IEEE80211_MAX_PROBE_TRIES) {
248 + else if (ifmgd->probe_send_count < max_tries) {
249 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
250 wiphy_debug(local->hw.wiphy,
251 "%s: No probe response from AP %pM"
252 @@ -2012,6 +2067,8 @@ void ieee80211_sta_restart(struct ieee80
253 add_timer(&ifmgd->timer);
254 if (test_and_clear_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running))
255 add_timer(&ifmgd->chswitch_timer);
256 + ieee80211_sta_reset_beacon_monitor(sdata);
257 + ieee80211_send_nullfunc(sdata->local, sdata, 0);
258 }
259 #endif
260
261 --- a/net/mac80211/status.c
262 +++ b/net/mac80211/status.c
263 @@ -155,6 +155,10 @@ static void ieee80211_frame_acked(struct
264
265 ieee80211_queue_work(&local->hw, &local->recalc_smps);
266 }
267 +
268 + if ((sdata->vif.type == NL80211_IFTYPE_STATION) &&
269 + (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS))
270 + ieee80211_sta_tx_notify(sdata, (void *) skb->data);
271 }
272
273 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)