u32 rtw_ch2freq(u32 channel)
{
  if (channel <= 14) {
    return ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
  } else {
    return ieee80211_channel_to_frequency(channel, NL80211_BAND_5GHZ);
  }
}
Esempio n. 2
0
static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel,
					  u8 sync_band)
{
	struct sk_buff *skb;
	enum ieee80211_band band;
	int freq;

	if (sync_band == WLCORE_BAND_5GHZ)
		band = IEEE80211_BAND_5GHZ;
	else
		band = IEEE80211_BAND_2GHZ;

	freq = ieee80211_channel_to_frequency(sync_channel, band);

	wl1271_debug(DEBUG_EVENT,
		     "SMART_CONFIG_SYNC_EVENT_ID, freq: %d (chan: %d band %d)",
		     freq, sync_channel, sync_band);
	skb = cfg80211_vendor_event_alloc(wl->hw->wiphy, NULL, 20,
					  WLCORE_VENDOR_EVENT_SC_SYNC,
					  GFP_KERNEL);

	if (nla_put_u32(skb, WLCORE_VENDOR_ATTR_FREQ, freq)) {
		kfree_skb(skb);
		return -EMSGSIZE;
	}
	cfg80211_vendor_event(skb, GFP_KERNEL);
	return 0;
}
Esempio n. 3
0
/*
 * This function informs the CFG802.11 subsystem of a new IBSS.
 *
 * The following information are sent to the CFG802.11 subsystem
 * to register the new IBSS. If we do not register the new IBSS,
 * a kernel panic will result.
 *      - SSID
 *      - SSID length
 *      - BSSID
 *      - Channel
 */
static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
{
	struct ieee80211_channel *chan;
	struct mwifiex_bss_info bss_info;
	struct cfg80211_bss *bss;
	int ie_len;
	u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
	enum ieee80211_band band;

	if (mwifiex_get_bss_info(priv, &bss_info))
		return -1;

	ie_buf[0] = WLAN_EID_SSID;
	ie_buf[1] = bss_info.ssid.ssid_len;

	memcpy(&ie_buf[sizeof(struct ieee_types_header)],
	       &bss_info.ssid.ssid, bss_info.ssid.ssid_len);
	ie_len = ie_buf[1] + sizeof(struct ieee_types_header);

	band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
	chan = __ieee80211_get_channel(priv->wdev->wiphy,
			ieee80211_channel_to_frequency(bss_info.bss_chan,
						       band));

	bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
				  bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
				  0, ie_buf, ie_len, 0, GFP_KERNEL);
	cfg80211_put_bss(bss);
	memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);

	return 0;
}
Esempio n. 4
0
static int ieee80211_ioctl_siwfreq(struct net_device *dev,
				   struct iw_request_info *info,
				   struct iw_freq *freq, char *extra)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	if (sdata->vif.type == NL80211_IFTYPE_STATION)
		sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;

	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
	if (freq->e == 0) {
		if (freq->m < 0) {
			if (sdata->vif.type == NL80211_IFTYPE_STATION)
				sdata->u.sta.flags |=
					IEEE80211_STA_AUTO_CHANNEL_SEL;
			return 0;
		} else
			return ieee80211_set_freq(sdata,
				ieee80211_channel_to_frequency(freq->m));
	} else {
		int i, div = 1000000;
		for (i = 0; i < freq->e; i++)
			div /= 10;
		if (div > 0)
			return ieee80211_set_freq(sdata, freq->m / div);
		else
			return -EINVAL;
	}
}
static void wl1271_rx_status(struct wl1271 *wl,
			     struct wl1271_rx_descriptor *desc,
			     struct ieee80211_rx_status *status,
			     u8 beacon)
{
	memset(status, 0, sizeof(struct ieee80211_rx_status));

	status->band = wl->band;
	status->rate_idx = wl1271_rate_to_idx(wl, desc->rate);

	/*
	 * FIXME: Add mactime handling.  For IBSS (ad-hoc) we need to get the
	 * timestamp from the beacon (acx_tsf_info).  In BSS mode (infra) we
	 * only need the mactime for monitor mode.  For now the mactime is
	 * not valid, so RX_FLAG_TSFT should not be set
	 */
	status->signal = desc->rssi;

	status->freq = ieee80211_channel_to_frequency(desc->channel);

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;

		if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
			status->flag |= RX_FLAG_DECRYPTED;
		if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
			status->flag |= RX_FLAG_MMIC_ERROR;
	}
}
Esempio n. 6
0
/**
 * cfg80211_wext_freq - get wext frequency for non-"auto"
 * @wiphy: the wiphy
 * @freq: the wext freq encoding
 *
 * Returns a channel, %NULL for auto, or an ERR_PTR for errors!
 */
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
					     struct iw_freq *freq)
{
	struct ieee80211_channel *chan;
	int f;

	/*
	 * Parse frequency - return NULL for auto and
	 * -EINVAL for impossible things.
	 */
	if (freq->e == 0) {
		if (freq->m < 0)
			return NULL;
		f = ieee80211_channel_to_frequency(freq->m);
	} else {
		int i, div = 1000000;
		for (i = 0; i < freq->e; i++)
			div /= 10;
		if (div <= 0)
			return ERR_PTR(-EINVAL);
		f = freq->m / div;
	}

	/*
	 * Look up channel struct and return -EINVAL when
	 * it cannot be found.
	 */
	chan = ieee80211_get_channel(wiphy, f);
	if (!chan)
		return ERR_PTR(-EINVAL);
	return chan;
}
Esempio n. 7
0
static void CFG80211_UpdateBssTableRssi(
	IN VOID							*pAdCB)
{

	PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)pAdCB;
	CFG80211_CB *pCfg80211_CB  = (CFG80211_CB *)pAd->pCfg80211_CB;
	struct wiphy *pWiphy = pCfg80211_CB->pCfg80211_Wdev->wiphy;
	struct ieee80211_channel *chan;
	struct cfg80211_bss *bss;
	BSS_ENTRY *pBssEntry;
	UINT index;
	UINT32 CenFreq;
	
	for (index = 0; index < pAd->ScanTab.BssNr; index++) 
	{
		pBssEntry = &pAd->ScanTab.BssEntry[index];
			
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)) 
		if (pAd->ScanTab.BssEntry[index].Channel > 14) 
			CenFreq = ieee80211_channel_to_frequency(pAd->ScanTab.BssEntry[index].Channel , IEEE80211_BAND_5GHZ);
		else 
			CenFreq = ieee80211_channel_to_frequency(pAd->ScanTab.BssEntry[index].Channel , IEEE80211_BAND_2GHZ);
#else
		CenFreq = ieee80211_channel_to_frequency(pAd->ScanTab.BssEntry[index].Channel);
#endif

		chan = ieee80211_get_channel(pWiphy, CenFreq);			
		bss = cfg80211_get_bss(pWiphy, chan, pBssEntry->Bssid, pBssEntry->Ssid, pBssEntry->SsidLen, 
						WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
		if (bss == NULL)
		{
			/* ScanTable Entry not exist in kernel buffer */
		}
		else
		{
			/* HIT */
			CFG80211_CalBssAvgRssi(pBssEntry);
			bss->signal = pBssEntry->AvgRssi * 100; //UNIT: MdBm
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0))
			cfg80211_put_bss(pWiphy, bss);
#else
			cfg80211_put_bss(bss);
