1351 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1351 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| --- 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 <linux/moduleparam.h>
 | |
|  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) {
 | |
|  		/*
 | |
| @@ -7799,12 +7815,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;
 | |
|  		}
 | |
| @@ -8097,7 +8115,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;
 | |
| @@ -9064,7 +9082,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);
 | |
| @@ -10121,8 +10139,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;
 | |
| @@ -10136,17 +10153,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.
 | |
|  	 */
 | |
| @@ -10392,7 +10423,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)
 | |
| @@ -10405,57 +10436,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)
 | |
|  {
 | |
| @@ -10464,7 +10454,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:
 | |
| @@ -10482,6 +10472,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;
 | |
| @@ -10496,10 +10492,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;
 | |
|  }
 | |
|  
 | |
| @@ -10528,13 +10530,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];
 | |
| @@ -10544,7 +10551,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;
 | |
| @@ -10945,9 +10952,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)
 | |
|  {
 | |
| @@ -11026,6 +11130,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];
 | |
| @@ -11049,25 +11154,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) {
 | |
| @@ -11220,6 +11334,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;
 | |
| @@ -11238,6 +11355,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;
 | |
| @@ -11351,11 +11471,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,
 | |
| @@ -11363,7 +11489,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,
 | |
|  	},
 | |
| @@ -11426,6 +11552,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,
 | |
| @@ -11666,13 +11798,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,
 | |
| @@ -11680,13 +11805,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,58 @@ 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;
 | |
| +
 | |
| +	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 +359,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 +796,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 +827,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 +1241,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 +1451,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 +1469,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 +1911,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 +1944,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 */
 | |
| @@ -715,6 +713,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);
 | |
| @@ -794,6 +793,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;) {
 | |
| @@ -1401,6 +1401,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
 | |
| @@ -2133,7 +2133,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;
 | |
|  	}
 | |
| @@ -4081,46 +4081,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);
 | 
