@@ -5915,6 +5915,22 @@ void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer,
void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, 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_radar_event - radar detection event
* @wiphy: the wiphy
* @chandef: chandef for the current channel
@@ -1249,6 +1249,7 @@ enum nl80211_commands {
NL80211_CMD_CONTROL_PORT_FRAME,
NL80211_CMD_SET_STA_MON,
+ NL80211_CMD_NOTIFY_STA_MON,
/* add new commands above here */
@@ -15364,6 +15364,104 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
}
EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+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_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;
+ 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 void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
struct cfg80211_chan_def *chandef,
@@ -3282,6 +3282,28 @@
WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
__entry->rssi_thold, __entry->rssi_hyst)
);
+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
Add cfg80211_sta_mon_rssi_notify api to update user space upon crossing the configured rssi threshold of a station. NL80211_CMD_NOTIFY_STA_MON introduced to send this event to userspace along with NL80211_ATTR_STA_MON_RSSI_THRESHOLD_EVENT, NL80211_ATTR_MAC and NL80211_ATTR_STA_MON_RSSI_LEVEL info. Userspace application can make a decision depends on this notification. Signed-off-by: Tamizh chelvam <tamizhr@codeaurora.org> --- include/net/cfg80211.h | 16 ++++++++ include/uapi/linux/nl80211.h | 1 + net/wireless/nl80211.c | 98 ++++++++++++++++++++++++++++++++++++++++++++ net/wireless/trace.h | 22 ++++++++++ 4 files changed, 137 insertions(+)