Commit 978420c2 authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: mlme: refactor assoc req element building

For MLO, we will need to build these elements per link, so
factor out the code that does this, returning the capability,
to simplify building the multi-link element in the future.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 39d80599
......@@ -936,17 +936,158 @@ static size_t ieee80211_add_before_he_elems(struct sk_buff *skb,
return noffset;
}
static size_t ieee80211_assoc_link_elems(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u16 *capab,
const struct element *ext_capa,
const u8 *extra_elems,
size_t extra_elems_len,
struct ieee80211_link_data *link)
{
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
struct cfg80211_bss *cbss = assoc_data->bss;
struct ieee80211_channel *chan = cbss->channel;
const struct ieee80211_sband_iftype_data *iftd;
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20;
struct ieee80211_chanctx_conf *chanctx_conf;
size_t offset = 0;
u8 *pos;
int i;
/*
* 5/10 MHz scenarios are only viable without MLO, in which
* case this pointer should be used ... All of this is a bit
* unclear though, not sure this even works at all.
*/
rcu_read_lock();
chanctx_conf = rcu_dereference(link->conf->chanctx_conf);
if (chanctx_conf)
width = chanctx_conf->def.width;
rcu_read_unlock();
sband = local->hw.wiphy->bands[chan->band];
iftd = ieee80211_get_sband_iftype_data(sband, iftype);
if (sband->band == NL80211_BAND_2GHZ) {
*capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
*capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
}
if ((cbss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
ieee80211_hw_check(&local->hw, SPECTRUM_MGMT))
*capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
if (sband->band != NL80211_BAND_S1GHZ)
ieee80211_assoc_add_rates(skb, width, sband, assoc_data);
if (*capab & WLAN_CAPABILITY_SPECTRUM_MGMT ||
*capab & WLAN_CAPABILITY_RADIO_MEASURE) {
struct cfg80211_chan_def chandef = {
.width = width,
.chan = chan,
};
pos = skb_put(skb, 4);
*pos++ = WLAN_EID_PWR_CAPABILITY;
*pos++ = 2;
*pos++ = 0; /* min tx power */
/* max tx power */
*pos++ = ieee80211_chandef_max_power(&chandef);
}
/*
* Per spec, we shouldn't include the list of channels if we advertise
* support for extended channel switching, but we've always done that;
* (for now?) apply this restriction only on the (new) 6 GHz band.
*/
if (*capab & WLAN_CAPABILITY_SPECTRUM_MGMT &&
(sband->band != NL80211_BAND_6GHZ ||
!ext_capa || ext_capa->datalen < 1 ||
!(ext_capa->data[0] & WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING))) {
/* TODO: get this in reg domain format */
pos = skb_put(skb, 2 * sband->n_channels + 2);
*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
*pos++ = 2 * sband->n_channels;
for (i = 0; i < sband->n_channels; i++) {
int cf = sband->channels[i].center_freq;
*pos++ = ieee80211_frequency_to_channel(cf);
*pos++ = 1; /* one channel in the subband*/
}
}
/* if present, add any custom IEs that go before HT */
offset = ieee80211_add_before_ht_elems(skb, extra_elems,
extra_elems_len,
offset);
if (sband->band != NL80211_BAND_6GHZ &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
ieee80211_add_ht_ie(sdata, skb,
assoc_data->ap_ht_param,
sband, chan, link->smps_mode,
link->u.mgd.conn_flags);
/* if present, add any custom IEs that go before VHT */
offset = ieee80211_add_before_vht_elems(skb, extra_elems,
extra_elems_len,
offset);
if (sband->band != NL80211_BAND_6GHZ &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
link->conf->mu_mimo_owner =
ieee80211_add_vht_ie(sdata, skb, sband,
&assoc_data->ap_vht_cap,
link->u.mgd.conn_flags);
/*
* If AP doesn't support HT, mark HE and EHT as disabled.
* If on the 5GHz band, make sure it supports VHT.
*/
if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT ||
(sband->band == NL80211_BAND_5GHZ &&
link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
link->u.mgd.conn_flags |=
IEEE80211_CONN_DISABLE_HE |
IEEE80211_CONN_DISABLE_EHT;
/* if present, add any custom IEs that go before HE */
offset = ieee80211_add_before_he_elems(skb, extra_elems,
extra_elems_len,
offset);
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE))
ieee80211_add_he_ie(sdata, skb, sband,
link->u.mgd.conn_flags);
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
ieee80211_add_eht_ie(sdata, skb, sband);
if (sband->band == NL80211_BAND_S1GHZ) {
ieee80211_add_aid_request_ie(sdata, skb);
ieee80211_add_s1g_capab_ie(sdata, &sband->s1g_cap, skb);
}
if (iftd && iftd->vendor_elems.data && iftd->vendor_elems.len)
skb_put_data(skb, iftd->vendor_elems.data, iftd->vendor_elems.len);
return offset;
}
static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_mgd_assoc_data *assoc_data = ifmgd->assoc_data;
struct ieee80211_link_data *link = &sdata->deflink;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, qos_info, *ie_start;
size_t offset = 0, noffset;
int i;
u16 capab;
size_t offset, noffset;
u16 capab = WLAN_CAPABILITY_ESS;
struct ieee80211_supported_band *sband;
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *chan;
......@@ -955,7 +1096,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
const struct ieee80211_sband_iftype_data *iftd;
struct ieee80211_prep_tx_info info = {};
struct ieee80211_link_data *link = &sdata->deflink;
void *capab_pos;
int ret;
/* we know it's writable, cast away the const */
......@@ -1003,23 +1144,18 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
skb_reserve(skb, local->hw.extra_tx_headroom);
capab = WLAN_CAPABILITY_ESS;
if (sband->band == NL80211_BAND_2GHZ) {
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
}
if (assoc_data->capability & WLAN_CAPABILITY_PRIVACY)
capab |= WLAN_CAPABILITY_PRIVACY;
if ((assoc_data->capability & WLAN_CAPABILITY_SPECTRUM_MGMT) &&
ieee80211_hw_check(&local->hw, SPECTRUM_MGMT))
capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
if (ifmgd->flags & IEEE80211_STA_ENABLE_RRM)
capab |= WLAN_CAPABILITY_RADIO_MEASURE;
/* Set MBSSID support for HE AP if needed */
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
ext_capa && ext_capa->datalen >= 3)
ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
mgmt = skb_put_zero(skb, 24);
memcpy(mgmt->da, assoc_data->bss->bssid, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
......@@ -1032,7 +1168,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
skb_put(skb, 10);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_REASSOC_REQ);
mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
capab_pos = &mgmt->u.reassoc_req.capab_info;
mgmt->u.reassoc_req.listen_interval = listen_int;
memcpy(mgmt->u.reassoc_req.current_ap, assoc_data->prev_bssid,
ETH_ALEN);
......@@ -1041,7 +1177,7 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
skb_put(skb, 4);
mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
IEEE80211_STYPE_ASSOC_REQ);
mgmt->u.assoc_req.capab_info = cpu_to_le16(capab);
capab_pos = &mgmt->u.assoc_req.capab_info;
mgmt->u.assoc_req.listen_interval = listen_int;
info.subtype = IEEE80211_STYPE_ASSOC_REQ;
}
......@@ -1053,97 +1189,15 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
*pos++ = assoc_data->ssid_len;
memcpy(pos, assoc_data->ssid, assoc_data->ssid_len);
if (sband->band != NL80211_BAND_S1GHZ)
ieee80211_assoc_add_rates(skb, chanctx_conf->def.width,
sband, assoc_data);
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT ||
capab & WLAN_CAPABILITY_RADIO_MEASURE) {
pos = skb_put(skb, 4);
*pos++ = WLAN_EID_PWR_CAPABILITY;
*pos++ = 2;
*pos++ = 0; /* min tx power */
/* max tx power */
*pos++ = ieee80211_chandef_max_power(&chanctx_conf->def);
}
/*
* Per spec, we shouldn't include the list of channels if we advertise
* support for extended channel switching, but we've always done that;
* (for now?) apply this restriction only on the (new) 6 GHz band.
*/
if (capab & WLAN_CAPABILITY_SPECTRUM_MGMT &&
(sband->band != NL80211_BAND_6GHZ ||
!ext_capa || ext_capa->datalen < 1 ||
!(ext_capa->data[0] & WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING))) {
/* TODO: get this in reg domain format */
pos = skb_put(skb, 2 * sband->n_channels + 2);
*pos++ = WLAN_EID_SUPPORTED_CHANNELS;
*pos++ = 2 * sband->n_channels;
for (i = 0; i < sband->n_channels; i++) {
int cf = sband->channels[i].center_freq;
*pos++ = ieee80211_frequency_to_channel(cf);
*pos++ = 1; /* one channel in the subband*/
}
}
/* add the elements for the assoc (main) link */
offset = ieee80211_assoc_link_elems(sdata, skb, &capab,
ext_capa,
assoc_data->ie,
assoc_data->ie_len,
link);
put_unaligned_le16(capab, capab_pos);
/* Set MBSSID support for HE AP if needed */
if (ieee80211_hw_check(&local->hw, SUPPORTS_ONLY_HE_MULTI_BSSID) &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE) &&
ext_capa && ext_capa->datalen >= 3)
ext_capa->data[2] |= WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT;
/* if present, add any custom IEs that go before HT */
offset = ieee80211_add_before_ht_elems(skb, assoc_data->ie,
assoc_data->ie_len,
offset);
if (WARN_ON_ONCE((link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT) &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)))
link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_VHT;
if (sband->band != NL80211_BAND_6GHZ &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT))
ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
sband, chan, link->smps_mode,
link->u.mgd.conn_flags);
/* if present, add any custom IEs that go before VHT */
offset = ieee80211_add_before_vht_elems(skb, assoc_data->ie,
assoc_data->ie_len,
offset);
if (sband->band != NL80211_BAND_6GHZ &&
!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
link->conf->mu_mimo_owner =
ieee80211_add_vht_ie(sdata, skb, sband,
&assoc_data->ap_vht_cap,
link->u.mgd.conn_flags);
/*
* If AP doesn't support HT, mark HE and EHT as disabled.
* If on the 5GHz band, make sure it supports VHT.
*/
if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT ||
(sband->band == NL80211_BAND_5GHZ &&
link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT))
link->u.mgd.conn_flags |= IEEE80211_CONN_DISABLE_HE |
IEEE80211_CONN_DISABLE_EHT;
/* if present, add any custom IEs that go before HE */
offset = ieee80211_add_before_he_elems(skb, assoc_data->ie,
assoc_data->ie_len,
offset);
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HE)) {
ieee80211_add_he_ie(sdata, skb, sband, link->u.mgd.conn_flags);
if (!(link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_EHT))
ieee80211_add_eht_ie(sdata, skb, sband);
}
/* if present, add any custom non-vendor IEs that go after HE */
/* if present, add any custom non-vendor IEs */
if (assoc_data->ie_len) {
noffset = ieee80211_ie_split_vendor(assoc_data->ie,
assoc_data->ie_len,
......@@ -1164,14 +1218,6 @@ static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
pos = ieee80211_add_wmm_info_ie(skb_put(skb, 9), qos_info);
}
if (sband->band == NL80211_BAND_S1GHZ) {
ieee80211_add_aid_request_ie(sdata, skb);
ieee80211_add_s1g_capab_ie(sdata, &sband->s1g_cap, skb);
}
if (iftd && iftd->vendor_elems.data && iftd->vendor_elems.len)
skb_put_data(skb, iftd->vendor_elems.data, iftd->vendor_elems.len);
/* add any remaining custom (i.e. vendor specific here) IEs */
if (assoc_data->ie_len) {
noffset = assoc_data->ie_len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment