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,
int ieee80211_parse_bitrates(enum nl80211_chan_width width,
const struct ieee80211_supported_band *sband,
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);
void ieee80211_add_s1g_capab_ie(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_s1g_cap *caps,
......@@ -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);
/* 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,
struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode);
......
......@@ -968,19 +968,19 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
int head_len, tail_len;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
struct ieee80211_chanctx_conf *chanctx_conf;
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 *pos;
struct ieee80211_sub_if_data *sdata;
int hdr_len = offsetofend(struct ieee80211_mgmt, u.beacon);
u32 rate_flags;
sdata = container_of(ifmsh, struct ieee80211_sub_if_data, u.mesh);
rcu_read_lock();
chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
band = chanctx_conf->def.chan->band;
rcu_read_unlock();
sband = ieee80211_get_sband(sdata);
rate_flags =
ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper);
ie_len_he_cap = ieee80211_ie_len_he_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)
}
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))
goto out_free;
......@@ -1118,7 +1120,9 @@ ieee80211_mesh_build_beacon(struct ieee80211_if_mesh *ifmsh)
skb_trim(skb, 0);
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_ht_cap_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,
if (action != WLAN_SP_MESH_PEERING_CLOSE) {
struct ieee80211_supported_band *sband;
enum nl80211_band band;
u32 rate_flags, basic_rates;
sband = ieee80211_get_sband(sdata);
if (!sband) {
err = -EINVAL;
goto free;
}
band = sband->band;
/* capability info */
pos = skb_put_zero(skb, 2);
......@@ -280,8 +279,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
pos = skb_put(skb, 2);
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_meshid_ie(sdata, skb) ||
mesh_add_meshconf_ie(sdata, skb))
......
......@@ -1110,10 +1110,7 @@ static void ieee80211_assoc_add_rates(struct sk_buff *skb,
struct ieee80211_supported_band *sband,
struct ieee80211_mgd_assoc_data *assoc_data)
{
unsigned int rates_len, supp_rates_len;
u32 rates = 0;
int i, count;
u8 *pos;
u32 rates;
if (assoc_data->supp_rates_len) {
/*
......@@ -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
* b-only mode)...
*/
rates_len = ieee80211_parse_bitrates(width, sband,
assoc_data->supp_rates,
assoc_data->supp_rates_len,
&rates);
ieee80211_parse_bitrates(width, sband,
assoc_data->supp_rates,
assoc_data->supp_rates_len,
&rates);
} else {
/*
* In case AP not provide any supported rates information
* before association, we send information element(s) with
* all rates that we support.
*/
rates_len = sband->n_bitrates;
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;
}
rates = ~0;
}
if (rates_len > count) {
pos = skb_put(skb, rates_len - count + 2);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = rates_len - count;
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;
}
}
}
ieee80211_put_srates_elem(skb, sband, 0, 0, ~rates,
WLAN_EID_SUPP_RATES);
ieee80211_put_srates_elem(skb, sband, 0, 0, ~rates,
WLAN_EID_EXT_SUPP_RATES);
}
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,
if (WARN_ON_ONCE(!sband))
return;
ieee80211_add_srates_ie(sdata, skb, false, sband->band);
ieee80211_add_ext_srates_ie(sdata, skb, false, sband->band);
ieee80211_put_srates_elem(skb, sband, 0, 0, 0, WLAN_EID_SUPP_RATES);
ieee80211_put_srates_elem(skb, sband, 0, 0, 0, WLAN_EID_EXT_SUPP_RATES);
ieee80211_tdls_add_supp_channels(sdata, skb);
/* add any custom IEs that go before Extended Capabilities */
......
......@@ -4091,93 +4091,62 @@ int ieee80211_parse_bitrates(enum nl80211_chan_width width,
return count;
}
int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool need_basic,
enum nl80211_band band)
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)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
int rate;
u8 i, rates, *pos;
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
u32 rate_flags;
u8 i, rates, skip;
rate_flags =
ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chanreq.oper);
sband = local->hw.wiphy->bands[band];
rates = 0;
for (i = 0; i < sband->n_bitrates; i++) {
if ((rate_flags & sband->bitrates[i].flags) != rate_flags)
continue;
if (masked_rates & BIT(i))
continue;
rates++;
}
if (rates > 8)
rates = 8;
if (skb_tailroom(skb) < rates + 2)
return -ENOMEM;
pos = skb_put(skb, rates + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = rates;
for (i = 0; i < rates; 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;
if (element_id == WLAN_EID_SUPP_RATES) {
rates = min_t(u8, rates, 8);
skip = 0;
} else {
skip = 8;
if (rates <= skip)
return 0;
rates -= skip;
}
return 0;
}
if (skb_tailroom(skb) < rates + 2)
return -ENOBUFS;
int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, bool need_basic,
enum nl80211_band band)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
int rate;
u8 i, exrates, *pos;
u32 basic_rates = sdata->vif.bss_conf.basic_rates;
u32 rate_flags;
skb_put_u8(skb, element_id);
skb_put_u8(skb, rates);
for (i = 0; i < sband->n_bitrates && rates; i++) {
int rate;
u8 basic;
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)
continue;
exrates++;
}
if (masked_rates & BIT(i))
continue;
if (exrates > 8)
exrates -= 8;
else
exrates = 0;
if (skip > 0) {
skip--;
continue;
}
if (skb_tailroom(skb) < exrates + 2)
return -ENOMEM;
basic = basic_rates & BIT(i) ? 0x80 : 0;
if (exrates) {
pos = skb_put(skb, exrates + 2);
*pos++ = WLAN_EID_EXT_SUPP_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;
}
rate = DIV_ROUND_UP(sband->bitrates[i].bitrate, 5);
skb_put_u8(skb, basic | (u8)rate);
rates--;
}
WARN(rates > 0, "rates confused: rates:%d, element:%d\n",
rates, element_id);
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