summaryrefslogtreecommitdiff
path: root/package/madwifi/patches/393-mbss_vap_auth.patch
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2009-01-25 00:37:41 +0000
committerFelix Fietkau <nbd@openwrt.org>2009-01-25 00:37:41 +0000
commit87db54da68aa2614122a0f2f2d4c79722dad2bb9 (patch)
tree022b7bd5bc73da3bce22c057ba58b97b4596e5c1 /package/madwifi/patches/393-mbss_vap_auth.patch
parent28abf79c44dc8a464d9573a9dc0c657ad5a35b60 (diff)
downloadmtk-20170518-87db54da68aa2614122a0f2f2d4c79722dad2bb9.zip
mtk-20170518-87db54da68aa2614122a0f2f2d4c79722dad2bb9.tar.gz
mtk-20170518-87db54da68aa2614122a0f2f2d4c79722dad2bb9.tar.bz2
madwifi: fix the long standing bug that is triggered by nodes getting a timeout on one vap, then moving to another
SVN-Revision: 14171
Diffstat (limited to 'package/madwifi/patches/393-mbss_vap_auth.patch')
-rw-r--r--package/madwifi/patches/393-mbss_vap_auth.patch423
1 files changed, 423 insertions, 0 deletions
diff --git a/package/madwifi/patches/393-mbss_vap_auth.patch b/package/madwifi/patches/393-mbss_vap_auth.patch
new file mode 100644
index 0000000..48d3df3
--- /dev/null
+++ b/package/madwifi/patches/393-mbss_vap_auth.patch
@@ -0,0 +1,423 @@
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -123,6 +123,9 @@ static void ieee80211_node_table_cleanup
+ static void ieee80211_node_table_reset(struct ieee80211_node_table *,
+ struct ieee80211vap *);
+
++static struct ieee80211_node *
++lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap, const u_int8_t *addr);
++
+ MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
+
+ void
+@@ -697,7 +700,7 @@ ieee80211_sta_join(struct ieee80211vap *
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_node *ni;
+
+- ni = ieee80211_find_node(&ic->ic_sta, se->se_macaddr);
++ ni = lookup_rxnode(ic, vap, se->se_macaddr);
+ if (ni == NULL) {
+ ni = ieee80211_alloc_node_table(vap, se->se_macaddr);
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
+@@ -1391,6 +1394,53 @@ ieee80211_add_neighbor(struct ieee80211v
+ return ni;
+ }
+
++struct ieee80211vap *
++ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac)
++{
++ struct ieee80211vap *vap;
++
++ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++ if (IEEE80211_ADDR_EQ(vap->iv_myaddr, mac))
++ return vap;
++ }
++ return NULL;
++}
++EXPORT_SYMBOL(ieee80211_find_rxvap);
++
++static struct ieee80211_node *
++lookup_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap,
++ const u_int8_t *addr)
++{
++ struct ieee80211_node_table *nt;
++ struct ieee80211_node *ni = NULL;
++ int use_bss = 0;
++ int hash;
++
++ nt = &ic->ic_sta;
++ IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
++ hash = IEEE80211_NODE_HASH(addr);
++ LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
++ if (IEEE80211_ADDR_EQ(ni->ni_macaddr, addr)) {
++ /* allow multiple nodes on different vaps */
++ if (vap && (ni->ni_vap != vap))
++ continue;
++
++ ieee80211_ref_node(ni);
++ goto out;
++ }
++ }
++
++ /* no match found */
++ ni = NULL;
++
++out:
++ IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
++ return ni;
++#undef IS_PSPOLL
++#undef IS_CTL
++}
++
++
+ /*
+ * Return the node for the sender of a frame; if the sender is unknown return
+ * NULL. The caller is expected to deal with this. (The frame is sent to all
+@@ -1400,10 +1450,10 @@ ieee80211_add_neighbor(struct ieee80211v
+ */
+ struct ieee80211_node *
+ #ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_find_rxnode_debug(struct ieee80211com *ic,
++ieee80211_find_rxnode_debug(struct ieee80211com *ic, struct ieee80211vap *vap,
+ const struct ieee80211_frame_min *wh, const char *func, int line)
+ #else
+-ieee80211_find_rxnode(struct ieee80211com *ic,
++ieee80211_find_rxnode(struct ieee80211com *ic, struct ieee80211vap *vap,
+ const struct ieee80211_frame_min *wh)
+ #endif
+ {
+@@ -1411,9 +1461,8 @@ ieee80211_find_rxnode(struct ieee80211co
+ ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
+ #define IS_PSPOLL(wh) \
+ ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
+- struct ieee80211_node_table *nt;
+- struct ieee80211_node *ni;
+- struct ieee80211vap *vap, *avp;
++ struct ieee80211_node *ni = NULL;
++ struct ieee80211vap *avp;
+ const u_int8_t *addr;
+
+ if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
+@@ -1426,32 +1475,21 @@ ieee80211_find_rxnode(struct ieee80211co
+
+ /* XXX check ic_bss first in station mode */
+ /* XXX 4-address frames? */
+- nt = &ic->ic_sta;
+- IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+ if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
+- TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++ if (vap) { /* assume unicast if vap is set, mcast not supported for wds */
+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
+- if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac))
++ if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac) ||
++ !IEEE80211_ADDR_EQ(wh->i_addr1, avp->iv_myaddr))
+ continue;
+
+ if (avp->iv_wdsnode)
+- return ieee80211_ref_node(avp->iv_wdsnode);
+- else
+- return NULL;
++ ni = ieee80211_ref_node(avp->iv_wdsnode);
+ }
+ }
++ return ni;
+ }
+
+-#ifdef IEEE80211_DEBUG_REFCNT
+- ni = ieee80211_find_node_locked_debug(nt, addr, func, line);
+-#else
+- ni = ieee80211_find_node_locked(nt, addr);
+-#endif
+- IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-
+- return ni;
+-#undef IS_PSPOLL
+-#undef IS_CTL
++ return lookup_rxnode(ic, vap, addr);
+ }
+ #ifdef IEEE80211_DEBUG_REFCNT
+ EXPORT_SYMBOL(ieee80211_find_rxnode_debug);
+@@ -1476,15 +1514,14 @@ ieee80211_find_txnode(struct ieee80211va
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_node_table *nt;
+ struct ieee80211_node *ni = NULL;
++ int hash;
+
+- IEEE80211_LOCK_IRQ(ic);
+ if (vap->iv_opmode == IEEE80211_M_WDS) {
+ if (vap->iv_wdsnode && (vap->iv_state == IEEE80211_S_RUN))
+ return ieee80211_ref_node(vap->iv_wdsnode);
+ else
+ return NULL;
+ }
+- IEEE80211_UNLOCK_IRQ(ic);
+
+ /*
+ * The destination address should be in the node table
+@@ -1502,11 +1539,22 @@ ieee80211_find_txnode(struct ieee80211va
+ /* XXX: Can't hold lock across dup_bss due to recursive locking. */
+ nt = &vap->iv_ic->ic_sta;
+ IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
++ hash = IEEE80211_NODE_HASH(mac);
++ LIST_FOREACH(ni, &nt->nt_hash[hash], ni_hash) {
++ if (ni->ni_vap != vap)
++ continue;
++
++ if (IEEE80211_ADDR_EQ(ni->ni_macaddr, mac)) {
+ #ifdef IEEE80211_DEBUG_REFCNT
+- ni = ieee80211_find_node_locked_debug(nt, mac, func, line);
++ ieee80211_ref_node_debug(ni, func, line);
+ #else
+- ni = ieee80211_find_node_locked(nt, mac);
++ ieee80211_ref_node(ni);
+ #endif
++ goto found;
++ }
++ }
++ ni = NULL;
++found:
+ IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+
+ if (ni == NULL) {
+@@ -1961,13 +2009,29 @@ remove_worse_nodes(void *arg, struct iee
+ }
+ }
+
++static void
++remove_duplicate_nodes(void *arg, struct ieee80211_node *ni)
++{
++ struct ieee80211_node *rni = arg;
++
++ if (ni == rni)
++ return;
++
++ if (ni->ni_vap == rni->ni_vap)
++ return;
++
++ ieee80211_node_leave(ni);
++}
++
+ void
+ ieee80211_node_join(struct ieee80211_node *ni, int resp)
+ {
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
++ struct ieee80211_node *tni;
+ int newassoc;
+
++ ieee80211_iterate_nodes(&ic->ic_sta, remove_duplicate_nodes, ni);
+ if (ni->ni_associd == 0) {
+ u_int16_t aid;
+
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -227,15 +227,22 @@ ieee80211_input(struct ieee80211vap * va
+ if (!dev)
+ goto out;
+
++ if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
++ goto out;
++
++ if (!vap->iv_bss)
++ goto out;
++
+ /* initialize ni as in the previous API */
+ if (ni_or_null == NULL) {
+ /* This function does not 'own' vap->iv_bss, so we cannot
+ * guarantee its existence during the following call, hence
+ * briefly grab our own reference. */
+ ni = ieee80211_ref_node(vap->iv_bss);
++ KASSERT(ni != NULL, ("null node"));
++ } else {
++ ni->ni_inact = ni->ni_inact_reload;
+ }
+- KASSERT(ni != NULL, ("null node"));
+- ni->ni_inact = ni->ni_inact_reload;
+
+ KASSERT(skb->len >= sizeof(struct ieee80211_frame_min),
+ ("frame length too short: %u", skb->len));
+@@ -933,16 +940,23 @@ int
+ ieee80211_input_all(struct ieee80211com *ic,
+ struct sk_buff *skb, int rssi, u_int64_t rtsf)
+ {
++ struct ieee80211_frame_min *wh = (struct ieee80211_frame_min *) skb->data;
+ struct ieee80211vap *vap;
+ int type = -1;
+
+ /* XXX locking */
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
++ struct ieee80211_node *ni = NULL;
+ struct sk_buff *skb1;
+
+ if ((vap->iv_dev->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
+ continue;
+
++ if ((vap->iv_opmode == IEEE80211_M_HOSTAP) &&
++ !IEEE80211_IS_MULTICAST(wh->i_addr1))
++ continue;
++
++ ni = ieee80211_find_rxnode(ic, vap, wh);
+ if (TAILQ_NEXT(vap, iv_next) != NULL) {
+ skb1 = skb_copy(skb, GFP_ATOMIC);
+ if (skb1 == NULL) {
+@@ -954,8 +968,10 @@ ieee80211_input_all(struct ieee80211com
+ skb1 = skb;
+ skb = NULL;
+ }
+- type = ieee80211_input(vap, NULL, skb1, rssi, rtsf);
++ type = ieee80211_input(vap, ni, skb1, rssi, rtsf);
+ }
++
++out:
+ if (skb != NULL) /* no vaps, reclaim skb */
+ ieee80211_dev_kfree_skb(&skb);
+ return type;
+@@ -1146,11 +1162,9 @@ ieee80211_deliver_data(struct ieee80211_
+ * sending it will not work; just let it be
+ * delivered normally.
+ */
+- struct ieee80211_node *ni1 = ieee80211_find_node(
+- &vap->iv_ic->ic_sta, eh->ether_dhost);
++ struct ieee80211_node *ni1 = ieee80211_find_txnode(vap, eh->ether_dhost);
+ if (ni1 != NULL) {
+- if (ni1->ni_vap == vap &&
+- ieee80211_node_is_authorized(ni1) &&
++ if (ieee80211_node_is_authorized(ni1) &&
+ !ni1->ni_subif &&
+ ni1 != vap->iv_bss) {
+
+--- a/ath/if_ath.c
++++ b/ath/if_ath.c
+@@ -6577,9 +6577,8 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+
+ sc->sc_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf);
+
+-
+ /* Lookup the new node if any (this grabs a reference to it) */
+- ni = ieee80211_find_rxnode(vap->iv_ic,
++ ni = ieee80211_find_rxnode(vap->iv_ic, vap,
+ (const struct ieee80211_frame_min *)skb->data);
+ if (ni == NULL) {
+ DPRINTF(sc, ATH_DEBUG_BEACON, "Dropping; node unknown.\n");
+@@ -6734,7 +6733,9 @@ ath_rx_poll(struct net_device *dev, int
+ struct ath_desc *ds;
+ struct ath_rx_status *rs;
+ struct sk_buff *skb = NULL;
++ struct ieee80211vap *vap;
+ struct ieee80211_node *ni;
++ const struct ieee80211_frame_min *wh;
+ unsigned int len;
+ int type;
+ u_int phyerr;
+@@ -6889,12 +6890,15 @@ rx_accept:
+ skb_trim(skb, skb->len - IEEE80211_CRC_LEN);
+
+ if (mic_fail) {
++ wh = (const struct ieee80211_frame_min *) skb->data;
++
+ /* Ignore control frames which are reported with mic error */
+- if ((((struct ieee80211_frame *)skb->data)->i_fc[0] &
++ if ((wh->i_fc[0] &
+ IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
+ goto drop_micfail;
+
+- ni = ieee80211_find_rxnode(ic, (const struct ieee80211_frame_min *) skb->data);
++ vap = ieee80211_find_rxvap(ic, wh->i_addr1);
++ ni = ieee80211_find_rxnode(ic, vap, wh);
+
+ if (ni && ni->ni_table) {
+ ieee80211_check_mic(ni, skb);
+@@ -6956,11 +6960,24 @@ drop_micfail:
+ * for its use. If the sender is unknown spam the
+ * frame; it'll be dropped where it's not wanted.
+ */
+- if (rs->rs_keyix != HAL_RXKEYIX_INVALID &&
++ wh = (const struct ieee80211_frame_min *) skb->data;
++ if ((rs->rs_keyix != HAL_RXKEYIX_INVALID) &&
+ (ni = sc->sc_keyixmap[rs->rs_keyix]) != NULL) {
+ /* Fast path: node is present in the key map;
+ * grab a reference for processing the frame. */
+- ni = ieee80211_ref_node(ni);
++ ieee80211_ref_node(ni);
++ if ((ATH_GET_VAP_ID(wh->i_addr1) !=
++ ATH_GET_VAP_ID(ni->ni_vap->iv_myaddr)) ||
++ ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) ==
++ IEEE80211_FC1_DIR_DSTODS)) {
++ /* key cache node lookup is fast, but it can
++ * lead to problems in multi-bss (foreign vap
++ * node reference) or wds (wdsap node ref instead
++ * of base ap node ref).
++ * use slowpath lookup in both cases
++ */
++ goto lookup_slowpath;
++ }
+ ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
+ type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
+ ieee80211_unref_node(&ni);
+@@ -6969,24 +6986,35 @@ drop_micfail:
+ * No key index or no entry, do a lookup and
+ * add the node to the mapping table if possible.
+ */
+- ni = ieee80211_find_rxnode(ic,
+- (const struct ieee80211_frame_min *)skb->data);
++
++lookup_slowpath:
++ vap = ieee80211_find_rxvap(ic, wh->i_addr1);
++ if (vap)
++ ni = ieee80211_find_rxnode(ic, vap, wh);
++ else
++ ni = NULL;
++
+ if (ni != NULL) {
+ ieee80211_keyix_t keyix;
+
+ ATH_RSSI_LPF(ATH_NODE(ni)->an_avgrssi, rs->rs_rssi);
+- type = ieee80211_input(ni->ni_vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
++ type = ieee80211_input(vap, ni, skb, rs->rs_rssi, bf->bf_tsf);
+ /*
+ * If the station has a key cache slot assigned
+ * update the key->node mapping table.
+ */
+ keyix = ni->ni_ucastkey.wk_keyix;
+ if (keyix != IEEE80211_KEYIX_NONE &&
+- sc->sc_keyixmap[keyix] == NULL)
++ sc->sc_keyixmap[keyix] == NULL) {
+ sc->sc_keyixmap[keyix] = ieee80211_ref_node(ni);
++ }
+ ieee80211_unref_node(&ni);
+- } else
+- type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf);
++ } else {
++ if (vap)
++ type = ieee80211_input(vap, NULL, skb, rs->rs_rssi, bf->bf_tsf);
++ else
++ type = ieee80211_input_all(ic, skb, rs->rs_rssi, bf->bf_tsf);
++ }
+ }
+
+ if (sc->sc_diversity) {
+--- a/net80211/ieee80211_node.h
++++ b/net80211/ieee80211_node.h
+@@ -286,15 +286,18 @@ struct ieee80211_node *ieee80211_find_no
+ const u_int8_t *);
+ #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+
++struct ieee80211vap *
++ieee80211_find_rxvap(struct ieee80211com *ic, const u_int8_t *mac);
++
+ /* Returns a ieee80211_node* with refcount incremented, if found */
+ #ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_find_rxnode(_nt, _wh) \
+- ieee80211_find_rxnode_debug(_nt, _wh, __func__, __LINE__)
++#define ieee80211_find_rxnode(_nt, _vap, _wh) \
++ ieee80211_find_rxnode_debug(_nt, _vap, _wh, __func__, __LINE__)
+ struct ieee80211_node *ieee80211_find_rxnode_debug(struct ieee80211com *,
+- const struct ieee80211_frame_min *, const char *, int);
++ struct ieee80211vap *, const struct ieee80211_frame_min *, const char *, int);
+ #else
+ struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *,
+- const struct ieee80211_frame_min *);
++ struct ieee80211vap *, const struct ieee80211_frame_min *);
+ #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+
+ /* Returns a ieee80211_node* with refcount incremented, if found */