This diff tries to avoid situations where background scans play
ping-pong between different APs with nearly equal RSSI, as
observed by phessler.

Not all drivers represent RSSI values in dBm or percentage, so the
diff includes the possibility for drivers to override the new RSSI
comparison function. However, since the threshold is rather low
applying this to all drivers for now should not do any harm, unless
there is a driver where the RSSI value range is ridiculously small.
I'm not aware of any such driver at present.

Paul, do you think this is approach fits into the larger context
of your plans for RSSI? Or would it disturb you?

Index: ieee80211_node.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_node.c,v
retrieving revision 1.129
diff -u -p -r1.129 ieee80211_node.c
--- ieee80211_node.c    28 Apr 2018 14:49:07 -0000      1.129
+++ ieee80211_node.c    29 Apr 2018 09:08:05 -0000
@@ -67,6 +67,8 @@ u_int8_t ieee80211_node_getrssi(struct i
     const struct ieee80211_node *);
 int ieee80211_node_checkrssi(struct ieee80211com *,
     const struct ieee80211_node *);
+int ieee80211_node_cmprssi(struct ieee80211com *,
+    const struct ieee80211_node *, uint8_t);
 void ieee80211_setup_node(struct ieee80211com *, struct ieee80211_node *,
     const u_int8_t *);
 void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *);
@@ -133,6 +135,7 @@ ieee80211_node_attach(struct ifnet *ifp)
        ic->ic_node_copy = ieee80211_node_copy;
        ic->ic_node_getrssi = ieee80211_node_getrssi;
        ic->ic_node_checkrssi = ieee80211_node_checkrssi;
+       ic->ic_node_cmprssi = ieee80211_node_cmprssi;
        ic->ic_scangen = 1;
        ic->ic_max_nnodes = ieee80211_cache_size;
 
@@ -761,12 +764,15 @@ ieee80211_end_scan(struct ifnet *ifp)
 
                if (ic->ic_caps & IEEE80211_C_SCANALLBAND) {
                        if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) &&
-                           (selbs2 == NULL || ni->ni_rssi > selbs2->ni_rssi))
+                           (selbs2 == NULL ||
+                           ic->ic_node_cmprssi(ic, ni, selbs2->ni_rssi) > 0))
                                selbs2 = ni;
                        else if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) &&
-                           (selbs5 == NULL || ni->ni_rssi > selbs5->ni_rssi))
+                           (selbs5 == NULL ||
+                           ic->ic_node_cmprssi(ic, ni, selbs5->ni_rssi) > 0))
                                selbs5 = ni;
-               } else if (selbs == NULL || ni->ni_rssi > selbs->ni_rssi)
+               } else if (selbs == NULL ||
+                   ic->ic_node_cmprssi(ic, ni, selbs->ni_rssi) > 0)
                        selbs = ni;
        }
 
@@ -782,9 +788,12 @@ ieee80211_end_scan(struct ifnet *ifp)
         */
        if (selbs5 && selbs5->ni_rssi > min_5ghz_rssi)
                selbs = selbs5;
-       else if (selbs5 && selbs2)
-               selbs = (selbs5->ni_rssi >= selbs2->ni_rssi ? selbs5 : selbs2);
-       else if (selbs2)
+       else if (selbs5 && selbs2) {
+               if (ic->ic_node_cmprssi(ic, selbs5, selbs2->ni_rssi) >= 0)
+                       selbs = selbs5;
+               else
+                       selbs = selbs2;
+       } else if (selbs2)
                selbs = selbs2;
        else if (selbs5)
                selbs = selbs5;
@@ -991,6 +1000,31 @@ ieee80211_node_checkrssi(struct ieee8021
        return (ni->ni_rssi >= (u_int8_t)thres);
 }
 
+/*
+ * Determine if an RSSI value is significantly different from the
+ * RSSI stored in a node structure. This function assumes RSSI values
+ * are represented either dBm or as a percentage of ic_max_rssi.
+ * Drivers should override this function in case their RSSI
+ * values use a different representation.
+ */
+int
+ieee80211_node_cmprssi(struct ieee80211com *ic,
+    const struct ieee80211_node *ni, uint8_t rssi)
+{
+       uint8_t thres;
+
+       if (ic->ic_max_rssi)
+               thres = IEEE80211_RSSI_CMP_THRES_RATIO;
+       else
+               thres = IEEE80211_RSSI_CMP_THRES;
+
+       if (ni->ni_rssi + thres < rssi)
+               return -1;
+       if (ni->ni_rssi - thres > rssi)
+               return 1;
+       return 0;
+}
+
 void
 ieee80211_setup_node(struct ieee80211com *ic,
        struct ieee80211_node *ni, const u_int8_t *macaddr)
@@ -1259,7 +1293,8 @@ ieee80211_find_node_for_beacon(struct ie
        if ((ni = ieee80211_find_node(ic, macaddr)) != NULL) {
                s = splnet();
 
-               if (ni->ni_chan != chan && ni->ni_rssi >= rssi)
+               if (ni->ni_chan != chan &&
+                   ic->ic_node_cmprssi(ic, ni, rssi) >= 0)
                        score++;
                if (ssid[1] == 0 && ni->ni_esslen != 0)
                        score++;
Index: ieee80211_var.h
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_var.h,v
retrieving revision 1.85
diff -u -p -r1.85 ieee80211_var.h
--- ieee80211_var.h     26 Apr 2018 12:50:07 -0000      1.85
+++ ieee80211_var.h     29 Apr 2018 08:54:20 -0000
@@ -62,6 +62,9 @@
 #define IEEE80211_RSSI_THRES_RATIO_2GHZ                60      /* in percent */
 #define IEEE80211_RSSI_THRES_RATIO_5GHZ                50      /* in percent */
 
+#define IEEE80211_RSSI_CMP_THRES               8       /* in dBm */
+#define IEEE80211_RSSI_CMP_THRES_RATIO         5       /* in percent */
+
 #define IEEE80211_BGSCAN_FAIL_MAX              360     /* units of 500 msec */
 
 enum ieee80211_phytype {
@@ -270,6 +273,8 @@ struct ieee80211com {
                                        const struct ieee80211_node *);
        int                     (*ic_node_checkrssi)(struct ieee80211com *,
                                        const struct ieee80211_node *);
+       int                     (*ic_node_cmprssi)(struct ieee80211com *,
+                                       const struct ieee80211_node *, uint8_t);
        u_int8_t                ic_max_rssi;
        struct ieee80211_tree   ic_tree;
        int                     ic_nnodes;      /* length of ic_nnodes */

Reply via email to