Example #1
0
static u_int
getmodesmask(struct ath_hal *ah, REG_DOMAIN *rd5GHz, u_int modeSelect)
{
#define	HAL_MODE_11A_ALL \
	(HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
	 HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
	u_int modesMask;

	/* get modes that HW is capable of */
	modesMask = ath_hal_getWirelessModes(ah);
	modesMask &= modeSelect;
	/* optimize work below if no 11a channels */
	if (isChanBitMaskZero(rd5GHz->chan11a) &&
	    (modesMask & HAL_MODE_11A_ALL)) {
		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
		    "%s: disallow all 11a\n", __func__);
		modesMask &= ~HAL_MODE_11A_ALL;
	}

	return (modesMask);
#undef HAL_MODE_11A_ALL
}
Example #2
0
/*
 * Construct the channel list for the specified regulatory config.
 */
static HAL_STATUS
getchannels(struct ath_hal *ah,
    struct ieee80211_channel chans[], u_int maxchans, int *nchans,
    u_int modeSelect, HAL_CTRY_CODE cc, HAL_REG_DOMAIN regDmn,
    HAL_BOOL enableExtendedChannels,
    COUNTRY_CODE_TO_ENUM_RD **pcountry,
    REG_DOMAIN **prd2GHz, REG_DOMAIN **prd5GHz)
{
#define CHANNEL_HALF_BW		10
#define CHANNEL_QUARTER_BW	5
#define	HAL_MODE_11A_ALL \
	(HAL_MODE_11A | HAL_MODE_11A_TURBO | HAL_MODE_TURBO | \
	 HAL_MODE_11A_QUARTER_RATE | HAL_MODE_11A_HALF_RATE)
	REG_DOMAIN *rd5GHz, *rd2GHz;
	u_int modesAvail;
	const struct cmode *cm;
	struct ieee80211_channel *ic;
	int next, b;
	HAL_STATUS status;

	HALDEBUG(ah, HAL_DEBUG_REGDOMAIN, "%s: cc %u regDmn 0x%x mode 0x%x%s\n",
	    __func__, cc, regDmn, modeSelect, 
	    enableExtendedChannels ? " ecm" : "");

	status = getregstate(ah, cc, regDmn, pcountry, &rd2GHz, &rd5GHz);
	if (status != HAL_OK)
		return status;

	/* get modes that HW is capable of */
	modesAvail = ath_hal_getWirelessModes(ah);
	/* optimize work below if no 11a channels */
	if (isChanBitMaskZero(rd5GHz->chan11a) &&
	    (modesAvail & HAL_MODE_11A_ALL)) {
		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
		    "%s: disallow all 11a\n", __func__);
		modesAvail &= ~HAL_MODE_11A_ALL;
	}

	next = 0;
	ic = &chans[0];
	for (cm = modes; cm < &modes[N(modes)]; cm++) {
		uint16_t c, c_hi, c_lo;
		uint64_t *channelBM = AH_NULL;
		REG_DMN_FREQ_BAND *fband = AH_NULL,*freqs;
		int low_adj, hi_adj, channelSep, lastc;
		uint32_t rdflags;
		uint64_t dfsMask;
		uint64_t pscan;

		if ((cm->mode & modeSelect) == 0) {
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: skip mode 0x%x flags 0x%x\n",
			    __func__, cm->mode, cm->flags);
			continue;
		}
		if ((cm->mode & modesAvail) == 0) {
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: !avail mode 0x%x (0x%x) flags 0x%x\n",
			    __func__, modesAvail, cm->mode, cm->flags);
			continue;
		}
		if (!ath_hal_getChannelEdges(ah, cm->flags, &c_lo, &c_hi)) {
			/* channel not supported by hardware, skip it */
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: channels 0x%x not supported by hardware\n",
			    __func__,cm->flags);
			continue;
		}
		switch (cm->mode) {
		case HAL_MODE_TURBO:
		case HAL_MODE_11A_TURBO:
			rdflags = rd5GHz->flags;
			dfsMask = rd5GHz->dfsMask;
			pscan = rd5GHz->pscan;
			if (cm->mode == HAL_MODE_TURBO)
				channelBM = rd5GHz->chan11a_turbo;
			else
				channelBM = rd5GHz->chan11a_dyn_turbo;
			freqs = &regDmn5GhzTurboFreq[0];
			break;
		case HAL_MODE_11G_TURBO:
			rdflags = rd2GHz->flags;
			dfsMask = rd2GHz->dfsMask;
			pscan = rd2GHz->pscan;
			channelBM = rd2GHz->chan11g_turbo;
			freqs = &regDmn2Ghz11gTurboFreq[0];
			break;
		case HAL_MODE_11A:
		case HAL_MODE_11A_HALF_RATE:
		case HAL_MODE_11A_QUARTER_RATE:
		case HAL_MODE_11NA_HT20:
		case HAL_MODE_11NA_HT40PLUS:
		case HAL_MODE_11NA_HT40MINUS:
			rdflags = rd5GHz->flags;
			dfsMask = rd5GHz->dfsMask;
			pscan = rd5GHz->pscan;
			if (cm->mode == HAL_MODE_11A_HALF_RATE)
				channelBM = rd5GHz->chan11a_half;
			else if (cm->mode == HAL_MODE_11A_QUARTER_RATE)
				channelBM = rd5GHz->chan11a_quarter;
			else
				channelBM = rd5GHz->chan11a;
			freqs = &regDmn5GhzFreq[0];
			break;
		case HAL_MODE_11B:
		case HAL_MODE_11G:
		case HAL_MODE_11G_HALF_RATE:
		case HAL_MODE_11G_QUARTER_RATE:
		case HAL_MODE_11NG_HT20:
		case HAL_MODE_11NG_HT40PLUS:
		case HAL_MODE_11NG_HT40MINUS:
			rdflags = rd2GHz->flags;
			dfsMask = rd2GHz->dfsMask;
			pscan = rd2GHz->pscan;
			if (cm->mode == HAL_MODE_11G_HALF_RATE)
				channelBM = rd2GHz->chan11g_half;
			else if (cm->mode == HAL_MODE_11G_QUARTER_RATE)
				channelBM = rd2GHz->chan11g_quarter;
			else if (cm->mode == HAL_MODE_11B)
				channelBM = rd2GHz->chan11b;
			else
				channelBM = rd2GHz->chan11g;
			if (cm->mode == HAL_MODE_11B)
				freqs = &regDmn2GhzFreq[0];
			else
				freqs = &regDmn2Ghz11gFreq[0];
			break;
		default:
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: Unkonwn HAL mode 0x%x\n", __func__, cm->mode);
			continue;
		}
		if (isChanBitMaskZero(channelBM))
			continue;
		/*
		 * Setup special handling for HT40 channels; e.g.
		 * 5G HT40 channels require 40Mhz channel separation.
		 */
		hi_adj = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
		    cm->mode == HAL_MODE_11NG_HT40PLUS) ? -20 : 0;
		low_adj = (cm->mode == HAL_MODE_11NA_HT40MINUS || 
		    cm->mode == HAL_MODE_11NG_HT40MINUS) ? 20 : 0;
		channelSep = (cm->mode == HAL_MODE_11NA_HT40PLUS ||
		    cm->mode == HAL_MODE_11NA_HT40MINUS) ? 40 : 0;

		for (b = 0; b < 64*BMLEN; b++) {
			if (!IS_BIT_SET(b, channelBM))
				continue;
			fband = &freqs[b];
			lastc = 0;

			for (c = fband->lowChannel + low_adj;
			     c <= fband->highChannel + hi_adj;
			     c += fband->channelSep) {
				if (!(c_lo <= c && c <= c_hi)) {
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "%s: c %u out of range [%u..%u]\n",
					    __func__, c, c_lo, c_hi);
					continue;
				}
				if (next >= maxchans){
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "%s: too many channels for channel table\n",
					    __func__);
					goto done;
				}
				if ((fband->usePassScan & IS_ECM_CHAN) &&
				    !enableExtendedChannels) {
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "skip ecm channel\n");
					continue;
				}
