Commit 585625c9 authored by Johannes Berg's avatar Johannes Berg

mac80211_hwsim: check TX and STA bandwidth

Add checks to hwsim to validate that neither TX nor any
station's configured bandwidth can exceed the channel
(context) configuration previously requested.

Link: https://lore.kernel.org/r/20220214173004.9fd154d2c3c2.Ia0cd152357a373149bab017d479ab7d5ded289c0@changeidSigned-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent a3a20feb
...@@ -654,6 +654,7 @@ struct mac80211_hwsim_data { ...@@ -654,6 +654,7 @@ struct mac80211_hwsim_data {
ARRAY_SIZE(hwsim_channels_6ghz)]; ARRAY_SIZE(hwsim_channels_6ghz)];
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
enum nl80211_chan_width bw;
u64 beacon_int /* beacon interval in us */; u64 beacon_int /* beacon interval in us */;
unsigned int rx_filter; unsigned int rx_filter;
bool started, idle, scanning; bool started, idle, scanning;
...@@ -808,6 +809,38 @@ extern int hwsim_tx_virtio(struct mac80211_hwsim_data *data, ...@@ -808,6 +809,38 @@ extern int hwsim_tx_virtio(struct mac80211_hwsim_data *data,
#define hwsim_virtio_enabled false #define hwsim_virtio_enabled false
#endif #endif
static int hwsim_get_chanwidth(enum nl80211_chan_width bw)
{
switch (bw) {
case NL80211_CHAN_WIDTH_20_NOHT:
case NL80211_CHAN_WIDTH_20:
return 20;
case NL80211_CHAN_WIDTH_40:
return 40;
case NL80211_CHAN_WIDTH_80:
return 80;
case NL80211_CHAN_WIDTH_80P80:
case NL80211_CHAN_WIDTH_160:
return 160;
case NL80211_CHAN_WIDTH_5:
return 5;
case NL80211_CHAN_WIDTH_10:
return 10;
case NL80211_CHAN_WIDTH_1:
return 1;
case NL80211_CHAN_WIDTH_2:
return 2;
case NL80211_CHAN_WIDTH_4:
return 4;
case NL80211_CHAN_WIDTH_8:
return 8;
case NL80211_CHAN_WIDTH_16:
return 16;
}
return INT_MAX;
}
static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
struct sk_buff *skb, struct sk_buff *skb,
struct ieee80211_channel *chan); struct ieee80211_channel *chan);
...@@ -1623,7 +1656,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, ...@@ -1623,7 +1656,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
bool ack; bool ack;
u32 _portid; enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
u32 _portid, i;
if (WARN_ON(skb->len < 10)) { if (WARN_ON(skb->len < 10)) {
/* Should not happen; just a sanity check for addr1 use */ /* Should not happen; just a sanity check for addr1 use */
...@@ -1633,14 +1667,17 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, ...@@ -1633,14 +1667,17 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
if (!data->use_chanctx) { if (!data->use_chanctx) {
channel = data->channel; channel = data->channel;
confbw = data->bw;
} else if (txi->hw_queue == 4) { } else if (txi->hw_queue == 4) {
channel = data->tmp_chan; channel = data->tmp_chan;
} else { } else {
chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf); chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf);
if (chanctx_conf) if (chanctx_conf) {
channel = chanctx_conf->def.chan; channel = chanctx_conf->def.chan;
else confbw = chanctx_conf->def.width;
} else {
channel = NULL; channel = NULL;
}
} }
if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) { if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
...@@ -1664,6 +1701,25 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, ...@@ -1664,6 +1701,25 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
txi->control.rates, txi->control.rates,
ARRAY_SIZE(txi->control.rates)); ARRAY_SIZE(txi->control.rates));
for (i = 0; i < ARRAY_SIZE(txi->control.rates); i++) {
u16 rflags = txi->control.rates[i].flags;
/* initialize to data->bw for 5/10 MHz handling */
enum nl80211_chan_width bw = data->bw;
if (txi->control.rates[i].idx == -1)
break;
if (rflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
bw = NL80211_CHAN_WIDTH_40;
else if (rflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
bw = NL80211_CHAN_WIDTH_80;
else if (rflags & IEEE80211_TX_RC_160_MHZ_WIDTH)
bw = NL80211_CHAN_WIDTH_160;
if (WARN_ON(hwsim_get_chanwidth(bw) > hwsim_get_chanwidth(confbw)))
return;
}
if (skb->len >= 24 + 8 && if (skb->len >= 24 + 8 &&
ieee80211_is_probe_resp(hdr->frame_control)) { ieee80211_is_probe_resp(hdr->frame_control)) {
/* fake header transmission time */ /* fake header transmission time */
...@@ -1963,6 +2019,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) ...@@ -1963,6 +2019,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
} }
data->channel = conf->chandef.chan; data->channel = conf->chandef.chan;
data->bw = conf->chandef.width;
for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) { for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) {
if (data->survey_data[idx].channel && if (data->survey_data[idx].channel &&
...@@ -1974,6 +2031,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) ...@@ -1974,6 +2031,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
} }
} else { } else {
data->channel = conf->chandef.chan; data->channel = conf->chandef.chan;
data->bw = conf->chandef.width;
} }
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
...@@ -2105,12 +2163,48 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, ...@@ -2105,12 +2163,48 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
wiphy_dbg(hw->wiphy, " TX Power: %d dBm\n", info->txpower); wiphy_dbg(hw->wiphy, " TX Power: %d dBm\n", info->txpower);
} }
static void
mac80211_hwsim_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
u32 changed)
{
struct mac80211_hwsim_data *data = hw->priv;
u32 bw = U32_MAX;
enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
switch (sta->bandwidth) {
#define C(_bw) case IEEE80211_STA_RX_BW_##_bw: bw = _bw; break
C(20);
C(40);
C(80);
C(160);
#undef C
}
if (!data->use_chanctx) {
confbw = data->bw;
} else {
struct ieee80211_chanctx_conf *chanctx_conf =
rcu_dereference(vif->chanctx_conf);
if (!WARN_ON(!chanctx_conf))
confbw = chanctx_conf->def.width;
}
WARN(bw > hwsim_get_chanwidth(confbw),
"intf %pM: bad STA %pM bandwidth %d MHz (%d) > channel config %d MHz (%d)\n",
vif->addr, sta->addr, bw, sta->bandwidth,
hwsim_get_chanwidth(data->bw), data->bw);
}
static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw, static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta) struct ieee80211_sta *sta)
{ {
hwsim_check_magic(vif); hwsim_check_magic(vif);
hwsim_set_sta_magic(sta); hwsim_set_sta_magic(sta);
mac80211_hwsim_sta_rc_update(hw, vif, sta, 0);
return 0; return 0;
} }
...@@ -2677,6 +2771,7 @@ static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw) ...@@ -2677,6 +2771,7 @@ static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw)
.sta_add = mac80211_hwsim_sta_add, \ .sta_add = mac80211_hwsim_sta_add, \
.sta_remove = mac80211_hwsim_sta_remove, \ .sta_remove = mac80211_hwsim_sta_remove, \
.sta_notify = mac80211_hwsim_sta_notify, \ .sta_notify = mac80211_hwsim_sta_notify, \
.sta_rc_update = mac80211_hwsim_sta_rc_update, \
.set_tim = mac80211_hwsim_set_tim, \ .set_tim = mac80211_hwsim_set_tim, \
.conf_tx = mac80211_hwsim_conf_tx, \ .conf_tx = mac80211_hwsim_conf_tx, \
.get_survey = mac80211_hwsim_get_survey, \ .get_survey = mac80211_hwsim_get_survey, \
......
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