Merge remote-tracking branch 'wireless/main' into wireless-next
[linux-2.6-microblaze.git] / net / mac80211 / mlme.c
index 5265d2b..699e409 100644 (file)
@@ -314,7 +314,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        if (eht_oper && (eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT)) {
                struct cfg80211_chan_def eht_chandef = *chandef;
 
-               ieee80211_chandef_eht_oper(sdata, eht_oper,
+               ieee80211_chandef_eht_oper(eht_oper,
                                           eht_chandef.width ==
                                           NL80211_CHAN_WIDTH_160,
                                           false, &eht_chandef);
@@ -695,6 +695,7 @@ static bool ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
                                struct sk_buff *skb,
                                struct ieee80211_supported_band *sband,
+                               enum ieee80211_smps_mode smps_mode,
                                ieee80211_conn_flags_t conn_flags)
 {
        u8 *pos, *pre_he_pos;
@@ -719,7 +720,7 @@ static void ieee80211_add_he_ie(struct ieee80211_sub_if_data *sdata,
        /* trim excess if any */
        skb_trim(skb, skb->len - (pre_he_pos + he_cap_size - pos));
 
-       ieee80211_ie_build_he_6ghz_cap(sdata, skb);
+       ieee80211_ie_build_he_6ghz_cap(sdata, smps_mode, skb);
 }
 
 static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata,
@@ -746,11 +747,13 @@ static void ieee80211_add_eht_ie(struct ieee80211_sub_if_data *sdata,
        eht_cap_size =
                2 + 1 + sizeof(eht_cap->eht_cap_elem) +
                ieee80211_eht_mcs_nss_size(&he_cap->he_cap_elem,
-                                          &eht_cap->eht_cap_elem) +
+                                          &eht_cap->eht_cap_elem,
+                                          false) +
                ieee80211_eht_ppe_size(eht_cap->eht_ppe_thres[0],
                                       eht_cap->eht_cap_elem.phy_cap_info);
        pos = skb_put(skb, eht_cap_size);
-       ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size);
+       ieee80211_ie_build_eht_cap(pos, he_cap, eht_cap, pos + eht_cap_size,
+                                  false);
 }
 
 static void ieee80211_assoc_add_rates(struct sk_buff *skb,
@@ -1098,7 +1101,7 @@ static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata,
                                               offset);
 
        if (!(assoc_data->link[link_id].conn_flags & IEEE80211_CONN_DISABLE_HE)) {
-               ieee80211_add_he_ie(sdata, skb, sband,
+               ieee80211_add_he_ie(sdata, skb, sband, smps_mode,
                                    assoc_data->link[link_id].conn_flags);
                ADD_PRESENT_EXT_ELEM(WLAN_EID_EXT_HE_CAPABILITY);
        }
@@ -1220,14 +1223,21 @@ static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata,
        ml_elem = skb_put(skb, sizeof(*ml_elem));
        ml_elem->control =
                cpu_to_le16(IEEE80211_ML_CONTROL_TYPE_BASIC |
-                           IEEE80211_MLC_BASIC_PRES_EML_CAPA |
                            IEEE80211_MLC_BASIC_PRES_MLD_CAPA_OP);
        common = skb_put(skb, sizeof(*common));
        common->len = sizeof(*common) +
-                     2 + /* EML capabilities */
                      2;  /* MLD capa/ops */
        memcpy(common->mld_mac_addr, sdata->vif.addr, ETH_ALEN);
-       skb_put_data(skb, &eml_capa, sizeof(eml_capa));
+
+       /* add EML_CAPA only if needed, see Draft P802.11be_D2.1, 35.3.17 */
+       if (eml_capa &
+           cpu_to_le16((IEEE80211_EML_CAP_EMLSR_SUPP |
+                        IEEE80211_EML_CAP_EMLMR_SUPPORT))) {
+               common->len += 2; /* EML capabilities */
+               ml_elem->control |=
+                       cpu_to_le16(IEEE80211_MLC_BASIC_PRES_EML_CAPA);
+               skb_put_data(skb, &eml_capa, sizeof(eml_capa));
+       }
        /* need indication from userspace to support this */
        mld_capa_ops &= ~cpu_to_le16(IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP);
        skb_put_data(skb, &mld_capa_ops, sizeof(mld_capa_ops));
@@ -1902,7 +1912,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link,
                                          IEEE80211_QUEUE_STOP_REASON_CSA);
        mutex_unlock(&local->mtx);
 
