aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2024-02-03 16:33:56 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2024-02-14 19:47:53 +0000
commit2ac8a2189ac6707f48f77ef2e36baf696a0d2f40 (patch)
treed78f4e98aa02e837170af834af3e7b9519c1bfb6
parent713db49d06deee90dd358b2e4b9ca05368a5eaf6 (diff)
downloadsrc-2ac8a2189ac6707f48f77ef2e36baf696a0d2f40.tar.gz
src-2ac8a2189ac6707f48f77ef2e36baf696a0d2f40.zip
LinuxKPI: 802.11: band-aid for invalid state changes after (*iv_update_bss)
With firmware based solutions we cannot just jump from an active session to a new iv_bss node without tearing down state for the old and bringing up the new node. This likely used to work on softmac based cards/drivers where one could essentially set the state and fire at will. We track (*iv_update_bss) calls from net80211 and set a local flag that we are out of synch and do not allow any further operations up the state machine until we hit INIT or SCAN. That means someone will take the state down, clean up firmware state and then we can join again and build up state. Apparently this problem has been "known" for a while as native iwm(4) and others have similar workarounds (though less strict) and can be equally pestered into bad states. For LinuxKPI all the KASSERTs just massively brought this problem out. The solution will be some rewrites in net80211. Until then, try to keep us more stable at least and not die on second join1() calls triggered by service netif start wlan0 and similar. PR: 271979, 271988, 275255, 263613, 274003 Sponsored by: The FreeBSD Foundation (2023, partial) MFC after: 3 days Reviewed by: cc Differential Revision: https://reviews.freebsd.org/D43725
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.c309
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.h2
2 files changed, 216 insertions, 95 deletions
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index edd2423c59b5..ea742371f797 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -610,6 +610,7 @@ lkpi_find_lkpi80211_chan(struct lkpi_hw *lhw,
return (NULL);
}
+#if 0
static struct linuxkpi_ieee80211_channel *
lkpi_get_lkpi80211_chan(struct ieee80211com *ic, struct ieee80211_node *ni)
{
@@ -634,6 +635,7 @@ lkpi_get_lkpi80211_chan(struct ieee80211com *ic, struct ieee80211_node *ni)
return (chan);
}
+#endif
struct linuxkpi_ieee80211_channel *
linuxkpi_ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq)
@@ -1039,19 +1041,37 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
uint32_t changed;
int error;
- chan = lkpi_get_lkpi80211_chan(vap->iv_ic, vap->iv_bss);
+ /*
+ * In here we use vap->iv_bss until lvif->lvif_bss is set.
+ * For all later (STATE >= AUTH) functions we need to use the lvif
+ * cache which will be tracked even through (*iv_update_bss)().
+ */
+
+ if (vap->iv_bss == NULL) {
+ ic_printf(vap->iv_ic, "%s: no iv_bss for vap %p\n", __func__, vap);
+ return (EINVAL);
+ }
+ ni = ieee80211_ref_node(vap->iv_bss);
+ if (ni->ni_chan == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC) {
+ ic_printf(vap->iv_ic, "%s: no channel set for iv_bss ni %p "
+ "on vap %p\n", __func__, ni, vap);
+ ieee80211_free_node(ni);
+ return (EINVAL);
+ }
+
+ lhw = vap->iv_ic->ic_softc;
+ chan = lkpi_find_lkpi80211_chan(lhw, ni->ni_chan);
if (chan == NULL) {
- ic_printf(vap->iv_ic, "%s: failed to get channel\n", __func__);
+ ic_printf(vap->iv_ic, "%s: failed to get LKPI channel from "
+ "iv_bss ni %p on vap %p\n", __func__, ni, vap);
+ ieee80211_free_node(ni);
return (ESRCH);
}
- lhw = vap->iv_ic->ic_softc;
hw = LHW_TO_HW(lhw);
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- ni = ieee80211_ref_node(vap->iv_bss);
-
IEEE80211_UNLOCK(vap->iv_ic);
LKPI_80211_LHW_LOCK(lhw);
@@ -1076,6 +1096,8 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
conf->def.center_freq1 = chan->center_freq;
conf->def.center_freq2 = 0;
IMPROVE("Check vht_cap from band not just chan?");
+ KASSERT(ni->ni_chan != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC,
+ ("%s:%d: ni %p ni_chan %p\n", __func__, __LINE__, ni, ni->ni_chan));
#ifdef LKPI_80211_HT
if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
@@ -1186,6 +1208,8 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
* workflow so live with this. It is a compat layer after all.
*/
if (ni->ni_drv_data == NULL) {
+ ic_printf(vap->iv_ic, "%s:%d: lkpi_lsta_alloc to be called: "
+ "ni %p lsta %p\n", __func__, __LINE__, ni, ni->ni_drv_data);
lsta = lkpi_lsta_alloc(vap, ni->ni_macaddr, hw, ni);
if (lsta == NULL) {
error = ENOMEM;
@@ -1198,8 +1222,22 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lsta = ni->ni_drv_data;
}
- /* Insert the [l]sta into the list of known stations. */
LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ /* XXX-BZ this should have caught the upper lkpi_lsta_alloc() too! */
+ if (lvif->lvif_bss_synched || lvif->lvif_bss != NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d, ni %p lsta %p\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched, ni, lsta);
+
+ /* Reference the ni for this cache of lsta. */
+ ieee80211_ref_node(vap->iv_bss);
+ lvif->lvif_bss = lsta;
+ lvif->lvif_bss_synched = true;
+
+ /* Insert the [l]sta into the list of known stations. */
TAILQ_INSERT_TAIL(&lvif->lsta_head, lsta, lsta_entry);
LKPI_80211_LVIF_UNLOCK(lvif);
@@ -1271,9 +1309,23 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1323,6 +1375,13 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* Remove ni reference for this cache of lsta. */
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ ieee80211_free_node(ni); /* was lvif->lvif_bss->ni */
+
lkpi_lsta_remove(lsta, lvif);
/* conf_tx */
@@ -1346,8 +1405,6 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int
out:
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1369,7 +1426,6 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
struct ieee80211_hw *hw;
struct lkpi_vif *lvif;
struct ieee80211_vif *vif;
- struct ieee80211_node *ni;
struct lkpi_sta *lsta;
struct ieee80211_prep_tx_info prep_tx_info;
int error;
@@ -1381,15 +1437,30 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
IEEE80211_UNLOCK(vap->iv_ic);
LKPI_80211_LHW_LOCK(lhw);
- ni = NULL;
+
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
+#ifdef LINUXKPI_DEBUG_80211
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ error = ENOTRECOVERABLE;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ goto out;
+ }
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+
+ KASSERT(lsta != NULL, ("%s: lsta %p\n", __func__, lsta));
/* Finish auth. */
IMPROVE("event callback");
/* Update sta_state (NONE to AUTH). */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
- KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "
"NONE: %#x\n", __func__, lsta, lsta->state));
error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);
@@ -1433,8 +1504,6 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
out:
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1446,20 +1515,37 @@ lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
struct ieee80211_hw *hw;
struct lkpi_vif *lvif;
struct ieee80211_vif *vif;
- struct ieee80211_node *ni;
struct lkpi_sta *lsta;
struct ieee80211_prep_tx_info prep_tx_info;
+ int error;
lhw = vap->iv_ic->ic_softc;
hw = LHW_TO_HW(lhw);
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- ni = ieee80211_ref_node(vap->iv_bss);
-
IEEE80211_UNLOCK(vap->iv_ic);
LKPI_80211_LHW_LOCK(lhw);
- lsta = ni->ni_drv_data;
+
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
+#ifdef LINUXKPI_DEBUG_80211
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ error = ENOTRECOVERABLE;
+ goto out;
+ }
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+
+ KASSERT(lsta != NULL, ("%s: lsta %p! lvif %p vap %p\n", __func__,
+ lsta, lvif, vap));
IMPROVE("event callback?");
@@ -1481,12 +1567,12 @@ lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
lsta->in_mgd = true;
}
+ error = 0;
+out:
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
- return (0);
+ return (error);
}
static int
@@ -1508,16 +1594,30 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
+
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
- IEEE80211_UNLOCK(vap->iv_ic);
- LKPI_80211_LHW_LOCK(lhw);
-
/* flush, drop. */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
@@ -1613,6 +1713,13 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
bss_changed |= BSS_CHANGED_BSSID;
lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* Remove ni reference for this cache of lsta. */
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ ieee80211_free_node(ni); /* was lvif->lvif_bss->ni */
+
lkpi_lsta_remove(lsta, lvif);
/* conf_tx */
@@ -1638,8 +1745,6 @@ out:
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
outni:
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1697,16 +1802,34 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
IEEE80211_UNLOCK(vap->iv_ic);
LKPI_80211_LHW_LOCK(lhw);
- ni = NULL;
+
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
+#ifdef LINUXKPI_DEBUG_80211
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ error = ENOTRECOVERABLE;
+ goto out;
+ }
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
IMPROVE("ponder some of this moved to ic_newassoc, scan_assoc_success, "
"and to lesser extend ieee80211_notify_node_join");
/* Finish assoc. */
/* Update sta_state (AUTH to ASSOC) and set aid. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
- KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
"AUTH: %#x\n", __func__, lsta, lsta->state));
sta = LSTA_TO_STA(lsta);
@@ -1819,8 +1942,6 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
out:
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1856,9 +1977,23 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1954,8 +2089,6 @@ out:
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
outni:
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1978,16 +2111,30 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
+
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
- IEEE80211_UNLOCK(vap->iv_ic);
- LKPI_80211_LHW_LOCK(lhw);
-
/* flush, drop. */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
@@ -2107,6 +2254,13 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
bss_changed |= BSS_CHANGED_BSSID;
lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* Remove ni reference for this cache of lsta. */
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ ieee80211_free_node(ni); /* was lvif->lvif_bss->ni */
+
lkpi_lsta_remove(lsta, lvif);
/* conf_tx */
@@ -2132,8 +2286,6 @@ out:
LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
outni:
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -2306,53 +2458,18 @@ static struct ieee80211_node *
lkpi_iv_update_bss(struct ieee80211vap *vap, struct ieee80211_node *ni)
{
struct lkpi_vif *lvif;
- struct ieee80211_node *obss;
- struct lkpi_sta *lsta;
- struct ieee80211_sta *sta;
-
- obss = vap->iv_bss;
-
-#ifdef LINUXKPI_DEBUG_80211
- if (linuxkpi_debug_80211 & D80211_TRACE)
- ic_printf(vap->iv_ic, "%s: obss %p ni_drv_data %p "
- "ni %p ni_drv_data %p\n", __func__,
- obss, (obss != NULL) ? obss->ni_drv_data : NULL,
- ni, (ni != NULL) ? ni->ni_drv_data : NULL);
-#endif
+ struct ieee80211_node *rni;
- /* Nothing to copy from. Just return. */
- if (obss == NULL || obss->ni_drv_data == NULL)
- goto out;
-
- /* Nothing to copy to. Just return. */
- IMPROVE("clearing the obss might still be needed?");
- if (ni == NULL)
- goto out;
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
- /* Nothing changed? panic? */
- if (obss == ni)
- goto out;
+ lvif = VAP_TO_LVIF(vap);
- lsta = obss->ni_drv_data;
- obss->ni_drv_data = ni->ni_drv_data;
- ni->ni_drv_data = lsta;
- if (lsta != NULL) {
- lsta->ni = ni;
- sta = LSTA_TO_STA(lsta);
- IEEE80211_ADDR_COPY(sta->addr, lsta->ni->ni_macaddr);
- IEEE80211_ADDR_COPY(sta->deflink.addr, sta->addr);
- }
- lsta = obss->ni_drv_data;
- if (lsta != NULL) {
- lsta->ni = obss;
- sta = LSTA_TO_STA(lsta);
- IEEE80211_ADDR_COPY(sta->addr, lsta->ni->ni_macaddr);
- IEEE80211_ADDR_COPY(sta->deflink.addr, sta->addr);
- }
+ LKPI_80211_LVIF_LOCK(lvif);
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
-out:
- lvif = VAP_TO_LVIF(vap);
- return (lvif->iv_update_bss(vap, ni));
+ rni = lvif->iv_update_bss(vap, ni);
+ return (rni);
}
#ifdef LKPI_80211_WME
@@ -2473,6 +2590,8 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);
mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF);
TAILQ_INIT(&lvif->lsta_head);
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
vap = LVIF_TO_VAP(lvif);
vif = LVIF_TO_VIF(lvif);
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h
index c9ac19321ab3..4aeca414973c 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.h
+++ b/sys/compat/linuxkpi/common/src/linux_80211.h
@@ -156,6 +156,8 @@ struct lkpi_vif {
struct ieee80211_node * (*iv_update_bss)(struct ieee80211vap *,
struct ieee80211_node *);
TAILQ_HEAD(, lkpi_sta) lsta_head;
+ struct lkpi_sta *lvif_bss;
+ bool lvif_bss_synched;
bool added_to_drv; /* Driver knows; i.e. we called add_interface(). */
bool hw_queue_stopped[IEEE80211_NUM_ACS];