All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold
@ 2018-04-27  5:30 Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 1/6] cfg80211: Add support to configure station specific rssi threshold for AP mode Tamizh chelvam
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Tamizh chelvam @ 2018-04-27  5:30 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Tamizh chelvam

This patchsets introduced new NL command and api to support
configuring rssi and txrate for the connected stations.
And implemented new api to notify the threshold cross event.
This will be useful/requires for the user application like steering
to monitor station's activity change.

Tamizh chelvam (6):
  cfg80211: Add support to configure station specific rssi threshold for
    AP mode
  mac80211: Add support to configure rssi threshold for AP mode
  mac80211: Implement functionality to monitor station's rssi threshold
    cross
  cfg80211: Add support to configure station specific txrate threshold
    for AP mode
  mac80211: Add support to configure txrate threshold for station
  mac80211: Implement functionality to monitor txrate cross event for
    station

v2:
  * fixed kbuild warnings
  * updated commit log

 include/net/cfg80211.h       |  69 ++++++-
 include/net/mac80211.h       |  12 ++
 include/uapi/linux/nl80211.h |  96 +++++++++
 net/mac80211/cfg.c           | 111 +++++++++++
 net/mac80211/rx.c            |  65 +++++-
 net/mac80211/sta_info.h      |  37 ++++
 net/mac80211/status.c        |  40 +++-
 net/wireless/core.c          |  26 ++-
 net/wireless/core.h          |   6 +-
 net/wireless/nl80211.c       | 462 ++++++++++++++++++++++++++++++++++++++-----
 net/wireless/rdev-ops.h      |  48 +++++
 net/wireless/trace.h         | 123 ++++++++++++
 12 files changed, 1030 insertions(+), 65 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [RFCv2 1/6] cfg80211: Add support to configure station specific rssi threshold for AP mode
  2018-04-27  5:30 [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold Tamizh chelvam
@ 2018-04-27  5:30 ` Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 2/6] mac80211: Add support to configure " Tamizh chelvam
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Tamizh chelvam @ 2018-04-27  5:30 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Tamizh chelvam

This patch add support to configure station specific rssi threshold
to monitor station's signal strength modification. This will be useful
for the user application like steering to configure and monitor the station's
signal strength change event.

New NL80211_CMD_STA_MON command introduced to cofigure single or multi
rssi thresholds using NL80211_ATTR_STA_MON_RSSI_THOLD and
NL80211_ATTR_STA_MON_RSSI_HYST.

cfg80211_sta_mon_rssi_notify introduce to notify station's signal strength
goes out of range using NL80211_CMD_NOTIFY_STA_MON command.

NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG flag needs to be advertised by the
drvier to allow single rssi threshold and hysteresis configuration.
NL80211_EXT_FEATURE_STA_MON_RSSI_LIST needs to be advertised to allow
multi rssi thresholds.

Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
 include/net/cfg80211.h       |  43 ++++-
 include/uapi/linux/nl80211.h |  62 +++++++
 net/wireless/core.c          |  26 ++-
 net/wireless/core.h          |   6 +-
 net/wireless/nl80211.c       | 388 +++++++++++++++++++++++++++++++++++++------
 net/wireless/rdev-ops.h      |  31 ++++
 net/wireless/trace.h         |  74 +++++++++
 7 files changed, 567 insertions(+), 63 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 250dac3..7e7a0bf 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2973,6 +2973,17 @@ struct cfg80211_external_auth_params {
  *
  * @tx_control_port: TX a control port frame (EAPoL).  The noencrypt parameter
  *	tells the driver that the frame should not be encrypted.
+ * @set_sta_mon_rssi_config: Configure  RSSI threshold for a station.
+ *	After configuration, the driver should (soon) send an event indicating
+ *	the current level of a station is above/below the configured threshold;
+ *	this may need some care when the configuration is changed
+ *	(without first being disabled.)
+ * @set_sta_mon_rssi_range_config: Configure two RSSI thresholds in the
+ *	station's rssi monitor.  An event is to be sent only when the
+ *	signal level of a station is found to be outside the two values.
+ *	The driver should set %NL80211_EXT_FEATURE_STA_MON_RSSI_LIST if this
+ *	method is implemented. If it is provided then there's no point providing
+ *	@set_sta_mon_rssi_config.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3274,6 +3285,14 @@ struct cfg80211_ops {
 				   const u8 *buf, size_t len,
 				   const u8 *dest, const __be16 proto,
 				   const bool noencrypt);
+	int     (*set_sta_mon_rssi_config)(struct wiphy *wiphy,
+					    struct net_device *dev,
+					    const u8 *addr,
+					    s32 rssi_thold, u32 rssi_hyst);
+	int     (*set_sta_mon_rssi_range_config)(struct wiphy *wiphy,
+						 struct net_device *dev,
+						 const u8 *addr,
+						 s32 rssi_low, s32 rssi_high);
 };
 
 /*
@@ -4076,7 +4095,7 @@ static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
 struct cfg80211_cached_keys;
-struct cfg80211_cqm_config;
+struct cfg80211_rssi_config;
 
 /**
  * struct wireless_dev - wireless device state
@@ -4141,7 +4160,8 @@ static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops,
  * @event_lock: (private) lock for event list
  * @owner_nlportid: (private) owner socket port ID
  * @nl_owner_dead: (private) owner socket went away
- * @cqm_config: (private) nl80211 RSSI monitor state
+ * @rssi_config: (private) nl80211 RSSI monitor state
+ * @rssi_config_list: list of peer address based rssi configuration
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
@@ -4212,7 +4232,8 @@ struct wireless_dev {
 	} wext;
 #endif
 
-	struct cfg80211_cqm_config *cqm_config;
+	struct cfg80211_rssi_config *rssi_config;
+	struct list_head rssi_config_list;
 };
 
 static inline u8 *wdev_address(struct wireless_dev *wdev)
@@ -5776,6 +5797,22 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      s32 rssi_level, gfp_t gfp);
 
 /**
+ * cfg80211_sta_mon_rssi_notify - Station's rssi out of range event
+ * @dev: network device
+ * @peer: Station's mac address
+ * @rssi_event: the triggered RSSI event
+ * @rssi_level: new RSSI level value or 0 if not available
+ * @gfp: context flags
+ *
+ * This function is called when a configured rssi threshold reached event
+ * occurs for a station.
+ */
+void
+cfg80211_sta_mon_rssi_notify(struct net_device *dev, const u8 *peer,
+		     enum nl80211_sta_mon_rssi_threshold_event rssi_event,
+		     s32 rssi_level, gfp_t gfp);
+
+/**
  * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
  * @dev: network device
  * @peer: peer's MAC address
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9c36301..fa1fed1 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1029,6 +1029,11 @@
  *	ht opmode or vht opmode changes using any of &NL80211_ATTR_SMPS_MODE,
  *	&NL80211_ATTR_CHANNEL_WIDTH,&NL80211_ATTR_NSS attributes with its
  *	address(specified in &NL80211_ATTR_MAC).
+ * @NL80211_CMD_SET_STA_MON: This command is used to configure station's
+ *	connection monitoring notification trigger levels.
+ * @NL80211_CMD_NOTIFY_STA_MON: Station's connection monitor notification. This
+ *	command is used as an event to indicate the that a trigger level was
+ *	reached for a station.
  *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
@@ -1242,6 +1247,9 @@ enum nl80211_commands {
 
 	NL80211_CMD_CONTROL_PORT_FRAME,
 
+	NL80211_CMD_STA_MON,
+	NL80211_CMD_NOTIFY_STA_MON,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -2225,6 +2233,10 @@ enum nl80211_commands {
  * @NL80211_ATTR_NSS: Station's New/updated  RX_NSS value notified using this
  *	u8 attribute. This is used with %NL80211_CMD_STA_OPMODE_CHANGED.
  *
+ * @NL80211_ATTR_STA_MON: Station's connection monitor configuration in a
+ *	nested attribute with %NL80211_ATTR_STA_MON_* sub-attributes.
+ *
+ * @NL80211_ATTR_LOCAL_STATE_CHANGE: Flag attribute to indicate that a command
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2659,6 +2671,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_CONTROL_PORT_OVER_NL80211,
 
+	NL80211_ATTR_STA_MON,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -4238,6 +4252,34 @@ enum nl80211_attr_cqm {
 };
 
 /**
+ * enum nl80211_attr_sta_mon - Attributes to monitor station's connection
+ * @NL80211_ATTR_STA_MON_RSSI_THOLD: RSSI threshold in dBm. This value specifies
+ *	the threshold for the RSSI level at which an event will be sent. Zero
+ *	to disable.  Alternatively, if %NL80211_EXT_FEATURE_STA_MON_RSSI_LIST is
+ *	set, multiple values can be supplied as a low-to-high sorted array of
+ *	threshold values in dBm.  Events will be sent when the RSSI value
+ *	crosses any of the thresholds. This threshold values are station
+ *	spcific.
+ * @NL80211_ATTR_STA_MON_RSSI_HYST: RSSI hysteresis in dBm. This value specifies
+ *	the minimum amount the RSSI level must change after an event before a
+ *	new event may be issued (to reduce effects of RSSI oscillation).
+ * @NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT: RSSI threshold event
+ * @NL80211_ATTR_STA_MON_RSSI_LEVEL: the RSSI value in dBm that triggered the
+ *	RSSI threshold event.
+ */
+enum nl80211_attr_sta_mon {
+	__NL80211_ATTR_STA_MON_INVALID,
+	NL80211_ATTR_STA_MON_RSSI_THOLD,
+	NL80211_ATTR_STA_MON_RSSI_HYST,
+	NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT,
+	NL80211_ATTR_STA_MON_RSSI_LEVEL,
+
+	/* keep last */
+	__NL80211_ATTR_STA_MON_AFTER_LAST,
+	NL80211_ATTR_STA_MON_MAX = __NL80211_ATTR_STA_MON_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_cqm_rssi_threshold_event - RSSI threshold event
  * @NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
  *      configured threshold
@@ -4251,6 +4293,18 @@ enum nl80211_cqm_rssi_threshold_event {
 	NL80211_CQM_RSSI_BEACON_LOSS_EVENT,
 };
 
+/**
+ * enum nl80211_sta_mon_rssi_threshold_event - RSSI threshold event
+ * @NL80211_STA_MON_RSSI_THRESHOLD_EVENT_LOW: The RSSI level is lower than the
+ *      configured threshold
+ * @NL80211_STA_MON_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
+ *      configured threshold
+ */
+enum nl80211_sta_mon_rssi_threshold_event {
+	NL80211_STA_MON_RSSI_THRESHOLD_EVENT_LOW,
+	NL80211_STA_MON_RSSI_THRESHOLD_EVENT_HIGH,
+};
+
 
 /**
  * enum nl80211_tx_power_setting - TX power adjustment
@@ -5040,6 +5094,12 @@ enum nl80211_feature_flags {
  *	"radar detected" event.
  * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211: Driver supports sending and
  *	receiving control port frames over nl80211 instead of the netdevice.
+ * @NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG: With this driver can set
+ *	rssi threshold using %NL80211_ATTR_STA_MON_RSSI_THOLD attribute
+ *	for a connected station.
+ * @NL80211_EXT_FEATURE_STA_MON_RSSI_LIST: With this driver the
+ *	%NL80211_ATTR_STA_MON_RSSI_THOLD attribute accepts a list of zero or
+ *	more RSSI threshold values to monitor rather than exactly one threshold.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5072,6 +5132,8 @@ enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN,
 	NL80211_EXT_FEATURE_DFS_OFFLOAD,
 	NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
+	NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG,
+	NL80211_EXT_FEATURE_STA_MON_RSSI_LIST,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c0fd8a8..7933337 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -990,10 +990,25 @@ void wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool blocked)
 }
 EXPORT_SYMBOL(wiphy_rfkill_set_hw_state);
 
-void cfg80211_cqm_config_free(struct wireless_dev *wdev)
+void cfg80211_rssi_config_free(struct wireless_dev *wdev)
 {
-	kfree(wdev->cqm_config);
-	wdev->cqm_config = NULL;
+	struct cfg80211_rssi_config *rssi_config, *tmp;
+
+	if (list_empty(&wdev->rssi_config_list))
+		goto free;
+
+	list_for_each_entry_safe(rssi_config, tmp, &wdev->rssi_config_list,
+				 list) {
+		list_del(&rssi_config->list);
+		kfree(rssi_config);
+		if (list_empty(&wdev->rssi_config_list))
+			goto out;
+	}
+
+free:
+	kfree(wdev->rssi_config);
+out:
+	wdev->rssi_config = NULL;
 }
 
 void cfg80211_unregister_wdev(struct wireless_dev *wdev)
@@ -1023,7 +1038,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 		break;
 	}
 
-	cfg80211_cqm_config_free(wdev);
+	cfg80211_rssi_config_free(wdev);
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
 
@@ -1159,6 +1174,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		spin_lock_init(&wdev->event_lock);
 		INIT_LIST_HEAD(&wdev->mgmt_registrations);
 		spin_lock_init(&wdev->mgmt_registrations_lock);
+		INIT_LIST_HEAD(&wdev->rssi_config_list);
 
 		/*
 		 * We get here also when the interface changes network namespaces,
@@ -1288,7 +1304,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 			kzfree(wdev->wext.keys);
 #endif
 			flush_work(&wdev->disconnect_wk);
-			cfg80211_cqm_config_free(wdev);
+			cfg80211_rssi_config_free(wdev);
 		}
 		/*
 		 * synchronise (so that we won't find this netdev
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 63eb1b5..17883ec 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -260,10 +260,12 @@ struct cfg80211_beacon_registration {
 	u32 nlportid;
 };
 
-struct cfg80211_cqm_config {
+struct cfg80211_rssi_config {
+	struct list_head list;
 	u32 rssi_hyst;
 	s32 last_rssi_event_value;
 	int n_rssi_thresholds;
+	u8 addr[ETH_ALEN];
 	s32 rssi_thresholds[0];
 };
 
@@ -514,6 +516,6 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev,
 #define CFG80211_DEV_WARN_ON(cond)	({bool __r = (cond); __r; })
 #endif
 
-void cfg80211_cqm_config_free(struct wireless_dev *wdev);
+void cfg80211_rssi_config_free(struct wireless_dev *wdev);
 
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a052693..382dc63 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -423,6 +423,7 @@ enum nl80211_multicast_groups {
 	[NL80211_ATTR_PMK] = { .type = NLA_BINARY, .len = PMK_MAX_LEN },
 	[NL80211_ATTR_SCHED_SCAN_MULTI] = { .type = NLA_FLAG },
 	[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT] = { .type = NLA_FLAG },
+	[NL80211_ATTR_STA_MON] = { .type = NLA_NESTED },
 };
 
 /* policy for the key attributes */
@@ -3043,6 +3044,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
 		spin_lock_init(&wdev->event_lock);
 		INIT_LIST_HEAD(&wdev->mgmt_registrations);
 		spin_lock_init(&wdev->mgmt_registrations_lock);
+		INIT_LIST_HEAD(&wdev->rssi_config_list);
 
 		wdev->identifier = ++rdev->wdev_id;
 		list_add_rcu(&wdev->list, &rdev->wiphy.wdev_list);
@@ -9864,6 +9866,14 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
 	[NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
 };
 
+static const struct nla_policy
+nl80211_attr_sta_mon_policy[NL80211_ATTR_STA_MON_MAX + 1] = {
+	[NL80211_ATTR_STA_MON_RSSI_THOLD] = { .type = NLA_BINARY },
+	[NL80211_ATTR_STA_MON_RSSI_HYST] = { .type = NLA_U32 },
+	[NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+	[NL80211_ATTR_STA_MON_RSSI_LEVEL] = { .type = NLA_S32 },
+};
+
 static int nl80211_set_cqm_txe(struct genl_info *info,
 			       u32 rate, u32 pkts, u32 intvl)
 {
@@ -9884,17 +9894,65 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
 	return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
 }
 
+static int cfg80211_set_rssi_range(struct cfg80211_registered_device *rdev,
+				   struct net_device *dev, const u8 *mac_addr,
+				   bool get_last_rssi)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	s32 low, high, last;
+	u32 hyst;
+	int i, n, err;
+
+	if (get_last_rssi && mac_addr) {
+		struct station_info sinfo = {};
+
+		err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
+		if (err)
+			return err;
+
+		if (wdev->iftype != NL80211_IFTYPE_STATION &&
+		    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) {
+			if (sinfo.filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))
+				wdev->rssi_config->last_rssi_event_value =
+					(s8)sinfo.signal_avg;
+		} else {
+			if (sinfo.filled &
+			    BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
+				wdev->rssi_config->last_rssi_event_value =
+						(s8)sinfo.rx_beacon_signal_avg;
+		}
+	}
+
+	last = wdev->rssi_config->last_rssi_event_value;
+	hyst = wdev->rssi_config->rssi_hyst;
+	n = wdev->rssi_config->n_rssi_thresholds;
+
+	for (i = 0; i < n; i++) {
+		if (last < wdev->rssi_config->rssi_thresholds[i])
+			break;
+	}
+
+	low = i > 0 ?
+		(wdev->rssi_config->rssi_thresholds[i - 1] - hyst) : S32_MIN;
+	high = i < n ?
+		(wdev->rssi_config->rssi_thresholds[i] + hyst - 1) : S32_MAX;
+
+	if (wdev->iftype == NL80211_IFTYPE_STATION ||
+	    wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)
+		return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
+
+	return rdev_set_sta_mon_rssi_range_config(rdev, dev, mac_addr,
+						  low, high);
+}
+
 static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
 				    struct net_device *dev)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	s32 last, low, high;
-	u32 hyst;
-	int i, n;
-	int err;
+	u8 *mac_addr = NULL;
 
 	/* RSSI reporting disabled? */
-	if (!wdev->cqm_config)
+	if (!wdev->rssi_config)
 		return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
 
 	/*
@@ -9903,36 +9961,62 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
 	 * connection is established and enough beacons received to calculate
 	 * the average.
 	 */
-	if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss &&
-	    rdev->ops->get_station) {
-		struct station_info sinfo = {};
-		u8 *mac_addr;
-
+	if (!wdev->rssi_config->last_rssi_event_value && wdev->current_bss &&
+	    rdev->ops->get_station)
 		mac_addr = wdev->current_bss->pub.bssid;
 
-		err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
-		if (err)
-			return err;
+	return cfg80211_set_rssi_range(rdev, dev, mac_addr,
+				!wdev->rssi_config->last_rssi_event_value);
+}
 
-		if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
-			wdev->cqm_config->last_rssi_event_value =
-				(s8) sinfo.rx_beacon_signal_avg;
+static int nl80211_validate_rssi_tholds(const s32 *thresholds, int n_thresholds)
+{
+	int i;
+	s32 prev = S32_MIN;
+
+	/* Check all values negative and sorted */
+	for (i = 0; i < n_thresholds; i++) {
+		if (thresholds[i] > 0 || thresholds[i] <= prev)
+			return -EINVAL;
+
+		prev = thresholds[i];
 	}
 
-	last = wdev->cqm_config->last_rssi_event_value;
-	hyst = wdev->cqm_config->rssi_hyst;
-	n = wdev->cqm_config->n_rssi_thresholds;
+	return 0;
+}
 
-	for (i = 0; i < n; i++)
-		if (last < wdev->cqm_config->rssi_thresholds[i])
+static struct cfg80211_rssi_config *
+cfg80211_get_rssi_config(struct wireless_dev *wdev, const s32 *thresholds,
+			 int n_thresholds, u32 hysteresis, const u8 *peer)
+{
+	struct cfg80211_rssi_config *rssi_config;
+
+	if (!peer)
+		return NULL;
+
+	if (list_empty(&wdev->rssi_config_list))
+		goto new;
+
+	list_for_each_entry(rssi_config, &wdev->rssi_config_list, list) {
+		if (!memcmp(rssi_config->addr, peer, ETH_ALEN)) {
+			list_del(&rssi_config->list);
+			kfree(rssi_config);
 			break;
+		}
+	}
 
-	low = i > 0 ?
-		(wdev->cqm_config->rssi_thresholds[i - 1] - hyst) : S32_MIN;
-	high = i < n ?
-		(wdev->cqm_config->rssi_thresholds[i] + hyst - 1) : S32_MAX;
+new:
+	rssi_config = kzalloc(sizeof(struct cfg80211_rssi_config) +
+			      n_thresholds * sizeof(s32), GFP_KERNEL);
+	if (!rssi_config)
+		return NULL;
 
-	return rdev_set_cqm_rssi_range_config(rdev, dev, low, high);
+	rssi_config->rssi_hyst = hysteresis;
+	rssi_config->n_rssi_thresholds = n_thresholds;
+	memcpy(rssi_config->addr, peer, ETH_ALEN);
+	memcpy(rssi_config->rssi_thresholds, thresholds,
+	       n_thresholds * sizeof(s32));
+	return rssi_config;
 }
 
 static int nl80211_set_cqm_rssi(struct genl_info *info,
@@ -9942,23 +10026,19 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct net_device *dev = info->user_ptr[1];
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
-	int i, err;
-	s32 prev = S32_MIN;
+	int err;
 
-	/* Check all values negative and sorted */
-	for (i = 0; i < n_thresholds; i++) {
-		if (thresholds[i] > 0 || thresholds[i] <= prev)
-			return -EINVAL;
+	err = nl80211_validate_rssi_tholds(thresholds, n_thresholds);
 
-		prev = thresholds[i];
-	}
+	if (err)
+		return err;
 
 	if (wdev->iftype != NL80211_IFTYPE_STATION &&
 	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
 		return -EOPNOTSUPP;
 
 	wdev_lock(wdev);
-	cfg80211_cqm_config_free(wdev);
+	cfg80211_rssi_config_free(wdev);
 	wdev_unlock(wdev);
 
 	if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
@@ -9977,26 +10057,22 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
 		n_thresholds = 0;
 
 	wdev_lock(wdev);
-	if (n_thresholds) {
-		struct cfg80211_cqm_config *cqm_config;
+	if (n_thresholds)
+		wdev->rssi_config = cfg80211_get_rssi_config(
+						wdev, thresholds,
+						n_thresholds, hysteresis,
+						wdev->current_bss->pub.bssid);
 
-		cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
-				     n_thresholds * sizeof(s32), GFP_KERNEL);
-		if (!cqm_config) {
-			err = -ENOMEM;
-			goto unlock;
-		}
-
-		cqm_config->rssi_hyst = hysteresis;
-		cqm_config->n_rssi_thresholds = n_thresholds;
-		memcpy(cqm_config->rssi_thresholds, thresholds,
-		       n_thresholds * sizeof(s32));
-
-		wdev->cqm_config = cqm_config;
+	if (!wdev->rssi_config) {
+		err = -ENOMEM;
+		goto unlock;
 	}
 
 	err = cfg80211_cqm_rssi_update(rdev, dev);
 
+	if (!err)
+		list_add(&wdev->rssi_config->list, &wdev->rssi_config_list);
+
 unlock:
 	wdev_unlock(wdev);
 
@@ -12642,6 +12718,103 @@ static int nl80211_tx_control_port(struct sk_buff *skb, struct genl_info *info)
 	return err;
 }
 
+static int nl80211_set_sta_mon_rssi(struct genl_info *info,
+				    const u8 *peer, const s32 *thresholds,
+				    int n_thresholds, u32 hysteresis)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	if ((wdev->iftype != NL80211_IFTYPE_AP &&
+	     wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+	     wdev->iftype != NL80211_IFTYPE_AP_VLAN) ||
+	    !wiphy_ext_feature_isset(&rdev->wiphy,
+				     NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG))
+		return -EOPNOTSUPP;
+
+	err = nl80211_validate_rssi_tholds(thresholds, n_thresholds);
+
+	if (err)
+		return err;
+
+	if (n_thresholds <= 1 && rdev->ops->set_sta_mon_rssi_config) {
+		if (n_thresholds == 0 || thresholds[0] == 0)
+			return rdev_set_sta_mon_rssi_config(rdev, dev,
+					peer, 0, 0);
+		return rdev_set_sta_mon_rssi_config(rdev, dev, peer,
+				thresholds[0], hysteresis);
+	}
+
+	if (!rdev->ops->set_sta_mon_rssi_range_config ||
+	    !wiphy_ext_feature_isset(&rdev->wiphy,
+				     NL80211_EXT_FEATURE_STA_MON_RSSI_LIST))
+		return -EOPNOTSUPP;
+
+	/* Disabling */
+	if (!n_thresholds || (n_thresholds == 1 && thresholds[0] == 0))
+		return rdev_set_sta_mon_rssi_range_config(rdev, dev,
+							  peer, 0, 0);
+
+	wdev_lock(wdev);
+	wdev->rssi_config = cfg80211_get_rssi_config(wdev, thresholds,
+						     n_thresholds, hysteresis,
+						     peer);
+
+	if (!wdev->rssi_config) {
+		err = -ENOMEM;
+		goto unlock;
+	}
+
+	err = cfg80211_set_rssi_range(rdev, dev, peer,
+				!wdev->rssi_config->last_rssi_event_value);
+
+	if (!err)
+		list_add(&wdev->rssi_config->list, &wdev->rssi_config_list);
+unlock:
+	wdev_unlock(wdev);
+	return err;
+}
+
+static int nl80211_sta_mon(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nlattr *attrs[NL80211_ATTR_STA_MON_MAX + 1];
+	struct nlattr *sta_mon;
+	u8 *addr = NULL;
+	int err;
+
+	sta_mon = info->attrs[NL80211_ATTR_STA_MON];
+	if (!sta_mon || !(info->attrs[NL80211_ATTR_MAC]))
+		return -EINVAL;
+
+	err = nla_parse_nested(attrs, NL80211_ATTR_STA_MON_MAX,
+			       sta_mon, nl80211_attr_sta_mon_policy,
+			       info->extack);
+
+	if (err)
+		return err;
+
+	addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+	if (attrs[NL80211_ATTR_STA_MON_RSSI_THOLD] &&
+	    attrs[NL80211_ATTR_STA_MON_RSSI_HYST]) {
+		const s32 *tholds =
+			nla_data(attrs[NL80211_ATTR_STA_MON_RSSI_THOLD]);
+		int len = nla_len(attrs[NL80211_ATTR_STA_MON_RSSI_THOLD]);
+		u32 hysteresis =
+			nla_get_u32(attrs[NL80211_ATTR_STA_MON_RSSI_HYST]);
+
+		if (len % 4)
+			return -EINVAL;
+
+		return nl80211_set_sta_mon_rssi(info, addr, tholds, len / 4,
+				hysteresis);
+	}
+
+	return -EINVAL;
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -13553,6 +13726,14 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_STA_MON,
+		.doit = nl80211_sta_mon,
+		.policy = nl80211_policy,
+		.flags = GENL_UNS_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_family nl80211_fam __ro_after_init = {
@@ -14725,6 +14906,107 @@ bool cfg80211_rx_control_port(struct net_device *dev,
 }
 EXPORT_SYMBOL(cfg80211_rx_control_port);
 
+static struct sk_buff *cfg80211_prepare_sta_mon(struct net_device *dev,
+						const char *mac, gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+	struct sk_buff *msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
+	void **cb;
+
+	if (!msg)
+		return NULL;
+
+	cb = (void **)msg->cb;
+
+	cb[0] = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_STA_MON);
+	if (!cb[0]) {
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex))
+		goto nla_put_failure;
+
+	if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac))
+		goto nla_put_failure;
+
+	cb[1] = nla_nest_start(msg, NL80211_ATTR_STA_MON);
+	if (!cb[1])
+		goto nla_put_failure;
+
+	cb[2] = rdev;
+
+	return msg;
+nla_put_failure:
+	nlmsg_free(msg);
+	return NULL;
+}
+
+static void cfg80211_send_sta_mon(struct sk_buff *msg, gfp_t gfp)
+{
+	void **cb = (void **)msg->cb;
+	struct cfg80211_registered_device *rdev = cb[2];
+
+	nla_nest_end(msg, cb[1]);
+	genlmsg_end(msg, cb[0]);
+
+	memset(msg->cb, 0, sizeof(msg->cb));
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+				NL80211_MCGRP_MLME, gfp);
+}
+
+void cfg80211_sta_mon_rssi_notify(struct net_device *dev, const u8 *peer,
+			  enum nl80211_sta_mon_rssi_threshold_event rssi_event,
+			  s32 rssi_level, gfp_t gfp)
+{
+	struct sk_buff *msg;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
+	struct cfg80211_rssi_config *rssi_config;
+
+	if (WARN_ON(!peer))
+		return;
+
+	if (WARN_ON(rssi_event != NL80211_STA_MON_RSSI_THRESHOLD_EVENT_LOW &&
+		    rssi_event != NL80211_STA_MON_RSSI_THRESHOLD_EVENT_HIGH))
+		return;
+
+	trace_cfg80211_sta_mon_rssi_notify(dev, peer, rssi_event, rssi_level);
+
+	list_for_each_entry(rssi_config, &wdev->rssi_config_list, list) {
+		if (!memcmp(rssi_config->addr, peer, ETH_ALEN)) {
+			wdev->rssi_config = rssi_config;
+			wdev->rssi_config->last_rssi_event_value = rssi_level;
+			cfg80211_set_rssi_range(rdev, dev, peer,
+				!wdev->rssi_config->last_rssi_event_value);
+			break;
+		}
+	}
+
+	msg = cfg80211_prepare_sta_mon(dev, peer, gfp);
+	if (!msg)
+		return;
+
+	if (nla_put_u32(msg, NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT,
+			rssi_event))
+		goto nla_put_failure;
+
+	if (rssi_level && nla_put_s32(msg, NL80211_ATTR_STA_MON_RSSI_LEVEL,
+				      rssi_level))
+		goto nla_put_failure;
+
+	cfg80211_send_sta_mon(msg, gfp);
+
+	return;
+
+ nla_put_failure:
+	nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_sta_mon_rssi_notify);
+
 static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
 					    const char *mac, gfp_t gfp)
 {
@@ -14791,13 +15073,13 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 		    rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
 		return;
 
-	if (wdev->cqm_config) {
-		wdev->cqm_config->last_rssi_event_value = rssi_level;
+	if (wdev->rssi_config) {
+		wdev->rssi_config->last_rssi_event_value = rssi_level;
 
 		cfg80211_cqm_rssi_update(rdev, dev);
 
 		if (rssi_level == 0)
-			rssi_level = wdev->cqm_config->last_rssi_event_value;
+			rssi_level = wdev->rssi_config->last_rssi_event_value;
 	}
 
 	msg = cfg80211_prepare_cqm(dev, NULL, gfp);
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 87479a5..47562b9 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1220,4 +1220,35 @@ static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev,
 	return ret;
 }
 
+static inline int
+rdev_set_sta_mon_rssi_config(struct cfg80211_registered_device *rdev,
+			     struct net_device *dev, const u8 *peer,
+			     s32 rssi_tholds, u32 rssi_hyst)
+
+{
+	int ret;
+
+	trace_rdev_set_sta_mon_rssi_config(&rdev->wiphy, dev, peer,
+					   rssi_tholds, rssi_hyst);
+	ret = rdev->ops->set_sta_mon_rssi_config(&rdev->wiphy, dev, peer,
+						 rssi_tholds, rssi_hyst);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
+static inline int
+rdev_set_sta_mon_rssi_range_config(struct cfg80211_registered_device *rdev,
+				   struct net_device *dev, const u8 *peer,
+				   s32 low, s32 high)
+{
+	int ret;
+
+	trace_rdev_set_sta_mon_rssi_range_config(&rdev->wiphy, dev, peer,
+						 low, high);
+	ret = rdev->ops->set_sta_mon_rssi_range_config(&rdev->wiphy, dev, peer,
+						       low, high);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 55fb279..78ff0f2 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1340,6 +1340,56 @@
 		  __entry->rssi_low, __entry->rssi_high)
 );
 
+TRACE_EVENT(rdev_set_sta_mon_rssi_config,
+	TP_PROTO(struct wiphy *wiphy,
+		 struct net_device *netdev, const u8 *peer,
+		 s32 rssi_thold, u32 rssi_hyst),
+	TP_ARGS(wiphy, netdev, peer, rssi_thold, rssi_hyst),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		MAC_ENTRY(peer)
+		__field(s32, rssi_thold)
+		__field(u32, rssi_hyst)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		MAC_ASSIGN(peer, peer);
+		__entry->rssi_thold = rssi_thold;
+		__entry->rssi_hyst = rssi_hyst;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT
+		  ", rssi_thold: %d, rssi_hyst: %u ",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
+		  __entry->rssi_thold, __entry->rssi_hyst)
+);
+
+TRACE_EVENT(rdev_set_sta_mon_rssi_range_config,
+	TP_PROTO(struct wiphy *wiphy,
+		 struct net_device *netdev, const u8 *peer,
+		 s32 low, s32 high),
+	TP_ARGS(wiphy, netdev, peer, low, high),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		MAC_ENTRY(peer)
+		__field(s32, rssi_low)
+		__field(s32, rssi_high)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		MAC_ASSIGN(peer, peer);
+		__entry->rssi_low = low;
+		__entry->rssi_high = high;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT
+		  ", range: %d - %d ",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
+		  __entry->rssi_low, __entry->rssi_high)
+);
+
 TRACE_EVENT(rdev_set_cqm_txe_config,
 	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate,
 		 u32 pkts, u32 intvl),
@@ -3243,6 +3293,30 @@
 		  WIPHY_PR_ARG, NETDEV_PR_ARG,
 		  BOOL_TO_STR(__entry->enabled))
 );
+
+TRACE_EVENT(cfg80211_sta_mon_rssi_notify,
+	TP_PROTO(struct net_device *netdev, const u8 *peer,
+		 enum nl80211_sta_mon_rssi_threshold_event rssi_event,
+		 s32 rssi_level),
+	TP_ARGS(netdev, peer, rssi_event, rssi_level),
+	TP_STRUCT__entry(
+		NETDEV_ENTRY
+		MAC_ENTRY(peer)
+		__field(enum nl80211_sta_mon_rssi_threshold_event, rssi_event)
+		__field(s32, rssi_level)
+	),
+	TP_fast_assign(
+		NETDEV_ASSIGN;
+		MAC_ASSIGN(peer, peer);
+		__entry->rssi_event = rssi_event;
+		__entry->rssi_level = rssi_level;
+	),
+	TP_printk(NETDEV_PR_FMT ", peer: " MAC_PR_FMT
+		  ", rssi event: %d, rssi : %d",
+		  NETDEV_PR_ARG, MAC_PR_ARG(peer),
+		  __entry->rssi_event, __entry->rssi_level)
+);
+
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
 
 #undef TRACE_INCLUDE_PATH
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFCv2 2/6] mac80211: Add support to configure rssi threshold for AP mode
  2018-04-27  5:30 [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 1/6] cfg80211: Add support to configure station specific rssi threshold for AP mode Tamizh chelvam
@ 2018-04-27  5:30 ` Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 3/6] mac80211: Implement functionality to monitor station's rssi threshold cross Tamizh chelvam
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Tamizh chelvam @ 2018-04-27  5:30 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Tamizh chelvam