#if 0
				if ((fband->useDfs & dfsMask) && 
				    (cm->flags & IEEE80211_CHAN_HT40)) {
					/* NB: DFS and HT40 don't mix */
					HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
					    "skip HT40 chan, DFS required\n");
					continue;
				}
#endif
				/*
				 * Make sure that channel separation
				 * meets the requirement.
				 */
				if (lastc && channelSep &&
				    (c-lastc) < channelSep)
					continue;
				lastc = c;

				OS_MEMZERO(ic, sizeof(*ic));
				ic->ic_freq = c;
				ic->ic_flags = cm->flags;
				ic->ic_maxregpower = fband->powerDfs;
				ath_hal_getpowerlimits(ah, ic);
				ic->ic_maxantgain = fband->antennaMax;
				if (fband->usePassScan & pscan)
					ic->ic_flags |= IEEE80211_CHAN_PASSIVE;
				if (fband->useDfs & dfsMask)
					ic->ic_flags |= IEEE80211_CHAN_DFS;
				if (IEEE80211_IS_CHAN_5GHZ(ic) &&
				    (rdflags & DISALLOW_ADHOC_11A))
					ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
				if (IEEE80211_IS_CHAN_TURBO(ic) &&
				    (rdflags & DISALLOW_ADHOC_11A_TURB))
					ic->ic_flags |= IEEE80211_CHAN_NOADHOC;
				if (rdflags & NO_HOSTAP)
					ic->ic_flags |= IEEE80211_CHAN_NOHOSTAP;
				if (rdflags & LIMIT_FRAME_4MS)
					ic->ic_flags |= IEEE80211_CHAN_4MSXMIT;
				if (rdflags & NEED_NFC)
					ic->ic_flags |= CHANNEL_NFCREQUIRED;

				ic++, next++;
			}
		}
	}
