--- a/ath/if_ath.c +++ b/ath/if_ath.c @@ -148,7 +148,6 @@ static int ath_key_set(struct ieee80211v static void ath_key_update_begin(struct ieee80211vap *); static void ath_key_update_end(struct ieee80211vap *); static void ath_mode_init(struct net_device *); -static void ath_setslottime(struct ath_softc *); static void ath_updateslot(struct net_device *); static int ath_beaconq_setup(struct ath_softc *); static int ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *); @@ -240,7 +239,7 @@ static void ath_setup_stationkey(struct static void ath_setup_stationwepkey(struct ieee80211_node *); static void ath_setup_keycacheslot(struct ath_softc *, struct ieee80211_node *); static void ath_newassoc(struct ieee80211_node *, int); -static int ath_getchannels(struct net_device *, u_int, HAL_BOOL, HAL_BOOL); +static int ath_getchannels(struct net_device *); static void ath_led_event(struct ath_softc *, int); static void ath_update_txpow(struct ath_softc *); @@ -265,7 +264,6 @@ static int ath_change_mtu(struct net_dev static int ath_ioctl(struct net_device *, struct ifreq *, int); static int ath_rate_setup(struct net_device *, u_int); -static void ath_setup_subrates(struct net_device *); #ifdef ATH_SUPERG_XR static int ath_xr_rate_setup(struct net_device *); static void ath_grppoll_txq_setup(struct ath_softc *, int, int); @@ -387,8 +385,6 @@ static void ath_fetch_idle_time(struct a /* calibrate every 30 secs in steady state but check every second at first. */ static int ath_calinterval = ATH_SHORT_CALINTERVAL; -static int ath_countrycode = CTRY_DEFAULT; /* country code */ -static int ath_outdoor = AH_FALSE; /* enable outdoor use */ static int ath_xchanmode = AH_TRUE; /* enable extended channels */ static int ath_maxvaps = ATH_MAXVAPS_DEFAULT; /* set default maximum vaps */ static int bstuck_thresh = BSTUCK_THRESH; /* Stuck beacon count required for reset */ @@ -396,9 +392,7 @@ static char *autocreate = NULL; static char *ratectl = DEF_RATE_CTL; static int rfkill = 0; static int tpc = 1; -static int countrycode = -1; static int maxvaps = -1; -static int outdoor = -1; static int xchanmode = -1; #include "ath_wprobe.c" static int beacon_cal = 1; @@ -437,9 +431,7 @@ static struct notifier_block ath_event_b #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,52)) MODULE_PARM(beacon_cal, "i"); -MODULE_PARM(countrycode, "i"); MODULE_PARM(maxvaps, "i"); -MODULE_PARM(outdoor, "i"); MODULE_PARM(xchanmode, "i"); MODULE_PARM(rfkill, "i"); #ifdef ATH_CAP_TPC @@ -451,9 +443,7 @@ MODULE_PARM(ratectl, "s"); #else #include module_param(beacon_cal, int, 0600); -module_param(countrycode, int, 0600); module_param(maxvaps, int, 0600); -module_param(outdoor, int, 0600); module_param(xchanmode, int, 0600); module_param(rfkill, int, 0600); #ifdef ATH_CAP_TPC @@ -463,9 +453,7 @@ module_param(bstuck_thresh, int, 0600); module_param(autocreate, charp, 0600); module_param(ratectl, charp, 0600); #endif -MODULE_PARM_DESC(countrycode, "Override default country code"); MODULE_PARM_DESC(maxvaps, "Maximum VAPs"); -MODULE_PARM_DESC(outdoor, "Enable/disable outdoor use"); MODULE_PARM_DESC(xchanmode, "Enable/disable extended channel mode"); MODULE_PARM_DESC(rfkill, "Enable/disable RFKILL capability"); #ifdef ATH_CAP_TPC @@ -531,6 +519,50 @@ MODULE_PARM_DESC(ieee80211_debug, "Load- (bssid)[0] |= (((id) << 2) | 0x02); \ } while (0) +static inline int ath_chan2mode(struct ieee80211_channel *c) +{ + if (IEEE80211_IS_CHAN_HALF(c)) + return ATH_MODE_HALF; + else if (IEEE80211_IS_CHAN_QUARTER(c)) + return ATH_MODE_QUARTER; + else + return ieee80211_chan2mode(c); +} + +static inline int rate_hal2ieee(int dot11Rate, int f) +{ + int flag = dot11Rate & ~(IEEE80211_RATE_VAL); + dot11Rate &= IEEE80211_RATE_VAL; + + if (f == 4) { /* Quarter */ + if (dot11Rate == 4) + return 18 | flag; + } + return (dot11Rate * f) | flag; +} + +static inline int rate_factor(int mode) +{ + int f; + + /* + * NB: Fix up rates. HAL returns half or quarter dot11Rates, + * while the stack deals with full rates only + */ + switch(mode) { + case ATH_MODE_HALF: + f = 2; + break; + case ATH_MODE_QUARTER: + f = 4; + break; + default: + f = 1; + break; + } + return f; +} + /* Initialize ath_softc structure */ int @@ -647,14 +679,6 @@ ath_attach(u_int16_t devid, struct net_d for (i = 0; i < sc->sc_keymax; i++) ath_hal_keyreset(ah, i); - /* - * Collect the channel list using the default country - * code and including outdoor channels. The 802.11 layer - * is responsible for filtering this list based on settings - * like the phy mode. - */ - if (countrycode != -1) - ath_countrycode = countrycode; if (maxvaps != -1) { ath_maxvaps = maxvaps; if (ath_maxvaps < ATH_MAXVAPS_MIN) @@ -662,17 +686,14 @@ ath_attach(u_int16_t devid, struct net_d else if (ath_maxvaps > ATH_MAXVAPS_MAX) ath_maxvaps = ATH_MAXVAPS_MAX; } - if (outdoor != -1) - ath_outdoor = outdoor; if (xchanmode != -1) ath_xchanmode = xchanmode; - error = ath_getchannels(dev, ath_countrycode, - ath_outdoor, ath_xchanmode); + error = ath_getchannels(dev); if (error != 0) goto bad; - ic->ic_country_code = ath_countrycode; - ic->ic_country_outdoor = ath_outdoor; + ic->ic_country_code = CTRY_DEFAULT; + ic->ic_country_outdoor = 0; IPRINTF(sc, "Switching rfkill capability %s\n", rfkill ? "on" : "off"); @@ -686,9 +707,8 @@ ath_attach(u_int16_t devid, struct net_d ath_rate_setup(dev, IEEE80211_MODE_11G); ath_rate_setup(dev, IEEE80211_MODE_TURBO_A); ath_rate_setup(dev, IEEE80211_MODE_TURBO_G); - - /* Setup for half/quarter rates */ - ath_setup_subrates(dev); + ath_rate_setup(dev, ATH_MODE_HALF); + ath_rate_setup(dev, ATH_MODE_QUARTER); /* NB: setup here so ath_rate_update is happy */ ath_setcurmode(sc, IEEE80211_MODE_11A); @@ -908,10 +928,6 @@ ath_attach(u_int16_t devid, struct net_d IEEE80211_ATHC_COMP : 0); #endif -#ifdef ATH_SUPERG_DYNTURBO - ic->ic_ath_cap |= (ath_hal_turboagsupported(ah, ath_countrycode) ? - (IEEE80211_ATHC_TURBOP | IEEE80211_ATHC_AR) : 0); -#endif #ifdef ATH_SUPERG_XR ic->ic_ath_cap |= (ath_hal_xrsupported(ah) ? IEEE80211_ATHC_XR : 0); #endif @@ -4470,17 +4486,17 @@ ath_mode_init(struct net_device *dev) * Set the slot time based on the current setting. */ static void -ath_setslottime(struct ath_softc *sc) +ath_settiming(struct ath_softc *sc) { - struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; + u_int offset = getTimingOffset(sc); - if (sc->sc_slottimeconf > 0) /* manual override */ - ath_hal_setslottime(ah, sc->sc_slottimeconf); - else if (ic->ic_flags & IEEE80211_F_SHSLOT) - ath_hal_setslottime(ah, HAL_SLOT_TIME_9); - else - ath_hal_setslottime(ah, HAL_SLOT_TIME_20); + if (sc->sc_slottimeconf > 0) + ath_hal_setslottime(ah, offset + sc->sc_slottimeconf); + if (sc->sc_acktimeconf > 0) + ath_hal_setacktimeout(ah, 2 * offset + sc->sc_acktimeconf); + if (sc->sc_ctstimeconf > 0) + ath_hal_setctstimeout(ah, 2 * offset + sc->sc_ctstimeconf); sc->sc_updateslot = OK; } @@ -4502,7 +4518,7 @@ ath_updateslot(struct net_device *dev) if (ic->ic_opmode == IEEE80211_M_HOSTAP) sc->sc_updateslot = UPDATE; else if (dev->flags & IFF_RUNNING) - ath_setslottime(sc); + ath_settiming(sc); } #ifdef ATH_SUPERG_DYNTURBO @@ -5346,7 +5362,7 @@ ath_beacon_send(struct ath_softc *sc, in sc->sc_updateslot = COMMIT; /* commit next beacon */ sc->sc_slotupdate = slot; } else if ((sc->sc_updateslot == COMMIT) && (sc->sc_slotupdate == slot)) - ath_setslottime(sc); /* commit change to hardware */ + ath_settiming(sc); /* commit change to hardware */ if (bfaddr != 0) { /* @@ -7802,12 +7818,14 @@ ath_get_ivlen(struct ieee80211_key *k) * Get transmit rate index using rate in Kbps */ static __inline int -ath_tx_findindex(const HAL_RATE_TABLE *rt, int rate) +ath_tx_findindex(struct ath_softc *sc, const HAL_RATE_TABLE *rt, int rate) { unsigned int i, ndx = 0; + int f; + f = rate_factor(sc->sc_curmode); for (i = 0; i < rt->rateCount; i++) { - if (rt->info[i].rateKbps == rate) { + if ((rt->info[i].rateKbps * f) == rate) { ndx = i; break; } @@ -8100,7 +8118,7 @@ ath_tx_start(struct net_device *dev, str atype = HAL_PKT_TYPE_NORMAL; /* default */ if (ismcast) { - rix = ath_tx_findindex(rt, vap->iv_mcast_rate); + rix = ath_tx_findindex(sc, rt, vap->iv_mcast_rate); txrate = rt->info[rix].rateCode; if (shortPreamble) txrate |= rt->info[rix].shortPreamble; @@ -9067,7 +9085,7 @@ ath_chan_change(struct ath_softc *sc, st struct net_device *dev = sc->sc_dev; enum ieee80211_phymode mode; - mode = ieee80211_chan2mode(chan); + mode = ath_chan2mode(chan); ath_rate_setup(dev, mode); ath_setcurmode(sc, mode); @@ -10124,8 +10142,7 @@ ath_newassoc(struct ieee80211_node *ni, } static int -ath_getchannels(struct net_device *dev, u_int cc, - HAL_BOOL outdoor, HAL_BOOL xchanmode) +ath_getchannels(struct net_device *dev) { struct ath_softc *sc = dev->priv; struct ieee80211com *ic = &sc->sc_ic; @@ -10139,17 +10156,31 @@ ath_getchannels(struct net_device *dev, EPRINTF(sc, "Insufficient memory for channel table!\n"); return -ENOMEM; } + +restart: if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, ic->ic_regclassids, IEEE80211_REGCLASSIDS_MAX, &ic->ic_nregclass, - cc, HAL_MODE_ALL, outdoor, xchanmode)) { + ic->ic_country_code, HAL_MODE_ALL, ic->ic_country_outdoor, ath_xchanmode)) { u_int32_t rd; ath_hal_getregdomain(ah, &rd); EPRINTF(sc, "Unable to collect channel list from HAL; " - "regdomain likely %u country code %u\n", rd, cc); + "regdomain likely %u country code %u\n", rd, ic->ic_country_code); + if ((ic->ic_country_code != CTRY_DEFAULT) || + (ic->ic_country_outdoor != 0)) { + EPRINTF(sc, "Reverting to defaults\n"); + ic->ic_country_code = CTRY_DEFAULT; + ic->ic_country_outdoor = 0; + goto restart; + } kfree(chans); return -EINVAL; } +#ifdef ATH_SUPERG_DYNTURBO + ic->ic_ath_cap &= ~(IEEE80211_ATHC_TURBOP | IEEE80211_ATHC_AR); + ic->ic_ath_cap |= (ath_hal_turboagsupported(ah, ic->ic_country_code) ? + (IEEE80211_ATHC_TURBOP | IEEE80211_ATHC_AR) : 0); +#endif /* * Convert HAL channels to ieee80211 ones. */ @@ -10395,7 +10426,7 @@ ath_xr_rate_setup(struct net_device *dev struct ieee80211com *ic = &sc->sc_ic; const HAL_RATE_TABLE *rt; struct ieee80211_rateset *rs; - unsigned int i, maxrates; + unsigned int i, j, maxrates; sc->sc_xr_rates = ath_hal_getratetable(ah, HAL_MODE_XR); rt = sc->sc_xr_rates; if (rt == NULL) @@ -10408,57 +10439,16 @@ ath_xr_rate_setup(struct net_device *dev } else maxrates = rt->rateCount; rs = &ic->ic_sup_xr_rates; - for (i = 0; i < maxrates; i++) - rs->rs_rates[i] = rt->info[i].dot11Rate; - rs->rs_nrates = maxrates; + for (j = 0, i = 0; i < maxrates; i++) { + if (!rt->info[i].valid) + continue; + rs->rs_rates[j++] = rt->info[i].dot11Rate; + } + rs->rs_nrates = j; return 1; } #endif -/* Setup half/quarter rate table support */ -static void -ath_setup_subrates(struct net_device *dev) -{ - struct ath_softc *sc = dev->priv; - struct ath_hal *ah = sc->sc_ah; - struct ieee80211com *ic = &sc->sc_ic; - const HAL_RATE_TABLE *rt; - struct ieee80211_rateset *rs; - unsigned int i, maxrates; - - sc->sc_half_rates = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE); - rt = sc->sc_half_rates; - if (rt != NULL) { - if (rt->rateCount > IEEE80211_RATE_MAXSIZE) { - DPRINTF(sc, ATH_DEBUG_ANY, - "The rate table is too small (%u > %u)\n", - rt->rateCount, IEEE80211_RATE_MAXSIZE); - maxrates = IEEE80211_RATE_MAXSIZE; - } else - maxrates = rt->rateCount; - rs = &ic->ic_sup_half_rates; - for (i = 0; i < maxrates; i++) - rs->rs_rates[i] = rt->info[i].dot11Rate; - rs->rs_nrates = maxrates; - } - - sc->sc_quarter_rates = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE); - rt = sc->sc_quarter_rates; - if (rt != NULL) { - if (rt->rateCount > IEEE80211_RATE_MAXSIZE) { - DPRINTF(sc, ATH_DEBUG_ANY, - "The rate table is too small (%u > %u)\n", - rt->rateCount, IEEE80211_RATE_MAXSIZE); - maxrates = IEEE80211_RATE_MAXSIZE; - } else - maxrates = rt->rateCount; - rs = &ic->ic_sup_quarter_rates; - for (i = 0; i < maxrates; i++) - rs->rs_rates[i] = rt->info[i].dot11Rate; - rs->rs_nrates = maxrates; - } -} - static int ath_rate_setup(struct net_device *dev, u_int mode) { @@ -10467,7 +10457,7 @@ ath_rate_setup(struct net_device *dev, u struct ieee80211com *ic = &sc->sc_ic; const HAL_RATE_TABLE *rt; struct ieee80211_rateset *rs; - unsigned int i, maxrates; + unsigned int i, j, maxrates, f; switch (mode) { case IEEE80211_MODE_11A: @@ -10485,6 +10475,12 @@ ath_rate_setup(struct net_device *dev, u case IEEE80211_MODE_TURBO_G: sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_108G); break; + case ATH_MODE_HALF: + sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11A_HALF_RATE); + break; + case ATH_MODE_QUARTER: + sc->sc_rates[mode] = ath_hal_getratetable(ah, HAL_MODE_11A_QUARTER_RATE); + break; default: DPRINTF(sc, ATH_DEBUG_ANY, "Invalid mode %u\n", mode); return 0; @@ -10499,10 +10495,16 @@ ath_rate_setup(struct net_device *dev, u maxrates = IEEE80211_RATE_MAXSIZE; } else maxrates = rt->rateCount; + + /* NB: quarter/half rate channels hijack the 11A rateset */ + if (mode >= IEEE80211_MODE_MAX) + return 1; + rs = &ic->ic_sup_rates[mode]; for (i = 0; i < maxrates; i++) rs->rs_rates[i] = rt->info[i].dot11Rate; rs->rs_nrates = maxrates; + return 1; } @@ -10531,13 +10533,18 @@ ath_setcurmode(struct ath_softc *sc, enu { 0, 500, 130 }, }; const HAL_RATE_TABLE *rt; - unsigned int i, j; + unsigned int i, j, f; + /* + * NB: Fix up rixmap. HAL returns half or quarter dot11Rates, + * while the stack deals with full rates only + */ + f = rate_factor(mode); memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); rt = sc->sc_rates[mode]; KASSERT(rt != NULL, ("no h/w rate set for phy mode %u", mode)); for (i = 0; i < rt->rateCount; i++) - sc->sc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; + sc->sc_rixmap[rate_hal2ieee(rt->info[i].dot11Rate, f) & IEEE80211_RATE_VAL] = i; memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); for (i = 0; i < 32; i++) { u_int8_t ix = rt->rateCodeToIndex[i]; @@ -10547,7 +10554,7 @@ ath_setcurmode(struct ath_softc *sc, enu continue; } sc->sc_hwmap[i].ieeerate = - rt->info[ix].dot11Rate & IEEE80211_RATE_VAL; + rate_hal2ieee(rt->info[ix].dot11Rate, f) & IEEE80211_RATE_VAL; if (rt->info[ix].shortPreamble || rt->info[ix].phy == IEEE80211_T_OFDM) sc->sc_hwmap[i].flags |= IEEE80211_RADIOTAP_F_SHORTPRE; @@ -10948,9 +10955,106 @@ enum { ATH_MAXVAPS = 26, ATH_INTMIT = 27, ATH_NOISE_IMMUNITY = 28, - ATH_OFDM_WEAK_DET = 29 + ATH_OFDM_WEAK_DET = 29, + ATH_CHANBW = 30, + ATH_OUTDOOR = 31, }; +/* + * perform the channel related sysctl, reload the channel list + * and try to stay on the current frequency + */ +static int ath_sysctl_setchanparam(struct ath_softc *sc, unsigned long ctl, u_int val) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct ath_hal *ah = sc->sc_ah; + struct ieee80211_channel *c = NULL; + struct ieee80211vap *vap; + u_int16_t freq = 0; + struct ifreq ifr; + + if (ic->ic_curchan != IEEE80211_CHAN_ANYC) + freq = ic->ic_curchan->ic_freq; + + switch(ctl) { + case ATH_COUNTRYCODE: + ic->ic_country_code = val; + break; + case ATH_OUTDOOR: + ic->ic_country_outdoor = val; + break; + case ATH_CHANBW: + switch(val) { + case 0: + case 5: + case 10: + case 20: + case 40: + if (ath_hal_setcapability(ah, HAL_CAP_CHANBW, 1, val, NULL) == AH_TRUE) { + sc->sc_chanbw = val; + break; + } + default: + return -EINVAL; + } + break; + } + + if (ic->ic_curchan != IEEE80211_CHAN_ANYC) + freq = ic->ic_curchan->ic_freq; + + /* clear out any old state */ + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + vap->iv_des_mode = IEEE80211_MODE_AUTO; + vap->iv_des_chan = IEEE80211_CHAN_ANYC; + } + ieee80211_scan_flush(ic); + + IEEE80211_LOCK_IRQ(ic); + ath_getchannels(sc->sc_dev); + ieee80211_update_channels(ic, 0); + if (freq) + c = ieee80211_find_channel(ic, freq, IEEE80211_MODE_AUTO); + if (!c) + c = &ic->ic_channels[0]; + ic->ic_curchan = c; + ic->ic_bsschan = c; + ic->ic_curmode = IEEE80211_MODE_AUTO; + IEEE80211_UNLOCK_IRQ(ic); + + if (!(sc->sc_dev->flags & IFF_RUNNING)) { + ic->ic_bsschan = IEEE80211_CHAN_ANYC; + return 0; + } + +#ifndef ifr_media +#define ifr_media ifr_ifru.ifru_ivalue +#endif + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_media = ic->ic_media.ifm_cur->ifm_media & ~IFM_MMASK; + ifr.ifr_media |= IFM_MAKEMODE(IEEE80211_MODE_AUTO); + ifmedia_ioctl(ic->ic_dev, &ifr, &ic->ic_media, SIOCSIFMEDIA); + + /* apply the channel to the hw */ + ath_set_channel(ic); + + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct net_device *dev = vap->iv_dev; + + /* reactivate all active vaps */ + vap->iv_state = IEEE80211_S_SCAN; + if ((vap->iv_opmode == IEEE80211_M_HOSTAP) || + (vap->iv_opmode == IEEE80211_M_MONITOR) || + (vap->iv_opmode == IEEE80211_M_WDS)) + ieee80211_new_state(vap, IEEE80211_S_RUN, 0); + else + ieee80211_new_state(vap, IEEE80211_S_INIT, -1); + } + + return 0; +} + + static int ath_sysctl_set_intmit(struct ath_softc *sc, long ctl, u_int val) { @@ -11029,6 +11133,7 @@ static int ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl, write, filp, buffer, lenp, ppos) { struct ath_softc *sc = ctl->extra1; + struct ieee80211com *ic = &sc->sc_ic; struct ath_hal *ah = sc->sc_ah; u_int val; u_int tab_3_val[3]; @@ -11052,25 +11157,34 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl lenp, ppos); if (ret == 0) { switch ((long)ctl->extra2) { + case ATH_REGDOMAIN: + ath_hal_setregdomain(ah, val); + break; + case ATH_OUTDOOR: + case ATH_COUNTRYCODE: + case ATH_CHANBW: + ret = ath_sysctl_setchanparam(sc, (long) ctl->extra2, val); + break; case ATH_SLOTTIME: - if (val > 0) { - if (!ath_hal_setslottime(ah, val)) - ret = -EINVAL; - else - sc->sc_slottimeconf = val; - } else { - /* disable manual override */ + if (val > 0) + sc->sc_slottimeconf = val; + else sc->sc_slottimeconf = 0; - ath_setslottime(sc); - } + ath_settiming(sc); break; case ATH_ACKTIMEOUT: - if (!ath_hal_setacktimeout(ah, val)) - ret = -EINVAL; + if (val > 0) + sc->sc_acktimeconf = val; + else + sc->sc_acktimeconf = 0; + ath_settiming(sc); break; case ATH_CTSTIMEOUT: - if (!ath_hal_setctstimeout(ah, val)) - ret = -EINVAL; + if (val > 0) + sc->sc_ctstimeconf = val; + else + sc->sc_ctstimeconf = 0; + ath_settiming(sc); break; case ATH_SOFTLED: if (val != sc->sc_softled) { @@ -11223,6 +11337,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl } } else { switch ((long)ctl->extra2) { + case ATH_CHANBW: + val = sc->sc_chanbw ?: 20; + break; case ATH_SLOTTIME: val = ath_hal_getslottime(ah); break; @@ -11241,6 +11358,9 @@ ATH_SYSCTL_DECL(ath_sysctl_halparam, ctl case ATH_COUNTRYCODE: ath_hal_getcountrycode(ah, &val); break; + case ATH_OUTDOOR: + val = ic->ic_country_outdoor; + break; case ATH_MAXVAPS: val = ath_maxvaps; break; @@ -11354,11 +11474,17 @@ static const ctl_table ath_sysctl_templa }, { .ctl_name = CTL_AUTO, .procname = "countrycode", - .mode = 0444, + .mode = 0644, .proc_handler = ath_sysctl_halparam, .extra2 = (void *)ATH_COUNTRYCODE, }, { .ctl_name = CTL_AUTO, + .procname = "outdoor", + .mode = 0644, + .proc_handler = ath_sysctl_halparam, + .extra2 = (void *)ATH_OUTDOOR, + }, + { .ctl_name = CTL_AUTO, .procname = "maxvaps", .mode = 0444, .proc_handler = ath_sysctl_halparam, @@ -11366,7 +11492,7 @@ static const ctl_table ath_sysctl_templa }, { .ctl_name = CTL_AUTO, .procname = "regdomain", - .mode = 0444, + .mode = 0644, .proc_handler = ath_sysctl_halparam, .extra2 = (void *)ATH_REGDOMAIN, }, @@ -11429,6 +11555,12 @@ static const ctl_table ath_sysctl_templa .extra2 = (void *)ATH_ACKRATE, }, { .ctl_name = CTL_AUTO, + .procname = "channelbw", + .mode = 0644, + .proc_handler = ath_sysctl_halparam, + .extra2 = (void *)ATH_CHANBW, + }, + { .ctl_name = CTL_AUTO, .procname = "rp", .mode = 0200, .proc_handler = ath_sysctl_halparam, @@ -11669,13 +11801,6 @@ static ctl_table ath_static_sysctls[] = }, #endif { .ctl_name = CTL_AUTO, - .procname = "countrycode", - .mode = 0444, - .data = &ath_countrycode, - .maxlen = sizeof(ath_countrycode), - .proc_handler = proc_dointvec - }, - { .ctl_name = CTL_AUTO, .procname = "maxvaps", .mode = 0444, .data = &ath_maxvaps, @@ -11683,13 +11808,6 @@ static ctl_table ath_static_sysctls[] = .proc_handler = proc_dointvec }, { .ctl_name = CTL_AUTO, - .procname = "outdoor", - .mode = 0444, - .data = &ath_outdoor, - .maxlen = sizeof(ath_outdoor), - .proc_handler = proc_dointvec - }, - { .ctl_name = CTL_AUTO, .procname = "xchanmode", .mode = 0444, .data = &ath_xchanmode, --- a/ath/if_athvar.h +++ b/ath/if_athvar.h @@ -688,17 +688,18 @@ struct ath_softc { int8_t sc_ofdm_weak_det; /* OFDM weak frames detection, -1 == auto */ /* rate tables */ - const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX]; +#define ATH_MODE_HALF (IEEE80211_MODE_MAX) +#define ATH_MODE_QUARTER (IEEE80211_MODE_MAX + 1) + const HAL_RATE_TABLE *sc_rates[IEEE80211_MODE_MAX + 2]; const HAL_RATE_TABLE *sc_currates; /* current rate table */ const HAL_RATE_TABLE *sc_xr_rates; /* XR rate table */ - const HAL_RATE_TABLE *sc_half_rates; /* half rate table */ - const HAL_RATE_TABLE *sc_quarter_rates; /* quarter rate table */ HAL_OPMODE sc_opmode; /* current hal operating mode */ enum ieee80211_phymode sc_curmode; /* current phy mode */ u_int sc_poweroffset; /* hardware power offset */ u_int16_t sc_curtxpow; /* current tx power limit */ u_int16_t sc_curaid; /* current association id */ HAL_CHANNEL sc_curchan; /* current h/w channel */ + u_int8_t sc_chanbw; /* channel bandwidth */ u_int8_t sc_curbssid[IEEE80211_ADDR_LEN]; u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */ struct { @@ -809,6 +810,8 @@ struct ath_softc { u_int32_t sc_dturbo_bw_turbo; /* bandwidth threshold */ #endif u_int sc_slottimeconf; /* manual override for slottime */ + u_int sc_acktimeconf; /* manual override for acktime */ + u_int sc_ctstimeconf; /* manual override for ctstime */ struct timer_list sc_dfs_excl_timer; /* mark expiration timer task */ struct timer_list sc_dfs_cac_timer; /* dfs wait timer */ @@ -827,6 +830,7 @@ struct ath_softc { int sc_rp_num; int sc_rp_min; HAL_BOOL (*sc_rp_analyse)(struct ath_softc *sc); + struct ATH_TQ_STRUCT sc_refresh_tq; struct ATH_TQ_STRUCT sc_rp_tq; int sc_rp_ignored; /* if set, we ignored all @@ -942,6 +946,48 @@ int ar_device(int devid); DEV_NAME(_v->iv_ic->ic_dev)) void ath_radar_detected(struct ath_softc *sc, const char* message); +static inline u_int getTimingOffset(struct ath_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + u_int usec = 9; + if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan)) { + usec = 20; + if (ic->ic_flags & IEEE80211_F_SHSLOT) + usec = 9; + } else if (IEEE80211_IS_CHAN_A(ic->ic_curchan)) + usec = 9; + + if (IEEE80211_IS_CHAN_TURBO(ic->ic_curchan)) + usec = 6; + + if (IEEE80211_IS_CHAN_HALF(ic->ic_curchan)) + usec = 13; + else if (IEEE80211_IS_CHAN_QUARTER(ic->ic_curchan)) + usec = 21; + return usec; +} + +static inline void ath_get_timings(struct ath_softc *sc, u_int *t_slot, u_int *t_sifs, u_int *t_difs) +{ + struct ieee80211_channel *c = sc->sc_ic.ic_curchan; + + *t_slot = getTimingOffset(sc) + sc->sc_slottimeconf; + + if (IEEE80211_IS_CHAN_HALF(c)) { + *t_sifs = 32; + *t_difs = 56; + } else if (IEEE80211_IS_CHAN_QUARTER(c)) { + *t_sifs = 64; + *t_difs = 112; + } else if (IEEE80211_IS_CHAN_TURBO(c)) { + *t_sifs = 8; + *t_difs = 28; + } else { + *t_sifs = 16; + *t_difs = 28; + } +} + struct ath_hw_detect { const char *vendor_name; --- a/tools/athctrl.c +++ b/tools/athctrl.c @@ -118,7 +118,7 @@ CMD(athctrl)(int argc, char *argv[]) } if (distance >= 0) { - int slottime = 9 + (distance / 300) + ((distance % 300) ? 1 : 0); + int slottime = (distance / 300) + ((distance % 300) ? 1 : 0); int acktimeout = slottime * 2 + 3; int ctstimeout = slottime * 2 + 3; --- a/net80211/ieee80211.c +++ b/net80211/ieee80211.c @@ -243,34 +243,17 @@ static const struct country_code_to_str {CTRY_ZIMBABWE, "ZW"} }; -int -ieee80211_ifattach(struct ieee80211com *ic) +void ieee80211_update_channels(struct ieee80211com *ic, int init) { - struct net_device *dev = ic->ic_dev; struct ieee80211_channel *c; + struct ieee80211vap *vap; struct ifmediareq imr; + int ext = 0; int i; - _MOD_INC_USE(THIS_MODULE, return -ENODEV); - - /* - * Pick an initial operating mode until we have a vap - * created to lock it down correctly. This is only - * drivers have something defined for configuring the - * hardware at startup. - */ - ic->ic_opmode = IEEE80211_M_STA; /* everyone supports this */ - - /* - * Fill in 802.11 available channel set, mark - * all available channels as active, and pick - * a default channel if not already specified. - */ - KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX, - ("invalid number of channels specified: %u", ic->ic_nchans)); memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); - ic->ic_modecaps |= 1 << IEEE80211_MODE_AUTO; ic->ic_max_txpower = IEEE80211_TXPOWER_MIN; + ic->ic_modecaps = 1 << IEEE80211_MODE_AUTO; for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; @@ -298,6 +281,8 @@ ieee80211_ifattach(struct ieee80211com * ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_A; if (IEEE80211_IS_CHAN_108G(c)) ic->ic_modecaps |= 1 << IEEE80211_MODE_TURBO_G; + if (IEEE80211_IS_CHAN_HALF(c) || IEEE80211_IS_CHAN_QUARTER(c)) + ext = 1; } /* Initialize candidate channels to all available */ memcpy(ic->ic_chan_active, ic->ic_chan_avail, @@ -311,11 +296,59 @@ ieee80211_ifattach(struct ieee80211com * * When 11g is supported, force the rate set to * include basic rates suitable for a mixed b/g bss. */ - if (ic->ic_modecaps & (1 << IEEE80211_MODE_11G)) + if ((ic->ic_modecaps & (1 << IEEE80211_MODE_11G)) && !ext) ieee80211_set11gbasicrates( &ic->ic_sup_rates[IEEE80211_MODE_11G], IEEE80211_MODE_11G); + if (init) + return; + + ifmedia_removeall(&ic->ic_media); + ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, NULL, NULL); + ieee80211com_media_status(ic->ic_dev, &imr); + ifmedia_set(&ic->ic_media, imr.ifm_active); + + TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { + struct ieee80211vap *avp; + TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) { + (void) ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, NULL, NULL); + ieee80211_media_status(vap->iv_dev, &imr); + ifmedia_set(&vap->iv_media, imr.ifm_active); + } + (void) ieee80211_media_setup(ic, &vap->iv_media, vap->iv_caps, NULL, NULL); + ieee80211_media_status(vap->iv_dev, &imr); + ifmedia_set(&vap->iv_media, imr.ifm_active); + } +} +EXPORT_SYMBOL(ieee80211_update_channels); + +int +ieee80211_ifattach(struct ieee80211com *ic) +{ + struct net_device *dev = ic->ic_dev; + struct ieee80211_channel *c; + struct ifmediareq imr; + + _MOD_INC_USE(THIS_MODULE, return -ENODEV); + + /* + * Pick an initial operating mode until we have a vap + * created to lock it down correctly. This is only + * drivers have something defined for configuring the + * hardware at startup. + */ + ic->ic_opmode = IEEE80211_M_STA; /* everyone supports this */ + + /* + * Fill in 802.11 available channel set, mark + * all available channels as active, and pick + * a default channel if not already specified. + */ + KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX, + ("invalid number of channels specified: %u", ic->ic_nchans)); + ieee80211_update_channels(ic, 1); + /* Setup initial channel settings */ ic->ic_bsschan = IEEE80211_CHAN_ANYC; /* Arbitrarily pick the first channel */ @@ -327,6 +360,7 @@ ieee80211_ifattach(struct ieee80211com * /* Enable WME by default, if we're capable. */ if (ic->ic_caps & IEEE80211_C_WME) ic->ic_flags |= IEEE80211_F_WME; + (void) ieee80211_setmode(ic, ic->ic_curmode); /* Store default beacon interval, as nec. */ @@ -763,7 +797,8 @@ ieee80211_media_setup(struct ieee80211co struct ieee80211_rateset allrates; /* Fill in media characteristics. */ - ifmedia_init(media, 0, media_change, media_stat); + if (media_change || media_stat) + ifmedia_init(media, 0, media_change, media_stat); maxrate = 0; memset(&allrates, 0, sizeof(allrates)); @@ -793,7 +828,7 @@ ieee80211_media_setup(struct ieee80211co ADD(media, IFM_AUTO, mopt | IFM_IEEE80211_WDS); if (mode == IEEE80211_MODE_AUTO) continue; - rs = &ic->ic_sup_rates[mode]; + rs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; @@ -1207,7 +1242,7 @@ ieee80211_announce(struct ieee80211com * if ((ic->ic_modecaps & (1 << mode)) == 0) continue; if_printf(dev, "%s rates: ", ieee80211_phymode_name[mode]); - rs = &ic->ic_sup_rates[mode]; + rs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)]; for (i = 0; i < rs->rs_nrates; i++) { rate = rs->rs_rates[i]; mword = ieee80211_rate2media(ic, rate, mode); @@ -1417,7 +1452,7 @@ ieee80211com_media_change(struct net_dev * now so drivers have a consistent state. */ KASSERT(vap->iv_bss != NULL, ("no bss node")); - vap->iv_bss->ni_rates = ic->ic_sup_rates[newphymode]; + vap->iv_bss->ni_rates = ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, newphymode)]; } error = -ENETRESET; } @@ -1435,7 +1470,7 @@ findrate(struct ieee80211com *ic, enum i { #define IEEERATE(_ic,_m,_i) \ ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) - int i, nrates = ic->ic_sup_rates[mode].rs_nrates; + int i, nrates = ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)].rs_nrates; for (i = 0; i < nrates; i++) if (IEEERATE(ic, mode, i) == rate) return i; @@ -1877,11 +1912,6 @@ ieee80211_build_countryie(struct ieee802 if (ieee80211_chan2mode(c) != curmode_noturbo) continue; - /* Skip half/quarter rate channels */ - if (IEEE80211_IS_CHAN_HALF(c) || - IEEE80211_IS_CHAN_QUARTER(c)) - continue; - if (*cur_runlen == 0) { (*cur_runlen)++; *cur_pow = c->ic_maxregpower; @@ -1915,7 +1945,7 @@ void ieee80211_build_sc_ie(struct ieee80211com *ic) { struct ieee80211_ie_sc *ie = &ic->ic_sc_ie; - int i, j; + int i, j, k; struct ieee80211_channel *c; u_int8_t prevchan; --- a/net80211/ieee80211_var.h +++ b/net80211/ieee80211_var.h @@ -336,8 +336,6 @@ struct ieee80211com { u_int8_t ic_nopened; /* VAPs been opened */ struct ieee80211_rateset ic_sup_rates[IEEE80211_MODE_MAX]; struct ieee80211_rateset ic_sup_xr_rates; - struct ieee80211_rateset ic_sup_half_rates; - struct ieee80211_rateset ic_sup_quarter_rates; u_int16_t ic_modecaps; /* set of mode capabilities */ u_int16_t ic_curmode; /* current mode */ u_int16_t ic_lintval; /* beacon interval */ @@ -714,6 +712,7 @@ MALLOC_DECLARE(M_80211_VAP); int ieee80211_ifattach(struct ieee80211com *); void ieee80211_ifdetach(struct ieee80211com *); +void ieee80211_update_channels(struct ieee80211com *ic, int); int ieee80211_vap_setup(struct ieee80211com *, struct net_device *, const char *, int, int, struct ieee80211vap *); int ieee80211_vap_attach(struct ieee80211vap *, ifm_change_cb_t, ifm_stat_cb_t); @@ -793,6 +792,23 @@ ieee80211_anyhdrspace(struct ieee80211co return size; } +static __inline int +ieee80211_chan2ratemode(struct ieee80211_channel *c, int mode) +{ + if (mode == -1) + mode = ieee80211_chan2mode(c); + + /* + * Use 11a rateset for half/quarter to restrict things + * to pure OFDM + */ + if (IEEE80211_IS_CHAN_HALF(c) || + IEEE80211_IS_CHAN_QUARTER(c)) + return IEEE80211_MODE_11A; + + return mode; +} + /* Macros to print MAC address used in 802.11 headers */ #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" --- a/net80211/ieee80211_node.c +++ b/net80211/ieee80211_node.c @@ -287,7 +287,7 @@ ieee80211_node_set_chan(struct ieee80211 ni->ni_rates = ic->ic_sup_xr_rates; else #endif - ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(chan)]; + ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2ratemode(chan, -1)]; } static __inline void @@ -387,6 +387,8 @@ ieee80211_create_ibss(struct ieee80211va ic->ic_bsschan = chan; ieee80211_node_set_chan(ic, ni); ic->ic_curmode = ieee80211_chan2mode(chan); + ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2ratemode(chan, -1)]; + spin_lock_irqsave(&channel_lock, flags); ieee80211_scan_set_bss_channel(ic, ic->ic_bsschan); spin_unlock_irqrestore(&channel_lock, flags); @@ -394,14 +396,8 @@ ieee80211_create_ibss(struct ieee80211va /* Update country ie information */ ieee80211_build_countryie(ic); - if (IEEE80211_IS_CHAN_HALF(chan)) { - ni->ni_rates = ic->ic_sup_half_rates; - } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { - ni->ni_rates = ic->ic_sup_quarter_rates; - } - - if ((vap->iv_flags & IEEE80211_F_PUREG) && - IEEE80211_IS_CHAN_ANYG(chan)) { + if ((ieee80211_chan2ratemode(chan, -1) != IEEE80211_MODE_11A) && + IEEE80211_IS_CHAN_ANYG(chan) && (vap->iv_flags & IEEE80211_F_PUREG)) { ieee80211_setpuregbasicrates(&ni->ni_rates); } --- a/net80211/ieee80211_scan_sta.c +++ b/net80211/ieee80211_scan_sta.c @@ -490,12 +490,7 @@ check_rate(struct ieee80211vap *vap, con okrate = badrate = fixedrate = 0; - if (IEEE80211_IS_CHAN_HALF(se->se_chan)) - srs = &ic->ic_sup_half_rates; - else if (IEEE80211_IS_CHAN_QUARTER(se->se_chan)) - srs = &ic->ic_sup_quarter_rates; - else - srs = &ic->ic_sup_rates[ieee80211_chan2mode(se->se_chan)]; + srs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, -1)]; nrs = se->se_rates[1]; rs = se->se_rates + 2; fixedrate = IEEE80211_FIXED_RATE_NONE; --- a/net80211/ieee80211_output.c +++ b/net80211/ieee80211_output.c @@ -1676,8 +1676,8 @@ ieee80211_send_probereq(struct ieee80211 frm = ieee80211_add_ssid(frm, ssid, ssidlen); mode = ieee80211_chan2mode(ic->ic_curchan); - frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]); - frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]); + frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)]); + frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, mode)]); if (optie != NULL) { memcpy(frm, optie, optielen); --- a/net80211/ieee80211_proto.c +++ b/net80211/ieee80211_proto.c @@ -404,7 +404,7 @@ ieee80211_fix_rate(struct ieee80211_node error = 0; okrate = badrate = fixedrate = 0; - srs = &ic->ic_sup_rates[ieee80211_chan2mode(ni->ni_chan)]; + srs = &ic->ic_sup_rates[ieee80211_chan2ratemode(ic->ic_curchan, -1)]; nrs = &ni->ni_rates; fixedrate = IEEE80211_FIXED_RATE_NONE; for (i = 0; i < nrs->rs_nrates;) { @@ -1407,6 +1407,7 @@ ieee80211_new_state(struct ieee80211vap IEEE80211_VAPS_UNLOCK_IRQ(ic); return rc; } +EXPORT_SYMBOL(ieee80211_new_state); static int __ieee80211_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) --- a/ath_rate/minstrel/minstrel.c +++ b/ath_rate/minstrel/minstrel.c @@ -195,31 +195,7 @@ calc_usecs_unicast_packet(struct ath_sof return 0; } - /* XXX: Getting MAC/PHY level timings should be fixed for turbo - * rates, and there is probably a way to get this from the - * HAL... */ - switch (rt->info[rix].phy) { - case IEEE80211_T_OFDM: -#if 0 - t_slot = 9; - t_sifs = 16; - t_difs = 28; - /* fall through */ -#endif - case IEEE80211_T_TURBO: - t_slot = 9; - t_sifs = 8; - t_difs = 28; - break; - case IEEE80211_T_DS: - /* Fall through to default */ - default: - /* pg. 205 ieee.802.11.pdf */ - t_slot = 20; - t_difs = 50; - t_sifs = 10; - } - + ath_get_timings(sc, &t_slot, &t_sifs, &t_difs); if ((ic->ic_flags & IEEE80211_F_USEPROT) && (rt->info[rix].phy == IEEE80211_T_OFDM)) { if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) --- a/ath_rate/sample/sample.c +++ b/ath_rate/sample/sample.c @@ -172,26 +172,7 @@ calc_usecs_unicast_packet(struct ath_sof * rates, and there is probably a way to get this from the * hal... */ - switch (rt->info[rix].phy) { - case IEEE80211_T_OFDM: - t_slot = 9; - t_sifs = 16; - t_difs = 28; - /* fall through */ - case IEEE80211_T_TURBO: - t_slot = 9; - t_sifs = 8; - t_difs = 28; - break; - case IEEE80211_T_DS: - /* fall through to default */ - default: - /* pg 205 ieee.802.11.pdf */ - t_slot = 20; - t_difs = 50; - t_sifs = 10; - } - + ath_get_timings(sc, &t_slot, &t_sifs, &t_difs); rts = cts = 0; if ((ic->ic_flags & IEEE80211_F_USEPROT) && --- a/net80211/ieee80211_wireless.c +++ b/net80211/ieee80211_wireless.c @@ -2142,7 +2142,7 @@ ieee80211_ioctl_setmode(struct net_devic vap->iv_des_mode = mode; if (IS_UP_AUTO(vap)) - ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); + ieee80211_init(vap->iv_dev, 0); retv = 0; } @@ -4090,46 +4090,60 @@ ieee80211_ioctl_getchanlist(struct net_d return 0; } +static int alreadyListed(struct ieee80211req_chaninfo *chans, u_int16_t mhz) +{ + int i; + for (i = 0; i < chans->ic_nchans; i++) { + if (chans->ic_chans[i].ic_freq == mhz) + return 1; + } + return 0; +} + static int ieee80211_ioctl_getchaninfo(struct net_device *dev, - struct iw_request_info *info, void *w, char *extra) + struct iw_request_info *info, void *w, char *extra) { struct ieee80211vap *vap = dev->priv; struct ieee80211com *ic = vap->iv_ic; - struct ieee80211req_chaninfo chans; + struct ieee80211req_chaninfo *chans = + (struct ieee80211req_chaninfo *)extra; + u_int8_t reported[IEEE80211_CHAN_BYTES]; /* XXX stack usage? */ int i; - memset(&chans, 0, sizeof(chans)); - memset(&reported, 0, sizeof(reported)); + memset(chans, 0, sizeof(*chans)); + memset(reported, 0, sizeof(reported)); for (i = 0; i < ic->ic_nchans; i++) { const struct ieee80211_channel *c = &ic->ic_channels[i]; const struct ieee80211_channel *c1 = c; - if (isclr(reported, c->ic_ieee)) { + if (!alreadyListed(chans, c->ic_freq)) { setbit(reported, c->ic_ieee); - /* pick turbo channel over non-turbo channel, and - * 11g channel over 11b channel */ if (IEEE80211_IS_CHAN_A(c)) - c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_TURBO_A); + c1 = findchannel(ic, c->ic_freq, + IEEE80211_MODE_TURBO_A); if (IEEE80211_IS_CHAN_ANYG(c)) - c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_TURBO_G); + c1 = findchannel(ic, c->ic_freq, + IEEE80211_MODE_TURBO_G); else if (IEEE80211_IS_CHAN_B(c)) { - c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_TURBO_G); + c1 = findchannel(ic, c->ic_freq, + IEEE80211_MODE_TURBO_G); if (!c1) - c1 = findchannel(ic, c->ic_ieee, IEEE80211_MODE_11G); + c1 = findchannel(ic, c->ic_freq, + IEEE80211_MODE_11G); } if (c1) c = c1; - /* Copy the entire structure, whereas it used to just copy a few fields */ - memcpy(&chans.ic_chans[chans.ic_nchans], c, sizeof(struct ieee80211_channel)); - if (++chans.ic_nchans >= IEEE80211_CHAN_MAX) + chans->ic_chans[chans->ic_nchans].ic_ieee = c->ic_ieee; + chans->ic_chans[chans->ic_nchans].ic_freq = c->ic_freq; + chans->ic_chans[chans->ic_nchans].ic_flags = c->ic_flags; + if (++chans->ic_nchans >= IEEE80211_CHAN_MAX) break; } } - memcpy(extra, &chans, sizeof(struct ieee80211req_chaninfo)); return 0; } --- a/net80211/ieee80211_scan_ap.c +++ b/net80211/ieee80211_scan_ap.c @@ -512,12 +512,13 @@ pick_channel(struct ieee80211_scan_state int ss_last = ss->ss_last; struct ieee80211_channel *best; struct ap_state *as = ss->ss_priv; - struct channel chans[ss_last]; /* actually ss_last-1 is required */ + struct channel *chans; /* actually ss_last-1 is required */ struct channel *c = NULL; struct pc_params params = { vap, ss, flags }; int benefit = 0; int sta_assoc = 0; + chans = (struct channel *)kmalloc(ss_last*sizeof(struct channel),GFP_ATOMIC); for (i = 0; i < ss_last; i++) { chans[i].chan = ss->ss_chans[i]; chans[i].orig = i; @@ -571,6 +572,7 @@ pick_channel(struct ieee80211_scan_state "%s: best: channel %u rssi %d\n", __func__, i, as->as_maxrssi[i]); } + kfree(chans); return best; } @@ -609,6 +611,7 @@ ap_end(struct ieee80211_scan_state *ss, res = 1; /* Do NOT restart scan */ } else { struct ieee80211_scan_entry se; + int i; /* XXX: notify all VAPs? */ /* if this is a dynamic turbo frequency , start with normal * mode first */ @@ -623,6 +626,11 @@ ap_end(struct ieee80211_scan_state *ss, return 0; } } + for (i = (bestchan - &ic->ic_channels[0])/sizeof(*bestchan) + 1; i < ic->ic_nchans; i++) { + if ((ic->ic_channels[i].ic_freq == bestchan->ic_freq) && + IEEE80211_IS_CHAN_ANYG(&ic->ic_channels[i])) + bestchan = &ic->ic_channels[i]; + } memset(&se, 0, sizeof(se)); se.se_chan = bestchan; --- a/tools/wlanconfig.c +++ b/tools/wlanconfig.c @@ -737,7 +737,7 @@ list_channels(const char *ifname, int al if (get80211priv(ifname, IEEE80211_IOCTL_GETCHANINFO, &chans, sizeof(chans)) < 0) errx(1, "unable to get channel information"); if (!allchans) { - uint8_t active[32]; + uint8_t active[IEEE80211_CHAN_BYTES]; if (get80211priv(ifname, IEEE80211_IOCTL_GETCHANLIST, &active, sizeof(active)) < 0) errx(1, "unable to get active channel list"); --- a/net80211/ieee80211_scan.c +++ b/net80211/ieee80211_scan.c @@ -1044,6 +1044,7 @@ ieee80211_scan_assoc_fail(struct ieee802 ss->ss_ops->scan_assoc_fail(ss, mac, reason); } } +EXPORT_SYMBOL(ieee80211_scan_flush); /* * Iterate over the contents of the scan cache. --- a/ath/if_ath_hal_wrappers.h +++ b/ath/if_ath_hal_wrappers.h @@ -111,6 +111,11 @@ static inline HAL_BOOL ath_hal_getregdom return (ath_hal_getcapability(ah, HAL_CAP_REG_DMN, 0, destination) == HAL_OK); } +static inline HAL_BOOL ath_hal_setregdomain(struct ath_hal *ah, u_int32_t v) +{ + return (ath_hal_setcapability(ah, HAL_CAP_REG_DMN, 0, v, NULL)); +} + static inline HAL_BOOL ath_hal_gettkipmic(struct ath_hal *ah) { return (ath_hal_getcapability(ah, HAL_CAP_TKIP_MIC, 1, NULL) == HAL_OK);