2 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
3 * Copyright (c) 2005 Matt Mackall <mpm@selenic.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * $Id: ieee80211_scan_ap.c 3627 2008-05-14 19:11:57Z mentor $
39 * IEEE 802.11 ap scanning support.
41 #ifndef AUTOCONF_INCLUDED
42 #include <linux/config.h>
44 #include <linux/version.h>
45 #include <linux/module.h>
46 #include <linux/skbuff.h>
47 #include <linux/netdevice.h>
48 #include <linux/init.h>
49 #include <linux/delay.h>
51 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
52 /* Copied from Linux lib/sort.c */
53 static void u32_swap(void *a
, void *b
, int size
)
56 *(u32
*)a
= *(u32
*)b
;
60 static void generic_swap(void *a
, void *b
, int size
)
66 *(char *)a
++ = *(char *)b
;
72 * sort - sort an array of elements
73 * @base: pointer to data to sort
74 * @num: number of elements
75 * @size: size of each element
76 * @cmp: pointer to comparison function
77 * @swap: pointer to swap function or NULL
79 * This function does a heapsort on the given array. You may provide a
80 * swap function optimized to your element type.
82 * Sorting time is O(n log n) both on average and worst-case. While
83 * qsort is about 20% faster on average, it suffers from exploitable
84 * O(n*n) worst-case behavior and extra memory requirements that make
85 * it less suitable for kernel use.
88 void sort(void *base
, size_t num
, size_t size
,
89 int (*cmp
)(const void *, const void *),
90 void (*swap
)(void *, void *, int size
))
92 /* pre-scale counters for performance */
93 int i
= (num
/2 - 1) * size
, n
= num
* size
, c
, r
;
96 swap
= (size
== 4 ? u32_swap
: generic_swap
);
99 for ( ; i
>= 0; i
-= size
) {
100 for (r
= i
; r
* 2 + size
< n
; r
= c
) {
102 if (c
< n
- size
&& cmp(base
+ c
, base
+ c
+ size
) < 0)
104 if (cmp(base
+ r
, base
+ c
) >= 0)
106 swap(base
+ r
, base
+ c
, size
);
111 for (i
= n
- size
; i
> 0; i
-= size
) {
112 swap(base
, base
+ i
, size
);
113 for (r
= 0; r
* 2 + size
< i
; r
= c
) {
115 if (c
< i
- size
&& cmp(base
+ c
, base
+ c
+ size
) < 0)
117 if (cmp(base
+ r
, base
+ c
) >= 0)
119 swap(base
+ r
, base
+ c
, size
);
124 #include <linux/sort.h>
127 #include "if_media.h"
129 #include <net80211/ieee80211_var.h>
131 #define AP_PURGE_SCANS 2 /* age for purging entries (scans) */
132 #define RSSI_LPF_LEN 10
133 #define RSSI_EP_MULTIPLIER (1 << 7) /* pow2 to optimize out * and / */
134 #define RSSI_IN(x) ((x) * RSSI_EP_MULTIPLIER)
135 #define LPF_RSSI(x, y, len) (((x) * ((len) - 1) + (y)) / (len))
136 #define RSSI_LPF(x, y) do { \
138 x = LPF_RSSI((x), RSSI_IN((y)), RSSI_LPF_LEN); \
140 #define EP_RND(x, mul) \
141 ((((x)%(mul)) >= ((mul)/2)) ? howmany(x, mul) : (x)/(mul))
142 #define RSSI_GET(x) EP_RND(x, RSSI_EP_MULTIPLIER)
143 #define AP_HASHSIZE 32
144 /* simple hash is enough for variation of macaddr */
145 #define AP_HASH(addr) \
146 (((const u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % AP_HASHSIZE)
147 #define SCAN_AP_LOCK_INIT(_st, _name) \
148 spin_lock_init(&(_st)->as_lock)
149 #define SCAN_AP_LOCK_DESTROY(_st)
150 #define SCAN_AP_LOCK_IRQ(_st) do { \
151 unsigned long __stlockflags; \
152 spin_lock_irqsave(&(_st)->as_lock, __stlockflags);
153 #define SCAN_AP_UNLOCK_IRQ(_st) \
154 spin_unlock_irqrestore(&(_st)->as_lock, __stlockflags); \
156 #define SCAN_AP_UNLOCK_IRQ_EARLY(_st) \
157 spin_unlock_irqrestore(&(_st)->as_lock, __stlockflags);
159 #define SCAN_AP_GEN_LOCK_INIT(_st, _name) \
160 spin_lock_init(&(_st)->as_scanlock)
161 #define SCAN_AP_GEN_LOCK_DESTROY(_st)
162 #define SCAN_AP_GEN_LOCK(_st) spin_lock(&(_st)->as_scanlock);
163 #define SCAN_AP_GEN_UNLOCK(_st) spin_unlock(&(_st)->as_scanlock);
166 struct ieee80211_scan_entry base
;
167 TAILQ_ENTRY(scan_entry
) se_list
;
168 LIST_ENTRY(scan_entry
) se_hash
;
169 u_int8_t se_seen
; /* seen during current scan */
170 u_int8_t se_notseen
; /* not seen in previous scans */
171 u_int32_t se_avgrssi
; /* LPF rssi state */
172 unsigned long se_lastupdate
; /* time of last update */
173 unsigned long se_lastfail
; /* time of last failure */
174 unsigned long se_lastassoc
; /* time of last association */
175 u_int se_scangen
; /* iterator scan gen# */
179 unsigned int as_vap_desired_mode
; /* Used for channel selection,
180 * vap->iv_des_mode */
181 unsigned int as_required_mode
; /* Used for channel selection,
182 * filtered version of
183 * as_vap_desired_mode */
184 int as_maxrssi
[IEEE80211_CHAN_MAX
]; /* Used for channel selection */
186 /* These fields are just for scan caching for returning responses to
187 * wireless extensions. i.e. show peers, APs, etc. */
188 spinlock_t as_lock
; /* on scan table */
189 int as_newscan
; /* trigger for updating
190 * seen/not-seen for aging */
191 TAILQ_HEAD(, scan_entry
) as_entry
; /* all entries */
192 ATH_LIST_HEAD(, scan_entry
) as_hash
[AP_HASHSIZE
];
193 spinlock_t as_scanlock
; /* on as_scangen */
194 u_int as_scangen
; /* gen# for iterator */
196 struct IEEE80211_TQ_STRUCT as_actiontq
; /* tasklet for "action" */
197 struct ieee80211_scan_entry as_selbss
; /* selected bss for action tasklet */
198 int (*as_action
)(struct ieee80211vap
*, const struct ieee80211_scan_entry
*);
201 static int ap_flush(struct ieee80211_scan_state
*);
202 static void action_tasklet(IEEE80211_TQUEUE_ARG
);
203 static struct ieee80211_channel
*find11gchannel(struct ieee80211com
*ic
,
206 static const u_int chanflags
[] = {
207 IEEE80211_CHAN_B
, /* IEEE80211_MODE_AUTO */
208 IEEE80211_CHAN_A
, /* IEEE80211_MODE_11A */
209 IEEE80211_CHAN_B
, /* IEEE80211_MODE_11B */
210 IEEE80211_CHAN_PUREG
, /* IEEE80211_MODE_11G */
211 IEEE80211_CHAN_FHSS
, /* IEEE80211_MODE_FH */
212 IEEE80211_CHAN_A
, /* IEEE80211_MODE_TURBO_A */ /* for turbo mode
216 IEEE80211_CHAN_PUREG
, /* IEEE80211_MODE_TURBO_G */
217 IEEE80211_CHAN_ST
, /* IEEE80211_MODE_TURBO_STATIC_A */
220 static const u_int16_t rcl1
[] = /* 8 FCC channel: 52, 56, 60, 64,
222 { 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 };
223 static const u_int16_t rcl2
[] = /* 4 MKK channels: 34, 38, 42, 46 */
224 { 5170, 5190, 5210, 5230 };
225 static const u_int16_t rcl3
[] = /* 2.4Ghz ch: 1,6,11,7,13 */
226 { 2412, 2437, 2462, 2442, 2472 };
227 static const u_int16_t rcl4
[] = /* 5 FCC channel: 149, 153, 161, 165 */
228 { 5745, 5765, 5785, 5805, 5825 };
229 static const u_int16_t rcl7
[] = /* 11 ETSI channel: 100, 104, 108, 112,
230 * 116, 120, 124, 128,
232 { 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 };
233 static const u_int16_t rcl8
[] = /* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */
234 { 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 };
235 static const u_int16_t rcl9
[] = /* 2.4Ghz ch: 14 */
237 static const u_int16_t rcl10
[] = /* Added Korean channels 2312-2372 */
238 { 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 };
239 static const u_int16_t rcl11
[] = /* Added Japan channels in 4.9/5.0 spectrum */
240 { 5040, 5060, 5080, 4920, 4940, 4960, 4980 };
241 #ifdef ATH_TURBO_SCAN
242 static const u_int16_t rcl5
[] = /* 3 static turbo channels */
243 { 5210, 5250, 5290 };
244 static const u_int16_t rcl6
[] = /* 2 static turbo channels */
246 static const u_int16_t rcl6x
[] = /* 4 FCC3 turbo channels */
247 { 5540, 5580, 5620, 5660 };
248 static const u_int16_t rcl12
[] = /* 2.4Ghz Turbo channel 6 */
250 static const u_int16_t rcl13
[] = /* dynamic Turbo channels */
251 { 5200, 5240, 5280, 5765, 5805 };
252 #endif /* ATH_TURBO_SCAN */
257 const u_int16_t
*list
;
260 #define IEEE80211_MODE_TURBO_STATIC_A IEEE80211_MODE_MAX
261 #define X(a) .count = ARRAY_SIZE(a), .list = a
263 static const struct scanlist staScanTable
[] = {
264 { IEEE80211_MODE_11B
, X(rcl3
) },
265 { IEEE80211_MODE_11A
, X(rcl1
) },
266 { IEEE80211_MODE_11A
, X(rcl2
) },
267 { IEEE80211_MODE_11B
, X(rcl8
) },
268 { IEEE80211_MODE_11B
, X(rcl9
) },
269 { IEEE80211_MODE_11A
, X(rcl4
) },
270 #ifdef ATH_TURBO_SCAN
271 { IEEE80211_MODE_TURBO_STATIC_A
, X(rcl5
) },
272 { IEEE80211_MODE_TURBO_STATIC_A
, X(rcl6
) },
273 { IEEE80211_MODE_TURBO_A
, X(rcl6x
) },
274 { IEEE80211_MODE_TURBO_A
, X(rcl13
) },
275 #endif /* ATH_TURBO_SCAN */
276 { IEEE80211_MODE_11A
, X(rcl7
) },
277 { IEEE80211_MODE_11B
, X(rcl10
) },
278 { IEEE80211_MODE_11A
, X(rcl11
) },
279 #ifdef ATH_TURBO_SCAN
280 { IEEE80211_MODE_TURBO_G
, X(rcl12
) },
281 #endif /* ATH_TURBO_SCAN */
286 /* This function must be invoked with locks acquired */
288 add_channels(struct ieee80211com
*ic
,
289 struct ieee80211_scan_state
*ss
,
290 enum ieee80211_phymode mode
, const u_int16_t freq
[], int nfreq
)
292 struct ieee80211_channel
*c
, *cg
;
296 KASSERT(mode
< ARRAY_SIZE(chanflags
), ("Unexpected mode %u", mode
));
297 modeflags
= chanflags
[mode
];
298 for (i
= 0; i
< nfreq
; i
++) {
299 c
= ieee80211_find_channel(ic
, freq
[i
], modeflags
);
300 if ((c
== NULL
) || isclr(ic
->ic_chan_active
, c
->ic_ieee
))
302 if (mode
== IEEE80211_MODE_AUTO
) {
303 /* XXX special-case 11b/g channels so we select
304 * the g channel if both are present. */
305 if (IEEE80211_IS_CHAN_B(c
) &&
306 (cg
= find11gchannel(ic
, i
, c
->ic_freq
)) != NULL
)
309 if (ss
->ss_last
>= IEEE80211_SCAN_MAX
)
311 ss
->ss_chans
[ss
->ss_last
++] = c
;
315 /* This function must be invoked with locks acquired */
317 checktable(const struct scanlist
*scan
, const struct ieee80211_channel
*c
)
321 for (; scan
->list
!= NULL
; scan
++) {
322 for (i
= 0; i
< scan
->count
; i
++)
323 if (scan
->list
[i
] == c
->ic_freq
)
330 * Attach prior to any scanning work.
333 ap_attach(struct ieee80211_scan_state
*ss
)
337 _MOD_INC_USE(THIS_MODULE
, return 0);
339 MALLOC(as
, struct ap_state
*, sizeof(struct ap_state
),
340 M_80211_SCAN
, M_NOWAIT
| M_ZERO
);
343 SCAN_AP_LOCK_INIT(as
, "scan_ap");
344 SCAN_AP_GEN_LOCK_INIT(as
, "scan_ap_gen");
345 TAILQ_INIT(&as
->as_entry
);
346 IEEE80211_INIT_TQUEUE(&as
->as_actiontq
, action_tasklet
, ss
);
353 * Cleanup any private state.
356 ap_detach(struct ieee80211_scan_state
*ss
)
358 struct ap_state
*as
= ss
->ss_priv
;
362 IEEE80211_CANCEL_TQUEUE(&as
->as_actiontq
);
363 FREE(as
, M_80211_SCAN
);
366 _MOD_DEC_USE(THIS_MODULE
);
371 * Flush all per-scan state.
374 ap_flush(struct ieee80211_scan_state
*ss
)
376 struct ap_state
*as
= ss
->ss_priv
;
377 struct scan_entry
*se
, *next
;
379 SCAN_AP_LOCK_IRQ(as
);
380 memset(as
->as_maxrssi
, 0, sizeof(as
->as_maxrssi
));
381 TAILQ_FOREACH_SAFE(se
, &as
->as_entry
, se_list
, next
) {
382 TAILQ_REMOVE(&as
->as_entry
, se
, se_list
);
383 LIST_REMOVE(se
, se_hash
);
384 FREE(se
, M_80211_SCAN
);
386 ss
->ss_last
= 0; /* ensure no channel will be picked */
387 SCAN_AP_UNLOCK_IRQ(as
);
391 /* This function must be invoked with locks acquired */
393 saveie(u_int8_t
**iep
, const u_int8_t
*ie
)
398 ieee80211_saveie(iep
, ie
);
401 /* This function must be invoked with locks acquired */
402 static struct ieee80211_channel
*
403 find11gchannel(struct ieee80211com
*ic
, int i
, int freq
)
405 struct ieee80211_channel
*c
;
408 /* The normal ordering in the channel list is b channel
409 * immediately followed by g so optimize the search for
410 * this. We'll still do a full search just in case. */
411 for (j
= i
+ 1; j
< ic
->ic_nchans
; j
++) {
412 c
= &ic
->ic_channels
[j
];
413 if ((c
->ic_freq
== freq
) && IEEE80211_IS_CHAN_ANYG(c
))
416 for (j
= 0; j
< i
; j
++) {
417 c
= &ic
->ic_channels
[j
];
418 if ((c
->ic_freq
== freq
) && IEEE80211_IS_CHAN_ANYG(c
))
425 * Start an ap scan by populating the channel list.
428 ap_start(struct ieee80211_scan_state
*ss
, struct ieee80211vap
*vap
)
430 struct ap_state
*as
= ss
->ss_priv
;
431 struct ieee80211com
*ic
= NULL
;
432 const struct scanlist
*sl
= NULL
;
433 struct ieee80211_channel
*c
= NULL
;
435 unsigned int mode
= 0;
437 SCAN_AP_LOCK_IRQ(as
);
439 /* Determine mode flags to match, or leave zero for auto mode */
440 as
->as_vap_desired_mode
= vap
->iv_des_mode
;
441 as
->as_required_mode
= 0;
442 if (as
->as_vap_desired_mode
!= IEEE80211_MODE_AUTO
) {
443 as
->as_required_mode
= chanflags
[as
->as_vap_desired_mode
];
444 if ((vap
->iv_ath_cap
& IEEE80211_ATHC_TURBOP
) &&
445 (as
->as_required_mode
!= IEEE80211_CHAN_ST
)) {
446 /* Fixup for dynamic turbo flags */
447 if (as
->as_vap_desired_mode
== IEEE80211_MODE_11G
)
448 as
->as_required_mode
= IEEE80211_CHAN_108G
;
450 as
->as_required_mode
= IEEE80211_CHAN_108A
;
455 /* Use the table of ordered channels to construct the list
456 * of channels for scanning. Any channels in the ordered
457 * list not in the master list will be discarded. */
458 for (sl
= staScanTable
; sl
->list
!= NULL
; sl
++) {
461 /* The scan table marks 2.4Ghz channels as b
462 * so if the desired mode is 11g, then use
463 * the 11b channel list but upgrade the mode. */
464 if (as
->as_vap_desired_mode
&&
465 (as
->as_vap_desired_mode
!= mode
) &&
466 (as
->as_vap_desired_mode
== IEEE80211_MODE_11G
) &&
467 (mode
== IEEE80211_MODE_11B
))
468 mode
= IEEE80211_MODE_11G
;
470 /* If we are in "AUTO" mode, upgrade the mode to auto.
471 * This lets add_channels upgrade an 11b channel to
472 * 11g if available. */
473 if (!as
->as_vap_desired_mode
&& (mode
== IEEE80211_MODE_11B
))
474 mode
= IEEE80211_MODE_AUTO
;
476 /* Add the list of the channels; any that are not
477 * in the master channel list will be discarded. */
478 add_channels(ic
, ss
, mode
, sl
->list
, sl
->count
);
481 /* Add the channels from the ic (from HAL) that are not present
482 * in the staScanTable, assuming they pass the sanity checks... */
483 for (i
= 0; i
< ic
->ic_nchans
; i
++) {
484 c
= &ic
->ic_channels
[i
];
486 /* XR is not supported on turbo channels */
487 if (IEEE80211_IS_CHAN_TURBO(c
) && vap
->iv_flags
& IEEE80211_F_XR
)
490 /* Dynamic channels are scanned in base mode */
491 if (!as
->as_required_mode
&& !IEEE80211_IS_CHAN_ST(c
))
494 /* Use any 11g channel instead of 11b one. */
495 if (vap
->iv_des_mode
== IEEE80211_MODE_AUTO
&&
496 IEEE80211_IS_CHAN_B(c
) &&
497 find11gchannel(ic
, i
, c
->ic_freq
))
500 /* Do not add channels already put into the scan list by the
501 * scan table - these have already been filtered by mode
502 * and for whether they are in the active channel list. */
503 if (checktable(staScanTable
, c
))
506 /* Make sure the channel is active */
507 if ((c
== NULL
) || isclr(ic
->ic_chan_active
, c
->ic_ieee
))
511 if (ss
->ss_last
>= IEEE80211_SCAN_MAX
)
514 ss
->ss_chans
[ss
->ss_last
++] = c
;
518 ss
->ss_mindwell
= msecs_to_jiffies(200); /* 200ms */
519 ss
->ss_maxdwell
= msecs_to_jiffies(300); /* 300ms */
521 #ifdef IEEE80211_DEBUG
522 if (ieee80211_msg_scan(vap
)) {
523 printk("%s: scan set ", vap
->iv_dev
->name
);
524 ieee80211_scan_dump_channels(ss
);
525 printk(" dwell min %ld max %ld\n",
526 ss
->ss_mindwell
, ss
->ss_maxdwell
);
528 #endif /* IEEE80211_DEBUG */
531 SCAN_AP_UNLOCK_IRQ(as
);
539 ap_restart(struct ieee80211_scan_state
*ss
, struct ieee80211vap
*vap
)
541 struct ap_state
*as
= ss
->ss_priv
;
547 * Cancel an ongoing scan.
550 ap_cancel(struct ieee80211_scan_state
*ss
, struct ieee80211vap
*vap
)
552 struct ap_state
*as
= ss
->ss_priv
;
553 IEEE80211_CANCEL_TQUEUE(&as
->as_actiontq
);
558 * Record max rssi on channel.
561 ap_add(struct ieee80211_scan_state
*ss
, const struct ieee80211_scanparams
*sp
,
562 const struct ieee80211_frame
*wh
, int subtype
, int rssi
, u_int64_t rtsf
)
564 struct ap_state
*as
= ss
->ss_priv
;
565 const u_int8_t
*macaddr
= wh
->i_addr2
;
566 struct ieee80211vap
*vap
= ss
->ss_vap
;
567 struct ieee80211com
*ic
= vap
->iv_ic
;
568 struct scan_entry
*se
= NULL
;
569 struct ieee80211_scan_entry
*ise
= NULL
;
570 int hash
= AP_HASH(macaddr
);
573 /* This section provides scan results to wireless extensions */
574 SCAN_AP_LOCK_IRQ(as
);
576 chan
= ieee80211_chan2ieee(ic
, ic
->ic_curchan
);
577 /* This is the only information used for channel selection by AP */
578 if (rssi
> as
->as_maxrssi
[chan
])
579 as
->as_maxrssi
[chan
] = rssi
;
580 LIST_FOREACH(se
, &as
->as_hash
[hash
], se_hash
)
581 if (IEEE80211_ADDR_EQ(se
->base
.se_macaddr
, macaddr
) &&
582 (sp
->ssid
[1] == se
->base
.se_ssid
[1]) &&
583 !memcmp(se
->base
.se_ssid
+ 2, sp
->ssid
+ 2,
584 se
->base
.se_ssid
[1]))
587 MALLOC(se
, struct scan_entry
*, sizeof(struct scan_entry
),
588 M_80211_SCAN
, M_NOWAIT
| M_ZERO
);
591 SCAN_AP_UNLOCK_IRQ_EARLY(as
);
595 se
->se_scangen
= as
->as_scangen
-1;
596 IEEE80211_ADDR_COPY(se
->base
.se_macaddr
, macaddr
);
597 TAILQ_INSERT_TAIL(&as
->as_entry
, se
, se_list
);
598 LIST_INSERT_HEAD(&as
->as_hash
[hash
], se
, se_hash
);
603 /* XXX: AP beaconing multiple SSID w/ same BSSID */
604 if ((sp
->ssid
[1] != 0) &&
605 ((subtype
== IEEE80211_FC0_SUBTYPE_PROBE_RESP
) ||
606 (ise
->se_ssid
[1] == 0)))
607 memcpy(ise
->se_ssid
, sp
->ssid
, 2 + sp
->ssid
[1]);
609 memcpy(ise
->se_rates
, sp
->rates
,
610 IEEE80211_SANITISE_RATESIZE(2 + sp
->rates
[1]));
611 if (sp
->xrates
!= NULL
) {
612 memcpy(ise
->se_xrates
, sp
->xrates
,
613 IEEE80211_SANITISE_RATESIZE(2 + sp
->xrates
[1]));
615 ise
->se_xrates
[1] = 0;
617 IEEE80211_ADDR_COPY(ise
->se_bssid
, wh
->i_addr3
);
619 /* Record RSSI data using extended precision LPF filter.*/
620 if (se
->se_lastupdate
== 0) /* First sample */
621 se
->se_avgrssi
= RSSI_IN(rssi
);
622 else /* Avg. w/ previous samples */
623 RSSI_LPF(se
->se_avgrssi
, rssi
);
624 se
->base
.se_rssi
= RSSI_GET(se
->se_avgrssi
);
627 memcpy(ise
->se_tstamp
.data
, sp
->tstamp
, sizeof(ise
->se_tstamp
));
628 ise
->se_intval
= sp
->bintval
;
629 ise
->se_capinfo
= sp
->capinfo
;
630 ise
->se_chan
= ic
->ic_curchan
;
631 ise
->se_fhdwell
= sp
->fhdwell
;
632 ise
->se_fhindex
= sp
->fhindex
;
633 ise
->se_erp
= sp
->erp
;
634 ise
->se_timoff
= sp
->timoff
;
636 if (sp
->tim
!= NULL
) {
637 const struct ieee80211_tim_ie
*tim
=
638 (const struct ieee80211_tim_ie
*)sp
->tim
;
639 ise
->se_dtimperiod
= tim
->tim_period
;
642 saveie(&ise
->se_wme_ie
, sp
->wme
);
643 saveie(&ise
->se_wpa_ie
, sp
->wpa
);
644 saveie(&ise
->se_rsn_ie
, sp
->rsn
);
645 saveie(&ise
->se_ath_ie
, sp
->ath
);
647 se
->se_lastupdate
= jiffies
; /* update time */
651 SCAN_AP_UNLOCK_IRQ(as
);
657 struct ieee80211vap
*vap
;
658 struct ieee80211_scan_state
*ss
;
663 struct ieee80211_channel
*chan
;
665 struct pc_params
*params
;
668 /* This function must be invoked with locks acquired */
670 pc_cmp_radar(struct ieee80211_channel
*a
, struct ieee80211_channel
*b
)
672 /* a is better than b (return < 0) when b is marked while a is not */
673 return !!IEEE80211_IS_CHAN_RADAR(a
) - !!IEEE80211_IS_CHAN_RADAR(b
);
676 /* This function must be invoked with locks acquired */
678 pc_cmp_keepmode(struct pc_params
*params
, struct ieee80211_channel
*a
,
679 struct ieee80211_channel
*b
)
681 struct ieee80211com
*ic
= params
->vap
->iv_ic
;
682 struct ieee80211_channel
*cur
= ic
->ic_bsschan
;
684 if (!(params
->flags
& IEEE80211_SCAN_KEEPMODE
))
687 /* a is better than b (return < 0) when (a, cur) have the same mode
688 * and (b, cur) do not. */
690 !!IEEE80211_ARE_CHANS_SAME_MODE(b
, cur
) -
691 !!IEEE80211_ARE_CHANS_SAME_MODE(a
, cur
);
694 /* This function must be invoked with locks acquired */
696 pc_cmp_sc(struct ieee80211com
*ic
, struct ieee80211_channel
*a
,
697 struct ieee80211_channel
*b
)
699 /* a is better than b (return < 0) when a has more chan nodes than b */
701 ic
->ic_chan_nodes
[b
->ic_ieee
] -
702 ic
->ic_chan_nodes
[a
->ic_ieee
];
705 /* This function must be invoked with locks acquired */
707 pc_cmp_rssi(struct ap_state
*as
, struct ieee80211_channel
*a
,
708 struct ieee80211_channel
*b
)
710 /* a is better than b (return < 0) when a has rssi less than b */
712 as
->as_maxrssi
[a
->ic_ieee
] -
713 as
->as_maxrssi
[b
->ic_ieee
];
716 /* This function must be invoked with locks acquired */
718 pc_cmp_samechan(struct ieee80211com
*ic
, struct ieee80211_channel
*a
,
719 struct ieee80211_channel
*b
)
721 struct ieee80211_channel
*ic_bsschan
= ic
->ic_bsschan
;
722 if (ic_bsschan
== IEEE80211_CHAN_ANYC
)
724 /* a is better than b (return < 0) when a is current (and b is not) */
725 return (b
== ic_bsschan
) - (a
== ic_bsschan
);
728 /* This function must be invoked with locks acquired */
730 pc_cmp_orig(struct channel
*a
, struct channel
*b
)
732 return a
->orig
- b
->orig
;
735 /* This function must be invoked with locks acquired */
737 pc_cmp(const void *_a
, const void *_b
)
739 struct ieee80211_channel
*a
= ((struct channel
*)_a
)->chan
;
740 struct ieee80211_channel
*b
= ((struct channel
*)_b
)->chan
;
741 struct pc_params
*params
= ((struct channel
*)_a
)->params
;
742 struct ieee80211com
*ic
= params
->vap
->iv_ic
;
745 #define EVALUATE_CRITERION(name, ...) do { \
746 if ((res = pc_cmp_##name(__VA_ARGS__)) != 0) \
750 EVALUATE_CRITERION(radar
, a
, b
);
751 EVALUATE_CRITERION(keepmode
, params
, a
, b
);
752 EVALUATE_CRITERION(sc
, ic
, a
, b
);
753 /* XXX: rssi useless? pick_channel evaluates it anyway */
754 EVALUATE_CRITERION(rssi
, params
->ss
->ss_priv
, a
, b
);
755 EVALUATE_CRITERION(samechan
, ic
, a
, b
);
756 EVALUATE_CRITERION(orig
, (struct channel
*)_a
, (struct channel
*)_b
);
758 #undef EVALUATE_CRITERION
762 /* This function must be invoked with locks acquired */
764 pc_swap(void *a
, void *b
, int n
)
766 struct ieee80211_channel
*t
= ((struct channel
*)a
)->chan
;
769 ((struct channel
*)a
)->chan
= ((struct channel
*)b
)->chan
;
770 ((struct channel
*)b
)->chan
= t
;
772 i
= ((struct channel
*)a
)->orig
;
773 ((struct channel
*)a
)->orig
= ((struct channel
*)b
)->orig
;
774 ((struct channel
*)b
)->orig
= i
;
776 /* (struct channel *)x->params doesn't have to be swapped, because it
777 * is the same across all channels */
780 /* Pick a quiet channel to use for ap operation.
781 * Must be invoked while we hold the locks. */
782 static struct ieee80211_channel
*
783 pick_channel(struct ieee80211_scan_state
*ss
, struct ieee80211vap
*vap
,
786 struct ieee80211com
*ic
= vap
->iv_ic
;
787 unsigned int i
, best_rssi
;
788 int ss_last
= ss
->ss_last
;
789 struct ieee80211_channel
*best
;
790 struct ap_state
*as
= ss
->ss_priv
;
791 struct channel chans
[ss_last
]; /* actually ss_last-1 is required */
792 struct channel
*c
= NULL
;
793 struct pc_params params
= { vap
, ss
, flags
};
797 for (i
= 0; i
< ss_last
; i
++) {
798 chans
[i
].chan
= ss
->ss_chans
[i
];
800 chans
[i
].params
= ¶ms
;
803 sort(chans
, ss_last
, sizeof(*chans
), pc_cmp
, pc_swap
);
805 #ifdef IEEE80211_DEBUG
806 for (i
= 0; i
< ss_last
; i
++) {
807 int chan
= ieee80211_chan2ieee(ic
, chans
[i
].chan
);
808 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_SCAN
, "%s: channel %u, "
809 "rssi %d, radar %d, cn %d, km %d\n",
810 __func__
, chan
, as
->as_maxrssi
[chan
],
811 IEEE80211_IS_CHAN_RADAR(chans
[i
].chan
),
812 ic
->ic_chan_nodes
[chans
[i
].chan
->ic_ieee
],
813 !!IEEE80211_ARE_CHANS_SAME_MODE(chans
[i
].chan
,
816 #endif /* IEEE80211_DEBUG */
819 best_rssi
= 0xff; /* If signal is bigger than 0xff, we'd be melting. */
821 for (i
= 0; i
< ss_last
; i
++) {
823 benefit
= best_rssi
- as
->as_maxrssi
[c
->chan
->ic_ieee
];
824 sta_assoc
= ic
->ic_sta_assoc
;
826 /* Don't switch... */
830 /* Verify channel is not marked for non-occupancy */
831 if (IEEE80211_IS_CHAN_RADAR(c
->chan
))
834 /* Do not select 802.11a ST if mode is specified and is not
836 if (as
->as_required_mode
&&
837 IEEE80211_IS_CHAN_STURBO(c
->chan
) &&
838 (as
->as_vap_desired_mode
!= IEEE80211_MODE_TURBO_STATIC_A
))
841 /* Verify mode matches any fixed mode specified */
842 if ((c
->chan
->ic_flags
& as
->as_required_mode
) !=
843 as
->as_required_mode
)
846 if ((ic
->ic_bsschan
!= NULL
) &&
847 (ic
->ic_bsschan
!= IEEE80211_CHAN_ANYC
)) {
849 /* Make sure the channels are the same mode */
850 if ((flags
& IEEE80211_SCAN_KEEPMODE
) &&
851 !IEEE80211_ARE_CHANS_SAME_MODE(c
->chan
,
853 /* break the loop as the subsequent chans won't be
858 if (sta_assoc
!= 0) {
859 int sl
= ic
->ic_cn_total
-
860 ic
->ic_chan_nodes
[c
->chan
->ic_ieee
]; /* count */
861 if (ic
->ic_sc_algorithm
== IEEE80211_SC_LOOSE
) {
862 int sl_max
= ic
->ic_sc_sldg
* benefit
;
863 sl
= 1000 * sl
/ sta_assoc
; /* permil */
864 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_SCAN
,
865 "%s: chan %d, dB gained: %d, "
866 "STAs lost: %d permil (max %d)\n",
867 __func__
, c
->chan
->ic_ieee
,
868 benefit
, sl
, sl_max
);
871 } else if (((ic
->ic_sc_algorithm
==
872 IEEE80211_SC_TIGHT
) ||
873 (ic
->ic_sc_algorithm
==
874 IEEE80211_SC_STRICT
)) &&
876 /* Break the loop as the subsequent chans
877 * won't be better. */
882 best_rssi
= as
->as_maxrssi
[best
->ic_ieee
];
887 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_SCAN
,
888 "%s: best: channel %u rssi %d\n",
889 __func__
, i
, as
->as_maxrssi
[i
]);
895 ap_end(struct ieee80211_scan_state
*ss
, struct ieee80211vap
*vap
,
896 int (*action
)(struct ieee80211vap
*,
897 const struct ieee80211_scan_entry
*),
900 struct ap_state
*as
= ss
->ss_priv
;
901 struct ieee80211_channel
*bestchan
= NULL
;
902 struct ieee80211com
*ic
= NULL
;
905 SCAN_AP_LOCK_IRQ(as
);
907 KASSERT(vap
->iv_opmode
== IEEE80211_M_HOSTAP
,
908 ("wrong opmode %u", vap
->iv_opmode
));
911 bestchan
= pick_channel(ss
, vap
, flags
);
912 if (bestchan
== NULL
) {
913 if (ss
->ss_last
> 0) {
914 /* no suitable channel, should not happen */
915 printk(KERN_ERR
"%s: %s: no suitable channel! "
916 "(should not happen)\n",
917 DEV_NAME(vap
->iv_dev
), __func__
);
919 res
= 1; /* Do NOT restart scan */
921 struct ieee80211_scan_entry se
;
922 /* XXX: notify all VAPs? */
923 /* if this is a dynamic turbo frequency , start with normal
925 if (IEEE80211_IS_CHAN_TURBO(bestchan
) &&
926 !IEEE80211_IS_CHAN_STURBO(bestchan
)) {
927 if ((bestchan
= ieee80211_find_channel(ic
,
928 bestchan
->ic_freq
, bestchan
->ic_flags
&
929 ~IEEE80211_CHAN_TURBO
)) == NULL
) {
930 /* should never happen ?? */
931 SCAN_AP_UNLOCK_IRQ_EARLY(as
);
935 memset(&se
, 0, sizeof(se
));
936 se
.se_chan
= bestchan
;
938 as
->as_action
= ss
->ss_ops
->scan_default
;
940 as
->as_action
= action
;
943 /* Must defer action to avoid possible recursive call through
944 * 80211 state machine, which would result in recursive
946 IEEE80211_SCHEDULE_TQUEUE(&as
->as_actiontq
);
949 SCAN_AP_UNLOCK_IRQ(as
);
954 ap_age(struct ieee80211_scan_state
*ss
)
956 struct ap_state
*as
= ss
->ss_priv
;
957 struct scan_entry
*se
, *next
;
959 SCAN_AP_LOCK_IRQ(as
);
960 TAILQ_FOREACH_SAFE(se
, &as
->as_entry
, se_list
, next
) {
961 if (se
->se_notseen
> AP_PURGE_SCANS
) {
962 TAILQ_REMOVE(&as
->as_entry
, se
, se_list
);
963 LIST_REMOVE(se
, se_hash
);
964 FREE(se
, M_80211_SCAN
);
967 SCAN_AP_UNLOCK_IRQ(as
);
971 ap_iterate(struct ieee80211_scan_state
*ss
,
972 ieee80211_scan_iter_func
*f
, void *arg
)
974 struct ap_state
*as
= ss
->ss_priv
;
975 struct scan_entry
*se
;
979 SCAN_AP_GEN_LOCK(as
);
980 gen
= as
->as_scangen
++;
982 SCAN_AP_LOCK_IRQ(as
);
983 TAILQ_FOREACH(se
, &as
->as_entry
, se_list
) {
984 if (se
->se_scangen
!= gen
) {
985 se
->se_scangen
= gen
;
986 /* update public state */
987 se
->base
.se_age
= jiffies
- se
->se_lastupdate
;
988 SCAN_AP_UNLOCK_IRQ_EARLY(as
);
990 res
= (*f
)(arg
, &se
->base
);
992 /* We probably ran out of buffer space. */
1000 SCAN_AP_UNLOCK_IRQ(as
);
1003 SCAN_AP_GEN_UNLOCK(as
);
1009 ap_assoc_success(struct ieee80211_scan_state
*ss
,
1010 const u_int8_t macaddr
[IEEE80211_ADDR_LEN
])
1012 /* should not be called */
1016 ap_assoc_fail(struct ieee80211_scan_state
*ss
,
1017 const u_int8_t macaddr
[IEEE80211_ADDR_LEN
], int reason
)
1019 /* should not be called */
1023 * Default action to execute when a scan entry is found for ap
1024 * mode. Return 1 on success, 0 on failure
1027 ap_default_action(struct ieee80211vap
*vap
,
1028 const struct ieee80211_scan_entry
*se
)
1030 ieee80211_create_ibss(vap
, se
->se_chan
);
1036 action_tasklet(IEEE80211_TQUEUE_ARG data
)
1038 struct ieee80211_scan_state
*ss
= (struct ieee80211_scan_state
*)data
;
1039 struct ap_state
*as
= (struct ap_state
*)ss
->ss_priv
;
1040 struct ieee80211vap
*vap
= ss
->ss_vap
;
1041 SCAN_AP_LOCK_IRQ(as
);
1042 if (as
->as_newscan
) {
1043 struct scan_entry
*se
;
1044 TAILQ_FOREACH(se
, &as
->as_entry
, se_list
) {
1046 * If seen then reset and don't bump the count;
1047 * otherwise bump the ``not seen'' count. Note
1048 * that this ensures that stations for which we
1049 * see frames while not scanning but not during
1050 * this scan will not be penalized.
1059 SCAN_AP_UNLOCK_IRQ(as
);
1061 (*ss
->ss_ops
->scan_default
)(vap
, &as
->as_selbss
);
1067 MODULE_AUTHOR("Errno Consulting, Sam Leffler");
1068 MODULE_DESCRIPTION("802.11 wireless support: default ap scanner");
1069 #ifdef MODULE_LICENSE
1070 MODULE_LICENSE("Dual BSD/GPL");
1073 static const struct ieee80211_scanner ap_default
= {
1074 .scan_name
= "default",
1075 .scan_attach
= ap_attach
,
1076 .scan_detach
= ap_detach
,
1077 .scan_start
= ap_start
,
1078 .scan_restart
= ap_restart
,
1079 .scan_cancel
= ap_cancel
,
1081 .scan_flush
= ap_flush
,
1084 .scan_iterate
= ap_iterate
,
1085 .scan_assoc_success
= ap_assoc_success
,
1086 .scan_assoc_fail
= ap_assoc_fail
,
1087 .scan_default
= ap_default_action
,
1092 init_scanner_ap(void)
1094 ieee80211_scanner_register(IEEE80211_M_HOSTAP
, &ap_default
);
1097 module_init(init_scanner_ap
);
1100 exit_scanner_ap(void)
1102 ieee80211_scanner_unregister_all(&ap_default
);
1104 module_exit(exit_scanner_ap
);