-       cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef,
+       cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef, 0,
                                          csa_ie.count, csa_ie.mode);
 
        if (local->ops->channel_switch) {
@@ -2435,6 +2445,29 @@ static void ieee80211_sta_handle_tspec_ac_params_wk(struct work_struct *work)
        ieee80211_sta_handle_tspec_ac_params(sdata);
 }
 
+void ieee80211_mgd_set_link_qos_params(struct ieee80211_link_data *link)
+{
+       struct ieee80211_sub_if_data *sdata = link->sdata;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       struct ieee80211_tx_queue_params *params = link->tx_conf;
+       u8 ac;
+
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               mlme_dbg(sdata,
+                        "WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
+                        ac, params[ac].acm,
+                        params[ac].aifs, params[ac].cw_min, params[ac].cw_max,
+                        params[ac].txop, params[ac].uapsd,
+                        ifmgd->tx_tspec[ac].downgraded);
+               if (!ifmgd->tx_tspec[ac].downgraded &&
+                   drv_conf_tx(local, link, ac, &params[ac]))
+                       link_err(link,
+                                "failed to set TX queue parameters for AC %d\n",
+                                ac);
+       }
+}
+
 /* MLME */
 static bool
 ieee80211_sta_wmm_params(struct ieee80211_local *local,
@@ -2566,20 +2599,10 @@ ieee80211_sta_wmm_params(struct ieee80211_local *local,
                }
        }
 
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-               mlme_dbg(sdata,
-                        "WMM AC=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d, downgraded=%d\n",
-                        ac, params[ac].acm,
-                        params[ac].aifs, params[ac].cw_min, params[ac].cw_max,
-                        params[ac].txop, params[ac].uapsd,
-                        ifmgd->tx_tspec[ac].downgraded);
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                link->tx_conf[ac] = params[ac];
-               if (!ifmgd->tx_tspec[ac].downgraded &&
-                   drv_conf_tx(local, link, ac, &params[ac]))
-                       link_err(link,
-                                "failed to set TX queue parameters for AC %d\n",
-                                ac);
-       }
+
+       ieee80211_mgd_set_link_qos_params(link);
 
        /* enable WMM or activate new settings */
        link->conf->qos = true;
@@ -3904,6 +3927,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
                .len = elem_len,
                .bss = cbss,
                .link_id = link == &sdata->deflink ? -1 : link->link_id,
+               .from_ap = true,
        };
        bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
        bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ;
@@ -4572,6 +4596,11 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ;
        bool is_5ghz = cbss->channel->band == NL80211_BAND_5GHZ;
        struct ieee80211_bss *bss = (void *)cbss->priv;
+       struct ieee80211_elems_parse_params parse_params = {
+               .bss = cbss,
+               .link_id = -1,
+               .from_ap = true,
+       };
        struct ieee802_11_elems *elems;
        const struct cfg80211_bss_ies *ies;
        int ret;
@@ -4581,7 +4610,9 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        rcu_read_lock();
 
        ies = rcu_dereference(cbss->ies);
