]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/net80211/ieee80211_scan_ap.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / net80211 / ieee80211_scan_ap.c
1 /*-
2  * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 /*
30  * IEEE 802.11 ap scanning support.
31  */
32 #include <sys/param.h>
33 #include <sys/systm.h> 
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36  
37 #include <sys/socket.h>
38
39 #include <net/if.h>
40 #include <net/if_media.h>
41 #include <net/ethernet.h>
42
43 #include <net80211/ieee80211_var.h>
44
45 #include <net/bpf.h>
46
47 struct ap_state {
48         int     as_maxrssi[IEEE80211_CHAN_MAX];
49 };
50
51 static int ap_flush(struct ieee80211_scan_state *);
52
53 /* number of references from net80211 layer */
54 static  int nrefs = 0;
55
56 /*
57  * Attach prior to any scanning work.
58  */
59 static int
60 ap_attach(struct ieee80211_scan_state *ss)
61 {
62         struct ap_state *as;
63
64         MALLOC(as, struct ap_state *, sizeof(struct ap_state),
65                 M_80211_SCAN, M_NOWAIT);
66         ss->ss_priv = as;
67         ap_flush(ss);
68         nrefs++;                        /* NB: we assume caller locking */
69         return 1;
70 }
71
72 /*
73  * Cleanup any private state.
74  */
75 static int
76 ap_detach(struct ieee80211_scan_state *ss)
77 {
78         struct ap_state *as = ss->ss_priv;
79
80         if (as != NULL) {
81                 KASSERT(nrefs > 0, ("imbalanced attach/detach"));
82                 nrefs--;                /* NB: we assume caller locking */
83                 FREE(as, M_80211_SCAN);
84         }
85         return 1;
86 }
87
88 /*
89  * Flush all per-scan state.
90  */
91 static int
92 ap_flush(struct ieee80211_scan_state *ss)
93 {
94         struct ap_state *as = ss->ss_priv;
95
96         memset(as->as_maxrssi, 0, sizeof(as->as_maxrssi));
97         ss->ss_last = 0;                /* insure no channel will be picked */
98         return 0;
99 }
100
101 static int
102 find11gchannel(struct ieee80211com *ic, int i, int freq)
103 {
104         const struct ieee80211_channel *c;
105         int j;
106
107         /*
108          * The normal ordering in the channel list is b channel
109          * immediately followed by g so optimize the search for
110          * this.  We'll still do a full search just in case.
111          */
112         for (j = i+1; j < ic->ic_nchans; j++) {
113                 c = &ic->ic_channels[j];
114                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
115                         return 1;
116         }
117         for (j = 0; j < i; j++) {
118                 c = &ic->ic_channels[j];
119                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
120                         return 1;
121         }
122         return 0;
123 }
124
125 /*
126  * Start an ap scan by populating the channel list.
127  */
128 static int
129 ap_start(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
130 {
131         struct ieee80211_channel *c;
132         int i;
133
134         ss->ss_last = 0;
135         if (ic->ic_des_mode == IEEE80211_MODE_AUTO) {
136                 for (i = 0; i < ic->ic_nchans; i++) {
137                         c = &ic->ic_channels[i];
138                         if (IEEE80211_IS_CHAN_TURBO(c)) {
139 #ifdef IEEE80211_F_XR
140                                 /* XR is not supported on turbo channels */
141                                 if (ic->ic_flags & IEEE80211_F_XR)
142                                         continue;
143 #endif
144                                 /* dynamic channels are scanned in base mode */
145                                 if (!IEEE80211_IS_CHAN_ST(c))
146                                         continue;
147                         } else if (IEEE80211_IS_CHAN_HT(c)) {
148                                 /* HT channels are scanned in legacy */
149                                 continue;
150                         } else {
151                                 /*
152                                  * Use any 11g channel instead of 11b one.
153                                  */
154                                 if (IEEE80211_IS_CHAN_B(c) &&
155                                     find11gchannel(ic, i, c->ic_freq))
156                                         continue;
157                         }
158                         if (ss->ss_last >= IEEE80211_SCAN_MAX)
159                                 break;
160                         ss->ss_chans[ss->ss_last++] = c;
161                 }
162         } else {
163                 static const u_int chanflags[IEEE80211_MODE_MAX] = {
164                         0,                      /* IEEE80211_MODE_AUTO */
165                         IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
166                         IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
167                         IEEE80211_CHAN_G,       /* IEEE80211_MODE_11G */
168                         IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
169                         IEEE80211_CHAN_108A,    /* IEEE80211_MODE_TURBO_A */
170                         IEEE80211_CHAN_108G,    /* IEEE80211_MODE_TURBO_G */
171                         IEEE80211_CHAN_ST,      /* IEEE80211_MODE_STURBO_A */
172                         IEEE80211_CHAN_A,       /* IEEE80211_MODE_11NA */
173                         IEEE80211_CHAN_G,       /* IEEE80211_MODE_11NG */
174                 };
175                 u_int modeflags;
176
177                 modeflags = chanflags[ic->ic_des_mode];
178                 if ((ic->ic_flags & IEEE80211_F_TURBOP) &&
179                     modeflags != IEEE80211_CHAN_ST) {
180                         if (ic->ic_des_mode == IEEE80211_MODE_11G)
181                                 modeflags = IEEE80211_CHAN_108G;
182                         else
183                                 modeflags = IEEE80211_CHAN_108A;
184                 }
185                 for (i = 0; i < ic->ic_nchans; i++) {
186                         c = &ic->ic_channels[i];
187                         if ((c->ic_flags & modeflags) != modeflags)
188                                 continue;
189 #ifdef IEEE80211_F_XR
190                         /* XR is not supported on turbo channels */
191                         if (IEEE80211_IS_CHAN_TURBO(c) &&
192                             (ic->ic_flags & IEEE80211_F_XR))
193                                 continue;
194 #endif
195                         if (ss->ss_last >= IEEE80211_SCAN_MAX)
196                                 break;
197                         /* 
198                          * Do not select static turbo channels if
199                          * the mode is not static turbo.
200                          */
201                         if (IEEE80211_IS_CHAN_STURBO(c) &&
202                             ic->ic_des_mode != IEEE80211_MODE_STURBO_A)
203                                 continue;
204                         ss->ss_chans[ss->ss_last++] = c;
205                 }
206         }
207         ss->ss_next = 0;
208         /* XXX tunables */
209         ss->ss_mindwell = msecs_to_ticks(200);          /* 200ms */
210         ss->ss_maxdwell = msecs_to_ticks(300);          /* 300ms */
211
212 #ifdef IEEE80211_DEBUG
213         if (ieee80211_msg_scan(ic)) {
214                 if_printf(ic->ic_ifp, "scan set ");
215                 ieee80211_scan_dump_channels(ss);
216                 printf(" dwell min %ld max %ld\n",
217                         ss->ss_mindwell, ss->ss_maxdwell);
218         }
219 #endif /* IEEE80211_DEBUG */
220
221         return 0;
222 }
223
224 /*
225  * Restart a bg scan.
226  */
227 static int
228 ap_restart(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
229 {
230         return 0;
231 }
232
233 /*
234  * Cancel an ongoing scan.
235  */
236 static int
237 ap_cancel(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
238 {
239         return 0;
240 }
241
242 /*
243  * Record max rssi on channel.
244  */
245 static int
246 ap_add(struct ieee80211_scan_state *ss,
247         const struct ieee80211_scanparams *sp,
248         const struct ieee80211_frame *wh,
249         int subtype, int rssi, int noise, int rstamp)
250 {
251         struct ap_state *as = ss->ss_priv;
252         struct ieee80211com *ic = ss->ss_ic;
253         int chan;
254
255         chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
256         /* XXX better quantification of channel use? */
257         /* XXX count bss's? */
258         if (rssi > as->as_maxrssi[chan])
259                 as->as_maxrssi[chan] = rssi;
260         /* XXX interference, turbo requirements */
261         return 1;
262 }
263
264 /*
265  * Pick a quiet channel to use for ap operation.
266  */
267 static int
268 ap_end(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
269 {
270         struct ap_state *as = ss->ss_priv;
271         int i, chan, bestchan, bestchanix;
272
273         KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP,
274                 ("wrong opmode %u", ic->ic_opmode));
275         /* XXX select channel more intelligently, e.g. channel spread, power */
276         bestchan = -1;
277         bestchanix = 0;         /* NB: silence compiler */
278         /* NB: use scan list order to preserve channel preference */
279         for (i = 0; i < ss->ss_last; i++) {
280                 /*
281                  * If the channel is unoccupied the max rssi
282                  * should be zero; just take it.  Otherwise
283                  * track the channel with the lowest rssi and
284                  * use that when all channels appear occupied.
285                  */
286                 /* XXX channel have interference? */
287                 chan = ieee80211_chan2ieee(ic, ss->ss_chans[i]);
288
289                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
290                     "%s: channel %u rssi %d bestchan %d bestchan rssi %d\n",
291                     __func__, chan, as->as_maxrssi[chan],
292                     bestchan, bestchan != -1 ? as->as_maxrssi[bestchan] : 0);
293
294                 if (as->as_maxrssi[chan] == 0) {
295                         bestchan = chan;
296                         bestchanix = i;
297                         /* XXX use other considerations */
298                         break;
299                 }
300                 if (bestchan == -1 ||
301                     as->as_maxrssi[chan] < as->as_maxrssi[bestchan])
302                         bestchan = chan;
303         }
304         if (bestchan == -1) {
305                 /* no suitable channel, should not happen */
306                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
307                     "%s: no suitable channel! (should not happen)\n", __func__);
308                 /* XXX print something? */
309                 return 0;                       /* restart scan */
310         } else {
311                 struct ieee80211_channel *c;
312
313                 /* XXX notify all vap's? */
314                 /*
315                  * If this is a dynamic turbo frequency,
316                  * start with normal mode first.
317                  */
318                 c = ss->ss_chans[bestchanix];
319                 if (IEEE80211_IS_CHAN_TURBO(c) &&
320                     !IEEE80211_IS_CHAN_STURBO(c)) { 
321                         c = ieee80211_find_channel(ic, c->ic_freq,
322                                 c->ic_flags & ~IEEE80211_CHAN_TURBO);
323                         if (c == NULL) {
324                                 /* should never happen ?? */
325                                 return 0;
326                         }
327                 }
328                 ieee80211_create_ibss(ic,
329                     ieee80211_ht_adjust_channel(ic, c, ic->ic_flags_ext));
330                 return 1;
331         }
332 }
333
334 static void
335 ap_age(struct ieee80211_scan_state *ss)
336 {
337         /* XXX is there anything meaningful to do? */
338 }
339
340 static void
341 ap_iterate(struct ieee80211_scan_state *ss,
342         ieee80211_scan_iter_func *f, void *arg)
343 {
344         /* NB: nothing meaningful we can do */
345 }
346
347 static void
348 ap_assoc_success(struct ieee80211_scan_state *ss,
349         const uint8_t macaddr[IEEE80211_ADDR_LEN])
350 {
351         /* should not be called */
352 }
353
354 static void
355 ap_assoc_fail(struct ieee80211_scan_state *ss,
356         const uint8_t macaddr[IEEE80211_ADDR_LEN], int reason)
357 {
358         /* should not be called */
359 }
360
361 static const struct ieee80211_scanner ap_default = {
362         .scan_name              = "default",
363         .scan_attach            = ap_attach,
364         .scan_detach            = ap_detach,
365         .scan_start             = ap_start,
366         .scan_restart           = ap_restart,
367         .scan_cancel            = ap_cancel,
368         .scan_end               = ap_end,
369         .scan_flush             = ap_flush,
370         .scan_add               = ap_add,
371         .scan_age               = ap_age,
372         .scan_iterate           = ap_iterate,
373         .scan_assoc_success     = ap_assoc_success,
374         .scan_assoc_fail        = ap_assoc_fail,
375 };
376
377 /*
378  * Module glue.
379  */
380 static int
381 wlan_modevent(module_t mod, int type, void *unused)
382 {
383         switch (type) {
384         case MOD_LOAD:
385                 ieee80211_scanner_register(IEEE80211_M_HOSTAP, &ap_default);
386                 return 0;
387         case MOD_UNLOAD:
388         case MOD_QUIESCE:
389                 if (nrefs) {
390                         printf("wlan_scan_ap: still in use (%u dynamic refs)\n",
391                                 nrefs);
392                         return EBUSY;
393                 }
394                 if (type == MOD_UNLOAD)
395                         ieee80211_scanner_unregister_all(&ap_default);
396                 return 0;
397         }
398         return EINVAL;
399 }
400
401 static moduledata_t wlan_mod = {
402         "wlan_scan_ap",
403         wlan_modevent,
404         0
405 };
406 DECLARE_MODULE(wlan_scan_ap, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
407 MODULE_VERSION(wlan_scan_ap, 1);
408 MODULE_DEPEND(wlan_scan_ap, wlan, 1, 1, 1);