This patch add support to configure station specific single or
multi rssi thresholds using ieee80211_set_sta_mon_rssi_config and
ieee80211_set_sta_mon_rssi_range_confg APIs. This configuration
is used for tracking the connected station's signal strength.

Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
 net/mac80211/cfg.c      | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/sta_info.h | 18 ++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 85dbaa8..0e2047c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3705,6 +3705,79 @@ static int ieee80211_set_multicast_to_unicast(struct wiphy *wiphy,
 	return 0;
 }
 
+static int ieee80211_set_sta_mon_rssi_config(struct wiphy *wiphy,
+					     struct net_device *dev,
+					     const u8 *peer, s32 rssi_thold,
+					     u32 rssi_hyst)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP &&
+	    (!sdata->vif.bss_conf.enable_beacon ||
+	    !wiphy_ext_feature_isset(sdata->local->hw.wiphy,
+			NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG)))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&sdata->local->sta_mtx);
+
+	sta = sta_info_get_bss(sdata, peer);
+	if (!sta) {
+		mutex_unlock(&sdata->local->sta_mtx);
+		return -ENOENT;
+	}
+
+	if (sta->rssi_thold == rssi_thold &&
+	    sta->rssi_hyst == rssi_hyst)
+		goto unlock;
+
+	sta->rssi_thold = rssi_thold;
+	sta->rssi_hyst = rssi_hyst;
+	sta->rssi_low = 0;
+	sta->rssi_high = 0;
+	sta->last_sta_mon_event_signal = 0;
+unlock:
+	mutex_unlock(&sdata->local->sta_mtx);
+	return 0;
+}
+
+static int ieee80211_set_sta_mon_rssi_range_confg(struct wiphy *wiphy,
+						  struct net_device *dev,
+						  const u8 *peer,
+						  s32 rssi_low, s32 rssi_high)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP &&
+	    (!sdata->vif.bss_conf.enable_beacon ||
+	    !wiphy_ext_feature_isset(sdata->local->hw.wiphy,
+			NL80211_EXT_FEATURE_STA_MON_RSSI_LIST)))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&sdata->local->sta_mtx);
+
+	sta = sta_info_get_bss(sdata, peer);
+	if (!sta) {
+		mutex_unlock(&sdata->local->sta_mtx);
+		return -ENOENT;
+	}
+
+	if (sta->rssi_low == rssi_low &&
+	    sta->rssi_high == rssi_high)
+		goto unlock;
+
+	sta->rssi_thold = 0;
+	sta->rssi_hyst = 0;
+	sta->rssi_low = rssi_low;
+	sta->rssi_high = rssi_high;
+	sta->last_sta_mon_event_signal = 0;
+
+unlock:
+	mutex_unlock(&sdata->local->sta_mtx);
+	return 0;
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -3798,4 +3871,6 @@ static int ieee80211_set_multicast_to_unicast(struct wiphy *wiphy,
 	.del_nan_func = ieee80211_del_nan_func,
 	.set_multicast_to_unicast = ieee80211_set_multicast_to_unicast,
 	.tx_control_port = ieee80211_tx_control_port,
+	.set_sta_mon_rssi_config = ieee80211_set_sta_mon_rssi_config,
+	.set_sta_mon_rssi_range_config = ieee80211_set_sta_mon_rssi_range_confg,
 };
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index f64eb86..701eb37 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -481,6 +481,18 @@ struct ieee80211_sta_rx_stats {
  * @pcpu_rx_stats: per-CPU RX statistics, assigned only if the driver needs
  *	this (by advertising the USES_RSS hw flag)
  * @status_stats: TX status statistics
+ * @rssi_thold: RSSI threshold to monitor station's signal strength, a zero
+ *	value implies disabled. As with the cfg80211 callback, a change here
+ *	should cause an event to be sent indicating where the current value
+ *	is in relation to the newly configured threshold
+ * @rssi_hyst: Station's RSSI hysteresis
+ * @rssi_low: RSSI lower threshold to monitor station's signal strength, a zero
+ *	value implies disabled.  This is an alternative mechanism to the single
+ *	threshold event and can't be enabled simultaneously with it
+ * @rssi_high: RSSI upper threshold for station
+ * @last_sta_mon_event_signal: Last signal strength average for a station
+ *	that triggered a sta_mon event. 0 indicates that no event has been
+ *	generated for the current association
  */
 struct sta_info {
 	/* General information, mostly static */
@@ -581,6 +593,12 @@ struct sta_info {
 
 	struct cfg80211_chan_def tdls_chandef;
 
+	s32 rssi_thold;
+	u32 rssi_hyst;
+	s32 rssi_low;
+	s32 rssi_high;
+	int last_sta_mon_event_signal;
+
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFCv2 3/6] mac80211: Implement functionality to monitor station's rssi threshold cross
  2018-04-27  5:30 [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 1/6] cfg80211: Add support to configure station specific rssi threshold for AP mode Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 2/6] mac80211: Add support to configure " Tamizh chelvam
@ 2018-04-27  5:30 ` Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 4/6] cfg80211: Add support to configure station specific txrate threshold for AP mode Tamizh chelvam
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Tamizh chelvam @ 2018-04-27  5:30 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Tamizh chelvam

Triggers cfg80211_sta_mon_rssi_notify with the corresponding event when
station signal goes out of configured threshold. It uses rx data signal
to check against rssi threshold configured by the user.
This event will be useful for the application like steering to take
decision on any station depends on its current capability.

Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
 include/net/mac80211.h  |  7 ++++++
 net/mac80211/rx.c       | 65 ++++++++++++++++++++++++++++++++++++++++++++++++-
 net/mac80211/sta_info.h |  4 +++
 3 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index d2279b2..7b3d505 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -803,6 +803,13 @@ enum mac80211_rate_control_flags {
 };
 
 
+/*
+ * How many frames need to have been used in average station's
+ * signal strength before checking against the threshold
+ */
+#define IEEE80211_STA_SIGNAL_AVE_MIN_COUNT	4
+
+
 /* there are 40 bytes if you don't need the rateset to be kept */
 #define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40
 
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 03102af..d21f5b1 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1536,6 +1536,66 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
 	return RX_CONTINUE;
 }
 
+static void ieee80211_sta_rx_signal_thold_check(struct ieee80211_rx_data *rx)
+{
+	struct sta_info *sta = rx->sta;
+	struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
+
+	if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
+				NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG))
+		return;
+
+	sta->count_rx_signal++;
+	if (sta->count_rx_signal < IEEE80211_STA_SIGNAL_AVE_MIN_COUNT)
+		return;
+
+	if (sta->rssi_thold && bss_conf->enable_beacon) {
+		int last_event = sta->last_sta_mon_event_signal;
+		int thold = sta->rssi_thold;
+		int hyst = sta->rssi_hyst;
+		int sig = -ewma_signal_read(&sta->rx_stats_avg.signal);
+
+		if (sig < thold &&
+		    (last_event == 0 || sig < last_event - hyst)) {
+			sta->last_sta_mon_event_signal = sig;
+			cfg80211_sta_mon_rssi_notify(
+				rx->sdata->dev, sta->addr,
+				NL80211_STA_MON_RSSI_THRESHOLD_EVENT_LOW,
+				sig, GFP_ATOMIC);
+		} else if (sig > thold &&
+			   (last_event == 0 || sig > last_event + hyst)) {
+			sta->last_sta_mon_event_signal = sig;
+			cfg80211_sta_mon_rssi_notify(
+				rx->sdata->dev, sta->addr,
+				NL80211_STA_MON_RSSI_THRESHOLD_EVENT_HIGH,
+				sig, GFP_ATOMIC);
+		}
+	}
+
+	if (sta->rssi_low) {
+		int last_event = sta->last_sta_mon_event_signal;
+		int sig = -ewma_signal_read(&sta->rx_stats_avg.signal);
+		int low = sta->rssi_low;
+		int high = sta->rssi_high;
+
+		if (sig < low &&
+		    (last_event == 0 || last_event >= low)) {
+			sta->last_sta_mon_event_signal = sig;
+			cfg80211_sta_mon_rssi_notify(
+				rx->sdata->dev, sta->addr,
+				NL80211_STA_MON_RSSI_THRESHOLD_EVENT_LOW,
+				sig, GFP_ATOMIC);
+		} else if (sig > high &&
+			   (last_event == 0 || last_event <= high)) {
+			sta->last_sta_mon_event_signal = sig;
+			cfg80211_sta_mon_rssi_notify(
+				rx->sdata->dev, sta->addr,
+				NL80211_STA_MON_RSSI_THRESHOLD_EVENT_HIGH,
+				sig, GFP_ATOMIC);
+		}
+	}
+}
+
 static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 {
@@ -1591,6 +1651,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid)
 	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
 		sta->rx_stats.last_signal = status->signal;
 		ewma_signal_add(&sta->rx_stats_avg.signal, -status->signal);
+		ieee80211_sta_rx_signal_thold_check(rx);
 	}
 
 	if (status->chains) {
@@ -4032,9 +4093,11 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
 	/* statistics part of ieee80211_rx_h_sta_process() */
 	if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
 		stats->last_signal = status->signal;
-		if (!fast_rx->uses_rss)
+		if (!fast_rx->uses_rss) {
 			ewma_signal_add(&sta->rx_stats_avg.signal,
 					-status->signal);
+			ieee80211_sta_rx_signal_thold_check(rx);
+		}
 	}
 
 	if (status->chains) {
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 701eb37..1599973 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -493,6 +493,9 @@ struct ieee80211_sta_rx_stats {
  * @last_sta_mon_event_signal: Last signal strength average for a station
  *	that triggered a sta_mon event. 0 indicates that no event has been
  *	generated for the current association
+ * @count_rx_signal: Number of data frames used in averaging station signal.
+ *	This can be used to avoid generating less reliable station rssi cross
+ *	events that would be based only on couple of received frames.
  */
 struct sta_info {
 	/* General information, mostly static */
@@ -598,6 +601,7 @@ struct sta_info {
 	s32 rssi_low;
 	s32 rssi_high;
 	int last_sta_mon_event_signal;
+	unsigned int count_rx_signal;
 
 	/* keep last! */
 	struct ieee80211_sta sta;
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFCv2 4/6] cfg80211: Add support to configure station specific txrate threshold for AP mode
  2018-04-27  5:30 [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold Tamizh chelvam
                   ` (2 preceding siblings ...)
  2018-04-27  5:30 ` [RFCv2 3/6] mac80211: Implement functionality to monitor station's rssi threshold cross Tamizh chelvam
@ 2018-04-27  5:30 ` Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 5/6] mac80211: Add support to configure txrate threshold for station Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 6/6] mac80211: Implement functionality to monitor txrate cross event " Tamizh chelvam
  5 siblings, 0 replies; 7+ messages in thread
