1 commit 930b0dffd1731f3f418f9132faea720a23b7af61
2 Author: Johannes Berg <johannes.berg@intel.com>
3 Date: Tue Jun 3 11:18:47 2014 +0200
5 mac80211: fix station/driver powersave race
7 It is currently possible to have a race due to the station PS
8 unblock work like this:
9 * station goes to sleep with frames buffered in the driver
10 * driver blocks wakeup
11 * station wakes up again
12 * driver flushes/returns frames, and unblocks, which schedules
14 * unblock work starts to run, and checks that the station is
15 awake (i.e. that the WLAN_STA_PS_STA flag isn't set)
16 * we process a received frame with PM=1, setting the flag again
17 * ieee80211_sta_ps_deliver_wakeup() runs, delivering all frames
18 to the driver, and then clearing the WLAN_STA_PS_DRIVER and
21 In this scenario, mac80211 will think that the station is awake,
22 while it really is asleep, and any TX'ed frames should be filtered
23 by the device (it will know that the station is sleeping) but then
24 passed to mac80211 again, which will not buffer it either as it
25 thinks the station is awake, and eventually the packets will be
28 Fix this by moving the clearing of the flags to exactly where we
29 learn about the situation. This creates a problem of reordering,
30 so introduce another flag indicating that delivery is being done,
31 this new flag also queues frames and is cleared only while the
32 spinlock is held (which the queuing code also holds) so that any
33 concurrent delivery/TX is handled correctly.
35 Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
36 Signed-off-by: Johannes Berg <johannes.berg@intel.com>
38 commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873
39 Author: Felix Fietkau <nbd@openwrt.org>
40 Date: Fri May 23 19:58:14 2014 +0200
42 mac80211: reduce packet loss notifications under load
44 During strong signal fluctuations under high throughput, few consecutive
45 failed A-MPDU transmissions can easily trigger packet loss notification,
46 and thus (in AP mode) client disconnection.
48 Reduce the number of false positives by checking the A-MPDU status flag
49 and treating a failed A-MPDU as a single packet.
51 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
53 commit 7b7843a36fbcc568834404c7430ff895d8502131
54 Author: Felix Fietkau <nbd@openwrt.org>
55 Date: Fri May 23 19:26:32 2014 +0200
57 mac80211: fix a memory leak on sta rate selection table
59 Cc: stable@vger.kernel.org
60 Reported-by: Christophe Prévotaux <cprevotaux@nltinc.com>
61 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
63 commit 96892d6aa0a153423070addf3070bc79578b3897
64 Author: Felix Fietkau <nbd@openwrt.org>
65 Date: Mon May 19 21:20:49 2014 +0200
67 ath9k: avoid passing buffers to the hardware during flush
69 The commit "ath9k: fix possible hang on flush" changed the receive code
70 to always link rx descriptors of processed frames, even when flushing.
71 In some cases, this leads to flushed rx buffers being passed to the
72 hardware while rx is already stopped.
74 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
76 --- a/drivers/net/wireless/ath/ath9k/recv.c
77 +++ b/drivers/net/wireless/ath/ath9k/recv.c
78 @@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee
79 * buffer (or rx fifo). This can incorrectly acknowledge packets
80 * to a sender if last desc is self-linked.
82 -static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf)
83 +static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf,
86 struct ath_hw *ah = sc->sc_ah;
87 struct ath_common *common = ath9k_hw_common(ah);
88 @@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s
92 - if (sc->rx.rxlink == NULL)
93 - ath9k_hw_putrxbuf(ah, bf->bf_daddr);
96 *sc->rx.rxlink = bf->bf_daddr;
98 + ath9k_hw_putrxbuf(ah, bf->bf_daddr);
100 sc->rx.rxlink = &ds->ds_link;
103 -static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf)
104 +static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf,
108 - ath_rx_buf_link(sc, sc->rx.buf_hold);
109 + ath_rx_buf_link(sc, sc->rx.buf_hold, flush);
111 sc->rx.buf_hold = bf;
113 @@ -442,7 +444,7 @@ int ath_startrecv(struct ath_softc *sc)
114 sc->rx.buf_hold = NULL;
115 sc->rx.rxlink = NULL;
116 list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) {
117 - ath_rx_buf_link(sc, bf);
118 + ath_rx_buf_link(sc, bf, false);
121 /* We could have deleted elements so the list may be empty now */
122 @@ -1118,12 +1120,12 @@ requeue_drop_frag:
124 list_add_tail(&bf->list, &sc->rx.rxbuf);
127 - ath_rx_edma_buf_link(sc, qtype);
129 - ath_rx_buf_relink(sc, bf);
131 + ath_rx_buf_relink(sc, bf, flush);
134 + } else if (!flush) {
135 + ath_rx_edma_buf_link(sc, qtype);
139 --- a/net/mac80211/sta_info.c
140 +++ b/net/mac80211/sta_info.c
141 @@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct
144 if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
145 - test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
146 + test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
147 + test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
148 if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
149 sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
150 ps = &sdata->bss->ps;
151 @@ -111,6 +112,7 @@ static void __cleanup_single_sta(struct
153 clear_sta_flag(sta, WLAN_STA_PS_STA);
154 clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
155 + clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
157 atomic_dec(&ps->num_sta_ps);
158 sta_info_recalc_tim(sta);
159 @@ -125,7 +127,7 @@ static void __cleanup_single_sta(struct
160 if (ieee80211_vif_is_mesh(&sdata->vif))
161 mesh_sta_cleanup(sta);
163 - cancel_work_sync(&sta->drv_unblock_wk);
164 + cancel_work_sync(&sta->drv_deliver_wk);
167 * Destroy aggregation state here. It would be nice to wait for the
168 @@ -227,6 +229,7 @@ struct sta_info *sta_info_get_by_idx(str
170 void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
172 + struct ieee80211_sta_rates *rates;
176 @@ -238,6 +241,10 @@ void sta_info_free(struct ieee80211_loca
180 + rates = rcu_dereference_protected(sta->sta.rates, true);
184 sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);
187 @@ -252,33 +259,23 @@ static void sta_info_hash_add(struct iee
188 rcu_assign_pointer(local->sta_hash[STA_HASH(sta->sta.addr)], sta);
191 -static void sta_unblock(struct work_struct *wk)
192 +static void sta_deliver_ps_frames(struct work_struct *wk)
194 struct sta_info *sta;
196 - sta = container_of(wk, struct sta_info, drv_unblock_wk);
197 + sta = container_of(wk, struct sta_info, drv_deliver_wk);
202 - if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
203 - local_bh_disable();
204 + local_bh_disable();
205 + if (!test_sta_flag(sta, WLAN_STA_PS_STA))
206 ieee80211_sta_ps_deliver_wakeup(sta);
208 - } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) {
209 - clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
211 - local_bh_disable();
212 + else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL))
213 ieee80211_sta_ps_deliver_poll_response(sta);
215 - } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) {
216 - clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
218 - local_bh_disable();
219 + else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD))
220 ieee80211_sta_ps_deliver_uapsd(sta);
223 - clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
227 static int sta_prepare_rate_control(struct ieee80211_local *local,
228 @@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i
230 spin_lock_init(&sta->lock);
231 spin_lock_init(&sta->ps_lock);
232 - INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
233 + INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
234 INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
235 mutex_init(&sta->ampdu_mlme.mtx);
236 #ifdef CPTCFG_MAC80211_MESH
237 @@ -1140,8 +1137,15 @@ void ieee80211_sta_ps_deliver_wakeup(str
240 ieee80211_add_pending_skbs(local, &pending);
241 - clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
242 - clear_sta_flag(sta, WLAN_STA_PS_STA);
244 + /* now we're no longer in the deliver code */
245 + clear_sta_flag(sta, WLAN_STA_PS_DELIVER);
247 + /* The station might have polled and then woken up before we responded,
248 + * so clear these flags now to avoid them sticking around.
250 + clear_sta_flag(sta, WLAN_STA_PSPOLL);
251 + clear_sta_flag(sta, WLAN_STA_UAPSD);
252 spin_unlock(&sta->ps_lock);
254 atomic_dec(&ps->num_sta_ps);
255 @@ -1542,10 +1546,26 @@ void ieee80211_sta_block_awake(struct ie
257 trace_api_sta_block_awake(sta->local, pubsta, block);
261 set_sta_flag(sta, WLAN_STA_PS_DRIVER);
262 - else if (test_sta_flag(sta, WLAN_STA_PS_DRIVER))
263 - ieee80211_queue_work(hw, &sta->drv_unblock_wk);
267 + if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER))
270 + if (!test_sta_flag(sta, WLAN_STA_PS_STA)) {
271 + set_sta_flag(sta, WLAN_STA_PS_DELIVER);
272 + clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
273 + ieee80211_queue_work(hw, &sta->drv_deliver_wk);
274 + } else if (test_sta_flag(sta, WLAN_STA_PSPOLL) ||
275 + test_sta_flag(sta, WLAN_STA_UAPSD)) {
276 + /* must be asleep in this case */
277 + clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
278 + ieee80211_queue_work(hw, &sta->drv_deliver_wk);
280 + clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
283 EXPORT_SYMBOL(ieee80211_sta_block_awake);
285 --- a/net/mac80211/status.c
286 +++ b/net/mac80211/status.c
287 @@ -541,6 +541,23 @@ static void ieee80211_tx_latency_end_msr
289 #define STA_LOST_PKT_THRESHOLD 50
291 +static void ieee80211_lost_packet(struct sta_info *sta, struct sk_buff *skb)
293 + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
295 + /* This packet was aggregated but doesn't carry status info */
296 + if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
297 + !(info->flags & IEEE80211_TX_STAT_AMPDU))
300 + if (++sta->lost_packets < STA_LOST_PKT_THRESHOLD)
303 + cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
304 + sta->lost_packets, GFP_ATOMIC);
305 + sta->lost_packets = 0;
308 void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
310 struct sk_buff *skb2;
311 @@ -680,12 +697,8 @@ void ieee80211_tx_status(struct ieee8021
312 if (info->flags & IEEE80211_TX_STAT_ACK) {
313 if (sta->lost_packets)
314 sta->lost_packets = 0;
315 - } else if (++sta->lost_packets >= STA_LOST_PKT_THRESHOLD) {
316 - cfg80211_cqm_pktloss_notify(sta->sdata->dev,
320 - sta->lost_packets = 0;
322 + ieee80211_lost_packet(sta, skb);
326 --- a/net/mac80211/rx.c
327 +++ b/net/mac80211/rx.c
328 @@ -1107,6 +1107,8 @@ static void sta_ps_end(struct sta_info *
332 + set_sta_flag(sta, WLAN_STA_PS_DELIVER);
333 + clear_sta_flag(sta, WLAN_STA_PS_STA);
334 ieee80211_sta_ps_deliver_wakeup(sta);
337 --- a/net/mac80211/sta_info.h
338 +++ b/net/mac80211/sta_info.h
339 @@ -82,6 +82,7 @@ enum ieee80211_sta_info_flags {
340 WLAN_STA_TOFFSET_KNOWN,
342 WLAN_STA_MPSP_RECIPIENT,
343 + WLAN_STA_PS_DELIVER,
346 #define ADDBA_RESP_INTERVAL HZ
347 @@ -265,7 +266,7 @@ struct ieee80211_tx_latency_stat {
348 * @last_rx_rate_vht_nss: rx status nss of last data packet
349 * @lock: used for locking all fields that require locking, see comments
350 * in the header file.
351 - * @drv_unblock_wk: used for driver PS unblocking
352 + * @drv_deliver_wk: used for delivering frames after driver PS unblocking
353 * @listen_interval: listen interval of this station, when we're acting as AP
354 * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
355 * @ps_lock: used for powersave (when mac80211 is the AP) related locking
356 @@ -345,7 +346,7 @@ struct sta_info {
357 void *rate_ctrl_priv;
360 - struct work_struct drv_unblock_wk;
361 + struct work_struct drv_deliver_wk;
365 --- a/net/mac80211/tx.c
366 +++ b/net/mac80211/tx.c
367 @@ -469,7 +469,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
370 if (unlikely((test_sta_flag(sta, WLAN_STA_PS_STA) ||
371 - test_sta_flag(sta, WLAN_STA_PS_DRIVER)) &&
372 + test_sta_flag(sta, WLAN_STA_PS_DRIVER) ||
373 + test_sta_flag(sta, WLAN_STA_PS_DELIVER)) &&
374 !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
375 int ac = skb_get_queue_mapping(tx->skb);
377 @@ -486,7 +487,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
378 * ahead and Tx the packet.
380 if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
381 - !test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
382 + !test_sta_flag(sta, WLAN_STA_PS_DRIVER) &&
383 + !test_sta_flag(sta, WLAN_STA_PS_DELIVER)) {
384 spin_unlock(&sta->ps_lock);