1 --- a/net80211/ieee80211_scan.c
2 +++ b/net80211/ieee80211_scan.c
3 @@ -97,6 +97,123 @@ struct scan_state {
4 static void scan_restart_pwrsav(unsigned long);
5 static void scan_next(unsigned long);
7 +spinlock_t channel_lock = SPIN_LOCK_UNLOCKED;
8 +static LIST_HEAD(channels_inuse);
10 +struct channel_inuse {
11 + struct list_head list;
12 + struct ieee80211com *ic;
18 +get_signal(u8 bw, u8 distance)
22 + /* signal = 1 - (distance / bw)^2 [scale: 100] */
23 + v = 100 * distance / bw;
24 + v = (100 - ((v * v) / 100));
29 +get_overlap(u16 f1, u16 f2, u8 b1, u8 b2)
34 + /* add offsets for sidechannel interference */
38 + /* use only one direction */
42 + if (f1 + b1 < f2 - b2)
46 + c = d * b1 / (b1 + b2);
47 + v = get_signal(b1, c);
53 +get_channel_bw(struct ieee80211_channel *c)
55 + switch(c->ic_flags & (
56 + IEEE80211_CHAN_HALF |
57 + IEEE80211_CHAN_QUARTER |
58 + IEEE80211_CHAN_TURBO |
59 + IEEE80211_CHAN_STURBO)) {
60 + case IEEE80211_CHAN_QUARTER:
62 + case IEEE80211_CHAN_HALF:
64 + case IEEE80211_CHAN_TURBO:
65 + case IEEE80211_CHAN_STURBO:
72 +/* must be called with channel_lock held */
74 +ieee80211_scan_get_bias(struct ieee80211_channel *c)
76 + struct channel_inuse *ch;
77 + u8 bw = get_channel_bw(c);
80 + list_for_each_entry(ch, &channels_inuse, list) {
81 + if (ch->freq == c->ic_freq) {
85 + if (c->ic_freq < ch->freq)
86 + bias += get_overlap(c->ic_freq, ch->freq, bw, ch->bw);
88 + bias += get_overlap(ch->freq, c->ic_freq, ch->bw, bw);
92 +EXPORT_SYMBOL(ieee80211_scan_get_bias);
94 +/* must be called with channel_lock held */
96 +ieee80211_scan_set_bss_channel(struct ieee80211com *ic, struct ieee80211_channel *c)
98 + unsigned long flags;
99 + struct channel_inuse *ch;
101 + list_for_each_entry(ch, &channels_inuse, list) {
107 + if (c && (c != IEEE80211_CHAN_ANYC)) {
109 + ch = kmalloc(sizeof(struct channel_inuse), GFP_ATOMIC);
111 + INIT_LIST_HEAD(&ch->list);
112 + list_add(&ch->list, &channels_inuse);
114 + ch->freq = c->ic_freq;
115 + ch->bw = get_channel_bw(c);
117 + list_del(&ch->list);
121 +EXPORT_SYMBOL(ieee80211_scan_set_bss_channel);
125 ieee80211_scan_attach(struct ieee80211com *ic)
127 @@ -1169,7 +1286,7 @@ ieee80211_scan_dfs_action(struct ieee802
128 IEEE80211_RADAR_CHANCHANGE_TBTT_COUNT;
129 ic->ic_flags |= IEEE80211_F_CHANSWITCH;
132 + unsigned long flags;
133 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
134 "%s: directly switching to channel "
135 "%3d (%4d MHz)\n", __func__,
136 @@ -1180,6 +1297,9 @@ ieee80211_scan_dfs_action(struct ieee802
137 * change the channel here. */
138 change_channel(ic, new_channel);
139 ic->ic_bsschan = new_channel;
140 + spin_lock_irqsave(&channel_lock, flags);
141 + ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
142 + spin_unlock_irqrestore(&channel_lock, flags);
144 vap->iv_bss->ni_chan = new_channel;
146 --- a/net80211/ieee80211_scan.h
147 +++ b/net80211/ieee80211_scan.h
150 #define IEEE80211_SCAN_MAX IEEE80211_CHAN_MAX
152 +extern spinlock_t channel_lock;
153 struct ieee80211_scanner;
154 struct ieee80211_scan_entry;
156 @@ -116,6 +117,8 @@ void ieee80211_scan_flush(struct ieee802
157 struct ieee80211_scan_entry;
158 typedef int ieee80211_scan_iter_func(void *, const struct ieee80211_scan_entry *);
159 int ieee80211_scan_iterate(struct ieee80211com *, ieee80211_scan_iter_func *, void *);
160 +u32 ieee80211_scan_get_bias(struct ieee80211_channel *c);
161 +void ieee80211_scan_set_bss_channel(struct ieee80211com *ic, struct ieee80211_channel *c);
164 * Parameters supplied when adding/updating an entry in a
165 --- a/net80211/ieee80211.c
166 +++ b/net80211/ieee80211.c
167 @@ -373,8 +373,16 @@ void
168 ieee80211_ifdetach(struct ieee80211com *ic)
170 struct ieee80211vap *vap;
171 + unsigned long flags;
174 + /* mark the channel as no longer in use */
175 + ic->ic_bsschan = IEEE80211_CHAN_ANYC;
176 + spin_lock_irqsave(&channel_lock, flags);
177 + ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
178 + spin_unlock_irqrestore(&channel_lock, flags);
181 /* bring down all vaps */
182 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
183 ieee80211_stop(vap->iv_dev);
184 --- a/net80211/ieee80211_input.c
185 +++ b/net80211/ieee80211_input.c
186 @@ -2775,6 +2775,7 @@ static void
187 ieee80211_doth_switch_channel(struct ieee80211vap *vap)
189 struct ieee80211com *ic = vap->iv_ic;
190 + unsigned long flags;
192 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
193 "%s: Channel switch to %3d (%4d MHz) NOW!\n",
194 @@ -2797,6 +2798,9 @@ ieee80211_doth_switch_channel(struct iee
196 ic->ic_curchan = ic->ic_bsschan = vap->iv_csa_chan;
197 ic->ic_set_channel(ic);
198 + spin_lock_irqsave(&channel_lock, flags);
199 + ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
200 + spin_unlock_irqrestore(&channel_lock, flags);
204 --- a/net80211/ieee80211_node.c
205 +++ b/net80211/ieee80211_node.c
206 @@ -308,6 +308,7 @@ ieee80211_create_ibss(struct ieee80211va
208 struct ieee80211com *ic = vap->iv_ic;
209 struct ieee80211_node *ni;
210 + unsigned long flags;
212 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
213 "%s: creating ibss on channel %u\n", __func__,
214 @@ -386,6 +387,9 @@ ieee80211_create_ibss(struct ieee80211va
215 ic->ic_bsschan = chan;
216 ieee80211_node_set_chan(ic, ni);
217 ic->ic_curmode = ieee80211_chan2mode(chan);
218 + spin_lock_irqsave(&channel_lock, flags);
219 + ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
220 + spin_unlock_irqrestore(&channel_lock, flags);
222 /* Update country ie information */
223 ieee80211_build_countryie(ic);
224 @@ -622,6 +626,7 @@ ieee80211_sta_join1(struct ieee80211_nod
225 struct ieee80211vap *vap = selbs->ni_vap;
226 struct ieee80211com *ic = selbs->ni_ic;
227 struct ieee80211_node *obss;
228 + unsigned long flags;
231 if (vap->iv_opmode == IEEE80211_M_IBSS) {
232 @@ -650,6 +655,9 @@ ieee80211_sta_join1(struct ieee80211_nod
233 ic->ic_curchan = ic->ic_bsschan;
234 ic->ic_curmode = ieee80211_chan2mode(ic->ic_curchan);
235 ic->ic_set_channel(ic);
236 + spin_lock_irqsave(&channel_lock, flags);
237 + ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
238 + spin_unlock_irqrestore(&channel_lock, flags);
240 * Set the erp state (mostly the slot time) to deal with
241 * the auto-select case; this should be redundant if the
242 --- a/net80211/ieee80211_proto.c
243 +++ b/net80211/ieee80211_proto.c
244 @@ -1231,6 +1231,7 @@ ieee80211_dturbo_switch(struct ieee80211
245 struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
247 struct ieee80211_channel *chan;
248 + unsigned long flags;
250 chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags);
251 if (chan == NULL) { /* XXX should not happen */
252 @@ -1249,6 +1250,9 @@ ieee80211_dturbo_switch(struct ieee80211
253 ic->ic_bsschan = chan;
254 ic->ic_curchan = chan;
255 ic->ic_set_channel(ic);
256 + spin_lock_irqsave(&channel_lock, flags);
257 + ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
258 + spin_unlock_irqrestore(&channel_lock, flags);
259 /* NB: do not need to reset ERP state because in sta mode */
261 EXPORT_SYMBOL(ieee80211_dturbo_switch);
262 --- a/net80211/ieee80211_wireless.c
263 +++ b/net80211/ieee80211_wireless.c
264 @@ -4076,8 +4076,13 @@ ieee80211_ioctl_setchanlist(struct net_d
265 if (nchan == 0) /* no valid channels, disallow */
267 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && /* XXX */
268 - isclr(chanlist, ic->ic_bsschan->ic_ieee))
269 + isclr(chanlist, ic->ic_bsschan->ic_ieee)) {
270 + unsigned long flags;
271 ic->ic_bsschan = IEEE80211_CHAN_ANYC; /* invalidate */
272 + spin_lock_irqsave(&channel_lock, flags);
273 + ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan);
274 + spin_unlock_irqrestore(&channel_lock, flags);
277 memcpy(ic->ic_chan_active, chanlist, sizeof(ic->ic_chan_active));
278 /* update Supported Channels information element */
279 --- a/net80211/ieee80211_scan_ap.c
280 +++ b/net80211/ieee80211_scan_ap.c
281 @@ -208,9 +208,15 @@ ap_start(struct ieee80211_scan_state *ss
282 struct ieee80211com *ic = NULL;
284 unsigned int mode = 0;
285 + unsigned long sflags;
287 SCAN_AP_LOCK_IRQ(as);
290 + spin_lock_irqsave(&channel_lock, sflags);
291 + ieee80211_scan_set_bss_channel(ic, NULL);
292 + spin_unlock_irqrestore(&channel_lock, sflags);
294 /* Determine mode flags to match, or leave zero for auto mode */
296 ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode);
297 @@ -423,8 +429,10 @@ pc_cmp_idletime(struct ieee80211_channel
298 if (!a->ic_idletime || !b->ic_idletime)
301 - /* a is better than b (return < 0) when a has more idle time than b */
302 - return b->ic_idletime - a->ic_idletime;
303 + /* a is better than b (return < 0) when a has more idle and less bias time than b */
305 + ((100 - (u32) a->ic_idletime) + ieee80211_scan_get_bias(a)) -
306 + ((100 - (u32) b->ic_idletime) + ieee80211_scan_get_bias(b));
310 @@ -575,6 +583,7 @@ ap_end(struct ieee80211_scan_state *ss,
311 struct ap_state *as = ss->ss_priv;
312 struct ieee80211_channel *bestchan = NULL;
313 struct ieee80211com *ic = NULL;
314 + unsigned long sflags;
317 SCAN_AP_LOCK_IRQ(as);
318 @@ -586,8 +595,11 @@ ap_end(struct ieee80211_scan_state *ss,
320 /* record stats for the channel that was scanned last */
321 ic->ic_set_channel(ic);
322 + spin_lock_irqsave(&channel_lock, sflags);
323 + ieee80211_scan_set_bss_channel(ic, NULL);
324 bestchan = pick_channel(ss, vap, flags);
325 if (bestchan == NULL) {
326 + spin_unlock_irqrestore(&channel_lock, sflags);
327 if (ss->ss_last > 0) {
328 /* no suitable channel, should not happen */
329 printk(KERN_ERR "%s: %s: no suitable channel! "
330 @@ -606,6 +618,7 @@ ap_end(struct ieee80211_scan_state *ss,
331 bestchan->ic_freq, bestchan->ic_flags &
332 ~IEEE80211_CHAN_TURBO)) == NULL) {
333 /* should never happen ?? */
334 + spin_unlock_irqrestore(&channel_lock, sflags);
335 SCAN_AP_UNLOCK_IRQ_EARLY(as);
338 @@ -618,6 +631,9 @@ ap_end(struct ieee80211_scan_state *ss,
339 as->as_action = action;
342 + ieee80211_scan_set_bss_channel(ic, bestchan);
343 + spin_unlock_irqrestore(&channel_lock, sflags);
345 /* Must defer action to avoid possible recursive call through
346 * 80211 state machine, which would result in recursive