Commit 9d40f7e3 authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg
Browse files

wifi: mac80211: add flag to opt out of virtual monitor support



This is useful for multi-radio devices that are capable of monitoring on
multiple channels simultanenously. When this flag is set, each monitor
interface is passed to the driver individually and can have a configured
channel.
The vif mac address for non-active monitor interfaces is cleared, in order
to allow the driver to tell them apart from active ones.

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
Link: https://patch.msgid.link/3c55505ee0cf0a5f141fbcb30d1e8be8d9f40373.1728462320.git-series.nbd@nbd.name


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 9c4f8309
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2694,6 +2694,11 @@ struct ieee80211_txq {
 *	a virtual monitor interface when monitor interfaces are the only
 *	active interfaces.
 *
 * @IEEE80211_HW_NO_VIRTUAL_MONITOR: The driver would like to be informed
 *	of any monitor interface, as well as their configured channel.
 *	This is useful for supporting multiple monitor interfaces on different
 *	channels.
 *
 * @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to
 *	be created.  It is expected user-space will create vifs as
 *	desired (and thus have them named as desired).
@@ -2853,6 +2858,7 @@ enum ieee80211_hw_flags {
	IEEE80211_HW_SUPPORTS_DYNAMIC_PS,
	IEEE80211_HW_MFP_CAPABLE,
	IEEE80211_HW_WANT_MONITOR_VIF,
	IEEE80211_HW_NO_VIRTUAL_MONITOR,
	IEEE80211_HW_NO_AUTO_VIF,
	IEEE80211_HW_SW_CRYPTO_CONTROL,
	IEEE80211_HW_SUPPORT_FAST_XMIT,
+28 −16
Original line number Diff line number Diff line
@@ -105,6 +105,9 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
	}

	/* also validate MU-MIMO change */
	if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
		monitor_sdata = sdata;
	else
		monitor_sdata = wiphy_dereference(local->hw.wiphy,
						  local->monitor_sdata);

@@ -114,7 +117,9 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,

	/* apply all changes now - no failures allowed */

	if (monitor_sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
	if (monitor_sdata &&
		(ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
		 ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)))
		ieee80211_set_mu_mimo_follow(monitor_sdata, params);

	if (params->flags) {
@@ -907,22 +912,25 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,

	lockdep_assert_wiphy(local->hw.wiphy);

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
		if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
						   &chanreq.oper))
			return 0;

	sdata = wiphy_dereference(local->hw.wiphy,
				  local->monitor_sdata);
		sdata = wiphy_dereference(wiphy, local->monitor_sdata);
		if (!sdata)
			goto done;
	}

	if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
	if (rcu_access_pointer(sdata->deflink.conf->chanctx_conf) &&
		cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
				       &chanreq.oper))
		return 0;

	ieee80211_link_release_channel(&sdata->deflink);
	ret = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
					 IEEE80211_CHANCTX_EXCLUSIVE);
					 IEEE80211_CHANCTX_SHARED);
	if (ret)
		return ret;
done:
@@ -3084,7 +3092,8 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
	if (wdev) {
		sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);

		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
		if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
		    !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
			if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
				return -EOPNOTSUPP;

@@ -3118,7 +3127,8 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
	local->user_power_level = user_power_level;

	list_for_each_entry(sdata, &local->interfaces, list) {
		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
		if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
		    !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
			has_monitor = true;
			continue;
		}
@@ -3139,7 +3149,8 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy,
		}
	}
	list_for_each_entry(sdata, &local->interfaces, list) {
		if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
		if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
		    !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
			continue;

		for (int link_id = 0;
@@ -4342,7 +4353,8 @@ static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
	if (chanctx_conf) {
		*chandef = link->conf->chanreq.oper;
		ret = 0;
	} else if (local->open_count > 0 &&
	} else if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
		   local->open_count > 0 &&
		   local->open_count == local->monitors &&
		   sdata->vif.type == NL80211_IFTYPE_MONITOR) {
		*chandef = local->monitor_chanreq.oper;
+13 −1
Original line number Diff line number Diff line
@@ -347,6 +347,10 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
		case NL80211_IFTYPE_P2P_DEVICE:
		case NL80211_IFTYPE_NAN:
			continue;
		case NL80211_IFTYPE_MONITOR:
			WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
							 NO_VIRTUAL_MONITOR));
			fallthrough;
		case NL80211_IFTYPE_ADHOC:
		case NL80211_IFTYPE_MESH_POINT:
		case NL80211_IFTYPE_OCB:
@@ -355,7 +359,6 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,
		case NL80211_IFTYPE_WDS:
		case NL80211_IFTYPE_UNSPECIFIED:
		case NUM_NL80211_IFTYPES:
		case NL80211_IFTYPE_MONITOR:
		case NL80211_IFTYPE_P2P_CLIENT:
		case NL80211_IFTYPE_P2P_GO:
			WARN_ON_ONCE(1);
@@ -964,6 +967,10 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
			if (!link->sdata->u.mgd.associated)
				continue;
			break;
		case NL80211_IFTYPE_MONITOR:
			if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
				continue;
			break;
		case NL80211_IFTYPE_AP:
		case NL80211_IFTYPE_ADHOC:
		case NL80211_IFTYPE_MESH_POINT:
@@ -976,6 +983,11 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
		if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
			continue;

		if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
			rx_chains_dynamic = rx_chains_static = local->rx_chains;
			break;
		}

		switch (link->smps_mode) {
		default:
			WARN_ONCE(1, "Invalid SMPS mode %d\n",
+1 −0
Original line number Diff line number Diff line
@@ -456,6 +456,7 @@ static const char *hw_flag_names[] = {
	FLAG(SUPPORTS_DYNAMIC_PS),
	FLAG(MFP_CAPABLE),
	FLAG(WANT_MONITOR_VIF),
	FLAG(NO_VIRTUAL_MONITOR),
	FLAG(NO_AUTO_VIF),
	FLAG(SW_CRYPTO_CONTROL),
	FLAG(SUPPORT_FAST_XMIT),
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ int drv_add_interface(struct ieee80211_local *local,
	if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
		    (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
		     !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
		     !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
		     !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
		return -EINVAL;

Loading