Search Linux Wireless

[RFC 3/5] nl80211/cfg80211: adding intermediate scan result event.

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

 



Adding intermediate scan result event by exposing new
NL80211_CMD_IM_SCAN_RESULT event, which will contain
NL80211_BSS_BSSID to specify the BSSID of received scan result and
NL80211_BSS_SIGNAL_MBM to indicate signal strength.

This event might be optionally enabled during
NL80211_CMD_TRIGGER_SCAN, with NL80211_ATTR_IM_SCAN_RESULT
flag attribute.

Signed-off-by: Victor Goldenshtein <VictorG@xxxxxx>
---
 include/linux/nl80211.h |   17 +++++++++++++++
 include/net/cfg80211.h  |   10 +++++++++
 net/wireless/core.h     |   10 +++++++++
 net/wireless/nl80211.c  |   51 +++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.h  |    3 ++
 net/wireless/scan.c     |   43 +++++++++++++++++++++++++++++++++++++++
 net/wireless/util.c     |    3 ++
 7 files changed, 137 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2fee93a..5a10ec0 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -504,6 +504,14 @@
  *	event, partial scan results will be available. Returns -ENOENT
  *	if scan is not running.
  *
+ * @NL80211_CMD_IM_SCAN_RESULT: Intermediate scan result notification event,
+ *	this event could be enabled with @NL80211_ATTR_IM_SCAN_RESULT
+ *	flag during @NL80211_CMD_TRIGGER_SCAN. This event contains
+ *	%NL80211_BSS_BSSID which is used to specify the BSSID of received
+ *	scan result and %NL80211_BSS_SIGNAL_MBM to indicate signal strength.
+ *	On reception of this notification, userspace may decide to stop earlier
+ *	currently running scan with (@NL80211_CMD_SCAN_CANCEL).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -630,6 +638,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_SCAN_CANCEL,
 
+	NL80211_CMD_IM_SCAN_RESULT,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1049,6 +1059,11 @@ enum nl80211_commands {
  *	(Re)Association Response frames when the driver (or firmware) replies to
  *	(Re)Association Request frames.
  *
+ * @%NL80211_ATTR_IM_SCAN_RESULT: Flag attribute to enable intermediate
+ *	scan result notification event (%NL80211_CMD_IM_SCAN_RESULT)
+ *	for the %NL80211_CMD_TRIGGER_SCAN command.
+ *	When set: will notify on each new scan result in the cache.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1259,6 +1274,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_IE_PROBE_RESP,
 	NL80211_ATTR_IE_ASSOC_RESP,
 
+	NL80211_ATTR_IM_SCAN_RESULT,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7b0c31e..967d385 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2527,6 +2527,16 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy);
 void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
 
 /**
+ * cfg80211_send_intermediate_result - inform userspace about new
+ * scan result.
+ *
+ * @dev: network device
+ * @cbss: bss info to report.
+ */
+void cfg80211_send_intermediate_result(struct net_device *dev,
+				       struct cfg80211_bss *cbss);
+
+/**
  * cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame
  *
  * @wiphy: the wiphy reporting the BSS
diff --git a/net/wireless/core.h b/net/wireless/core.h
index af22fe3..7484255 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -76,6 +76,9 @@ struct cfg80211_registered_device {
 
 	struct cfg80211_wowlan *wowlan;
 
+	/* intermediate scan result configuration */
+	bool im_scan_result;
+
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
 	struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -231,6 +234,7 @@ enum cfg80211_event_type {
 	EVENT_ROAMED,
 	EVENT_DISCONNECTED,
 	EVENT_IBSS_JOINED,
+	EVENT_IM_SCAN_RESULT,
 };
 
 struct cfg80211_event {
@@ -262,6 +266,10 @@ struct cfg80211_event {
 		struct {
 			u8 bssid[ETH_ALEN];
 		} ij;
+		struct {
+			u8 bssid[ETH_ALEN];
+			s32 signal;
+		} im;
 	};
 };
 
@@ -421,6 +429,8 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
 void __cfg80211_sched_scan_results(struct work_struct *wk);
 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 			       bool driver_initiated);
