diff mbox series

mac80211_hwsim: check TX and STA bandwidth

Message ID 20220204174105.5026d3892bf6.Ia0cd152357a373149bab017d479ab7d5ded289c0@changeid
State Superseded
Headers show
Series mac80211_hwsim: check TX and STA bandwidth | expand

Commit Message

Johannes Berg Feb. 4, 2022, 4:41 p.m. UTC
From: Johannes Berg <johannes.berg@intel.com>

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

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 drivers/net/wireless/mac80211_hwsim.c | 90 ++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 3 deletions(-)

Comments

kernel test robot Feb. 4, 2022, 6:39 p.m. UTC | #1
Hi Johannes,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc2 next-20220204]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Johannes-Berg/mac80211_hwsim-check-TX-and-STA-bandwidth/20220205-004233
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git dcb85f85fa6f142aae1fe86f399d4503d49f2b60
config: mips-allyesconfig (https://download.01.org/0day-ci/archive/20220205/202202050254.pz3jVGvO-lkp@intel.com/config)
compiler: mips-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/99f1c0b151e550eed22429c2eb48876108bf3de7
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Johannes-Berg/mac80211_hwsim-check-TX-and-STA-bandwidth/20220205-004233
        git checkout 99f1c0b151e550eed22429c2eb48876108bf3de7
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=mips SHELL=/bin/bash drivers/net/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

   drivers/net/wireless/mac80211_hwsim.c: In function 'mac80211_hwsim_tx':
>> drivers/net/wireless/mac80211_hwsim.c:1631:33: warning: variable 'confbw' set but not used [-Wunused-but-set-variable]
    1631 |         enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
         |                                 ^~~~~~


vim +/confbw +1631 drivers/net/wireless/mac80211_hwsim.c

  1620	
  1621	static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
  1622				      struct ieee80211_tx_control *control,
  1623				      struct sk_buff *skb)
  1624	{
  1625		struct mac80211_hwsim_data *data = hw->priv;
  1626		struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
  1627		struct ieee80211_hdr *hdr = (void *)skb->data;
  1628		struct ieee80211_chanctx_conf *chanctx_conf;
  1629		struct ieee80211_channel *channel;
  1630		bool ack;
> 1631		enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
  1632		u32 _portid, i;
  1633	
  1634		if (WARN_ON(skb->len < 10)) {
  1635			/* Should not happen; just a sanity check for addr1 use */
  1636			ieee80211_free_txskb(hw, skb);
  1637			return;
  1638		}
  1639	
  1640		if (!data->use_chanctx) {
  1641			channel = data->channel;
  1642			confbw = data->bw;
  1643		} else if (txi->hw_queue == 4) {
  1644			channel = data->tmp_chan;
  1645		} else {
  1646			chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf);
  1647			if (chanctx_conf) {
  1648				channel = chanctx_conf->def.chan;
  1649				confbw = chanctx_conf->def.width;
  1650			} else {
  1651				channel = NULL;
  1652			}
  1653		}
  1654	
  1655		if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
  1656			ieee80211_free_txskb(hw, skb);
  1657			return;
  1658		}
  1659	
  1660		if (data->idle && !data->tmp_chan) {
  1661			wiphy_dbg(hw->wiphy, "Trying to TX when idle - reject\n");
  1662			ieee80211_free_txskb(hw, skb);
  1663			return;
  1664		}
  1665	
  1666		if (txi->control.vif)
  1667			hwsim_check_magic(txi->control.vif);
  1668		if (control->sta)
  1669			hwsim_check_sta_magic(control->sta);
  1670	
  1671		if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
  1672			ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
  1673					       txi->control.rates,
  1674					       ARRAY_SIZE(txi->control.rates));
  1675	
  1676		for (i = 0; i < ARRAY_SIZE(txi->control.rates); i++) {
  1677			u16 rflags = txi->control.rates[i].flags;
  1678			/* initialize to data->bw for 5/10 MHz handling */
  1679			enum nl80211_chan_width bw = data->bw;
  1680	
  1681			if (txi->control.rates[i].idx == -1)
  1682				break;
  1683	
  1684			if (rflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
  1685				bw = NL80211_CHAN_WIDTH_40;
  1686			else if (rflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
  1687				bw = NL80211_CHAN_WIDTH_80;
  1688			else if (rflags & IEEE80211_TX_RC_160_MHZ_WIDTH)
  1689				bw = NL80211_CHAN_WIDTH_160;
  1690	
  1691			if (WARN_ON(hwsim_get_chanwidth(bw) > hwsim_get_chanwidth(data->bw)))
  1692				return;
  1693		}
  1694	
  1695		if (skb->len >= 24 + 8 &&
  1696		    ieee80211_is_probe_resp(hdr->frame_control)) {
  1697			/* fake header transmission time */
  1698			struct ieee80211_mgmt *mgmt;
  1699			struct ieee80211_rate *txrate;
  1700			/* TODO: get MCS */
  1701			int bitrate = 100;
  1702			u64 ts;
  1703	
  1704			mgmt = (struct ieee80211_mgmt *)skb->data;
  1705			txrate = ieee80211_get_tx_rate(hw, txi);
  1706			if (txrate)
  1707				bitrate = txrate->bitrate;
  1708			ts = mac80211_hwsim_get_tsf_raw();
  1709			mgmt->u.probe_resp.timestamp =
  1710				cpu_to_le64(ts + data->tsf_offset +
  1711					    24 * 8 * 10 / bitrate);
  1712		}
  1713	
  1714		mac80211_hwsim_monitor_rx(hw, skb, channel);
  1715	
  1716		/* wmediumd mode check */
  1717		_portid = READ_ONCE(data->wmediumd);
  1718	
  1719		if (_portid || hwsim_virtio_enabled)
  1720			return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel);
  1721	
  1722		/* NO wmediumd detected, perfect medium simulation */
  1723		data->tx_pkts++;
  1724		data->tx_bytes += skb->len;
  1725		ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
  1726	
  1727		if (ack && skb->len >= 16)
  1728			mac80211_hwsim_monitor_ack(channel, hdr->addr2);
  1729	
  1730		ieee80211_tx_info_clear_status(txi);
  1731	
  1732		/* frame was transmitted at most favorable rate at first attempt */
  1733		txi->control.rates[0].count = 1;
  1734		txi->control.rates[1].idx = -1;
  1735	
  1736		if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
  1737			txi->flags |= IEEE80211_TX_STAT_ACK;
  1738		ieee80211_tx_status_irqsafe(hw, skb);
  1739	}
  1740	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
kernel test robot Feb. 4, 2022, 10:33 p.m. UTC | #2
Hi Johannes,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.17-rc2 next-20220204]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Johannes-Berg/mac80211_hwsim-check-TX-and-STA-bandwidth/20220205-004233
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git dcb85f85fa6f142aae1fe86f399d4503d49f2b60
config: hexagon-randconfig-r041-20220204 (https://download.01.org/0day-ci/archive/20220205/202202050604.dzCxQjWk-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project a73e4ce6a59b01f0e37037761c1e6889d539d233)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/99f1c0b151e550eed22429c2eb48876108bf3de7
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Johannes-Berg/mac80211_hwsim-check-TX-and-STA-bandwidth/20220205-004233
        git checkout 99f1c0b151e550eed22429c2eb48876108bf3de7
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=hexagon SHELL=/bin/bash drivers/net/wireless/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/net/wireless/mac80211_hwsim.c:1631:26: warning: variable 'confbw' set but not used [-Wunused-but-set-variable]
           enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
                                   ^
   1 warning generated.


vim +/confbw +1631 drivers/net/wireless/mac80211_hwsim.c

  1620	
  1621	static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
  1622				      struct ieee80211_tx_control *control,
  1623				      struct sk_buff *skb)
  1624	{
  1625		struct mac80211_hwsim_data *data = hw->priv;
  1626		struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
  1627		struct ieee80211_hdr *hdr = (void *)skb->data;
  1628		struct ieee80211_chanctx_conf *chanctx_conf;
  1629		struct ieee80211_channel *channel;
  1630		bool ack;
> 1631		enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
  1632		u32 _portid, i;
  1633	
  1634		if (WARN_ON(skb->len < 10)) {
  1635			/* Should not happen; just a sanity check for addr1 use */
  1636			ieee80211_free_txskb(hw, skb);
  1637			return;
  1638		}
  1639	
  1640		if (!data->use_chanctx) {
  1641			channel = data->channel;
  1642			confbw = data->bw;
  1643		} else if (txi->hw_queue == 4) {
  1644			channel = data->tmp_chan;
  1645		} else {
  1646			chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf);
  1647			if (chanctx_conf) {
  1648				channel = chanctx_conf->def.chan;
  1649				confbw = chanctx_conf->def.width;
  1650			} else {
  1651				channel = NULL;
  1652			}
  1653		}
  1654	
  1655		if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
  1656			ieee80211_free_txskb(hw, skb);
  1657			return;
  1658		}
  1659	
  1660		if (data->idle && !data->tmp_chan) {
  1661			wiphy_dbg(hw->wiphy, "Trying to TX when idle - reject\n");
  1662			ieee80211_free_txskb(hw, skb);
  1663			return;
  1664		}
  1665	
  1666		if (txi->control.vif)
  1667			hwsim_check_magic(txi->control.vif);
  1668		if (control->sta)
  1669			hwsim_check_sta_magic(control->sta);
  1670	
  1671		if (ieee80211_hw_check(hw, SUPPORTS_RC_TABLE))
  1672			ieee80211_get_tx_rates(txi->control.vif, control->sta, skb,
  1673					       txi->control.rates,
  1674					       ARRAY_SIZE(txi->control.rates));
  1675	
  1676		for (i = 0; i < ARRAY_SIZE(txi->control.rates); i++) {
  1677			u16 rflags = txi->control.rates[i].flags;
  1678			/* initialize to data->bw for 5/10 MHz handling */
  1679			enum nl80211_chan_width bw = data->bw;
  1680	
  1681			if (txi->control.rates[i].idx == -1)
  1682				break;
  1683	
  1684			if (rflags & IEEE80211_TX_RC_40_MHZ_WIDTH)
  1685				bw = NL80211_CHAN_WIDTH_40;
  1686			else if (rflags & IEEE80211_TX_RC_80_MHZ_WIDTH)
  1687				bw = NL80211_CHAN_WIDTH_80;
  1688			else if (rflags & IEEE80211_TX_RC_160_MHZ_WIDTH)
  1689				bw = NL80211_CHAN_WIDTH_160;
  1690	
  1691			if (WARN_ON(hwsim_get_chanwidth(bw) > hwsim_get_chanwidth(data->bw)))
  1692				return;
  1693		}
  1694	
  1695		if (skb->len >= 24 + 8 &&
  1696		    ieee80211_is_probe_resp(hdr->frame_control)) {
  1697			/* fake header transmission time */
  1698			struct ieee80211_mgmt *mgmt;
  1699			struct ieee80211_rate *txrate;
  1700			/* TODO: get MCS */
  1701			int bitrate = 100;
  1702			u64 ts;
  1703	
  1704			mgmt = (struct ieee80211_mgmt *)skb->data;
  1705			txrate = ieee80211_get_tx_rate(hw, txi);
  1706			if (txrate)
  1707				bitrate = txrate->bitrate;
  1708			ts = mac80211_hwsim_get_tsf_raw();
  1709			mgmt->u.probe_resp.timestamp =
  1710				cpu_to_le64(ts + data->tsf_offset +
  1711					    24 * 8 * 10 / bitrate);
  1712		}
  1713	
  1714		mac80211_hwsim_monitor_rx(hw, skb, channel);
  1715	
  1716		/* wmediumd mode check */
  1717		_portid = READ_ONCE(data->wmediumd);
  1718	
  1719		if (_portid || hwsim_virtio_enabled)
  1720			return mac80211_hwsim_tx_frame_nl(hw, skb, _portid, channel);
  1721	
  1722		/* NO wmediumd detected, perfect medium simulation */
  1723		data->tx_pkts++;
  1724		data->tx_bytes += skb->len;
  1725		ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
  1726	
  1727		if (ack && skb->len >= 16)
  1728			mac80211_hwsim_monitor_ack(channel, hdr->addr2);
  1729	
  1730		ieee80211_tx_info_clear_status(txi);
  1731	
  1732		/* frame was transmitted at most favorable rate at first attempt */
  1733		txi->control.rates[0].count = 1;
  1734		txi->control.rates[1].idx = -1;
  1735	
  1736		if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
  1737			txi->flags |= IEEE80211_TX_STAT_ACK;
  1738		ieee80211_tx_status_irqsafe(hw, skb);
  1739	}
  1740	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff mbox series