#endif /* LINUX_VERSION_CODE: 3.9.0 */
		}
	}	
}
Esempio n. 8
0
static void rt2x00lib_channel(struct ieee80211_channel *entry,
			      const int channel, const int tx_power,
			      const int value)
{
	entry->center_freq = ieee80211_channel_to_frequency(channel);
	entry->hw_value = value;
	entry->max_power = tx_power;
	entry->max_antenna_gain = 0xff;
}
Esempio n. 9
0
static void wl1251_rx_status(struct wl1251 *wl,
                             struct wl1251_rx_descriptor *desc,
                             struct ieee80211_rx_status *status,
                             u8 beacon)
{
    u64 mactime;
    int ret;

    memset(status, 0, sizeof(struct ieee80211_rx_status));

    status->band = IEEE80211_BAND_2GHZ;
    status->mactime = desc->timestamp;

    /*
     * The rx status timestamp is a 32 bits value while the TSF is a
     * 64 bits one.
     * For IBSS merging, TSF is mandatory, so we have to get it
     * somehow, so we ask for ACX_TSF_INFO.
     * That could be moved to the get_tsf() hook, but unfortunately,
     * this one must be atomic, while our SPI routines can sleep.
     */
    if ((wl->bss_type == BSS_TYPE_IBSS) && beacon) {
        ret = wl1251_acx_tsf_info(wl, &mactime);
        if (ret == 0)
            status->mactime = mactime;
    }

    status->signal = desc->rssi;

    /*
     * FIXME: guessing that snr needs to be divided by two, otherwise
     * the values don't make any sense
     */
    wl->noise = desc->rssi - desc->snr / 2;

    status->freq = ieee80211_channel_to_frequency(desc->channel,
                   status->band);

    status->flag |= RX_FLAG_MACTIME_MPDU;

    if (desc->flags & RX_DESC_ENCRYPTION_MASK) {
        status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;

        if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL)))
            status->flag |= RX_FLAG_DECRYPTED;

        if (unlikely(desc->flags & RX_DESC_MIC_FAIL))
            status->flag |= RX_FLAG_MMIC_ERROR;
    }

    if (unlikely(!(desc->flags & RX_DESC_VALID_FCS)))
        status->flag |= RX_FLAG_FAILED_FCS_CRC;


    /* FIXME: set status->rate_idx */
}
Esempio n. 10
0
static void wl1271_rx_status(struct wl1271 *wl,
			     struct wl1271_rx_descriptor *desc,
			     struct ieee80211_rx_status *status,
			     u8 beacon)
{
	memset(status, 0, sizeof(struct ieee80211_rx_status));

	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
		status->band = IEEE80211_BAND_2GHZ;
	else
		status->band = IEEE80211_BAND_5GHZ;

	status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band);

	/* 11n support */
	if (desc->rate <= wl->hw_min_ht_rate)
		status->flag |= RX_FLAG_HT;

	/*
	 * Read the signal level and antenna diversity indication.
	 * The msb in the signal level is always set as it is a
	 * negative number.
	 * The antenna indication is the msb of the rssi.
	 */

	status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7));
	status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7);

	/*
	 * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
	 * need to divide by two for now, but TI has been discussing about
	 * changing it.  This needs to be rechecked.
	 */
	wl->noise = desc->rssi - (desc->snr >> 1);

	status->freq = ieee80211_channel_to_frequency(desc->channel,
						      status->band);

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
		u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK;

		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
				RX_FLAG_DECRYPTED;

		if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) {
			status->flag |= RX_FLAG_MMIC_ERROR;
			wl1271_warning("Michael MIC error. Desc: 0x%x",
				       desc_err_code);
		}
	}

	if (beacon)
		wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel,
						status->band);
}
Esempio n. 11
0
static void rt2x00lib_channel(struct ieee80211_channel *entry,
			      const int channel, const int tx_power,
			      const int value)
{
	/* XXX: this assumption about the band is wrong for 802.11j */
	entry->band = channel <= 14 ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
	entry->center_freq = ieee80211_channel_to_frequency(channel,
							    entry->band);
	entry->hw_value = value;
	entry->max_power = tx_power;
	entry->max_antenna_gain = 0xff;
}
Esempio n. 12
0
static void wl1271_rx_status(struct wl1271 *wl,
			     struct wl1271_rx_descriptor *desc,
			     struct ieee80211_rx_status *status,
			     u8 beacon)
{
	memset(status, 0, sizeof(struct ieee80211_rx_status));

	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
		status->band = IEEE80211_BAND_2GHZ;
	else
		wl1271_warning("unsupported band 0x%x",
			       desc->flags & WL1271_RX_DESC_BAND_MASK);

	/*
	 * FIXME: Add mactime handling.  For IBSS (ad-hoc) we need to get the
	 * timestamp from the beacon (acx_tsf_info).  In BSS mode (infra) we
	 * only need the mactime for monitor mode.  For now the mactime is
	 * not valid, so RX_FLAG_TSFT should not be set
	 */
	status->signal = desc->rssi;

	/* FIXME: Should this be optimized? */
	status->qual = (desc->rssi - WL1271_RX_MIN_RSSI) * 100 /
		(WL1271_RX_MAX_RSSI - WL1271_RX_MIN_RSSI);
	status->qual = min(status->qual, 100);
	status->qual = max(status->qual, 0);

	/*
	 * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
	 * need to divide by two for now, but TI has been discussing about
	 * changing it.  This needs to be rechecked.
	 */
	status->noise = desc->rssi - (desc->snr >> 1);

	status->freq = ieee80211_channel_to_frequency(desc->channel);

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;

		if (likely(!(desc->flags & WL1271_RX_DESC_DECRYPT_FAIL)))
			status->flag |= RX_FLAG_DECRYPTED;

		if (unlikely(desc->flags & WL1271_RX_DESC_MIC_FAIL))
			status->flag |= RX_FLAG_MMIC_ERROR;
	}

	status->rate_idx = wl1271_rx_rate_to_idx[desc->rate];

	if (status->rate_idx == WL1271_RX_RATE_UNSUPPORTED)
		wl1271_warning("unsupported rate");
}
Esempio n. 13
0
static void CFG80211_UpdateBssTableRssi(
	IN struct rtmp_adapter			*pAd)
{

	struct mt7612u_cfg80211_cb *pCfg80211_CB  = (struct mt7612u_cfg80211_cb *)pAd->pCfg80211_CB;
	struct wiphy *pWiphy = pCfg80211_CB->pCfg80211_Wdev->wiphy;
	struct ieee80211_channel *chan;
	struct cfg80211_bss *bss;
	BSS_ENTRY *pBssEntry;
	UINT index;
	uint32_t CenFreq;

	for (index = 0; index < pAd->ScanTab.BssNr; index++)
	{
		pBssEntry = &pAd->ScanTab.BssEntry[index];

		if (pAd->ScanTab.BssEntry[index].Channel > 14)
			CenFreq = ieee80211_channel_to_frequency(pAd->ScanTab.BssEntry[index].Channel , NL80211_BAND_5GHZ);
		else
			CenFreq = ieee80211_channel_to_frequency(pAd->ScanTab.BssEntry[index].Channel , NL80211_BAND_2GHZ);

		chan = ieee80211_get_channel(pWiphy, CenFreq);
		bss = cfg80211_get_bss(pWiphy, chan, pBssEntry->Bssid, pBssEntry->Ssid, pBssEntry->SsidLen,
						WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
		if (bss == NULL)
		{
			/* ScanTable Entry not exist in kernel buffer */
		}
		else
		{
			/* HIT */
			CFG80211_CalBssAvgRssi(pBssEntry);
			bss->signal = pBssEntry->AvgRssi * 100; //UNIT: MdBm
			cfg80211_put_bss(pWiphy, bss);
		}
	}
}
Esempio n. 14
0
static void wl1271_rx_status(struct wl1271 *wl,
			     struct wl1271_rx_descriptor *desc,
			     struct ieee80211_rx_status *status,
			     u8 beacon)
{
	memset(status, 0, sizeof(struct ieee80211_rx_status));

	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
		status->band = IEEE80211_BAND_2GHZ;
	else
		status->band = IEEE80211_BAND_5GHZ;

	status->rate_idx = wlcore_rate_to_idx(wl, desc->rate, status->band);

	/* 11n support */
	if (desc->rate <= wl->hw_min_ht_rate)
		status->flag |= RX_FLAG_HT;

	status->signal = desc->rssi;

	/*
	 * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
	 * need to divide by two for now, but TI has been discussing about
	 * changing it.  This needs to be rechecked.
	 */
	wl->noise = desc->rssi - (desc->snr >> 1);

	status->freq = ieee80211_channel_to_frequency(desc->channel,
						      status->band);

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
		u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK;

		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
				RX_FLAG_DECRYPTED;

		if (unlikely(desc_err_code & WL1271_RX_DESC_MIC_FAIL)) {
			status->flag |= RX_FLAG_MMIC_ERROR;
			wl1271_warning("Michael MIC error. Desc: 0x%x",
				       desc_err_code);
		}
	}

	if (beacon)
		wlcore_set_pending_regdomain_ch(wl, (u16)desc->channel,
						status->band);
}
Esempio n. 15
0
int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
{
	if (freq->e == 0) {
		enum ieee80211_band band = IEEE80211_BAND_2GHZ;
		if (freq->m < 0)
			return 0;
		if (freq->m > 14)
			band = IEEE80211_BAND_5GHZ;
		return ieee80211_channel_to_frequency(freq->m, band);
	} else {
		int i, div = 1000000;
		for (i = 0; i < freq->e; i++)
			div /= 10;
		if (div <= 0)
			return -EINVAL;
		return freq->m / div;
	}
}
Esempio n. 16
0
static void wl1271_rx_status(struct wl1271 *wl,
			     struct wl1271_rx_descriptor *desc,
			     struct ieee80211_rx_status *status,
			     u8 beacon)
{
	enum ieee80211_band desc_band;

	memset(status, 0, sizeof(struct ieee80211_rx_status));

	status->band = wl->band;

	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
		desc_band = IEEE80211_BAND_2GHZ;
	else
		desc_band = IEEE80211_BAND_5GHZ;

	status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band);