+void __cfg80211_send_intermediate_result(struct net_device *dev,
+					 struct cfg80211_event *ev);
 int cfg80211_scan_cancel(struct cfg80211_registered_device *rdev);
 void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
 int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index f9f239f..9e60b48 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -189,6 +189,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
 					 .len = IEEE80211_MAX_DATA_LEN },
 	[NL80211_ATTR_IE_ASSOC_RESP] = { .type = NLA_BINARY,
 					 .len = IEEE80211_MAX_DATA_LEN },
+	[NL80211_ATTR_IM_SCAN_RESULT] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -3557,6 +3558,11 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
 		}
 	}
 
+	if (info->attrs[NL80211_ATTR_IM_SCAN_RESULT])
+		rdev->im_scan_result = 1;
+	else
+		rdev->im_scan_result = 0;
+
 	request->dev = dev;
 	request->wiphy = &rdev->wiphy;
 
@@ -6296,6 +6302,31 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg,
 	return -EMSGSIZE;
 }
 
+static int nl80211_send_intermediate_msg(struct sk_buff *msg,
+					struct cfg80211_registered_device *rdev,
+					struct net_device *netdev,
+					u32 pid, u32 seq, int flags,
+					struct cfg80211_event *ev, u32 cmd)
+{
+	void *hdr;
+
+	hdr = nl80211hdr_put(msg, pid, seq, flags, cmd);
+	if (!hdr)
+		return -1;
+
+	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+	NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, ev->im.signal);
+	if (!is_zero_ether_addr(ev->im.bssid))
+		NLA_PUT(msg, NL80211_BSS_BSSID, ETH_ALEN, ev->im.bssid);
+
+	return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
 void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev)
 {
@@ -6353,6 +6384,26 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
 				nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
+void nl80211_send_intermediate_result(struct cfg80211_registered_device *rdev,
+				      struct net_device *netdev,
+				      struct cfg80211_event *ev)
+{
+	struct sk_buff *msg;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	if (nl80211_send_intermediate_msg(msg, rdev, netdev, 0, 0, 0, ev,
+				   NL80211_CMD_IM_SCAN_RESULT) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+				nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
 void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 				     struct net_device *netdev)
 {
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 5d69c56..e0ea1b7 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -12,6 +12,9 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
 			    struct net_device *netdev);
 void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
 			       struct net_device *netdev);
+void nl80211_send_intermediate_result(struct cfg80211_registered_device *rdev,
+				      struct net_device *netdev,
+				      struct cfg80211_event *ev);
 void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev, u32 cmd);
 void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index bb4a991..9be42c3 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -156,6 +156,49 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 	return 0;
 }
 
+void __cfg80211_send_intermediate_result(struct net_device *dev,
+					 struct cfg80211_event *ev)
+{
+	struct wireless_dev *wdev;
+	struct cfg80211_registered_device *rdev;
+
+	if (!dev)
+		return;
+
+	wdev = dev->ieee80211_ptr;
+	rdev = wiphy_to_dev(wdev->wiphy);
+
+	if (rdev->scan_req)
+		nl80211_send_intermediate_result(rdev, dev, ev);
+}
+
+void cfg80211_send_intermediate_result(struct net_device *dev,
+				       struct cfg80211_bss *cbss)
+{
+	struct cfg80211_event *ev;
+	unsigned long flags;
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+	if ((!rdev->im_scan_result) || (!rdev->scan_req) || (!cbss))
+		return;
+
+	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
+	if (!ev)
+		return;
+
+	ev->type = EVENT_IM_SCAN_RESULT;
+	ev->im.signal = cbss->signal;
+	if (cbss->bssid)
+		memcpy(ev->im.bssid, cbss->bssid, ETH_ALEN);
+
+	spin_lock_irqsave(&wdev->event_lock, flags);
+	list_add_tail(&ev->list, &wdev->event_list);
+	spin_unlock_irqrestore(&wdev->event_lock, flags);
+	queue_work(cfg80211_wq, &rdev->event_work);
+}
+EXPORT_SYMBOL(cfg80211_send_intermediate_result);
+
 int cfg80211_scan_cancel(struct cfg80211_registered_device *rdev)
 {
 	struct net_device *dev;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 844ddb0..ad421ad 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -759,6 +759,9 @@ static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
 		case EVENT_IBSS_JOINED:
 			__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
 			break;
+		case EVENT_IM_SCAN_RESULT:
+			__cfg80211_send_intermediate_result(wdev->netdev, ev);
+			break;
 		}
 		wdev_unlock(wdev);
 
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]
  Powered by Linux