From: Tamizh chelvam @ 2018-04-27  5:30 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Tamizh chelvam

This patch add support to configure station specific txrate threshold
to monitor change in txrate for stations. This will be useful
for the user application like steering to configure and monitor the
change event of txrate for the station.

NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD and NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD
used with NL80211_CMD_STA_MON command to configure the txrate threshold and
the configuration will be represented in 100kbps.

cfg80211_sta_mon_txrate_notify introduce to notify txrate for a station
goes out of range using NL80211_CMD_NOTIFY_STA_MON command.

NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG flag needs to be advertised by the
drvier to allow and monitor txrate threshold configuration.

Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
 include/net/cfg80211.h       | 26 ++++++++++++++++
 include/uapi/linux/nl80211.h | 34 ++++++++++++++++++++
 net/wireless/nl80211.c       | 74 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/rdev-ops.h      | 17 ++++++++++
 net/wireless/trace.h         | 49 +++++++++++++++++++++++++++++
 5 files changed, 200 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7e7a0bf..4456e2e 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2984,6 +2984,10 @@ struct cfg80211_external_auth_params {
  *	The driver should set %NL80211_EXT_FEATURE_STA_MON_RSSI_LIST if this
  *	method is implemented. If it is provided then there's no point providing
  *	@set_sta_mon_rssi_config.
+ * @set_sta_mon_txrate_config: Configure low and high TXRATE threshold in 100kbs
+ *	for a connected station. The driver should(soon) send an event
+ *	indicating the current attempted frame txrate level is above/below the
+ *	configured threshold.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3293,6 +3297,11 @@ struct cfg80211_ops {
 						 struct net_device *dev,
 						 const u8 *addr,
 						 s32 rssi_low, s32 rssi_high);
+	int     (*set_sta_mon_txrate_config)(struct wiphy *wiphy,
+					     struct net_device *dev,
+					     const u8 *addr,
+					     u32 low_txrate_thold,
+					     u32 high_txrate_thold);
 };
 
 /*
@@ -5813,6 +5822,23 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 		     s32 rssi_level, gfp_t gfp);
 
 /**
+ * cfg80211_sta_mon_txrate_notify - txrate event for connected stations
+ * @dev: network device
+ * @peer: peer's MAC address
+ * @txrate_event: the triggered TX RATE event
+ * @txrate_level: new TX RATE level value or 0 if not available
+ * @gfp: context flags
+ *
+ * This function is called when a average of attempted frame txrate crossed
+ * above configured high txrate or below configured low txrate event
+ * occurs for a station.
+ */
+void
+cfg80211_sta_mon_txrate_notify(struct net_device *dev, const u8 *peer,
+		enum nl80211_sta_mon_txrate_threshold_event txrate_event,
+		u32 txrate_level, gfp_t gfp);
+
+/**
  * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
  * @dev: network device
  * @peer: peer's MAC address
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index fa1fed1..a8b5e3d 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4266,6 +4266,15 @@ enum nl80211_attr_cqm {
  * @NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT: RSSI threshold event
  * @NL80211_ATTR_STA_MON_RSSI_LEVEL: the RSSI value in dBm that triggered the
  *	RSSI threshold event.
+ * @NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD: TX_RATE threshold in 100kbps. This
+ *	u32 attribute specifies the low txrate threshold. Event will be sent
+ *	if the txrate for a station goes lesser than this threshold.
+ * @NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD: TX_RATE threshold in 100kbps. This
+ *	u32 attribute specifies the upper txrate threshold. Event will be sent
+ *	if the txrate for a station goes greater than this threshold.
+ * @NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT: TX_RATE threshold cross event
+ * @NL80211_ATTR_STA_MON_TXRATE_LEVEL: TXRATE for a station in 100kbps that
+ *	triggered the TX_RATE threshold cross event.
  */
 enum nl80211_attr_sta_mon {
 	__NL80211_ATTR_STA_MON_INVALID,
@@ -4273,6 +4282,10 @@ enum nl80211_attr_sta_mon {
 	NL80211_ATTR_STA_MON_RSSI_HYST,
 	NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT,
 	NL80211_ATTR_STA_MON_RSSI_LEVEL,
+	NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD,
+	NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD,
+	NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT,
+	NL80211_ATTR_STA_MON_TXRATE_LEVEL,
 
 	/* keep last */
 	__NL80211_ATTR_STA_MON_AFTER_LAST,
@@ -4305,6 +4318,21 @@ enum nl80211_sta_mon_rssi_threshold_event {
 	NL80211_STA_MON_RSSI_THRESHOLD_EVENT_HIGH,
 };
 
+/**
+ * enum nl80211_sta_mon_txrate_threshold_event - TX_RATE threshold event
+ * @NL80211_STA_MON_TXRATE_THRESHOLD_IN_RANGE: The TX_RATE level is in between
+ *	low and high threshold
+ * @NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_LOW: The TX_RATE level is lower than
+ *	the configured threshold
+ * @NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_HIGH: The TX_RATE is higher than the
+ *      configured threshold
+ */
+enum nl80211_sta_mon_txrate_threshold_event {
+	NL80211_STA_MON_TXRATE_THRESHOLD_IN_RANGE,
+	NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_LOW,
+	NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_HIGH,
+};
+
 
 /**
  * enum nl80211_tx_power_setting - TX power adjustment
@@ -5100,6 +5128,11 @@ enum nl80211_feature_flags {
  * @NL80211_EXT_FEATURE_STA_MON_RSSI_LIST: With this driver the
  *	%NL80211_ATTR_STA_MON_RSSI_THOLD attribute accepts a list of zero or
  *	more RSSI threshold values to monitor rather than exactly one threshold.
+ * @NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG: With this driver will accept
+ *	%NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD attribute as low txrate and
+ *	%NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD attribute as high txrate
+ *	for AP/AP_VLAN/P2P_GO interface to monitor txrate for the connected
+ *	stations and the drvier should advertise txrate via ieee80211_tx_status.
  *
  * @NUM_NL80211_EXT_FEATURES: number of extended features.
  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -5134,6 +5167,7 @@ enum nl80211_ext_feature_index {
 	NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211,
 	NL80211_EXT_FEATURE_STA_MON_RSSI_CONFIG,
 	NL80211_EXT_FEATURE_STA_MON_RSSI_LIST,
+	NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG,
 
 	/* add new features before the definition below */
 	NUM_NL80211_EXT_FEATURES,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 382dc63..7268371 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9872,6 +9872,10 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
 	[NL80211_ATTR_STA_MON_RSSI_HYST] = { .type = NLA_U32 },
 	[NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
 	[NL80211_ATTR_STA_MON_RSSI_LEVEL] = { .type = NLA_S32 },
+	[NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD] = { .type = NLA_U32 },
+	[NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD] = { .type = NLA_U32 },
+	[NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT] = { .type = NLA_U32 },
+	[NL80211_ATTR_STA_MON_TXRATE_LEVEL] = { .type = NLA_U32 },
 };
 
 static int nl80211_set_cqm_txe(struct genl_info *info,
@@ -12777,6 +12781,27 @@ static int nl80211_set_sta_mon_rssi(struct genl_info *info,
 	return err;
 }
 
+static int nl80211_set_sta_mon_txrate(struct genl_info *info, const u8 *addr,
+				      u32 low_thold, u32 high_thold)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	if (!rdev->ops->set_sta_mon_txrate_config)
+		return -EOPNOTSUPP;
+
+	if ((wdev->iftype != NL80211_IFTYPE_AP &&
+	     wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+	     wdev->iftype != NL80211_IFTYPE_AP_VLAN) ||
+	    (!wiphy_ext_feature_isset(&rdev->wiphy,
+			NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG)))
+		return -EOPNOTSUPP;
+
+	return rdev_set_sta_mon_txrate_config(rdev, dev, addr, low_thold,
+					      high_thold);
+}
+
 static int nl80211_sta_mon(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nlattr *attrs[NL80211_ATTR_STA_MON_MAX + 1];
@@ -12812,6 +12837,19 @@ static int nl80211_sta_mon(struct sk_buff *skb, struct genl_info *info)
 				hysteresis);
 	}
 
+	if (attrs[NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD] &&
+	    attrs[NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD]) {
+		u32 low_thold =
+		     nla_get_u32(attrs[NL80211_ATTR_STA_MON_LOW_TXRATE_THOLD]);
+		u32 high_thold =
+		     nla_get_u32(attrs[NL80211_ATTR_STA_MON_HIGH_TXRATE_THOLD]);
+
+		if (low_thold > high_thold)
+			return -EINVAL;
+
+		return nl80211_set_sta_mon_txrate(info, addr, low_thold,
+						  high_thold);
+	}
 	return -EINVAL;
 }
 