#ifdef CONFIG_WL12XX_HT
	/* 11n support */
	if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
		status->flag |= RX_FLAG_HT;
#endif

	status->signal = desc->rssi;

	/*
	 * FIXME: In wl1251, the SNR should be divided by two.  In wl1271 we
	 * need to divide by two for now, but TI has been discussing about
	 * changing it.  This needs to be rechecked.
	 */
	wl->noise = desc->rssi - (desc->snr >> 1);

	status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band);

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;

		if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
			status->flag |= RX_FLAG_DECRYPTED;
		if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
			status->flag |= RX_FLAG_MMIC_ERROR;
	}
}
/**
 * cfg80211_wext_freq - get wext frequency for non-"auto"
 * @wiphy: the wiphy
 * @freq: the wext freq encoding
 *
 * Returns a frequency, or a negative error code, or 0 for auto.
 */
int cfg80211_wext_freq(struct wiphy *wiphy, struct iw_freq *freq)
{
	/*
	 * Parse frequency - return 0 for auto and
	 * -EINVAL for impossible things.
	 */
	if (freq->e == 0) {
		if (freq->m < 0)
			return 0;
		return ieee80211_channel_to_frequency(freq->m);
	} else {
		int i, div = 1000000;
		for (i = 0; i < freq->e; i++)
			div /= 10;
		if (div <= 0)
			return -EINVAL;
		return freq->m / div;
	}
}
Esempio n. 18
0
static void wl1271_rx_status(struct wl1271 *wl,
			     struct wl1271_rx_descriptor *desc,
			     struct ieee80211_rx_status *status,
			     u8 beacon)
{
	memset(status, 0, sizeof(struct ieee80211_rx_status));

	if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
		status->band = IEEE80211_BAND_2GHZ;
	else
		status->band = IEEE80211_BAND_5GHZ;

	status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);

	/*             */
	if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
		status->flag |= RX_FLAG_HT;

	status->signal = desc->rssi;

	/*
                                                                     
                                                                   
                                             
  */
	wl->noise = desc->rssi - (desc->snr >> 1);

	status->freq = ieee80211_channel_to_frequency(desc->channel,
						      status->band);

	if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
		u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK;

		status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
				RX_FLAG_DECRYPTED;

		if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
			status->flag |= RX_FLAG_MMIC_ERROR;
			wl1271_warning("Michael MIC error");
		}
	}
}
Esempio n. 19
0
void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
				  struct ieee80211_channel_sw_ie *sw_elem,
				  struct ieee80211_bss *bss)
{
	struct ieee80211_channel *new_ch;
	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
	int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);

	/* FIXME: Handle ADHOC later */
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
		return;

	if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
		return;

	if (sdata->local->sw_scanning || sdata->local->hw_scanning)
		return;

	/* Disregard subsequent beacons if we are already running a timer
	   processing a CSA */

	if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
		return;

	new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
	if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
		return;

	sdata->local->csa_channel = new_ch;

	if (sw_elem->count <= 1) {
		queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
	} else {
		ieee80211_stop_queues_by_reason(&sdata->local->hw,
						IEEE80211_QUEUE_STOP_REASON_CSA);
		ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
		mod_timer(&ifmgd->chswitch_timer,
			  jiffies +
			  msecs_to_jiffies(sw_elem->count *
					   bss->cbss.beacon_interval));
	}
}
Esempio n. 20
0
/**
 * cfg80211_wext_freq - get wext frequency for non-"auto"
 * @dev: the net device
 * @freq: the wext freq encoding
 *
 * Returns a frequency, or a negative error code, or 0 for auto.
 */
int cfg80211_wext_freq(struct iw_freq *freq)
{
	/*
	 * Parse frequency - return 0 for auto and
	 * -EINVAL for impossible things.
	 */
	if (freq->e == 0) {
		enum ieee80211_band band = IEEE80211_BAND_2GHZ;
		if (freq->m < 0)
			return 0;
		if (freq->m > 14)
			band = IEEE80211_BAND_5GHZ;
		return ieee80211_channel_to_frequency(freq->m, band);
	} else {
		int i, div = 1000000;
		for (i = 0; i < freq->e; i++)
			div /= 10;
		if (div <= 0)
			return -EINVAL;
		return freq->m / div;
	}
}
Esempio n. 21
0
File: hw.c Progetto: 020gzh/linux
int orinoco_hw_get_freq(struct orinoco_private *priv)
{
	struct hermes *hw = &priv->hw;
	int err = 0;
	u16 channel;
	int freq = 0;
	unsigned long flags;

	if (orinoco_lock(priv, &flags) != 0)
		return -EBUSY;

	err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
				  &channel);
	if (err)
		goto out;

	/* Intersil firmware 1.3.5 returns 0 when the interface is down */
	if (channel == 0) {
		err = -EBUSY;
		goto out;
	}

	if ((channel < 1) || (channel > NUM_CHANNELS)) {
		printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
		       priv->ndev->name, channel);
		err = -EBUSY;
		goto out;

	}
	freq = ieee80211_channel_to_frequency(channel, IEEE80211_BAND_2GHZ);

 out:
	orinoco_unlock(priv, &flags);

	if (err > 0)
		err = -EBUSY;
	return err ? err : freq;
}
Esempio n. 22
0
/*
 * iwl_mvm_rx_rx_mpdu - REPLY_RX_MPDU_CMD handler
 *
 * Handles the actual data of the Rx packet from the fw
 */
