1*32176cfdSRui Paulo /*- 2*32176cfdSRui Paulo * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting 3*32176cfdSRui Paulo * All rights reserved. 4*32176cfdSRui Paulo * 5*32176cfdSRui Paulo * Redistribution and use in source and binary forms, with or without 6*32176cfdSRui Paulo * modification, are permitted provided that the following conditions 7*32176cfdSRui Paulo * are met: 8*32176cfdSRui Paulo * 1. Redistributions of source code must retain the above copyright 9*32176cfdSRui Paulo * notice, this list of conditions and the following disclaimer. 10*32176cfdSRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 11*32176cfdSRui Paulo * notice, this list of conditions and the following disclaimer in the 12*32176cfdSRui Paulo * documentation and/or other materials provided with the distribution. 13*32176cfdSRui Paulo * 14*32176cfdSRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15*32176cfdSRui Paulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16*32176cfdSRui Paulo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17*32176cfdSRui Paulo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18*32176cfdSRui Paulo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19*32176cfdSRui Paulo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20*32176cfdSRui Paulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21*32176cfdSRui Paulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22*32176cfdSRui Paulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23*32176cfdSRui Paulo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24*32176cfdSRui Paulo * 25*32176cfdSRui Paulo * $FreeBSD: head/sys/net80211/ieee80211_dfs.c 196785 2009-09-03 16:29:02Z sam $ 26*32176cfdSRui Paulo * $DragonFly$ 27*32176cfdSRui Paulo */ 28*32176cfdSRui Paulo 29*32176cfdSRui Paulo /* 30*32176cfdSRui Paulo * IEEE 802.11 DFS/Radar support. 31*32176cfdSRui Paulo */ 32*32176cfdSRui Paulo #include "opt_inet.h" 33*32176cfdSRui Paulo #include "opt_wlan.h" 34*32176cfdSRui Paulo 35*32176cfdSRui Paulo #include <sys/param.h> 36*32176cfdSRui Paulo #include <sys/systm.h> 37*32176cfdSRui Paulo #include <sys/mbuf.h> 38*32176cfdSRui Paulo #include <sys/malloc.h> 39*32176cfdSRui Paulo #include <sys/kernel.h> 40*32176cfdSRui Paulo 41*32176cfdSRui Paulo #include <sys/socket.h> 42*32176cfdSRui Paulo #include <sys/sockio.h> 43*32176cfdSRui Paulo #include <sys/endian.h> 44*32176cfdSRui Paulo #include <sys/errno.h> 45*32176cfdSRui Paulo #include <sys/proc.h> 46*32176cfdSRui Paulo #include <sys/sysctl.h> 47*32176cfdSRui Paulo 48*32176cfdSRui Paulo #include <net/if.h> 49*32176cfdSRui Paulo #include <net/if_media.h> 50*32176cfdSRui Paulo #include <net/route.h> 51*32176cfdSRui Paulo 52*32176cfdSRui Paulo #include <netproto/802_11/ieee80211_var.h> 53*32176cfdSRui Paulo 54*32176cfdSRui Paulo MALLOC_DEFINE(M_80211_DFS, "80211dfs", "802.11 DFS state"); 55*32176cfdSRui Paulo 56*32176cfdSRui Paulo static int ieee80211_nol_timeout = 30*60; /* 30 minutes */ 57*32176cfdSRui Paulo SYSCTL_INT(_net_wlan, OID_AUTO, nol_timeout, CTLFLAG_RW, 58*32176cfdSRui Paulo &ieee80211_nol_timeout, 0, "NOL timeout (secs)"); 59*32176cfdSRui Paulo #define NOL_TIMEOUT msecs_to_ticks(ieee80211_nol_timeout*1000) 60*32176cfdSRui Paulo 61*32176cfdSRui Paulo static int ieee80211_cac_timeout = 60; /* 60 seconds */ 62*32176cfdSRui Paulo SYSCTL_INT(_net_wlan, OID_AUTO, cac_timeout, CTLFLAG_RW, 63*32176cfdSRui Paulo &ieee80211_cac_timeout, 0, "CAC timeout (secs)"); 64*32176cfdSRui Paulo #define CAC_TIMEOUT msecs_to_ticks(ieee80211_cac_timeout*1000) 65*32176cfdSRui Paulo 66*32176cfdSRui Paulo void 67*32176cfdSRui Paulo ieee80211_dfs_attach(struct ieee80211com *ic) 68*32176cfdSRui Paulo { 69*32176cfdSRui Paulo struct ieee80211_dfs_state *dfs = &ic->ic_dfs; 70*32176cfdSRui Paulo 71*32176cfdSRui Paulo callout_init_mtx(&dfs->nol_timer, IEEE80211_LOCK_OBJ(ic), 0); 72*32176cfdSRui Paulo callout_init_mtx(&dfs->cac_timer, IEEE80211_LOCK_OBJ(ic), 0); 73*32176cfdSRui Paulo } 74*32176cfdSRui Paulo 75*32176cfdSRui Paulo void 76*32176cfdSRui Paulo ieee80211_dfs_detach(struct ieee80211com *ic) 77*32176cfdSRui Paulo { 78*32176cfdSRui Paulo /* NB: we assume no locking is needed */ 79*32176cfdSRui Paulo ieee80211_dfs_reset(ic); 80*32176cfdSRui Paulo } 81*32176cfdSRui Paulo 82*32176cfdSRui Paulo void 83*32176cfdSRui Paulo ieee80211_dfs_reset(struct ieee80211com *ic) 84*32176cfdSRui Paulo { 85*32176cfdSRui Paulo struct ieee80211_dfs_state *dfs = &ic->ic_dfs; 86*32176cfdSRui Paulo int i; 87*32176cfdSRui Paulo 88*32176cfdSRui Paulo /* NB: we assume no locking is needed */ 89*32176cfdSRui Paulo /* NB: cac_timer should be cleared by the state machine */ 90*32176cfdSRui Paulo callout_drain(&dfs->nol_timer); 91*32176cfdSRui Paulo for (i = 0; i < ic->ic_nchans; i++) 92*32176cfdSRui Paulo ic->ic_channels[i].ic_state = 0; 93*32176cfdSRui Paulo dfs->lastchan = NULL; 94*32176cfdSRui Paulo } 95*32176cfdSRui Paulo 96*32176cfdSRui Paulo static void 97*32176cfdSRui Paulo cac_timeout(void *arg) 98*32176cfdSRui Paulo { 99*32176cfdSRui Paulo struct ieee80211vap *vap = arg; 100*32176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 101*32176cfdSRui Paulo struct ieee80211_dfs_state *dfs = &ic->ic_dfs; 102*32176cfdSRui Paulo int i; 103*32176cfdSRui Paulo 104*32176cfdSRui Paulo IEEE80211_LOCK_ASSERT(ic); 105*32176cfdSRui Paulo 106*32176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_CAC) /* NB: just in case */ 107*32176cfdSRui Paulo return; 108*32176cfdSRui Paulo /* 109*32176cfdSRui Paulo * When radar is detected during a CAC we are woken 110*32176cfdSRui Paulo * up prematurely to switch to a new channel. 111*32176cfdSRui Paulo * Check the channel to decide how to act. 112*32176cfdSRui Paulo */ 113*32176cfdSRui Paulo if (IEEE80211_IS_CHAN_RADAR(ic->ic_curchan)) { 114*32176cfdSRui Paulo ieee80211_notify_cac(ic, ic->ic_curchan, 115*32176cfdSRui Paulo IEEE80211_NOTIFY_CAC_RADAR); 116*32176cfdSRui Paulo 117*32176cfdSRui Paulo if_printf(vap->iv_ifp, 118*32176cfdSRui Paulo "CAC timer on channel %u (%u MHz) stopped due to radar\n", 119*32176cfdSRui Paulo ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq); 120*32176cfdSRui Paulo 121*32176cfdSRui Paulo /* XXX clobbers any existing desired channel */ 122*32176cfdSRui Paulo /* NB: dfs->newchan may be NULL, that's ok */ 123*32176cfdSRui Paulo vap->iv_des_chan = dfs->newchan; 124*32176cfdSRui Paulo /* XXX recursive lock need ieee80211_new_state_locked */ 125*32176cfdSRui Paulo ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); 126*32176cfdSRui Paulo } else { 127*32176cfdSRui Paulo if_printf(vap->iv_ifp, 128*32176cfdSRui Paulo "CAC timer on channel %u (%u MHz) expired; " 129*32176cfdSRui Paulo "no radar detected\n", 130*32176cfdSRui Paulo ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq); 131*32176cfdSRui Paulo /* 132*32176cfdSRui Paulo * Mark all channels with the current frequency 133*32176cfdSRui Paulo * as having completed CAC; this keeps us from 134*32176cfdSRui Paulo * doing it again until we change channels. 135*32176cfdSRui Paulo */ 136*32176cfdSRui Paulo for (i = 0; i < ic->ic_nchans; i++) { 137*32176cfdSRui Paulo struct ieee80211_channel *c = &ic->ic_channels[i]; 138*32176cfdSRui Paulo if (c->ic_freq == ic->ic_curchan->ic_freq) 139*32176cfdSRui Paulo c->ic_state |= IEEE80211_CHANSTATE_CACDONE; 140*32176cfdSRui Paulo } 141*32176cfdSRui Paulo ieee80211_notify_cac(ic, ic->ic_curchan, 142*32176cfdSRui Paulo IEEE80211_NOTIFY_CAC_EXPIRE); 143*32176cfdSRui Paulo ieee80211_cac_completeswitch(vap); 144*32176cfdSRui Paulo } 145*32176cfdSRui Paulo } 146*32176cfdSRui Paulo 147*32176cfdSRui Paulo /* 148*32176cfdSRui Paulo * Initiate the CAC timer. The driver is responsible 149*32176cfdSRui Paulo * for setting up the hardware to scan for radar on the 150*32176cfdSRui Paulo * channnel, we just handle timing things out. 151*32176cfdSRui Paulo */ 152*32176cfdSRui Paulo void 153*32176cfdSRui Paulo ieee80211_dfs_cac_start(struct ieee80211vap *vap) 154*32176cfdSRui Paulo { 155*32176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 156*32176cfdSRui Paulo struct ieee80211_dfs_state *dfs = &ic->ic_dfs; 157*32176cfdSRui Paulo 158*32176cfdSRui Paulo IEEE80211_LOCK_ASSERT(ic); 159*32176cfdSRui Paulo 160*32176cfdSRui Paulo callout_reset(&dfs->cac_timer, CAC_TIMEOUT, cac_timeout, vap); 161*32176cfdSRui Paulo if_printf(vap->iv_ifp, "start %d second CAC timer on channel %u (%u MHz)\n", 162*32176cfdSRui Paulo ticks_to_secs(CAC_TIMEOUT), 163*32176cfdSRui Paulo ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq); 164*32176cfdSRui Paulo ieee80211_notify_cac(ic, ic->ic_curchan, IEEE80211_NOTIFY_CAC_START); 165*32176cfdSRui Paulo } 166*32176cfdSRui Paulo 167*32176cfdSRui Paulo /* 168*32176cfdSRui Paulo * Clear the CAC timer. 169*32176cfdSRui Paulo */ 170*32176cfdSRui Paulo void 171*32176cfdSRui Paulo ieee80211_dfs_cac_stop(struct ieee80211vap *vap) 172*32176cfdSRui Paulo { 173*32176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 174*32176cfdSRui Paulo struct ieee80211_dfs_state *dfs = &ic->ic_dfs; 175*32176cfdSRui Paulo 176*32176cfdSRui Paulo IEEE80211_LOCK_ASSERT(ic); 177*32176cfdSRui Paulo 178*32176cfdSRui Paulo /* NB: racey but not important */ 179*32176cfdSRui Paulo if (callout_pending(&dfs->cac_timer)) { 180*32176cfdSRui Paulo if_printf(vap->iv_ifp, "stop CAC timer on channel %u (%u MHz)\n", 181*32176cfdSRui Paulo ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq); 182*32176cfdSRui Paulo ieee80211_notify_cac(ic, ic->ic_curchan, 183*32176cfdSRui Paulo IEEE80211_NOTIFY_CAC_STOP); 184*32176cfdSRui Paulo } 185*32176cfdSRui Paulo callout_stop(&dfs->cac_timer); 186*32176cfdSRui Paulo } 187*32176cfdSRui Paulo 188*32176cfdSRui Paulo void 189*32176cfdSRui Paulo ieee80211_dfs_cac_clear(struct ieee80211com *ic, 190*32176cfdSRui Paulo const struct ieee80211_channel *chan) 191*32176cfdSRui Paulo { 192*32176cfdSRui Paulo int i; 193*32176cfdSRui Paulo 194*32176cfdSRui Paulo for (i = 0; i < ic->ic_nchans; i++) { 195*32176cfdSRui Paulo struct ieee80211_channel *c = &ic->ic_channels[i]; 196*32176cfdSRui Paulo if (c->ic_freq == chan->ic_freq) 197*32176cfdSRui Paulo c->ic_state &= ~IEEE80211_CHANSTATE_CACDONE; 198*32176cfdSRui Paulo } 199*32176cfdSRui Paulo } 200*32176cfdSRui Paulo 201*32176cfdSRui Paulo static void 202*32176cfdSRui Paulo dfs_timeout(void *arg) 203*32176cfdSRui Paulo { 204*32176cfdSRui Paulo struct ieee80211com *ic = arg; 205*32176cfdSRui Paulo struct ieee80211_dfs_state *dfs = &ic->ic_dfs; 206*32176cfdSRui Paulo struct ieee80211_channel *c; 207*32176cfdSRui Paulo int i, oldest, now; 208*32176cfdSRui Paulo 209*32176cfdSRui Paulo IEEE80211_LOCK_ASSERT(ic); 210*32176cfdSRui Paulo 211*32176cfdSRui Paulo now = oldest = ticks; 212*32176cfdSRui Paulo for (i = 0; i < ic->ic_nchans; i++) { 213*32176cfdSRui Paulo c = &ic->ic_channels[i]; 214*32176cfdSRui Paulo if (IEEE80211_IS_CHAN_RADAR(c)) { 215*32176cfdSRui Paulo if (time_after_eq(now, dfs->nol_event[i]+NOL_TIMEOUT)) { 216*32176cfdSRui Paulo c->ic_state &= ~IEEE80211_CHANSTATE_RADAR; 217*32176cfdSRui Paulo if (c->ic_state & IEEE80211_CHANSTATE_NORADAR) { 218*32176cfdSRui Paulo /* 219*32176cfdSRui Paulo * NB: do this here so we get only one 220*32176cfdSRui Paulo * msg instead of one for every channel 221*32176cfdSRui Paulo * table entry. 222*32176cfdSRui Paulo */ 223*32176cfdSRui Paulo if_printf(ic->ic_ifp, "radar on channel" 224*32176cfdSRui Paulo " %u (%u MHz) cleared after timeout\n", 225*32176cfdSRui Paulo c->ic_ieee, c->ic_freq); 226*32176cfdSRui Paulo /* notify user space */ 227*32176cfdSRui Paulo c->ic_state &= 228*32176cfdSRui Paulo ~IEEE80211_CHANSTATE_NORADAR; 229*32176cfdSRui Paulo ieee80211_notify_radar(ic, c); 230*32176cfdSRui Paulo } 231*32176cfdSRui Paulo } else if (dfs->nol_event[i] < oldest) 232*32176cfdSRui Paulo oldest = dfs->nol_event[i]; 233*32176cfdSRui Paulo } 234*32176cfdSRui Paulo } 235*32176cfdSRui Paulo if (oldest != now) { 236*32176cfdSRui Paulo /* arrange to process next channel up for a status change */ 237*32176cfdSRui Paulo callout_schedule(&dfs->nol_timer, oldest + NOL_TIMEOUT - now); 238*32176cfdSRui Paulo } 239*32176cfdSRui Paulo } 240*32176cfdSRui Paulo 241*32176cfdSRui Paulo static void 242*32176cfdSRui Paulo announce_radar(struct ifnet *ifp, const struct ieee80211_channel *curchan, 243*32176cfdSRui Paulo const struct ieee80211_channel *newchan) 244*32176cfdSRui Paulo { 245*32176cfdSRui Paulo if (newchan == NULL) 246*32176cfdSRui Paulo if_printf(ifp, "radar detected on channel %u (%u MHz)\n", 247*32176cfdSRui Paulo curchan->ic_ieee, curchan->ic_freq); 248*32176cfdSRui Paulo else 249*32176cfdSRui Paulo if_printf(ifp, "radar detected on channel %u (%u MHz), " 250*32176cfdSRui Paulo "moving to channel %u (%u MHz)\n", 251*32176cfdSRui Paulo curchan->ic_ieee, curchan->ic_freq, 252*32176cfdSRui Paulo newchan->ic_ieee, newchan->ic_freq); 253*32176cfdSRui Paulo } 254*32176cfdSRui Paulo 255*32176cfdSRui Paulo /* 256*32176cfdSRui Paulo * Handle a radar detection event on a channel. The channel is 257*32176cfdSRui Paulo * added to the NOL list and we record the time of the event. 258*32176cfdSRui Paulo * Entries are aged out after NOL_TIMEOUT. If radar was 259*32176cfdSRui Paulo * detected while doing CAC we force a state/channel change. 260*32176cfdSRui Paulo * Otherwise radar triggers a channel switch using the CSA 261*32176cfdSRui Paulo * mechanism (when the channel is the bss channel). 262*32176cfdSRui Paulo */ 263*32176cfdSRui Paulo void 264*32176cfdSRui Paulo ieee80211_dfs_notify_radar(struct ieee80211com *ic, struct ieee80211_channel *chan) 265*32176cfdSRui Paulo { 266*32176cfdSRui Paulo struct ieee80211_dfs_state *dfs = &ic->ic_dfs; 267*32176cfdSRui Paulo int i, now; 268*32176cfdSRui Paulo 269*32176cfdSRui Paulo IEEE80211_LOCK_ASSERT(ic); 270*32176cfdSRui Paulo 271*32176cfdSRui Paulo /* 272*32176cfdSRui Paulo * Mark all entries with this frequency. Notify user 273*32176cfdSRui Paulo * space and arrange for notification when the radar 274*32176cfdSRui Paulo * indication is cleared. Then kick the NOL processing 275*32176cfdSRui Paulo * thread if not already running. 276*32176cfdSRui Paulo */ 277*32176cfdSRui Paulo now = ticks; 278*32176cfdSRui Paulo for (i = 0; i < ic->ic_nchans; i++) { 279*32176cfdSRui Paulo struct ieee80211_channel *c = &ic->ic_channels[i]; 280*32176cfdSRui Paulo if (c->ic_freq == chan->ic_freq) { 281*32176cfdSRui Paulo c->ic_state &= ~IEEE80211_CHANSTATE_CACDONE; 282*32176cfdSRui Paulo c->ic_state |= IEEE80211_CHANSTATE_RADAR; 283*32176cfdSRui Paulo dfs->nol_event[i] = now; 284*32176cfdSRui Paulo } 285*32176cfdSRui Paulo } 286*32176cfdSRui Paulo ieee80211_notify_radar(ic, chan); 287*32176cfdSRui Paulo chan->ic_state |= IEEE80211_CHANSTATE_NORADAR; 288*32176cfdSRui Paulo if (!callout_pending(&dfs->nol_timer)) 289*32176cfdSRui Paulo callout_reset(&dfs->nol_timer, NOL_TIMEOUT, dfs_timeout, ic); 290*32176cfdSRui Paulo 291*32176cfdSRui Paulo /* 292*32176cfdSRui Paulo * If radar is detected on the bss channel while 293*32176cfdSRui Paulo * doing CAC; force a state change by scheduling the 294*32176cfdSRui Paulo * callout to be dispatched asap. Otherwise, if this 295*32176cfdSRui Paulo * event is for the bss channel then we must quiet 296*32176cfdSRui Paulo * traffic and schedule a channel switch. 297*32176cfdSRui Paulo * 298*32176cfdSRui Paulo * Note this allows us to receive notification about 299*32176cfdSRui Paulo * channels other than the bss channel; not sure 300*32176cfdSRui Paulo * that can/will happen but it's simple to support. 301*32176cfdSRui Paulo */ 302*32176cfdSRui Paulo if (chan == ic->ic_bsschan) { 303*32176cfdSRui Paulo /* XXX need a way to defer to user app */ 304*32176cfdSRui Paulo dfs->newchan = ieee80211_dfs_pickchannel(ic); 305*32176cfdSRui Paulo 306*32176cfdSRui Paulo announce_radar(ic->ic_ifp, chan, dfs->newchan); 307*32176cfdSRui Paulo 308*32176cfdSRui Paulo if (callout_pending(&dfs->cac_timer)) 309*32176cfdSRui Paulo callout_schedule(&dfs->cac_timer, 0); 310*32176cfdSRui Paulo else if (dfs->newchan != NULL) { 311*32176cfdSRui Paulo /* XXX mode 1, switch count 2 */ 312*32176cfdSRui Paulo /* XXX calculate switch count based on max 313*32176cfdSRui Paulo switch time and beacon interval? */ 314*32176cfdSRui Paulo ieee80211_csa_startswitch(ic, dfs->newchan, 1, 2); 315*32176cfdSRui Paulo } else { 316*32176cfdSRui Paulo /* 317*32176cfdSRui Paulo * Spec says to stop all transmissions and 318*32176cfdSRui Paulo * wait on the current channel for an entry 319*32176cfdSRui Paulo * on the NOL to expire. 320*32176cfdSRui Paulo */ 321*32176cfdSRui Paulo /*XXX*/ 322*32176cfdSRui Paulo } 323*32176cfdSRui Paulo } else { 324*32176cfdSRui Paulo /* 325*32176cfdSRui Paulo * Issue rate-limited console msgs. 326*32176cfdSRui Paulo */ 327*32176cfdSRui Paulo if (dfs->lastchan != chan) { 328*32176cfdSRui Paulo dfs->lastchan = chan; 329*32176cfdSRui Paulo dfs->cureps = 0; 330*32176cfdSRui Paulo announce_radar(ic->ic_ifp, chan, NULL); 331*32176cfdSRui Paulo } else if (ppsratecheck(&dfs->lastevent, &dfs->cureps, 1)) { 332*32176cfdSRui Paulo announce_radar(ic->ic_ifp, chan, NULL); 333*32176cfdSRui Paulo } 334*32176cfdSRui Paulo } 335*32176cfdSRui Paulo } 336*32176cfdSRui Paulo 337*32176cfdSRui Paulo struct ieee80211_channel * 338*32176cfdSRui Paulo ieee80211_dfs_pickchannel(struct ieee80211com *ic) 339*32176cfdSRui Paulo { 340*32176cfdSRui Paulo struct ieee80211_channel *c; 341*32176cfdSRui Paulo int i, flags; 342*32176cfdSRui Paulo uint16_t v; 343*32176cfdSRui Paulo 344*32176cfdSRui Paulo /* 345*32176cfdSRui Paulo * Consult the scan cache first. 346*32176cfdSRui Paulo */ 347*32176cfdSRui Paulo flags = ic->ic_curchan->ic_flags & IEEE80211_CHAN_ALL; 348*32176cfdSRui Paulo /* 349*32176cfdSRui Paulo * XXX if curchan is HT this will never find a channel 350*32176cfdSRui Paulo * XXX 'cuz we scan only legacy channels 351*32176cfdSRui Paulo */ 352*32176cfdSRui Paulo c = ieee80211_scan_pickchannel(ic, flags); 353*32176cfdSRui Paulo if (c != NULL) 354*32176cfdSRui Paulo return c; 355*32176cfdSRui Paulo /* 356*32176cfdSRui Paulo * No channel found in scan cache; select a compatible 357*32176cfdSRui Paulo * one at random (skipping channels where radar has 358*32176cfdSRui Paulo * been detected). 359*32176cfdSRui Paulo */ 360*32176cfdSRui Paulo get_random_bytes(&v, sizeof(v)); 361*32176cfdSRui Paulo v %= ic->ic_nchans; 362*32176cfdSRui Paulo for (i = v; i < ic->ic_nchans; i++) { 363*32176cfdSRui Paulo c = &ic->ic_channels[i]; 364*32176cfdSRui Paulo if (!IEEE80211_IS_CHAN_RADAR(c) && 365*32176cfdSRui Paulo (c->ic_flags & flags) == flags) 366*32176cfdSRui Paulo return c; 367*32176cfdSRui Paulo } 368*32176cfdSRui Paulo for (i = 0; i < v; i++) { 369*32176cfdSRui Paulo c = &ic->ic_channels[i]; 370*32176cfdSRui Paulo if (!IEEE80211_IS_CHAN_RADAR(c) && 371*32176cfdSRui Paulo (c->ic_flags & flags) == flags) 372*32176cfdSRui Paulo return c; 373*32176cfdSRui Paulo } 374*32176cfdSRui Paulo if_printf(ic->ic_ifp, "HELP, no channel located to switch to!\n"); 375*32176cfdSRui Paulo return NULL; 376*32176cfdSRui Paulo } 377