2013-02-06 08:06:38

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH] mac80211: fix mesh sta teardown

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.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh.c | 25 +++++++++++++++++++++++++
net/mac80211/mesh.h | 4 +++-
net/mac80211/mesh_plink.c | 4 ++--
net/mac80211/sta_info.c | 9 ++-------
4 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 35ac388..0c51b78 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -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;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index eb33625..e5f6095 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -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 */
@@ -380,6 +381,7 @@ static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata)
{ return false; }
static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
{}
+static inline void mesh_sta_cleanup(struct sta_info *sta) {}
#endif

#endif /* IEEE80211S_H */
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 67524e7..cdf66fb 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -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,
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 47a0f06..19db20a 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -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);

--
1.7.10.4



2013-02-06 08:26:38

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH] mac80211: fix mesh sta teardown

On Wed, Feb 6, 2013 at 12:05 AM, Thomas Pedersen <[email protected]> wrote:
> 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.

Wait, this would also apply to the del_timer_sync() in
mesh_plink_quiesce() then. v2 will add this check to that function.

--
Thomas