@@ -15007,6 +15045,42 @@ void cfg80211_sta_mon_rssi_notify(struct net_device *dev, const u8 *peer,
 }
 EXPORT_SYMBOL(cfg80211_sta_mon_rssi_notify);
 
+void
+cfg80211_sta_mon_txrate_notify(struct net_device *dev, const u8 *peer,
+		enum nl80211_sta_mon_txrate_threshold_event txrate_event,
+		u32 txrate_level, gfp_t gfp)
+{
+	struct sk_buff *msg;
+
+	trace_cfg80211_sta_mon_txrate_notify(dev, peer, txrate_event,
+					     txrate_level);
+
+	if (WARN_ON(txrate_event !=
+			NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_LOW &&
+		    txrate_event !=
+			NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_HIGH))
+		return;
+
+	msg = cfg80211_prepare_sta_mon(dev, peer, gfp);
+	if (!msg)
+		return;
+
+	if (nla_put_u32(msg, NL80211_ATTR_STA_MON_TXRATE_THRESHOLD_EVENT,
+			txrate_event))
+		goto nla_put_failure;
+
+	if (txrate_level && nla_put_u32(msg, NL80211_ATTR_STA_MON_TXRATE_LEVEL,
+					txrate_level))
+		goto nla_put_failure;
+
+	cfg80211_send_sta_mon(msg, gfp);
+
+	return;
+nla_put_failure:
+	nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_sta_mon_txrate_notify);
+
 static struct sk_buff *cfg80211_prepare_cqm(struct net_device *dev,
 					    const char *mac, gfp_t gfp)
 {
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 47562b9..5c3289c 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1251,4 +1251,21 @@ static inline int rdev_del_pmk(struct cfg80211_registered_device *rdev,
 	return ret;
 }
 
+static inline int
+rdev_set_sta_mon_txrate_config(struct cfg80211_registered_device *rdev,
+			       struct net_device *dev, const u8 *peer,
+			       u32 low_txrate_thold, u32 high_txrate_thold)
+{
+	int ret;
+
+	trace_rdev_set_sta_mon_txrate_config(&rdev->wiphy, dev, peer,
+					     low_txrate_thold,
+					     high_txrate_thold);
+	ret = rdev->ops->set_sta_mon_txrate_config(&rdev->wiphy, dev, peer,
+						   low_txrate_thold,
+						   high_txrate_thold);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 78ff0f2..1819411 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1390,6 +1390,55 @@
 		  __entry->rssi_low, __entry->rssi_high)
 );
 
