Changeset 40995


Ignore:
Timestamp:
2014-06-03T15:59:43+02:00 (4 years ago)
Author:
nbd
Message:

mac80211: backport a powersave related fix

Signed-off-by: Felix Fietkau <nbd@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/package/kernel/mac80211/patches/300-pending_work.patch

    r40834 r40995  
     1commit 930b0dffd1731f3f418f9132faea720a23b7af61 
     2Author: Johannes Berg <johannes.berg@intel.com> 
     3Date:   Tue Jun 3 11:18:47 2014 +0200 
     4 
     5    mac80211: fix station/driver powersave race 
     6     
     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 
     13       the unblock work 
     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 
     19       WLAN_STA_PS_STA flags 
     20     
     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 
     26    dropped. 
     27     
     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. 
     34     
     35    Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com> 
     36    Signed-off-by: Johannes Berg <johannes.berg@intel.com> 
     37 
    138commit 6df35206bc6c1c6aad1d8077df5786b4a7f77873 
    239Author: Felix Fietkau <nbd@openwrt.org> 
     
    102139--- a/net/mac80211/sta_info.c 
    103140+++ b/net/mac80211/sta_info.c 
    104 @@ -227,6 +227,7 @@ struct sta_info *sta_info_get_by_idx(str 
     141@@ -100,7 +100,8 @@ static void __cleanup_single_sta(struct  
     142        struct ps_data *ps; 
     143  
     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  
     152  
     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); 
     156  
     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); 
     162  
     163-       cancel_work_sync(&sta->drv_unblock_wk); 
     164+       cancel_work_sync(&sta->drv_deliver_wk); 
     165  
     166        /* 
     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 
    105169  */ 
    106170 void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) 
     
    110174  
    111175        if (sta->rate_ctrl) 
    112 @@ -238,6 +239,10 @@ void sta_info_free(struct ieee80211_loca 
     176@@ -238,6 +241,10 @@ void sta_info_free(struct ieee80211_loca 
    113177                kfree(sta->tx_lat); 
    114178        } 
     
    121185  
    122186        kfree(sta); 
     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); 
     189 } 
     190  
     191-static void sta_unblock(struct work_struct *wk) 
     192+static void sta_deliver_ps_frames(struct work_struct *wk) 
     193 { 
     194        struct sta_info *sta; 
     195  
     196-       sta = container_of(wk, struct sta_info, drv_unblock_wk); 
     197+       sta = container_of(wk, struct sta_info, drv_deliver_wk); 
     198  
     199        if (sta->dead) 
     200                return; 
     201  
     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); 
     207-               local_bh_enable(); 
     208-       } else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) { 
     209-               clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 
     210- 
     211-               local_bh_disable(); 
     212+       else if (test_and_clear_sta_flag(sta, WLAN_STA_PSPOLL)) 
     213                ieee80211_sta_ps_deliver_poll_response(sta); 
     214-               local_bh_enable(); 
     215-       } else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) { 
     216-               clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 
     217- 
     218-               local_bh_disable(); 
     219+       else if (test_and_clear_sta_flag(sta, WLAN_STA_UAPSD)) 
     220                ieee80211_sta_ps_deliver_uapsd(sta); 
     221-               local_bh_enable(); 
     222-       } else 
     223-               clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 
     224+       local_bh_enable(); 
     225 } 
     226  
     227 static int sta_prepare_rate_control(struct ieee80211_local *local, 
     228@@ -340,7 +337,7 @@ struct sta_info *sta_info_alloc(struct i 
     229  
     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 
     238        } 
     239  
     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); 
     243+ 
     244+       /* now we're no longer in the deliver code */ 
     245+       clear_sta_flag(sta, WLAN_STA_PS_DELIVER); 
     246+ 
     247+       /* The station might have polled and then woken up before we responded, 
     248+        * so clear these flags now to avoid them sticking around. 
     249+        */ 
     250+       clear_sta_flag(sta, WLAN_STA_PSPOLL); 
     251+       clear_sta_flag(sta, WLAN_STA_UAPSD); 
     252        spin_unlock(&sta->ps_lock); 
     253  
     254        atomic_dec(&ps->num_sta_ps); 
     255@@ -1542,10 +1546,26 @@ void ieee80211_sta_block_awake(struct ie 
     256  
     257        trace_api_sta_block_awake(sta->local, pubsta, block); 
     258  
     259-       if (block) 
     260+       if (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); 
     264+               return; 
     265+       } 
     266+ 
     267+       if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) 
     268+               return; 
     269+ 
     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); 
     279+       } else { 
     280+               clear_sta_flag(sta, WLAN_STA_PS_DRIVER); 
     281+       } 
     282 } 
     283 EXPORT_SYMBOL(ieee80211_sta_block_awake); 
     284  
    123285--- a/net/mac80211/status.c 
    124286+++ b/net/mac80211/status.c 
     
    162324                } 
    163325  
     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 * 
     329                return; 
     330        } 
     331  
     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); 
     335 } 
     336  
     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, 
     341        WLAN_STA_MPSP_OWNER, 
     342        WLAN_STA_MPSP_RECIPIENT, 
     343+       WLAN_STA_PS_DELIVER, 
     344 }; 
     345  
     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; 
     358        spinlock_t lock; 
     359  
     360-       struct work_struct drv_unblock_wk; 
     361+       struct work_struct drv_deliver_wk; 
     362  
     363        u16 listen_interval; 
     364  
     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 
     368                return TX_CONTINUE; 
     369  
     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); 
     376  
     377@@ -486,7 +487,8 @@ ieee80211_tx_h_unicast_ps_buf(struct iee 
     378                 * ahead and Tx the packet. 
     379                 */ 
     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); 
     385                        return TX_CONTINUE; 
     386                } 
Note: See TracChangeset for help on using the changeset viewer.