Search Linux Wireless

[RFC 3/6] wifi: mac80211: notify driver about per-radio monitor enabled state

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This allows monitoring on one or more radios while minimizing performance
impact on the others.

Signed-off-by: Felix Fietkau <nbd@xxxxxxxx>
---
 include/net/mac80211.h     |  3 +++
 net/mac80211/ieee80211_i.h |  6 ++++++
 net/mac80211/iface.c       | 26 +++++++++++++++++++++++++-
 net/mac80211/main.c        | 12 ++++++++++++
 4 files changed, 46 insertions(+), 1 deletion(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9618c82262e3..7bee2d912efe 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1748,6 +1748,8 @@ enum ieee80211_smps_mode {
  *
  * @flags: configuration flags defined above
  *
+ * @monitor_radios: bitmask of radios with monitor mode enabled.
+ *
  * @listen_interval: listen interval in units of beacon interval
  * @ps_dtim_period: The DTIM period of the AP we're connected to, for use
  *	in power saving. Power saving will not be enabled until a beacon
@@ -1777,6 +1779,7 @@ enum ieee80211_smps_mode {
  */
 struct ieee80211_conf {
 	u32 flags;
+	u32 monitor_radios;
 	int power_level, dynamic_ps_timeout;
 
 	u16 listen_interval;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 304cce0b771d..3be9f8149117 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1330,6 +1330,10 @@ enum mac80211_scan_state {
 
 DECLARE_STATIC_KEY_FALSE(aql_disable);
 
+struct ieee80211_radio_data {
+	u32 monitors;
+};
+
 struct ieee80211_local {
 	/* embed the driver visible part.
 	 * don't cast (use the static inlines below), but we keep
@@ -1613,6 +1617,8 @@ struct ieee80211_local {
 	u8 ext_capa[8];
 
 	bool wbrf_supported;
+
+	struct ieee80211_radio_data *radio_data;
 };
 
 static inline struct ieee80211_sub_if_data *
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 56fed4f69427..4db867ae97f0 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -601,6 +601,18 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
 			hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
 		}
 
+		for (i = 0; i < local->hw.wiphy->n_radio; i++) {
+			if (!(sdata->wdev.radio_mask & BIT(i)))
+				continue;
+
+			local->radio_data[i].monitors--;
+			if (local->radio_data[i].monitors)
+				continue;
+
+			local->hw.conf.monitor_radios &= ~BIT(i);
+			hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
+		}
+
 		ieee80211_adjust_monitor_flags(sdata, -1);
 		break;
 	case NL80211_IFTYPE_NAN:
@@ -1214,7 +1226,7 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 	struct net_device *dev = wdev->netdev;
 	struct ieee80211_local *local = sdata->local;
 	u64 changed = 0;
-	int res;
+	int i, res;
 	u32 hw_reconf_flags = 0;
 
 	lockdep_assert_wiphy(local->hw.wiphy);
@@ -1330,6 +1342,18 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
 			hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
 		}
 
+		for (i = 0; i < local->hw.wiphy->n_radio; i++) {
+			if (!(sdata->wdev.radio_mask & BIT(i)))
+				continue;
+
+			local->radio_data[i].monitors++;
+			if (local->radio_data[i].monitors > 1)
+				continue;
+
+			local->hw.conf.monitor_radios |= BIT(i);
+			hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
+		}
+
 		ieee80211_adjust_monitor_flags(sdata, 1);
 		ieee80211_configure_filter(local);
 		ieee80211_recalc_offload(local);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6abf85a58133..2ce771744ea8 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1348,6 +1348,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 	if (!local->int_scan_req)
 		return -ENOMEM;
 
+	if (hw->wiphy->n_radio) {
+		local->radio_data = kcalloc(hw->wiphy->n_radio,
+					    sizeof(*local->radio_data),
+					    GFP_KERNEL);
+		if (!local->radio_data) {
+			result = -ENOMEM;
+			goto fail_workqueue;
+		}
+	}
+
 	eth_broadcast_addr(local->int_scan_req->bssid);
 
 	for (band = 0; band < NUM_NL80211_BANDS; band++) {
@@ -1642,6 +1652,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 		local->wiphy_ciphers_allocated = false;
 	}
 	kfree(local->int_scan_req);
+	kfree(local->radio_data);
 	return result;
 }
 EXPORT_SYMBOL(ieee80211_register_hw);
@@ -1694,6 +1705,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 	destroy_workqueue(local->workqueue);
 	ieee80211_led_exit(local);
 	kfree(local->int_scan_req);
+	kfree(local->radio_data);
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
-- 
git-series 0.9.1




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux