[package] madwifi: remove cruft from madwifi.sh introduced by r15954, thanks Vasilis...
[openwrt.git] / 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 @@ -2772,6 +2772,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 @@ -2794,6 +2795,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 @@ -1225,6 +1225,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 @@ -1243,6 +1244,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. */