The function ieee80211_find_node_for_beacon() was added by reyk on 2005. At the time, net80211 nodes were stored in a hash table keyed on hashes the node's source MAC addresses. The purpose of ieee80211_find_node_for_beacon() was to avoid storing duplicate nodes with the same source MAC address in a given hash bucket. Hash collisions on differing MAC addresses were valid, but collisions on the same address had to be avoided.
Later on, the node table data structure was changed from a hash table to an RB tree which is still in use today. The RB tree can only store a single node per MAC address. However, find_node_for_beacon() was kept regardless, now documented to serve a different purpose. Its new purpose is to tell apart different nodes which happen to use the same MAC address and hence cannot both be stored in the RB tree. The idea is to help the net80211 stack to pick the "better" one of two such APs while it is scanning for access points. The comment also claims this function would avoid "bloat" of the nodes tree, which is obviously related to the function's original purpose. There are several problems with this: The code which decides which node is "better" can erroneously match an AP against itself, in case the AP uses a hidden SSID. This prevents state updates for such APs. Just a bit further down, the code looks up the same node again and performs all of the intended updates. Simply skipping the ieee80211_find_node_for_beacon() check makes state updates work. (I have received a patch submission which fixes probe responses for iwm/iwx in order to interop with hidden SSID APs. And that patch contains a workaround for this problem, which prompted me to look into it.) The intention of avoiding "bloat" makes no sense. There cannot be "bloat" of the node tree. Worst case we could end up leaking memory when we replace an existing node in the tree with a new node which has the same address (we would lose track of the pointer to memory which stores the original node, and would never be able to free this memory). There is no code in place which would prevent such a leak. Simply always updating the existing node we have allocated is the safer choice in the absence of proper collision handling. My opinion is that this function should simply be removed. It is an incomplete attempt at dealing with an edge case (MAC address collisions), which is not a problem this function alone could ever hope to solve completely. ok? diff d32c3633e170510dd593f1e288e78acfddaff882 32e6a77a0992dc0014e72c20005dfd9631b2055b blob - bb6367fd1d5dd9f4641fedd96491069a8f0878dc blob + 51d05f49c8b1ea58ea891f7b0f817e3bf94bed08 --- sys/net80211/ieee80211_input.c +++ sys/net80211/ieee80211_input.c @@ -1751,37 +1751,7 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str ic->ic_stats.is_rx_chanmismatch++; return; } - /* - * Use mac, channel and rssi so we collect only the - * best potential AP with the equal bssid while scanning. - * Collecting all potential APs may result in bloat of - * the node tree. This call will return NULL if the node - * for this APs does not exist or if the new node is the - * potential better one. - */ - ni = ieee80211_find_node_for_beacon(ic, wh->i_addr2, - &ic->ic_channels[chan], ssid, rxi->rxi_rssi); - if (ni != NULL) { - /* - * If we are doing a directed scan for an AP with a hidden SSID - * we must collect the SSID from a probe response to override - * a non-zero-length SSID filled with zeroes that we may have - * received earlier in a beacon. - */ - if (isprobe && ssid[1] != 0 && ni->ni_essid[0] == '\0') { - ni->ni_esslen = ssid[1]; - memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); - /* we know that ssid[1] <= IEEE80211_NWID_LEN */ - memcpy(ni->ni_essid, &ssid[2], ssid[1]); - } - /* Update channel in case AP has switched */ - if (ic->ic_opmode == IEEE80211_M_STA) - ni->ni_chan = rni->ni_chan; - - return; - } - #ifdef IEEE80211_DEBUG if (ieee80211_debug > 1 && (ni == NULL || ic->ic_state == IEEE80211_S_SCAN || @@ -1977,6 +1947,13 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str } } + /* + * Set our SSID if we do not know it yet. + * If we are doing a directed scan for an AP with a hidden SSID + * we must collect the SSID from a probe response to override + * a non-zero-length SSID filled with zeroes that we may have + * received earlier in a beacon. + */ if (ssid[1] != 0 && ni->ni_essid[0] == '\0') { ni->ni_esslen = ssid[1]; memset(ni->ni_essid, 0, sizeof(ni->ni_essid)); blob - 98cac0edbe5d0a070244293819042423b33e1e68 blob + 691dbc4f48afcdec88f15856c97fc3ebe123db70 --- sys/net80211/ieee80211_node.c +++ sys/net80211/ieee80211_node.c @@ -2025,30 +2025,6 @@ ieee80211_find_rxnode(struct ieee80211com *ic, return ieee80211_ref_node(ni); } -struct ieee80211_node * -ieee80211_find_node_for_beacon(struct ieee80211com *ic, - const u_int8_t *macaddr, const struct ieee80211_channel *chan, - const char *ssid, u_int8_t rssi) -{ - struct ieee80211_node *ni, *keep = NULL; - int s, score = 0; - - if ((ni = ieee80211_find_node(ic, macaddr)) != NULL) { - s = splnet(); - - if (ni->ni_chan != chan && ni->ni_rssi >= rssi) - score++; - if (ssid[1] == 0 && ni->ni_esslen != 0) - score++; - if (score > 0) - keep = ni; - - splx(s); - } - - return (keep); -} - void ieee80211_node_tx_ba_clear(struct ieee80211_node *ni, int tid) { blob - ca7f9cd59bbc04c36318d64eaf8ef2036a07644e blob + 4edf341acf6ae1ed4e6c3361bcc19a585dab636e --- sys/net80211/ieee80211_node.h +++ sys/net80211/ieee80211_node.h @@ -524,10 +524,6 @@ struct ieee80211_node *ieee80211_find_rxnode(struct ie const struct ieee80211_frame *); struct ieee80211_node *ieee80211_find_txnode(struct ieee80211com *, const u_int8_t *); -struct ieee80211_node * - ieee80211_find_node_for_beacon(struct ieee80211com *, - const u_int8_t *, const struct ieee80211_channel *, - const char *, u_int8_t); void ieee80211_release_node(struct ieee80211com *, struct ieee80211_node *); void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *);