wifi: mac80211: start building elements in SKBs
The building of elements is really mess, and really the only reason we're not doing it in SKBs in the first place is that the scan code in ieee80211_build_preq_ies() doesn't. Convert ieee80211_build_preq_ies() to use an SKB internally so that we can gradually convert other things to ..._put_*() style interfaces. Link: https://msgid.link/20240129202041.c3a8e3c2cc99.I9d9920858c30ae5154719783933de0d7bc2a2cb9@changeid Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
147ceae205
commit
07095d1677
3 changed files with 191 additions and 187 deletions
|
@ -2517,14 +2517,13 @@ void ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
|
||||||
struct sk_buff *skb);
|
struct sk_buff *skb);
|
||||||
void ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata,
|
void ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata,
|
||||||
struct sk_buff *skb);
|
struct sk_buff *skb);
|
||||||
u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap);
|
|
||||||
|
|
||||||
/* element building in SKBs */
|
/* element building in SKBs */
|
||||||
int ieee80211_put_srates_elem(struct sk_buff *skb,
|
int ieee80211_put_srates_elem(struct sk_buff *skb,
|
||||||
const struct ieee80211_supported_band *sband,
|
const struct ieee80211_supported_band *sband,
|
||||||
u32 basic_rates, u32 rate_flags, u32 masked_rates,
|
u32 basic_rates, u32 rate_flags, u32 masked_rates,
|
||||||
u8 element_id);
|
u8 element_id);
|
||||||
void ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
|
int ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
enum ieee80211_smps_mode smps_mode);
|
enum ieee80211_smps_mode smps_mode);
|
||||||
|
|
||||||
|
|
|
@ -400,6 +400,8 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_sub_if_data *sdata)
|
||||||
req->ie, req->ie_len,
|
req->ie, req->ie_len,
|
||||||
bands_used, req->rates, &chandef,
|
bands_used, req->rates, &chandef,
|
||||||
flags);
|
flags);
|
||||||
|
if (ielen < 0)
|
||||||
|
return false;
|
||||||
local->hw_scan_req->req.ie_len = ielen;
|
local->hw_scan_req->req.ie_len = ielen;
|
||||||
local->hw_scan_req->req.no_cck = req->no_cck;
|
local->hw_scan_req->req.no_cck = req->no_cck;
|
||||||
ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr);
|
ether_addr_copy(local->hw_scan_req->req.mac_addr, req->mac_addr);
|
||||||
|
@ -1322,10 +1324,12 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
ieee80211_prepare_scan_chandef(&chandef);
|
ieee80211_prepare_scan_chandef(&chandef);
|
||||||
|
|
||||||
ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz,
|
ret = ieee80211_build_preq_ies(sdata, ie, num_bands * iebufsz,
|
||||||
&sched_scan_ies, req->ie,
|
&sched_scan_ies, req->ie,
|
||||||
req->ie_len, bands_used, rate_masks, &chandef,
|
req->ie_len, bands_used, rate_masks,
|
||||||
flags);
|
&chandef, flags);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
|
ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
@ -1333,8 +1337,8 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||||
rcu_assign_pointer(local->sched_scan_req, req);
|
rcu_assign_pointer(local->sched_scan_req, req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
kfree(ie);
|
kfree(ie);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (ret) {
|
if (ret) {
|
||||||
/* Clean in case of failure after HW restart or upon resume. */
|
/* Clean in case of failure after HW restart or upon resume. */
|
||||||
|
|
|
@ -2035,37 +2035,36 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static u8 *ieee80211_write_he_6ghz_cap(u8 *pos, __le16 cap, u8 *end)
|
static int ieee80211_put_s1g_cap(struct sk_buff *skb,
|
||||||
|
struct ieee80211_sta_s1g_cap *s1g_cap)
|
||||||
{
|
{
|
||||||
if ((end - pos) < 5)
|
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_s1g_cap))
|
||||||
return pos;
|
return -ENOBUFS;
|
||||||
|
|
||||||
*pos++ = WLAN_EID_EXTENSION;
|
skb_put_u8(skb, WLAN_EID_S1G_CAPABILITIES);
|
||||||
*pos++ = 1 + sizeof(cap);
|
skb_put_u8(skb, sizeof(struct ieee80211_s1g_cap));
|
||||||
*pos++ = WLAN_EID_EXT_HE_6GHZ_CAPA;
|
|
||||||
memcpy(pos, &cap, sizeof(cap));
|
|
||||||
|
|
||||||
return pos + 2;
|
skb_put_data(skb, &s1g_cap->cap, sizeof(s1g_cap->cap));
|
||||||
|
skb_put_data(skb, &s1g_cap->nss_mcs, sizeof(s1g_cap->nss_mcs));
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
static int ieee80211_put_preq_ies_band(struct sk_buff *skb,
|
||||||
u8 *buffer, size_t buffer_len,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
const u8 *ie, size_t ie_len,
|
const u8 *ie, size_t ie_len,
|
||||||
|
size_t *offset,
|
||||||
enum nl80211_band band,
|
enum nl80211_band band,
|
||||||
u32 rate_mask,
|
u32 rate_mask,
|
||||||
struct cfg80211_chan_def *chandef,
|
struct cfg80211_chan_def *chandef,
|
||||||
size_t *offset, u32 flags)
|
u32 flags)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sdata->local;
|
struct ieee80211_local *local = sdata->local;
|
||||||
struct ieee80211_supported_band *sband;
|
struct ieee80211_supported_band *sband;
|
||||||
const struct ieee80211_sta_he_cap *he_cap;
|
const struct ieee80211_sta_he_cap *he_cap;
|
||||||
const struct ieee80211_sta_eht_cap *eht_cap;
|
const struct ieee80211_sta_eht_cap *eht_cap;
|
||||||
u8 *pos = buffer, *end = buffer + buffer_len;
|
int i, err;
|
||||||
size_t noffset;
|
size_t noffset;
|
||||||
int supp_rates_len, i;
|
|
||||||
u8 rates[32];
|
|
||||||
int num_rates;
|
|
||||||
int ext_rates_len;
|
|
||||||
u32 rate_flags;
|
u32 rate_flags;
|
||||||
bool have_80mhz = false;
|
bool have_80mhz = false;
|
||||||
|
|
||||||
|
@ -2078,32 +2077,13 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
rate_flags = ieee80211_chandef_rate_flags(chandef);
|
rate_flags = ieee80211_chandef_rate_flags(chandef);
|
||||||
|
|
||||||
/* For direct scan add S1G IE and consider its override bits */
|
/* For direct scan add S1G IE and consider its override bits */
|
||||||
if (band == NL80211_BAND_S1GHZ) {
|
if (band == NL80211_BAND_S1GHZ)
|
||||||
if (end - pos < 2 + sizeof(struct ieee80211_s1g_cap))
|
return ieee80211_put_s1g_cap(skb, &sband->s1g_cap);
|
||||||
goto out_err;
|
|
||||||
pos = ieee80211_ie_build_s1g_cap(pos, &sband->s1g_cap);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
num_rates = 0;
|
err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, 0,
|
||||||
for (i = 0; i < sband->n_bitrates; i++) {
|
WLAN_EID_SUPP_RATES);
|
||||||
if ((BIT(i) & rate_mask) == 0)
|
if (err)
|
||||||
continue; /* skip rate */
|
return err;
|
||||||
if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
rates[num_rates++] =
|
|
||||||
(u8) DIV_ROUND_UP(sband->bitrates[i].bitrate, 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
supp_rates_len = min_t(int, num_rates, 8);
|
|
||||||
|
|
||||||
if (end - pos < 2 + supp_rates_len)
|
|
||||||
goto out_err;
|
|
||||||
*pos++ = WLAN_EID_SUPP_RATES;
|
|
||||||
*pos++ = supp_rates_len;
|
|
||||||
memcpy(pos, rates, supp_rates_len);
|
|
||||||
pos += supp_rates_len;
|
|
||||||
|
|
||||||
/* insert "request information" if in custom IEs */
|
/* insert "request information" if in custom IEs */
|
||||||
if (ie && ie_len) {
|
if (ie && ie_len) {
|
||||||
|
@ -2116,34 +2096,28 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
before_extrates,
|
before_extrates,
|
||||||
ARRAY_SIZE(before_extrates),
|
ARRAY_SIZE(before_extrates),
|
||||||
*offset);
|
*offset);
|
||||||
if (end - pos < noffset - *offset)
|
if (skb_tailroom(skb) < noffset - *offset)
|
||||||
goto out_err;
|
return -ENOBUFS;
|
||||||
memcpy(pos, ie + *offset, noffset - *offset);
|
skb_put_data(skb, ie + *offset, noffset - *offset);
|
||||||
pos += noffset - *offset;
|
|
||||||
*offset = noffset;
|
*offset = noffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
ext_rates_len = num_rates - supp_rates_len;
|
err = ieee80211_put_srates_elem(skb, sband, 0, rate_flags, 0,
|
||||||
if (ext_rates_len > 0) {
|
WLAN_EID_EXT_SUPP_RATES);
|
||||||
if (end - pos < 2 + ext_rates_len)
|
if (err)
|
||||||
goto out_err;
|
return err;
|
||||||
*pos++ = WLAN_EID_EXT_SUPP_RATES;
|
|
||||||
*pos++ = ext_rates_len;
|
|
||||||
memcpy(pos, rates + supp_rates_len, ext_rates_len);
|
|
||||||
pos += ext_rates_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chandef->chan && sband->band == NL80211_BAND_2GHZ) {
|
if (chandef->chan && sband->band == NL80211_BAND_2GHZ) {
|
||||||
if (end - pos < 3)
|
if (skb_tailroom(skb) < 3)
|
||||||
goto out_err;
|
return -ENOBUFS;
|
||||||
*pos++ = WLAN_EID_DS_PARAMS;
|
skb_put_u8(skb, WLAN_EID_DS_PARAMS);
|
||||||
*pos++ = 1;
|
skb_put_u8(skb, 1);
|
||||||
*pos++ = ieee80211_frequency_to_channel(
|
skb_put_u8(skb,
|
||||||
chandef->chan->center_freq);
|
ieee80211_frequency_to_channel(chandef->chan->center_freq));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & IEEE80211_PROBE_FLAG_MIN_CONTENT)
|
if (flags & IEEE80211_PROBE_FLAG_MIN_CONTENT)
|
||||||
goto done;
|
return 0;
|
||||||
|
|
||||||
/* insert custom IEs that go before HT */
|
/* insert custom IEs that go before HT */
|
||||||
if (ie && ie_len) {
|
if (ie && ie_len) {
|
||||||
|
@ -2158,17 +2132,20 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
noffset = ieee80211_ie_split(ie, ie_len,
|
noffset = ieee80211_ie_split(ie, ie_len,
|
||||||
before_ht, ARRAY_SIZE(before_ht),
|
before_ht, ARRAY_SIZE(before_ht),
|
||||||
*offset);
|
*offset);
|
||||||
if (end - pos < noffset - *offset)
|
if (skb_tailroom(skb) < noffset - *offset)
|
||||||
goto out_err;
|
return -ENOBUFS;
|
||||||
memcpy(pos, ie + *offset, noffset - *offset);
|
skb_put_data(skb, ie + *offset, noffset - *offset);
|
||||||
pos += noffset - *offset;
|
|
||||||
*offset = noffset;
|
*offset = noffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sband->ht_cap.ht_supported) {
|
if (sband->ht_cap.ht_supported) {
|
||||||
if (end - pos < 2 + sizeof(struct ieee80211_ht_cap))
|
u8 *pos;
|
||||||
goto out_err;
|
|
||||||
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
|
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
|
||||||
|
return -ENOBUFS;
|
||||||
|
|
||||||
|
pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
|
||||||
|
ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
|
||||||
sband->ht_cap.cap);
|
sband->ht_cap.cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2190,10 +2167,9 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
noffset = ieee80211_ie_split(ie, ie_len,
|
noffset = ieee80211_ie_split(ie, ie_len,
|
||||||
before_vht, ARRAY_SIZE(before_vht),
|
before_vht, ARRAY_SIZE(before_vht),
|
||||||
*offset);
|
*offset);
|
||||||
if (end - pos < noffset - *offset)
|
if (skb_tailroom(skb) < noffset - *offset)
|
||||||
goto out_err;
|
return -ENOBUFS;
|
||||||
memcpy(pos, ie + *offset, noffset - *offset);
|
skb_put_data(skb, ie + *offset, noffset - *offset);
|
||||||
pos += noffset - *offset;
|
|
||||||
*offset = noffset;
|
*offset = noffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2208,9 +2184,13 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sband->vht_cap.vht_supported && have_80mhz) {
|
if (sband->vht_cap.vht_supported && have_80mhz) {
|
||||||
if (end - pos < 2 + sizeof(struct ieee80211_vht_cap))
|
u8 *pos;
|
||||||
goto out_err;
|
|
||||||
pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
|
if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap))
|
||||||
|
return -ENOBUFS;
|
||||||
|
|
||||||
|
pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap));
|
||||||
|
ieee80211_ie_build_vht_cap(pos, &sband->vht_cap,
|
||||||
sband->vht_cap.cap);
|
sband->vht_cap.cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2228,10 +2208,9 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
noffset = ieee80211_ie_split(ie, ie_len,
|
noffset = ieee80211_ie_split(ie, ie_len,
|
||||||
before_he, ARRAY_SIZE(before_he),
|
before_he, ARRAY_SIZE(before_he),
|
||||||
*offset);
|
*offset);
|
||||||
if (end - pos < noffset - *offset)
|
if (skb_tailroom(skb) < noffset - *offset)
|
||||||
goto out_err;
|
return -ENOBUFS;
|
||||||
memcpy(pos, ie + *offset, noffset - *offset);
|
skb_put_data(skb, ie + *offset, noffset - *offset);
|
||||||
pos += noffset - *offset;
|
|
||||||
*offset = noffset;
|
*offset = noffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2239,9 +2218,13 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
if (he_cap &&
|
if (he_cap &&
|
||||||
cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band),
|
cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band),
|
||||||
IEEE80211_CHAN_NO_HE)) {
|
IEEE80211_CHAN_NO_HE)) {
|
||||||
|
u8 *pos = skb_tail_pointer(skb);
|
||||||
|
u8 *end = pos + skb_tailroom(skb);
|
||||||
|
|
||||||
pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, end);
|
pos = ieee80211_ie_build_he_cap(NULL, he_cap, pos, end);
|
||||||
if (!pos)
|
if (!pos)
|
||||||
goto out_err;
|
return -ENOBUFS;
|
||||||
|
skb_put(skb, pos - skb_tail_pointer(skb));
|
||||||
}
|
}
|
||||||
|
|
||||||
eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif);
|
eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, &sdata->vif);
|
||||||
|
@ -2250,42 +2233,72 @@ static int ieee80211_build_preq_ies_band(struct ieee80211_sub_if_data *sdata,
|
||||||
cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band),
|
cfg80211_any_usable_channels(local->hw.wiphy, BIT(sband->band),
|
||||||
IEEE80211_CHAN_NO_HE |
|
IEEE80211_CHAN_NO_HE |
|
||||||
IEEE80211_CHAN_NO_EHT)) {
|
IEEE80211_CHAN_NO_EHT)) {
|
||||||
|
u8 *pos = skb_tail_pointer(skb);
|
||||||
|
u8 *end = pos + skb_tailroom(skb);
|
||||||
|
|
||||||
pos = ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap,
|
pos = ieee80211_ie_build_eht_cap(NULL, pos, he_cap, eht_cap,
|
||||||
end,
|
end,
|
||||||
sdata->vif.type == NL80211_IFTYPE_AP);
|
sdata->vif.type == NL80211_IFTYPE_AP);
|
||||||
if (!pos)
|
if (!pos)
|
||||||
goto out_err;
|
return -ENOBUFS;
|
||||||
|
skb_put(skb, pos - skb_tail_pointer(skb));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg80211_any_usable_channels(local->hw.wiphy,
|
err = ieee80211_put_he_6ghz_cap(skb, sdata, IEEE80211_SMPS_OFF);
|
||||||
BIT(NL80211_BAND_6GHZ),
|
if (err)
|
||||||
IEEE80211_CHAN_NO_HE)) {
|
return err;
|
||||||
struct ieee80211_supported_band *sband6;
|
|
||||||
|
|
||||||
sband6 = local->hw.wiphy->bands[NL80211_BAND_6GHZ];
|
|
||||||
he_cap = ieee80211_get_he_iftype_cap_vif(sband6, &sdata->vif);
|
|
||||||
|
|
||||||
if (he_cap) {
|
|
||||||
enum nl80211_iftype iftype =
|
|
||||||
ieee80211_vif_type_p2p(&sdata->vif);
|
|
||||||
__le16 cap = ieee80211_get_he_6ghz_capa(sband6, iftype);
|
|
||||||
|
|
||||||
pos = ieee80211_write_he_6ghz_cap(pos, cap, end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If adding more here, adjust code in main.c
|
* If adding more here, adjust code in main.c
|
||||||
* that calculates local->scan_ies_len.
|
* that calculates local->scan_ies_len.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return pos - buffer;
|
return 0;
|
||||||
out_err:
|
|
||||||
WARN_ONCE(1, "not enough space for preq IEs\n");
|
|
||||||
done:
|
|
||||||
return pos - buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ieee80211_put_preq_ies(struct sk_buff *skb,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
struct ieee80211_scan_ies *ie_desc,
|
||||||
|
const u8 *ie, size_t ie_len,
|
||||||
|
u8 bands_used, u32 *rate_masks,
|
||||||
|
struct cfg80211_chan_def *chandef,
|
||||||
|
u32 flags)
|
||||||
|
{
|
||||||
|
size_t custom_ie_offset = 0;
|
||||||
|
int i, err;
|
||||||
|
|
||||||
|
memset(ie_desc, 0, sizeof(*ie_desc));
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_NL80211_BANDS; i++) {
|
||||||
|
if (bands_used & BIT(i)) {
|
||||||
|
ie_desc->ies[i] = skb_tail_pointer(skb);
|
||||||
|
err = ieee80211_put_preq_ies_band(skb, sdata,
|
||||||
|
ie, ie_len,
|
||||||
|
&custom_ie_offset,
|
||||||
|
i, rate_masks[i],
|
||||||
|
chandef, flags);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
ie_desc->len[i] = skb_tail_pointer(skb) -
|
||||||
|
ie_desc->ies[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add any remaining custom IEs */
|
||||||
|
if (ie && ie_len) {
|
||||||
|
if (WARN_ONCE(skb_tailroom(skb) < ie_len - custom_ie_offset,
|
||||||
|
"not enough space for preq custom IEs\n"))
|
||||||
|
return -ENOBUFS;
|
||||||
|
ie_desc->common_ies = skb_tail_pointer(skb);
|
||||||
|
skb_put_data(skb, ie + custom_ie_offset,
|
||||||
|
ie_len - custom_ie_offset);
|
||||||
|
ie_desc->common_ie_len = skb_tail_pointer(skb) -
|
||||||
|
ie_desc->common_ies;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
int ieee80211_build_preq_ies(struct ieee80211_sub_if_data *sdata, u8 *buffer,
|
int ieee80211_build_preq_ies(struct ieee80211_sub_if_data *sdata, u8 *buffer,
|
||||||
size_t buffer_len,
|
size_t buffer_len,
|
||||||
struct ieee80211_scan_ies *ie_desc,
|
struct ieee80211_scan_ies *ie_desc,
|
||||||
|
@ -2294,41 +2307,43 @@ int ieee80211_build_preq_ies(struct ieee80211_sub_if_data *sdata, u8 *buffer,
|
||||||
struct cfg80211_chan_def *chandef,
|
struct cfg80211_chan_def *chandef,
|
||||||
u32 flags)
|
u32 flags)
|
||||||
{
|
{
|
||||||
size_t pos = 0, old_pos = 0, custom_ie_offset = 0;
|
struct sk_buff *skb = alloc_skb(buffer_len, GFP_KERNEL);
|
||||||
int i;
|
uintptr_t offs;
|
||||||
|
int ret, i;
|
||||||
|
u8 *start;
|
||||||
|
|
||||||
memset(ie_desc, 0, sizeof(*ie_desc));
|
if (!skb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < NUM_NL80211_BANDS; i++) {
|
start = skb_tail_pointer(skb);
|
||||||
if (bands_used & BIT(i)) {
|
memset(start, 0, skb_tailroom(skb));
|
||||||
pos += ieee80211_build_preq_ies_band(sdata,
|
ret = ieee80211_put_preq_ies(skb, sdata, ie_desc, ie, ie_len,
|
||||||
buffer + pos,
|
bands_used, rate_masks, chandef,
|
||||||
buffer_len - pos,
|
|
||||||
ie, ie_len, i,
|
|
||||||
rate_masks[i],
|
|
||||||
chandef,
|
|
||||||
&custom_ie_offset,
|
|
||||||
flags);
|
flags);
|
||||||
ie_desc->ies[i] = buffer + old_pos;
|
if (ret < 0) {
|
||||||
ie_desc->len[i] = pos - old_pos;
|
goto out;
|
||||||
old_pos = pos;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add any remaining custom IEs */
|
if (skb->len > buffer_len) {
|
||||||
if (ie && ie_len) {
|
ret = -ENOBUFS;
|
||||||
if (WARN_ONCE(buffer_len - pos < ie_len - custom_ie_offset,
|
goto out;
|
||||||
"not enough space for preq custom IEs\n"))
|
|
||||||
return pos;
|
|
||||||
memcpy(buffer + pos, ie + custom_ie_offset,
|
|
||||||
ie_len - custom_ie_offset);
|
|
||||||
ie_desc->common_ies = buffer + pos;
|
|
||||||
ie_desc->common_ie_len = ie_len - custom_ie_offset;
|
|
||||||
pos += ie_len - custom_ie_offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pos;
|
memcpy(buffer, start, skb->len);
|
||||||
};
|
|
||||||
|
/* adjust ie_desc for copy */
|
||||||
|
for (i = 0; i < NUM_NL80211_BANDS; i++) {
|
||||||
|
offs = ie_desc->ies[i] - start;
|
||||||
|
ie_desc->ies[i] = buffer + offs;
|
||||||
|
}
|
||||||
|
offs = ie_desc->common_ies - start;
|
||||||
|
ie_desc->common_ies = buffer + offs;
|
||||||
|
|
||||||
|
ret = skb->len;
|
||||||
|
out:
|
||||||
|
consume_skb(skb);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||||
const u8 *src, const u8 *dst,
|
const u8 *src, const u8 *dst,
|
||||||
|
@ -2342,7 +2357,6 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||||
struct cfg80211_chan_def chandef;
|
struct cfg80211_chan_def chandef;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct ieee80211_mgmt *mgmt;
|
struct ieee80211_mgmt *mgmt;
|
||||||
int ies_len;
|
|
||||||
u32 rate_masks[NUM_NL80211_BANDS] = {};
|
u32 rate_masks[NUM_NL80211_BANDS] = {};
|
||||||
struct ieee80211_scan_ies dummy_ie_desc;
|
struct ieee80211_scan_ies dummy_ie_desc;
|
||||||
|
|
||||||
|
@ -2363,11 +2377,9 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
rate_masks[chan->band] = ratemask;
|
rate_masks[chan->band] = ratemask;
|
||||||
ies_len = ieee80211_build_preq_ies(sdata, skb_tail_pointer(skb),
|
ieee80211_put_preq_ies(skb, sdata, &dummy_ie_desc,
|
||||||
skb_tailroom(skb), &dummy_ie_desc,
|
|
||||||
ie, ie_len, BIT(chan->band),
|
ie, ie_len, BIT(chan->band),
|
||||||
rate_masks, &chandef, flags);
|
rate_masks, &chandef, flags);
|
||||||
skb_put(skb, ies_len);
|
|
||||||
|
|
||||||
if (dst) {
|
if (dst) {
|
||||||
mgmt = (struct ieee80211_mgmt *) skb->data;
|
mgmt = (struct ieee80211_mgmt *) skb->data;
|
||||||
|
@ -3202,21 +3214,6 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap)
|
|
||||||
{
|
|
||||||
*pos++ = WLAN_EID_S1G_CAPABILITIES;
|
|
||||||
*pos++ = sizeof(struct ieee80211_s1g_cap);
|
|
||||||
memset(pos, 0, sizeof(struct ieee80211_s1g_cap));
|
|
||||||
|
|
||||||
memcpy(pos, &s1g_cap->cap, sizeof(s1g_cap->cap));
|
|
||||||
pos += sizeof(s1g_cap->cap);
|
|
||||||
|
|
||||||
memcpy(pos, &s1g_cap->nss_mcs, sizeof(s1g_cap->nss_mcs));
|
|
||||||
pos += sizeof(s1g_cap->nss_mcs);
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||||
u16 cap)
|
u16 cap)
|
||||||
{
|
{
|
||||||
|
@ -3413,33 +3410,32 @@ end:
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
|
int ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
enum ieee80211_smps_mode smps_mode)
|
enum ieee80211_smps_mode smps_mode)
|
||||||
{
|
{
|
||||||
struct ieee80211_supported_band *sband;
|
struct ieee80211_supported_band *sband;
|
||||||
const struct ieee80211_sband_iftype_data *iftd;
|
const struct ieee80211_sband_iftype_data *iftd;
|
||||||
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
|
enum nl80211_iftype iftype = ieee80211_vif_type_p2p(&sdata->vif);
|
||||||
u8 *pos;
|
__le16 cap;
|
||||||
u16 cap;
|
|
||||||
|
|
||||||
if (!cfg80211_any_usable_channels(sdata->local->hw.wiphy,
|
if (!cfg80211_any_usable_channels(sdata->local->hw.wiphy,
|
||||||
BIT(NL80211_BAND_6GHZ),
|
BIT(NL80211_BAND_6GHZ),
|
||||||
IEEE80211_CHAN_NO_HE))
|
IEEE80211_CHAN_NO_HE))
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
sband = sdata->local->hw.wiphy->bands[NL80211_BAND_6GHZ];
|
sband = sdata->local->hw.wiphy->bands[NL80211_BAND_6GHZ];
|
||||||
|
|
||||||
iftd = ieee80211_get_sband_iftype_data(sband, iftype);
|
iftd = ieee80211_get_sband_iftype_data(sband, iftype);
|
||||||
if (!iftd)
|
if (!iftd)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
/* Check for device HE 6 GHz capability before adding element */
|
/* Check for device HE 6 GHz capability before adding element */
|
||||||
if (!iftd->he_6ghz_capa.capa)
|
if (!iftd->he_6ghz_capa.capa)
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
cap = le16_to_cpu(iftd->he_6ghz_capa.capa);
|
cap = iftd->he_6ghz_capa.capa;
|
||||||
cap &= ~IEEE80211_HE_6GHZ_CAP_SM_PS;
|
cap &= cpu_to_le16(~IEEE80211_HE_6GHZ_CAP_SM_PS);
|
||||||
|
|
||||||
switch (smps_mode) {
|
switch (smps_mode) {
|
||||||
case IEEE80211_SMPS_AUTOMATIC:
|
case IEEE80211_SMPS_AUTOMATIC:
|
||||||
|
@ -3447,22 +3443,27 @@ void ieee80211_put_he_6ghz_cap(struct sk_buff *skb,
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
fallthrough;
|
fallthrough;
|
||||||
case IEEE80211_SMPS_OFF:
|
case IEEE80211_SMPS_OFF:
|
||||||
cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_DISABLED,
|
cap |= le16_encode_bits(WLAN_HT_CAP_SM_PS_DISABLED,
|
||||||
IEEE80211_HE_6GHZ_CAP_SM_PS);
|
IEEE80211_HE_6GHZ_CAP_SM_PS);
|
||||||
break;
|
break;
|
||||||
case IEEE80211_SMPS_STATIC:
|
case IEEE80211_SMPS_STATIC:
|
||||||
cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_STATIC,
|
cap |= le16_encode_bits(WLAN_HT_CAP_SM_PS_STATIC,
|
||||||
IEEE80211_HE_6GHZ_CAP_SM_PS);
|
IEEE80211_HE_6GHZ_CAP_SM_PS);
|
||||||
break;
|
break;
|
||||||
case IEEE80211_SMPS_DYNAMIC:
|
case IEEE80211_SMPS_DYNAMIC:
|
||||||
cap |= u16_encode_bits(WLAN_HT_CAP_SM_PS_DYNAMIC,
|
cap |= le16_encode_bits(WLAN_HT_CAP_SM_PS_DYNAMIC,
|
||||||
IEEE80211_HE_6GHZ_CAP_SM_PS);
|
IEEE80211_HE_6GHZ_CAP_SM_PS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = skb_put(skb, 2 + 1 + sizeof(cap));
|
if (skb_tailroom(skb) < 2 + 1 + sizeof(cap))
|
||||||
ieee80211_write_he_6ghz_cap(pos, cpu_to_le16(cap),
|
return -ENOBUFS;
|
||||||
pos + 2 + 1 + sizeof(cap));
|
|
||||||
|
skb_put_u8(skb, WLAN_EID_EXTENSION);
|
||||||
|
skb_put_u8(skb, 1 + sizeof(cap));
|
||||||
|
skb_put_u8(skb, WLAN_EID_EXT_HE_6GHZ_CAPA);
|
||||||
|
skb_put_data(skb, &cap, sizeof(cap));
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
|
||||||
|
|
Loading…
Add table
Reference in a new issue