done:
	*nchans = next;
	/* NB: pcountry set above by getregstate */
	if (prd2GHz != AH_NULL)
		*prd2GHz = rd2GHz;
	if (prd5GHz != AH_NULL)
		*prd5GHz = rd5GHz;
	return HAL_OK;
#undef HAL_MODE_11A_ALL
#undef CHANNEL_HALF_BW
#undef CHANNEL_QUARTER_BW
}
Example #3
0
static void
add_chanlist_mode(struct ath_hal *ah, struct ieee80211_channel chans[],
    u_int maxchans, int *nchans, const struct cmode *cm, REG_DOMAIN *rd,
    HAL_BOOL enableExtendedChannels)
{
	uint64_t *channelBM;
	uint16_t freq_lo, freq_hi;
	int b, error, low_adj, hi_adj, channelSep;

	if (!ath_hal_getChannelEdges(ah, cm->flags, &freq_lo, &freq_hi)) {
		/* channel not supported by hardware, skip it */
		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
		    "%s: channels 0x%x not supported by hardware\n",
		    __func__, cm->flags);
		return;
	}

	channelBM = getchannelBM(cm->mode, rd);
	if (isChanBitMaskZero(channelBM))
		return;

	/*
	 * Setup special handling for HT40 channels; e.g.
	 * 5G HT40 channels require 40Mhz channel separation.
	 */
	adj_freq_ht40(cm->mode, &low_adj, &hi_adj, &channelSep);

	for (b = 0; b < 64*BMLEN; b++) {
		REG_DMN_FREQ_BAND *fband;
		uint16_t bfreq_lo, bfreq_hi;
		int step;

		if (!IS_BIT_SET(b, channelBM))
			continue;
		fband = &cm->freqs[b];

		if ((fband->usePassScan & IS_ECM_CHAN) &&
		    !enableExtendedChannels) {
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "skip ecm channels\n");
			continue;
		}
#if 0
		if ((fband->useDfs & rd->dfsMask) && 
		    (cm->flags & IEEE80211_CHAN_HT40)) {
			/* NB: DFS and HT40 don't mix */
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "skip HT40 chan, DFS required\n");
			continue;
		}