Patch

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 8d54f9face2f..1fcc2000950b 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -652,6 +652,7 @@  struct mac80211_hwsim_data {
 		      ARRAY_SIZE(hwsim_channels_6ghz)];
 
 	struct ieee80211_channel *channel;
+	enum nl80211_chan_width bw;
 	u64 beacon_int	/* beacon interval in us */;
 	unsigned int rx_filter;
 	bool started, idle, scanning;
@@ -803,6 +804,38 @@  extern int hwsim_tx_virtio(struct mac80211_hwsim_data *data,
 #define hwsim_virtio_enabled false
 #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,
 				    struct sk_buff *skb,
 				    struct ieee80211_channel *chan);
@@ -1595,7 +1628,8 @@  static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 	struct ieee80211_chanctx_conf *chanctx_conf;
 	struct ieee80211_channel *channel;
 	bool ack;
-	u32 _portid;
+	enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT;
+	u32 _portid, i;
 
 	if (WARN_ON(skb->len < 10)) {
 		/* Should not happen; just a sanity check for addr1 use */
@@ -1605,14 +1639,17 @@  static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 
 	if (!data->use_chanctx) {
 		channel = data->channel;
+		confbw = data->bw;
 	} else if (txi->hw_queue == 4) {
 		channel = data->tmp_chan;
 	} else {
 		chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf);
-		if (chanctx_conf)
+		if (chanctx_conf) {
 			channel = chanctx_conf->def.chan;
-		else
+			confbw = chanctx_conf->def.width;
+		} else {
 			channel = NULL;
+		}
 	}
 
 	if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
@@ -1636,6 +1673,25 @@  static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
 				       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(data->bw)))
+			return;
+	}
+
 	if (skb->len >= 24 + 8 &&
 	    ieee80211_is_probe_resp(hdr->frame_control)) {
 		/* fake header transmission time */
@@ -1935,6 +1991,7 @@  static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 		}
 
 		data->channel = conf->chandef.chan;
+		data->bw = conf->chandef.width;
 
 		for (idx = 0; idx < ARRAY_SIZE(data->survey_data); idx++) {
 			if (data->survey_data[idx].channel &&
@@ -1946,6 +2003,7 @@  static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
 		}
 	} else {
 		data->channel = conf->chandef.chan;
+		data->bw = conf->chandef.width;
 	}
 	mutex_unlock(&data->mutex);
 
@@ -2077,12 +2135,37 @@  static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
 		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;
+
+	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
+	}
+
+	WARN(bw > hwsim_get_chanwidth(data->bw),
+	     "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,
 				  struct ieee80211_vif *vif,
 				  struct ieee80211_sta *sta)
 {
 	hwsim_check_magic(vif);
 	hwsim_set_sta_magic(sta);
+	mac80211_hwsim_sta_rc_update(hw, vif, sta, 0);
 
 	return 0;
 }
@@ -2649,6 +2732,7 @@  static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw)
 	.sta_add = mac80211_hwsim_sta_add,			\
 	.sta_remove = mac80211_hwsim_sta_remove,		\
 	.sta_notify = mac80211_hwsim_sta_notify,		\
+	.sta_rc_update = mac80211_hwsim_sta_rc_update,		\
 	.set_tim = mac80211_hwsim_set_tim,			\
 	.conf_tx = mac80211_hwsim_conf_tx,			\
 	.get_survey = mac80211_hwsim_get_survey,		\