-       elems = ieee802_11_parse_elems(ies->data, ies->len, false, cbss);
+       parse_params.start = ies->data;
+       parse_params.len = ies->len;
+       elems = ieee802_11_parse_elems_full(&parse_params);
        if (!elems) {
                rcu_read_unlock();
                return -ENOMEM;
@@ -4936,6 +4967,11 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
        u16 capab_info, status_code, aid;
+       struct ieee80211_elems_parse_params parse_params = {
+               .bss = NULL,
+               .link_id = -1,
+               .from_ap = true,
+       };
        struct ieee802_11_elems *elems;
        int ac;
        const u8 *elem_start;
@@ -4990,7 +5026,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                return;
 
        elem_len = len - (elem_start - (u8 *)mgmt);
-       elems = ieee802_11_parse_elems(elem_start, elem_len, false, NULL);
+       parse_params.start = elem_start;
+       parse_params.len = elem_len;
+       elems = ieee802_11_parse_elems_full(&parse_params);
        if (!elems)
                goto notify_driver;
 
@@ -5123,7 +5161,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        resp.req_ies = ifmgd->assoc_req_ies;
        resp.req_ies_len = ifmgd->assoc_req_ies_len;
        if (sdata->vif.valid_links)
-               resp.ap_mld_addr = assoc_data->ap_addr;
+               resp.ap_mld_addr = sdata->vif.cfg.ap_addr;
        cfg80211_rx_assoc_resp(sdata->dev, &resp);
 notify_driver:
        drv_mgd_complete_tx(sdata->local, sdata, &info);
@@ -5355,6 +5393,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
        u32 ncrc = 0;
        u8 *bssid, *variable = mgmt->u.beacon.variable;
        u8 deauth_buf[IEEE80211_DEAUTH_FRAME_LEN];
+       struct ieee80211_elems_parse_params parse_params = {
+               .link_id = -1,
+               .from_ap = true,
+       };
 
        sdata_assert_lock(sdata);
 
@@ -5373,6 +5415,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
        if (baselen > len)
                return;
 
+       parse_params.start = variable;
+       parse_params.len = len - baselen;
+
        rcu_read_lock();
        chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
        if (!chanctx_conf) {
@@ -5391,8 +5436,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
        if (ifmgd->assoc_data && ifmgd->assoc_data->need_beacon &&
            !WARN_ON(sdata->vif.valid_links) &&
            ieee80211_rx_our_beacon(bssid, ifmgd->assoc_data->link[0].bss)) {
-               elems = ieee802_11_parse_elems(variable, len - baselen, false,
-                                              ifmgd->assoc_data->link[0].bss);
+               parse_params.bss = ifmgd->assoc_data->link[0].bss;
+               elems = ieee802_11_parse_elems_full(&parse_params);
                if (!elems)
                        return;
 
@@ -5458,9 +5503,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_link_data *link,
         */
        if (!ieee80211_is_s1g_beacon(hdr->frame_control))
                ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
-       elems = ieee802_11_parse_elems_crc(variable, len - baselen,
-                                          false, care_about_ies, ncrc,
-                                          link->u.mgd.bss);
+       parse_params.bss = link->u.mgd.bss;
+       parse_params.filter = care_about_ies;
+       parse_params.crc = ncrc;
+       elems = ieee802_11_parse_elems_full(&parse_params);
        if (!elems)
                return;
        ncrc = elems->crc;
@@ -5670,6 +5716,13 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
 
        sdata_lock(sdata);
 
+       if (rx_status->link_valid) {
+               link = sdata_dereference(sdata->link[rx_status->link_id],
+                                        sdata);
+               if (!link)
+                       goto out;
+       }
+
        switch (fc & IEEE80211_FCTL_STYPE) {
        case IEEE80211_STYPE_BEACON:
                ieee80211_rx_mgmt_beacon(link, (void *)mgmt,
@@ -5746,6 +5799,7 @@ void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                }
                break;
        }
+out:
        sdata_unlock(sdata);
 }
 
@@ -6281,6 +6335,8 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link)
        if (sdata->u.mgd.assoc_data)
                ether_addr_copy(link->conf->addr,
                                sdata->u.mgd.assoc_data->link[link_id].addr);
+       else if (!is_valid_ether_addr(link->conf->addr))
+               eth_random_addr(link->conf->addr);
 }
 
 /* scan finished notification */
@@ -6368,9 +6424,6 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
                goto out_err;
        }
 
-       if (mlo && !is_valid_ether_addr(link->conf->addr))
-               eth_random_addr(link->conf->addr);
-
        if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) {
                err = -EINVAL;
                goto out_err;
@@ -6853,6 +6906,10 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       /* FIXME: no support for 4-addr MLO yet */
+       if (sdata->u.mgd.use_4addr && req->link_id >= 0)
+               return -EOPNOTSUPP;
+
        assoc_data = kzalloc(size, GFP_KERNEL);
        if (!assoc_data)
                return -ENOMEM;