int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
                       struct iwl_device_cmd *cmd)
{
    struct ieee80211_hdr *hdr;
    struct ieee80211_rx_status *rx_status;
    struct iwl_rx_packet *pkt = rxb_addr(rxb);
    struct iwl_rx_phy_info *phy_info;
    struct iwl_rx_mpdu_res_start *rx_res;
    struct ieee80211_sta *sta;
    struct sk_buff *skb;
    u32 len;
    u32 ampdu_status;
    u32 rate_n_flags;
    u32 rx_pkt_status;
    u8 crypt_len = 0;

    phy_info = &mvm->last_phy_info;
    rx_res = (struct iwl_rx_mpdu_res_start *)pkt->data;
    hdr = (struct ieee80211_hdr *)(pkt->data + sizeof(*rx_res));
    len = le16_to_cpu(rx_res->byte_count);
    rx_pkt_status = le32_to_cpup((__le32 *)
                                 (pkt->data + sizeof(*rx_res) + len));

    /* Dont use dev_alloc_skb(), we'll have enough headroom once
     * ieee80211_hdr pulled.
     */
    skb = alloc_skb(128, GFP_ATOMIC);
    if (!skb) {
        IWL_ERR(mvm, "alloc_skb failed\n");
        return 0;
    }

    rx_status = IEEE80211_SKB_RXCB(skb);

    /*
     * drop the packet if it has failed being decrypted by HW
     */
    if (iwl_mvm_set_mac80211_rx_flag(mvm, hdr, rx_status, rx_pkt_status,
                                     &crypt_len)) {
        IWL_DEBUG_DROP(mvm, "Bad decryption results 0x%08x\n",
                       rx_pkt_status);
        kfree_skb(skb);
        return 0;
    }

    if ((unlikely(phy_info->cfg_phy_cnt > 20))) {
        IWL_DEBUG_DROP(mvm, "dsp size out of range [0,20]: %d\n",
                       phy_info->cfg_phy_cnt);
        kfree_skb(skb);
        return 0;
    }

