Commit 147ceae2 authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: simplify adding supported rates

Make this a new-style "put" function, and change the
parameters to pass more information directly, this
makes it usable also for the MLME code.

Link: https://msgid.link/20240129202041.f604a03bd728.I8c798ea45b8479ac9982e77d0378af11a09ccdaf@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent e0b5ee91
...@@ -2511,12 +2511,6 @@ u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef, ...@@ -2511,12 +2511,6 @@ u8 *ieee80211_ie_build_eht_oper(u8 *pos, struct cfg80211_chan_def *chandef,
int ieee80211_parse_bitrates(enum nl80211_chan_width width, int ieee80211_parse_bitrates(enum nl80211_chan_width width,
const struct ieee80211_supported_band *sband, const struct ieee80211_supported_band *sband,
const u8 *srates, int srates_len, u32 *rates); const u8 *srates, int srates_len, u32 *rates);
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool need_basic,
enum nl80211_band band);
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool need_basic,
enum nl80211_band band);
u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo); u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
void ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata, void ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_s1g_cap *caps, struct ieee80211_sta_s1g_cap *caps,
...@@ -2526,6 +2520,10 @@ void ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata, ...@@ -2526,6 +2520,10 @@ void ieee80211_add_aid_request_ie(struct ieee80211_sub_if_data *sdata,
u8 *ieee80211_ie_build_s1g_cap(u8 *pos, struct ieee80211_sta_s1g_cap *s1g_cap); 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,
const struct ieee80211_supported_band *sband,
u32 basic_rates, u32 rate_flags, u32 masked_rates,
u8 element_id);
void ieee80211_put_he_6ghz_cap(struct sk_buff *skb, void 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);
......
...@@ -968,19 +968,19 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) ...@@ -968,19 +968,19 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
int head_len, tail_len; int head_len, tail_len;
struct sk_buff *skb; struct sk_buff *skb;
struct ieee80211_mgmt *mgmt; struct ieee80211_mgmt *mgmt;
struct ieee80211_chanctx_conf *chanctx_conf;
struct mesh_csa_settings *csa; struct mesh_csa_settings *csa;
enum nl80211_band band; const struct ieee80211_supported_band *sband;
u8 ie_len_he_cap, ie_len_eht_cap; u8 ie_len_he_cap, ie_len_eht_cap;
u8 *pos; u8 *pos;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon); int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon);
u32 rate_flags;
sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh); sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); sband = ieee80211_get_sband(sdata);
band = chanctx_conf->def.chan->band; rate_flags =
rcu_read_unlock(); ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper);
ie_len_he_cap = ieee80211_ie_len_he_cap(sdata); ie_len_he_cap = ieee80211_ie_len_he_cap(sdata);
ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata); ie_len_eht_cap = ieee80211_ie_len_eht_cap(sdata);
...@@ -1107,7 +1107,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) ...@@ -1107,7 +1107,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
} }
rcu_read_unlock(); rcu_read_unlock();
if (ieee80211_add_srates_ie(sdata, skb, true, band) || if (ieee80211_put_srates_elem(skb, sband,
sdata->vif.bss_conf.basic_rates,
rate_flags, 0, WLAN_EID_SUPP_RATES) ||
mesh_add_ds_params_ie(sdata, skb)) mesh_add_ds_params_ie(sdata, skb))
goto out_free; goto out_free;
...@@ -1118,7 +1120,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh) ...@@ -1118,7 +1120,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
skb_trim(skb, 0); skb_trim(skb, 0);
bcn->tail = bcn->head + bcn->head_len; bcn->tail = bcn->head + bcn->head_len;
if (ieee80211_add_ext_srates_ie(sdata, skb, true, band) || if (ieee80211_put_srates_elem(skb, sband,
sdata->vif.bss_conf.basic_rates,
rate_flags, 0, WLAN_EID_EXT_SUPP_RATES) ||
mesh_add_rsn_ie(sdata, skb) || mesh_add_rsn_ie(sdata, skb) ||
mesh_add_ht_cap_ie(sdata, skb) || mesh_add_ht_cap_ie(sdata, skb) ||
mesh_add_ht_oper_ie(sdata, skb) || mesh_add_ht_oper_ie(sdata, skb) ||
......
...@@ -264,14 +264,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, ...@@ -264,14 +264,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
if (action != WLAN_SP_MESH_PEERING_CLOSE) { if (action != WLAN_SP_MESH_PEERING_CLOSE) {
struct ieee80211_supported_band *sband; struct ieee80211_supported_band *sband;
enum nl80211_band band; u32 rate_flags, basic_rates;
sband = ieee80211_get_sband(sdata); sband = ieee80211_get_sband(sdata);
if (!sband) { if (!sband) {
err = -EINVAL; err = -EINVAL;
goto free; goto free;
} }
band = sband->band;
/* capability info */ /* capability info */
pos = skb_put_zero(skb, 2); pos = skb_put_zero(skb, 2);
...@@ -280,8 +279,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, ...@@ -280,8 +279,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, 2); pos = skb_put(skb, 2);
put_unaligned_le16(sta->sta.aid, pos); put_unaligned_le16(sta->sta.aid, pos);
} }
if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
ieee80211_add_ext_srates_ie(sdata, skb, true, band) || rate_flags =
ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper);
basic_rates = sdata->vif.bss_conf.basic_rates;
if (ieee80211_put_srates_elem(skb, sband, basic_rates,
rate_flags, 0,
WLAN_EID_SUPP_RATES) ||
ieee80211_put_srates_elem(skb, sband, basic_rates,
rate_flags, 0,
WLAN_EID_EXT_SUPP_RATES) ||
mesh_add_rsn_ie(sdata, skb) || mesh_add_rsn_ie(sdata, skb) ||
mesh_add_meshid_ie(sdata, skb) || mesh_add_meshid_ie(sdata, skb) ||
mesh_add_meshconf_ie(sdata, skb)) mesh_add_meshconf_ie(sdata, skb))
......
...@@ -1110,10 +1110,7 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb, ...@@ -1110,10 +1110,7 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb,
struct ieee80211_supported_band *sband, struct ieee80211_supported_band *sband,
struct ieee80211_mgd_assoc_data *assoc_data) struct ieee80211_mgd_assoc_data *assoc_data)
{ {
unsigned int rates_len, supp_rates_len; u32 rates;
u32 rates = 0;
int i, count;
u8 *pos;
if (assoc_data->supp_rates_len) { if (assoc_data->supp_rates_len) {
/* /*
...@@ -1122,53 +1119,23 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb, ...@@ -1122,53 +1119,23 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb,
* in the association request (e.g. D-Link DAP 1353 in * in the association request (e.g. D-Link DAP 1353 in
* b-only mode)... * b-only mode)...
*/ */
rates_len = ieee80211_parse_bitrates(width, sband, ieee80211_parse_bitrates(width, sband,
assoc_data->supp_rates, assoc_data->supp_rates,
assoc_data->supp_rates_len, assoc_data->supp_rates_len,
&rates); &rates);
} else { } else {
/* /*
* In case AP not provide any supported rates information * In case AP not provide any supported rates information
* before association, we send information element(s) with * before association, we send information element(s) with
* all rates that we support. * all rates that we support.
*/ */
rates_len = sband->n_bitrates; rates = ~0;
for (i = 0; i < sband->n_bitrates; i++)
rates |= BIT(i);
}
supp_rates_len = rates_len;
if (supp_rates_len > 8)
supp_rates_len = 8;
pos = skb_put(skb, supp_rates_len + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = supp_rates_len;
count = 0;
for (i = 0; i < sband->n_bitrates; i++) {
if (BIT(i) & rates) {
int rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5);
*pos++ = (u8)rate;
if (++count == 8)
break;
}
} }
if (rates_len > count) { ieee80211_put_srates_elem(skb, sband, 0, 0, ~rates,
pos = skb_put(skb, rates_len - count + 2); WLAN_EID_SUPP_RATES);
*pos++ = WLAN_EID_EXT_SUPP_RATES; ieee80211_put_srates_elem(skb, sband, 0, 0, ~rates,
*pos++ = rates_len - count; WLAN_EID_EXT_SUPP_RATES);
for (i++; i < sband->n_bitrates; i++) {
if (BIT(i) & rates) {
int rate;
rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5);
*pos++ = (u8)rate;
}
}
}
} }
static size_t ieee80211_add_before_ht_elems(struct sk_buff *skb, static size_t ieee80211_add_before_ht_elems(struct sk_buff *skb,
......
...@@ -382,8 +382,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link, ...@@ -382,8 +382,8 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_link_data *link,
if (WARN_ON_ONCE(!sband)) if (WARN_ON_ONCE(!sband))
return; return;
ieee80211_add_srates_ie(sdata, skb, false, sband->band); ieee80211_put_srates_elem(skb, sband, 0, 0, 0, WLAN_EID_SUPP_RATES);
ieee80211_add_ext_srates_ie(sdata, skb, false, sband->band); ieee80211_put_srates_elem(skb, sband, 0, 0, 0, WLAN_EID_EXT_SUPP_RATES);
ieee80211_tdls_add_supp_channels(sdata, skb); ieee80211_tdls_add_supp_channels(sdata, skb);
/* add any custom IEs that go before Extended Capabilities */ /* add any custom IEs that go before Extended Capabilities */
......
...@@ -4091,93 +4091,62 @@ int ieee80211_parse_bitrates(enum nl80211_chan_width width, ...@@ -4091,93 +4091,62 @@ int ieee80211_parse_bitrates(enum nl80211_chan_width width,
return count; return count;
} }
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, int ieee80211_put_srates_elem(struct sk_buff *skb,
struct sk_buff *skb, bool need_basic, const struct ieee80211_supported_band *sband,
enum nl80211_band band) u32 basic_rates, u32 rate_flags, u32 masked_rates,
u8 element_id)
{ {
struct ieee80211_local *local = sdata->local; u8 i, rates, skip;
struct ieee80211_supported_band *sband;
int rate;
u8 i, rates, *pos;
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
u32 rate_flags;
rate_flags =
ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper);
sband = local->hw.wiphy->bands[band];
rates = 0; rates = 0;
for (i = 0; i < sband->n_bitrates; i++) { for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags) != rate_flags) if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
continue; continue;
if (masked_rates & BIT(i))
continue;
rates++; rates++;
} }
if (rates > 8)
rates = 8;
if (skb_tailroom(skb) < rates + 2) if (element_id == WLAN_EID_SUPP_RATES) {
return -ENOMEM; rates = min_t(u8, rates, 8);
skip = 0;
pos = skb_put(skb, rates + 2); } else {
*pos++ = WLAN_EID_SUPP_RATES; skip = 8;
*pos++ = rates; if (rates <= skip)
for (i = 0; i < rates; i++) { return 0;
u8 basic = 0; rates -= skip;
if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
continue;
if (need_basic && basic_rates & BIT(i))
basic = 0x80;
rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5);
*pos++ = basic | (u8) rate;
} }
return 0; if (skb_tailroom(skb) < rates + 2)
} return -ENOBUFS;
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, skb_put_u8(skb, element_id);
struct sk_buff *skb, bool need_basic, skb_put_u8(skb, rates);
enum nl80211_band band)
{ for (i = 0; i < sband->n_bitrates && rates; i++) {
struct ieee80211_local *local = sdata->local; int rate;
struct ieee80211_supported_band *sband; u8 basic;
int rate;
u8 i, exrates, *pos;
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
u32 rate_flags;
rate_flags =
ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper);
sband = local->hw.wiphy->bands[band];
exrates = 0;
for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags) != rate_flags) if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
continue; continue;
exrates++; if (masked_rates & BIT(i))
} continue;
if (exrates > 8) if (skip > 0) {
exrates -= 8; skip--;
else continue;
exrates = 0; }
if (skb_tailroom(skb) < exrates + 2) basic = basic_rates & BIT(i) ? 0x80 : 0;
return -ENOMEM;
if (exrates) { rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5);
pos = skb_put(skb, exrates + 2); skb_put_u8(skb, basic | (u8)rate);
*pos++ = WLAN_EID_EXT_SUPP_RATES; rates--;
*pos++ = exrates;
for (i = 8; i < sband->n_bitrates; i++) {
u8 basic = 0;
if ((rate_flags & sband->bitrates[i].flags)
!= rate_flags)
continue;
if (need_basic && basic_rates & BIT(i))
basic = 0x80;
rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5);
*pos++ = basic | (u8) rate;
}
} }
WARN(rates > 0, "rates confused: rates:%d, element:%d\n",
rates, element_id);
return 0; return 0;
} }
......
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