--- a/net80211/ieee80211_scan_sta.c +++ b/net80211/ieee80211_scan_sta.c @@ -317,147 +317,6 @@ found: #undef ISPROBE } -static struct ieee80211_channel * -find11gchannel(struct ieee80211com *ic, int i, int freq) -{ - struct ieee80211_channel *c; - int j; - - /* - * The normal ordering in the channel list is b channel - * immediately followed by g so optimize the search for - * this. We'll still do a full search just in case. - */ - for (j = i+1; j < ic->ic_nchans; j++) { - c = &ic->ic_channels[j]; - if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c)) - return c; - } - for (j = 0; j < i; j++) { - c = &ic->ic_channels[j]; - if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c)) - return c; - } - return NULL; -} -static const u_int chanflags[] = { - IEEE80211_CHAN_B, /* IEEE80211_MODE_AUTO */ - IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ - IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ - IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ - IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ - IEEE80211_CHAN_A, /* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */ - IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_TURBO_G */ - IEEE80211_CHAN_ST, /* IEEE80211_MODE_TURBO_STATIC_A */ -}; - -static void -add_channels(struct ieee80211com *ic, - struct ieee80211_scan_state *ss, - enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq) -{ - struct ieee80211_channel *c, *cg; - u_int modeflags; - int i; - - KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode)); - modeflags = chanflags[mode]; - for (i = 0; i < nfreq; i++) { - c = ieee80211_find_channel(ic, freq[i], modeflags); - if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee)) - continue; - if (mode == IEEE80211_MODE_AUTO) { - /* - * XXX special-case 11b/g channels so we select - * the g channel if both are present. - */ - if (IEEE80211_IS_CHAN_B(c) && - (cg = find11gchannel(ic, i, c->ic_freq)) != NULL) - c = cg; - } - if (ss->ss_last >= IEEE80211_SCAN_MAX) - break; - ss->ss_chans[ss->ss_last++] = c; - } -} - -static const u_int16_t rcl1[] = /* 8 FCC channel: 52, 56, 60, 64, 36, 40, 44, 48 */ -{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 }; -static const u_int16_t rcl2[] = /* 4 MKK channels: 34, 38, 42, 46 */ -{ 5170, 5190, 5210, 5230 }; -static const u_int16_t rcl3[] = /* 2.4Ghz ch: 1,6,11,7,13 */ -{ 2412, 2437, 2462, 2442, 2472 }; -static const u_int16_t rcl4[] = /* 5 FCC channel: 149, 153, 161, 165 */ -{ 5745, 5765, 5785, 5805, 5825 }; -static const u_int16_t rcl7[] = /* 11 ETSI channel: 100,104,108,112,116,120,124,128,132,136,140 */ -{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 }; -static const u_int16_t rcl8[] = /* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */ -{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 }; -static const u_int16_t rcl9[] = /* 2.4Ghz ch: 14 */ -{ 2484 }; -static const u_int16_t rcl10[] = /* Added Korean channels 2312-2372 */ -{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 }; -static const u_int16_t rcl11[] = /* Added Japan channels in 4.9/5.0 spectrum */ -{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 }; -#ifdef ATH_TURBO_SCAN -static const u_int16_t rcl5[] = /* 3 static turbo channels */ -{ 5210, 5250, 5290 }; -static const u_int16_t rcl6[] = /* 2 static turbo channels */ -{ 5760, 5800 }; -static const u_int16_t rcl6x[] = /* 4 FCC3 turbo channels */ -{ 5540, 5580, 5620, 5660 }; -static const u_int16_t rcl12[] = /* 2.4Ghz Turbo channel 6 */ -{ 2437 }; -static const u_int16_t rcl13[] = /* dynamic Turbo channels */ -{ 5200, 5240, 5280, 5765, 5805 }; -#endif /* ATH_TURBO_SCAN */ - -struct scanlist { - u_int16_t mode; - u_int16_t count; - const u_int16_t *list; -}; - -#define IEEE80211_MODE_TURBO_STATIC_A IEEE80211_MODE_MAX -#define X(a) .count = sizeof(a)/sizeof(a[0]), .list = a - -static const struct scanlist staScanTable[] = { - { IEEE80211_MODE_11B, X(rcl3) }, - { IEEE80211_MODE_11A, X(rcl1) }, - { IEEE80211_MODE_11A, X(rcl2) }, - { IEEE80211_MODE_11B, X(rcl8) }, - { IEEE80211_MODE_11B, X(rcl9) }, - { IEEE80211_MODE_11A, X(rcl4) }, -#ifdef ATH_TURBO_SCAN - { IEEE80211_MODE_TURBO_STATIC_A, X(rcl5) }, - { IEEE80211_MODE_TURBO_STATIC_A, X(rcl6) }, - { IEEE80211_MODE_TURBO_A, X(rcl6x) }, - { IEEE80211_MODE_TURBO_A, X(rcl13) }, -#endif /* ATH_TURBO_SCAN */ - { IEEE80211_MODE_11A, X(rcl7) }, - { IEEE80211_MODE_11B, X(rcl10) }, - { IEEE80211_MODE_11A, X(rcl11) }, -#ifdef ATH_TURBO_SCAN - { IEEE80211_MODE_TURBO_G, X(rcl12) }, -#endif /* ATH_TURBO_SCAN */ - { .list = NULL } -}; - -#undef X - -static int -checktable(const struct scanlist *scan, const struct ieee80211_channel *c) -{ - int i; - - for (; scan->list != NULL; scan++) { - for (i = 0; i < scan->count; i++) - if (scan->list[i] == c->ic_freq) - return 1; - } - return 0; -} - /* * Start a station-mode scan by populating the channel list. */ @@ -466,81 +325,14 @@ sta_start(struct ieee80211_scan_state *s { struct ieee80211com *ic = vap->iv_ic; struct sta_table *st = ss->ss_priv; - const struct scanlist *scan; enum ieee80211_phymode mode; struct ieee80211_channel *c; int i; ss->ss_last = 0; - /* - * Use the table of ordered channels to construct the list - * of channels for scanning. Any channels in the ordered - * list not in the master list will be discarded. - */ - for (scan = staScanTable; scan->list != NULL; scan++) { - mode = scan->mode; - if (vap->iv_des_mode != IEEE80211_MODE_AUTO) { - /* - * If a desired mode was specified, scan only - * channels that satisfy that constraint. - */ - if (vap->iv_des_mode != mode) { - /* - * The scan table marks 2.4Ghz channels as b - * so if the desired mode is 11g, then use - * the 11b channel list but upgrade the mode. - */ - if (vap->iv_des_mode != IEEE80211_MODE_11G || - mode != IEEE80211_MODE_11B) - continue; - mode = IEEE80211_MODE_11G; /* upgrade */ - } - } else { - /* - * This lets ieee80211_scan_add_channels - * upgrade an 11b channel to 11g if available. - */ - if (mode == IEEE80211_MODE_11B) - mode = IEEE80211_MODE_AUTO; - } - /* XR does not operate on turbo channels */ - if ((vap->iv_flags & IEEE80211_F_XR) && - (mode == IEEE80211_MODE_TURBO_A || - mode == IEEE80211_MODE_TURBO_G)) - continue; - /* - * Add the list of the channels; any that are not - * in the master channel list will be discarded. - */ - add_channels(ic, ss, mode, scan->list, scan->count); - } - - /* - * Add the channels from the ic (from HAL) that are not present - * in the staScanTable. - */ - for (i = 0; i < ic->ic_nchans; i++) { - c = &ic->ic_channels[i]; - /* - * scan dynamic turbo channels in normal mode. - */ - if (IEEE80211_IS_CHAN_DTURBO(c)) - continue; - mode = ieee80211_chan2mode(c); - if (vap->iv_des_mode != IEEE80211_MODE_AUTO) { - /* - * If a desired mode was specified, scan only - * channels that satisfy that constraint. - */ - if (vap->iv_des_mode != mode) - continue; - - } - if (!checktable(staScanTable, c)) - ss->ss_chans[ss->ss_last++] = c; - } - + ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode); ss->ss_next = 0; + /* XXX tunables */ /* * The scanner will stay on station for ss_maxdwell ms (using a @@ -749,17 +541,7 @@ match_bss(struct ieee80211vap *vap, fail = 0; if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, se->se_chan))) fail |= 0x01; - /* - * NB: normally the desired mode is used to construct - * the channel list, but it's possible for the scan - * cache to include entries for stations outside this - * list so we check the desired mode here to weed them - * out. - */ - if (vap->iv_des_mode != IEEE80211_MODE_AUTO && - (se->se_chan->ic_flags & IEEE80211_CHAN_ALLTURBO) != - chanflags[vap->iv_des_mode]) - fail |= 0x01; + if (vap->iv_opmode == IEEE80211_M_IBSS) { if ((se->se_capinfo & IEEE80211_CAPINFO_IBSS) == 0) fail |= 0x02; @@ -1168,78 +950,6 @@ static const struct ieee80211_scanner st .scan_default = ieee80211_sta_join, }; -/* - * Start an adhoc-mode scan by populating the channel list. - */ -static int -adhoc_start(struct ieee80211_scan_state *ss, struct ieee80211vap *vap) -{ - struct ieee80211com *ic = vap->iv_ic; - struct sta_table *st = ss->ss_priv; - const struct scanlist *scan; - enum ieee80211_phymode mode; - - ss->ss_last = 0; - /* - * Use the table of ordered channels to construct the list - * of channels for scanning. Any channels in the ordered - * list not in the master list will be discarded. - */ - for (scan = staScanTable; scan->list != NULL; scan++) { - mode = scan->mode; - if (vap->iv_des_mode != IEEE80211_MODE_AUTO) { - /* - * If a desired mode was specified, scan only - * channels that satisfy that constraint. - */ - if (vap->iv_des_mode != mode) { - /* - * The scan table marks 2.4Ghz channels as b - * so if the desired mode is 11g, then use - * the 11b channel list but upgrade the mode. - */ - if (vap->iv_des_mode != IEEE80211_MODE_11G || - mode != IEEE80211_MODE_11B) - continue; - mode = IEEE80211_MODE_11G; /* upgrade */ - } - } else { - /* - * This lets ieee80211_scan_add_channels - * upgrade an 11b channel to 11g if available. - */ - if (mode == IEEE80211_MODE_11B) - mode = IEEE80211_MODE_AUTO; - } - /* XR does not operate on turbo channels */ - if ((vap->iv_flags & IEEE80211_F_XR) && - (mode == IEEE80211_MODE_TURBO_A || - mode == IEEE80211_MODE_TURBO_G)) - continue; - /* - * Add the list of the channels; any that are not - * in the master channel list will be discarded. - */ - add_channels(ic, ss, mode, scan->list, scan->count); - } - ss->ss_next = 0; - /* XXX tunables */ - ss->ss_mindwell = msecs_to_jiffies(200); /* 200ms */ - ss->ss_maxdwell = msecs_to_jiffies(200); /* 200ms */ - -#ifdef IEEE80211_DEBUG - if (ieee80211_msg_scan(vap)) { - printk("%s: scan set ", vap->iv_dev->name); - ieee80211_scan_dump_channels(ss); - printk(" dwell min %ld max %ld\n", - ss->ss_mindwell, ss->ss_maxdwell); - } -#endif /* IEEE80211_DEBUG */ - - st->st_newscan = 1; - - return 0; -} /* * Select a channel to start an adhoc network on. @@ -1405,7 +1115,7 @@ static const struct ieee80211_scanner ad .scan_name = "default", .scan_attach = sta_attach, .scan_detach = sta_detach, - .scan_start = adhoc_start, + .scan_start = sta_start, .scan_restart = sta_restart, .scan_cancel = sta_cancel, .scan_end = adhoc_pick_bss, --- a/net80211/ieee80211.c +++ b/net80211/ieee80211.c @@ -278,6 +278,11 @@ ieee80211_ifattach(struct ieee80211com * ("channel with bogus ieee number %u", c->ic_ieee)); setbit(ic->ic_chan_avail, c->ic_ieee); + if (c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT) + c->ic_scanflags |= IEEE80211_NOSCAN_SET; + else + c->ic_scanflags &= ~IEEE80211_NOSCAN_SET; + /* Identify mode capabilities. */ if (IEEE80211_IS_CHAN_A(c)) ic->ic_modecaps |= 1 << IEEE80211_MODE_11A; @@ -1447,10 +1452,6 @@ ieee80211_media_change(struct net_device vap->iv_fixed_rate = newrate; /* fixed TX rate */ error = -ENETRESET; } - if (vap->iv_des_mode != newmode) { - vap->iv_des_mode = newmode; /* desired PHY mode */ - error = -ENETRESET; - } return error; } EXPORT_SYMBOL(ieee80211_media_change); --- a/net80211/_ieee80211.h +++ b/net80211/_ieee80211.h @@ -132,6 +132,11 @@ enum ieee80211_scanmode { IEEE80211_SCAN_FIRST = 2, /* take first suitable candidate */ }; +enum ieee80211_scanflags { + IEEE80211_NOSCAN_DEFAULT = (1 << 0), + IEEE80211_NOSCAN_SET = (1 << 1), +}; + /* * Channels are specified by frequency and attributes. */ @@ -142,6 +147,7 @@ struct ieee80211_channel { int8_t ic_maxregpower; /* maximum regulatory tx power in dBm */ int8_t ic_maxpower; /* maximum tx power in dBm */ int8_t ic_minpower; /* minimum tx power in dBm */ + u_int8_t ic_scanflags; }; #define IEEE80211_CHAN_MAX 255 --- a/net80211/ieee80211_ioctl.h +++ b/net80211/ieee80211_ioctl.h @@ -555,6 +555,7 @@ struct ieee80211req_scan_result { #define IEEE80211_IOCTL_WDSADDMAC (SIOCIWFIRSTPRIV+26) #define IEEE80211_IOCTL_WDSDELMAC (SIOCIWFIRSTPRIV+28) #define IEEE80211_IOCTL_KICKMAC (SIOCIWFIRSTPRIV+30) +#define IEEE80211_IOCTL_SETSCANLIST (SIOCIWFIRSTPRIV+31) enum { IEEE80211_WMMPARAMS_CWMIN = 1, --- a/net80211/ieee80211_scan_ap.c +++ b/net80211/ieee80211_scan_ap.c @@ -105,11 +105,6 @@ struct scan_entry { }; struct ap_state { - unsigned int as_vap_desired_mode; /* Used for channel selection, - * vap->iv_des_mode */ - unsigned int as_required_mode; /* Used for channel selection, - * filtered version of - * as_vap_desired_mode */ int as_maxrssi[IEEE80211_CHAN_MAX]; /* Used for channel selection */ /* These fields are just for scan caching for returning responses to @@ -129,131 +124,7 @@ struct ap_state { static int ap_flush(struct ieee80211_scan_state *); static void action_tasklet(IEEE80211_TQUEUE_ARG); -static struct ieee80211_channel *find11gchannel(struct ieee80211com *ic, - int i, int freq); -static const u_int chanflags[] = { - IEEE80211_CHAN_B, /* IEEE80211_MODE_AUTO */ - IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ - IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ - IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ - IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ - IEEE80211_CHAN_A, /* IEEE80211_MODE_TURBO_A */ /* for turbo mode - * look for AP in - * normal channel - */ - IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_TURBO_G */ - IEEE80211_CHAN_ST, /* IEEE80211_MODE_TURBO_STATIC_A */ -}; - -static const u_int16_t rcl1[] = /* 8 FCC channel: 52, 56, 60, 64, - * 36, 40, 44, 48 */ -{ 5260, 5280, 5300, 5320, 5180, 5200, 5220, 5240 }; -static const u_int16_t rcl2[] = /* 4 MKK channels: 34, 38, 42, 46 */ -{ 5170, 5190, 5210, 5230 }; -static const u_int16_t rcl3[] = /* 2.4Ghz ch: 1,6,11,7,13 */ -{ 2412, 2437, 2462, 2442, 2472 }; -static const u_int16_t rcl4[] = /* 5 FCC channel: 149, 153, 161, 165 */ -{ 5745, 5765, 5785, 5805, 5825 }; -static const u_int16_t rcl7[] = /* 11 ETSI channel: 100, 104, 108, 112, - * 116, 120, 124, 128, - * 132, 136, 140 */ -{ 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700 }; -static const u_int16_t rcl8[] = /* 2.4Ghz ch: 2,3,4,5,8,9,10,12 */ -{ 2417, 2422, 2427, 2432, 2447, 2452, 2457, 2467 }; -static const u_int16_t rcl9[] = /* 2.4Ghz ch: 14 */ -{ 2484 }; -static const u_int16_t rcl10[] = /* Added Korean channels 2312-2372 */ -{ 2312, 2317, 2322, 2327, 2332, 2337, 2342, 2347, 2352, 2357, 2362, 2367, 2372 }; -static const u_int16_t rcl11[] = /* Added Japan channels in 4.9/5.0 spectrum */ -{ 5040, 5060, 5080, 4920, 4940, 4960, 4980 }; -#ifdef ATH_TURBO_SCAN -static const u_int16_t rcl5[] = /* 3 static turbo channels */ -{ 5210, 5250, 5290 }; -static const u_int16_t rcl6[] = /* 2 static turbo channels */ -{ 5760, 5800 }; -static const u_int16_t rcl6x[] = /* 4 FCC3 turbo channels */ -{ 5540, 5580, 5620, 5660 }; -static const u_int16_t rcl12[] = /* 2.4Ghz Turbo channel 6 */ -{ 2437 }; -static const u_int16_t rcl13[] = /* dynamic Turbo channels */ -{ 5200, 5240, 5280, 5765, 5805 }; -#endif /* ATH_TURBO_SCAN */ - -struct scanlist { - u_int16_t mode; - u_int16_t count; - const u_int16_t *list; -}; - -#define IEEE80211_MODE_TURBO_STATIC_A IEEE80211_MODE_MAX -#define X(a) .count = ARRAY_SIZE(a), .list = a - -static const struct scanlist staScanTable[] = { - { IEEE80211_MODE_11B, X(rcl3) }, - { IEEE80211_MODE_11A, X(rcl1) }, - { IEEE80211_MODE_11A, X(rcl2) }, - { IEEE80211_MODE_11B, X(rcl8) }, - { IEEE80211_MODE_11B, X(rcl9) }, - { IEEE80211_MODE_11A, X(rcl4) }, -#ifdef ATH_TURBO_SCAN - { IEEE80211_MODE_TURBO_STATIC_A, X(rcl5) }, - { IEEE80211_MODE_TURBO_STATIC_A, X(rcl6) }, - { IEEE80211_MODE_TURBO_A, X(rcl6x) }, - { IEEE80211_MODE_TURBO_A, X(rcl13) }, -#endif /* ATH_TURBO_SCAN */ - { IEEE80211_MODE_11A, X(rcl7) }, - { IEEE80211_MODE_11B, X(rcl10) }, - { IEEE80211_MODE_11A, X(rcl11) }, -#ifdef ATH_TURBO_SCAN - { IEEE80211_MODE_TURBO_G, X(rcl12) }, -#endif /* ATH_TURBO_SCAN */ - { .list = NULL } -}; - -#undef X -/* This function must be invoked with locks acquired */ -static void -add_channels(struct ieee80211com *ic, - struct ieee80211_scan_state *ss, - enum ieee80211_phymode mode, const u_int16_t freq[], int nfreq) -{ - struct ieee80211_channel *c, *cg; - u_int modeflags; - int i; - - KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode)); - modeflags = chanflags[mode]; - for (i = 0; i < nfreq; i++) { - c = ieee80211_find_channel(ic, freq[i], modeflags); - if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee)) - continue; - if (mode == IEEE80211_MODE_AUTO) { - /* XXX special-case 11b/g channels so we select - * the g channel if both are present. */ - if (IEEE80211_IS_CHAN_B(c) && - (cg = find11gchannel(ic, i, c->ic_freq)) != NULL) - c = cg; - } - if (ss->ss_last >= IEEE80211_SCAN_MAX) - break; - ss->ss_chans[ss->ss_last++] = c; - } -} - -/* This function must be invoked with locks acquired */ -static int -checktable(const struct scanlist *scan, const struct ieee80211_channel *c) -{ - int i; - - for (; scan->list != NULL; scan++) { - for (i = 0; i < scan->count; i++) - if (scan->list[i] == c->ic_freq) - return 1; - } - return 0; -} /* * Attach prior to any scanning work. @@ -327,29 +198,6 @@ saveie(u_int8_t **iep, const u_int8_t *i ieee80211_saveie(iep, ie); } -/* This function must be invoked with locks acquired */ -static struct ieee80211_channel * -find11gchannel(struct ieee80211com *ic, int i, int freq) -{ - struct ieee80211_channel *c; - int j; - - /* The normal ordering in the channel list is b channel - * immediately followed by g so optimize the search for - * this. We'll still do a full search just in case. */ - for (j = i + 1; j < ic->ic_nchans; j++) { - c = &ic->ic_channels[j]; - if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c)) - return c; - } - for (j = 0; j < i; j++) { - c = &ic->ic_channels[j]; - if ((c->ic_freq == freq) && IEEE80211_IS_CHAN_ANYG(c)) - return c; - } - return NULL; -} - /* * Start an ap scan by populating the channel list. */ @@ -358,90 +206,15 @@ ap_start(struct ieee80211_scan_state *ss { struct ap_state *as = ss->ss_priv; struct ieee80211com *ic = NULL; - const struct scanlist *sl = NULL; - struct ieee80211_channel *c = NULL; int i; unsigned int mode = 0; SCAN_AP_LOCK_IRQ(as); ic = vap->iv_ic; /* Determine mode flags to match, or leave zero for auto mode */ - as->as_vap_desired_mode = vap->iv_des_mode; - as->as_required_mode = 0; - if (as->as_vap_desired_mode != IEEE80211_MODE_AUTO) { - as->as_required_mode = chanflags[as->as_vap_desired_mode]; - if ((vap->iv_ath_cap & IEEE80211_ATHC_TURBOP) && - (as->as_required_mode != IEEE80211_CHAN_ST)) { - /* Fixup for dynamic turbo flags */ - if (as->as_vap_desired_mode == IEEE80211_MODE_11G) - as->as_required_mode = IEEE80211_CHAN_108G; - else - as->as_required_mode = IEEE80211_CHAN_108A; - } - } - ss->ss_last = 0; - /* Use the table of ordered channels to construct the list - * of channels for scanning. Any channels in the ordered - * list not in the master list will be discarded. */ - for (sl = staScanTable; sl->list != NULL; sl++) { - mode = sl->mode; - - /* The scan table marks 2.4Ghz channels as b - * so if the desired mode is 11g, then use - * the 11b channel list but upgrade the mode. */ - if (as->as_vap_desired_mode && - (as->as_vap_desired_mode != mode) && - (as->as_vap_desired_mode == IEEE80211_MODE_11G) && - (mode == IEEE80211_MODE_11B)) - mode = IEEE80211_MODE_11G; - - /* If we are in "AUTO" mode, upgrade the mode to auto. - * This lets add_channels upgrade an 11b channel to - * 11g if available. */ - if (!as->as_vap_desired_mode && (mode == IEEE80211_MODE_11B)) - mode = IEEE80211_MODE_AUTO; - - /* Add the list of the channels; any that are not - * in the master channel list will be discarded. */ - add_channels(ic, ss, mode, sl->list, sl->count); - } - - /* Add the channels from the ic (from HAL) that are not present - * in the staScanTable, assuming they pass the sanity checks... */ - for (i = 0; i < ic->ic_nchans; i++) { - c = &ic->ic_channels[i]; - - /* XR is not supported on turbo channels */ - if (IEEE80211_IS_CHAN_TURBO(c) && vap->iv_flags & IEEE80211_F_XR) - continue; - - /* Dynamic channels are scanned in base mode */ - if (!as->as_required_mode && !IEEE80211_IS_CHAN_ST(c)) - continue; - - /* Use any 11g channel instead of 11b one. */ - if (vap->iv_des_mode == IEEE80211_MODE_AUTO && - IEEE80211_IS_CHAN_B(c) && - find11gchannel(ic, i, c->ic_freq)) - continue; - - /* Do not add channels already put into the scan list by the - * scan table - these have already been filtered by mode - * and for whether they are in the active channel list. */ - if (checktable(staScanTable, c)) - continue; - - /* Make sure the channel is active */ - if ((c == NULL) || isclr(ic->ic_chan_active, c->ic_ieee)) - continue; + ieee80211_scan_add_channels(ic, ss, vap->iv_des_mode); - /* Don't overrun */ - if (ss->ss_last >= IEEE80211_SCAN_MAX) - break; - - ss->ss_chans[ss->ss_last++] = c; - } ss->ss_next = 0; /* XXX tunables */ ss->ss_mindwell = msecs_to_jiffies(200); /* 200ms */ @@ -761,18 +534,6 @@ pick_channel(struct ieee80211_scan_state if (IEEE80211_IS_CHAN_RADAR(c->chan)) continue; - /* Do not select 802.11a ST if mode is specified and is not - * 802.11a ST */ - if (as->as_required_mode && - IEEE80211_IS_CHAN_STURBO(c->chan) && - (as->as_vap_desired_mode != IEEE80211_MODE_TURBO_STATIC_A)) - continue; - - /* Verify mode matches any fixed mode specified */ - if((c->chan->ic_flags & as->as_required_mode) != - as->as_required_mode) - continue; - if ((ic->ic_bsschan != NULL) && (ic->ic_bsschan != IEEE80211_CHAN_ANYC)) { --- a/net80211/ieee80211_scan.c +++ b/net80211/ieee80211_scan.c @@ -958,6 +958,80 @@ ieee80211_scan_flush(struct ieee80211com } } +static const u_int chanflags[] = { + 0, /* IEEE80211_MODE_AUTO */ + IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ + IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ + IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ + IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */ + IEEE80211_CHAN_A, /* IEEE80211_MODE_TURBO_A */ /* for turbo mode look for AP in normal channel */ + IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_TURBO_G */ + IEEE80211_CHAN_ST, /* IEEE80211_MODE_TURBO_STATIC_A */ +}; + +static struct ieee80211_channel * +find11gchannel(struct ieee80211com *ic, int i, int freq) +{ + struct ieee80211_channel *c; + int j; + + /* + * The normal ordering in the channel list is b channel + * immediately followed by g so optimize the search for + * this. We'll still do a full search just in case. + */ + for (j = i+1; j < ic->ic_nchans; j++) { + c = &ic->ic_channels[j]; + if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c)) + return c; + } + for (j = 0; j < i; j++) { + c = &ic->ic_channels[j]; + if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c)) + return c; + } + return NULL; +} + + +void +ieee80211_scan_add_channels(struct ieee80211com *ic, + struct ieee80211_scan_state *ss, + enum ieee80211_phymode mode) +{ + struct ieee80211_channel *c, *cg; + u_int modeflags; + int i; + + KASSERT(mode < ARRAY_SIZE(chanflags), ("Unexpected mode %u", mode)); + modeflags = chanflags[mode]; + for (i = 0; i < ic->ic_nchans; i++) { + c = &ic->ic_channels[i]; + if (c == NULL || isclr(ic->ic_chan_active, c->ic_ieee)) + continue; + if (c->ic_scanflags & IEEE80211_NOSCAN_SET) + continue; + if (modeflags && + ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) != + (modeflags & IEEE80211_CHAN_ALLTURBO))) + continue; + if (mode == IEEE80211_MODE_AUTO) { + /* + * XXX special-case 11b/g channels so we select + * the g channel if both are present. + */ + if (IEEE80211_IS_CHAN_B(c) && + (cg = find11gchannel(ic, i, c->ic_freq)) != NULL) + continue; + } + if (ss->ss_last >= IEEE80211_SCAN_MAX) + break; + ss->ss_chans[ss->ss_last++] = c; + } +} +EXPORT_SYMBOL(ieee80211_scan_add_channels); + + /* * Execute radar channel change. This is called when a radar/dfs * signal is detected. AP mode only. Return 1 on success, 0 on --- a/net80211/ieee80211_scan.h +++ b/net80211/ieee80211_scan.h @@ -219,4 +219,7 @@ void ieee80211_scanner_register(enum iee void ieee80211_scanner_unregister(enum ieee80211_opmode, const struct ieee80211_scanner *); void ieee80211_scanner_unregister_all(const struct ieee80211_scanner *); +void ieee80211_scan_add_channels(struct ieee80211com *ic, + struct ieee80211_scan_state *ss, + enum ieee80211_phymode mode); #endif /* _NET80211_IEEE80211_SCAN_H_ */ --- a/net80211/ieee80211_wireless.c +++ b/net80211/ieee80211_wireless.c @@ -3873,6 +3873,106 @@ ieee80211_ioctl_kickmac(struct net_devic return ieee80211_ioctl_setmlme(dev, info, w, (char *)&mlme); } +static inline void setflag(struct ieee80211_channel *c, int flag) +{ + if (flag) + c->ic_scanflags |= IEEE80211_NOSCAN_SET; + else + c->ic_scanflags &= ~IEEE80211_NOSCAN_SET; +} + +static void setscanflag(struct ieee80211com *ic, int min, int max, int set) +{ + int i; + + for (i = 0; i < ic->ic_nchans; i++) { + struct ieee80211_channel *c = &ic->ic_channels[i]; + + if (min == -1) { + if (!(c->ic_scanflags & IEEE80211_NOSCAN_DEFAULT)) + setflag(c, set); + } else if ((c->ic_freq >= min) && (c->ic_freq <= max)) { + setflag(c, set); + } + } +} + +static int +ieee80211_ioctl_setscanlist(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211vap *vap = dev->priv; + struct ieee80211com *ic = vap->iv_ic; + char *s, *next; + int val = 1; + + if (data->length <= 0) + return -EINVAL; + + s = kmalloc(data->length + 1, GFP_KERNEL); + if (!s) + return -ENOMEM; + + memset(s, 0, data->length + 1); + if (copy_from_user(s, data->pointer, data->length)) + return -EFAULT; + + s[data->length - 1] = '\0'; /* ensure null termination */ + + switch(*s) { + case '-': + val = 1; + break; + case '+': + val = 0; + break; + default: + goto error; + } + s++; + next = s; + do { + next = strchr(s, ','); + if (next) { + *next = 0; + next++; + } + if (!strcmp(s, "ALL")) { + setscanflag(ic, 0, 10000, val); + } else if (!strcmp(s, "REG")) { + setscanflag(ic, -1, -1, val); + } else { + int min, max; + char *n, *end = NULL; + + n = strchr(s, '-'); + if (n) { + *n = 0; + n++; + } + min = simple_strtoul(s, &end, 10); + if (end && *end) + goto error; + if (n) { + max = simple_strtoul(n, &end, 10); + if (end && *end) + goto error; + } else { + max = min; + } + setscanflag(ic, min, max, val); + } + s = next; + } while (next); + return 0; + +error: + if (s) + kfree(s); + return -EINVAL; +} + static int ieee80211_ioctl_addmac(struct net_device *dev, struct iw_request_info *info, void *w, char *extra) @@ -5656,6 +5756,8 @@ static const struct iw_priv_args ieee802 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "minrate"}, {IEEE80211_PARAM_MINRATE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"}, + { IEEE80211_IOCTL_SETSCANLIST, + IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"}, #ifdef ATH_REVERSE_ENGINEERING /* @@ -5753,6 +5855,7 @@ static const iw_handler ieee80211_priv_h set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac), set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac), set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac), + set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist), #ifdef ATH_REVERSE_ENGINEERING set_priv(IEEE80211_IOCTL_READREG, ieee80211_ioctl_readreg), set_priv(IEEE80211_IOCTL_WRITEREG, ieee80211_ioctl_writereg),