+TRACE_EVENT(rdev_set_sta_mon_txrate_config,
+	TP_PROTO(struct wiphy *wiphy,
+		 struct net_device *netdev, const u8 *peer,
+		 u32 low_txrate_thold, u32 high_txrate_thold),
+	TP_ARGS(wiphy, netdev, peer, low_txrate_thold, high_txrate_thold),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		MAC_ENTRY(peer)
+		__field(u32, low_txrate_thold)
+		__field(u32, high_txrate_thold)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		MAC_ASSIGN(peer, peer);
+		__entry->low_txrate_thold = low_txrate_thold;
+		__entry->high_txrate_thold = high_txrate_thold;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT
+		  ", low_txrate_thold: %u, high_txrate_thold: %u ",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
+		  __entry->low_txrate_thold, __entry->high_txrate_thold)
+);
+
+TRACE_EVENT(cfg80211_sta_mon_txrate_notify,
+	TP_PROTO(struct net_device *netdev, const u8 *peer,
+		 enum nl80211_sta_mon_txrate_threshold_event txrate_event,
+		 u32 txrate_level),
+	TP_ARGS(netdev, peer, txrate_event, txrate_level),
+	TP_STRUCT__entry(
+		NETDEV_ENTRY
+		MAC_ENTRY(peer)
+		__field(enum nl80211_sta_mon_txrate_threshold_event,
+			txrate_event)
+		__field(u32, txrate_level)
+	),
+	TP_fast_assign(
+		NETDEV_ASSIGN;
+		MAC_ASSIGN(peer, peer);
+		__entry->txrate_event = txrate_event;
+		__entry->txrate_level = txrate_level;
+	),
+	TP_printk(NETDEV_PR_FMT ", peer: " MAC_PR_FMT
+		  ", tx_rate event: %d, txrate : %u",
+		  NETDEV_PR_ARG, MAC_PR_ARG(peer),
+		  __entry->txrate_event, __entry->txrate_level)
+);
+
 TRACE_EVENT(rdev_set_cqm_txe_config,
 	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, u32 rate,
 		 u32 pkts, u32 intvl),
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFCv2 5/6] mac80211: Add support to configure txrate threshold for station
  2018-04-27  5:30 [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold Tamizh chelvam
                   ` (3 preceding siblings ...)
  2018-04-27  5:30 ` [RFCv2 4/6] cfg80211: Add support to configure station specific txrate threshold for AP mode Tamizh chelvam
@ 2018-04-27  5:30 ` Tamizh chelvam
  2018-04-27  5:30 ` [RFCv2 6/6] mac80211: Implement functionality to monitor txrate cross event " Tamizh chelvam
  5 siblings, 0 replies; 7+ messages in thread
From: Tamizh chelvam @ 2018-04-27  5:30 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Tamizh chelvam

This patch add support to configure station specific low and high
txrate thresholds using ieee80211_set_sta_mon_txrate_config API.
This configuration is used for tracking the txrate for connected
stations.

Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
 net/mac80211/cfg.c      | 35 +++++++++++++++++++++++++++++++++++
 net/mac80211/sta_info.h |  5 +++++
 2 files changed, 40 insertions(+)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 0e2047c..ba2555d 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3778,6 +3778,40 @@ static int ieee80211_set_sta_mon_rssi_range_confg(struct wiphy *wiphy,
 	return 0;
 }
 
+static int ieee80211_set_sta_mon_txrate_config(struct wiphy *wiphy,
+					       struct net_device *dev,
+					       const u8 *peer,
+					       u32 low_txrate_thold,
+					       u32 high_txrate_thold)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct sta_info *sta;
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP &&
+	    !wiphy_ext_feature_isset(sdata->local->hw.wiphy,
+			NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG))
+		return -EOPNOTSUPP;
+
+	mutex_lock(&sdata->local->sta_mtx);
+
+	sta = sta_info_get_bss(sdata, peer);
+	if (!sta) {
+		mutex_unlock(&sdata->local->sta_mtx);
+		return -ENOENT;
+	}
+
+	if (sta->txrate_low == low_txrate_thold &&
+	    sta->txrate_high == high_txrate_thold)
+		goto unlock;
+
+	sta->txrate_low = low_txrate_thold;
+	sta->txrate_high = high_txrate_thold;
+
+unlock:
+	mutex_unlock(&sdata->local->sta_mtx);
+	return 0;
+}
+
 const struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -3873,4 +3907,5 @@ static int ieee80211_set_sta_mon_rssi_range_confg(struct wiphy *wiphy,
 	.tx_control_port = ieee80211_tx_control_port,
 	.set_sta_mon_rssi_config = ieee80211_set_sta_mon_rssi_config,
 	.set_sta_mon_rssi_range_config = ieee80211_set_sta_mon_rssi_range_confg,
+	.set_sta_mon_txrate_config = ieee80211_set_sta_mon_txrate_config,
 };
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 1599973..c73d010 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -496,6 +496,8 @@ struct ieee80211_sta_rx_stats {
  * @count_rx_signal: Number of data frames used in averaging station signal.
  *	This can be used to avoid generating less reliable station rssi cross
  *	events that would be based only on couple of received frames.
+ * @txrate_low: TXRATE lower threshold for a station to monitor
+ * @txrate_high: TXRATE upper threshold for a station to monitor
  */
 struct sta_info {
 	/* General information, mostly static */
@@ -603,6 +605,9 @@ struct sta_info {
 	int last_sta_mon_event_signal;
 	unsigned int count_rx_signal;
 
+	u32 txrate_low;
+	u32 txrate_high;
+
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [RFCv2 6/6] mac80211: Implement functionality to monitor txrate cross event for station
  2018-04-27  5:30 [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold Tamizh chelvam
                   ` (4 preceding siblings ...)
  2018-04-27  5:30 ` [RFCv2 5/6] mac80211: Add support to configure txrate threshold for station Tamizh chelvam
@ 2018-04-27  5:30 ` Tamizh chelvam
  5 siblings, 0 replies; 7+ messages in thread
From: Tamizh chelvam @ 2018-04-27  5:30 UTC (permalink / raw)
  To: johannes; +Cc: linux-wireless, Tamizh chelvam

Trigger cfg80211_sta_mon_txrate_notify with the corresponding txrate
event when the txrate for a station goes out of configured range.
This event will be useful for the application like steering to take
decision on any station depends on its current capability.

Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org>
---
 include/net/mac80211.h  |  5 +++++
 net/mac80211/cfg.c      |  1 +
 net/mac80211/sta_info.h | 10 ++++++++++
 net/mac80211/status.c   | 40 +++++++++++++++++++++++++++++++++++++++-
 4 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 7b3d505..7023f40 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -809,6 +809,11 @@ enum mac80211_rate_control_flags {
  */
 #define IEEE80211_STA_SIGNAL_AVE_MIN_COUNT	4
 
+/* Number of txrate count need to have been used in average station's
+ * txrate before checking against the threshold
+ */
+#define IEEE80211_STA_TXRATE_AVE_MIN_COUNT	4
+
 
 /* there are 40 bytes if you don't need the rateset to be kept */
 #define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index ba2555d..0f06b0b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3806,6 +3806,7 @@ static int ieee80211_set_sta_mon_txrate_config(struct wiphy *wiphy,
 
 	sta->txrate_low = low_txrate_thold;
 	sta->txrate_high = high_txrate_thold;
+	sta->last_txrate_event = 0;
 
 unlock:
 	mutex_unlock(&sdata->local->sta_mtx);
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index c73d010..e23d916 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -418,6 +418,8 @@ struct ieee80211_sta_rx_stats {
  */
 #define STA_SLOW_THRESHOLD 6000 /* 6 Mbps */
 
+DECLARE_EWMA(sta_txrate, 4, 4)
+
 /**
  * struct sta_info - STA information
  *
@@ -498,6 +500,11 @@ struct ieee80211_sta_rx_stats {
  *	events that would be based only on couple of received frames.
  * @txrate_low: TXRATE lower threshold for a station to monitor
  * @txrate_high: TXRATE upper threshold for a station to monitor
+ * @count_sta_txrate: Number of transmitted data frames used in ave_sta_txrate
+ * @last_txrate_event: Last txrate event that triggered sta_mon event for a
+ *	station
+ * @ave_sta_txrate: Average txrate to check against the txrate_low and
+ *	txrate_high. Values expressed in 100kbps
  */
 struct sta_info {
 	/* General information, mostly static */
@@ -608,6 +615,9 @@ struct sta_info {
 	u32 txrate_low;
 	u32 txrate_high;
 
+	unsigned int count_sta_txrate;
+	enum nl80211_sta_mon_txrate_threshold_event last_txrate_event;
+	struct ewma_sta_txrate ave_sta_txrate;
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 743e89c..6656b04 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -699,6 +699,40 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb,
 	dev_kfree_skb(skb);
 }
 
+static void ieee80211_sta_mon_txrate_thold_check(struct sta_info *sta)
+{
+	struct rate_info rinfo;
+	enum nl80211_sta_mon_txrate_threshold_event sta_txrate_event;
+	int txrate;
+
+	if (!sta->txrate_high)
+		return;
+
+	sta_set_rate_info_tx(sta, &sta->tx_stats.last_rate, &rinfo);
+	txrate = cfg80211_calculate_bitrate(&rinfo);
+	ewma_sta_txrate_add(&sta->ave_sta_txrate, txrate);
+	sta->count_sta_txrate++;
+
+	if (sta->count_sta_txrate < IEEE80211_STA_TXRATE_AVE_MIN_COUNT)
+		return;
+
+	txrate = ewma_sta_txrate_read(&sta->ave_sta_txrate);
+
+	if (txrate < sta->txrate_low)
+		sta_txrate_event = NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_LOW;
+	else if (txrate > sta->txrate_high)
+		sta_txrate_event = NL80211_STA_MON_TXRATE_THRESHOLD_EVENT_HIGH;
+	else
+		sta_txrate_event = NL80211_STA_MON_TXRATE_THRESHOLD_IN_RANGE;
+
+	if (sta_txrate_event != sta->last_txrate_event) {
+		cfg80211_sta_mon_txrate_notify(sta->sdata->dev, sta->addr,
+					       sta_txrate_event, txrate,
+					       GFP_ATOMIC);
+		sta->last_txrate_event = sta_txrate_event;
+	}
+}
+
 static void __ieee80211_tx_status(struct ieee80211_hw *hw,
 				  struct ieee80211_tx_status *status)
 {
@@ -748,9 +782,13 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw,
 
 		if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) &&
 		    (ieee80211_is_data(hdr->frame_control)) &&
-		    (rates_idx != -1))
+		    (rates_idx != -1)) {
 			sta->tx_stats.last_rate =
 				info->status.rates[rates_idx];
+			if (wiphy_ext_feature_isset(hw->wiphy,
+				NL80211_EXT_FEATURE_STA_MON_TXRATE_CONFIG))
+				ieee80211_sta_mon_txrate_thold_check(sta);
+		}
 
 		if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
 		    (ieee80211_is_data_qos(fc))) {
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-04-27  5:30 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-27  5:30 [RFCv2 0/6] cfg80211/mac80211: Add support to configure and monitor rssi/txrate threshold Tamizh chelvam
2018-04-27  5:30 ` [RFCv2 1/6] cfg80211: Add support to configure station specific rssi threshold for AP mode Tamizh chelvam
2018-04-27  5:30 ` [RFCv2 2/6] mac80211: Add support to configure " Tamizh chelvam
2018-04-27  5:30 ` [RFCv2 3/6] mac80211: Implement functionality to monitor station's rssi threshold cross Tamizh chelvam
2018-04-27  5:30 ` [RFCv2 4/6] cfg80211: Add support to configure station specific txrate threshold for AP mode Tamizh chelvam
2018-04-27  5:30 ` [RFCv2 5/6] mac80211: Add support to configure txrate threshold for station Tamizh chelvam
2018-04-27  5:30 ` [RFCv2 6/6] mac80211: Implement functionality to monitor txrate cross event " Tamizh chelvam

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.