Merge tag 'kbuild-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy...
[linux-2.6-microblaze.git] / net / mac80211 / util.c
index dad42d4..53826c6 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-2021 Intel Corporation
+ * Copyright (C) 2018-2022 Intel Corporation
  *
  * utilities for mac80211
  */
@@ -191,7 +191,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
        if (vif) {
                sdata = vif_to_sdata(vif);
                short_preamble = sdata->vif.bss_conf.use_short_preamble;
-               if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+               if (sdata->deflink.operating_11g_mode)
                        erp = rate->flags & IEEE80211_RATE_ERP_G;
                shift = ieee80211_vif_get_shift(vif);
        }
@@ -225,7 +225,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
        if (vif) {
                sdata = vif_to_sdata(vif);
                short_preamble = sdata->vif.bss_conf.use_short_preamble;
-               if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+               if (sdata->deflink.operating_11g_mode)
                        erp = rate->flags & IEEE80211_RATE_ERP_G;
                shift = ieee80211_vif_get_shift(vif);
        }
@@ -268,7 +268,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
        if (vif) {
                sdata = vif_to_sdata(vif);
                short_preamble = sdata->vif.bss_conf.use_short_preamble;
-               if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
+               if (sdata->deflink.operating_11g_mode)
                        erp = rate->flags & IEEE80211_RATE_ERP_G;
                shift = ieee80211_vif_get_shift(vif);
        }
@@ -1022,23 +1022,27 @@ static void ieee80211_parse_extension_element(u32 *crc,
                if (ieee80211_eht_oper_size_ok(data, len))
                        elems->eht_operation = data;
                break;
+       case WLAN_EID_EXT_EHT_MULTI_LINK:
+               if (ieee80211_mle_size_ok(data, len))
+                       elems->multi_link = (void *)data;
+               break;
        }
 }
 
 static u32
-_ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
-                           struct ieee802_11_elems *elems,
-                           u64 filter, u32 crc,
-                           const struct element *check_inherit)
+_ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params,
+                            struct ieee802_11_elems *elems,
+                            const struct element *check_inherit)
 {
        const struct element *elem;
-       bool calc_crc = filter != 0;
+       bool calc_crc = params->filter != 0;
        DECLARE_BITMAP(seen_elems, 256);
+       u32 crc = params->crc;
        const u8 *ie;
 
        bitmap_zero(seen_elems, 256);
 
-       for_each_element(elem, start, len) {
+       for_each_element(elem, params->start, params->len) {
                bool elem_parse_failed;
                u8 id = elem->id;
                u8 elen = elem->datalen;
@@ -1101,7 +1105,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        break;
                }
 
-               if (calc_crc && id < 64 && (filter & (1ULL << id)))
+               if (calc_crc && id < 64 && (params->filter & (1ULL << id)))
                        crc = crc32_be(crc, pos - 2, elen + 2);
 
                elem_parse_failed = false;
@@ -1282,7 +1286,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        elems->mesh_chansw_params_ie = (void *)pos;
                        break;
                case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
-                       if (!action ||
+                       if (!params->action ||
                            elen < sizeof(*elems->wide_bw_chansw_ie)) {
                                elem_parse_failed = true;
                                break;
@@ -1290,7 +1294,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        elems->wide_bw_chansw_ie = (void *)pos;
                        break;
                case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
-                       if (action) {
+                       if (params->action) {
                                elem_parse_failed = true;
                                break;
                        }
@@ -1417,7 +1421,7 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
                        __set_bit(id, seen_elems);
        }
 
-       if (!for_each_element_completed(elem, start, len))
+       if (!for_each_element_completed(elem, params->start, params->len))
                elems->parse_error = true;
 
        return crc;
@@ -1425,15 +1429,14 @@ _ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
 
 static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
                                            struct ieee802_11_elems *elems,
-                                           const u8 *transmitter_bssid,
-                                           const u8 *bss_bssid,
+                                           struct cfg80211_bss *bss,
                                            u8 *nontransmitted_profile)
 {
        const struct element *elem, *sub;
        size_t profile_len = 0;
        bool found = false;
 
-       if (!bss_bssid || !transmitter_bssid)
+       if (!bss || !bss->transmitted_bss)
                return profile_len;
 
        for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
@@ -1475,11 +1478,11 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
                                continue;
                        }
 
-                       cfg80211_gen_new_bssid(transmitter_bssid,
+                       cfg80211_gen_new_bssid(bss->transmitted_bss->bssid,
                                               elem->data[0],
                                               index[2],
                                               new_bssid);
-                       if (ether_addr_equal(new_bssid, bss_bssid)) {
+                       if (ether_addr_equal(new_bssid, bss->bssid)) {
                                found = true;
                                elems->bssid_index_len = index[1];
                                elems->bssid_index = (void *)&index[2];
@@ -1491,11 +1494,8 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
        return found ? profile_len : 0;
 }
 
-struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
-                                                   bool action, u64 filter,
-                                                   u32 crc,
-                                                   const u8 *transmitter_bssid,
-                                                   const u8 *bss_bssid)
+struct ieee802_11_elems *
+ieee802_11_parse_elems_full(struct ieee80211_elems_parse_params *params)
 {
        struct ieee802_11_elems *elems;
        const struct element *non_inherit = NULL;
@@ -1505,15 +1505,14 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
        elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
        if (!elems)
                return NULL;
-       elems->ie_start = start;
-       elems->total_len = len;
+       elems->ie_start = params->start;
+       elems->total_len = params->len;
 
-       nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
+       nontransmitted_profile = kmalloc(params->len, GFP_ATOMIC);
        if (nontransmitted_profile) {
                nontransmitted_profile_len =
-                       ieee802_11_find_bssid_profile(start, len, elems,
-                                                     transmitter_bssid,
-                                                     bss_bssid,
+                       ieee802_11_find_bssid_profile(params->start, params->len,
+                                                     elems, params->bss,
                                                      nontransmitted_profile);
                non_inherit =
                        cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
@@ -1521,14 +1520,19 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
                                               nontransmitted_profile_len);
        }
 
-       crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
-                                         crc, non_inherit);
+       elems->crc = _ieee802_11_parse_elems_full(params, elems, non_inherit);
 
        /* Override with nontransmitted profile, if found */
-       if (nontransmitted_profile_len)
-               _ieee802_11_parse_elems_crc(nontransmitted_profile,
-                                           nontransmitted_profile_len,
-                                           action, elems, 0, 0, NULL);
+       if (nontransmitted_profile_len) {
+               struct ieee80211_elems_parse_params sub = {
+                       .start = nontransmitted_profile,
+                       .len = nontransmitted_profile_len,
+                       .action = params->action,
+                       .link_id = params->link_id,
+               };
+
+               _ieee802_11_parse_elems_full(&sub, elems, NULL);
+       }
 
        if (elems->tim && !elems->parse_error) {
                const struct ieee80211_tim_ie *tim_ie = elems->tim;
@@ -1550,8 +1554,6 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
 
        kfree(nontransmitted_profile);
 
-       elems->crc = crc;
-
        return elems;
 }
 
@@ -1569,7 +1571,7 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
                return;
 
        rcu_read_lock();
-       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
        if (chanctx_conf)
                center_freq = chanctx_conf->def.chan->center_freq;
 
@@ -1596,9 +1598,10 @@ void ieee80211_regulatory_limit_wmm_params(struct ieee80211_sub_if_data *sdata,
        rcu_read_unlock();
 }
 
-void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
+void ieee80211_set_wmm_default(struct ieee80211_link_data *link,
                               bool bss_notify, bool enable_qos)
 {
+       struct ieee80211_sub_if_data *sdata = link->sdata;
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_tx_queue_params qparam;
        struct ieee80211_chanctx_conf *chanctx_conf;
@@ -1616,10 +1619,10 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
        memset(&qparam, 0, sizeof(qparam));
 
        rcu_read_lock();
-       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
        use_11b = (chanctx_conf &&
                   chanctx_conf->def.chan->band == NL80211_BAND_2GHZ) &&
-                !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
+                !link->operating_11g_mode;
        rcu_read_unlock();
 
        is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB);
@@ -1693,17 +1696,17 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
 
                qparam.uapsd = false;
 
-               sdata->tx_conf[ac] = qparam;
-               drv_conf_tx(local, sdata, ac, &qparam);
+               link->tx_conf[ac] = qparam;
+               drv_conf_tx(local, link, ac, &qparam);
        }
 
        if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
            sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
            sdata->vif.type != NL80211_IFTYPE_NAN) {
-               sdata->vif.bss_conf.qos = enable_qos;
+               link->conf->qos = enable_qos;
                if (bss_notify)
-                       ieee80211_bss_info_change_notify(sdata,
-                                                        BSS_CHANGED_QOS);
+                       ieee80211_link_info_change_notify(sdata, link,
+                                                         BSS_CHANGED_QOS);
        }
 }
 
@@ -1716,11 +1719,28 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
+       bool multi_link = sdata->vif.valid_links;
+       struct {
+               u8 id;
+               u8 len;
+               u8 ext_id;
+               struct ieee80211_multi_link_elem ml;
+               struct ieee80211_mle_basic_common_info basic;
+       } __packed mle = {
+               .id = WLAN_EID_EXTENSION,
+               .len = sizeof(mle) - 2,
+               .ext_id = WLAN_EID_EXT_EHT_MULTI_LINK,
+               .ml.control = cpu_to_le16(IEEE80211_ML_CONTROL_TYPE_BASIC),
+               .basic.len = sizeof(mle.basic),
+       };
        int err;
 
+       memcpy(mle.basic.mld_mac_addr, sdata->vif.addr, ETH_ALEN);
+
        /* 24 + 6 = header + auth_algo + auth_transaction + status_code */
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + IEEE80211_WEP_IV_LEN +
-                           24 + 6 + extra_len + IEEE80211_WEP_ICV_LEN);
+                           24 + 6 + extra_len + IEEE80211_WEP_ICV_LEN +
+                           multi_link * sizeof(mle));
        if (!skb)
                return;
 