#endif

		/*
		 * XXX TODO: handle REG_EXT_FCC_CH_144.
		 *
		 * Figure out which instances/uses cause us to not
		 * be allowed to use channel 144 (pri or sec overlap.)
		 */

		bfreq_lo = MAX(fband->lowChannel + low_adj, freq_lo);
		bfreq_hi = MIN(fband->highChannel + hi_adj, freq_hi);
		if (fband->channelSep >= channelSep)
			step = fband->channelSep;
		else
			step = roundup(channelSep, fband->channelSep);

		error = add_chanlist_band(ah, chans, maxchans, nchans,
		    bfreq_lo, bfreq_hi, step, cm->flags, fband, rd);
		if (error != 0)	{
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: too many channels for channel table\n",
			    __func__);
			return;
		}
	}
}
Example #4
0
static void
add_chanlist_mode(struct ath_hal *ah, struct ieee80211_channel chans[],
    u_int maxchans, int *nchans, const struct cmode *cm, REG_DOMAIN *rd,
    HAL_BOOL enableExtendedChannels)
{
	uint64_t *channelBM;
	uint16_t freq_lo, freq_hi;
	int b, error, low_adj, hi_adj, channelSep;

	if (!ath_hal_getChannelEdges(ah, cm->flags, &freq_lo, &freq_hi)) {
		/* channel not supported by hardware, skip it */
		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
		    "%s: channels 0x%x not supported by hardware\n",
		    __func__, cm->flags);
		return;
	}

	channelBM = getchannelBM(cm->mode, rd);
	if (isChanBitMaskZero(channelBM))
		return;

	/*
	 * Setup special handling for HT40 channels; e.g.
	 * 5G HT40 channels require 40Mhz channel separation.
	 */
	adj_freq_ht40(cm->mode, &low_adj, &hi_adj, &channelSep);

	for (b = 0; b < 64*BMLEN; b++) {
		REG_DMN_FREQ_BAND *fband;
		uint16_t bfreq_lo, bfreq_hi;
		int step;

		if (!IS_BIT_SET(b, channelBM))
			continue;
		fband = &cm->freqs[b];

		if ((fband->usePassScan & IS_ECM_CHAN) &&
		    !enableExtendedChannels) {
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "skip ecm channels\n");
			continue;
		}
#if 0
		if ((fband->useDfs & rd->dfsMask) && 
		    (cm->flags & IEEE80211_CHAN_HT40)) {
			/* NB: DFS and HT40 don't mix */
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "skip HT40 chan, DFS required\n");
			continue;
		}
#endif
		/*
		 * XXX TODO: handle REG_EXT_FCC_CH_144.
		 *
		 * Figure out which instances/uses cause us to not
		 * be allowed to use channel 144 (pri or sec overlap.)
		 */

		bfreq_lo = MAX(fband->lowChannel + low_adj, freq_lo);
		bfreq_hi = MIN(fband->highChannel + hi_adj, freq_hi);

		/*
		 * Don't start the 5GHz channel list at 5120MHz.
		 *
		 * Unfortunately (sigh) the HT40 channel creation
		 * logic will create HT40U channels at 5120, 5160, 5200.
		 * This means that 36 (5180) isn't considered as a
		 * HT40 channel, and everything goes messed up from there.
		 */
		if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
		    (cm->flags & IEEE80211_CHAN_HT40U)) {
			if (bfreq_lo < 5180)
				bfreq_lo = 5180;
		}

		/*
		 * Same with HT40D - need to start at 5200 or the low
		 * channels are all wrong again.
		 */
		if ((cm->flags & IEEE80211_CHAN_5GHZ) &&
		    (cm->flags & IEEE80211_CHAN_HT40D)) {
			if (bfreq_lo < 5200)
				bfreq_lo = 5200;
		}

		if (fband->channelSep >= channelSep)
			step = fband->channelSep;
		else
			step = roundup(channelSep, fband->channelSep);

		HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
		    "%s: freq_lo=%d, freq_hi=%d, low_adj=%d, hi_adj=%d, "
		    "bandlo=%d, bandhi=%d, bfreqlo=%d, bfreqhi=%d, step=%d, "
		    "flags=0x%08x\n",
		    __func__,
		    (int) freq_lo,
		    (int) freq_hi,
		    (int) low_adj,
		    (int) hi_adj,
		    (int) fband->lowChannel,
		    (int) fband->highChannel,
		    (int) bfreq_lo,
		    (int) bfreq_hi,
		    step,
		    (int) cm->flags);

		error = add_chanlist_band(ah, chans, maxchans, nchans,
		    bfreq_lo, bfreq_hi, step, cm->flags, fband, rd);
		if (error != 0)	{
			HALDEBUG(ah, HAL_DEBUG_REGDOMAIN,
			    "%s: too many channels for channel table\n",
			    __func__);
			return;
		}
	}
}
Example #5
0
/*
 * Return the mask of available modes based on the hardware
 * capabilities and the specified country code and reg domain.
 */