    /*
     * Keep packets with CRC errors (and with overrun) for monitor mode
     * (otherwise the firmware discards them) but mark them as bad.
     */
    if (!(rx_pkt_status & RX_MPDU_RES_STATUS_CRC_OK) ||
            !(rx_pkt_status & RX_MPDU_RES_STATUS_OVERRUN_OK)) {
        IWL_DEBUG_RX(mvm, "Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status);
        rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
    }

    /* This will be used in several places later */
    rate_n_flags = le32_to_cpu(phy_info->rate_n_flags);

    /* rx_status carries information about the packet to mac80211 */
    rx_status->mactime = le64_to_cpu(phy_info->timestamp);
    rx_status->device_timestamp = le32_to_cpu(phy_info->system_timestamp);
    rx_status->band =
        (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
        IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
    rx_status->freq =
        ieee80211_channel_to_frequency(le16_to_cpu(phy_info->channel),
                                       rx_status->band);
    /*
     * TSF as indicated by the fw is at INA time, but mac80211 expects the
     * TSF at the beginning of the MPDU.
     */
    /*rx_status->flag |= RX_FLAG_MACTIME_MPDU;*/

    iwl_mvm_get_signal_strength(mvm, phy_info, rx_status);

    IWL_DEBUG_STATS_LIMIT(mvm, "Rssi %d, TSF %llu\n", rx_status->signal,
                          (unsigned long long)rx_status->mactime);

    rcu_read_lock();
    /*
     * We have tx blocked stations (with CS bit). If we heard frames from
     * a blocked station on a new channel we can TX to it again.
     */
    if (unlikely(mvm->csa_tx_block_bcn_timeout)) {
        sta = ieee80211_find_sta(
                  rcu_dereference(mvm->csa_tx_blocked_vif), hdr->addr2);
        if (sta)
            iwl_mvm_sta_modify_disable_tx_ap(mvm, sta, false);
    }

    /* This is fine since we don't support multiple AP interfaces */
    sta = ieee80211_find_sta_by_ifaddr(mvm->hw, hdr->addr2, NULL);
    if (sta) {
        struct iwl_mvm_sta *mvmsta;
        mvmsta = iwl_mvm_sta_from_mac80211(sta);
        rs_update_last_rssi(mvm, &mvmsta->lq_sta, rx_status);

        if (iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_RSSI) &&
                ieee80211_is_beacon(hdr->frame_control)) {
            struct iwl_fw_dbg_trigger_tlv *trig;
            struct iwl_fw_dbg_trigger_low_rssi *rssi_trig;
            bool trig_check;
            s32 rssi;

            trig = iwl_fw_dbg_get_trigger(mvm->fw,
                                          FW_DBG_TRIGGER_RSSI);
            rssi_trig = (void *)trig->data;
            rssi = le32_to_cpu(rssi_trig->rssi);

            trig_check =
                iwl_fw_dbg_trigger_check_stop(mvm, mvmsta->vif,
                                              trig);
            if (trig_check && rx_status->signal < rssi)
                iwl_mvm_fw_dbg_collect_trig(mvm, trig, NULL);
        }
    }

    rcu_read_unlock();

    /* set the preamble flag if appropriate */
    if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_SHORT_PREAMBLE))
        rx_status->flag |= RX_FLAG_SHORTPRE;

    if (phy_info->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_AGG)) {
        /*
         * We know which subframes of an A-MPDU belong
         * together since we get a single PHY response
         * from the firmware for all of them
         */
        rx_status->flag |= RX_FLAG_AMPDU_DETAILS;
        rx_status->ampdu_reference = mvm->ampdu_ref;
    }

    /* Set up the HT phy flags */
    switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) {
    case RATE_MCS_CHAN_WIDTH_20:
        break;
    case RATE_MCS_CHAN_WIDTH_40:
        rx_status->flag |= RX_FLAG_40MHZ;
        break;
    case RATE_MCS_CHAN_WIDTH_80:
        rx_status->vht_flag |= RX_VHT_FLAG_80MHZ;
        break;
    case RATE_MCS_CHAN_WIDTH_160:
        rx_status->vht_flag |= RX_VHT_FLAG_160MHZ;
        break;
    }
    if (rate_n_flags & RATE_MCS_SGI_MSK)
        rx_status->flag |= RX_FLAG_SHORT_GI;
    if (rate_n_flags & RATE_HT_MCS_GF_MSK)
        rx_status->flag |= RX_FLAG_HT_GF;
    if (rate_n_flags & RATE_MCS_LDPC_MSK)
        rx_status->flag |= RX_FLAG_LDPC;
    if (rate_n_flags & RATE_MCS_HT_MSK) {
        u8 stbc = (rate_n_flags & RATE_MCS_HT_STBC_MSK) >>
                  RATE_MCS_STBC_POS;
        rx_status->flag |= RX_FLAG_HT;
        rx_status->rate_idx = rate_n_flags & RATE_HT_MCS_INDEX_MSK;
        rx_status->flag |= stbc << RX_FLAG_STBC_SHIFT;
    } else if (rate_n_flags & RATE_MCS_VHT_MSK) {
Esempio n. 23
0
static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
				struct iwl_nvm_data *data,
				const __le16 * const nvm_ch_flags,
				bool lar_supported)
{
	int ch_idx;
	int n_channels = 0;
	struct ieee80211_channel *channel;
	u16 ch_flags;
	bool is_5ghz;
	int num_of_ch, num_2ghz_channels;
	const u8 *nvm_chan;

	if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
		num_of_ch = IWL_NUM_CHANNELS;
		nvm_chan = &iwl_nvm_channels[0];
		num_2ghz_channels = NUM_2GHZ_CHANNELS;
	} else {
		num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
		nvm_chan = &iwl_nvm_channels_family_8000[0];
		num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000;
	}

	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);

		if (ch_idx >= num_2ghz_channels &&
		    !data->sku_cap_band_52GHz_enable)
			continue;

		if (ch_flags & NVM_CHANNEL_160MHZ)
			data->vht160_supported = true;

		if (!lar_supported && !(ch_flags & NVM_CHANNEL_VALID)) {
			/*
			 * Channels might become valid later if lar is
			 * supported, hence we still want to add them to
			 * the list of supported channels to cfg80211.
			 */
			IWL_DEBUG_EEPROM(dev,
					 "Ch. %d Flags %x [%sGHz] - No traffic\n",
					 nvm_chan[ch_idx],
					 ch_flags,
					 (ch_idx >= num_2ghz_channels) ?
					 "5.2" : "2.4");
			continue;
		}

		channel = &data->channels[n_channels];
		n_channels++;

		channel->hw_value = nvm_chan[ch_idx];
		channel->band = (ch_idx < num_2ghz_channels) ?
				NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
		channel->center_freq =
			ieee80211_channel_to_frequency(
				channel->hw_value, channel->band);

		/* Initialize regulatory-based run-time data */

		/*
		 * Default value - highest tx power value.  max_power
		 * is not used in mvm, and is used for backwards compatibility
		 */
		channel->max_power = IWL_DEFAULT_MAX_TX_POWER;
		is_5ghz = channel->band == NL80211_BAND_5GHZ;

		/* don't put limitations in case we're using LAR */
		if (!lar_supported)
			channel->flags = iwl_get_channel_flags(nvm_chan[ch_idx],
							       ch_idx, is_5ghz,
							       ch_flags, cfg);
		else
			channel->flags = 0;

		IWL_DEBUG_EEPROM(dev,
				 "Ch. %d [%sGHz] flags 0x%x %s%s%s%s%s%s%s%s%s%s(%ddBm): Ad-Hoc %ssupported\n",
				 channel->hw_value,
				 is_5ghz ? "5.2" : "2.4",
				 ch_flags,
				 CHECK_AND_PRINT_I(VALID),
				 CHECK_AND_PRINT_I(IBSS),
				 CHECK_AND_PRINT_I(ACTIVE),
				 CHECK_AND_PRINT_I(RADAR),
				 CHECK_AND_PRINT_I(INDOOR_ONLY),
				 CHECK_AND_PRINT_I(GO_CONCURRENT),
				 CHECK_AND_PRINT_I(WIDE),
				 CHECK_AND_PRINT_I(40MHZ),
				 CHECK_AND_PRINT_I(80MHZ),
				 CHECK_AND_PRINT_I(160MHZ),
				 channel->max_power,
				 ((ch_flags & NVM_CHANNEL_IBSS) &&
				  !(ch_flags & NVM_CHANNEL_RADAR))
					? "" : "not ");
	}

	return n_channels;
}
Esempio n. 24
0
static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
				struct iwl_nvm_data *data,
				const __le16 * const nvm_ch_flags)
{
	int ch_idx;
	int n_channels = 0;
	struct ieee80211_channel *channel;
	u16 ch_flags;
	bool is_5ghz;
	int num_of_ch, num_2ghz_channels;
	const u8 *nvm_chan;

	if (cfg->device_family != IWL_DEVICE_FAMILY_8000) {
		num_of_ch = IWL_NUM_CHANNELS;
		nvm_chan = &iwl_nvm_channels[0];
		num_2ghz_channels = NUM_2GHZ_CHANNELS;
	} else {
		num_of_ch = IWL_NUM_CHANNELS_FAMILY_8000;
		nvm_chan = &iwl_nvm_channels_family_8000[0];
		num_2ghz_channels = NUM_2GHZ_CHANNELS_FAMILY_8000;
	}

	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);

		if (ch_idx >= num_2ghz_channels &&
		    !data->sku_cap_band_52GHz_enable)
			ch_flags &= ~NVM_CHANNEL_VALID;

		if (!(ch_flags & NVM_CHANNEL_VALID)) {
			IWL_DEBUG_EEPROM(dev,
					 "Ch. %d Flags %x [%sGHz] - No traffic\n",
					 nvm_chan[ch_idx],
					 ch_flags,
					 (ch_idx >= num_2ghz_channels) ?
					 "5.2" : "2.4");
			continue;
		}

		channel = &data->channels[n_channels];
		n_channels++;

		channel->hw_value = nvm_chan[ch_idx];
		channel->band = (ch_idx < num_2ghz_channels) ?
				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
		channel->center_freq =
			ieee80211_channel_to_frequency(
				channel->hw_value, channel->band);

		/* TODO: Need to be dependent to the NVM */
		channel->flags = IEEE80211_CHAN_NO_HT40;
		if (ch_idx < num_2ghz_channels &&
		    (ch_flags & NVM_CHANNEL_40MHZ)) {
			if (nvm_chan[ch_idx] <= LAST_2GHZ_HT_PLUS)
				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
			if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS)
				channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
		} else if (nvm_chan[ch_idx] <= LAST_5GHZ_HT &&
			   (ch_flags & NVM_CHANNEL_40MHZ)) {
			if ((ch_idx - num_2ghz_channels) % 2 == 0)
				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
			else
				channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
		}
		if (!(ch_flags & NVM_CHANNEL_80MHZ))
			channel->flags |= IEEE80211_CHAN_NO_80MHZ;
		if (!(ch_flags & NVM_CHANNEL_160MHZ))
			channel->flags |= IEEE80211_CHAN_NO_160MHZ;

		if (!(ch_flags & NVM_CHANNEL_IBSS))
			channel->flags |= IEEE80211_CHAN_NO_IR;

		if (!(ch_flags & NVM_CHANNEL_ACTIVE))
			channel->flags |= IEEE80211_CHAN_NO_IR;

		if (ch_flags & NVM_CHANNEL_RADAR)
			channel->flags |= IEEE80211_CHAN_RADAR;

		/* Initialize regulatory-based run-time data */

		/*
		 * Default value - highest tx power value.  max_power
		 * is not used in mvm, and is used for backwards compatibility
		 */
		channel->max_power = DEFAULT_MAX_TX_POWER;
		is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
		IWL_DEBUG_EEPROM(dev,
				 "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
				 channel->hw_value,
				 is_5ghz ? "5.2" : "2.4",
				 CHECK_AND_PRINT_I(VALID),
				 CHECK_AND_PRINT_I(IBSS),
				 CHECK_AND_PRINT_I(ACTIVE),
				 CHECK_AND_PRINT_I(RADAR),
				 CHECK_AND_PRINT_I(WIDE),
				 CHECK_AND_PRINT_I(DFS),
				 ch_flags,
				 channel->max_power,
				 ((ch_flags & NVM_CHANNEL_IBSS) &&
				  !(ch_flags & NVM_CHANNEL_RADAR))
					? "" : "not ");
	}

	return n_channels;
}
Esempio n. 25
0
static int prism2_scan(struct wiphy *wiphy,
		       struct cfg80211_scan_request *request)
{
	struct net_device *dev;
	struct prism2_wiphy_private *priv = wiphy_priv(wiphy);
	struct wlandevice *wlandev;
	struct p80211msg_dot11req_scan msg1;
	struct p80211msg_dot11req_scan_results msg2;
	struct cfg80211_bss *bss;
	struct cfg80211_scan_info info = {};

	int result;
	int err = 0;
	int numbss = 0;
	int i = 0;
	u8 ie_buf[46];
	int ie_len;

	if (!request)
		return -EINVAL;

	dev = request->wdev->netdev;
	wlandev = dev->ml_priv;

	if (priv->scan_request && priv->scan_request != request)
		return -EBUSY;