@@ -1737,6 +1757,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        mgmt->u.auth.status_code = cpu_to_le16(status);
        if (extra)
                skb_put_data(skb, extra, extra_len);
+       if (multi_link)
+               skb_put_data(skb, &mle, sizeof(mle));
 
        if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
                mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
@@ -2258,7 +2280,8 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
 }
 
 static void ieee80211_assign_chanctx(struct ieee80211_local *local,
-                                    struct ieee80211_sub_if_data *sdata)
+                                    struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_link_data *link)
 {
        struct ieee80211_chanctx_conf *conf;
        struct ieee80211_chanctx *ctx;
@@ -2267,11 +2290,11 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local,
                return;
 
        mutex_lock(&local->chanctx_mtx);
-       conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+       conf = rcu_dereference_protected(link->conf->chanctx_conf,
                                         lockdep_is_held(&local->chanctx_mtx));
        if (conf) {
                ctx = container_of(conf, struct ieee80211_chanctx, conf);
-               drv_assign_vif_chanctx(local, sdata, ctx);
+               drv_assign_vif_chanctx(local, sdata, link->conf, ctx);
        }
        mutex_unlock(&local->chanctx_mtx);
 }
@@ -2477,7 +2500,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                sdata = wiphy_dereference(local->hw.wiphy,
                                          local->monitor_sdata);
                if (sdata && ieee80211_sdata_running(sdata))
-                       ieee80211_assign_chanctx(local, sdata);
+                       ieee80211_assign_chanctx(local, sdata, &sdata->deflink);
        }
 
        /* reconfigure hardware */
