From 8a0558317eb437d6ccecc5fb668fb93b464df9d4 Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 3 May 2015 22:28:42 +0000 Subject: [PATCH] Remove old iv_bss entry from the node table This may happen on RUN -> SCAN -> RUN -> SCAN state transition: 1. RUN -> SCAN: in ieee80211_sta_join1(): iv_bss will be moved to obss, refcnt will be reduced by 2 (default minimum). Now, if old iv_bss have some extra references (for example, from unacknowledged probe responses), it will not be freed and will stay in the node table. 2. SCAN -> RUN. 3. If old iv_bss will not be deleted by the time when the next RUN -> SCAN state transition occurs, then sta_leave() will reduce it's reference counter once more. As a result, two last users will free it -> this will lead to kernel panic. In this patch old iv_bss entry is explicitly removed from the node table in ieee80211_sta_join1() (as a result, it will not be processed by sta_leave()). PR: kern/199676 Differential Revision: Andriy Voskoboinyk --- sys/net80211/ieee80211_node.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 9fc4cd4d3157..4328a00c5c05 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -93,6 +93,8 @@ static void node_getmimoinfo(const struct ieee80211_node *, static void _ieee80211_free_node(struct ieee80211_node *); +static void node_reclaim(struct ieee80211_node_table *nt, + struct ieee80211_node *ni); static void ieee80211_node_table_init(struct ieee80211com *ic, struct ieee80211_node_table *nt, const char *name, int inact, int keymaxix); @@ -719,9 +721,15 @@ ieee80211_sta_join1(struct ieee80211_node *selbs) IEEE80211_ADDR_EQ(obss->ni_macaddr, selbs->ni_macaddr)); vap->iv_bss = selbs; /* NB: caller assumed to bump refcnt */ if (obss != NULL) { + struct ieee80211_node_table *nt = obss->ni_table; + copy_bss(selbs, obss); ieee80211_node_decref(obss); /* iv_bss reference */ - ieee80211_free_node(obss); /* station table reference */ + + IEEE80211_NODE_LOCK(nt); + node_reclaim(nt, obss); /* station table reference */ + IEEE80211_NODE_UNLOCK(nt); + obss = NULL; /* NB: guard against later use */ }