u_int32_t regdmn_getwmodesnreg(u_int32_t modesAvail,
		const COUNTRY_CODE_TO_ENUM_RD *country,
		const REG_DOMAIN *rd5GHz)
{

	/* Check country regulations for allowed modes */
	if ((modesAvail & (REGDMN_MODE_11A_TURBO|REGDMN_MODE_TURBO)) &&
			(!country->allow11aTurbo))
		modesAvail &= ~(REGDMN_MODE_11A_TURBO | REGDMN_MODE_TURBO);

	if ((modesAvail & REGDMN_MODE_11G_TURBO) &&
			(!country->allow11gTurbo))
		modesAvail &= ~REGDMN_MODE_11G_TURBO;

	if ((modesAvail & REGDMN_MODE_11G) &&
			(!country->allow11g))
		modesAvail &= ~REGDMN_MODE_11G;

	if ((modesAvail & REGDMN_MODE_11A) &&
			(isChanBitMaskZero(rd5GHz->chan11a)))
		modesAvail &= ~REGDMN_MODE_11A;

	if ((modesAvail & REGDMN_MODE_11NG_HT20) &&
			(!country->allow11ng20))
		modesAvail &= ~REGDMN_MODE_11NG_HT20;

	if ((modesAvail & REGDMN_MODE_11NA_HT20) &&
			(!country->allow11na20))
		modesAvail &= ~REGDMN_MODE_11NA_HT20;

	if ((modesAvail & REGDMN_MODE_11NG_HT40PLUS) &&
			(!country->allow11ng40))
		modesAvail &= ~REGDMN_MODE_11NG_HT40PLUS;

	if ((modesAvail & REGDMN_MODE_11NG_HT40MINUS) &&
			(!country->allow11ng40))
		modesAvail &= ~REGDMN_MODE_11NG_HT40MINUS;

	if ((modesAvail & REGDMN_MODE_11NA_HT40PLUS) &&
			(!country->allow11na40))
		modesAvail &= ~REGDMN_MODE_11NA_HT40PLUS;

	if ((modesAvail & REGDMN_MODE_11NA_HT40MINUS) &&
			(!country->allow11na40))
		modesAvail &= ~REGDMN_MODE_11NA_HT40MINUS;

	if ((modesAvail & REGDMN_MODE_11AC_VHT20) &&
			(!country->allow11na20))
		modesAvail &= ~REGDMN_MODE_11AC_VHT20;

	if ((modesAvail & REGDMN_MODE_11AC_VHT40PLUS) &&
			(!country->allow11na40))
		modesAvail &= ~REGDMN_MODE_11AC_VHT40PLUS;

	if ((modesAvail & REGDMN_MODE_11AC_VHT40MINUS) &&
			(!country->allow11na40))
		modesAvail &= ~REGDMN_MODE_11AC_VHT40MINUS;

	if ((modesAvail & REGDMN_MODE_11AC_VHT80) &&
			(!country->allow11na80))
		modesAvail &= ~REGDMN_MODE_11AC_VHT80;

	if ((modesAvail & REGDMN_MODE_11AC_VHT20_2G) &&
			(!country->allow11ng20))
		modesAvail &= ~REGDMN_MODE_11AC_VHT20_2G;

	return modesAvail;
}