madwifi: fix the long standing bug that is triggered by nodes getting a timeout on...
authorFelix Fietkau <nbd@openwrt.org>
Sun, 25 Jan 2009 00:37:41 +0000 (00:37 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 25 Jan 2009 00:37:41 +0000 (00:37 +0000)
SVN-Revision: 14171

package/madwifi/patches/391-vap_auth.patch [new file with mode: 0644]
package/madwifi/patches/392-remove_wds_nodetracking.patch [new file with mode: 0644]
package/madwifi/patches/393-mbss_vap_auth.patch [new file with mode: 0644]
package/madwifi/patches/394-probereq.patch
package/madwifi/patches/405-retransmit_check.patch
package/madwifi/patches/450-new_hal.patch

diff --git a/package/madwifi/patches/391-vap_auth.patch b/package/madwifi/patches/391-vap_auth.patch
new file mode 100644 (file)
index 0000000..acee271
--- /dev/null
@@ -0,0 +1,29 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -1374,7 +1386,7 @@ ieee80211_auth_open(struct ieee80211_nod
+               vap->iv_stats.is_rx_bad_auth++; /* XXX maybe a unique error? */
+               if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+                       if (ni == vap->iv_bss) {
+-                              ni = ieee80211_dup_bss(vap, wh->i_addr2, 0);
++                              ni = ieee80211_dup_bss(vap, wh->i_addr2, 1);
+                               if (ni == NULL)
+                                       return;
+                               tmpnode = 1;
+@@ -1762,6 +1774,8 @@ ieee80211_ssid_mismatch(struct ieee80211
+ }
+ #define       IEEE80211_VERIFY_SSID(_ni, _ssid) do {                          \
++      if ((_ni)->ni_esslen == 0)                                      \
++              return;                                                 \
+       if ((_ssid)[1] != 0 &&                                          \
+           ((_ssid)[1] != (_ni)->ni_esslen ||                          \
+           memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {   \
+@@ -1776,6 +1790,8 @@ ieee80211_ssid_mismatch(struct ieee80211
+ } while (0)
+ #else /* !IEEE80211_DEBUG */
+ #define       IEEE80211_VERIFY_SSID(_ni, _ssid) do {                          \
++      if ((_ni)->ni_esslen == 0)                                      \
++              return;                                                 \
+       if ((_ssid)[1] != 0 &&                                          \
+           ((_ssid)[1] != (_ni)->ni_esslen ||                          \
+           memcmp((_ssid) + 2, (_ni)->ni_essid, (_ssid)[1]) != 0)) {   \
diff --git a/package/madwifi/patches/392-remove_wds_nodetracking.patch b/package/madwifi/patches/392-remove_wds_nodetracking.patch
new file mode 100644 (file)
index 0000000..d035fd6
--- /dev/null
@@ -0,0 +1,388 @@
+--- a/net80211/ieee80211_input.c
++++ b/net80211/ieee80211_input.c
+@@ -572,36 +572,6 @@ ieee80211_input(struct ieee80211vap * va
+                               }
+                       }
+-                      /* XXX: Useless node mgmt API; make better */
+-                      if ((dir == IEEE80211_FC1_DIR_DSTODS) && !vap->iv_wdsnode &&
+-                                      !ni_wds && !ni->ni_subif) {
+-                              struct ieee80211_node_table *nt = &ic->ic_sta;
+-                              struct ieee80211_frame_addr4 *wh4;
+-
+-                              if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) {
+-                                      IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
+-                                              wh, "data", "%s", "4 addr not allowed");
+-                                      goto err;
+-                              }
+-                              wh4 = (struct ieee80211_frame_addr4 *)skb->data;
+-                              ni_wds = ieee80211_find_wds_node(nt, wh4->i_addr4);
+-                              /* Last call increments ref count if !NULL */
+-                              if ((ni_wds != NULL) && (ni_wds != ni)) {
+-                                      /*
+-                                       * node with source address (addr4) moved
+-                                       * to another WDS capable station. remove the
+-                                       * reference to the previous station and add 
+-                                       * reference to the new one
+-                                       */
+-                                       (void) ieee80211_remove_wds_addr(nt, wh4->i_addr4);
+-                                       ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0);
+-                              }
+-                              if (ni_wds == NULL)
+-                                      ieee80211_add_wds_addr(nt, ni, wh4->i_addr4, 0);
+-                              else
+-                                      ieee80211_unref_node(&ni_wds);
+-                      }
+-
+                       /*
+                        * Check for power save state change.
+                        */
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -122,7 +122,6 @@ static void ieee80211_node_table_init(st
+ static void ieee80211_node_table_cleanup(struct ieee80211_node_table *);
+ static void ieee80211_node_table_reset(struct ieee80211_node_table *,
+       struct ieee80211vap *);
+-static void ieee80211_node_wds_ageout(unsigned long);
+ MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
+@@ -785,10 +784,6 @@ ieee80211_node_table_init(struct ieee802
+       nt->nt_name = name;
+       nt->nt_scangen = 1;
+       nt->nt_inact_init = inact;
+-      init_timer(&nt->nt_wds_aging_timer);
+-      nt->nt_wds_aging_timer.function = ieee80211_node_wds_ageout;
+-      nt->nt_wds_aging_timer.data = (unsigned long) nt;
+-      mod_timer(&nt->nt_wds_aging_timer, jiffies + HZ * WDS_AGING_TIMER_VAL);
+ }
+ static __inline 
+@@ -1201,142 +1196,6 @@ void ieee80211_wds_addif(struct ieee8021
+       schedule_work(&ni->ni_create);
+ }
+-/* Add wds address to the node table */
+-int
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_add_wds_addr_debug(struct ieee80211_node_table *nt,
+-      struct ieee80211_node *ni, const u_int8_t *macaddr, u_int8_t wds_static,
+-      const char* func, int line)
+-#else
+-ieee80211_add_wds_addr(struct ieee80211_node_table *nt,
+-      struct ieee80211_node *ni, const u_int8_t *macaddr, u_int8_t wds_static)
+-#endif
+-{
+-      int hash;
+-      struct ieee80211_wds_addr *wds;
+-
+-      MALLOC(wds, struct ieee80211_wds_addr *, sizeof(struct ieee80211_wds_addr),
+-              M_80211_WDS, M_NOWAIT | M_ZERO);
+-      if (wds == NULL) {
+-              /* XXX msg */
+-              return 1;
+-      }
+-      if (wds_static)
+-              wds->wds_agingcount = WDS_AGING_STATIC;
+-      else
+-              wds->wds_agingcount = WDS_AGING_COUNT;
+-      hash = IEEE80211_NODE_HASH(macaddr);
+-      IEEE80211_ADDR_COPY(wds->wds_macaddr, macaddr);
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-      wds->wds_ni = ieee80211_ref_node_debug(ni, func, line);
+-#else
+-      wds->wds_ni = ieee80211_ref_node(ni);
+-#endif
+-      LIST_INSERT_HEAD(&nt->nt_wds_hash[hash], wds, wds_hash);
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-      return 0;
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_add_wds_addr_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_add_wds_addr);
+-#endif
+-
+-/* remove wds address from the wds hash table */
+-void
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_remove_wds_addr_debug(struct ieee80211_node_table *nt, const u_int8_t *macaddr, 
+-                         const char* func, int line)
+-#else
+-ieee80211_remove_wds_addr(struct ieee80211_node_table *nt, const u_int8_t *macaddr)
+-#endif
+-{
+-      int hash;
+-      struct ieee80211_wds_addr *wds, *twds;
+-
+-      hash = IEEE80211_NODE_HASH(macaddr);
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-      LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) {
+-              if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) {
+-                      LIST_REMOVE(wds, wds_hash);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                      ieee80211_unref_node_debug(&wds->wds_ni, func, line);
+-#else
+-                      ieee80211_unref_node(&wds->wds_ni);
+-#endif
+-                      FREE(wds, M_80211_WDS);
+-                      break;
+-              }
+-      }
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_remove_wds_addr_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_remove_wds_addr);
+-#endif
+-
+-/* Remove node references from wds table */
+-void
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_del_wds_node_debug(struct ieee80211_node_table *nt, struct ieee80211_node *ni, 
+-                      const char* func, int line)
+-#else
+-ieee80211_del_wds_node(struct ieee80211_node_table *nt, struct ieee80211_node *ni)
+-#endif
+-{
+-      int hash;
+-      struct ieee80211_wds_addr *wds, *twds;
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-      for (hash = 0; hash < IEEE80211_NODE_HASHSIZE; hash++) {
+-              LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) {
+-                      if (wds->wds_ni == ni) {
+-                              LIST_REMOVE(wds, wds_hash);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                              ieee80211_unref_node_debug(&wds->wds_ni, func, line);
+-#else
+-                              ieee80211_unref_node(&wds->wds_ni);
+-#endif
+-                              FREE(wds, M_80211_WDS);
+-                      }
+-              }
+-      }
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_del_wds_node_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_del_wds_node);
+-#endif
+-
+-static void
+-ieee80211_node_wds_ageout(unsigned long data)
+-{
+-      struct ieee80211_node_table *nt = (struct ieee80211_node_table *)data;
+-      int hash;
+-      struct ieee80211_wds_addr *wds, *twds;
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-      for (hash = 0; hash < IEEE80211_NODE_HASHSIZE; hash++) {
+-              LIST_FOREACH_SAFE(wds, &nt->nt_wds_hash[hash], wds_hash, twds) {
+-                      if (wds->wds_agingcount != WDS_AGING_STATIC) {
+-                              if (!wds->wds_agingcount) {
+-                                      LIST_REMOVE(wds, wds_hash);
+-                                      ieee80211_unref_node(&wds->wds_ni);
+-                                      FREE(wds, M_80211_WDS);
+-                              } else
+-                                      wds->wds_agingcount--;
+-                      }
+-              }
+-      }
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-      mod_timer(&nt->nt_wds_aging_timer, jiffies + HZ * WDS_AGING_TIMER_VAL);
+-}
+-
+-
+ /* Add the specified station to the station table.
+  * Allocates a new ieee80211_node* that has a reference count of one
+  * If tmp is 0, it is added to the node table and the reference is used.
+@@ -1382,34 +1241,6 @@ ieee80211_dup_bss(struct ieee80211vap *v
+       return ni;
+ }
+-static struct ieee80211_node *
+-#ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_find_wds_node_locked_debug(struct ieee80211_node_table *nt, 
+-                       const u_int8_t *macaddr, const char* func, int line)
+-#else
+-ieee80211_find_wds_node_locked(struct ieee80211_node_table *nt, 
+-                       const u_int8_t *macaddr)
+-#endif
+-{
+-      struct ieee80211_wds_addr *wds;
+-      int hash;
+-      IEEE80211_NODE_TABLE_LOCK_ASSERT(nt);
+-
+-      hash = IEEE80211_NODE_HASH(macaddr);
+-      LIST_FOREACH(wds, &nt->nt_wds_hash[hash], wds_hash) {
+-              if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) {
+-                      if (wds->wds_agingcount != WDS_AGING_STATIC)
+-                              wds->wds_agingcount = WDS_AGING_COUNT; /* reset the aging count */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                      return ieee80211_ref_node_debug(wds->wds_ni, func, line);
+-#else
+-                      return ieee80211_ref_node(wds->wds_ni);
+-#endif
+-              }
+-      }
+-      return NULL;
+-}
+-
+ /* NB: A node reference is acquired here; the caller MUST release it. */
+ #ifdef IEEE80211_DEBUG_REFCNT
+ #define       ieee80211_find_node_locked(nt, mac) \
+@@ -1427,7 +1258,6 @@ ieee80211_find_node_locked(struct ieee80
+ {
+       struct ieee80211_node *ni;
+       int hash;
+-      struct ieee80211_wds_addr *wds;
+       IEEE80211_NODE_TABLE_LOCK_ASSERT(nt);
+@@ -1442,48 +1272,11 @@ ieee80211_find_node_locked(struct ieee80
+                       return ni;
+               }
+       }
+-
+-      /* Now, we look for the desired mac address in the 4 address
+-         nodes. */
+-      LIST_FOREACH(wds, &nt->nt_wds_hash[hash], wds_hash) {
+-              if (IEEE80211_ADDR_EQ(wds->wds_macaddr, macaddr)) {
+-#ifdef IEEE80211_DEBUG_REFCNT
+-                      return ieee80211_ref_node_debug(wds->wds_ni, func, line);
+-#else
+-                      return ieee80211_ref_node(wds->wds_ni);
+-#endif 
+-              }
+-      }
+       return NULL;
+ }
+ struct ieee80211_node *
+ #ifdef IEEE80211_DEBUG_REFCNT
+-ieee80211_find_wds_node_debug(struct ieee80211_node_table *nt, const u_int8_t *macaddr, 
+-                       const char* func, int line)
+-#else
+-ieee80211_find_wds_node(struct ieee80211_node_table *nt, const u_int8_t *macaddr)
+-#endif
+-{
+-      struct ieee80211_node *ni;
+-
+-      IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+-#ifdef IEEE80211_DEBUG_REFCNT
+-      ni = ieee80211_find_wds_node_locked_debug(nt, macaddr, func, line);
+-#else
+-      ni = ieee80211_find_wds_node_locked(nt, macaddr);
+-#endif
+-      IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+-      return ni;
+-}
+-#ifdef IEEE80211_DEBUG_REFCNT
+-EXPORT_SYMBOL(ieee80211_find_wds_node_debug);
+-#else
+-EXPORT_SYMBOL(ieee80211_find_wds_node);
+-#endif
+-
+-struct ieee80211_node *
+-#ifdef IEEE80211_DEBUG_REFCNT
+ ieee80211_find_node_debug(struct ieee80211_node_table *nt,
+       const u_int8_t *macaddr, const char *func, int line)
+ #else
+@@ -1835,7 +1628,6 @@ ieee80211_node_table_cleanup(struct ieee
+               ic->ic_node_cleanup(ni);
+ #endif
+       }
+-      del_timer(&nt->nt_wds_aging_timer);
+       IEEE80211_SCAN_LOCK_DESTROY(nt);
+       IEEE80211_NODE_TABLE_LOCK_DESTROY(nt);
+ }
+@@ -2402,8 +2194,6 @@ ieee80211_node_leave(struct ieee80211_no
+        * so no more references are generated
+        */
+       if (nt) {
+-              ieee80211_remove_wds_addr(nt, ni->ni_macaddr);
+-              ieee80211_del_wds_node(nt, ni);
+               IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
+               node_table_leave_locked(nt, ni);
+               IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
+--- a/net80211/ieee80211_node.h
++++ b/net80211/ieee80211_node.h
+@@ -231,13 +231,6 @@ void ieee80211_sta_leave(struct ieee8021
+ #define WDS_AGING_STATIC      0xffff
+ #define WDS_AGING_TIMER_VAL   (WDS_AGING_TIME / 2)
+-struct ieee80211_wds_addr {
+-      LIST_ENTRY(ieee80211_wds_addr) wds_hash;
+-      u_int8_t        wds_macaddr[IEEE80211_ADDR_LEN];
+-      struct ieee80211_node *wds_ni;
+-      u_int16_t wds_agingcount;
+-};
+-
+ /*
+  * Table of ieee80211_node instances.  Each ieee80211com
+  * has at least one for holding the scan candidates.
+@@ -250,11 +243,9 @@ struct ieee80211_node_table {
+       ieee80211_node_table_lock_t nt_nodelock;        /* on node table */
+       TAILQ_HEAD(, ieee80211_node) nt_node;   /* information of all nodes */
+       ATH_LIST_HEAD(, ieee80211_node) nt_hash[IEEE80211_NODE_HASHSIZE];
+-      ATH_LIST_HEAD(, ieee80211_wds_addr) nt_wds_hash[IEEE80211_NODE_HASHSIZE];
+       ieee80211_scan_lock_t nt_scanlock;      /* on nt_scangen */
+       u_int nt_scangen;                       /* gen# for timeout scan */
+       int nt_inact_init;                      /* initial node inact setting */
+-      struct timer_list nt_wds_aging_timer;   /* timer to age out wds entries */
+ };
+ /* Allocates a new ieee80211_node* that has a reference count of one, and 
+@@ -363,47 +354,6 @@ void
+ ieee80211_unref_node(struct ieee80211_node **pni);
+ #endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-/* Increments reference count of ieee80211_node *ni */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_add_wds_addr(_table, _node, _mac, _static) \
+-      ieee80211_add_wds_addr_debug(_table, _node, _mac, _static, __func__, __LINE__)
+-int ieee80211_add_wds_addr_debug(struct ieee80211_node_table *, struct ieee80211_node *,
+-      const u_int8_t *, u_int8_t, const char* func, int line);
+-#else
+-int ieee80211_add_wds_addr(struct ieee80211_node_table *, struct ieee80211_node *,
+-      const u_int8_t *, u_int8_t);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-
+-/* Decrements reference count of ieee80211_node *ni */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_remove_wds_addr(_table, _mac) \
+-      ieee80211_remove_wds_addr_debug(_table, _mac, __func__, __LINE__)
+-void ieee80211_remove_wds_addr_debug(struct ieee80211_node_table *, const u_int8_t *,
+-                             const char* func, int line);
+-#else
+-void ieee80211_remove_wds_addr(struct ieee80211_node_table *, const u_int8_t *);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-
+-/* Decrements reference count of node, if found */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_del_wds_node(_table, _node) \
+-      ieee80211_del_wds_node_debug(_table, _node, __func__, __LINE__)
+-void ieee80211_del_wds_node_debug(struct ieee80211_node_table *, struct ieee80211_node *,
+-                          const char* func, int line);
+-#else
+-void ieee80211_del_wds_node(struct ieee80211_node_table *, struct ieee80211_node *);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+-
+-/* Increments reference count of node, if found */
+-#ifdef IEEE80211_DEBUG_REFCNT
+-#define ieee80211_find_wds_node(_table, _mac) \
+-      ieee80211_find_wds_node_debug(_table, _mac, __func__, __LINE__)
+-struct ieee80211_node *ieee80211_find_wds_node_debug(struct ieee80211_node_table *,
+-      const u_int8_t *, const char* func, int line);
+-#else
+-struct ieee80211_node *ieee80211_find_wds_node(struct ieee80211_node_table *,
+-      const u_int8_t *);
+-#endif /* #ifdef IEEE80211_DEBUG_REFCNT */
+ typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
+ void ieee80211_iterate_nodes(struct ieee80211_node_table *,
+       ieee80211_iter_func *, void *);
diff --git a/package/madwifi/patches/393-mbss_vap_auth.patch b/package/madwifi/patches/393-mbss_vap_auth.patch
new file mode 100644 (file)
index 0000000..48d3df3
--- /dev/null
@@ -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 */
index fc8cda0..1dd0bcd 100644 (file)
@@ -1,6 +1,6 @@
 --- a/net80211/ieee80211_input.c
 +++ b/net80211/ieee80211_input.c
-@@ -3604,6 +3604,8 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+@@ -3618,6 +3618,8 @@ ieee80211_recv_mgmt(struct ieee80211vap 
                        vap->iv_stats.is_rx_mgtdiscard++;
                        return;
                }
index b03232a..dadb423 100644 (file)
@@ -11,7 +11,7 @@
  #define       IEEE80211_QOS_TXOP                      0x00ff
 --- a/net80211/ieee80211_input.c
 +++ b/net80211/ieee80211_input.c
-@@ -429,7 +429,7 @@ ieee80211_input(struct ieee80211vap * va
+@@ -436,7 +436,7 @@ ieee80211_input(struct ieee80211vap * va
                                tid = 0;
                        rxseq = le16toh(*(__le16 *)wh->i_seq);
                        if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
index 324f7dd..7494f0d 100644 (file)
        /*
         * Check if the MAC has multi-rate retry support.
         * We do this by trying to setup a fake extended
-@@ -7524,7 +7532,7 @@ ath_txq_setup(struct ath_softc *sc, int 
+@@ -7552,7 +7560,7 @@ ath_txq_setup(struct ath_softc *sc, int 
        if (qtype == HAL_TX_QUEUE_UAPSD)
                qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE;
        else