Merge tag 'mac80211-next-for-net-next-2020-02-14' of git://git.kernel.org/pub/scm...
[platform/kernel/linux-rpi.git] / net / mac80211 / util.c
index 32a7a53..ea7d277 100644 (file)
@@ -6,7 +6,7 @@
  * 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
  */
@@ -39,7 +39,6 @@ const void *const mac80211_wiphy_privid = &mac80211_wiphy_privid;
 struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
 {
        struct ieee80211_local *local;
-       BUG_ON(!wiphy);
 
        local = wiphy_priv(wiphy);
        return &local->hw;
@@ -891,6 +890,51 @@ void ieee80211_queue_delayed_work(struct ieee80211_hw *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,
@@ -950,6 +994,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                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
@@ -1063,16 +1108,22 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                                elem_parse_failed = true;
                        break;
                case WLAN_EID_VHT_OPERATION:
-                       if (elen >= sizeof(struct ieee80211_vht_operation))
+                       if (elen >= sizeof(struct ieee80211_vht_operation)) {
                                elems->vht_operation = (void *)pos;
-                       else
-                               elem_parse_failed = true;
+                               if (calc_crc)
+                                       crc = crc32_be(crc, pos - 2, elen + 2);
+                               break;
+                       }
+                       elem_parse_failed = true;
                        break;
                case WLAN_EID_OPMODE_NOTIF:
-                       if (elen > 0)
+                       if (elen > 0) {
                                elems->opmode_notif = pos;
-                       else
-                               elem_parse_failed = true;
+                               if (calc_crc)
+                                       crc = crc32_be(crc, pos - 2, elen + 2);
+                               break;
+                       }
+                       elem_parse_failed = true;
                        break;
                case WLAN_EID_MESH_ID:
                        elems->mesh_id = pos;
@@ -1220,34 +1271,14 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        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;
@@ -2987,10 +3018,22 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
        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) &
@@ -3018,10 +3061,10 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw,
                        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;
                        }