* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2019 Intel Corporation
+ * Copyright (C) 2018-2020 Intel Corporation
*
* utilities for mac80211
*/
struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
{
struct ieee80211_local *local;
- BUG_ON(!wiphy);
local = wiphy_priv(wiphy);
return &local->hw;
}
EXPORT_SYMBOL(ieee80211_queue_delayed_work);
+static void ieee80211_parse_extension_element(u32 *crc,
+ const struct element *elem,
+ struct ieee802_11_elems *elems)
+{
+ const void *data = elem->data + 1;
+ u8 len = elem->datalen - 1;
+
+ switch (elem->data[0]) {
+ case WLAN_EID_EXT_HE_MU_EDCA:
+ if (len == sizeof(*elems->mu_edca_param_set)) {
+ elems->mu_edca_param_set = data;
+ if (crc)
+ *crc = crc32_be(*crc, (void *)elem,
+ elem->datalen + 2);
+ }
+ break;
+ case WLAN_EID_EXT_HE_CAPABILITY:
+ elems->he_cap = data;
+ elems->he_cap_len = len;
+ break;
+ case WLAN_EID_EXT_HE_OPERATION:
+ if (len >= sizeof(*elems->he_operation) &&
+ len == ieee80211_he_oper_size(data) - 1)
+ elems->he_operation = data;
+ break;
+ case WLAN_EID_EXT_UORA:
+ if (len == 1)
+ elems->uora_element = data;
+ break;
+ case WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME:
+ if (len == 3)
+ elems->max_channel_switch_time = data;
+ break;
+ case WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION:
+ if (len == sizeof(*elems->mbssid_config_ie))
+ elems->mbssid_config_ie = data;
+ break;
+ case WLAN_EID_EXT_HE_SPR:
+ if (len >= sizeof(*elems->he_spr) &&
+ len >= ieee80211_he_spr_size(data))
+ elems->he_spr = data;
+ break;
+ }
+}
+
static u32
_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
struct ieee802_11_elems *elems,
case WLAN_EID_CHAN_SWITCH_TIMING:
case WLAN_EID_LINK_ID:
case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+ case WLAN_EID_RSNX:
/*
* not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
* that if the content gets bigger it might be needed more than once
if (elen >= sizeof(*elems->max_idle_period_ie))
elems->max_idle_period_ie = (void *)pos;
break;
+ case WLAN_EID_RSNX:
+ elems->rsnx = pos;
+ elems->rsnx_len = elen;
+ break;
case WLAN_EID_EXTENSION:
- if (pos[0] == WLAN_EID_EXT_HE_MU_EDCA &&
- elen >= (sizeof(*elems->mu_edca_param_set) + 1)) {
- elems->mu_edca_param_set = (void *)&pos[1];
- if (calc_crc)
- crc = crc32_be(crc, pos - 2, elen + 2);
- } else if (pos[0] == WLAN_EID_EXT_HE_CAPABILITY) {
- elems->he_cap = (void *)&pos[1];
- elems->he_cap_len = elen - 1;
- } else if (pos[0] == WLAN_EID_EXT_HE_OPERATION &&
- elen >= sizeof(*elems->he_operation) &&
- elen >= ieee80211_he_oper_size(&pos[1])) {
- elems->he_operation = (void *)&pos[1];
- } else if (pos[0] == WLAN_EID_EXT_UORA && elen >= 1) {
- elems->uora_element = (void *)&pos[1];
- } else if (pos[0] ==
- WLAN_EID_EXT_MAX_CHANNEL_SWITCH_TIME &&
- elen == 4) {
- elems->max_channel_switch_time = pos + 1;
- } else if (pos[0] ==
- WLAN_EID_EXT_MULTIPLE_BSSID_CONFIGURATION &&
- elen == 3) {
- elems->mbssid_config_ie = (void *)&pos[1];
- } else if (pos[0] == WLAN_EID_EXT_HE_SPR &&
- elen >= sizeof(*elems->he_spr) &&
- elen >= ieee80211_he_spr_size(&pos[1])) {
- elems->he_spr = (void *)&pos[1];
- }
+ ieee80211_parse_extension_element(calc_crc ?
+ &crc : NULL,
+ elem, elems);
break;
default:
break;
int cf0, cf1;
int ccfs0, ccfs1, ccfs2;
int ccf0, ccf1;
+ u32 vht_cap;
+ bool support_80_80 = false;
+ bool support_160 = false;
if (!oper || !htop)
return false;
+ vht_cap = hw->wiphy->bands[chandef->chan->band]->vht_cap.cap;
+ support_160 = (vht_cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK |
+ IEEE80211_VHT_CAP_EXT_NSS_BW_MASK));
+ support_80_80 = ((vht_cap &
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) ||
+ (vht_cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ &&
+ vht_cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) ||
+ ((vht_cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) >>
+ IEEE80211_VHT_CAP_EXT_NSS_BW_SHIFT > 1));
ccfs0 = oper->center_freq_seg0_idx;
ccfs1 = oper->center_freq_seg1_idx;
ccfs2 = (le16_to_cpu(htop->operation_mode) &
unsigned int diff;
diff = abs(ccf1 - ccf0);
- if (diff == 8) {
+ if ((diff == 8) && support_160) {
new.width = NL80211_CHAN_WIDTH_160;
new.center_freq1 = cf1;
- } else if (diff > 8) {
+ } else if ((diff > 8) && support_80_80) {
new.width = NL80211_CHAN_WIDTH_80P80;
new.center_freq2 = cf1;
}