Ping. I have had zero feedback on this so far. Anyone?
On Tue, Jan 04, 2022 at 02:35:52PM +0100, Stefan Sperling wrote:
> 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 *);
>
>