brcm47xx-2.6 cleanup, fix the kernel config
[openwrt.git] / package / d80211 / src / ieee80211_scan.c
1 /*
2  * Copyright 2002-2004, Instant802 Networks, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include <linux/module.h>
10 #include <linux/netdevice.h>
11 #include <linux/types.h>
12 #include <linux/slab.h>
13 #include <linux/skbuff.h>
14
15 #include <net/d80211.h>
16 #include "ieee80211_i.h"
17 #include "ieee80211_rate.h"
18
19
20 /* Maximum number of seconds to wait for the traffic load to get below
21  * threshold before forcing a passive scan. */
22 #define MAX_SCAN_WAIT 60
23 /* Threshold (pkts/sec TX or RX) for delaying passive scan */
24 #define SCAN_TXRX_THRESHOLD 75
25
26 static void get_channel_params(struct ieee80211_local *local, int channel,
27                                 struct ieee80211_hw_mode **mode,
28                                 struct ieee80211_channel **chan)
29 {
30         struct ieee80211_hw_mode *m;
31
32         list_for_each_entry(m, &local->modes_list, list) {
33                 *mode = m;
34                 if (m->mode == local->hw.conf.phymode)
35                         break;
36         }
37         local->scan.mode = m;
38         local->scan.chan_idx = 0;
39         do {
40                 *chan = &m->channels[local->scan.chan_idx];
41                 if ((*chan)->chan == channel)
42                         return;
43                 local->scan.chan_idx++;
44         } while (local->scan.chan_idx < m->num_channels);
45         *chan = NULL;
46 }
47
48
49 static void next_chan_same_mode(struct ieee80211_local *local,
50                                 struct ieee80211_hw_mode **mode,
51                                 struct ieee80211_channel **chan)
52 {
53         struct ieee80211_hw_mode *m;
54         int prev;
55
56         list_for_each_entry(m, &local->modes_list, list) {
57                 *mode = m;
58                 if (m->mode == local->hw.conf.phymode)
59                         break;
60         }
61         local->scan.mode = m;
62
63         /* Select next channel - scan only channels marked with W_SCAN flag */
64         prev = local->scan.chan_idx;
65         do {
66                 local->scan.chan_idx++;
67                 if (local->scan.chan_idx >= m->num_channels)
68                         local->scan.chan_idx = 0;
69                 *chan = &m->channels[local->scan.chan_idx];
70                 if ((*chan)->flag & IEEE80211_CHAN_W_SCAN)
71                         break;
72         } while (local->scan.chan_idx != prev);
73 }
74
75
76 static void next_chan_all_modes(struct ieee80211_local *local,
77                                 struct ieee80211_hw_mode **mode,
78                                 struct ieee80211_channel **chan)
79 {
80         struct ieee80211_hw_mode *prev_m;
81         int prev;
82
83         /* Select next channel - scan only channels marked with W_SCAN flag */
84         prev = local->scan.chan_idx;
85         prev_m = local->scan.mode;
86         do {
87                 *mode = local->scan.mode;
88                 local->scan.chan_idx++;
89                 if (local->scan.chan_idx >= (*mode)->num_channels) {
90                         struct list_head *next;
91
92                         local->scan.chan_idx = 0;
93                         next = (*mode)->list.next;
94                         if (next == &local->modes_list)
95                                 next = next->next;
96                         *mode = list_entry(next,
97                                            struct ieee80211_hw_mode,
98                                            list);
99                         local->scan.mode = *mode;
100                 }
101                 *chan = &(*mode)->channels[local->scan.chan_idx];
102                 if ((*chan)->flag & IEEE80211_CHAN_W_SCAN)
103                         break;
104         } while (local->scan.chan_idx != prev ||
105                  local->scan.mode != prev_m);
106 }
107
108
109 static void ieee80211_scan_start(struct ieee80211_local *local,
110                                  struct ieee80211_scan_conf *conf)
111 {
112         struct ieee80211_hw_mode *old_mode = local->scan.mode;
113         int old_chan_idx = local->scan.chan_idx;
114         struct ieee80211_hw_mode *mode = NULL;
115         struct ieee80211_channel *chan = NULL;
116         int ret;
117
118         if (!local->ops->passive_scan) {
119                 printk(KERN_DEBUG "%s: Scan handler called, yet the hardware "
120                        "does not support passive scanning. Disabled.\n",
121                        local->mdev->name);
122                 return;
123         }
124
125         if ((local->scan.tries < MAX_SCAN_WAIT &&
126              local->scan.txrx_count > SCAN_TXRX_THRESHOLD)) {
127                 local->scan.tries++;
128                 /* Count TX/RX packets during one second interval and allow
129                  * scan to start only if the number of packets is below the
130                  * threshold. */
131                 local->scan.txrx_count = 0;
132                 local->scan.timer.expires = jiffies + HZ;
133                 add_timer(&local->scan.timer);
134                 return;
135         }
136
137         if (!local->scan.skb) {
138                 printk(KERN_DEBUG "%s: Scan start called even though scan.skb "
139                        "is not set\n", local->mdev->name);
140         }
141
142         if (local->scan.our_mode_only) {
143                 if (local->scan.channel > 0) {
144                         get_channel_params(local, local->scan.channel, &mode,
145                                            &chan);
146                 } else
147                         next_chan_same_mode(local, &mode, &chan);
148         }
149         else
150                 next_chan_all_modes(local, &mode, &chan);
151
152         conf->scan_channel = chan->chan;
153         conf->scan_freq = chan->freq;
154         conf->scan_channel_val = chan->val;
155         conf->scan_phymode = mode->mode;
156         conf->scan_power_level = chan->power_level;
157         conf->scan_antenna_max = chan->antenna_max;
158         conf->scan_time = 2 * local->hw.channel_change_time +
159                 local->scan.time; /* 10ms scan time+hardware changes */
160         conf->skb = local->scan.skb ?
161                 skb_clone(local->scan.skb, GFP_ATOMIC) : NULL;
162         conf->tx_control = &local->scan.tx_control;
163 #if 0
164         printk(KERN_DEBUG "%s: Doing scan on mode: %d freq: %d chan: %d "
165                "for %d ms\n",
166                local->mdev->name, conf->scan_phymode, conf->scan_freq,
167                conf->scan_channel, conf->scan_time);
168 #endif
169         local->scan.rx_packets = 0;
170         local->scan.rx_beacon = 0;
171         local->scan.freq = chan->freq;
172         local->scan.in_scan = 1;
173
174         ieee80211_netif_oper(local_to_hw(local), NETIF_STOP);
175
176         ret = local->ops->passive_scan(local_to_hw(local),
177                                       IEEE80211_SCAN_START, conf);
178
179         if (ret == 0) {
180                 long usec = local->hw.channel_change_time +
181                         local->scan.time;
182                 usec += 1000000L / HZ - 1;
183                 usec /= 1000000L / HZ;
184                 local->scan.timer.expires = jiffies + usec;
185         } else {
186                 local->scan.in_scan = 0;
187                 if (conf->skb)
188                         dev_kfree_skb(conf->skb);
189                 ieee80211_netif_oper(local_to_hw(local), NETIF_WAKE);
190                 if (ret == -EAGAIN) {
191                         local->scan.timer.expires = jiffies +
192                                 (local->scan.interval * HZ / 100);
193                         local->scan.mode = old_mode;
194                         local->scan.chan_idx = old_chan_idx;
195                 } else {
196                         printk(KERN_DEBUG "%s: Got unknown error from "
197                                "passive_scan %d\n", local->mdev->name, ret);
198                         local->scan.timer.expires = jiffies +
199                                 (local->scan.interval * HZ);
200                 }
201                 local->scan.in_scan = 0;
202         }
203
204         add_timer(&local->scan.timer);
205 }
206
207
208 static void ieee80211_scan_stop(struct ieee80211_local *local,
209                                 struct ieee80211_scan_conf *conf)
210 {
211         struct ieee80211_hw_mode *mode;
212         struct ieee80211_channel *chan;
213         int wait;
214
215         if (!local->ops->passive_scan)
216                 return;
217
218         mode = local->scan.mode;
219
220         if (local->scan.chan_idx >= mode->num_channels)
221                 local->scan.chan_idx = 0;
222
223         chan = &mode->channels[local->scan.chan_idx];
224
225         local->ops->passive_scan(local_to_hw(local), IEEE80211_SCAN_END,
226                                 conf);
227
228 #ifdef CONFIG_D80211_VERBOSE_DEBUG
229         printk(KERN_DEBUG "%s: Did scan on mode: %d freq: %d chan: %d "
230                "GOT: %d Beacon: %d (%d)\n",
231                local->mdev->name,
232                mode->mode, chan->freq, chan->chan,
233                local->scan.rx_packets, local->scan.rx_beacon,
234                local->scan.tries);
235 #endif /* CONFIG_D80211_VERBOSE_DEBUG */
236         local->scan.num_scans++;
237
238         local->scan.in_scan = 0;
239         ieee80211_netif_oper(local_to_hw(local), NETIF_WAKE);
240
241         local->scan.tries = 0;
242         /* Use random interval of scan.interval .. 2 * scan.interval */
243         wait = (local->scan.interval * HZ * ((net_random() & 127) + 128)) /
244                 128;
245         local->scan.timer.expires = jiffies + wait;
246
247         add_timer(&local->scan.timer);
248 }
249
250
251 static void ieee80211_scan_handler(unsigned long ullocal)
252 {
253         struct ieee80211_local *local = (struct ieee80211_local *) ullocal;
254         struct ieee80211_scan_conf conf;
255
256         if (local->scan.interval == 0 && !local->scan.in_scan) {
257                 /* Passive scanning is disabled - keep the timer always
258                  * running to make code cleaner. */
259                 local->scan.timer.expires = jiffies + 10 * HZ;
260                 add_timer(&local->scan.timer);
261                 return;
262         }
263
264         memset(&conf, 0, sizeof(struct ieee80211_scan_conf));
265         conf.running_freq = local->hw.conf.freq;
266         conf.running_channel = local->hw.conf.channel;
267         conf.running_phymode = local->hw.conf.phymode;
268         conf.running_channel_val = local->hw.conf.channel_val;
269         conf.running_power_level = local->hw.conf.power_level;
270         conf.running_antenna_max = local->hw.conf.antenna_max;
271
272         if (local->scan.in_scan == 0)
273                 ieee80211_scan_start(local, &conf);
274         else
275                 ieee80211_scan_stop(local, &conf);
276 }
277
278
279 void ieee80211_init_scan(struct ieee80211_local *local)
280 {
281         struct ieee80211_hdr hdr;
282         u16 fc;
283         int len = 10;
284         struct rate_control_extra extra;
285
286         /* Only initialize passive scanning if the hardware supports it */
287         if (!local->ops->passive_scan) {
288                 local->scan.skb = NULL;
289                 memset(&local->scan.tx_control, 0,
290                        sizeof(local->scan.tx_control));
291                 printk(KERN_DEBUG "%s: Does not support passive scan, "
292                        "disabled\n", local->mdev->name);
293                 return;
294         }
295
296         local->scan.interval = 0;
297         local->scan.our_mode_only = 1;
298         local->scan.time = 10000;
299         local->scan.timer.function = ieee80211_scan_handler;
300         local->scan.timer.data = (unsigned long) local;
301         local->scan.timer.expires = jiffies + local->scan.interval * HZ;
302         add_timer(&local->scan.timer);
303
304         /* Create a CTS from for broadcasting before
305          * the low level changes channels */
306         local->scan.skb = alloc_skb(len, GFP_KERNEL);
307         if (!local->scan.skb) {
308                 printk(KERN_WARNING "%s: Failed to allocate CTS packet for "
309                        "passive scan\n", local->mdev->name);
310                 return;
311         }
312
313         fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS;
314         hdr.frame_control = cpu_to_le16(fc);
315         hdr.duration_id =
316                 cpu_to_le16(2 * local->hw.channel_change_time +
317                             local->scan.time);
318         memcpy(hdr.addr1, local->mdev->dev_addr, ETH_ALEN); /* DA */
319         hdr.seq_ctrl = 0;
320
321         memcpy(skb_put(local->scan.skb, len), &hdr, len);
322
323         memset(&local->scan.tx_control, 0, sizeof(local->scan.tx_control));
324         local->scan.tx_control.key_idx = HW_KEY_IDX_INVALID;
325         local->scan.tx_control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
326         memset(&extra, 0, sizeof(extra));
327         extra.endidx = local->num_curr_rates;
328         local->scan.tx_control.tx_rate =
329                 rate_control_get_rate(local, local->mdev,
330                                       local->scan.skb, &extra)->val;
331         local->scan.tx_control.flags |= IEEE80211_TXCTL_NO_ACK;
332 }
333
334
335 void ieee80211_stop_scan(struct ieee80211_local *local)
336 {
337         if (local->ops->passive_scan) {
338                 del_timer_sync(&local->scan.timer);
339                 dev_kfree_skb(local->scan.skb);
340                 local->scan.skb = NULL;
341         }
342 }