@@ -2487,19 +2510,30 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
        /* Finally also reconfigure all the BSS information */
        list_for_each_entry(sdata, &local->interfaces, list) {
+               unsigned int link_id;
                u32 changed;
 
                if (!ieee80211_sdata_running(sdata))
                        continue;
 
-               ieee80211_assign_chanctx(local, sdata);
+               sdata_lock(sdata);
+               for (link_id = 0;
+                    link_id < ARRAY_SIZE(sdata->vif.link_conf);
+                    link_id++) {
+                       struct ieee80211_link_data *link;
+
+                       link = sdata_dereference(sdata->link[link_id], sdata);
+                       if (link)
+                               ieee80211_assign_chanctx(local, sdata, link);
+               }
+               sdata_unlock(sdata);
 
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_AP_VLAN:
                case NL80211_IFTYPE_MONITOR:
                        break;
                case NL80211_IFTYPE_ADHOC:
-                       if (sdata->vif.bss_conf.ibss_joined)
+                       if (sdata->vif.cfg.ibss_joined)
                                WARN_ON(drv_join_ibss(local, sdata));
                        fallthrough;
                default:
@@ -2507,8 +2541,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        fallthrough;
                case NL80211_IFTYPE_AP: /* AP stations are handled later */
                        for (i = 0; i < IEEE80211_NUM_ACS; i++)
-                               drv_conf_tx(local, sdata, i,
-                                           &sdata->tx_conf[i]);
+                               drv_conf_tx(local, &sdata->deflink, i,
+                                           &sdata->deflink.tx_conf[i]);
                        break;
                }
 
@@ -2526,7 +2560,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_TXPOWER |
                          BSS_CHANGED_MCAST_RATE;
 
-               if (sdata->vif.mu_mimo_owner)
+               if (sdata->vif.bss_conf.mu_mimo_owner)
                        changed |= BSS_CHANGED_MU_GROUPS;
 
                switch (sdata->vif.type) {
@@ -2536,7 +2570,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                                   BSS_CHANGED_PS;
 
                        /* Re-send beacon info report to the driver */
-                       if (sdata->u.mgd.have_beacon)
+                       if (sdata->deflink.u.mgd.have_beacon)
                                changed |= BSS_CHANGED_BEACON_INFO;
 
                        if (sdata->vif.bss_conf.max_idle_period ||
@@ -2565,8 +2599,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                                changed |= BSS_CHANGED_AP_PROBE_RESP;
 
-                               if (rcu_access_pointer(sdata->u.ap.beacon))
-                                       drv_start_ap(local, sdata);
+                               if (rcu_access_pointer(sdata->deflink.u.ap.beacon))
+                                       drv_start_ap(local, sdata,
+                                                    sdata->deflink.conf);
                        }
                        fallthrough;
                case NL80211_IFTYPE_MESH_POINT:
@@ -2801,7 +2836,8 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
 
-void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
+void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata,
+                          struct ieee80211_link_data *link)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx_conf *chanctx_conf;
@@ -2809,8 +2845,8 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
 
        mutex_lock(&local->chanctx_mtx);
 
-       chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-                                       lockdep_is_held(&local->chanctx_mtx));
+       chanctx_conf = rcu_dereference_protected(link->conf->chanctx_conf,
+                                                lockdep_is_held(&local->chanctx_mtx));
 
        /*
         * This function can be called from a work, thus it may be possible
@@ -2827,22 +2863,48 @@ void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata)
        mutex_unlock(&local->chanctx_mtx);
 }
 
-void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata)
+void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata,
+                                 int link_id)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_chanctx *chanctx;
+       int i;
 
        mutex_lock(&local->chanctx_mtx);
 
-       chanctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-                                       lockdep_is_held(&local->chanctx_mtx));
+       for (i = 0; i < ARRAY_SIZE(sdata->vif.link_conf); i++) {
+               struct ieee80211_bss_conf *bss_conf;
 
-       if (WARN_ON_ONCE(!chanctx_conf))
-               goto unlock;
+               if (link_id >= 0 && link_id != i)
+                       continue;
 
-       chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
-       ieee80211_recalc_chanctx_min_def(local, chanctx);
+               rcu_read_lock();
+               bss_conf = rcu_dereference(sdata->vif.link_conf[i]);
+               if (!bss_conf) {
+                       rcu_read_unlock();
+                       continue;
+               }
+
+               chanctx_conf = rcu_dereference_protected(bss_conf->chanctx_conf,
+                                                        lockdep_is_held(&local->chanctx_mtx));
+               /*
+                * Since we hold the chanctx_mtx (checked above)
+                * we can take the chanctx_conf pointer out of the
+                * RCU critical section, it cannot go away without
+                * the mutex. Just the way we reached it could - in
+                * theory - go away, but we don't really care and
+                * it really shouldn't happen anyway.
+                */
+               rcu_read_unlock();
+
+               if (WARN_ON_ONCE(!chanctx_conf))
+                       goto unlock;
+
+               chanctx = container_of(chanctx_conf, struct ieee80211_chanctx,
+                                      conf);
+               ieee80211_recalc_chanctx_min_def(local, chanctx);
+       }
  unlock:
        mutex_unlock(&local->chanctx_mtx);
 }
