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); } }
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; }
/* * 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; }
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; } }
/** * 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; }
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 */ } } }
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; }
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 */ }
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); }
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; }
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"); }
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); } } }
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); }
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; } }
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; } }
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"); } } }
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)); } }
/** * 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; } }
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; }
/* * 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) {
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; }
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; }
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; }
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; }
/** * 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; }
/* 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); }
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 = ®d->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; }
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; }