	if (wlandev->macmode == WLAN_MACMODE_ESS_AP) {
		netdev_err(dev, "Can't scan in AP mode\n");
		return -EOPNOTSUPP;
	}

	priv->scan_request = request;

	memset(&msg1, 0x00, sizeof(msg1));
	msg1.msgcode = DIDMSG_DOT11REQ_SCAN;
	msg1.bsstype.data = P80211ENUM_bsstype_any;

	memset(&msg1.bssid.data.data, 0xFF, sizeof(msg1.bssid.data.data));
	msg1.bssid.data.len = 6;

	if (request->n_ssids > 0) {
		msg1.scantype.data = P80211ENUM_scantype_active;
		msg1.ssid.data.len = request->ssids->ssid_len;
		memcpy(msg1.ssid.data.data,
		       request->ssids->ssid, request->ssids->ssid_len);
	} else {
		msg1.scantype.data = 0;
	}
	msg1.probedelay.data = 0;

	for (i = 0;
		(i < request->n_channels) && i < ARRAY_SIZE(prism2_channels);
		i++)
		msg1.channellist.data.data[i] =
			ieee80211_frequency_to_channel(
				request->channels[i]->center_freq);
	msg1.channellist.data.len = request->n_channels;

	msg1.maxchanneltime.data = 250;
	msg1.minchanneltime.data = 200;

	result = p80211req_dorequest(wlandev, (u8 *)&msg1);
	if (result) {
		err = prism2_result2err(msg1.resultcode.data);
		goto exit;
	}
	/* Now retrieve scan results */
	numbss = msg1.numbss.data;

	for (i = 0; i < numbss; i++) {
		int freq;

		memset(&msg2, 0, sizeof(msg2));
		msg2.msgcode = DIDMSG_DOT11REQ_SCAN_RESULTS;
		msg2.bssindex.data = i;

		result = p80211req_dorequest(wlandev, (u8 *)&msg2);
		if ((result != 0) ||
		    (msg2.resultcode.data != P80211ENUM_resultcode_success)) {
			break;
		}

		ie_buf[0] = WLAN_EID_SSID;
		ie_buf[1] = msg2.ssid.data.len;
		ie_len = ie_buf[1] + 2;
		memcpy(&ie_buf[2], &msg2.ssid.data.data, msg2.ssid.data.len);
		freq = ieee80211_channel_to_frequency(msg2.dschannel.data,
						      NL80211_BAND_2GHZ);
		bss = cfg80211_inform_bss(wiphy,
			ieee80211_get_channel(wiphy, freq),
			CFG80211_BSS_FTYPE_UNKNOWN,
			(const u8 *)&msg2.bssid.data.data,
			msg2.timestamp.data, msg2.capinfo.data,
			msg2.beaconperiod.data,
			ie_buf,
			ie_len,
			(msg2.signal.data - 65536) * 100, /* Conversion to signed type */
			GFP_KERNEL
		);

		if (!bss) {
			err = -ENOMEM;
			goto exit;
		}

		cfg80211_put_bss(wiphy, bss);
	}

	if (result)
		err = prism2_result2err(msg2.resultcode.data);

exit:
	info.aborted = !!(err);
	cfg80211_scan_done(request, &info);
	priv->scan_request = NULL;
	return err;
}
Esempio n. 26
0
int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
				 struct ieee802_11_elems *elems,
				 enum nl80211_band current_band,
				 u32 sta_flags, u8 *bssid,
				 struct ieee80211_csa_ie *csa_ie)
{
	enum nl80211_band new_band;
	int new_freq;
	u8 new_chan_no;
	struct ieee80211_channel *new_chan;
	struct cfg80211_chan_def new_vht_chandef = {};
	const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
	const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
	int secondary_channel_offset = -1;

	sec_chan_offs = elems->sec_chan_offs;
	wide_bw_chansw_ie = elems->wide_bw_chansw_ie;

	if (sta_flags & (IEEE80211_STA_DISABLE_HT |
			 IEEE80211_STA_DISABLE_40MHZ)) {
		sec_chan_offs = NULL;
		wide_bw_chansw_ie = NULL;
	}

	if (sta_flags & IEEE80211_STA_DISABLE_VHT)
		wide_bw_chansw_ie = NULL;

	if (elems->ext_chansw_ie) {
		if (!ieee80211_operating_class_to_band(
				elems->ext_chansw_ie->new_operating_class,
				&new_band)) {
			sdata_info(sdata,
				   "cannot understand ECSA IE operating class %d, disconnecting\n",
				   elems->ext_chansw_ie->new_operating_class);
			return -EINVAL;
		}
		new_chan_no = elems->ext_chansw_ie->new_ch_num;
		csa_ie->count = elems->ext_chansw_ie->count;
		csa_ie->mode = elems->ext_chansw_ie->mode;
	} else if (elems->ch_switch_ie) {
		new_band = current_band;
		new_chan_no = elems->ch_switch_ie->new_ch_num;
		csa_ie->count = elems->ch_switch_ie->count;
		csa_ie->mode = elems->ch_switch_ie->mode;
	} else {
		/* nothing here we understand */
		return 1;
	}

	/* Mesh Channel Switch Parameters Element */
	if (elems->mesh_chansw_params_ie) {
		csa_ie->ttl = elems->mesh_chansw_params_ie->mesh_ttl;
		csa_ie->mode = elems->mesh_chansw_params_ie->mesh_flags;
		csa_ie->pre_value = le16_to_cpu(
				elems->mesh_chansw_params_ie->mesh_pre_value);
	}

	new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
	new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
	if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
		sdata_info(sdata,
			   "BSS %pM switches to unsupported channel (%d MHz), disconnecting\n",
			   bssid, new_freq);
		return -EINVAL;
	}

	if (sec_chan_offs) {
		secondary_channel_offset = sec_chan_offs->sec_chan_offs;
	} else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) {
		/* If the secondary channel offset IE is not present,
		 * we can't know what's the post-CSA offset, so the
		 * best we can do is use 20MHz.
		*/
		secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
	}

	switch (secondary_channel_offset) {
	default:
		/* secondary_channel_offset was present but is invalid */
	case IEEE80211_HT_PARAM_CHA_SEC_NONE:
		cfg80211_chandef_create(&csa_ie->chandef, new_chan,
					NL80211_CHAN_HT20);
		break;
	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
		cfg80211_chandef_create(&csa_ie->chandef, new_chan,
					NL80211_CHAN_HT40PLUS);
		break;
	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
		cfg80211_chandef_create(&csa_ie->chandef, new_chan,
					NL80211_CHAN_HT40MINUS);
		break;
	case -1:
		cfg80211_chandef_create(&csa_ie->chandef, new_chan,
					NL80211_CHAN_NO_HT);
		/* keep width for 5/10 MHz channels */
		switch (sdata->vif.bss_conf.chandef.width) {
		case NL80211_CHAN_WIDTH_5:
		case NL80211_CHAN_WIDTH_10:
			csa_ie->chandef.width =
				sdata->vif.bss_conf.chandef.width;
			break;
		default:
			break;
		}
		break;
	}

	if (wide_bw_chansw_ie) {
		new_vht_chandef.chan = new_chan;
		new_vht_chandef.center_freq1 =
			ieee80211_channel_to_frequency(
				wide_bw_chansw_ie->new_center_freq_seg0,
				new_band);

		switch (wide_bw_chansw_ie->new_channel_width) {
		default:
			/* hmmm, ignore VHT and use HT if present */
		case IEEE80211_VHT_CHANWIDTH_USE_HT:
			new_vht_chandef.chan = NULL;
			break;
		case IEEE80211_VHT_CHANWIDTH_80MHZ:
			new_vht_chandef.width = NL80211_CHAN_WIDTH_80;
			break;
		case IEEE80211_VHT_CHANWIDTH_160MHZ:
			new_vht_chandef.width = NL80211_CHAN_WIDTH_160;
			break;
		case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
			/* field is otherwise reserved */
			new_vht_chandef.center_freq2 =
				ieee80211_channel_to_frequency(
					wide_bw_chansw_ie->new_center_freq_seg1,
					new_band);
			new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
			break;
		}
		if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
		    new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
			ieee80211_chandef_downgrade(&new_vht_chandef);
		if (sta_flags & IEEE80211_STA_DISABLE_160MHZ &&
		    new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
			ieee80211_chandef_downgrade(&new_vht_chandef);
		if (sta_flags & IEEE80211_STA_DISABLE_40MHZ &&
		    new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
			ieee80211_chandef_downgrade(&new_vht_chandef);
	}

	/* if VHT data is there validate & use it */
	if (new_vht_chandef.chan) {
		if (!cfg80211_chandef_compatible(&new_vht_chandef,
						 &csa_ie->chandef)) {
			sdata_info(sdata,
				   "BSS %pM: CSA has inconsistent channel data, disconnecting\n",
				   bssid);
			return -EINVAL;
		}
		csa_ie->chandef = new_vht_chandef;
	}

	return 0;
}
Esempio n. 27
0
/**
 * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
 */
int iwl_init_geos(struct iwl_priv *priv)
{
	struct iwl_channel_info *ch;
	struct ieee80211_supported_band *sband;
	struct ieee80211_channel *channels;
	struct ieee80211_channel *geo_ch;
	struct ieee80211_rate *rates;
	int i = 0;
	s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;

	if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
	    priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
		IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n");
		set_bit(STATUS_GEO_CONFIGURED, &priv->status);
		return 0;
	}

	channels = kcalloc(priv->channel_count,
			   sizeof(struct ieee80211_channel), GFP_KERNEL);
	if (!channels)
		return -ENOMEM;

	rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
			GFP_KERNEL);
	if (!rates) {
		kfree(channels);
		return -ENOMEM;
	}

	/* 5.2GHz channels start after the 2.4GHz channels */
	sband = &priv->bands[IEEE80211_BAND_5GHZ];
	sband->channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
	/* just OFDM */
	sband->bitrates = &rates[IWL_FIRST_OFDM_RATE];
	sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE;

	if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
		iwl_init_ht_hw_capab(priv, &sband->ht_cap,
					 IEEE80211_BAND_5GHZ);

	sband = &priv->bands[IEEE80211_BAND_2GHZ];
	sband->channels = channels;
	/* OFDM & CCK */
	sband->bitrates = rates;
	sband->n_bitrates = IWL_RATE_COUNT_LEGACY;

	if (hw_params(priv).sku & EEPROM_SKU_CAP_11N_ENABLE)
		iwl_init_ht_hw_capab(priv, &sband->ht_cap,
					 IEEE80211_BAND_2GHZ);

	priv->ieee_channels = channels;
	priv->ieee_rates = rates;

	for (i = 0;  i < priv->channel_count; i++) {
		ch = &priv->channel_info[i];

		/* FIXME: might be removed if scan is OK */
		if (!is_channel_valid(ch))
			continue;

		sband =  &priv->bands[ch->band];

		geo_ch = &sband->channels[sband->n_channels++];

		geo_ch->center_freq =
			ieee80211_channel_to_frequency(ch->channel, ch->band);
		geo_ch->max_power = ch->max_power_avg;
		geo_ch->max_antenna_gain = 0xff;
		geo_ch->hw_value = ch->channel;

		if (is_channel_valid(ch)) {
			if (!(ch->flags & EEPROM_CHANNEL_IBSS))
				geo_ch->flags |= IEEE80211_CHAN_NO_IBSS;

			if (!(ch->flags & EEPROM_CHANNEL_ACTIVE))
				geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN;

			if (ch->flags & EEPROM_CHANNEL_RADAR)
				geo_ch->flags |= IEEE80211_CHAN_RADAR;

			geo_ch->flags |= ch->ht40_extension_channel;

			if (ch->max_power_avg > max_tx_power)
				max_tx_power = ch->max_power_avg;
		} else {
			geo_ch->flags |= IEEE80211_CHAN_DISABLED;
		}

		IWL_DEBUG_INFO(priv, "Channel %d Freq=%d[%sGHz] %s flag=0x%X\n",
				ch->channel, geo_ch->center_freq,
				is_channel_a_band(ch) ?  "5.2" : "2.4",
				geo_ch->flags & IEEE80211_CHAN_DISABLED ?
				"restricted" : "valid",
				 geo_ch->flags);
	}

	priv->tx_power_device_lmt = max_tx_power;
	priv->tx_power_user_lmt = max_tx_power;
	priv->tx_power_next = max_tx_power;

	if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
	     hw_params(priv).sku & EEPROM_SKU_CAP_BAND_52GHZ) {
		IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
			"Please send your %s to maintainer.\n",
			trans(priv)->hw_id_str);
		hw_params(priv).sku &= ~EEPROM_SKU_CAP_BAND_52GHZ;
	}

	IWL_INFO(priv, "Tunable channels: %d 802.11bg, %d 802.11a channels\n",
		   priv->bands[IEEE80211_BAND_2GHZ].n_channels,
		   priv->bands[IEEE80211_BAND_5GHZ].n_channels);

	set_bit(STATUS_GEO_CONFIGURED, &priv->status);

	return 0;
}
Esempio n. 28
0
File: cfg.c Progetto: 020gzh/linux
/* Called after firmware is initialised */
int orinoco_wiphy_register(struct wiphy *wiphy)
{
	struct orinoco_private *priv = wiphy_priv(wiphy);
	int i, channels = 0;

	if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
		wiphy->max_scan_ssids = 1;
	else
		wiphy->max_scan_ssids = 0;

	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);

	/* TODO: should we set if we only have demo ad-hoc?
	 *       (priv->has_port3)
	 */
	if (priv->has_ibss)
		wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);

	if (!priv->broken_monitor || force_monitor)
		wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);

	priv->band.bitrates = orinoco_rates;
	priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);

	/* Only support channels allowed by the card EEPROM */
	for (i = 0; i < NUM_CHANNELS; i++) {
		if (priv->channel_mask & (1 << i)) {
			priv->channels[i].center_freq =
				ieee80211_channel_to_frequency(i + 1,
							   IEEE80211_BAND_2GHZ);
			channels++;
		}
	}
	priv->band.channels = priv->channels;
	priv->band.n_channels = channels;

	wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;

	i = 0;
	if (priv->has_wep) {
		priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
		i++;

		if (priv->has_big_wep) {
			priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
			i++;
		}
	}
	if (priv->has_wpa) {
		priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
		i++;
	}
	wiphy->cipher_suites = priv->cipher_suites;
	wiphy->n_cipher_suites = i;

	wiphy->rts_threshold = priv->rts_thresh;
	if (!priv->has_mwo)
		wiphy->frag_threshold = priv->frag_thresh + 1;
	wiphy->retry_short = priv->short_retry_limit;
	wiphy->retry_long = priv->long_retry_limit;

	return wiphy_register(wiphy);
}
Esempio n. 29
0
struct ieee80211_regdomain *
iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg,
		       int num_of_ch, __le32 *channels, u16 fw_mcc)
{
	int ch_idx;
	u16 ch_flags, prev_ch_flags = 0;
	const u8 *nvm_chan = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
			     iwl_nvm_channels_family_8000 : iwl_nvm_channels;
	struct ieee80211_regdomain *regd;
	int size_of_regd;
	struct ieee80211_reg_rule *rule;
	enum nl80211_band band;
	int center_freq, prev_center_freq = 0;
	int valid_rules = 0;
	bool new_rule;
	int max_num_ch = cfg->device_family == IWL_DEVICE_FAMILY_8000 ?
			 IWL_NUM_CHANNELS_FAMILY_8000 : IWL_NUM_CHANNELS;

	if (WARN_ON_ONCE(num_of_ch > NL80211_MAX_SUPP_REG_RULES))
		return ERR_PTR(-EINVAL);

	if (WARN_ON(num_of_ch > max_num_ch))
		num_of_ch = max_num_ch;

	IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
		      num_of_ch);

	/* build a regdomain rule for every valid channel */
	size_of_regd =
		sizeof(struct ieee80211_regdomain) +
		num_of_ch * sizeof(struct ieee80211_reg_rule);

	regd = kzalloc(size_of_regd, GFP_KERNEL);
	if (!regd)
		return ERR_PTR(-ENOMEM);

	for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) {
		ch_flags = (u16)__le32_to_cpup(channels + ch_idx);
		band = (ch_idx < NUM_2GHZ_CHANNELS) ?
		       NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
		center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx],
							     band);
		new_rule = false;

		if (!(ch_flags & NVM_CHANNEL_VALID)) {
			IWL_DEBUG_DEV(dev, IWL_DL_LAR,
				      "Ch. %d Flags %x [%sGHz] - No traffic\n",
				      nvm_chan[ch_idx],
				      ch_flags,
				      (ch_idx >= NUM_2GHZ_CHANNELS) ?
				      "5.2" : "2.4");
			continue;
		}

		/* we can't continue the same rule */
		if (ch_idx == 0 || prev_ch_flags != ch_flags ||
		    center_freq - prev_center_freq > 20) {
			valid_rules++;
			new_rule = true;
		}

		rule = &regd->reg_rules[valid_rules - 1];

		if (new_rule)
			rule->freq_range.start_freq_khz =
						MHZ_TO_KHZ(center_freq - 10);

		rule->freq_range.end_freq_khz = MHZ_TO_KHZ(center_freq + 10);

		/* this doesn't matter - not used by FW */
		rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
		rule->power_rule.max_eirp =
			DBM_TO_MBM(IWL_DEFAULT_MAX_TX_POWER);

		rule->flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
							  ch_flags, cfg);

		/* rely on auto-calculation to merge BW of contiguous chans */
		rule->flags |= NL80211_RRF_AUTO_BW;
		rule->freq_range.max_bandwidth_khz = 0;

		prev_ch_flags = ch_flags;
		prev_center_freq = center_freq;

		IWL_DEBUG_DEV(dev, IWL_DL_LAR,
			      "Ch. %d [%sGHz] %s%s%s%s%s%s%s%s%s(0x%02x): Ad-Hoc %ssupported\n",
			      center_freq,
			      band == NL80211_BAND_5GHZ ? "5.2" : "2.4",
			      CHECK_AND_PRINT_I(VALID),
			      CHECK_AND_PRINT_I(ACTIVE),
			      CHECK_AND_PRINT_I(RADAR),
			      CHECK_AND_PRINT_I(WIDE),
			      CHECK_AND_PRINT_I(40MHZ),
			      CHECK_AND_PRINT_I(80MHZ),
			      CHECK_AND_PRINT_I(160MHZ),
			      CHECK_AND_PRINT_I(INDOOR_ONLY),
			      CHECK_AND_PRINT_I(GO_CONCURRENT),
			      ch_flags,
			      ((ch_flags & NVM_CHANNEL_ACTIVE) &&
			       !(ch_flags & NVM_CHANNEL_RADAR))
					 ? "" : "not ");
	}

	regd->n_reg_rules = valid_rules;

	/* set alpha2 from FW. */
	regd->alpha2[0] = fw_mcc >> 8;
	regd->alpha2[1] = fw_mcc & 0xff;

	return regd;
}
Esempio n. 30
0
static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg,
				struct iwl_nvm_data *data,
				const __le16 * const nvm_ch_flags)
{
	int ch_idx;
	int n_channels = 0;
	struct ieee80211_channel *channel;
	u16 ch_flags;
	bool is_5ghz;

	for (ch_idx = 0; ch_idx < IWL_NUM_CHANNELS; ch_idx++) {
		ch_flags = __le16_to_cpup(nvm_ch_flags + ch_idx);
		if (!(ch_flags & NVM_CHANNEL_VALID)) {
			IWL_DEBUG_EEPROM(dev,
					 "Ch. %d Flags %x [%sGHz] - No traffic\n",
					 iwl_nvm_channels[ch_idx],
					 ch_flags,
					 (ch_idx >= NUM_2GHZ_CHANNELS) ?
					 "5.2" : "2.4");
			continue;
		}

		channel = &data->channels[n_channels];
		n_channels++;

		channel->hw_value = iwl_nvm_channels[ch_idx];
		channel->band = (ch_idx < NUM_2GHZ_CHANNELS) ?
				IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
		channel->center_freq =
			ieee80211_channel_to_frequency(
				channel->hw_value, channel->band);

		/* TODO: Need to be dependent to the NVM */
		channel->flags = IEEE80211_CHAN_NO_HT40;
		if (ch_idx < NUM_2GHZ_CHANNELS &&
		    (ch_flags & NVM_CHANNEL_40MHZ)) {
			if (iwl_nvm_channels[ch_idx] <= LAST_2GHZ_HT_PLUS)
				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
			if (iwl_nvm_channels[ch_idx] >= FIRST_2GHZ_HT_MINUS)
				channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
		} else if (iwl_nvm_channels[ch_idx] <= LAST_5GHZ_HT &&
			   (ch_flags & NVM_CHANNEL_40MHZ)) {
			if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0)
				channel->flags &= ~IEEE80211_CHAN_NO_HT40PLUS;
			else
				channel->flags &= ~IEEE80211_CHAN_NO_HT40MINUS;
		}
		if (!(ch_flags & NVM_CHANNEL_80MHZ))
			channel->flags |= IEEE80211_CHAN_NO_80MHZ;
		if (!(ch_flags & NVM_CHANNEL_160MHZ))
			channel->flags |= IEEE80211_CHAN_NO_160MHZ;

		if (!(ch_flags & NVM_CHANNEL_IBSS))
			channel->flags |= IEEE80211_CHAN_NO_IBSS;

		if (!(ch_flags & NVM_CHANNEL_ACTIVE))
			channel->flags |= IEEE80211_CHAN_PASSIVE_SCAN;

		if (ch_flags & NVM_CHANNEL_RADAR)
			channel->flags |= IEEE80211_CHAN_RADAR;

		/* Initialize regulatory-based run-time data */

		/* TODO: read the real value from the NVM */
		channel->max_power = 0;
		is_5ghz = channel->band == IEEE80211_BAND_5GHZ;
		IWL_DEBUG_EEPROM(dev,
				 "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n",
				 channel->hw_value,
				 is_5ghz ? "5.2" : "2.4",
				 CHECK_AND_PRINT_I(VALID),
				 CHECK_AND_PRINT_I(IBSS),
				 CHECK_AND_PRINT_I(ACTIVE),
				 CHECK_AND_PRINT_I(RADAR),
				 CHECK_AND_PRINT_I(WIDE),
				 CHECK_AND_PRINT_I(DFS),
				 ch_flags,
				 channel->max_power,
				 ((ch_flags & NVM_CHANNEL_IBSS) &&
				  !(ch_flags & NVM_CHANNEL_RADAR))
					? "" : "not ");
	}

	return n_channels;
}