| 1 | Add an optional background scanning threshold triggered by low rssi |
| 2 | (useful for passing updated scan results to the supplicant ahead of |
| 3 | time, before losing connectivity entirely) |
| 4 | |
| 5 | Signed-off-by: Felix Fietkau <nbd@openwrt.org> |
| 6 | |
| 7 | --- a/net80211/ieee80211_ioctl.h |
| 8 | +++ b/net80211/ieee80211_ioctl.h |
| 9 | @@ -646,6 +646,7 @@ enum { |
| 10 | IEEE80211_PARAM_MINRATE = 76, /* Minimum rate (by table index) */ |
| 11 | IEEE80211_PARAM_PROTMODE_RSSI = 77, /* RSSI Threshold for enabling protection mode */ |
| 12 | IEEE80211_PARAM_PROTMODE_TIMEOUT = 78, /* Timeout for expiring protection mode */ |
| 13 | + IEEE80211_PARAM_BGSCAN_THRESH = 79, /* bg scan rssi threshold */ |
| 14 | }; |
| 15 | |
| 16 | #define SIOCG80211STATS (SIOCDEVPRIVATE+2) |
| 17 | --- a/net80211/ieee80211_var.h |
| 18 | +++ b/net80211/ieee80211_var.h |
| 19 | @@ -92,6 +92,8 @@ |
| 20 | #define IEEE80211_BGSCAN_IDLE_MIN 100 /* min idle time (ms) */ |
| 21 | #define IEEE80211_BGSCAN_IDLE_DEFAULT 250 /* default idle time (ms) */ |
| 22 | |
| 23 | +#define IEEE80211_BGSCAN_TRIGGER_INTVL 20 /* min trigger interval for thresh based bgscan (secs) */ |
| 24 | + |
| 25 | #define IEEE80211_COVERAGE_CLASS_MAX 31 /* max coverage class */ |
| 26 | #define IEEE80211_REGCLASSIDS_MAX 10 /* max regclass id list */ |
| 27 | |
| 28 | @@ -219,6 +221,10 @@ struct ieee80211vap { |
| 29 | u_int8_t iv_nickname[IEEE80211_NWID_LEN]; |
| 30 | u_int iv_bgscanidle; /* bg scan idle threshold */ |
| 31 | u_int iv_bgscanintvl; /* bg scan min interval */ |
| 32 | + u_int iv_bgscanthr; /* bg scan rssi threshold */ |
| 33 | + u_int iv_bgscantrintvl; /* bg scan trigger interval */ |
| 34 | + unsigned long iv_bgscanthr_next; /* last trigger for bgscan */ |
| 35 | + unsigned long iv_lastconnect; /* time of last connect attempt */ |
| 36 | u_int iv_scanvalid; /* scan cache valid threshold */ |
| 37 | struct ieee80211_roam iv_roam; /* sta-mode roaming state */ |
| 38 | |
| 39 | @@ -608,6 +614,7 @@ MALLOC_DECLARE(M_80211_VAP); |
| 40 | #define IEEE80211_FEXT_SWBMISS 0x00000400 /* CONF: use software beacon timer */ |
| 41 | #define IEEE80211_FEXT_DROPUNENC_EAPOL 0x00000800 /* CONF: drop unencrypted eapol frames */ |
| 42 | #define IEEE80211_FEXT_APPIE_UPDATE 0x00001000 /* STATE: beacon APP IE updated */ |
| 43 | +#define IEEE80211_FEXT_BGSCAN_THR 0x00002000 /* bgscan due to low rssi */ |
| 44 | |
| 45 | #define IEEE80211_COM_UAPSD_ENABLE(_ic) ((_ic)->ic_flags_ext |= IEEE80211_FEXT_UAPSD) |
| 46 | #define IEEE80211_COM_UAPSD_DISABLE(_ic) ((_ic)->ic_flags_ext &= ~IEEE80211_FEXT_UAPSD) |
| 47 | --- a/net80211/ieee80211_wireless.c |
| 48 | +++ b/net80211/ieee80211_wireless.c |
| 49 | @@ -2744,6 +2744,9 @@ ieee80211_ioctl_setparam(struct net_devi |
| 50 | else |
| 51 | retv = EINVAL; |
| 52 | break; |
| 53 | + case IEEE80211_PARAM_BGSCAN_THRESH: |
| 54 | + vap->iv_bgscanthr = value; |
| 55 | + break; |
| 56 | case IEEE80211_PARAM_MCAST_RATE: |
| 57 | /* units are in KILObits per second */ |
| 58 | if (value >= 256 && value <= 54000) |
| 59 | @@ -3144,6 +3147,9 @@ ieee80211_ioctl_getparam(struct net_devi |
| 60 | case IEEE80211_PARAM_BGSCAN_INTERVAL: |
| 61 | param[0] = vap->iv_bgscanintvl / HZ; /* seconds */ |
| 62 | break; |
| 63 | + case IEEE80211_PARAM_BGSCAN_THRESH: |
| 64 | + param[0] = vap->iv_bgscanthr; /* rssi */ |
| 65 | + break; |
| 66 | case IEEE80211_PARAM_MCAST_RATE: |
| 67 | param[0] = vap->iv_mcast_rate; /* seconds */ |
| 68 | break; |
| 69 | @@ -5666,6 +5672,10 @@ static const struct iw_priv_args ieee802 |
| 70 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanintvl" }, |
| 71 | { IEEE80211_PARAM_BGSCAN_INTERVAL, |
| 72 | 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanintvl" }, |
| 73 | + { IEEE80211_PARAM_BGSCAN_THRESH, |
| 74 | + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "bgscanthr" }, |
| 75 | + { IEEE80211_PARAM_BGSCAN_THRESH, |
| 76 | + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_bgscanthr" }, |
| 77 | { IEEE80211_PARAM_MCAST_RATE, |
| 78 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "mcast_rate" }, |
| 79 | { IEEE80211_PARAM_MCAST_RATE, |
| 80 | --- a/net80211/ieee80211_input.c |
| 81 | +++ b/net80211/ieee80211_input.c |
| 82 | @@ -3013,8 +3013,10 @@ contbgscan(struct ieee80211vap *vap) |
| 83 | { |
| 84 | struct ieee80211com *ic = vap->iv_ic; |
| 85 | |
| 86 | + vap->iv_bgscantrintvl = (vap->iv_bgscantrintvl + 1) % 4; |
| 87 | return ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) && |
| 88 | - time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle)); |
| 89 | + (((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && !vap->iv_bgscantrintvl) || |
| 90 | + time_after(jiffies, ic->ic_lastdata + vap->iv_bgscanidle))); |
| 91 | } |
| 92 | |
| 93 | static __inline int |
| 94 | @@ -3258,6 +3260,25 @@ ieee80211_recv_mgmt(struct ieee80211vap |
| 95 | /* record tsf of last beacon */ |
| 96 | memcpy(ni->ni_tstamp.data, scan.tstamp, |
| 97 | sizeof(ni->ni_tstamp)); |
| 98 | + |
| 99 | + /* When rssi is low, start doing bgscans more frequently to allow |
| 100 | + * the supplicant to make a better switching decision */ |
| 101 | + if (!(ic->ic_flags & IEEE80211_F_SCAN) && (rssi < vap->iv_bgscanthr) && |
| 102 | + (!vap->iv_bgscanthr_next || |
| 103 | + !time_before(jiffies, vap->iv_bgscanthr_next)) && |
| 104 | + (vap->iv_state == IEEE80211_S_RUN) && |
| 105 | + time_after(jiffies, vap->iv_lastconnect + |
| 106 | + msecs_to_jiffies(IEEE80211_BGSCAN_INTVAL_MIN * 1000))) { |
| 107 | + int ret; |
| 108 | + |
| 109 | + ic->ic_lastdata = 0; |
| 110 | + ic->ic_lastscan = 0; |
| 111 | + ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN_THR; |
| 112 | + ret = ieee80211_bg_scan(vap); |
| 113 | + if (ret) |
| 114 | + vap->iv_bgscanthr_next = jiffies + msecs_to_jiffies(IEEE80211_BGSCAN_TRIGGER_INTVL * 1000); |
| 115 | + } |
| 116 | + |
| 117 | if (ni->ni_intval != scan.bintval) { |
| 118 | IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, |
| 119 | "beacon interval divergence: " |
| 120 | --- a/net80211/ieee80211_scan.c |
| 121 | +++ b/net80211/ieee80211_scan.c |
| 122 | @@ -616,6 +616,7 @@ ieee80211_cancel_scan(struct ieee80211va |
| 123 | |
| 124 | /* clear bg scan NOPICK and mark cancel request */ |
| 125 | ss->ss_flags &= ~IEEE80211_SCAN_NOPICK; |
| 126 | + ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN_THR; |
| 127 | SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL; |
| 128 | ss->ss_ops->scan_cancel(ss, vap); |
| 129 | /* force it to fire asap */ |
| 130 | @@ -782,7 +783,7 @@ again: |
| 131 | ieee80211_sta_pwrsave(vap, 0); |
| 132 | if (ss->ss_next >= ss->ss_last) { |
| 133 | ieee80211_notify_scan_done(vap); |
| 134 | - ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; |
| 135 | + ic->ic_flags_ext &= ~(IEEE80211_FEXT_BGSCAN|IEEE80211_FEXT_BGSCAN_THR); |
| 136 | } |
| 137 | } |
| 138 | SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL; |
| 139 | --- a/net80211/ieee80211_proto.c |
| 140 | +++ b/net80211/ieee80211_proto.c |
| 141 | @@ -1450,6 +1450,7 @@ __ieee80211_newstate(struct ieee80211vap |
| 142 | } |
| 143 | break; |
| 144 | case IEEE80211_S_AUTH: |
| 145 | + vap->iv_lastconnect = jiffies; |
| 146 | /* auth frames are possible between IBSS nodes, |
| 147 | * see 802.11-1999, chapter 5.7.6 */ |
| 148 | KASSERT(vap->iv_opmode == IEEE80211_M_STA || |
| 149 | --- a/net80211/ieee80211_output.c |
| 150 | +++ b/net80211/ieee80211_output.c |
| 151 | @@ -238,7 +238,8 @@ ieee80211_hardstart(struct sk_buff *skb, |
| 152 | } |
| 153 | |
| 154 | /* Cancel any running BG scan */ |
| 155 | - ieee80211_cancel_scan(vap); |
| 156 | + if (!(ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && (vap->iv_state == IEEE80211_S_RUN)) |
| 157 | + ieee80211_cancel_scan(vap); |
| 158 | |
| 159 | /* |
| 160 | * Find the node for the destination so we can do |
| 161 | |