Add an optional background scanning threshold triggered by low rssi (useful for passing updated scan results to the supplicant ahead of time, before losing connectivity entirely) Signed-off-by: Felix Fietkau --- a/net80211/ieee80211_ioctl.h +++ b/net80211/ieee80211_ioctl.h @@ -646,6 +646,7 @@ IEEE80211_PARAM_MINRATE = 76, /* Maximum rate (by table index) */ IEEE80211_PARAM_PROTMODE_RSSI = 77, /* RSSI Threshold for enabling protection mode */ IEEE80211_PARAM_PROTMODE_TIMEOUT = 78, /* Timeout for expiring protection mode */ + IEEE80211_PARAM_BGSCAN_THRESH = 79, /* bg scan rssi threshold */ }; #define SIOCG80211STATS (SIOCDEVPRIVATE+2) --- a/net80211/ieee80211_var.h +++ b/net80211/ieee80211_var.h @@ -92,6 +92,8 @@ #define IEEE80211_BGSCAN_IDLE_MIN 100 /* min idle time (ms) */ #define IEEE80211_BGSCAN_IDLE_DEFAULT 250 /* default idle time (ms) */ +#define IEEE80211_BGSCAN_TRIGGER_INTVL 20 /* min trigger interval for thresh based bgscan (secs) */ + #define IEEE80211_COVERAGE_CLASS_MAX 31 /* max coverage class */ #define IEEE80211_REGCLASSIDS_MAX 10 /* max regclass id list */ @@ -219,6 +221,9 @@ u_int8_t iv_nickname[IEEE80211_NWID_LEN]; u_int iv_bgscanidle; /* bg scan idle threshold */ u_int iv_bgscanintvl; /* bg scan min interval */ + u_int iv_bgscanthr; /* bg scan rssi threshold */ + u_int iv_bgscantrintvl; /* bg scan trigger interval */ + unsigned long iv_bgscanthr_next; /* last trigger for bgscan */ u_int iv_scanvalid; /* scan cache valid threshold */ struct ieee80211_roam iv_roam; /* sta-mode roaming state */ @@ -608,6 +613,7 @@ #define IEEE80211_FEXT_SWBMISS 0x00000400 /* CONF: use software beacon timer */ #define IEEE80211_FEXT_DROPUNENC_EAPOL 0x00000800 /* CONF: drop unencrypted eapol frames */ #define IEEE80211_FEXT_APPIE_UPDATE 0x00001000 /* STATE: beacon APP IE updated */ +#define IEEE80211_FEXT_BGSCAN_THR 0x00002000 /* bgscan due to low rssi */ #define IEEE80211_COM_UAPSD_ENABLE(_ic) ((_ic)->ic_flags_ext |= IEEE80211_FEXT_UAPSD) #define IEEE80211_COM_UAPSD_DISABLE(_ic) ((_ic)->ic_flags_ext &= ~IEEE80211_FEXT_UAPSD) --- a/net80211/ieee80211_wireless.c +++ b/net80211/ieee80211_wireless.c @@ -2744,6 +2744,9 @@ else retv = EINVAL; break; + case IEEE80211_PARAM_BGSCAN_THRESH: + vap->iv_bgscanthr = value; + break; case IEEE80211_PARAM_MCAST_RATE: /* units are in KILObits per second */ if (value >= 256 && value <= 54000) @@ -3144,6 +3147,9 @@ case IEEE80211_PARAM_BGSCAN_INTERVAL: param[0] = vap->iv_bgscanintvl / HZ; /* seconds */ break; + case IEEE80211_PARAM_BGSCAN_THRESH: + param[0] = vap->iv_bgscanthr; /* rssi */ + break; case IEEE80211_PARAM_MCAST_RATE: param[0] = vap->iv_mcast_rate; /* seconds */ break; @@ -5666,6 +5672,10 @@ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanintvl" }, { IEEE80211_PARAM_BGSCAN_INTERVAL, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanintvl" }, + { IEEE80211_PARAM_BGSCAN_THRESH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanthr" }, + { IEEE80211_PARAM_BGSCAN_THRESH, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanthr" }, { IEEE80211_PARAM_MCAST_RATE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcast_rate" }, { IEEE80211_PARAM_MCAST_RATE, --- a/net80211/ieee80211_input.c +++ b/net80211/ieee80211_input.c @@ -3013,8 +3013,10 @@ { struct ieee80211com *ic = vap->iv_ic; + vap->iv_bgscantrintvl = (vap->iv_bgscantrintvl + 1) % 4; return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) && - time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle)); + (((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && !vap->iv_bgscantrintvl) || + time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle))); } static __inline int @@ -3258,6 +3260,23 @@ /* record tsf of last beacon */ memcpy(ni->ni_tstamp.data, scan.tstamp, sizeof(ni->ni_tstamp)); + + /* When rssi is low, start doing bgscans more frequently to allow + * the supplicant to make a better switching decision */ + if ((rssi < vap->iv_bgscanthr) && + (!vap->iv_bgscanthr_next || + !time_before(jiffies, vap->iv_bgscanthr_next)) && + !(ic->ic_flags & IEEE80211_F_SCAN)) { + int ret; + + ic->ic_lastdata = 0; + ic->ic_lastscan = 0; + ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN_THR; + ret = ieee80211_bg_scan(vap); + if (ret) + vap->iv_bgscanthr_next = jiffies + msecs_to_jiffies(IEEE80211_BGSCAN_TRIGGER_INTVL * 1000); + } + if (ni->ni_intval != scan.bintval) { IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, "beacon interval divergence: " --- a/net80211/ieee80211_scan.c +++ b/net80211/ieee80211_scan.c @@ -782,7 +782,7 @@ ieee80211_sta_pwrsave(vap, 0); if (ss->ss_next >= ss->ss_last) { ieee80211_notify_scan_done(vap); - ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; + ic->ic_flags_ext &= ~(IEEE80211_FEXT_BGSCAN|IEEE80211_FEXT_BGSCAN_THR); } } SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL;