mac80211: fix mesh sta teardown
authorThomas Pedersen <thomas@cozybit.com>
Wed, 6 Feb 2013 18:17:21 +0000 (10:17 -0800)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 11 Feb 2013 17:44:54 +0000 (18:44 +0100)
The patch "mac80211: clean up mesh sta allocation warning"
moved some mesh initialization into a path which is only
called when the kernel handles peering. This causes a hang
when mac80211 tries to clean up a userspace-allocated
station entry and delete a timer which has never been
initialized.

To avoid this, only do any mesh sta peering teardown if
the kernel is actually handling it.

The same is true when quiescing before suspend.

Signed-off-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/sta_info.c

index 35ac388714203a87322fed44e9487159b56d3e29..0c51b78b8fdc12310fbcc3ad1d9552073ba1b41a 100644 (file)
@@ -149,6 +149,31 @@ u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
        return changed;
 }
 
+/*
+ * mesh_sta_cleanup - clean up any mesh sta state
+ *
+ * @sta: mesh sta to clean up.
+ */
+void mesh_sta_cleanup(struct sta_info *sta)
+{
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+       u32 changed;
+
+       /*
+        * maybe userspace handles peer allocation and peering, but in either
+        * case the beacon is still generated by the kernel and we might need
+        * an update.
+        */
+       changed = mesh_accept_plinks_update(sdata);
+       if (sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
+               changed |= mesh_plink_deactivate(sta);
+               del_timer_sync(&sta->plink_timer);
+       }
+
+       if (changed)
+               ieee80211_bss_info_change_notify(sdata, changed);
+}
+
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
 {
        int i;
index eb336253b6b392ec531a81def0dcffae796870e1..3b9d862744bade8d4cf972b7b70159d1f48fcd32 100644 (file)
@@ -288,12 +288,13 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
 bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
 u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
 void mesh_plink_broken(struct sta_info *sta);
-void mesh_plink_deactivate(struct sta_info *sta);
+u32 mesh_plink_deactivate(struct sta_info *sta);
 int mesh_plink_open(struct sta_info *sta);
 void mesh_plink_block(struct sta_info *sta);
 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
                         struct ieee80211_mgmt *mgmt, size_t len,
                         struct ieee80211_rx_status *rx_status);
+void mesh_sta_cleanup(struct sta_info *sta);
 
 /* Private interfaces */
 /* Mesh tables */
index 67524e7d2548bb7a7901c9834acee8b9e29d6939..56c9b318a97e7f599542fd4e674795c385423b97 100644 (file)
@@ -214,7 +214,7 @@ static u32 __mesh_plink_deactivate(struct sta_info *sta)
  *
  * All mesh paths with this peer as next hop will be flushed
  */
-void mesh_plink_deactivate(struct sta_info *sta)
+u32 mesh_plink_deactivate(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        u32 changed;
@@ -227,7 +227,7 @@ void mesh_plink_deactivate(struct sta_info *sta)
                            sta->reason);
        spin_unlock_bh(&sta->lock);
 
-       ieee80211_bss_info_change_notify(sdata, changed);
+       return changed;
 }
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@@ -595,6 +595,10 @@ void mesh_plink_quiesce(struct sta_info *sta)
        if (!ieee80211_vif_is_mesh(&sta->sdata->vif))
                return;
 
+       /* no kernel mesh sta timers have been initialized */
+       if (sta->sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)
+               return;
+
        if (del_timer_sync(&sta->plink_timer))
                sta->plink_timer_was_running = true;
 }
index 47a0f060176861cba62aa97db1784cb270ea43fd..19db20a58e23d69bc857ffcb5e8d60cecd8e592f 100644 (file)
@@ -137,13 +137,8 @@ static void cleanup_single_sta(struct sta_info *sta)
                ieee80211_purge_tx_queue(&local->hw, &sta->tx_filtered[ac]);
        }
 
-#ifdef CONFIG_MAC80211_MESH
-       if (ieee80211_vif_is_mesh(&sdata->vif)) {
-               mesh_accept_plinks_update(sdata);
-               mesh_plink_deactivate(sta);
-               del_timer_sync(&sta->plink_timer);
-       }
-#endif
+       if (ieee80211_vif_is_mesh(&sdata->vif))
+               mesh_sta_cleanup(sta);
 
        cancel_work_sync(&sta->drv_unblock_wk);