@@ -2934,7 +2996,7 @@ u8 ieee80211_ie_len_he_cap(struct ieee80211_sub_if_data *sdata, u8 iftype)
                                     he_cap->he_cap_elem.phy_cap_info);
 }
 
-u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos,
+u8 *ieee80211_ie_build_he_cap(ieee80211_conn_flags_t disable_flags, u8 *pos,
                              const struct ieee80211_sta_he_cap *he_cap,
                              u8 *end)
 {
@@ -2954,16 +3016,16 @@ u8 *ieee80211_ie_build_he_cap(u32 disable_flags, u8 *pos,
        /* modify on stack first to calculate 'n' and 'ie_len' correctly */
        elem = he_cap->he_cap_elem;
 
-       if (disable_flags & IEEE80211_STA_DISABLE_40MHZ)
+       if (disable_flags & IEEE80211_CONN_DISABLE_40MHZ)
                elem.phy_cap_info[0] &=
                        ~(IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
                          IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G);
 
-       if (disable_flags & IEEE80211_STA_DISABLE_160MHZ)
+       if (disable_flags & IEEE80211_CONN_DISABLE_160MHZ)
                elem.phy_cap_info[0] &=
                        ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
 
-       if (disable_flags & IEEE80211_STA_DISABLE_80P80MHZ)
+       if (disable_flags & IEEE80211_CONN_DISABLE_80P80MHZ)
                elem.phy_cap_info[0] &=
                        ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
 
@@ -3044,7 +3106,7 @@ void ieee80211_ie_build_he_6ghz_cap(struct ieee80211_sub_if_data *sdata,
        cap = le16_to_cpu(iftd->he_6ghz_capa.capa);
        cap &= ~IEEE80211_HE_6GHZ_CAP_SM_PS;
 
-       switch (sdata->smps_mode) {
+       switch (sdata->deflink.smps_mode) {
        case IEEE80211_SMPS_AUTOMATIC:
        case IEEE80211_SMPS_NUM_MODES:
                WARN_ON(1);
@@ -3445,6 +3507,58 @@ bool ieee80211_chandef_vht_oper(struct ieee80211_hw *hw, u32 vht_cap_info,
        return true;
 }
 
+void ieee80211_chandef_eht_oper(struct ieee80211_sub_if_data *sdata,
+                               const struct ieee80211_eht_operation *eht_oper,
+                               bool support_160, bool support_320,
+                               struct cfg80211_chan_def *chandef)
+{
+       struct ieee80211_eht_operation_info *info = (void *)eht_oper->optional;
+
+       chandef->center_freq1 =
+               ieee80211_channel_to_frequency(info->ccfs0,
+                                              chandef->chan->band);
+
+       switch (u8_get_bits(info->control,
+                           IEEE80211_EHT_OPER_CHAN_WIDTH)) {
+       case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_20;
+               break;
+       case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_40;
+               break;
+       case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
+               chandef->width = NL80211_CHAN_WIDTH_80;
+               break;
+       case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
+               if (support_160) {
+                       chandef->width = NL80211_CHAN_WIDTH_160;
+                       chandef->center_freq1 =
+                               ieee80211_channel_to_frequency(info->ccfs1,
+                                                              chandef->chan->band);
+               } else {
+                       chandef->width = NL80211_CHAN_WIDTH_80;
+               }
+               break;
+       case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
+               if (support_320) {
+                       chandef->width = NL80211_CHAN_WIDTH_320;
+                       chandef->center_freq1 =
+                               ieee80211_channel_to_frequency(info->ccfs1,
+                                                              chandef->chan->band);
+               } else if (support_160) {
+                       chandef->width = NL80211_CHAN_WIDTH_160;
+               } else {
+                       chandef->width = NL80211_CHAN_WIDTH_80;
+
+                       if (chandef->center_freq1 > chandef->chan->center_freq)
+                               chandef->center_freq1 -= 40;
+                       else
+                               chandef->center_freq1 += 40;
+               }
+               break;
+       }
+}
+
 bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
                                    const struct ieee80211_he_operation *he_oper,
                                    const struct ieee80211_eht_operation *eht_oper,
@@ -3525,7 +3639,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
                break;
        }
 
-       if (!eht_oper) {
+       if (!eht_oper ||
+           !(eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
                switch (u8_get_bits(he_6ghz_oper->control,
                                    IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH)) {
                case IEEE80211_HE_6GHZ_OPER_CTRL_CHANWIDTH_20MHZ:
@@ -3569,36 +3684,8 @@ bool ieee80211_chandef_he_6ghz_oper(struct ieee80211_sub_if_data *sdata,
                support_320 =
                        eht_phy_cap & IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
 
-               switch (u8_get_bits(eht_oper->chan_width,
-                                   IEEE80211_EHT_OPER_CHAN_WIDTH)) {
-               case IEEE80211_EHT_OPER_CHAN_WIDTH_20MHZ:
-                       he_chandef.width = NL80211_CHAN_WIDTH_20;
-                       break;
-               case IEEE80211_EHT_OPER_CHAN_WIDTH_40MHZ:
-                       he_chandef.width = NL80211_CHAN_WIDTH_40;
-                       break;
-               case IEEE80211_EHT_OPER_CHAN_WIDTH_80MHZ:
-                       he_chandef.width = NL80211_CHAN_WIDTH_80;
-                       break;
-               case IEEE80211_EHT_OPER_CHAN_WIDTH_160MHZ:
-                       if (support_160)
-                               he_chandef.width = NL80211_CHAN_WIDTH_160;
-                       else
-                               he_chandef.width = NL80211_CHAN_WIDTH_80;
-                       break;
-               case IEEE80211_EHT_OPER_CHAN_WIDTH_320MHZ:
-                       if (support_320)
-                               he_chandef.width = NL80211_CHAN_WIDTH_320;
-                       else if (support_160)
-                               he_chandef.width = NL80211_CHAN_WIDTH_160;
-                       else
-                               he_chandef.width = NL80211_CHAN_WIDTH_80;
-                       break;
-               }
-
-               he_chandef.center_freq1 =
-                       ieee80211_channel_to_frequency(eht_oper->ccfs,
-                                                      NL80211_BAND_6GHZ);
+               ieee80211_chandef_eht_oper(sdata, eht_oper, support_160,
+                                          support_320, &he_chandef);
        }
 
        if (!cfg80211_chandef_valid(&he_chandef)) {
@@ -3652,12 +3739,12 @@ bool ieee80211_chandef_s1g_oper(const struct ieee80211_s1g_oper_ie *oper,
        return true;
 }
 
-int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
+int ieee80211_parse_bitrates(enum nl80211_chan_width width,
                             const struct ieee80211_supported_band *sband,
                             const u8 *srates, int srates_len, u32 *rates)
 {
-       u32 rate_flags = ieee80211_chandef_rate_flags(chandef);
-       int shift = ieee80211_chandef_get_shift(chandef);
+       u32 rate_flags = ieee80211_chanwidth_rate_flags(width);
+       int shift = ieee80211_chanwidth_get_shift(width);
        struct ieee80211_rate *br;
        int brate, rate, i, j, count = 0;
 
@@ -3778,13 +3865,11 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 int ieee80211_ave_rssi(struct ieee80211_vif *vif)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION)) {
-               /* non-managed type inferfaces */
+       if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
                return 0;
-       }
-       return -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
+
+       return -ewma_beacon_signal_read(&sdata->deflink.u.mgd.ave_beacon_signal);
 }
 EXPORT_SYMBOL_GPL(ieee80211_ave_rssi);
 
@@ -3976,11 +4061,11 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
                 * by the time it gets it, sdata->wdev.cac_started
                 * will no longer be true
                 */
-               cancel_delayed_work(&sdata->dfs_cac_timer_work);
+               cancel_delayed_work(&sdata->deflink.dfs_cac_timer_work);
 
                if (sdata->wdev.cac_started) {
                        chandef = sdata->vif.bss_conf.chandef;
-                       ieee80211_vif_release_channel(sdata);
+                       ieee80211_link_release_channel(&sdata->deflink);
                        cfg80211_cac_event(sdata->dev,
                                           &chandef,
                                           NL80211_RADAR_CAC_ABORTED,
@@ -4029,21 +4114,21 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_radar_detected);
 
-u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
+ieee80211_conn_flags_t ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
 {
-       u32 ret;
+       ieee80211_conn_flags_t ret;
        int tmp;
 
        switch (c->width) {
        case NL80211_CHAN_WIDTH_20:
                c->width = NL80211_CHAN_WIDTH_20_NOHT;
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT;
                break;
        case NL80211_CHAN_WIDTH_40:
                c->width = NL80211_CHAN_WIDTH_20;
                c->center_freq1 = c->chan->center_freq;
-               ret = IEEE80211_STA_DISABLE_40MHZ |
-                     IEEE80211_STA_DISABLE_VHT;
+               ret = IEEE80211_CONN_DISABLE_40MHZ |
+                     IEEE80211_CONN_DISABLE_VHT;
                break;
        case NL80211_CHAN_WIDTH_80:
                tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
@@ -4052,13 +4137,13 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
                /* freq_P40 */
                c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
                c->width = NL80211_CHAN_WIDTH_40;
-               ret = IEEE80211_STA_DISABLE_VHT;
+               ret = IEEE80211_CONN_DISABLE_VHT;
                break;
        case NL80211_CHAN_WIDTH_80P80:
                c->center_freq2 = 0;
                c->width = NL80211_CHAN_WIDTH_80;
-               ret = IEEE80211_STA_DISABLE_80P80MHZ |
-                     IEEE80211_STA_DISABLE_160MHZ;
+               ret = IEEE80211_CONN_DISABLE_80P80MHZ |
+                     IEEE80211_CONN_DISABLE_160MHZ;
                break;
        case NL80211_CHAN_WIDTH_160:
                /* n_P20 */
@@ -4067,23 +4152,23 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
                tmp /= 4;
                c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
                c->width = NL80211_CHAN_WIDTH_80;
-               ret = IEEE80211_STA_DISABLE_80P80MHZ |
-                     IEEE80211_STA_DISABLE_160MHZ;
+               ret = IEEE80211_CONN_DISABLE_80P80MHZ |
+                     IEEE80211_CONN_DISABLE_160MHZ;
                break;
        case NL80211_CHAN_WIDTH_320:
                /* n_P20 */
                tmp = (150 + c->chan->center_freq - c->center_freq1) / 20;
                /* n_P160 */
-               tmp /= 80;
+               tmp /= 8;
                c->center_freq1 = c->center_freq1 - 80 + 160 * tmp;
                c->width = NL80211_CHAN_WIDTH_160;
-               ret = IEEE80211_STA_DISABLE_320MHZ;
+               ret = IEEE80211_CONN_DISABLE_320MHZ;
                break;
        default:
        case NL80211_CHAN_WIDTH_20_NOHT:
                WARN_ON_ONCE(1);
                c->width = NL80211_CHAN_WIDTH_20_NOHT;
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT;
                break;
        case NL80211_CHAN_WIDTH_1:
        case NL80211_CHAN_WIDTH_2:
@@ -4094,7 +4179,7 @@ u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
        case NL80211_CHAN_WIDTH_10:
                WARN_ON_ONCE(1);
                /* keep c->width */
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               ret = IEEE80211_CONN_DISABLE_HT | IEEE80211_CONN_DISABLE_VHT;
                break;
        }
 
@@ -4215,74 +4300,6 @@ int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
        return 0;
 }
 
-bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs)
-{
-       return !(cs == NULL || cs->cipher == 0 ||
-                cs->hdr_len < cs->pn_len + cs->pn_off ||
-                cs->hdr_len <= cs->key_idx_off ||
-                cs->key_idx_shift > 7 ||
-                cs->key_idx_mask == 0);
-}
-
-bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n)
-{
-       int i;
-
-       /* Ensure we have enough iftype bitmap space for all iftype values */
-       WARN_ON((NUM_NL80211_IFTYPES / 8 + 1) > sizeof(cs[0].iftype));
-
-       for (i = 0; i < n; i++)
-               if (!ieee80211_cs_valid(&cs[i]))
-                       return false;
-
-       return true;
-}
-
-const struct ieee80211_cipher_scheme *
-ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,
-                enum nl80211_iftype iftype)
-{
-       const struct ieee80211_cipher_scheme *l = local->hw.cipher_schemes;
-       int n = local->hw.n_cipher_schemes;
-       int i;
-       const struct ieee80211_cipher_scheme *cs = NULL;
-
-       for (i = 0; i < n; i++) {
-               if (l[i].cipher == cipher) {
-                       cs = &l[i];
-                       break;
-               }
-       }
-
-       if (!cs || !(cs->iftype & BIT(iftype)))
-               return NULL;
-
-       return cs;
-}
-
-int ieee80211_cs_headroom(struct ieee80211_local *local,
-                         struct cfg80211_crypto_settings *crypto,
-                         enum nl80211_iftype iftype)
-{
-       const struct ieee80211_cipher_scheme *cs;
-       int headroom = IEEE80211_ENCRYPT_HEADROOM;
-       int i;
-
-       for (i = 0; i < crypto->n_ciphers_pairwise; i++) {
-               cs = ieee80211_cs_get(local, crypto->ciphers_pairwise[i],
-                                     iftype);
-
-               if (cs && headroom < cs->hdr_len)
-                       headroom = cs->hdr_len;
-       }
-
-       cs = ieee80211_cs_get(local, crypto->cipher_group, iftype);
-       if (cs && headroom < cs->hdr_len)
-               headroom = cs->hdr_len;
-
-       return headroom;
-}
-
 static bool
 ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
 {
@@ -4474,7 +4491,7 @@ void ieee80211_recalc_dtim(struct ieee80211_local *local,
 static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
                                         struct ieee80211_chanctx *ctx)
 {
-       struct ieee80211_sub_if_data *sdata;
+       struct ieee80211_link_data *link;
        u8 radar_detect = 0;
 
        lockdep_assert_held(&local->chanctx_mtx);
@@ -4482,20 +4499,24 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
        if (WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED))
                return 0;
 
-       list_for_each_entry(sdata, &ctx->reserved_vifs, reserved_chanctx_list)
-               if (sdata->reserved_radar_required)
-                       radar_detect |= BIT(sdata->reserved_chandef.width);
+       list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list)
+               if (link->reserved_radar_required)
+                       radar_detect |= BIT(link->reserved_chandef.width);
 
        /*
         * An in-place reservation context should not have any assigned vifs
         * until it replaces the other context.
         */
        WARN_ON(ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER &&
-               !list_empty(&ctx->assigned_vifs));
+               !list_empty(&ctx->assigned_links));
+
+       list_for_each_entry(link, &ctx->assigned_links, assigned_chanctx_list) {
+               if (!link->radar_required)
+                       continue;
 
-       list_for_each_entry(sdata, &ctx->assigned_vifs, assigned_chanctx_list)
-               if (sdata->radar_required)
-                       radar_detect |= BIT(sdata->vif.bss_conf.chandef.width);
+               radar_detect |=
+                       BIT(link->conf->chandef.width);
+       }
 
        return radar_detect;
 }
@@ -4809,3 +4830,31 @@ u8 *ieee80211_ie_build_eht_cap(u8 *pos,
 
        return pos;
 }
+
+void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos)
+{
+       unsigned int elem_len;
+
+       if (!len_pos)
+               return;
+
+       elem_len = skb->data + skb->len - len_pos - 1;
+
+       while (elem_len > 255) {
+               /* this one is 255 */
+               *len_pos = 255;
+               /* remaining data gets smaller */
+               elem_len -= 255;
+               /* make space for the fragment ID/len in SKB */
+               skb_put(skb, 2);
+               /* shift back the remaining data to place fragment ID/len */
+               memmove(len_pos + 255 + 3, len_pos + 255 + 1, elem_len);
+               /* place the fragment ID */
+               len_pos += 255 + 1;
+               *len_pos = WLAN_EID_FRAGMENT;
+               /* and point to fragment length to update later */
+               len_pos++;
+       }
+
+       *len_pos = elem_len;
+}