From 8b783d104e7f40684333d2ec155fac39219beb2f Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 5 Oct 2020 09:45:21 -0700 Subject: mac80211: handle lack of sband->bitrates in rates Even though a driver or mac80211 shouldn't produce a legacy bitrate if sband->bitrates doesn't exist, don't crash if that is the case either. This fixes a kernel panic if station dump is run before last_rate can be updated with a data frame when sband->bitrates is missing (eg. in S1G bands). Signed-off-by: Thomas Pedersen Link: https://lore.kernel.org/r/20201005164522.18069-1-thomas@adapt-ip.com Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 3 ++- net/mac80211/sta_info.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index da70f174d629..eb52aafd9381 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -709,7 +709,8 @@ void sta_set_rate_info_tx(struct sta_info *sta, u16 brate; sband = ieee80211_get_sband(sta->sdata); - if (sband) { + WARN_ON_ONCE(sband && !sband->bitrates); + if (sband && sband->bitrates) { brate = sband->bitrates[rate->idx].bitrate; rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f2840d1d95cf..fb4f2b9b294f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -2122,6 +2122,10 @@ static void sta_stats_decode_rate(struct ieee80211_local *local, u32 rate, int rate_idx = STA_STATS_GET(LEGACY_IDX, rate); sband = local->hw.wiphy->bands[band]; + + if (WARN_ON_ONCE(!sband->bitrates)) + break; + brate = sband->bitrates[rate_idx].bitrate; if (rinfo->bw == RATE_INFO_BW_5) shift = 2; -- cgit v1.2.3 From 12bf8fad4ca3cf712f80766be017a521757e14c7 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 5 Oct 2020 09:45:22 -0700 Subject: mac80211: initialize last_rate for S1G STAs last_rate is initialized to zero by sta_info_alloc(), but this indicates legacy bitrate for the last TX rate (and invalid for the last RX rate). To avoid a warning when decoding the last rate as legacy (before a data frame has been sent), initialize them as S1G MCS. Signed-off-by: Thomas Pedersen Link: https://lore.kernel.org/r/20201005164522.18069-2-thomas@adapt-ip.com [rename to ieee80211_s1g_sta_rate_init(), seems more appropriate] Signed-off-by: Johannes Berg --- net/mac80211/Makefile | 1 + net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/mlme.c | 4 +++- net/mac80211/rate.c | 1 + net/mac80211/s1g.c | 16 ++++++++++++++++ net/mac80211/sta_info.h | 1 + 6 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 net/mac80211/s1g.c (limited to 'net') diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 6cbb1286d6c0..ad04c361cba5 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -13,6 +13,7 @@ mac80211-y := \ ht.o agg-tx.o agg-rx.o \ vht.o \ he.o \ + s1g.o \ ibss.o \ iface.o \ rate.o \ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c3e3578574a6..2a21226fb518 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1928,6 +1928,9 @@ void ieee80211_he_op_ie_to_bss_conf(struct ieee80211_vif *vif, const struct ieee80211_he_operation *he_op_ie_elem); +/* S1G */ +void ieee80211_s1g_sta_rate_init(struct sta_info *sta); + /* Spectrum management */ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt, diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e9a8e8e94ee6..f400240a556f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5190,8 +5190,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, int shift = ieee80211_vif_get_shift(&sdata->vif); /* TODO: S1G Basic Rate Set is expressed elsewhere */ - if (cbss->channel->band == NL80211_BAND_S1GHZ) + if (cbss->channel->band == NL80211_BAND_S1GHZ) { + ieee80211_s1g_sta_rate_init(new_sta); goto skip_rates; + } ieee80211_get_rates(sband, bss->supp_rates, bss->supp_rates_len, diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 0cba7fed28cf..45927202c71c 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -53,6 +53,7 @@ void rate_control_rate_init(struct sta_info *sta) /* TODO: check for minstrel_s1g ? */ if (sband->band == NL80211_BAND_S1GHZ) { + ieee80211_s1g_sta_rate_init(sta); rcu_read_unlock(); return; } diff --git a/net/mac80211/s1g.c b/net/mac80211/s1g.c new file mode 100644 index 000000000000..c33f332b049a --- /dev/null +++ b/net/mac80211/s1g.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * S1G handling + * Copyright(c) 2020 Adapt-IP + */ +#include +#include +#include "ieee80211_i.h" + +void ieee80211_s1g_sta_rate_init(struct sta_info *sta) +{ + /* avoid indicating legacy bitrates for S1G STAs */ + sta->tx_stats.last_rate.flags |= IEEE80211_TX_RC_S1G_MCS; + sta->rx_stats.last_rate = + STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G); +} diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 91a61b44b4e0..00ae81e9e1a1 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -823,6 +823,7 @@ enum sta_stats_type { STA_STATS_RATE_TYPE_HT, STA_STATS_RATE_TYPE_VHT, STA_STATS_RATE_TYPE_HE, + STA_STATS_RATE_TYPE_S1G, }; #define STA_STATS_FIELD_HT_MCS GENMASK( 7, 0) -- cgit v1.2.3 From c1cd35c6060140cebf85f43f8c702abef9eca997 Mon Sep 17 00:00:00 2001 From: Thomas Pedersen Date: Mon, 5 Oct 2020 09:51:22 -0700 Subject: cfg80211: only allow S1G channels on S1G band As discovered by syzbot, cfg80211 was accepting S1G channel widths on non-S1G bands. Add a check for this, and consolidate the 1MHz frequency check as it ends up being a subset of the others. Reported-by: syzbot+92715a0eccd6c881bc32@syzkaller.appspotmail.com Fixes: 11b34737b18a ("nl80211: support setting S1G channels") Signed-off-by: Thomas Pedersen Link: https://lore.kernel.org/r/20201005165122.17583-1-thomas@adapt-ip.com Signed-off-by: Johannes Berg --- net/wireless/chan.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 96e24ee4c7e8..22d1779ab2b1 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -207,7 +207,6 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) control_freq = chandef->chan->center_freq; switch (chandef->width) { - case NL80211_CHAN_WIDTH_1: case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: case NL80211_CHAN_WIDTH_20: @@ -218,10 +217,14 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef) if (chandef->center_freq2) return false; break; + case NL80211_CHAN_WIDTH_1: case NL80211_CHAN_WIDTH_2: case NL80211_CHAN_WIDTH_4: case NL80211_CHAN_WIDTH_8: case NL80211_CHAN_WIDTH_16: + if (chandef->chan->band != NL80211_BAND_S1GHZ) + return false; + control_freq = ieee80211_channel_to_khz(chandef->chan); oper_freq = ieee80211_chandef_to_khz(chandef); control_width = nl80211_chan_width_to_mhz( -- cgit v1.2.3 From ba6ff70a3bb76c1ff440d3a0044b82e97abb648f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 3 Oct 2020 15:04:18 -0700 Subject: mac80211: copy configured beacon tx rate to driver The user is allowed to change beacon tx rate (HT/VHT/HE) from hostapd. This information needs to be passed to the driver when the rate control is offloaded to the firmware. The driver capability of allowing beacon rate is already validated in cfg80211, so simply passing the rate information to the driver is enough. Signed-off-by: Rajkumar Manoharan Link: https://lore.kernel.org/r/1601762658-15627-1-git-send-email-rmanohar@codeaurora.org [adjust commit message slightly] Signed-off-by: Johannes Berg --- include/net/mac80211.h | 3 +++ net/mac80211/cfg.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4747d446179a..e8e295dae744 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -628,6 +628,8 @@ struct ieee80211_fils_discovery { * @unsol_bcast_probe_resp_interval: Unsolicited broadcast probe response * interval. * @s1g: BSS is S1G BSS (affects Association Request format). + * @beacon_tx_rate: The configured beacon transmit rate that needs to be passed + * to driver when rate control is offloaded to firmware. */ struct ieee80211_bss_conf { const u8 *bssid; @@ -698,6 +700,7 @@ struct ieee80211_bss_conf { struct ieee80211_fils_discovery fils_discovery; u32 unsol_bcast_probe_resp_interval; bool s1g; + struct cfg80211_bitrate_mask beacon_tx_rate; }; /** diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index eb52aafd9381..7276e66ae435 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1154,6 +1154,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, } } + if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) + sdata->vif.bss_conf.beacon_tx_rate = params->beacon_rate; + err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); if (err < 0) goto error; -- cgit v1.2.3