A wifi driver's newassoc routine gets invoked excessively often in IBSS mode.
It runs whenever a probe response is received. Showing output from a patched
newassoc routine which prints "new node <address>":

Jan 10 02:01:09 jim /bsd: new node 00:24:fe:44:07:bb
Jan 10 02:01:09 jim /bsd: new node 88:25:2c:bf:81:59
Jan 10 02:01:09 jim /bsd: new node 34:81:c4:ac:4e:f0
Jan 10 02:01:09 jim /bsd: new node bc:05:43:c9:8b:d3
Jan 10 02:01:09 jim /bsd: new node 00:0e:8e:24:52:7d
Jan 10 02:01:09 jim /bsd: new node 00:0e:2e:5c:55:4f
Jan 10 02:01:09 jim /bsd: new node 00:24:fe:44:07:bb
Jan 10 02:01:09 jim /bsd: new node 34:81:c4:ac:4e:f0
Jan 10 02:01:09 jim /bsd: new node bc:05:43:c9:8b:d3
Jan 10 02:01:09 jim /bsd: new node 00:0e:8e:24:52:7d
Jan 10 02:01:09 jim /bsd: new node 00:0e:2e:5c:55:4f
Jan 10 02:01:09 jim /bsd: new node 34:81:c4:ac:4e:f0
Jan 10 02:01:09 jim /bsd: new node 00:0e:8e:24:52:7d

It keeps being called for the same nodes, very often. Since drivers
usually reset the node's tx rate in newassoc() this seems rather strange.

Looking at the history of ieee80211_input.c I believe a mistake crept
in several years ago in r1.4:

-               if (ic->ic_state == IEEE80211_S_SCAN)
-                       ieee80211_unref_node(&ni);      /* NB: do not free */
-               else if (ic->ic_opmode == IEEE80211_M_IBSS &&
-                   allocbs && isprobe) {
+               if (ic->ic_opmode == IEEE80211_M_IBSS || (is_new &&
+                   ISPROBE(subtype))) {

Note how && was changed to || in this revision and has since been kept.

The original code in r1.1 in this if-block applied only to IBSS mode:

              else if (ic->ic_opmode == IEEE80211_M_IBSS &&
                  allocbs && isprobe) {
                      /*
                       * Fake an association so the driver can setup it's
                       * private state.  The rate set has been setup above;
                       * there is no handshake as in ap/station operation.
                       */
                      if (ic->ic_newassoc)
                              (*ic->ic_newassoc)(ic, ni, 1);

In AP and station modes newassoc is called via ieee80211_node_join()
so there is no reason to call it for probe responses.

Proposed fix restores the original behaviour and removes an outdated comment.

Index: ieee80211_input.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
retrieving revision 1.128
diff -u -p -r1.128 ieee80211_input.c
--- ieee80211_input.c   23 Dec 2014 03:24:08 -0000      1.128
+++ ieee80211_input.c   10 Jan 2015 02:16:59 -0000
@@ -1633,18 +1633,8 @@ ieee80211_recv_probe_resp(struct ieee802
        /* NB: must be after ni_chan is setup */
        ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT);
 
-       /*
-        * When scanning we record results (nodes) with a zero
-        * refcnt.  Otherwise we want to hold the reference for
-        * ibss neighbors so the nodes don't get released prematurely.
-        * Anything else can be discarded (XXX and should be handled
-        * above so we don't do so much work).
-        */
-       if (
 #ifndef IEEE80211_STA_ONLY
-           ic->ic_opmode == IEEE80211_M_IBSS ||
-#endif
-           (is_new && isprobe)) {
+       if (ic->ic_opmode == IEEE80211_M_IBSS && is_new && isprobe) {
                /*
                 * Fake an association so the driver can setup it's
                 * private state.  The rate set has been setup above;
@@ -1653,6 +1643,7 @@ ieee80211_recv_probe_resp(struct ieee802
                if (ic->ic_newassoc)
                        (*ic->ic_newassoc)(ic, ni, 1);
        }
+#endif
 }
 
 #ifndef IEEE80211_STA_ONLY

Reply via email to