aboutsummaryrefslogtreecommitdiffstats
path: root/package/madwifi/patches/357-bgscan_thresh.patch
blob: c9d60ea856e3b3e9170ed01156ac7c69fc8dde4a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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 <nbd@openwrt.org>

--- a/net80211/ieee80211_ioctl.h
+++ b/net80211/ieee80211_ioctl.h
@@ -646,6 +646,7 @@ enum {
 	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,10 @@ struct ieee80211vap {
 	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 */
+	unsigned long iv_lastconnect;	/* time of last connect attempt */
 	u_int iv_scanvalid;				/* scan cache valid threshold */
 	struct ieee80211_roam iv_roam;			/* sta-mode roaming state */
 
@@ -608,6 +614,7 @@ MALLOC_DECLARE(M_80211_VAP);
 #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 @@ ieee80211_ioctl_setparam(struct net_devi
 		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 @@ ieee80211_ioctl_getparam(struct net_devi
 	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 @@ static const struct iw_priv_args ieee802
 	  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 @@ contbgscan(struct ieee80211vap *vap)
 {
 	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,25 @@ ieee80211_recv_mgmt(struct ieee80211vap 
 			/* 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 (!(ic->ic_flags & IEEE80211_F_SCAN) && (rssi < vap->iv_bgscanthr) &&
+					(!vap->iv_bgscanthr_next ||
+						!time_before(jiffies, vap->iv_bgscanthr_next)) &&
+					(vap->iv_state == IEEE80211_S_RUN) &&
+					time_after(jiffies, vap->iv_lastconnect +
+						msecs_to_jiffies(IEEE80211_BGSCAN_INTVAL_MIN * 1000))) {
+				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
@@ -616,6 +616,7 @@ ieee80211_cancel_scan(struct ieee80211va
 
 		/* clear bg scan NOPICK and mark cancel request */
 		ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
+		ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN_THR;
 		SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
 		ss->ss_ops->scan_cancel(ss, vap);
 		/* force it to fire asap */
@@ -782,7 +783,7 @@ again:
 				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;
--- a/net80211/ieee80211_proto.c
+++ b/net80211/ieee80211_proto.c
@@ -1450,6 +1450,7 @@ __ieee80211_newstate(struct ieee80211vap
 		}
 		break;
 	case IEEE80211_S_AUTH:
+		vap->iv_lastconnect = jiffies;
 		/* auth frames are possible between IBSS nodes, 
 		 * see 802.11-1999, chapter 5.7.6 */
 		KASSERT(vap->iv_opmode == IEEE80211_M_STA || 
--- a/net80211/ieee80211_output.c
+++ b/net80211/ieee80211_output.c
@@ -238,7 +238,8 @@ ieee80211_hardstart(struct sk_buff *skb,
 	}
 	
 	/* Cancel any running BG scan */
-	ieee80211_cancel_scan(vap);
+	if (!(ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN_THR) && (vap->iv_state == IEEE80211_S_RUN))
+		ieee80211_cancel_scan(vap);
 
 	/* 
 	 * Find the node for the destination so we can do