Root/package/madwifi/patches/411-autochannel_multi.patch

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);
6 
7+spinlock_t channel_lock = SPIN_LOCK_UNLOCKED;
8+static LIST_HEAD(channels_inuse);
9+
10+struct channel_inuse {
11+ struct list_head list;
12+ struct ieee80211com *ic;
13+ u16 freq;
14+ u8 bw;
15+};
16+
17+static inline u32
18+get_signal(u8 bw, u8 distance)
19+{
20+ u32 v;
21+
22+ /* signal = 1 - (distance / bw)^2 [scale: 100] */
23+ v = 100 * distance / bw;
24+ v = (100 - ((v * v) / 100));
25+ return v;
26+}
27+
28+static u32
29+get_overlap(u16 f1, u16 f2, u8 b1, u8 b2)
30+{
31+ u32 v;
32+ u16 d, c;
33+
34+ /* add offsets for sidechannel interference */
35+ b1 += (b1 / 5);
36+ b2 += (b2 / 5);
37+
38+ /* use only one direction */
39+ b1 /= 2;
40+ b2 /= 2;
41+
42+ if (f1 + b1 < f2 - b2)
43+ return 0;
44+
45+ d = f2 - f1;
46+ c = d * b1 / (b1 + b2);
47+ v = get_signal(b1, c);
48+
49+ return v * v / 100;
50+}
51+
52+static u8
53+get_channel_bw(struct ieee80211_channel *c)
54+{
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:
61+ return 5;
62+ case IEEE80211_CHAN_HALF:
63+ return 10;
64+ case IEEE80211_CHAN_TURBO:
65+ case IEEE80211_CHAN_STURBO:
66+ return 40;
67+ default:
68+ return 20;
69+ }
70+}
71+
72+/* must be called with channel_lock held */
73+u32
74+ieee80211_scan_get_bias(struct ieee80211_channel *c)
75+{
76+ struct channel_inuse *ch;
77+ u8 bw = get_channel_bw(c);
78+ u32 bias = 0;
79+
80+ list_for_each_entry(ch, &channels_inuse, list) {
81+ if (ch->freq == c->ic_freq) {
82+ bias += 50;
83+ continue;
84+ }
85+ if (c->ic_freq < ch->freq)
86+ bias += get_overlap(c->ic_freq, ch->freq, bw, ch->bw);
87+ else
88+ bias += get_overlap(ch->freq, c->ic_freq, ch->bw, bw);
89+ }
90+ return bias;
91+}
92+EXPORT_SYMBOL(ieee80211_scan_get_bias);
93+
94+/* must be called with channel_lock held */
95+void
96+ieee80211_scan_set_bss_channel(struct ieee80211com *ic, struct ieee80211_channel *c)
97+{
98+ unsigned long flags;
99+ struct channel_inuse *ch;
100+
101+ list_for_each_entry(ch, &channels_inuse, list) {
102+ if (ch->ic == ic)
103+ goto found;
104+ }
105+ ch = NULL;
106+found:
107+ if (c && (c != IEEE80211_CHAN_ANYC)) {
108+ if (!ch) {
109+ ch = kmalloc(sizeof(struct channel_inuse), GFP_ATOMIC);
110+ ch->ic = ic;
111+ INIT_LIST_HEAD(&ch->list);
112+ list_add(&ch->list, &channels_inuse);
113+ }
114+ ch->freq = c->ic_freq;
115+ ch->bw = get_channel_bw(c);
116+ } else if (ch) {
117+ list_del(&ch->list);
118+ kfree(ch);
119+ }
120+}
121+EXPORT_SYMBOL(ieee80211_scan_set_bss_channel);
122+
123+
124 void
125 ieee80211_scan_attach(struct ieee80211com *ic)
126 {
127@@ -1169,7 +1286,7 @@ ieee80211_scan_dfs_action(struct ieee802
128                 IEEE80211_RADAR_CHANCHANGE_TBTT_COUNT;
129             ic->ic_flags |= IEEE80211_F_CHANSWITCH;
130         } else {
131-
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);
143             if (vap->iv_bss)
144                 vap->iv_bss->ni_chan = new_channel;
145         }
146--- a/net80211/ieee80211_scan.h
147+++ b/net80211/ieee80211_scan.h
148@@ -35,6 +35,7 @@
149 
150 #define IEEE80211_SCAN_MAX IEEE80211_CHAN_MAX
151 
152+extern spinlock_t channel_lock;
153 struct ieee80211_scanner;
154 struct ieee80211_scan_entry;
155 
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);
162 
163 /*
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)
169 {
170     struct ieee80211vap *vap;
171+ unsigned long flags;
172     int count;
173 
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);
179+
180+
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)
188 {
189     struct ieee80211com *ic = vap->iv_ic;
190+ unsigned long flags;
191 
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
195 
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);
201 }
202 
203 static void
204--- a/net80211/ieee80211_node.c
205+++ b/net80211/ieee80211_node.c
206@@ -308,6 +308,7 @@ ieee80211_create_ibss(struct ieee80211va
207 {
208     struct ieee80211com *ic = vap->iv_ic;
209     struct ieee80211_node *ni;
210+ unsigned long flags;
211 
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);
221 
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;
229     int canreassoc;
230 
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);
239     /*
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);
246 #endif
247     struct ieee80211_channel *chan;
248+ unsigned long flags;
249 
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 */
260 }
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 */
266         return -EINVAL;
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);
275+ }
276 
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;
283     int i;
284     unsigned int mode = 0;
285+ unsigned long sflags;
286 
287     SCAN_AP_LOCK_IRQ(as);
288     ic = vap->iv_ic;
289+
290+ spin_lock_irqsave(&channel_lock, sflags);
291+ ieee80211_scan_set_bss_channel(ic, NULL);
292+ spin_unlock_irqrestore(&channel_lock, sflags);
293+
294     /* Determine mode flags to match, or leave zero for auto mode */
295     ss->ss_last = 0;
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)
299         return 0;
300 
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 */
304+ return
305+ ((100 - (u32) a->ic_idletime) + ieee80211_scan_get_bias(a)) -
306+ ((100 - (u32) b->ic_idletime) + ieee80211_scan_get_bias(b));
307 }
308 
309 
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;
315     int res = 1;
316 
317     SCAN_AP_LOCK_IRQ(as);
318@@ -586,8 +595,11 @@ ap_end(struct ieee80211_scan_state *ss,
319 
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);
336                 return 0;
337             }
338@@ -618,6 +631,9 @@ ap_end(struct ieee80211_scan_state *ss,
339             as->as_action = action;
340         as->as_selbss = se;
341 
342+ ieee80211_scan_set_bss_channel(ic, bestchan);
343+ spin_unlock_irqrestore(&channel_lock, sflags);
344+
345         /* Must defer action to avoid possible recursive call through
346          * 80211 state machine, which would result in recursive
347          * locking. */
348

Archive Download this file



interactive