From 87db54da68aa2614122a0f2f2d4c79722dad2bb9 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 25 Jan 2009 00:37:41 +0000 Subject: [PATCH] madwifi: fix the long standing bug that is triggered by nodes getting a timeout on one vap, then moving to another SVN-Revision: 14171 --- package/madwifi/patches/391-vap_auth.patch | 29 ++ .../patches/392-remove_wds_nodetracking.patch | 388 ++++++++++++++++ .../madwifi/patches/393-mbss_vap_auth.patch | 423 ++++++++++++++++++ package/madwifi/patches/394-probereq.patch | 2 +- .../patches/405-retransmit_check.patch | 2 +- package/madwifi/patches/450-new_hal.patch | 2 +- 6 files changed, 843 insertions(+), 3 deletions(-) create mode 100644 package/madwifi/patches/391-vap_auth.patch create mode 100644 package/madwifi/patches/392-remove_wds_nodetracking.patch create mode 100644 package/madwifi/patches/393-mbss_vap_auth.patch diff --git a/package/madwifi/patches/391-vap_auth.patch b/package/madwifi/patches/391-vap_auth.patch new file mode 100644 index 0000000000..acee271c33 --- /dev/null +++ b/package/madwifi/patches/391-vap_auth.patch @@ -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 index 0000000000..d035fd6158 --- /dev/null +++ b/package/madwifi/patches/392-remove_wds_nodetracking.patch @@ -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 index 0000000000..48d3df3e17 --- /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 */ diff --git a/package/madwifi/patches/394-probereq.patch b/package/madwifi/patches/394-probereq.patch index fc8cda0d54..1dd0bcd136 100644 --- a/package/madwifi/patches/394-probereq.patch +++ b/package/madwifi/patches/394-probereq.patch @@ -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; } diff --git a/package/madwifi/patches/405-retransmit_check.patch b/package/madwifi/patches/405-retransmit_check.patch index b03232ad5e..dadb4239ca 100644 --- a/package/madwifi/patches/405-retransmit_check.patch +++ b/package/madwifi/patches/405-retransmit_check.patch @@ -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) && diff --git a/package/madwifi/patches/450-new_hal.patch b/package/madwifi/patches/450-new_hal.patch index 324f7dd6b3..7494f0d4a0 100644 --- a/package/madwifi/patches/450-new_hal.patch +++ b/package/madwifi/patches/450-new_hal.patch @@ -108,7 +108,7 @@ /* * 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