2 * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
30 * IEEE 802.11 ap scanning support.
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
37 #include <sys/socket.h>
40 #include <net/if_media.h>
41 #include <net/ethernet.h>
43 #include <net80211/ieee80211_var.h>
48 int as_maxrssi[IEEE80211_CHAN_MAX];
51 static int ap_flush(struct ieee80211_scan_state *);
53 /* number of references from net80211 layer */
57 * Attach prior to any scanning work.
60 ap_attach(struct ieee80211_scan_state *ss)
64 MALLOC(as, struct ap_state *, sizeof(struct ap_state),
65 M_80211_SCAN, M_NOWAIT);
68 nrefs++; /* NB: we assume caller locking */
73 * Cleanup any private state.
76 ap_detach(struct ieee80211_scan_state *ss)
78 struct ap_state *as = ss->ss_priv;
81 KASSERT(nrefs > 0, ("imbalanced attach/detach"));
82 nrefs--; /* NB: we assume caller locking */
83 FREE(as, M_80211_SCAN);
89 * Flush all per-scan state.
92 ap_flush(struct ieee80211_scan_state *ss)
94 struct ap_state *as = ss->ss_priv;
96 memset(as->as_maxrssi, 0, sizeof(as->as_maxrssi));
97 ss->ss_last = 0; /* insure no channel will be picked */
102 find11gchannel(struct ieee80211com *ic, int i, int freq)
104 const struct ieee80211_channel *c;
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.
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))
117 for (j = 0; j < i; j++) {
118 c = &ic->ic_channels[j];
119 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
126 * Start an ap scan by populating the channel list.
129 ap_start(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
131 struct ieee80211_channel *c;
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)
144 /* dynamic channels are scanned in base mode */
145 if (!IEEE80211_IS_CHAN_ST(c))
147 } else if (IEEE80211_IS_CHAN_HT(c)) {
148 /* HT channels are scanned in legacy */
152 * Use any 11g channel instead of 11b one.
154 if (IEEE80211_IS_CHAN_B(c) &&
155 find11gchannel(ic, i, c->ic_freq))
158 if (ss->ss_last >= IEEE80211_SCAN_MAX)
160 ss->ss_chans[ss->ss_last++] = c;
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 */
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;
183 modeflags = IEEE80211_CHAN_108A;
185 for (i = 0; i < ic->ic_nchans; i++) {
186 c = &ic->ic_channels[i];
187 if ((c->ic_flags & modeflags) != modeflags)
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))
195 if (ss->ss_last >= IEEE80211_SCAN_MAX)
198 * Do not select static turbo channels if
199 * the mode is not static turbo.
201 if (IEEE80211_IS_CHAN_STURBO(c) &&
202 ic->ic_des_mode != IEEE80211_MODE_STURBO_A)
204 ss->ss_chans[ss->ss_last++] = c;
209 ss->ss_mindwell = msecs_to_ticks(200); /* 200ms */
210 ss->ss_maxdwell = msecs_to_ticks(300); /* 300ms */
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);
219 #endif /* IEEE80211_DEBUG */
228 ap_restart(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
234 * Cancel an ongoing scan.
237 ap_cancel(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
243 * Record max rssi on channel.
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)
251 struct ap_state *as = ss->ss_priv;
252 struct ieee80211com *ic = ss->ss_ic;
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 */
265 * Pick a quiet channel to use for ap operation.
268 ap_end(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
270 struct ap_state *as = ss->ss_priv;
271 int i, chan, bestchan, bestchanix;
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 */
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++) {
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.
286 /* XXX channel have interference? */
287 chan = ieee80211_chan2ieee(ic, ss->ss_chans[i]);
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);
294 if (as->as_maxrssi[chan] == 0) {
297 /* XXX use other considerations */
300 if (bestchan == -1 ||
301 as->as_maxrssi[chan] < as->as_maxrssi[bestchan])
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 */
311 struct ieee80211_channel *c;
313 /* XXX notify all vap's? */
315 * If this is a dynamic turbo frequency,
316 * start with normal mode first.
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);
324 /* should never happen ?? */
328 ieee80211_create_ibss(ic,
329 ieee80211_ht_adjust_channel(ic, c, ic->ic_flags_ext));
335 ap_age(struct ieee80211_scan_state *ss)
337 /* XXX is there anything meaningful to do? */
341 ap_iterate(struct ieee80211_scan_state *ss,
342 ieee80211_scan_iter_func *f, void *arg)
344 /* NB: nothing meaningful we can do */
348 ap_assoc_success(struct ieee80211_scan_state *ss,
349 const uint8_t macaddr[IEEE80211_ADDR_LEN])
351 /* should not be called */
355 ap_assoc_fail(struct ieee80211_scan_state *ss,
356 const uint8_t macaddr[IEEE80211_ADDR_LEN], int reason)
358 /* should not be called */
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,
369 .scan_flush = ap_flush,
372 .scan_iterate = ap_iterate,
373 .scan_assoc_success = ap_assoc_success,
374 .scan_assoc_fail = ap_assoc_fail,
381 wlan_modevent(module_t mod, int type, void *unused)
385 ieee80211_scanner_register(IEEE80211_M_HOSTAP, &ap_default);
390 printf("wlan_scan_ap: still in use (%u dynamic refs)\n",
394 if (type == MOD_UNLOAD)
395 ieee80211_scanner_unregister_all(&ap_default);
401 static moduledata_t wlan_mod = {
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);