Linux wireless drivers development
 help / color / mirror / Atom feed
* [RFC V3 04/11] nl80211: add driver api for gscan notifications
From: Arend van Spriel @ 2016-12-12 11:59 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1481543997-24624-1-git-send-email-arend.vanspriel@broadcom.com>

The driver can indicate gscan results are available or gscan operation
has stopped.

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
 include/net/cfg80211.h       | 28 +++++++++++++++++++++
 include/uapi/linux/nl80211.h |  2 ++
 net/wireless/core.c          |  2 ++
 net/wireless/core.h          |  2 ++
 net/wireless/nl80211.c       | 19 +++++++++++++++
 net/wireless/nl80211.h       |  2 ++
 net/wireless/scan.c          | 58 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/trace.h         | 10 ++++++++
 8 files changed, 123 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 8bc8842..4b02585 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4552,6 +4552,34 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request,
 void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy);

 /**
+ * cfg80211_gscan_results - notify that new scan results are available
+ *
+ * @wiphy: the wiphy which got GScan results
+ */
+void cfg80211_gscan_results(struct wiphy *wiphy);
+
+/**
+ * cfg80211_gscan_stopped - notify that the GScan has stopped
+ *
+ * @wiphy: the wiphy on which the GScan stopped.
+ *
+ * The driver can call this function to inform cfg80211 that the
+ * GScan had to be stopped, for whatever reason.
+ */
+void cfg80211_gscan_stopped(struct wiphy *wiphy);
+
+/**
+ * cfg80211_gscan_stopped_rtnl - notify that the GScan has stopped
+ *
+ * @wiphy: the wiphy on which the GScan stopped.
+ *
+ * The driver can call this function to inform cfg80211 that the
+ * GScan had to be stopped, for whatever reason.
+ * This function should be called with rtnl locked.
+ */
+void cfg80211_gscan_stopped_rtnl(struct wiphy *wiphy);
+
+/**
  * cfg80211_inform_bss_frame_data - inform cfg80211 of a received BSS frame
  * @wiphy: the wiphy reporting the BSS
  * @data: the BSS metadata
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 5e42383..fd7ccd2 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -896,6 +896,7 @@
  *
  * @NL80211_CMD_START_GSCAN: start GScan.
  * @NL80211_CMD_STOP_GSCAN: request to stop current GScan.
+ * @NL80211_CMD_GSCAN_RESULTS: indicates that there GScan results available.
  * @NL80211_CMD_GSCAN_STOPPED: indicates that the currently running GScan
  *	has stopped. This event is generated upon @NL80211_CMD_STOP_GSCAN and
  *	the driver may issue this event at any time when a GScan is running.
@@ -1101,6 +1102,7 @@ enum nl80211_commands {

 	NL80211_CMD_START_GSCAN,
 	NL80211_CMD_STOP_GSCAN,
+	NL80211_CMD_GSCAN_RESULTS,
 	NL80211_CMD_GSCAN_STOPPED,

 	/* add new commands above here */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 760a2fb..69eea4c 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -453,6 +453,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
 	INIT_LIST_HEAD(&rdev->bss_list);
 	INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
 	INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
+	INIT_WORK(&rdev->gscan_results_wk, __cfg80211_gscan_results);
 	INIT_LIST_HEAD(&rdev->mlme_unreg);
 	spin_lock_init(&rdev->mlme_unreg_lock);
 	INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk);
@@ -935,6 +936,7 @@ void wiphy_unregister(struct wiphy *wiphy)
 	cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
 	flush_work(&rdev->destroy_work);
 	flush_work(&rdev->sched_scan_stop_wk);
+	flush_work(&rdev->gscan_stop_wk);
 	flush_work(&rdev->mlme_unreg_wk);

 #ifdef CONFIG_PM
diff --git a/net/wireless/core.h b/net/wireless/core.h
index ee1d162..89e934f 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -79,6 +79,7 @@ struct cfg80211_registered_device {
 	unsigned long suspend_at;
 	struct work_struct scan_done_wk;
 	struct work_struct sched_scan_results_wk;
+	struct work_struct gscan_results_wk;

 	struct genl_info *cur_cmd_info;

@@ -424,6 +425,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
 void __cfg80211_sched_scan_results(struct work_struct *wk);
 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 			       bool driver_initiated);
+void __cfg80211_gscan_results(struct work_struct *wk);
 int __cfg80211_stop_gscan(struct cfg80211_registered_device *rdev,
 			  bool driver_initiated);
 void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 4186ece..7699b16 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -13302,6 +13302,25 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }

+void nl80211_send_gscan_results(struct cfg80211_registered_device *rdev,
+				struct net_device *netdev)
+{
+	struct sk_buff *msg;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	if (nl80211_send_scan_event_msg(msg, rdev, netdev, 0, 0, 0,
+					NL80211_CMD_GSCAN_RESULTS) < 0) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
+				NL80211_MCGRP_SCAN, GFP_KERNEL);
+}
+
 void nl80211_send_scan_event(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev, u32 cmd)
 {
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index fb304ce9..4eec856 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -20,6 +20,8 @@ void nl80211_send_scan_event(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev, u32 cmd);
 void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 				     struct net_device *netdev);
+void nl80211_send_gscan_results(struct cfg80211_registered_device *rdev,
+				     struct net_device *netdev);
 void nl80211_common_reg_change_event(enum nl80211_commands cmd_id,
 				     struct regulatory_request *request);

diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 8c141c2..cc4f7c7 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -338,6 +338,44 @@ void cfg80211_sched_scan_results(struct wiphy *wiphy)
 }
 EXPORT_SYMBOL(cfg80211_sched_scan_results);

+void __cfg80211_gscan_results(struct work_struct *wk)
+{
+	struct cfg80211_registered_device *rdev;
+	struct cfg80211_gscan_request *request;
+
+	rdev = container_of(wk, struct cfg80211_registered_device,
+			    gscan_results_wk);
+
+	rtnl_lock();
+
+	request = rtnl_dereference(rdev->gscan_req);
+
+	/* we don't have request anymore if the scan is stopping */
+	if (request) {
+		if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
+			/* flush entries from previous scans */
+			spin_lock_bh(&rdev->bss_lock);
+			__cfg80211_bss_expire(rdev, request->scan_start);
+			spin_unlock_bh(&rdev->bss_lock);
+			request->scan_start = jiffies;
+		}
+		nl80211_send_gscan_results(rdev, request->dev);
+	}
+
+	rtnl_unlock();
+}
+
+void cfg80211_gscan_results(struct wiphy *wiphy)
+{
+	trace_cfg80211_gscan_results(wiphy);
+	/* ignore if we're not scanning */
+
+	if (rcu_access_pointer(wiphy_to_rdev(wiphy)->gscan_req))
+		queue_work(cfg80211_wq,
+			   &wiphy_to_rdev(wiphy)->gscan_results_wk);
+}
+EXPORT_SYMBOL(cfg80211_gscan_results);
+
 void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -358,6 +396,26 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
 }
 EXPORT_SYMBOL(cfg80211_sched_scan_stopped);

+void cfg80211_gscan_stopped_rtnl(struct wiphy *wiphy)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+	ASSERT_RTNL();
+
+	trace_cfg80211_gscan_stopped(wiphy);
+
+	__cfg80211_stop_gscan(rdev, true);
+}
+EXPORT_SYMBOL(cfg80211_gscan_stopped_rtnl);
+
+void cfg80211_gscan_stopped(struct wiphy *wiphy)
+{
+	rtnl_lock();
+	cfg80211_gscan_stopped_rtnl(wiphy);
+	rtnl_unlock();
+}
+EXPORT_SYMBOL(cfg80211_gscan_stopped);
+
 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 			       bool driver_initiated)
 {
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 1d0fde9..f3f5d82 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2799,6 +2799,16 @@
 	TP_ARGS(wiphy)
 );

+DEFINE_EVENT(wiphy_only_evt, cfg80211_gscan_results,
+	TP_PROTO(struct wiphy *wiphy),
+	TP_ARGS(wiphy)
+);
+
+DEFINE_EVENT(wiphy_only_evt, cfg80211_gscan_stopped,
+	TP_PROTO(struct wiphy *wiphy),
+	TP_ARGS(wiphy)
+);
+
 TRACE_EVENT(cfg80211_get_bss,
 	TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
 		 const u8 *bssid, const u8 *ssid, size_t ssid_len,
--
1.9.1

^ permalink raw reply related

* [RFC V3 03/11] nl80211: add support for gscan
From: Arend van Spriel @ 2016-12-12 11:59 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1481543997-24624-1-git-send-email-arend.vanspriel@broadcom.com>

This patch adds support for GScan which is a scan offload feature
used in Android.

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
Changes:
 V2
  - remove pr_err() statement from nl80211.c
  - get rid of #if 0 code.
 V3
  - change and document storage type of gscan attributes.
  - remove base period attribute from nl80211.
  - bucket periods are changed to be seconds.
  - change NO_IR attribute to PASSIVE.
  - check for NL80211_ATTR_MAC{,_MASK} if random mac support is requested.
  - remove NL80211_SCAN_FLAG_IE_DATA.
---
 include/net/cfg80211.h       |  91 +++++++++++
 include/uapi/linux/nl80211.h | 146 ++++++++++++++++++
 net/wireless/core.c          |  31 ++++
 net/wireless/core.h          |   4 +
 net/wireless/nl80211.c       | 356 ++++++++++++++++++++++++++++++++++++++++++-
 net/wireless/rdev-ops.h      |  25 +++
 net/wireless/scan.c          |  28 ++++
 net/wireless/trace.h         |   9 ++
 8 files changed, 685 insertions(+), 5 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b78377f..8bc8842 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2453,6 +2453,92 @@ struct cfg80211_nan_func {
 };

 /**
+ * struct cfg80211_gscan_channel - GScan channel parameters.
+ *
+
+ * @ch: specific channel.
+ * @dwell_time: hint for dwell time in milliseconds.
+ * @passive: indicates passive scan is requested.
+ */
+struct cfg80211_gscan_channel {
+    struct ieee80211_channel *ch;
+    u8 dwell_time;
+    bool passive;
+};
+
+/**
+ * struct cfg80211_gscan_bucket - GScan bucket parameters.
+ *
+ * @idx: unique bucket index.
+ * @band: bit flags for band(s) to use, see %enum nl80211_bucket_band.
+ * @report_events: This is a bit field according %enum nl80211_bucket_report_event.
+ * @period: period in which the bucket is scheduled to be scanned. If the
+ *	period is too small for driver it should not fail but report results
+ *	as fast as it can. For exponential backoff bucket this is the minimum
+ *	period.
+ * @max_period: used only for the exponential backoff bucket whose scan period
+ *	will grow exponentially to a maximum period of max_period.
+ * @exponent: used only for the exponential backoff bucket.
+ * @step_count: used only for the exponential backoff bucket.
+ * @n_channels: number of channels in @channels array.
+ * @channels: channels to scan which may include DFS channels.
+ */
+struct cfg80211_gscan_bucket {
+	u32 idx;
+	u16 period;
+	u8 band;
+	u8 report_events;
+	u16 max_period;
+	u8 exponent;
+	u8 step_count;
+	u8 n_channels;
+	struct cfg80211_gscan_channel *channels;
+};
+
+/**
+ * struct cfg80211_gscan_request - GScan request parameters.
+ *
+ * @flags: scan request flags according %enum nl80211_scan_flags.
+ * @base_period: base timer period in milliseconds.
+ * @max_ap_per_scan: number of APs to store in each scan entry in the BSSID/RSSI
+ *	history buffer (keep APS with highest RSSI).
+ * @report_threshold_percent: wake up system when scan buffer is filled to this
+ *	percentage.
+ * @report_threshold_num_scans: wake up system when this many scans are stored
+ *	in scan buffer.
+ * @mac: MAC address used for randomisation.
+ * @mac_mask: MAC address mask. bits that are 0 in the mask should be
+ *	randomised, bits that are 1 should be taken as is from @mac.
+ * @n_buckets: number of entries in @buckets array.
+ * @buckets: array of GScan buckets.
+ *
+ * @dev: net device for which GScan is requested.
+ * @rcu_head: RCU callback used to free the struct.
+ * @owner_nlportid: netlink port which initiated this request.
+ * @scan_start: start time of this scan in jiffies.
+ */
+struct cfg80211_gscan_request {
+	u32 flags;
+	u16 base_period;
+	u8 max_ap_per_scan;
+	u8 report_threshold_percent;
+	u8 report_threshold_num_scans;
+	u8 mac[ETH_ALEN];
+	u8 mac_mask[ETH_ALEN];
+
+	u8 n_buckets;
+
+	/* internal */
+	struct net_device *dev;
+	struct rcu_head rcu_head;
+	u32 owner_nlportid;
+	unsigned long scan_start;
+
+	/* keep last */
+	struct cfg80211_gscan_bucket buckets[0];
+};
+
+/**
  * struct cfg80211_ops - backend description for wireless configuration
  *
  * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -2764,6 +2850,8 @@ struct cfg80211_nan_func {
  *	All other parameters must be ignored.
  *
  * @set_multicast_to_unicast: configure multicast to unicast conversion for BSS
+ * @start_gscan: start the GSCAN scanning offload.
+ * @stop_gscan: stop the GSCAN scanning offload.
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -3048,6 +3136,9 @@ struct cfg80211_ops {
 	int	(*set_multicast_to_unicast)(struct wiphy *wiphy,
 					    struct net_device *dev,
 					    const bool enabled);
+	int	(*start_gscan)(struct wiphy *wiphy, struct net_device *dev,
+			       struct cfg80211_gscan_request *gscan_req);
+	int	(*stop_gscan)(struct wiphy *wiphy, struct net_device *dev);
 };

 /*
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 01ab2f7..5e42383 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -894,6 +894,12 @@
  *	does not result in a change for the current association. Currently,
  *	only the %NL80211_ATTR_IE data is used and updated with this command.
  *
+ * @NL80211_CMD_START_GSCAN: start GScan.
+ * @NL80211_CMD_STOP_GSCAN: request to stop current GScan.
+ * @NL80211_CMD_GSCAN_STOPPED: indicates that the currently running GScan
+ *	has stopped. This event is generated upon @NL80211_CMD_STOP_GSCAN and
+ *	the driver may issue this event at any time when a GScan is running.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -1093,6 +1099,10 @@ enum nl80211_commands {

 	NL80211_CMD_UPDATE_CONNECT_PARAMS,

+	NL80211_CMD_START_GSCAN,
+	NL80211_CMD_STOP_GSCAN,
+	NL80211_CMD_GSCAN_STOPPED,
+
 	/* add new commands above here */

 	/* used to define NL80211_CMD_MAX below */
@@ -2389,6 +2399,7 @@ enum nl80211_attrs {

 	NL80211_ATTR_BSSID,
 	NL80211_ATTR_GSCAN_CAPS,
+	NL80211_ATTR_GSCAN_PARAMS,

 	/* add attributes here, update the policy in nl80211.c */

@@ -5246,4 +5257,139 @@ enum nl80211_gscan_caps_attr {
 	NL80211_GSCAN_CAPS_ATTR_MAX = __NL80211_GSCAN_CAPS_ATTR_AFTER_LAST - 1
 };

+/**
+ * enum nl80211_gscan_attr - common GScan parameters.
+ *
+ * @__NL80211_GSCAN_ATTR_INVALID: reserved.
+ * @NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN: number of APs that are kept per
+ *	scan. The kept APs are the ones with strongest RSSI level (u8).
+ * @NL80211_GSCAN_ATTR_REPORT_PERC: threshold specifying percentage of
+ *	scan cache filled that should trigger event for scan results (u8).
+ * @NL80211_GSCAN_ATTR_REPORT_SCANS: threshold specifying number of scans
+ *	after which an event is expected for scan results (u8).
+ * @NL80211_GSCAN_ATTR_BUCKETS: nested attribute specifying
+ *	per-bucket parameters for GScan. See %enum nl80211_gscan_bucket_attr
+ *	for description.
+ * @NL80211_GSCAN_ATTR_MAX: highest GScan attribute.
+ * @__NL80211_GSCAN_ATTR_AFTER_LAST: internal use.
+ */
+enum nl80211_gscan_attr {
+	__NL80211_GSCAN_ATTR_INVALID,
+	NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN,
+	NL80211_GSCAN_ATTR_REPORT_PERC,
+	NL80211_GSCAN_ATTR_REPORT_SCANS,
+	NL80211_GSCAN_ATTR_BUCKETS,
+
+	/* keep last */
+	__NL80211_GSCAN_ATTR_AFTER_LAST,
+	NL80211_GSCAN_ATTR_MAX = __NL80211_GSCAN_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_gscan_bucket_attr - per-bucket GScan parameters.
+ *
+ * @__NL80211_GSCAN_BUCKET_ATTR_INVALID,
+ * @NL80211_GSCAN_BUCKET_ATTR_ID: unique bucket id (u32).
+ * @NL80211_GSCAN_BUCKET_ATTR_BAND: specifies the band to be scanned
+ *	according %enum nl80211_bucket_band. If specified
+ *	@NL80211_GSCAN_BUCKET_ATTR_CHANNELS is ignored (u8).
+ * @NL80211_GSCAN_BUCKET_ATTR_PERIOD: specifies the period between consecutive
+ *	scans of this bucket in seconds. For the backoff bucket this is
+ *	period(0) (u16).
+ * @NL80211_GSCAN_BUCKET_ATTR_REPORT: specifies reporting flags according
+ *	%enum nl80211_bucket_report_event (u8).
+ * @NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD: maximum period between
+ *	consecutive scans. If specified this is a backoff bucket in
+ *	which the period increases according formula:
+ *	period(N) = period(0) * (base ^ (N/step_count)) (u16)
+ * @NL80211_GSCAN_BUCKET_ATTR_EXPONENT: exponential base value as used
+ *	in given formula. This attribute is required when
+ *	@NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD is specified (u8).
+ * @NL80211_GSCAN_BUCKET_ATTR_STEPS: step count as used in given formula.
+ *	This attribute is required when @NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD
+ *	is specified (u8).
+ * @NL80211_GSCAN_BUCKET_ATTR_CHANNELS: nested attribute specifying the
+ *	channels that are to be scanned for this bucket.
+ * @NL80211_GSCAN_BUCKET_ATTR_MAX: highest GScan bucket attribute.
+ * @__NL80211_GSCAN_BUCKET_ATTR_AFTER_LAST: internal use.
+ */
+enum nl80211_gscan_bucket_attr {
+	__NL80211_GSCAN_BUCKET_ATTR_INVALID,
+	NL80211_GSCAN_BUCKET_ATTR_ID,
+	NL80211_GSCAN_BUCKET_ATTR_BAND,
+	NL80211_GSCAN_BUCKET_ATTR_PERIOD,
+	NL80211_GSCAN_BUCKET_ATTR_REPORT,
+	NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD,
+	NL80211_GSCAN_BUCKET_ATTR_EXPONENT,
+	NL80211_GSCAN_BUCKET_ATTR_STEPS,
+	NL80211_GSCAN_BUCKET_ATTR_CHANNELS,
+
+	/* keep last */
+	__NL80211_GSCAN_BUCKET_ATTR_AFTER_LAST,
+	NL80211_GSCAN_BUCKET_ATTR_MAX = __NL80211_GSCAN_BUCKET_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_gscan_chan_attr - GScan bucket channel parameters.
+ *
+ * @__NL80211_GSCAN_CHAN_ATTR_INVALID: reserved.
+ * @NL80211_GSCAN_CHAN_ATTR_FREQ: frequency of channel to be scanned (u32).
+ * @NL80211_GSCAN_CHAN_ATTR_DWELL_TIME: dwell time in milliseconds to stay
+ *	on this channel during scanning (u8).
+ * @NL80211_GSCAN_CHAN_ATTR_PASSIVE: flag attribute indicating that scanning
+ *	should be done passive for this channel.
+ * @NL80211_GSCAN_CHAN_ATTR_MAX: highest GScan channel attribute.
+ * @__NL80211_GSCAN_CHAN_ATTR_AFTER_LAST: internal use.
+ *
+ * Apart from the channel itself the attributes %NL80211_GSCAN_CHAN_ATTR_DWELL_TIME
+ * and %NL80211_GSCAN_CHAN_ATTR_PASSIVE are advisory values. The driver may or
+ * may not comply.
+ */
+enum nl80211_gscan_chan_attr {
+	__NL80211_GSCAN_CHAN_ATTR_INVALID,
+	NL80211_GSCAN_CHAN_ATTR_FREQ,
+	NL80211_GSCAN_CHAN_ATTR_DWELL_TIME,
+	NL80211_GSCAN_CHAN_ATTR_PASSIVE,
+
+	/* keep last */
+	__NL80211_GSCAN_CHAN_ATTR_AFTER_LAST,
+	NL80211_GSCAN_CHAN_ATTR_MAX = __NL80211_GSCAN_CHAN_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bucket_band - GScan bucket band selection.
+ *
+ * @NL80211_BUCKET_BAND_2GHZ: consider all device supported channels
+ *	in 2G band.
+ * @NL80211_BUCKET_BAND_5GHZ: consider all device supported channels
+ *	in 5G band, ie. both DFS and non-DFS when @NL80211_BUCKET_BAND_NODFS
+ *	and @NL80211_BUCKET_BAND_DFS_ONLY are not set.
+ * @NL80211_BUCKET_BAND_NODFS: only consider non-DFS channels. Only
+ *	applicable when 5G band is selected, otherwise ignored.
+ * @NL80211_BUCKET_BAND_DFS_ONLY: only consider DFS channels. Only
+ *	applicable when 5G band is selected, otherwise ignored.
+ *
+ * Setting both @NL80211_BUCKET_BAND_NODFS and @NL80211_BUCKET_BAND_DFS_ONLY
+ * is considerd invalid.
+ */
+enum nl80211_bucket_band {
+	NL80211_BUCKET_BAND_2GHZ	= (1 << 0),
+	NL80211_BUCKET_BAND_5GHZ	= (1 << 1),
+	NL80211_BUCKET_BAND_NODFS	= (1 << 2),
+	NL80211_BUCKET_BAND_DFS_ONLY	= (1 << 3),
+};
+
+/**
+ * enum nl80211_bucket_report_event - GScan bucket report flags.
+ *
+ * @NL80211_BUCKET_REPORT_EACH_SCAN: report each bucket scan completion.
+ * @NL80211_BUCKET_REPORT_FULL_RESULTS: report full scan results.
+ * @NL80211_BUCKET_REPORT_NO_BATCH: no batching required.
+ */
+enum nl80211_bucket_report_event {
+	NL80211_BUCKET_REPORT_EACH_SCAN		= (1 << 0),
+	NL80211_BUCKET_REPORT_FULL_RESULTS	= (1 << 1),
+	NL80211_BUCKET_REPORT_NO_BATCH		= (1 << 2),
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 158c59e..760a2fb 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -357,6 +357,20 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
 	rtnl_unlock();
 }

+static void cfg80211_gscan_stop_wk(struct work_struct *work)
+{
+	struct cfg80211_registered_device *rdev;
+
+	rdev = container_of(work, struct cfg80211_registered_device,
+			    gscan_stop_wk);
+
+	rtnl_lock();
+
+	__cfg80211_stop_gscan(rdev, false);
+
+	rtnl_unlock();
+}
+
 /* exported functions */

 struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -383,6 +397,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
 	WARN_ON(ops->remain_on_channel && !ops->cancel_remain_on_channel);
 	WARN_ON(ops->tdls_channel_switch && !ops->tdls_cancel_channel_switch);
 	WARN_ON(ops->add_tx_ts && !ops->del_tx_ts);
+	WARN_ON(ops->start_gscan && !ops->stop_gscan);

 	alloc_size = sizeof(*rdev) + sizeof_priv;

@@ -456,6 +471,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
 	spin_lock_init(&rdev->destroy_list_lock);
 	INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
 	INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
+	INIT_WORK(&rdev->gscan_stop_wk, cfg80211_gscan_stop_wk);

 #ifdef CONFIG_CFG80211_DEFAULT_PS
 	rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -690,6 +706,12 @@ int wiphy_register(struct wiphy *wiphy)
 		    (wiphy->bss_select_support & ~(BIT(__NL80211_BSS_SELECT_ATTR_AFTER_LAST) - 2))))
 		return -EINVAL;

+	/* buckets must have unique index and in nl80211 parsing
+	 * a u32 is used to verify that hence this limit.
+	 */
+	if (WARN_ON(wiphy->gscan && wiphy->gscan->max_scan_buckets > 32))
+		return -EINVAL;
+
 	if (wiphy->addresses)
 		memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN);

@@ -1001,6 +1023,7 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
 {
 	struct net_device *dev = wdev->netdev;
 	struct cfg80211_sched_scan_request *sched_scan_req;
+	struct cfg80211_gscan_request *gscan_req;

 	ASSERT_RTNL();
 	ASSERT_WDEV_LOCK(wdev);
@@ -1014,6 +1037,9 @@ void __cfg80211_leave(struct cfg80211_registered_device *rdev,
 		sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
 		if (sched_scan_req && dev == sched_scan_req->dev)
 			__cfg80211_stop_sched_scan(rdev, false);
+		gscan_req = rtnl_dereference(rdev->gscan_req);
+		if (gscan_req && dev == gscan_req->dev)
+			__cfg80211_stop_gscan(rdev, false);

 #ifdef CONFIG_CFG80211_WEXT
 		kfree(wdev->wext.ie);
@@ -1089,6 +1115,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct cfg80211_registered_device *rdev;
 	struct cfg80211_sched_scan_request *sched_scan_req;
+	struct cfg80211_gscan_request *gscan_req;

 	if (!wdev)
 		return NOTIFY_DONE;
@@ -1160,6 +1187,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 			    sched_scan_req->dev == wdev->netdev)) {
 			__cfg80211_stop_sched_scan(rdev, false);
 		}
+		gscan_req = rtnl_dereference(rdev->gscan_req);
+		if (WARN_ON(gscan_req && gscan_req->dev == wdev->netdev)) {
+			__cfg80211_stop_gscan(rdev, false);
+		}

 		rdev->opencount--;
 		wake_up(&rdev->dev_wait);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index ec5f333..ee1d162 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -75,6 +75,7 @@ struct cfg80211_registered_device {
 	struct cfg80211_scan_request *scan_req; /* protected by RTNL */
 	struct sk_buff *scan_msg;
 	struct cfg80211_sched_scan_request __rcu *sched_scan_req;
+	struct cfg80211_gscan_request __rcu *gscan_req;
 	unsigned long suspend_at;
 	struct work_struct scan_done_wk;
 	struct work_struct sched_scan_results_wk;
@@ -96,6 +97,7 @@ struct cfg80211_registered_device {
 	struct work_struct destroy_work;

 	struct work_struct sched_scan_stop_wk;
+	struct work_struct gscan_stop_wk;

 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
@@ -422,6 +424,8 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
 void __cfg80211_sched_scan_results(struct work_struct *wk);
 int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 			       bool driver_initiated);
+int __cfg80211_stop_gscan(struct cfg80211_registered_device *rdev,
+			  bool driver_initiated);
 void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
 int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev, enum nl80211_iftype ntype,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 14e1940..4186ece 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9,6 +9,7 @@
 #include <linux/if.h>
 #include <linux/module.h>
 #include <linux/err.h>
+#include <linux/gcd.h>
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/if_ether.h>
@@ -405,6 +406,7 @@ enum nl80211_multicast_groups {
 	[NL80211_ATTR_FILS_NONCES] = { .len = 2 * FILS_NONCE_LEN },
 	[NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED] = { .type = NLA_FLAG, },
 	[NL80211_ATTR_BSSID] = { .len = ETH_ALEN },
+	[NL80211_ATTR_GSCAN_PARAMS] = { .type = NLA_NESTED },
 };

 /* policy for the key attributes */
@@ -11860,6 +11862,322 @@ static int nl80211_set_multicast_to_unicast(struct sk_buff *skb,
 	return rdev_set_multicast_to_unicast(rdev, dev, enabled);
 }

+static const
+struct nla_policy nl80211_gscan_policy[NL80211_GSCAN_ATTR_MAX + 1] = {
+	[NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN] = { .type = NLA_U8 },
+	[NL80211_GSCAN_ATTR_REPORT_PERC] = { .type = NLA_U8 },
+	[NL80211_GSCAN_ATTR_REPORT_SCANS] = { .type = NLA_U8 },
+	[NL80211_GSCAN_ATTR_BUCKETS] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+nl80211_gscan_bucket_policy[NL80211_GSCAN_BUCKET_ATTR_MAX + 1] = {
+	[NL80211_GSCAN_BUCKET_ATTR_ID] = { .type = NLA_U32 },
+	[NL80211_GSCAN_BUCKET_ATTR_BAND] = { .type = NLA_U8 },
+	[NL80211_GSCAN_BUCKET_ATTR_PERIOD] = { .type = NLA_U16 },
+	[NL80211_GSCAN_BUCKET_ATTR_REPORT] = { .type = NLA_U8 },
+	[NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD] = { .type = NLA_U16 },
+	[NL80211_GSCAN_BUCKET_ATTR_EXPONENT] = { .type = NLA_U8 },
+	[NL80211_GSCAN_BUCKET_ATTR_STEPS] = { .type = NLA_U8 },
+	[NL80211_GSCAN_BUCKET_ATTR_CHANNELS] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy
+nl80211_gscan_channel_policy[NL80211_GSCAN_CHAN_ATTR_MAX + 1] = {
+        [NL80211_GSCAN_CHAN_ATTR_FREQ] = { .type = NLA_U32 },
+        [NL80211_GSCAN_CHAN_ATTR_DWELL_TIME] = { .type = NLA_U8 },
+        [NL80211_GSCAN_CHAN_ATTR_PASSIVE] = { .type = NLA_FLAG },
+};
+
+static int nl80211_parse_gscan_channel(struct cfg80211_registered_device *rdev,
+				       struct nlattr *nattr,
+				       struct cfg80211_gscan_channel *chan)
+{
+	struct nlattr *tb[NL80211_GSCAN_CHAN_ATTR_MAX + 1];
+	struct ieee80211_channel *ch;
+	int err;
+
+	err = nla_parse(tb, NL80211_GSCAN_CHAN_ATTR_MAX, nla_data(nattr),
+			nla_len(nattr), nl80211_gscan_channel_policy);
+	if (err)
+		return err;
+
+	if (!tb[NL80211_GSCAN_CHAN_ATTR_FREQ])
+		return -EINVAL;
+
+	ch = ieee80211_get_channel(&rdev->wiphy,
+				   nla_get_u32(tb[NL80211_GSCAN_CHAN_ATTR_FREQ]));
+	if (!ch || (ch->flags & IEEE80211_CHAN_DISABLED))
+		return -EINVAL;
+
+	chan->ch = ch;
+
+	if (tb[NL80211_GSCAN_CHAN_ATTR_DWELL_TIME])
+		chan->dwell_time = nla_get_u8(tb[NL80211_GSCAN_CHAN_ATTR_DWELL_TIME]);
+
+	chan->passive = nla_get_flag(tb[NL80211_GSCAN_CHAN_ATTR_PASSIVE]);
+	return 0;
+}
+
+static int nl80211_parse_gscan_bucket(struct cfg80211_registered_device *rdev,
+				      struct nlattr *nattr,
+				      struct cfg80211_gscan_bucket *bucket,
+				      struct cfg80211_gscan_channel *channels)
+{
+	struct nlattr *tb[NL80211_GSCAN_BUCKET_ATTR_MAX + 1];
+	struct nlattr *chan;
+	struct cfg80211_gscan_channel *ch;
+	int err, rem;
+	int num_chans = 0;
+	u32 band_select = 0;
+	u32 dfs_invalid_mask;
+
+	err = nla_parse(tb, NL80211_GSCAN_BUCKET_ATTR_MAX, nla_data(nattr),
+			nla_len(nattr), nl80211_gscan_bucket_policy);
+	if (err)
+		return err;
+
+	if (!tb[NL80211_GSCAN_BUCKET_ATTR_ID] ||
+	    !tb[NL80211_GSCAN_BUCKET_ATTR_PERIOD])
+		return -EINVAL;
+
+	bucket->idx = nla_get_u32(tb[NL80211_GSCAN_BUCKET_ATTR_ID]);
+	if (tb[NL80211_GSCAN_BUCKET_ATTR_BAND]) {
+		band_select = nla_get_u8(tb[NL80211_GSCAN_BUCKET_ATTR_BAND]);
+
+		/* only makes sense if a band is selected */
+		if (!(band_select & (NL80211_BUCKET_BAND_2GHZ | NL80211_BUCKET_BAND_5GHZ)))
+			return -EINVAL;
+	} else if (!tb[NL80211_GSCAN_BUCKET_ATTR_CHANNELS]) {
+		return -EINVAL;
+	}
+
+	dfs_invalid_mask = NL80211_BUCKET_BAND_5GHZ | NL80211_BUCKET_BAND_NODFS |
+			   NL80211_BUCKET_BAND_DFS_ONLY;
+	if ((band_select & dfs_invalid_mask) == dfs_invalid_mask)
+		return -EINVAL;
+
+	bucket->band = band_select;
+	bucket->period = nla_get_u16(tb[NL80211_GSCAN_BUCKET_ATTR_PERIOD]);
+
+	if (tb[NL80211_GSCAN_BUCKET_ATTR_REPORT])
+		bucket->report_events = nla_get_u8(tb[NL80211_GSCAN_BUCKET_ATTR_REPORT]);
+
+	if (tb[NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD])
+		bucket->max_period = nla_get_u16(tb[NL80211_GSCAN_BUCKET_ATTR_MAX_PERIOD]);
+
+	if (bucket->max_period) {
+		if (bucket->max_period < bucket->period)
+			return -EINVAL;
+		/* additional attributes required for backoff bucket */
+		if (bucket->max_period > bucket->period) {
+			if (!tb[NL80211_GSCAN_BUCKET_ATTR_EXPONENT] ||
+			    !tb[NL80211_GSCAN_BUCKET_ATTR_STEPS])
+				return -EINVAL;
+
+			bucket->exponent = nla_get_u8(tb[NL80211_GSCAN_BUCKET_ATTR_EXPONENT]);
+			bucket->step_count = nla_get_u8(tb[NL80211_GSCAN_BUCKET_ATTR_STEPS]);
+		}
+	}
+
+	/* ignore channels if band is specified */
+	if (band_select)
+		return 0;
+
+        nla_for_each_nested(chan, tb[NL80211_GSCAN_BUCKET_ATTR_CHANNELS], rem) {
+                num_chans++;
+        }
+	if (num_chans > 16)
+		return -EINVAL;
+
+	bucket->n_channels = num_chans;
+	if (!num_chans)
+		return 0;
+
+	bucket->channels = channels;
+	ch = &bucket->channels[0];
+        nla_for_each_nested(chan, tb[NL80211_GSCAN_BUCKET_ATTR_CHANNELS], rem) {
+		err = nl80211_parse_gscan_channel(rdev, chan, ch);
+		if (err) {
+			return err;
+		}
+		ch++;
+        }
+
+	return 0;
+}
+
+static struct cfg80211_gscan_request *
+nl80211_alloc_gscan_request(struct cfg80211_registered_device *rdev,
+			    struct nlattr *buckets_attr)
+{
+	struct cfg80211_gscan_request *req;
+	struct cfg80211_gscan_bucket *b;
+	struct cfg80211_gscan_channel *ch;
+	int n_buckets, n_channels;
+	struct nlattr *attr, *bucket, *channel;
+	int rem, rem_b, rem_c;
+	size_t reqsize;
+
+	if (!buckets_attr)
+		return ERR_PTR(-EINVAL);
+
+	n_buckets = 0;
+	n_channels = 0;
+	nla_for_each_nested(bucket, buckets_attr, rem) {
+		n_buckets++;
+		if (n_buckets > rdev->wiphy.gscan->max_scan_buckets)
+			return ERR_PTR(-EINVAL);
+
+		nla_for_each_nested(attr, bucket, rem_b) {
+			if (nla_type(attr) == NL80211_GSCAN_BUCKET_ATTR_CHANNELS) {
+				nla_for_each_nested(channel, attr, rem_c)
+					n_channels++;
+			}
+		}
+	}
+
+	reqsize = sizeof(*req) +
+		  sizeof(*b) * n_buckets +
+		  sizeof(*ch) * n_channels;
+
+	req = kzalloc(reqsize, GFP_KERNEL);
+	if (!req)
+		return ERR_PTR(-ENOMEM);
+
+	req->n_buckets = n_buckets;
+	return req;
+}
+
+static int nl80211_parse_gscan_params(struct cfg80211_registered_device *rdev,
+				      struct nlattr *attrs[],
+				      struct cfg80211_gscan_request **request)
+{
+	struct cfg80211_gscan_request *req;
+	struct nlattr *tb[NL80211_GSCAN_ATTR_MAX + 1];
+	struct nlattr *bucket;
+	struct cfg80211_gscan_bucket *b;
+	struct cfg80211_gscan_channel *ch;
+	int err, rem, i;
+	u32 bucket_map;
+
+	if (!attrs[NL80211_ATTR_GSCAN_PARAMS])
+		return -EINVAL;
+
+	err = nla_parse(tb, NL80211_GSCAN_ATTR_MAX,
+			nla_data(attrs[NL80211_ATTR_GSCAN_PARAMS]),
+			nla_len(attrs[NL80211_ATTR_GSCAN_PARAMS]),
+			nl80211_gscan_policy);
+	if (err)
+		return err;
+
+	req = nl80211_alloc_gscan_request(rdev, tb[NL80211_GSCAN_ATTR_BUCKETS]);
+	if (IS_ERR(req))
+		return PTR_ERR(req);
+
+	if (tb[NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN])
+		req->max_ap_per_scan = nla_get_u8(tb[NL80211_GSCAN_ATTR_MAX_AP_PER_SCAN]);
+	if (tb[NL80211_GSCAN_ATTR_REPORT_PERC])
+		req->report_threshold_percent = nla_get_u8(tb[NL80211_GSCAN_ATTR_REPORT_PERC]);
+	if (tb[NL80211_GSCAN_ATTR_REPORT_SCANS])
+		req->report_threshold_num_scans = nla_get_u8(tb[NL80211_GSCAN_ATTR_REPORT_SCANS]);
+
+	b = &req->buckets[0];
+	ch = (struct cfg80211_gscan_channel *)(&req->buckets[req->n_buckets]);
+	nla_for_each_nested(bucket, tb[NL80211_GSCAN_ATTR_BUCKETS], rem) {
+		err = nl80211_parse_gscan_bucket(rdev, bucket, b, ch);
+		if (err)
+			goto free_req;
+		ch += b->n_channels;
+		b++;
+	}
+	bucket_map = 0;
+	for (i = 0; i < req->n_buckets; i++) {
+		if (BIT(req->buckets[i].idx) & bucket_map) {
+			err = -EINVAL;
+			goto free_req;
+		}
+		bucket_map |= BIT(req->buckets[i].idx);
+
+		if (req->base_period)
+			req->base_period = gcd(req->buckets[i].period,
+					       req->base_period);
+		else
+			req->base_period = req->buckets[i].period;
+	}
+	*request = req;
+	return 0;
+
+free_req:
+	kfree(req);
+	return err;
+}
+
+static int nl80211_start_gscan(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_gscan_request *request;
+	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 (!rdev->wiphy.gscan ||
+	    !rdev->ops->start_gscan)
+		return -EOPNOTSUPP;
+
+	if (rdev->gscan_req)
+		return -EINPROGRESS;
+
+	err = nl80211_parse_gscan_params(rdev, info->attrs, &request);
+	if (err)
+		return err;
+
+	if (info->attrs[NL80211_ATTR_MAC])
+		memcpy(request->mac, nla_data(info->attrs[NL80211_ATTR_MAC]),
+		       ETH_ALEN);
+	if (info->attrs[NL80211_ATTR_MAC_MASK])
+		memcpy(request->mac_mask,
+		       nla_data(info->attrs[NL80211_ATTR_MAC_MASK]), ETH_ALEN);
+	if (info->attrs[NL80211_ATTR_SCAN_FLAGS]) {
+		request->flags = nla_get_u32(info->attrs[NL80211_ATTR_SCAN_FLAGS]);
+		if (request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR &&
+		    (!info->attrs[NL80211_ATTR_MAC] ||
+		     !info->attrs[NL80211_ATTR_MAC_MASK])) {
+			kfree(request);
+			return -EINVAL;
+		}
+	}
+
+	wdev_lock(wdev);
+	err = rdev_start_gscan(rdev, dev, request);
+	wdev_unlock(wdev);
+	if (err) {
+		kfree(request);
+		return err;
+	}
+
+	request->scan_start = jiffies;
+	request->dev = dev;
+	if (info->attrs[NL80211_ATTR_SOCKET_OWNER])
+		request->owner_nlportid = info->snd_portid;
+
+	rcu_assign_pointer(rdev->gscan_req, request);
+
+	nl80211_send_scan_event(rdev, dev, NL80211_CMD_START_GSCAN);
+	return 0;
+}
+
+static int nl80211_stop_gscan(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+	if (!rdev->wiphy.gscan ||
+	    !rdev->ops->stop_gscan)
+		return -EOPNOTSUPP;
+
+	return __cfg80211_stop_gscan(rdev, false);
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -12735,6 +13053,22 @@ static void nl80211_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_START_GSCAN,
+		.doit = nl80211_start_gscan,
+		.policy = nl80211_policy,
+		.flags = GENL_UNS_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_STOP_GSCAN,
+		.doit = nl80211_stop_gscan,
+		.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 = {
@@ -14540,12 +14874,18 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 	list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
 		bool schedule_destroy_work = false;
 		bool schedule_scan_stop = false;
+		bool schedule_gscan_stop = false;
 		struct cfg80211_sched_scan_request *sched_scan_req =
 			rcu_dereference(rdev->sched_scan_req);
+		struct cfg80211_gscan_request *gscan_req =
+			rcu_dereference(rdev->gscan_req);

 		if (sched_scan_req && notify->portid &&
 		    sched_scan_req->owner_nlportid == notify->portid)
 			schedule_scan_stop = true;
+		if (gscan_req && notify->portid &&
+		    gscan_req->owner_nlportid == notify->portid)
+			schedule_gscan_stop = true;

 		list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
 			cfg80211_mlme_unregister_socket(wdev, notify->portid);
@@ -14576,12 +14916,18 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 				spin_unlock(&rdev->destroy_list_lock);
 				schedule_work(&rdev->destroy_work);
 			}
-		} else if (schedule_scan_stop) {
-			sched_scan_req->owner_nlportid = 0;
+		} else {
+			if (schedule_scan_stop) {
+				sched_scan_req->owner_nlportid = 0;

-			if (rdev->ops->sched_scan_stop &&
-			    rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
-				schedule_work(&rdev->sched_scan_stop_wk);
+				if (rdev->ops->sched_scan_stop &&
+				    rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+					schedule_work(&rdev->sched_scan_stop_wk);
+			}
+			if (schedule_gscan_stop) {
+				gscan_req->owner_nlportid = 0;
+				schedule_work(&rdev->gscan_stop_wk);
+			}
 		}
 	}

diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 2f42507..196e6a7 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1153,4 +1153,29 @@ static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
 	trace_rdev_return_int(&rdev->wiphy, ret);
 	return ret;
 }
+
+static inline int
+rdev_start_gscan(struct cfg80211_registered_device *rdev,
+		 struct net_device *dev,
+		 struct cfg80211_gscan_request *request)
+{
+	int ret;
+
+	trace_rdev_start_gscan(&rdev->wiphy, dev);
+	ret = rdev->ops->start_gscan(&rdev->wiphy, dev, request);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
+static inline int
+rdev_stop_gscan(struct cfg80211_registered_device *rdev,
+		struct net_device *dev)
+{
+	int ret;
+
+	trace_rdev_stop_gscan(&rdev->wiphy, dev);
+	ret = rdev->ops->stop_gscan(&rdev->wiphy, dev);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
 #endif /* __CFG80211_RDEV_OPS */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 174076b..8c141c2 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -386,6 +386,34 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 	return 0;
 }

+int __cfg80211_stop_gscan(struct cfg80211_registered_device *rdev,
+			  bool driver_initiated)
+{
+	struct cfg80211_gscan_request *gscan_req;
+	struct net_device *dev;
+
+	ASSERT_RTNL();
+
+	if (!rdev->gscan_req)
+		return -ENOENT;
+
+	gscan_req = rtnl_dereference(rdev->gscan_req);
+	dev = gscan_req->dev;
+
+	if (!driver_initiated) {
+		int err = rdev_stop_gscan(rdev, dev);
+		if (err)
+			return err;
+	}
+
+	nl80211_send_scan_event(rdev, dev, NL80211_CMD_GSCAN_STOPPED);
+
+	RCU_INIT_POINTER(rdev->gscan_req, NULL);
+	kfree_rcu(gscan_req, rcu_head);
+
+	return 0;
+}
+
 void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
                       unsigned long age_secs)
 {
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index ea1b47e..1d0fde9 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -3067,6 +3067,15 @@
 		  WIPHY_PR_ARG, NETDEV_PR_ARG,
 		  BOOL_TO_STR(__entry->enabled))
 );
+
+DEFINE_EVENT(wiphy_netdev_evt, rdev_start_gscan,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+	TP_ARGS(wiphy, netdev)
+);
+DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_gscan,
+	TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
+	TP_ARGS(wiphy, netdev)
+);
 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */

 #undef TRACE_INCLUDE_PATH
--
1.9.1

^ permalink raw reply related

* [RFC V3 00/11] nl80211: add support for g-scan
From: Arend van Spriel @ 2016-12-12 11:59 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel

Android employs a Wifi-HAL layer in its wireless frame. It basically abstracts
dealing with netlink messages from the framework. For some features it employs
nl80211 vendor commands. The goal I set myself is to be able to have a generic
nl80211 Wifi-HAL implementation. One of the features currently requiring the
vendor commands is g-scan. We can only guess what the 'g' stands for ;-) This
series converts the vendor command api into common nl80211 api.

This series adds basic support of g-scan (or GScan, or gscan, or something
completely different; suggestions are welcome). A basic g-scan request consists
of some common attributes and so-called buckets. Each bucket represents a
re-occurring scan request with a given interval and a set of channels. The
common attributes specify how much scans (m) should be stored and how many
BSS-es (n) should be kept per scan before an event is sent. The other option
is to specify a percentage at which an event is sent, where 100% equals (m * n).
A special case of bucket is the exponential backoff bucket, which has an
increasing interval.

The series is applied on top of master branch of wireless-testing as it relied
on patches pending in wireless-drivers-next. As such this series include two
fixes against those pending patched. Hopefully using wireless-testing allows
the nl80211 changes in this series to apply to mac80211-next. I consider it
still in RFC state so it may not matter right now.

Changes:
 V2
  - remove pr_err() statement from nl80211.c
  - get rid of #if 0 code.
  - reordered patches resolving compilation issue.
 V3
  - drop support for RTT info in scan results.
  - cleanup attribute definitions.
  - add driver implementation for brcmfmac.

Arend van Spriel (11):
  nl80211: add reporting of gscan capabilities
  nl80211: rename some notification functions
  nl80211: add support for gscan
  nl80211: add driver api for gscan notifications
  brcmfmac: fix memory leak in brcmf_cfg80211_attach()
  brcmfmac: fix uninitialized field in scheduled scan ssid configuration
  brcmfmac: add firmware feature detection for gscan feature
  brcmfmac: report gscan capabilities if firmware supports it
  brcmfmac: implement gscan functionality
  brcmfmac: handle gscan events from firmware
  brcmfmac: allow gscan to run concurrent with scheduled scan

 .../broadcom/brcm80211/brcmfmac/cfg80211.c         | 266 +++++++++++--
 .../broadcom/brcm80211/brcmfmac/cfg80211.h         |  12 +-
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    |   5 +-
 .../wireless/broadcom/brcm80211/brcmfmac/debug.h   |   2 +
 .../wireless/broadcom/brcm80211/brcmfmac/feature.c |  22 +-
 .../wireless/broadcom/brcm80211/brcmfmac/feature.h |   4 +-
 .../wireless/broadcom/brcm80211/brcmfmac/fweh.h    |   1 +
 .../broadcom/brcm80211/brcmfmac/fwil_types.h       |  92 +++++
 .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 381 +++++++++++++++++-
 .../net/wireless/broadcom/brcm80211/brcmfmac/pno.h |  37 ++
 include/net/cfg80211.h                             | 155 ++++++++
 include/uapi/linux/nl80211.h                       | 207 ++++++++++
 net/wireless/core.c                                |  33 ++
 net/wireless/core.h                                |   6 +
 net/wireless/nl80211.c                             | 430 ++++++++++++++++++++-
 net/wireless/nl80211.h                             |   4 +-
 net/wireless/rdev-ops.h                            |  25 ++
 net/wireless/scan.c                                |  90 ++++-
 net/wireless/trace.h                               |  19 +
 19 files changed, 1726 insertions(+), 65 deletions(-)

--
1.9.1

^ permalink raw reply

* [RFC V3 02/11] nl80211: rename some notification functions
From: Arend van Spriel @ 2016-12-12 11:59 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1481543997-24624-1-git-send-email-arend.vanspriel@broadcom.com>

The functions nl80211_send_sched_scan() and nl80211_send_sched_scan_msg()
take command as parameter, which strictly speaking makes them general
purpose and not directly related to scheduled scan functionality. The
message are sent to "scan" multicast group so renaming them to
nl80211_send_scan_event{,_msg}().

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
---
 net/wireless/nl80211.c | 10 +++++-----
 net/wireless/nl80211.h |  2 +-
 net/wireless/scan.c    |  4 ++--
 3 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 40209ec..14e1940 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7247,7 +7247,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,

 	rcu_assign_pointer(rdev->sched_scan_req, sched_scan_req);

-	nl80211_send_sched_scan(rdev, dev,
+	nl80211_send_scan_event(rdev, dev,
 				NL80211_CMD_START_SCHED_SCAN);
 	return 0;

@@ -12878,7 +12878,7 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
 }

 static int
-nl80211_send_sched_scan_msg(struct sk_buff *msg,
+nl80211_send_scan_event_msg(struct sk_buff *msg,
 			    struct cfg80211_registered_device *rdev,
 			    struct net_device *netdev,
 			    u32 portid, u32 seq, int flags, u32 cmd)
@@ -12958,7 +12958,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 	if (!msg)
 		return;

-	if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
+	if (nl80211_send_scan_event_msg(msg, rdev, netdev, 0, 0, 0,
 					NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
 		nlmsg_free(msg);
 		return;
@@ -12968,7 +12968,7 @@ void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }

-void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
+void nl80211_send_scan_event(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev, u32 cmd)
 {
 	struct sk_buff *msg;
@@ -12977,7 +12977,7 @@ void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 	if (!msg)
 		return;

-	if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
+	if (nl80211_send_scan_event_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
 		nlmsg_free(msg);
 		return;
 	}
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7e3821d..fb304ce9 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -16,7 +16,7 @@ struct sk_buff *nl80211_build_scan_msg(struct cfg80211_registered_device *rdev,
 				       struct wireless_dev *wdev, bool aborted);
 void nl80211_send_scan_result(struct cfg80211_registered_device *rdev,
 			      struct sk_buff *msg);
-void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
+void nl80211_send_scan_event(struct cfg80211_registered_device *rdev,
 			     struct net_device *netdev, u32 cmd);
 void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 				     struct net_device *netdev);
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 35ad69f..174076b 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -378,7 +378,7 @@ int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
 			return err;
 	}

-	nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
+	nl80211_send_scan_event(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);

 	RCU_INIT_POINTER(rdev->sched_scan_req, NULL);
 	kfree_rcu(sched_scan_req, rcu_head);
@@ -1147,7 +1147,7 @@ struct cfg80211_bss *
 	else
 		rcu_assign_pointer(tmp.pub.beacon_ies, ies);
 	rcu_assign_pointer(tmp.pub.ies, ies);
-
+
 	memcpy(tmp.pub.bssid, mgmt->bssid, ETH_ALEN);
 	tmp.pub.channel = channel;
 	tmp.pub.scan_width = data->scan_width;
--
1.9.1

^ permalink raw reply related

* [RFC V3 01/11] nl80211: add reporting of gscan capabilities
From: Arend van Spriel @ 2016-12-12 11:59 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Arend van Spriel
In-Reply-To: <1481543997-24624-1-git-send-email-arend.vanspriel@broadcom.com>

From: Arend van Spriel <arend@broadcom.com>

GScan is a scan offload feature used in recent Android releases. This
patch adds possibility for wireless device drivers to report their
capabilities and provide it to user-space.

Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
Reviewed-by: Franky Lin <franky.lin@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
Changes:
 V3:
  - change storage types for capabilities.
---
 include/net/cfg80211.h       | 36 +++++++++++++++++++++++++++
 include/uapi/linux/nl80211.h | 59 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.c       | 45 ++++++++++++++++++++++++++++++++-
 3 files changed, 139 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ef42749..b78377f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3361,6 +3361,40 @@ struct wiphy_iftype_ext_capab {
 };

 /**
+ * struct wiphy_gscan_caps -  gscan capabilities of the device.
+ *
+ * @max_scan_cache_size: total space allocated for scan results (in bytes).
+ * @max_scan_buckets: maximum number of channel buckets.
+ * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan.
+ * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI.
+ * @max_scan_reporting_threshold: max possible report threshold. in percentage.
+ * @max_hotlist_bssids: maximum number of entries for hotlist BSSIDs.
+ * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs.
+ * @max_significant_wifi_change_aps: maximum number of entries for significant
+ *	change APs.
+ * @max_bssid_history_entries: number of BSSID/RSSI entries that device can
+ *	hold.
+ * @max_epno_networks: max number of hashed epno entries.
+ * @max_epno_networks_by_ssid: max number of epno entries for which an
+ *	exact match of SSID is required or which are hidded SSIDs.
+ * @max_white_list_ssid: max number of white listed SSIDs.
+ */
+struct wiphy_gscan_caps {
+	u16 max_scan_cache_size;
+	u8 max_scan_buckets;
+	u8 max_ap_cache_per_scan;
+	u8 max_rssi_sample_size;
+	u8 max_scan_reporting_threshold;
+	u8 max_hotlist_bssids;
+	u8 max_hotlist_ssids;
+	u8 max_significant_wifi_change_aps;
+	u8 max_bssid_history_entries;
+	u8 max_epno_hashed_networks;
+	u8 max_epno_exact_networks;
+	u8 max_white_list_ssid;
+};
+
+/**
  * struct wiphy - wireless hardware description
  * @reg_notifier: the driver's regulatory notification callback,
  *	note that if your driver uses wiphy_apply_custom_regulatory()
@@ -3513,6 +3547,7 @@ struct wiphy_iftype_ext_capab {
  * @bss_select_support: bitmask indicating the BSS selection criteria supported
  *	by the driver in the .connect() callback. The bit position maps to the
  *	attribute indices defined in &enum nl80211_bss_select_attr.
+ * @gscan: structure holding the hardware capabilities for gscan.
  *
  * @cookie_counter: unique generic cookie counter, used to identify objects.
  */
@@ -3643,6 +3678,7 @@ struct wiphy {
 	u8 max_adj_channel_rssi_comp;

 	u32 bss_select_support;
+	const struct wiphy_gscan_caps *gscan;

 	u64 cookie_counter;

diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 6b76e3b..01ab2f7 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1980,6 +1980,9 @@ enum nl80211_commands {
  * @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also
  *	used in various commands/events for specifying the BSSID.
  *
+ * @NL80211_ATTR_GSCAN_CAPS: indicating capabilities of GScan functionality
+ *	of the device. This is a nested attribute.
+ *
  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2385,6 +2388,7 @@ enum nl80211_attrs {
 	NL80211_ATTR_MULTICAST_TO_UNICAST_ENABLED,

 	NL80211_ATTR_BSSID,
+	NL80211_ATTR_GSCAN_CAPS,

 	/* add attributes here, update the policy in nl80211.c */

@@ -5187,4 +5191,59 @@ enum nl80211_nan_match_attributes {
 	NL80211_NAN_MATCH_ATTR_MAX = NUM_NL80211_NAN_MATCH_ATTR - 1
 };

+/**
+ * enum nl80211_gscan_caps_attr - GScan capabilities attributes.
+ *
+ * @__NL80211_GSCAN_CAPS_ATTR_INVALID: reserved.
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_CACHE_SIZE: total space allocated for
+ *	scan results in bytes (u16).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_BUCKETS: maximum number of channel buckets
+ *	allowed (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_AP_CACHE_PER_SCAN: maximum number of APs that
+ *	can be stored per scan (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_RSSI_SAMPLE_SIZE: maximum number of RSSI samples
+ *	used for averaging RSSI (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_REPORTING_THRESHOLD: maximum allowed
+ *	percentile report threshold (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_BSSID: maximum number of entries for
+ *	hotlist BSSIDs (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_SSID: maximum number of entries for
+ *	hotlist SSIDs (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_SIGNIFICANT_WIFI_CHANGE_APS: maximum number of
+ *	entries for significant change APs (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_BSSID_HISTORY: number of BSSID/RSSI entries that
+ *	device can hold (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_HASHED_NETWORKS: maximum number of hashed
+ *	epno entries (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_EXACT_NETWORKS: maximum number of epno
+ *	entries for which an exact match of SSID is required or which are hidden
+ *	SSIDs (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX_WHITE_LIST_SSID: maximum number of white listed
+ *	SSIDs (u8).
+ * @NL80211_GSCAN_CAPS_ATTR_MAX: highest GScan capability attribute.
+ *
+ * @__NL80211_GSCAN_CAPS_ATTR_AFTER_LAST: internal use.
+ *
+ * All attributes are u32 type.
+ */
+enum nl80211_gscan_caps_attr {
+	__NL80211_GSCAN_CAPS_ATTR_INVALID,
+	NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_CACHE_SIZE,
+	NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_BUCKETS,
+	NL80211_GSCAN_CAPS_ATTR_MAX_AP_CACHE_PER_SCAN,
+	NL80211_GSCAN_CAPS_ATTR_MAX_RSSI_SAMPLE_SIZE,
+	NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_REPORTING_THRESHOLD,
+	NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_BSSID,
+	NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_SSID,
+	NL80211_GSCAN_CAPS_ATTR_MAX_SIGNIFICANT_WIFI_CHANGE_APS,
+	NL80211_GSCAN_CAPS_ATTR_MAX_BSSID_HISTORY,
+	NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_HASHED_NETWORKS,
+	NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_EXACT_NETWORKS,
+	NL80211_GSCAN_CAPS_ATTR_MAX_WHITE_LIST_SSID,
+
+	/* keep last */
+	__NL80211_GSCAN_CAPS_ATTR_AFTER_LAST,
+	NL80211_GSCAN_CAPS_ATTR_MAX = __NL80211_GSCAN_CAPS_ATTR_AFTER_LAST - 1
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 7762231..40209ec 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1424,9 +1424,10 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
 	void *hdr;
 	struct nlattr *nl_bands, *nl_band;
 	struct nlattr *nl_freqs, *nl_freq;
-	struct nlattr *nl_cmds;
+	struct nlattr *nl_cmds, *nl_gscan;
 	enum nl80211_band band;
 	struct ieee80211_channel *chan;
+	const struct wiphy_gscan_caps *gscan;
 	int i;
 	const struct ieee80211_txrx_stypes *mgmt_stypes =
 				rdev->wiphy.mgmt_stypes;
@@ -1881,6 +1882,48 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
 			}
 		}

+		state->split_start++;
+		break;
+	case 14:
+		if (!rdev->wiphy.gscan) {
+			/* done */
+			state->split_start = 0;
+			break;
+		}
+		gscan = rdev->wiphy.gscan;
+		nl_gscan = nla_nest_start(msg, NL80211_ATTR_GSCAN_CAPS);
+		if (!nl_gscan ||
+		    nla_put_u16(msg, NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_CACHE_SIZE,
+				gscan->max_scan_cache_size) ||
+		    nla_put_u8(msg, NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_BUCKETS,
+			       gscan->max_scan_buckets) ||
+		    nla_put_u8(msg, NL80211_GSCAN_CAPS_ATTR_MAX_AP_CACHE_PER_SCAN,
+			       gscan->max_ap_cache_per_scan) ||
+		    nla_put_u8(msg, NL80211_GSCAN_CAPS_ATTR_MAX_RSSI_SAMPLE_SIZE,
+			       gscan->max_rssi_sample_size) ||
+		    nla_put_u8(msg,
+			       NL80211_GSCAN_CAPS_ATTR_MAX_SCAN_REPORTING_THRESHOLD,
+			       gscan->max_scan_reporting_threshold) ||
+		    nla_put_u8(msg, NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_BSSID,
+			       gscan->max_hotlist_bssids) ||
+		    nla_put_u8(msg, NL80211_GSCAN_CAPS_ATTR_MAX_HOTLIST_SSID,
+			       gscan->max_hotlist_ssids) ||
+		    nla_put_u8(msg,
+			       NL80211_GSCAN_CAPS_ATTR_MAX_SIGNIFICANT_WIFI_CHANGE_APS,
+			       gscan->max_significant_wifi_change_aps) ||
+		    nla_put_u8(msg, NL80211_GSCAN_CAPS_ATTR_MAX_BSSID_HISTORY,
+			       gscan->max_bssid_history_entries) ||
+		    nla_put_u8(msg,
+			       NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_HASHED_NETWORKS,
+			       gscan->max_epno_hashed_networks) ||
+		    nla_put_u8(msg,
+			       NL80211_GSCAN_CAPS_ATTR_MAX_EPNO_EXACT_NETWORKS,
+			       gscan->max_epno_exact_networks) ||
+		    nla_put_u8(msg, NL80211_GSCAN_CAPS_ATTR_MAX_WHITE_LIST_SSID,
+			       gscan->max_white_list_ssid))
+			goto nla_put_failure;
+		nla_nest_end(msg, nl_gscan);
+
 		/* done */
 		state->split_start = 0;
 		break;
--
1.9.1

^ permalink raw reply related

* Re: Could we have request_firmware_nowait with FW_OPT_NO_WARN?
From: Kalle Valo @ 2016-12-12 11:48 UTC (permalink / raw)
  To: Rafał Miłecki
  Cc: Johannes Berg, Ming Lei, Luis R. Rodriguez,
	Linux Kernel Mailing List, linux-wireless@vger.kernel.org,
	brcm80211 development
In-Reply-To: <CACna6rzZnO1YtS2=6S1PGCTJkzTeuz9oJ+1yHBgWNhvUPz4acg@mail.gmail.com>

Rafa=C5=82 Mi=C5=82ecki <zajec5@gmail.com> writes:

> On 12 December 2016 at 09:12, Johannes Berg <johannes@sipsolutions.net> w=
rote:
>> On Sat, 2016-12-10 at 16:54 +0100, Rafa=C5=82 Mi=C5=82ecki wrote:
>>> In brcmfmac we use request_firmware_nowait and if fetching firmware
>>> with NVRAM variables fails then we try to fallback to the platform
>>> one (see brcmf_fw_request_code_done & brcmf_fw_request_nvram_done).
>>>
>>> Some problem for us is that on devices with platform NVRAM we get
>>> this error:
>>> Direct firmware load for brcm/brcmfmac43602-pcie.txt failed with error =
-2
>>
>> This also happens with iwlwifi, because it requests multiple firmware
>> versions starting at the most recent supported one (which is often not
>> released at the same time).
>
> Good to know it may help others as well!

We have the same problem also on ath10k :) And it's confusing users a
lot, especially as we also load calibration file and other files. So
yes, something like this is very much needed.

But in ath10k we use request_firmware() instead
request_firmware_nowait(). So I would appreciate if you could add the
support to both variants.

--=20
Kalle Valo

^ permalink raw reply

* Re: [PATCH] cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT
From: Johannes Berg @ 2016-12-12 10:27 UTC (permalink / raw)
  To: Andrew Zaborowski, Marcel Holtmann; +Cc: linux-wireless
In-Reply-To: <CAOq732Lvqez5mNne9YAk8aTrZyAQsxxL6pSwD9EkB4V0t2mLrg@mail.gmail.com>

On Mon, 2016-12-12 at 11:01 +0100, Andrew Zaborowski wrote:
> On 12 December 2016 at 08:21, Marcel Holtmann <marcel@holtmann.org>
> wrote:
> > 
> > > 
> > > Disconnect or deauthenticate when the owning socket is closed if
> > > this
> > > flag is supplied to CMD_CONNECT or CMD_AUTHENTICATE.  This may be
> > > used
> > > to ensure userspace daemon doesn't leave an unmanaged connection
> > > behind.
> > 
> > I think you have a typo here. The CMD_AUTHENTICATE should be
> > CMD_ASSOCIATE?
> 
> Good point, let me change this and resend.

It'd be helpful if you could follow normal practice and add a v2/v3/...
tag to your [PATCH] tag, that helps knowing which one's the latest.

johannes

^ permalink raw reply

* [PATCH] cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT
From: Andrew Zaborowski @ 2016-12-12 10:04 UTC (permalink / raw)
  To: linux-wireless

Disconnect or deauthenticate when the owning socket is closed if this
flag is supplied to CMD_CONNECT or CMD_ASSOCIATE.  This may be used
to ensure userspace daemon doesn't leave an unmanaged connection behind.

In some situations it would be possible to account for that, to some
degree, in the deamon restart code or in the up/down scripts without
the use of this attribute.  But there will be systems where the daemon
can go away for varying periods without a warning due to local resource
management.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 include/net/cfg80211.h       |  7 +++++++
 include/uapi/linux/nl80211.h |  2 ++
 net/wireless/core.c          | 33 +++++++++++++++++++++++++++++++++
 net/wireless/mlme.c          |  2 ++
 net/wireless/nl80211.c       | 28 +++++++++++++++++++++++++++-
 net/wireless/sme.c           |  4 ++++
 6 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bd19faa..ca2e252 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3764,6 +3764,9 @@ struct cfg80211_cached_keys;
  * @conn: (private) cfg80211 software SME connection state machine data
  * @connect_keys: (private) keys to set after connection is established
  * @conn_bss_type: connecting/connected BSS type
+ * @conn_owner_nlportid: (private) connection owner socket port ID
+ * @disconnect_wk: (private) auto-disconnect work
+ * @disconnect_bssid: (private) the BSSID to use for auto-disconnect
  * @ibss_fixed: (private) IBSS is using fixed BSSID
  * @ibss_dfs_possible: (private) IBSS may change to a DFS channel
  * @event_list: (private) list for internal event processing
@@ -3795,6 +3798,10 @@ struct wireless_dev {
 	struct cfg80211_conn *conn;
 	struct cfg80211_cached_keys *connect_keys;
 	enum ieee80211_bss_type conn_bss_type;
+	u32 conn_owner_nlportid;
+
+	struct work_struct disconnect_wk;
+	u8 disconnect_bssid[ETH_ALEN];
 
 	struct list_head event_list;
 	spinlock_t event_lock;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 56368e9..84db1f0 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1788,6 +1788,8 @@ enum nl80211_commands {
  *	and remove functions. NAN notifications will be sent in unicast to that
  *	socket. Without this attribute, any socket can add functions and the
  *	notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
+ *	If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
+ *	station will deauthenticate when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 8201e6d..6b8fd68 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -357,6 +357,36 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
 	rtnl_unlock();
 }
 
+static void cfg80211_disconnect_wk(struct work_struct *work)
+{
+	struct cfg80211_registered_device *rdev;
+	struct wireless_dev *wdev;
+
+	wdev = container_of(work, struct wireless_dev, disconnect_wk);
+	rdev = wiphy_to_rdev(wdev->wiphy);
+
+	if (!wdev->netdev)
+		return;
+
+	wdev_lock(wdev);
+
+	if (wdev->conn_owner_nlportid) {
+		/*
+		 * Use disconnect_bssid if still connecting and ops->disconnect
+		 * not implemented.  Otherwise we can use cfg80211_disconnect.
+		 */
+		if (rdev->ops->disconnect || wdev->current_bss)
+			cfg80211_disconnect(rdev, wdev->netdev,
+					WLAN_REASON_DEAUTH_LEAVING, true);
+		else
+			cfg80211_mlme_deauth(rdev, wdev->netdev,
+					wdev->disconnect_bssid, NULL, 0,
+					WLAN_REASON_DEAUTH_LEAVING, false);
+	}
+
+	wdev_unlock(wdev);
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -1117,6 +1147,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		     wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
 			dev->priv_flags |= IFF_DONT_BRIDGE;
 
+		INIT_WORK(&wdev->disconnect_wk, cfg80211_disconnect_wk);
+
 		nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
 		break;
 	case NETDEV_GOING_DOWN:
@@ -1205,6 +1237,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 #ifdef CONFIG_CFG80211_WEXT
 			kzfree(wdev->wext.keys);
 #endif
+			flush_work(&wdev->disconnect_wk);
 		}
 		/*
 		 * synchronise (so that we won't find this netdev
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index cbb48e2..9923244 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -328,6 +328,8 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	wdev->conn_owner_nlportid = 0;
+
 	if (local_state_change &&
 	    (!wdev->current_bss ||
 	     !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c510810..502ae92 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8003,6 +8003,12 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 		wdev_unlock(dev->ieee80211_ptr);
 	}
 
+	if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+		dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
+
+		memcpy(dev->ieee80211_ptr->disconnect_bssid, bssid, ETH_ALEN);
+	}
+
 	return err;
 }
 
@@ -8050,6 +8056,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 	err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
 				   local_state_change);
 	wdev_unlock(dev->ieee80211_ptr);
+
+	if (!err)
+		dev->ieee80211_ptr->conn_owner_nlportid = 0;
+
 	return err;
 }
 
@@ -8097,6 +8107,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 	err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
 				     local_state_change);
 	wdev_unlock(dev->ieee80211_ptr);
+
+	if (!err)
+		dev->ieee80211_ptr->conn_owner_nlportid = 0;
+
 	return err;
 }
 
@@ -8723,6 +8737,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 	wdev_unlock(dev->ieee80211_ptr);
 	if (err)
 		kzfree(connkeys);
+
+	if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER])
+		dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
+
 	return err;
 }
 
@@ -14425,13 +14443,21 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 				spin_unlock(&rdev->destroy_list_lock);
 				schedule_work(&rdev->destroy_work);
 			}
-		} else if (schedule_scan_stop) {
+
+			continue;
+		}
+
+		if (schedule_scan_stop) {
 			sched_scan_req->owner_nlportid = 0;
 
 			if (rdev->ops->sched_scan_stop &&
 			    rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
 				schedule_work(&rdev->sched_scan_stop_wk);
 		}
+
+		list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list)
+			if (wdev->conn_owner_nlportid == notify->portid)
+				schedule_work(&wdev->disconnect_wk);
 	}
 
 	rcu_read_unlock();
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index a77db33..f5cc067 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -713,6 +713,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 		kzfree(wdev->connect_keys);
 		wdev->connect_keys = NULL;
 		wdev->ssid_len = 0;
+		wdev->conn_owner_nlportid = 0;
 		if (bss) {
 			cfg80211_unhold_bss(bss_from_pub(bss));
 			cfg80211_put_bss(wdev->wiphy, bss);
@@ -941,6 +942,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 
 	wdev->current_bss = NULL;
 	wdev->ssid_len = 0;
+	wdev->conn_owner_nlportid = 0;
 
 	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 
@@ -1084,6 +1086,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 	kzfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
+	wdev->conn_owner_nlportid = 0;
+
 	if (wdev->conn)
 		err = cfg80211_sme_disconnect(wdev, reason);
 	else if (!rdev->ops->disconnect)
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH] cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT
From: Andrew Zaborowski @ 2016-12-12 10:01 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: linux-wireless
In-Reply-To: <8E332BC1-F05E-4771-ABA4-BD6C59449125@holtmann.org>

On 12 December 2016 at 08:21, Marcel Holtmann <marcel@holtmann.org> wrote:
>> Disconnect or deauthenticate when the owning socket is closed if this
>> flag is supplied to CMD_CONNECT or CMD_AUTHENTICATE.  This may be used
>> to ensure userspace daemon doesn't leave an unmanaged connection behind.
>
> I think you have a typo here. The CMD_AUTHENTICATE should be CMD_ASSOCIATE?

Good point, let me change this and resend.

Best regards

^ permalink raw reply

* Re: Could we have request_firmware_nowait with FW_OPT_NO_WARN?
From: Rafał Miłecki @ 2016-12-12  9:53 UTC (permalink / raw)
  To: Arend Van Spriel
  Cc: Johannes Berg, Ming Lei, Luis R. Rodriguez,
	Linux Kernel Mailing List, linux-wireless@vger.kernel.org,
	brcm80211 development
In-Reply-To: <815a15b6-f22d-8c45-f76c-2c756f159366@broadcom.com>

On 12 December 2016 at 10:26, Arend Van Spriel
<arend.vanspriel@broadcom.com> wrote:
> On 12-12-2016 9:32, Rafa=C5=82 Mi=C5=82ecki wrote:
>> On 12 December 2016 at 09:12, Johannes Berg <johannes@sipsolutions.net> =
wrote:
>>> On Sat, 2016-12-10 at 16:54 +0100, Rafa=C5=82 Mi=C5=82ecki wrote:
>>>> In brcmfmac we use request_firmware_nowait and if fetching firmware
>>>> with NVRAM variables fails then we try to fallback to the platform
>>>> one (see brcmf_fw_request_code_done & brcmf_fw_request_nvram_done).
>>>>
>>>> Some problem for us is that on devices with platform NVRAM we get
>>>> this error:
>>>> Direct firmware load for brcm/brcmfmac43602-pcie.txt failed with error=
 -2
>>>
>>> This also happens with iwlwifi, because it requests multiple firmware
>>> versions starting at the most recent supported one (which is often not
>>> released at the same time).
>>
>> Good to know it may help others as well!
>>
>>
>>> So yeah, this would be really useful - why don't you just make a patch
>>> with some kind of flags, whether it's FW_OPT_* or new flags?
>>
>> OK! If noone will come with any special comments/ideas soon, I'll
>> propose a patch for using some flags.
>>
>> FWIW, meanwhile I submitted
>> [PATCH V2] firmware: simplify defining and handling FW_OPT_FALLBACK
>> https://patchwork.kernel.org/patch/9469875/
>
> Similar thread couple of months ago [1]
>
> (...)
>
> [1] http://lists.infradead.org/pipermail/ath10k/2016-July/thread.html#802=
6

Oh, now I see it's a bit messy topic and not clearly maintained class.
It seems more ppl were confused by the API. I think having many
unrelated behavior bounded to few functions caused some of this
confusion. Let's hope adding some flags will let us use function the
way they were designed, I'll definitely try working on this.

--=20
Rafa=C5=82

^ permalink raw reply

* Re: Could we have request_firmware_nowait with FW_OPT_NO_WARN?
From: Arend Van Spriel @ 2016-12-12  9:26 UTC (permalink / raw)
  To: Rafał Miłecki, Johannes Berg
  Cc: Ming Lei, Luis R. Rodriguez, Linux Kernel Mailing List,
	linux-wireless@vger.kernel.org, brcm80211 development
In-Reply-To: <CACna6rzZnO1YtS2=6S1PGCTJkzTeuz9oJ+1yHBgWNhvUPz4acg@mail.gmail.com>

On 12-12-2016 9:32, Rafał Miłecki wrote:
> On 12 December 2016 at 09:12, Johannes Berg <johannes@sipsolutions.net> wrote:
>> On Sat, 2016-12-10 at 16:54 +0100, Rafał Miłecki wrote:
>>> In brcmfmac we use request_firmware_nowait and if fetching firmware
>>> with NVRAM variables fails then we try to fallback to the platform
>>> one (see brcmf_fw_request_code_done & brcmf_fw_request_nvram_done).
>>>
>>> Some problem for us is that on devices with platform NVRAM we get
>>> this error:
>>> Direct firmware load for brcm/brcmfmac43602-pcie.txt failed with error -2
>>
>> This also happens with iwlwifi, because it requests multiple firmware
>> versions starting at the most recent supported one (which is often not
>> released at the same time).
> 
> Good to know it may help others as well!
> 
> 
>> So yeah, this would be really useful - why don't you just make a patch
>> with some kind of flags, whether it's FW_OPT_* or new flags?
> 
> OK! If noone will come with any special comments/ideas soon, I'll
> propose a patch for using some flags.
> 
> FWIW, meanwhile I submitted
> [PATCH V2] firmware: simplify defining and handling FW_OPT_FALLBACK
> https://patchwork.kernel.org/patch/9469875/

Similar thread couple of months ago [1]

Regards,
Arend

[1] http://lists.infradead.org/pipermail/ath10k/2016-July/thread.html#8026

^ permalink raw reply

* Re: Could we have request_firmware_nowait with FW_OPT_NO_WARN?
From: Rafał Miłecki @ 2016-12-12  8:32 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Ming Lei, Luis R. Rodriguez, Linux Kernel Mailing List,
	linux-wireless@vger.kernel.org, brcm80211 development
In-Reply-To: <1481530339.4067.1.camel@sipsolutions.net>

On 12 December 2016 at 09:12, Johannes Berg <johannes@sipsolutions.net> wro=
te:
> On Sat, 2016-12-10 at 16:54 +0100, Rafa=C5=82 Mi=C5=82ecki wrote:
>> In brcmfmac we use request_firmware_nowait and if fetching firmware
>> with NVRAM variables fails then we try to fallback to the platform
>> one (see brcmf_fw_request_code_done & brcmf_fw_request_nvram_done).
>>
>> Some problem for us is that on devices with platform NVRAM we get
>> this error:
>> Direct firmware load for brcm/brcmfmac43602-pcie.txt failed with error -=
2
>
> This also happens with iwlwifi, because it requests multiple firmware
> versions starting at the most recent supported one (which is often not
> released at the same time).

Good to know it may help others as well!


> So yeah, this would be really useful - why don't you just make a patch
> with some kind of flags, whether it's FW_OPT_* or new flags?

OK! If noone will come with any special comments/ideas soon, I'll
propose a patch for using some flags.

FWIW, meanwhile I submitted
[PATCH V2] firmware: simplify defining and handling FW_OPT_FALLBACK
https://patchwork.kernel.org/patch/9469875/

--=20
Rafa=C5=82

^ permalink raw reply

* Re: Could we have request_firmware_nowait with FW_OPT_NO_WARN?
From: Johannes Berg @ 2016-12-12  8:12 UTC (permalink / raw)
  To: Rafał Miłecki, Ming Lei, Luis R. Rodriguez,
	Linux Kernel Mailing List
  Cc: linux-wireless@vger.kernel.org, brcm80211 development
In-Reply-To: <CACna6rxOGo0e9U7eXpUgnnBuxL+x1B0JBf9ZBq2WPbaBE=YZ-g@mail.gmail.com>

On Sat, 2016-12-10 at 16:54 +0100, Rafał Miłecki wrote:
> Hi,
> 
> In brcmfmac we use request_firmware_nowait and if fetching firmware
> with NVRAM variables fails then we try to fallback to the platform
> one (see brcmf_fw_request_code_done & brcmf_fw_request_nvram_done).
> 
> Some problem for us is that on devices with platform NVRAM we get
> this error:
> Direct firmware load for brcm/brcmfmac43602-pcie.txt failed with error -2

This also happens with iwlwifi, because it requests multiple firmware
versions starting at the most recent supported one (which is often not
released at the same time).

So yeah, this would be really useful - why don't you just make a patch
with some kind of flags, whether it's FW_OPT_* or new flags?

johannes

^ permalink raw reply

* Re: [PATCH] cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT
From: Marcel Holtmann @ 2016-12-12  7:21 UTC (permalink / raw)
  To: Andrew Zaborowski; +Cc: linux-wireless
In-Reply-To: <20161212002911.5541-1-andrew.zaborowski@intel.com>

Hi Andrew,

> Disconnect or deauthenticate when the owning socket is closed if this
> flag is supplied to CMD_CONNECT or CMD_AUTHENTICATE.  This may be used
> to ensure userspace daemon doesn't leave an unmanaged connection behind.

I think you have a typo here. The CMD_AUTHENTICATE should be CMD_ASSOCIATE?

Regards

Marcel

^ permalink raw reply

* [PATCH v2 4/4] mac80211: Add set_cqm_rssi_range_config
From: Andrew Zaborowski @ 2016-12-12  1:52 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20161212015213.21323-2-andrew.zaborowski@intel.com>

Support .set_cqm_rssi_range_config if the beacons are available for
processing in mac80211.  There's no reason that this couldn't be
offloaded by mac80211-based drivers but there's no driver method for
that added in this patch as I don't have the hardware.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 include/net/mac80211.h |  6 ++++++
 net/mac80211/cfg.c     | 28 ++++++++++++++++++++++++++++
 net/mac80211/mlme.c    | 24 ++++++++++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 33026e1..671e498 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -502,6 +502,10 @@ struct ieee80211_mu_group_data {
  *	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.
+ * @cqm_rssi_low: Connection quality monitor RSSI lower threshold, a zero value
+ *	implies disabled.  This is an alternative mechanism to the single
+ *	threshold event and can't be enabled simultaneously.
+ * @cqm_rssi_high: Connection quality monitor RSSI upper threshold.
  * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis
  * @arp_addr_list: List of IPv4 addresses for hardware ARP filtering. The
  *	may filter ARP queries targeted for other addresses than listed here.
@@ -554,6 +558,8 @@ struct ieee80211_bss_conf {
 	u16 ht_operation_mode;
 	s32 cqm_rssi_thold;
 	u32 cqm_rssi_hyst;
+	s32 cqm_rssi_low;
+	s32 cqm_rssi_high;
 	struct cfg80211_chan_def chandef;
 	struct ieee80211_mu_group_data mu_group;
 	__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index fd6541f..6ac0523 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2647,6 +2647,33 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy,
 
 	bss_conf->cqm_rssi_thold = rssi_thold;
 	bss_conf->cqm_rssi_hyst = rssi_hyst;
+	bss_conf->cqm_rssi_low = 0;
+	bss_conf->cqm_rssi_high = 0;
+	sdata->u.mgd.last_cqm_event_signal = 0;
+
+	/* tell the driver upon association, unless already associated */
+	if (sdata->u.mgd.associated &&
+	    sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)
+		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_CQM);
+
+	return 0;
+}
+
+static int ieee80211_set_cqm_rssi_range_config(struct wiphy *wiphy,
+					       struct net_device *dev,
+					       s32 rssi_low, s32 rssi_high)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_vif *vif = &sdata->vif;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+	if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER)
+		return -EOPNOTSUPP;
+
+	bss_conf->cqm_rssi_low = rssi_low;
+	bss_conf->cqm_rssi_high = rssi_high;
+	bss_conf->cqm_rssi_thold = 0;
+	bss_conf->cqm_rssi_hyst = 0;
 	sdata->u.mgd.last_cqm_event_signal = 0;
 
 	/* tell the driver upon association, unless already associated */
@@ -3645,6 +3672,7 @@ const struct cfg80211_ops mac80211_config_ops = {
 	.mgmt_tx = ieee80211_mgmt_tx,
 	.mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
 	.set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
+	.set_cqm_rssi_range_config = ieee80211_set_cqm_rssi_range_config,
 	.mgmt_frame_register = ieee80211_mgmt_frame_register,
 	.set_antenna = ieee80211_set_antenna,
 	.get_antenna = ieee80211_get_antenna,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6898ecb..7f99918 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3416,6 +3416,30 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 		}
 	}
 
+	if (bss_conf->cqm_rssi_low &&
+	    ifmgd->count_beacon_signal >= IEEE80211_SIGNAL_AVE_MIN_COUNT) {
+		int sig = -ewma_beacon_signal_read(&ifmgd->ave_beacon_signal);
+		int last_event = ifmgd->last_cqm_event_signal;
+		int low = bss_conf->cqm_rssi_low;
+		int high = bss_conf->cqm_rssi_high;
+
+		if (sig < low &&
+		    (last_event == 0 || last_event >= low)) {
+			ifmgd->last_cqm_event_signal = sig;
+			ieee80211_cqm_rssi_notify(
+				&sdata->vif,
+				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+				sig, GFP_KERNEL);
+		} else if (sig > high &&
+			   (last_event == 0 || last_event <= high)) {
+			ifmgd->last_cqm_event_signal = sig;
+			ieee80211_cqm_rssi_notify(
+				&sdata->vif,
+				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+				sig, GFP_KERNEL);
+		}
+	}
+
 	if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
 		mlme_dbg_ratelimited(sdata,
 				     "cancelling AP probe due to a received beacon\n");
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2 3/4] cfg80211: Accept multiple RSSI thresholds for CQM
From: Andrew Zaborowski @ 2016-12-12  1:52 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20161212015213.21323-2-andrew.zaborowski@intel.com>

Change the SET CQM command's RSSI threshold attribute to accept any
number of thresholds as a sorted array.  The API should be backwards
compatible so that if one s32 threshold value is passed, the old
mechanism is enabled.  The netlink event generated is the same in both
cases.

cfg80211 handles an arbitrary number of RSSI thresholds but drivers have
to provide a method (set_cqm_rssi_range_config) that configures a range
set by a high and a low value.  Drivers have to call back when the RSSI
goes out of that range and there's no additional event every time the
range is reconfigured as there was with the current API.

This method doesn't have a hysteresis parameter because there's no
benefit to the cfg80211 code from having the hysteresis be handled by
hardware/driver in terms of the number of wakeups.  At the same time
it would likely be less consistent between drivers if offloaded or
done in the drivers.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 include/net/cfg80211.h       |  12 ++++
 include/uapi/linux/nl80211.h |   4 +-
 net/wireless/core.c          |   9 +++
 net/wireless/core.h          |   9 +++
 net/wireless/nl80211.c       | 136 +++++++++++++++++++++++++++++++++++++++----
 net/wireless/rdev-ops.h      |  12 ++++
 net/wireless/trace.h         |  22 +++++++
 7 files changed, 192 insertions(+), 12 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 9700a11..d0a242a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2604,6 +2604,10 @@ struct cfg80211_nan_func {
  *	the current level is above/below the configured threshold; this may
  *	need some care when the configuration is changed (without first being
  *	disabled.)
+ * @set_cqm_rssi_range_config: Configure two RSSI thresholds in the
+ *	connection quality monitor.  An event is to be sent only when the
+ *	signal level is found to be outside the two values.  If this method
+ *	is provided then there's no point providing @set_cqm_rssi_config.
  * @set_cqm_txe_config: Configure connection quality monitor TX error
  *	thresholds.
  * @sched_scan_start: Tell the driver to start a scheduled scan.
@@ -2887,6 +2891,10 @@ struct cfg80211_ops {
 				       struct net_device *dev,
 				       s32 rssi_thold, u32 rssi_hyst);
 
+	int	(*set_cqm_rssi_range_config)(struct wiphy *wiphy,
+					     struct net_device *dev,
+					     s32 rssi_low, s32 rssi_high);
+
 	int	(*set_cqm_txe_config)(struct wiphy *wiphy,
 				      struct net_device *dev,
 				      u32 rate, u32 pkts, u32 intvl);
@@ -3709,6 +3717,7 @@ void wiphy_free(struct wiphy *wiphy);
 struct cfg80211_conn;
 struct cfg80211_internal_bss;
 struct cfg80211_cached_keys;
+struct cfg80211_cqm_config;
 
 /**
  * struct wireless_dev - wireless device state
@@ -3772,6 +3781,7 @@ struct cfg80211_cached_keys;
  * @event_list: (private) list for internal event processing
  * @event_lock: (private) lock for event list
  * @owner_nlportid: (private) owner socket port ID
+ * @cqm_config: (private) nl80211 RSSI monitor state
  */
 struct wireless_dev {
 	struct wiphy *wiphy;
@@ -3840,6 +3850,8 @@ struct wireless_dev {
 		bool prev_bssid_valid;
 	} wext;
 #endif
+
+	struct cfg80211_cqm_config *cqm_config;
 };
 
 static inline u8 *wdev_address(struct wireless_dev *wdev)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9043b77..e25e447 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3841,7 +3841,9 @@ enum nl80211_ps_state {
  * @__NL80211_ATTR_CQM_INVALID: invalid
  * @NL80211_ATTR_CQM_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.
+ *	to disable.  Alternatively multiple values can be supplied as a
+ *	low-to-high sorted array of thresholds in dBm.  Events will be sent
+ *	when the RSSI value crosses any of the thresholds.
  * @NL80211_ATTR_CQM_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).
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 6b8fd68..ed3efe0 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -958,6 +958,12 @@ 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)
+{
+	kfree(wdev->cqm_config);
+	wdev->cqm_config = NULL;
+}
+
 void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
@@ -984,6 +990,8 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
 		WARN_ON_ONCE(1);
 		break;
 	}
+
+	cfg80211_cqm_config_free(wdev);
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
 
@@ -1238,6 +1246,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);
 		}
 		/*
 		 * synchronise (so that we won't find this netdev
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 08d2e94..b9498a2 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -270,6 +270,13 @@ struct cfg80211_iface_destroy {
 	u32 nlportid;
 };
 
+struct cfg80211_cqm_config {
+	u32 rssi_hyst;
+	s32 last_rssi_event_value;
+	int n_rssi_thresholds;
+	s32 rssi_thresholds[0];
+};
+
 void cfg80211_destroy_ifaces(struct cfg80211_registered_device *rdev);
 
 /* free object */
@@ -504,4 +511,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);
+
 #endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 2ab3a56..831c8fb 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9290,7 +9290,7 @@ static int nl80211_get_power_save(struct sk_buff *skb, struct genl_info *info)
 
 static const struct nla_policy
 nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
-	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_BINARY },
 	[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
@@ -9319,28 +9319,126 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
 	return rdev_set_cqm_txe_config(rdev, dev, rate, pkts, intvl);
 }
 
+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;
+
+	/* RSSI reporting disabled? */
+	if (!wdev->cqm_config)
+		return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
+
+	/*
+	 * Obtain current RSSI value if possible, if not and no RSSI threshold
+	 * event has been received yet, we should receive an event after a
+	 * connection is established and enough beacons received to calculate
+	 * the average.
+	 */
+	if (!wdev->cqm_config->last_rssi_event_value && wdev->current_bss) {
+		struct station_info sinfo;
+		u8 *mac_addr;
+
+		mac_addr = wdev->current_bss->pub.bssid;
+
+		err = rdev_get_station(rdev, dev, mac_addr, &sinfo);
+		if (err)
+			return err;
+
+		if (sinfo.filled & BIT(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
+			wdev->cqm_config->last_rssi_event_value =
+				(s8) sinfo.rx_beacon_signal_avg;
+	}
+
+	last = wdev->cqm_config->last_rssi_event_value;
+	hyst = wdev->cqm_config->rssi_hyst;
+	n = wdev->cqm_config->n_rssi_thresholds;
+
+	for (i = 0; i < n; i++)
+		if (last < wdev->cqm_config->rssi_thresholds[i])
+			break;
+
+	low = i > 0 ? wdev->cqm_config->rssi_thresholds[i - 1] : S32_MIN;
+	high = i < n ? wdev->cqm_config->rssi_thresholds[i] : S32_MAX;
+
+	if (low > (s32) (last - hyst))
+		low = last - hyst;
+	if (high < (s32) (last + hyst))
+		high = last + hyst;
+
+	return rdev_set_cqm_rssi_range_config(rdev, dev, low, high - 1);
+}
+
 static int nl80211_set_cqm_rssi(struct genl_info *info,
-				s32 threshold, u32 hysteresis)
+				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 i, err;
+	s32 prev = S32_MIN;
 
-	if (threshold > 0)
-		return -EINVAL;
+	/* 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];
+	}
+
+	if (n_thresholds == 1 && thresholds[0] == 0)
+		n_thresholds = 0;
 
 	/* disabling - hysteresis should also be zero then */
-	if (threshold == 0)
+	if (n_thresholds == 0)
 		hysteresis = 0;
 
-	if (!rdev->ops->set_cqm_rssi_config)
-		return -EOPNOTSUPP;
-
 	if (wdev->iftype != NL80211_IFTYPE_STATION &&
 	    wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
 		return -EOPNOTSUPP;
 
-	return rdev_set_cqm_rssi_config(rdev, dev, threshold, hysteresis);
+	wdev_lock(wdev);
+	cfg80211_cqm_config_free(wdev);
+	wdev_unlock(wdev);
+
+	if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
+		const s32 disable = 0;
+
+		if (n_thresholds == 0) {
+			n_thresholds = 1;
+			thresholds = &disable;
+		}
+
+		return rdev_set_cqm_rssi_config(rdev, dev,
+						thresholds[0], hysteresis);
+	}
+
+	if (!rdev->ops->set_cqm_rssi_range_config || !rdev->ops->get_station)
+		return -EOPNOTSUPP;
+
+	wdev_lock(wdev);
+	if (n_thresholds) {
+		struct cfg80211_cqm_config *cqm_config;
+
+		cqm_config = kzalloc(sizeof(struct cfg80211_cqm_config) +
+				     n_thresholds * sizeof(s32), GFP_KERNEL);
+		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;
+	}
+
+	err = cfg80211_cqm_rssi_update(rdev, dev);
+
+	wdev_unlock(wdev);
+
+	return err;
 }
 
 static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
@@ -9360,10 +9458,15 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info)
 
 	if (attrs[NL80211_ATTR_CQM_RSSI_THOLD] &&
 	    attrs[NL80211_ATTR_CQM_RSSI_HYST]) {
-		s32 threshold = nla_get_s32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+		s32 *thresholds = nla_data(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
+		int len = nla_len(attrs[NL80211_ATTR_CQM_RSSI_THOLD]);
 		u32 hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]);
 
-		return nl80211_set_cqm_rssi(info, threshold, hysteresis);
+		if (len % 4)
+			return -EINVAL;
+
+		return nl80211_set_cqm_rssi(info, thresholds, len / 4,
+					    hysteresis);
 	}
 
 	if (attrs[NL80211_ATTR_CQM_TXE_RATE] &&
@@ -13759,6 +13862,8 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      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);
 
 	trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
 
@@ -13766,6 +13871,15 @@ 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;
+
+		cfg80211_cqm_rssi_update(rdev, dev);
+
+		if (rssi_level == 0)
+			rssi_level = wdev->cqm_config->last_rssi_event_value;
+	}
+
 	msg = cfg80211_prepare_cqm(dev, NULL, gfp);
 	if (!msg)
 		return;
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 11cf83c..ae180f3 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -726,6 +726,18 @@ rdev_set_cqm_rssi_config(struct cfg80211_registered_device *rdev,
 }
 
 static inline int
+rdev_set_cqm_rssi_range_config(struct cfg80211_registered_device *rdev,
+			       struct net_device *dev, s32 low, s32 high)
+{
+	int ret;
+	trace_rdev_set_cqm_rssi_range_config(&rdev->wiphy, dev, low, high);
+	ret = rdev->ops->set_cqm_rssi_range_config(&rdev->wiphy, dev,
+						   low, high);
+	trace_rdev_return_int(&rdev->wiphy, ret);
+	return ret;
+}
+
+static inline int
 rdev_set_cqm_txe_config(struct cfg80211_registered_device *rdev,
 			struct net_device *dev, u32 rate, u32 pkts, u32 intvl)
 {
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index 6ac46a0..993f661 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -1304,6 +1304,28 @@ TRACE_EVENT(rdev_set_cqm_rssi_config,
 		 __entry->rssi_thold, __entry->rssi_hyst)
 );
 
+TRACE_EVENT(rdev_set_cqm_rssi_range_config,
+	TP_PROTO(struct wiphy *wiphy,
+		 struct net_device *netdev, s32 low, s32 high),
+	TP_ARGS(wiphy, netdev, low, high),
+	TP_STRUCT__entry(
+		WIPHY_ENTRY
+		NETDEV_ENTRY
+		__field(s32, rssi_low)
+		__field(s32, rssi_high)
+	),
+	TP_fast_assign(
+		WIPHY_ASSIGN;
+		NETDEV_ASSIGN;
+		__entry->rssi_low = low;
+		__entry->rssi_high = high;
+	),
+	TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT
+		  ", range: %d - %d ",
+		  WIPHY_PR_ARG, NETDEV_PR_ARG,
+		  __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),
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2 2/4] cfg80211: Pass new RSSI level in CQM RSSI notification
From: Andrew Zaborowski @ 2016-12-12  1:52 UTC (permalink / raw)
  To: linux-wireless

Update the drivers to pass the RSSI level as a cfg80211_cqm_rssi_notify
parameter and pass this value to userspace in a new nl80211 attribute.
This helps both userspace and also helps in the implementation of the
multiple RSSI thresholds CQM mechanism.

Note for marvell/mwifiex I pass 0 for the RSSI value because the new
RSSI value is not available to the driver at the time of the
cfg80211_cqm_rssi_notify call, but the driver queries the new value
immediately after that, so it is actually available just a moment later
if we wanted to defer caling cfg80211_cqm_rssi_notify until that moment.
Without this, the new cfg80211 code (patch 3) will call .get_station
which will send a duplicate HostCmd_CMD_RSSI_INFO command to the hardware.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 drivers/net/wireless/marvell/mwifiex/sta_event.c |  4 ++--
 drivers/net/wireless/rndis_wlan.c                |  2 +-
 include/net/cfg80211.h                           |  3 ++-
 include/uapi/linux/nl80211.h                     |  3 +++
 net/mac80211/mlme.c                              |  2 +-
 net/wireless/nl80211.c                           |  9 +++++++--
 net/wireless/trace.h                             | 11 +++++++----
 7 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c
index 9df0c4d..5cc3aa7 100644
--- a/drivers/net/wireless/marvell/mwifiex/sta_event.c
+++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c
@@ -824,7 +824,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 	case EVENT_RSSI_LOW:
 		cfg80211_cqm_rssi_notify(priv->netdev,
 					 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-					 GFP_KERNEL);
+					 0, GFP_KERNEL);
 		mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
 				 HostCmd_ACT_GEN_GET, 0, NULL, false);
 		priv->subsc_evt_rssi_state = RSSI_LOW_RECVD;
@@ -839,7 +839,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 	case EVENT_RSSI_HIGH:
 		cfg80211_cqm_rssi_notify(priv->netdev,
 					 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-					 GFP_KERNEL);
+					 0, GFP_KERNEL);
 		mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
 				 HostCmd_ACT_GEN_GET, 0, NULL, false);
 		priv->subsc_evt_rssi_state = RSSI_HIGH_RECVD;
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 603c904..785334f 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -3187,7 +3187,7 @@ static void rndis_do_cqm(struct usbnet *usbdev, s32 rssi)
 		return;
 
 	priv->last_cqm_event_rssi = rssi;
-	cfg80211_cqm_rssi_notify(usbdev->net, event, GFP_KERNEL);
+	cfg80211_cqm_rssi_notify(usbdev->net, event, rssi, GFP_KERNEL);
 }
 
 #define DEVICE_POLLER_JIFFIES (HZ)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ca2e252..9700a11 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5174,6 +5174,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
  * cfg80211_cqm_rssi_notify - connection quality monitoring rssi event
  * @dev: network device
  * @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 connection quality monitoring
@@ -5181,7 +5182,7 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
  */
 void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      enum nl80211_cqm_rssi_threshold_event rssi_event,
-			      gfp_t gfp);
+			      s32 rssi_level, gfp_t gfp);
 
 /**
  * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 84db1f0..9043b77 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -3861,6 +3861,8 @@ enum nl80211_ps_state {
  *	%NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
  * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
  *	loss event
+ * @NL80211_ATTR_CQM_RSSI_LEVEL: the RSSI value in dBm that triggered the
+ *	RSSI threshold event.
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -3874,6 +3876,7 @@ enum nl80211_attr_cqm {
 	NL80211_ATTR_CQM_TXE_PKTS,
 	NL80211_ATTR_CQM_TXE_INTVL,
 	NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
+	NL80211_ATTR_CQM_RSSI_LEVEL,
 
 	/* keep last */
 	__NL80211_ATTR_CQM_AFTER_LAST,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a55cdd7..6898ecb 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5007,7 +5007,7 @@ void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 
 	trace_api_cqm_rssi_notify(sdata, rssi_event, rssi_level);
 
-	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
+	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, rssi_level, gfp);
 }
 EXPORT_SYMBOL(ieee80211_cqm_rssi_notify);
 
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 502ae92..2ab3a56 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9296,6 +9296,7 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
 	[NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 },
 	[NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 },
+	[NL80211_ATTR_CQM_RSSI_LEVEL] = { .type = NLA_S32 },
 };
 
 static int nl80211_set_cqm_txe(struct genl_info *info,
@@ -13755,11 +13756,11 @@ static void cfg80211_send_cqm(struct sk_buff *msg, gfp_t gfp)
 
 void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			      enum nl80211_cqm_rssi_threshold_event rssi_event,
-			      gfp_t gfp)
+			      s32 rssi_level, gfp_t gfp)
 {
 	struct sk_buff *msg;
 
-	trace_cfg80211_cqm_rssi_notify(dev, rssi_event);
+	trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
 
 	if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
 		    rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
@@ -13773,6 +13774,10 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
 			rssi_event))
 		goto nla_put_failure;
 
+	if (rssi_level && nla_put_s32(msg, NL80211_ATTR_CQM_RSSI_LEVEL,
+				      rssi_level))
+		goto nla_put_failure;
+
 	cfg80211_send_cqm(msg, gfp);
 
 	return;
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index a3d0a91..6ac46a0 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2472,18 +2472,21 @@ TRACE_EVENT(cfg80211_mgmt_tx_status,
 
 TRACE_EVENT(cfg80211_cqm_rssi_notify,
 	TP_PROTO(struct net_device *netdev,
-		 enum nl80211_cqm_rssi_threshold_event rssi_event),
-	TP_ARGS(netdev, rssi_event),
+		 enum nl80211_cqm_rssi_threshold_event rssi_event,
+		 s32 rssi_level),
+	TP_ARGS(netdev, rssi_event, rssi_level),
 	TP_STRUCT__entry(
 		NETDEV_ENTRY
 		__field(enum nl80211_cqm_rssi_threshold_event, rssi_event)
+		__field(s32, rssi_level)
 	),
 	TP_fast_assign(
 		NETDEV_ASSIGN;
 		__entry->rssi_event = rssi_event;
+		__entry->rssi_level = rssi_level;
 	),
-	TP_printk(NETDEV_PR_FMT ", rssi event: %d",
-		  NETDEV_PR_ARG, __entry->rssi_event)
+	TP_printk(NETDEV_PR_FMT ", rssi event: %d, level: %d",
+		  NETDEV_PR_ARG, __entry->rssi_event, __entry->rssi_level)
 );
 
 TRACE_EVENT(cfg80211_reg_can_beacon,
-- 
2.9.3

^ permalink raw reply related

* [PATCH v2 1/4] mac80211: Pass new RSSI level in CQM RSSI notification
From: Andrew Zaborowski @ 2016-12-12  1:51 UTC (permalink / raw)
  To: linux-wireless

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mvm/rx.c |  2 ++
 drivers/net/wireless/rsi/rsi_91x_mac80211.c |  2 +-
 drivers/net/wireless/st/cw1200/sta.c        |  2 +-
 drivers/net/wireless/ti/wl1251/event.c      |  4 ++--
 drivers/net/wireless/ti/wlcore/event.c      |  3 ++-
 include/net/mac80211.h                      |  2 ++
 net/mac80211/mlme.c                         |  7 ++++---
 net/mac80211/trace.h                        | 11 +++++++----
 8 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
index 0e60e38..e06a2e3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c
@@ -571,6 +571,7 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
 		ieee80211_cqm_rssi_notify(
 			vif,
 			NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+			sig,
 			GFP_KERNEL);
 	} else if (sig > thold &&
 		   (last_event == 0 || sig > last_event + hyst)) {
@@ -580,6 +581,7 @@ static void iwl_mvm_stat_iterator(void *_data, u8 *mac,
 		ieee80211_cqm_rssi_notify(
 			vif,
 			NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+			sig,
 			GFP_KERNEL);
 	}
 }
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index dbb2389..3e260b4 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -818,7 +818,7 @@ static void rsi_perform_cqm(struct rsi_common *common,
 
 	common->cqm_info.last_cqm_event_rssi = rssi;
 	rsi_dbg(INFO_ZONE, "CQM: Notifying event: %d\n", event);
-	ieee80211_cqm_rssi_notify(adapter->vifs[0], event, GFP_KERNEL);
+	ieee80211_cqm_rssi_notify(adapter->vifs[0], event, rssi, GFP_KERNEL);
 
 	return;
 }
diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c
index daf06a4..a522248 100644
--- a/drivers/net/wireless/st/cw1200/sta.c
+++ b/drivers/net/wireless/st/cw1200/sta.c
@@ -1019,7 +1019,7 @@ void cw1200_event_handler(struct work_struct *work)
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW :
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH;
 			pr_debug("[CQM] RSSI event: %d.\n", rcpi_rssi);
-			ieee80211_cqm_rssi_notify(priv->vif, cqm_evt,
+			ieee80211_cqm_rssi_notify(priv->vif, cqm_evt, rcpi_rssi,
 						  GFP_KERNEL);
 			break;
 		}
diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c
index d0593bc..f5acd24 100644
--- a/drivers/net/wireless/ti/wl1251/event.c
+++ b/drivers/net/wireless/ti/wl1251/event.c
@@ -150,7 +150,7 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
 				     "ROAMING_TRIGGER_LOW_RSSI_EVENT");
 			ieee80211_cqm_rssi_notify(wl->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-				GFP_KERNEL);
+				0, GFP_KERNEL);
 		}
 
 		if (vector & ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID) {
@@ -158,7 +158,7 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
 				     "ROAMING_TRIGGER_REGAINED_RSSI_EVENT");
 			ieee80211_cqm_rssi_notify(wl->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-				GFP_KERNEL);
+				0, GFP_KERNEL);
 		}
 	}
 
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 4b59f67..f2e90d2 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -129,7 +129,8 @@ void wlcore_event_rssi_trigger(struct wl1271 *wl, s8 *metric_arr)
 
 		vif = wl12xx_wlvif_to_vif(wlvif);
 		if (event != wlvif->last_rssi_event)
-			ieee80211_cqm_rssi_notify(vif, event, GFP_KERNEL);
+			ieee80211_cqm_rssi_notify(vif, event, metric,
+						  GFP_KERNEL);
 		wlvif->last_rssi_event = event;
 	}
 }
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a810dfc..33026e1 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -5244,6 +5244,7 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
  *
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @rssi_event: the RSSI trigger event type
+ * @rssi_level: new RSSI level value or 0 if not available
  * @gfp: context flags
  *
  * When the %IEEE80211_VIF_SUPPORTS_CQM_RSSI is set, and a connection quality
@@ -5252,6 +5253,7 @@ void ieee80211_resume_disconnect(struct ieee80211_vif *vif);
  */
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       enum nl80211_cqm_rssi_threshold_event rssi_event,
+			       s32 rssi_level,
 			       gfp_t gfp);
 
 /**
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 7486f2d..a55cdd7 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3405,14 +3405,14 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 			ieee80211_cqm_rssi_notify(
 				&sdata->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
-				GFP_KERNEL);
+				sig, GFP_KERNEL);
 		} else if (sig > thold &&
 			   (last_event == 0 || sig > last_event + hyst)) {
 			ifmgd->last_cqm_event_signal = sig;
 			ieee80211_cqm_rssi_notify(
 				&sdata->vif,
 				NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
-				GFP_KERNEL);
+				sig, GFP_KERNEL);
 		}
 	}
 
@@ -5000,11 +5000,12 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
 
 void ieee80211_cqm_rssi_notify(struct ieee80211_vif *vif,
 			       enum nl80211_cqm_rssi_threshold_event rssi_event,
+			       s32 rssi_level,
 			       gfp_t gfp)
 {
 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
-	trace_api_cqm_rssi_notify(sdata, rssi_event);
+	trace_api_cqm_rssi_notify(sdata, rssi_event, rssi_level);
 
 	cfg80211_cqm_rssi_notify(sdata->dev, rssi_event, gfp);
 }
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index 92a47af..f78d9f4 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -1996,23 +1996,26 @@ TRACE_EVENT(api_connection_loss,
 
 TRACE_EVENT(api_cqm_rssi_notify,
 	TP_PROTO(struct ieee80211_sub_if_data *sdata,
-		 enum nl80211_cqm_rssi_threshold_event rssi_event),
+		 enum nl80211_cqm_rssi_threshold_event rssi_event,
+		 s32 rssi_level),
 
-	TP_ARGS(sdata, rssi_event),
+	TP_ARGS(sdata, rssi_event, rssi_level),
 
 	TP_STRUCT__entry(
 		VIF_ENTRY
 		__field(u32, rssi_event)
+		__field(s32, rssi_level)
 	),
 
 	TP_fast_assign(
 		VIF_ASSIGN;
 		__entry->rssi_event = rssi_event;
+		__entry->rssi_level = rssi_level;
 	),
 
 	TP_printk(
-		VIF_PR_FMT " event:%d",
-		VIF_PR_ARG, __entry->rssi_event
+		VIF_PR_FMT " event:%d rssi:%d",
+		VIF_PR_ARG, __entry->rssi_event, __entry->rssi_level
 	)
 );
 
-- 
2.9.3

^ permalink raw reply related

* [PATCH] cfg80211: NL80211_ATTR_SOCKET_OWNER support for CMD_CONNECT
From: Andrew Zaborowski @ 2016-12-12  0:29 UTC (permalink / raw)
  To: linux-wireless

Disconnect or deauthenticate when the owning socket is closed if this
flag is supplied to CMD_CONNECT or CMD_AUTHENTICATE.  This may be used
to ensure userspace daemon doesn't leave an unmanaged connection behind.

In some situations it would be possible to account for that, to some
degree, in the deamon restart code, or in the up/down scripts without
the use of this attribute.  But there will be systems where the daemon
can go away for varying periods without a warning due to local resource
management.

Signed-off-by: Andrew Zaborowski <andrew.zaborowski@intel.com>
---
 include/net/cfg80211.h       |  7 +++++++
 include/uapi/linux/nl80211.h |  2 ++
 net/wireless/core.c          | 33 +++++++++++++++++++++++++++++++++
 net/wireless/mlme.c          |  2 ++
 net/wireless/nl80211.c       | 28 +++++++++++++++++++++++++++-
 net/wireless/sme.c           |  4 ++++
 6 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bd19faa..ca2e252 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3764,6 +3764,9 @@ struct cfg80211_cached_keys;
  * @conn: (private) cfg80211 software SME connection state machine data
  * @connect_keys: (private) keys to set after connection is established
  * @conn_bss_type: connecting/connected BSS type
+ * @conn_owner_nlportid: (private) connection owner socket port ID
+ * @disconnect_wk: (private) auto-disconnect work
+ * @disconnect_bssid: (private) the BSSID to use for auto-disconnect
  * @ibss_fixed: (private) IBSS is using fixed BSSID
  * @ibss_dfs_possible: (private) IBSS may change to a DFS channel
  * @event_list: (private) list for internal event processing
@@ -3795,6 +3798,10 @@ struct wireless_dev {
 	struct cfg80211_conn *conn;
 	struct cfg80211_cached_keys *connect_keys;
 	enum ieee80211_bss_type conn_bss_type;
+	u32 conn_owner_nlportid;
+
+	struct work_struct disconnect_wk;
+	u8 disconnect_bssid[ETH_ALEN];
 
 	struct list_head event_list;
 	spinlock_t event_lock;
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 56368e9..84db1f0 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1788,6 +1788,8 @@ enum nl80211_commands {
  *	and remove functions. NAN notifications will be sent in unicast to that
  *	socket. Without this attribute, any socket can add functions and the
  *	notifications will be sent to the %NL80211_MCGRP_NAN multicast group.
+ *	If set during %NL80211_CMD_ASSOCIATE or %NL80211_CMD_CONNECT the
+ *	station will deauthenticate when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 8201e6d..6b8fd68 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -357,6 +357,36 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
 	rtnl_unlock();
 }
 
+static void cfg80211_disconnect_wk(struct work_struct *work)
+{
+	struct cfg80211_registered_device *rdev;
+	struct wireless_dev *wdev;
+
+	wdev = container_of(work, struct wireless_dev, disconnect_wk);
+	rdev = wiphy_to_rdev(wdev->wiphy);
+
+	if (!wdev->netdev)
+		return;
+
+	wdev_lock(wdev);
+
+	if (wdev->conn_owner_nlportid) {
+		/*
+		 * Use disconnect_bssid if still connecting and ops->disconnect
+		 * not implemented.  Otherwise we can use cfg80211_disconnect.
+		 */
+		if (rdev->ops->disconnect || wdev->current_bss)
+			cfg80211_disconnect(rdev, wdev->netdev,
+					WLAN_REASON_DEAUTH_LEAVING, true);
+		else
+			cfg80211_mlme_deauth(rdev, wdev->netdev,
+					wdev->disconnect_bssid, NULL, 0,
+					WLAN_REASON_DEAUTH_LEAVING, false);
+	}
+
+	wdev_unlock(wdev);
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -1117,6 +1147,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 		     wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
 			dev->priv_flags |= IFF_DONT_BRIDGE;
 
+		INIT_WORK(&wdev->disconnect_wk, cfg80211_disconnect_wk);
+
 		nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE);
 		break;
 	case NETDEV_GOING_DOWN:
@@ -1205,6 +1237,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
 #ifdef CONFIG_CFG80211_WEXT
 			kzfree(wdev->wext.keys);
 #endif
+			flush_work(&wdev->disconnect_wk);
 		}
 		/*
 		 * synchronise (so that we won't find this netdev
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index cbb48e2..9923244 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -328,6 +328,8 @@ int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
 
 	ASSERT_WDEV_LOCK(wdev);
 
+	wdev->conn_owner_nlportid = 0;
+
 	if (local_state_change &&
 	    (!wdev->current_bss ||
 	     !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c510810..502ae92 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -8003,6 +8003,12 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
 		wdev_unlock(dev->ieee80211_ptr);
 	}
 
+	if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER]) {
+		dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
+
+		memcpy(dev->ieee80211_ptr->disconnect_bssid, bssid, ETH_ALEN);
+	}
+
 	return err;
 }
 
@@ -8050,6 +8056,10 @@ static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
 	err = cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason_code,
 				   local_state_change);
 	wdev_unlock(dev->ieee80211_ptr);
+
+	if (!err)
+		dev->ieee80211_ptr->conn_owner_nlportid = 0;
+
 	return err;
 }
 
@@ -8097,6 +8107,10 @@ static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
 	err = cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason_code,
 				     local_state_change);
 	wdev_unlock(dev->ieee80211_ptr);
+
+	if (!err)
+		dev->ieee80211_ptr->conn_owner_nlportid = 0;
+
 	return err;
 }
 
@@ -8723,6 +8737,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
 	wdev_unlock(dev->ieee80211_ptr);
 	if (err)
 		kzfree(connkeys);
+
+	if (!err && info->attrs[NL80211_ATTR_SOCKET_OWNER])
+		dev->ieee80211_ptr->conn_owner_nlportid = info->snd_portid;
+
 	return err;
 }
 
@@ -14425,13 +14443,21 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
 				spin_unlock(&rdev->destroy_list_lock);
 				schedule_work(&rdev->destroy_work);
 			}
-		} else if (schedule_scan_stop) {
+
+			continue;
+		}
+
+		if (schedule_scan_stop) {
 			sched_scan_req->owner_nlportid = 0;
 
 			if (rdev->ops->sched_scan_stop &&
 			    rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
 				schedule_work(&rdev->sched_scan_stop_wk);
 		}
+
+		list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list)
+			if (wdev->conn_owner_nlportid == notify->portid)
+				schedule_work(&wdev->disconnect_wk);
 	}
 
 	rcu_read_unlock();
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index a77db33..f5cc067 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -713,6 +713,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
 		kzfree(wdev->connect_keys);
 		wdev->connect_keys = NULL;
 		wdev->ssid_len = 0;
+		wdev->conn_owner_nlportid = 0;
 		if (bss) {
 			cfg80211_unhold_bss(bss_from_pub(bss));
 			cfg80211_put_bss(wdev->wiphy, bss);
@@ -941,6 +942,7 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
 
 	wdev->current_bss = NULL;
 	wdev->ssid_len = 0;
+	wdev->conn_owner_nlportid = 0;
 
 	nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 
@@ -1084,6 +1086,8 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
 	kzfree(wdev->connect_keys);
 	wdev->connect_keys = NULL;
 
+	wdev->conn_owner_nlportid = 0;
+
 	if (wdev->conn)
 		err = cfg80211_sme_disconnect(wdev, reason);
 	else if (!rdev->ops->disconnect)
-- 
2.9.3

^ permalink raw reply related

* Re: [PATCH 02/14] rtlwifi_new: Remove RT_TRACE messages that use DBG_EMERG
From: Larry Finger @ 2016-12-11 15:31 UTC (permalink / raw)
  To: Joe Perches, kvalo; +Cc: devel, linux-wireless, Ping-Ke Shih
In-Reply-To: <1481453445.1764.11.camel@perches.com>

On 12/11/2016 04:50 AM, Joe Perches wrote:
> On Sat, 2016-12-10 at 23:44 -0600, Larry Finger wrote:
>> These messages are always logged and reprresent error conditions, thus
>> we can use pr_err().
>>
>> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
>> Cc: Ping-Ke Shih <pkshih@realtek.com>
>> ---
>>  drivers/net/wireless/realtek/rtlwifi/base.c  | 15 ++++-----
>>  drivers/net/wireless/realtek/rtlwifi/cam.c   | 14 +++------
>>  drivers/net/wireless/realtek/rtlwifi/core.c  | 21 +++++--------
>>  drivers/net/wireless/realtek/rtlwifi/debug.c |  9 ++----
>>  drivers/net/wireless/realtek/rtlwifi/debug.h |  2 +-
>>  drivers/net/wireless/realtek/rtlwifi/efuse.c |  3 +-
>>  drivers/net/wireless/realtek/rtlwifi/pci.c   | 36 ++++++++--------------
>>  drivers/net/wireless/realtek/rtlwifi/ps.c    |  3 +-
>>  drivers/net/wireless/realtek/rtlwifi/rc.c    |  3 +-
>>  drivers/net/wireless/realtek/rtlwifi/usb.c   | 46 +++++++++-------------------
>>  10 files changed, 53 insertions(+), 99 deletions(-)
>>
>> diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
> []
>> @@ -207,8 +207,7 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
>>  	 *highest supported RX rate
>>  	 */
>>  	if (rtlpriv->dm.supp_phymode_switch) {
>> -		RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
>> -			 "Support phy mode switch\n");
>> +		pr_err("rtlwifi: Support phy mode switch\n");
>
> I believe most all of these are already prefixed
> by the wifi.h that has a #define pr_fmt

Yes, I missed that. V2 will not include the module name.

Larry

^ permalink raw reply

* Re: [PATCH 02/14] rtlwifi_new: Remove RT_TRACE messages that use DBG_EMERG
From: Joe Perches @ 2016-12-11 10:50 UTC (permalink / raw)
  To: Larry Finger, kvalo; +Cc: devel, linux-wireless, Ping-Ke Shih
In-Reply-To: <20161211054523.7119-3-Larry.Finger@lwfinger.net>

On Sat, 2016-12-10 at 23:44 -0600, Larry Finger wrote:
> These messages are always logged and reprresent error conditions, thus
> we can use pr_err().
> 
> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
> Cc: Ping-Ke Shih <pkshih@realtek.com>
> ---
>  drivers/net/wireless/realtek/rtlwifi/base.c  | 15 ++++-----
>  drivers/net/wireless/realtek/rtlwifi/cam.c   | 14 +++------
>  drivers/net/wireless/realtek/rtlwifi/core.c  | 21 +++++--------
>  drivers/net/wireless/realtek/rtlwifi/debug.c |  9 ++----
>  drivers/net/wireless/realtek/rtlwifi/debug.h |  2 +-
>  drivers/net/wireless/realtek/rtlwifi/efuse.c |  3 +-
>  drivers/net/wireless/realtek/rtlwifi/pci.c   | 36 ++++++++--------------
>  drivers/net/wireless/realtek/rtlwifi/ps.c    |  3 +-
>  drivers/net/wireless/realtek/rtlwifi/rc.c    |  3 +-
>  drivers/net/wireless/realtek/rtlwifi/usb.c   | 46 +++++++++-------------------
>  10 files changed, 53 insertions(+), 99 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c
[]
> @@ -207,8 +207,7 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
>  	 *highest supported RX rate
>  	 */
>  	if (rtlpriv->dm.supp_phymode_switch) {
> -		RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
> -			 "Support phy mode switch\n");
> +		pr_err("rtlwifi: Support phy mode switch\n");

I believe most all of these are already prefixed
by the wifi.h that has a #define pr_fmt 

^ permalink raw reply

* [PATCH 14/14] rtlwifi: Remove some redundant code
From: Larry Finger @ 2016-12-11  5:45 UTC (permalink / raw)
  To: kvalo; +Cc: devel, linux-wireless, Larry Finger, Ping-Ke Shih
In-Reply-To: <20161211054523.7119-1-Larry.Finger@lwfinger.net>

The symbol DBG_EMERG is no longer used and is removed.

In a number of places, the code has redundant messages. For example, if
the failure for the firmware to run is logged, it is not necessary to
log that the firmware has been started. In addition, extraneous braces are
removed.

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Ping-Ke Shih <pkshih@realtek.com>
---
 drivers/net/wireless/realtek/rtlwifi/debug.h          |  2 +-
 drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c   |  6 +-----
 .../net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c |  6 +-----
 drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c   | 10 ++--------
 drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c   | 19 ++-----------------
 .../wireless/realtek/rtlwifi/rtl8723com/fw_common.c   |  9 +--------
 drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c   | 15 +++------------
 7 files changed, 11 insertions(+), 56 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtlwifi/debug.h b/drivers/net/wireless/realtek/rtlwifi/debug.h
index 51794bc..75596e2 100644
--- a/drivers/net/wireless/realtek/rtlwifi/debug.h
+++ b/drivers/net/wireless/realtek/rtlwifi/debug.h
@@ -36,7 +36,7 @@
  *unexpected HW behavior, HW BUG
  *and so on.
  */
-#define DBG_EMERG			0
+/*#define DBG_EMERG			0 */
 
 /*
  *Abnormal, rare, or unexpeted cases.
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
index 3ba2a3f..2e22759 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
@@ -221,12 +221,8 @@ int rtl88e_download_fw(struct ieee80211_hw *hw,
 	_rtl88e_enable_fw_download(hw, false);
 
 	err = _rtl88e_fw_free_to_go(hw);
-	if (err) {
+	if (err)
 		pr_err("Firmware is not ready to run!\n");
-	} else {
-		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
-			 "Firmware is ready to run!\n");
-	}
 
 	return 0;
 }
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c
index 5c93ee0..eb4459c 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c
@@ -237,12 +237,8 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
 	_rtl92c_enable_fw_download(hw, false);
 
 	err = _rtl92c_fw_free_to_go(hw);
-	if (err) {
+	if (err)
 		pr_err("Firmware is not ready to run!\n");
-	} else {
-		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-			 "Firmware is ready to run!\n");
-	}
 
 	return 0;
 }
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c
index 5b33bed..e647605 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/fw.c
@@ -125,9 +125,8 @@ static void _rtl92d_write_fw(struct ieee80211_hw *hw,
 		_rtl92d_fill_dummy(bufferPtr, &size);
 	pagenums = size / FW_8192D_PAGE_SIZE;
 	remainSize = size % FW_8192D_PAGE_SIZE;
-	if (pagenums > 8) {
+	if (pagenums > 8)
 		pr_err("Page numbers should not greater then 8\n");
-	}
 	for (page = 0; page < pagenums; page++) {
 		offset = page * FW_8192D_PAGE_SIZE;
 		_rtl92d_fw_page_write(hw, page, (bufferPtr + offset),
@@ -155,8 +154,6 @@ static int _rtl92d_fw_free_to_go(struct ieee80211_hw *hw)
 		pr_err("chksum report fail! REG_MCUFWDL:0x%08x\n", value32);
 		return -EIO;
 	}
-	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-		 "Checksum report OK ! REG_MCUFWDL:0x%08x\n", value32);
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 	value32 |= MCUFWDL_RDY;
 	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
@@ -323,12 +320,9 @@ int rtl92d_download_fw(struct ieee80211_hw *hw)
 	value &= (~BIT(5));
 	rtl_write_byte(rtlpriv, 0x1f, value);
 	spin_unlock_irqrestore(&globalmutex_for_fwdownload, flags);
-	if (err) {
+	if (err)
 		pr_err("fw is not ready to run!\n");
 		goto exit;
-	} else {
-		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "fw is ready to run!\n");
-	}
 exit:
 	err = _rtl92d_fw_init(hw);
 	return err;
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
index 2959746..e05b181 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/fw.c
@@ -157,10 +157,6 @@ static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw)
 		       value32);
 		goto exit;
 	}
-
-	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-		 "Checksum report OK! REG_MCUFWDL:0x%08x\n", value32);
-
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 	value32 |= MCUFWDL_RDY;
 	value32 &= ~WINTINI_RDY;
@@ -171,13 +167,8 @@ static int _rtl92ee_fw_free_to_go(struct ieee80211_hw *hw)
 
 	do {
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-		if (value32 & WINTINI_RDY) {
-			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
-				 "Polling FW ready success!! REG_MCUFWDL:0x%08x. count = %d\n",
-				 value32, counter);
-			err = 0;
-			goto exit;
-		}
+		if (value32 & WINTINI_RDY)
+			return 0;
 
 		udelay(FW_8192C_POLLING_DELAY*10);
 
@@ -236,12 +227,6 @@ int rtl92ee_download_fw(struct ieee80211_hw *hw, bool buse_wake_on_wlan_fw)
 	_rtl92ee_enable_fw_download(hw, false);
 
 	err = _rtl92ee_fw_free_to_go(hw);
-	if (err) {
-		pr_err("Firmware is not ready to run!\n");
-	} else {
-		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD ,
-			 "Firmware is ready to run!\n");
-	}
 
 	return 0;
 }
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c
index a9cc67e..a040e6b 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/fw_common.c
@@ -212,9 +212,6 @@ int rtl8723_fw_free_to_go(struct ieee80211_hw *hw, bool is_8723be,
 		       value32);
 		goto exit;
 	}
-	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
-
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL) | MCUFWDL_RDY;
 	value32 &= ~WINTINI_RDY;
 	rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
@@ -290,12 +287,8 @@ int rtl8723_download_fw(struct ieee80211_hw *hw,
 	rtl8723_enable_fw_download(hw, false);
 
 	err = rtl8723_fw_free_to_go(hw, is_8723be, max_count);
-	if (err) {
+	if (err)
 		pr_err("Firmware is not ready to run!\n");
-	} else {
-		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-			 "Firmware is ready to run!\n");
-	}
 	return 0;
 }
 EXPORT_SYMBOL_GPL(rtl8723_download_fw);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c
index 536c12a..4f17140 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/fw.c
@@ -124,9 +124,8 @@ static void _rtl8821ae_write_fw(struct ieee80211_hw *hw,
 	pagenums = size / FW_8821AE_PAGE_SIZE;
 	remainsize = size % FW_8821AE_PAGE_SIZE;
 
-	if (pagenums > 8) {
+	if (pagenums > 8)
 		pr_err("Page numbers should not greater then 8\n");
-	}
 
 	for (page = 0; page < pagenums; page++) {
 		offset = page * FW_8821AE_PAGE_SIZE;
@@ -160,9 +159,6 @@ static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw)
 			  value32);
 		goto exit;
 	}
-
-	pr_err("Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
-
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 	value32 |= MCUFWDL_RDY;
 	value32 &= ~WINTINI_RDY;
@@ -173,13 +169,8 @@ static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw)
 	counter = 0;
 	do {
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-		if (value32 & WINTINI_RDY) {
-			RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
-				 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
-				  value32);
-			err = 0;
-			goto exit;
-		}
+		if (value32 & WINTINI_RDY)
+			return 0;
 
 		udelay(FW_8821AE_POLLING_DELAY);
 	} while (counter++ < FW_8821AE_POLLING_TIMEOUT_COUNT);
-- 
2.10.2

^ permalink raw reply related

* [PATCH 13/14] rtlwifi: rtl8188ee: Remove all instances of DBG_EMERG
From: Larry Finger @ 2016-12-11  5:45 UTC (permalink / raw)
  To: kvalo; +Cc: devel, linux-wireless, Larry Finger, Ping-Ke Shih
In-Reply-To: <20161211054523.7119-1-Larry.Finger@lwfinger.net>

This is a step toward eliminating the RT_TRACE macros. Those calls that
have DBG_EMERG as the level are always logged, and they represent error
conditions, thus they are replaced with pr_err().

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Ping-Ke Shih <pkshih@realtek.com>
---
 .../net/wireless/realtek/rtlwifi/rtl8188ee/fw.c    | 33 ++++++----------------
 .../net/wireless/realtek/rtlwifi/rtl8188ee/hw.c    | 30 ++++++++------------
 .../net/wireless/realtek/rtlwifi/rtl8188ee/phy.c   | 22 ++++++---------
 .../net/wireless/realtek/rtlwifi/rtl8188ee/rf.c    |  3 +-
 .../net/wireless/realtek/rtlwifi/rtl8188ee/sw.c    |  8 ++----
 5 files changed, 33 insertions(+), 63 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
index c34cde2..009fd3b 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
@@ -125,10 +125,8 @@ static void _rtl88e_write_fw(struct ieee80211_hw *hw,
 	pagenums = size / FW_8192C_PAGE_SIZE;
 	remainsize = size % FW_8192C_PAGE_SIZE;
 
-	if (pagenums > 8) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Page numbers should not greater then 8\n");
-	}
+	if (pagenums > 8)
+		pr_err("rtl8188ee: Page numbers should not greater then 8\n");
 
 	for (page = 0; page < pagenums; page++) {
 		offset = page * FW_8192C_PAGE_SIZE;
@@ -157,15 +155,10 @@ static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
 		 (!(value32 & FWDL_CHKSUM_RPT)));
 
 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
-			  value32);
+		pr_err("rtl8188ee: chksum report fail! REG_MCUFWDL:0x%08x .\n",
+		       value32);
 		goto exit;
 	}
-
-	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
-
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 	value32 |= MCUFWDL_RDY;
 	value32 &= ~WINTINI_RDY;
@@ -176,20 +169,15 @@ static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
 
 	do {
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-		if (value32 & WINTINI_RDY) {
-			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-				 "Polling FW ready success!! REG_MCUFWDL:0x%08x.\n",
-				  value32);
-			err = 0;
-			goto exit;
-		}
+		if (value32 & WINTINI_RDY)
+			return 0;
 
 		udelay(FW_8192C_POLLING_DELAY);
 
 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 
-	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
+	pr_err("rtl8188ee: Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n",
+	       value32);
 
 exit:
 	return err;
@@ -235,8 +222,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw,
 
 	err = _rtl88e_fw_free_to_go(hw);
 	if (err) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Firmware is not ready to run!\n");
+		pr_err("rtl8188ee: Firmware is not ready to run!\n");
 	} else {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 			 "Firmware is ready to run!\n");
@@ -309,8 +295,7 @@ static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
 	while (!write_sucess) {
 		wait_writeh2c_limit--;
 		if (wait_writeh2c_limit == 0) {
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Write H2C fail because no trigger for FW INT!\n");
+			pr_err("rtl8188ee: Write H2C fail because no trigger for FW INT!\n");
 			break;
 		}
 
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
index d85fa67..6aa593d 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
@@ -358,8 +358,7 @@ void rtl88ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HAL_DEF_WOWLAN:
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case %#x not processed\n", variable);
+		pr_err("rtl8188ee: switch case %#x not processed\n", variable);
 		break;
 	}
 }
@@ -572,9 +571,8 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 				acm_ctrl &= (~ACMHW_VOQEN);
 				break;
 			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-					 "switch case %#x not processed\n",
-					 e_aci);
+				pr_err("rtl8188ee: switch case %#x not processed\n",
+				       e_aci);
 				break;
 			}
 		}
@@ -737,8 +735,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 				    2, array);
 		break; }
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case %#x not processed\n", variable);
+		pr_err("rtl8188ee: switch case %#x not processed\n", variable);
 		break;
 	}
 }
@@ -759,9 +756,8 @@ static bool _rtl88ee_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
 			break;
 
 		if (count > POLLING_LLT_THRESHOLD) {
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Failed to polling write LLT done at address %d!\n",
-				 address);
+			pr_err("rtl8188ee: Failed to polling write LLT done at address %d!\n",
+			       address);
 			status = false;
 			break;
 		}
@@ -1096,7 +1092,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
 
 	rtstatus = _rtl88ee_init_mac(hw);
 	if (rtstatus != true) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+		pr_info("Init MAC failed\n");
 		err = 1;
 		goto exit;
 	}
@@ -1252,8 +1248,7 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw,
 			 "Set Network type to AP!\n");
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Network type %d not support!\n", type);
+		pr_err("rtl8188ee: Network type %d not support!\n", type);
 		return 1;
 		break;
 	}
@@ -1987,7 +1982,7 @@ void rtl88ee_read_eeprom_info(struct ieee80211_hw *hw)
 		rtlefuse->autoload_failflag = false;
 		_rtl88ee_read_adapter_info(hw);
 	} else {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+		pr_err("rtl8188ee: Autoload ERR!!\n");
 	}
 	_rtl88ee_hal_customized_behavior(hw);
 }
@@ -2354,8 +2349,8 @@ void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key_index,
 			enc_algo = CAM_AES;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case %#x not processed\n", enc_algo);
+			pr_err("rtl8188ee: switch case %#x not processed\n",
+			       enc_algo);
 			enc_algo = CAM_TKIP;
 			break;
 		}
@@ -2373,9 +2367,7 @@ void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key_index,
 					entry_id =
 					  rtl_cam_get_free_entry(hw, p_macaddr);
 					if (entry_id >=  TOTAL_CAM_ENTRY) {
-						RT_TRACE(rtlpriv, COMP_SEC,
-							 DBG_EMERG,
-							 "Can not find free hw security cam entry\n");
+						pr_err("rtl8188ee: Can not find free hw security cam entry\n");
 						return;
 					}
 				} else {
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
index 870d8202..925a43f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
@@ -176,7 +176,7 @@ static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw,
 	offset &= 0xff;
 	newoffset = offset;
 	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+		pr_err("rtl8188ee: return all one\n");
 		return 0xFFFFFFFF;
 	}
 	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
@@ -220,7 +220,7 @@ static void _rtl88e_phy_rf_serial_write(struct ieee80211_hw *hw,
 	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
 
 	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+		pr_err("rtl8188ee: stop\n");
 		return;
 	}
 	offset &= 0xff;
@@ -373,7 +373,7 @@ static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw)
 
 	rtstatus = phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG);
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n");
+		pr_err("rtl8188ee: Write BB Reg Fail!!\n");
 		return false;
 	}
 
@@ -383,13 +383,13 @@ static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw)
 		  phy_config_bb_with_pghdr(hw, BASEBAND_CONFIG_PHY_REG);
 	}
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n");
+		pr_err("rtl8188ee: BB_PG Reg Fail!!\n");
 		return false;
 	}
 	rtstatus =
 	  phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_AGC_TAB);
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+		pr_err("rtl8188ee: AGC Table Fail\n");
 		return false;
 	}
 	rtlphy->cck_high_power =
@@ -1095,8 +1095,7 @@ void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
 						      (u8 *)&iotype);
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Unknown Scan Backup operation.\n");
+			pr_err("rtl8188ee: Unknown Scan Backup operation.\n");
 			break;
 		}
 	}
@@ -1137,8 +1136,8 @@ void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+		pr_err("rtl8188ee: unknown bandwidth: %#X\n",
+		       rtlphy->current_chan_bw);
 		break;
 	}
 
@@ -1162,8 +1160,8 @@ void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+		pr_err("rtl8188ee: unknown bandwidth: %#X\n",
+		       rtlphy->current_chan_bw);
 		break;
 	}
 	rtl88e_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
@@ -1303,8 +1300,8 @@ static bool _rtl88e_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
 			currentcmd = &postcommoncmd[*step];
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Invalid 'stage' = %d, Check it!\n", *stage);
+			pr_err("rtl8188ee: Invalid 'stage' = %d, Check it!\n",
+			       *stage);
 			return true;
 		}
 
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c
index 26ac4c2..30798b1 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c
@@ -51,8 +51,7 @@ void rtl88e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 			      rtlphy->rfreg_chnlval[0]);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "unknown bandwidth: %#X\n", bandwidth);
+		pr_err("rtl8188ee: unknown bandwidth: %#X\n", bandwidth);
 		break;
 	}
 }
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
index f361808..276c745 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
@@ -165,8 +165,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
 	/* for firmware buf */
 	rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
 	if (!rtlpriv->rtlhal.pfirmware) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Can't alloc buffer for fw.\n");
+		pr_info("Can't alloc buffer for fw.\n");
 		return 1;
 	}
 
@@ -177,8 +176,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
 				      rtlpriv->io.dev, GFP_KERNEL, hw,
 				      rtl_fw_cb);
 	if (err) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Failed to request firmware!\n");
+		pr_info("Failed to request firmware!\n");
 		return 1;
 	}
 
@@ -278,7 +276,7 @@ static struct rtl_mod_params rtl88ee_mod_params = {
 	.swctrl_lps = false,
 	.fwctrl_lps = false,
 	.msi_support = true,
-	.debug = DBG_EMERG,
+	.debug = 0,
 };
 
 static const struct rtl_hal_cfg rtl88ee_hal_cfg = {
-- 
2.10.2

^ permalink raw reply related

* [PATCH 12/14] rtlwifi: rtl8192c-common: Remove all instances of DBG_EMERG
From: Larry Finger @ 2016-12-11  5:45 UTC (permalink / raw)
  To: kvalo; +Cc: devel, linux-wireless, Larry Finger, Ping-Ke Shih
In-Reply-To: <20161211054523.7119-1-Larry.Finger@lwfinger.net>

This is a step toward eliminating the RT_TRACE macros. Those calls that
have DBG_EMERG as the level are always logged, and they represent error
conditions, thus they are replaced with pr_err().

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Ping-Ke Shih <pkshih@realtek.com>
---
 .../wireless/realtek/rtlwifi/rtl8192c/fw_common.c  | 33 ++++++----------------
 .../wireless/realtek/rtlwifi/rtl8192c/phy_common.c | 13 ++++-----
 2 files changed, 15 insertions(+), 31 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c
index 4a49e66..e739e56 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/fw_common.c
@@ -145,10 +145,8 @@ static void _rtl92c_write_fw(struct ieee80211_hw *hw,
 		pageNums = size / FW_8192C_PAGE_SIZE;
 		remainsize = size % FW_8192C_PAGE_SIZE;
 
-		if (pageNums > 4) {
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Page numbers should not greater then 4\n");
-		}
+		if (pageNums > 4)
+			pr_err("rtl8192c-common: Page numbers should not greater then 4\n");
 
 		for (page = 0; page < pageNums; page++) {
 			offset = page * FW_8192C_PAGE_SIZE;
@@ -180,15 +178,10 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
 		 (!(value32 & FWDL_ChkSum_rpt)));
 
 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
-			  value32);
+		pr_err("rtl8192c-common: chksum report fail! REG_MCUFWDL:0x%08x .\n",
+		       value32);
 		goto exit;
 	}
-
-	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
-
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 	value32 |= MCUFWDL_RDY;
 	value32 &= ~WINTINI_RDY;
@@ -198,20 +191,15 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
 
 	do {
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-		if (value32 & WINTINI_RDY) {
-			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-				 "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
-					value32);
-			err = 0;
-			goto exit;
-		}
+		if (value32 & WINTINI_RDY)
+			return 0;
 
 		mdelay(FW_8192C_POLLING_DELAY);
 
 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 
-	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
+	pr_err("rtl8192c-common: Polling FW ready fail! REG_MCUFWDL:0x%08x.\n",
+	       value32);
 
 exit:
 	return err;
@@ -251,8 +238,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
 
 	err = _rtl92c_fw_free_to_go(hw);
 	if (err) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Firmware is not ready to run!\n");
+		pr_err("rtl8192c-common: Firmware is not ready to run!\n");
 	} else {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
 			 "Firmware is ready to run!\n");
@@ -327,8 +313,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
 	while (!bwrite_sucess) {
 		wait_writeh2c_limmit--;
 		if (wait_writeh2c_limmit == 0) {
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Write H2C fail because no trigger for FW INT!\n");
+			pr_err("rtl8192c-common: Write H2C fail because no trigger for FW INT!\n");
 			break;
 		}
 
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
index 30c2d12..5f8fa4a 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/phy_common.c
@@ -104,7 +104,7 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
 	offset &= 0x3f;
 	newoffset = offset;
 	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+		pr_err("rtl8192c-common: return all one\n");
 		return 0xFFFFFFFF;
 	}
 	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
@@ -152,7 +152,7 @@ void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
 	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
 
 	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+		pr_err("rtl8192c-common: stop\n");
 		return;
 	}
 	offset &= 0x3f;
@@ -209,7 +209,7 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
 	rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw,
 						 BASEBAND_CONFIG_PHY_REG);
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n");
+		pr_err("rtl8192c-common: Write BB Reg Fail!!\n");
 		return false;
 	}
 	if (rtlphy->rf_type == RF_1T2R) {
@@ -222,13 +222,13 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
 						   BASEBAND_CONFIG_PHY_REG);
 	}
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n");
+		pr_err("rtl8192c-common: BB_PG Reg Fail!!\n");
 		return false;
 	}
 	rtstatus = rtlpriv->cfg->ops->config_bb_with_headerfile(hw,
 						 BASEBAND_CONFIG_AGC_TAB);
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+		pr_err("rtl8192c-common: AGC Table Fail\n");
 		return false;
 	}
 	rtlphy->cck_high_power =
@@ -860,8 +860,8 @@ bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
 			currentcmd = &postcommoncmd[*step];
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Invalid 'stage' = %d, Check it!\n", *stage);
+			pr_err("rtl8192c-common: Invalid 'stage' = %d, Check it!\n",
+			       *stage);
 			return true;
 		}
 
-- 
2.10.2

^ permalink raw reply related

* [PATCH 13/14] rtlwifi_new: rtl8188ee: Remove all instances of DBG_EMERG
From: Larry Finger @ 2016-12-11  5:45 UTC (permalink / raw)
  To: kvalo; +Cc: devel, linux-wireless, Larry Finger, Ping-Ke Shih
In-Reply-To: <20161211054523.7119-1-Larry.Finger@lwfinger.net>

This is a step toward eliminating the RT_TRACE macros. Those calls that
have DBG_EMERG as the level are always logged, and they represent error
conditions, thus they are replaced with pr_err().

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
Cc: Ping-Ke Shih <pkshih@realtek.com>
---
 .../net/wireless/realtek/rtlwifi/rtl8188ee/fw.c    | 33 ++++++----------------
 .../net/wireless/realtek/rtlwifi/rtl8188ee/hw.c    | 30 ++++++++------------
 .../net/wireless/realtek/rtlwifi/rtl8188ee/phy.c   | 22 ++++++---------
 .../net/wireless/realtek/rtlwifi/rtl8188ee/rf.c    |  3 +-
 .../net/wireless/realtek/rtlwifi/rtl8188ee/sw.c    |  8 ++----
 5 files changed, 33 insertions(+), 63 deletions(-)

diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
index fbd3eea..3ba2a3f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/fw.c
@@ -125,10 +125,8 @@ static void _rtl88e_write_fw(struct ieee80211_hw *hw,
 	pagenums = size / FW_8192C_PAGE_SIZE;
 	remainsize = size % FW_8192C_PAGE_SIZE;
 
-	if (pagenums > 8) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Page numbers should not greater then 8\n");
-	}
+	if (pagenums > 8)
+		pr_err("Page numbers should not greater then 8\n");
 
 	for (page = 0; page < pagenums; page++) {
 		offset = page * FW_8192C_PAGE_SIZE;
@@ -157,15 +155,10 @@ static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
 		 (!(value32 & FWDL_CHKSUM_RPT)));
 
 	if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
-			  value32);
+		pr_err("chksum report fail! REG_MCUFWDL:0x%08x .\n",
+		       value32);
 		goto exit;
 	}
-
-	RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-		 "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
-
 	value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
 	value32 |= MCUFWDL_RDY;
 	value32 &= ~WINTINI_RDY;
@@ -176,20 +169,14 @@ static int _rtl88e_fw_free_to_go(struct ieee80211_hw *hw)
 
 	do {
 		value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
-		if (value32 & WINTINI_RDY) {
-			RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
-				 "Polling FW ready success!! REG_MCUFWDL:0x%08x.\n",
-				  value32);
-			err = 0;
-			goto exit;
-		}
+		if (value32 & WINTINI_RDY)
+			return 0;
 
 		udelay(FW_8192C_POLLING_DELAY);
 
 	} while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
 
-	RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-		 "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
+	pr_err("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
 
 exit:
 	return err;
@@ -235,8 +222,7 @@ int rtl88e_download_fw(struct ieee80211_hw *hw,
 
 	err = _rtl88e_fw_free_to_go(hw);
 	if (err) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Firmware is not ready to run!\n");
+		pr_err("Firmware is not ready to run!\n");
 	} else {
 		RT_TRACE(rtlpriv, COMP_FW, DBG_LOUD,
 			 "Firmware is ready to run!\n");
@@ -309,8 +295,7 @@ static void _rtl88e_fill_h2c_command(struct ieee80211_hw *hw,
 	while (!write_sucess) {
 		wait_writeh2c_limit--;
 		if (wait_writeh2c_limit == 0) {
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Write H2C fail because no trigger for FW INT!\n");
+			pr_err("Write H2C fail because no trigger for FW INT!\n");
 			break;
 		}
 
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
index 1a17dfe..0dc1293 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c
@@ -358,8 +358,7 @@ void rtl88ee_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 	case HAL_DEF_WOWLAN:
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case %#x not processed\n", variable);
+		pr_err("switch case %#x not processed\n", variable);
 		break;
 	}
 }
@@ -572,9 +571,8 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 				acm_ctrl &= (~ACMHW_VOQEN);
 				break;
 			default:
-				RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-					 "switch case %#x not processed\n",
-					 e_aci);
+				pr_err("switch case %#x not processed\n",
+				       e_aci);
 				break;
 			}
 		}
@@ -737,8 +735,7 @@ void rtl88ee_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
 				    2, array);
 		break; }
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "switch case %#x not processed\n", variable);
+		pr_err("switch case %#x not processed\n", variable);
 		break;
 	}
 }
@@ -759,9 +756,8 @@ static bool _rtl88ee_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
 			break;
 
 		if (count > POLLING_LLT_THRESHOLD) {
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Failed to polling write LLT done at address %d!\n",
-				 address);
+			pr_err("Failed to polling write LLT done at address %d!\n",
+			       address);
 			status = false;
 			break;
 		}
@@ -1096,7 +1092,7 @@ int rtl88ee_hw_init(struct ieee80211_hw *hw)
 
 	rtstatus = _rtl88ee_init_mac(hw);
 	if (rtstatus != true) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+		pr_info("Init MAC failed\n");
 		err = 1;
 		goto exit;
 	}
@@ -1252,8 +1248,7 @@ static int _rtl88ee_set_media_status(struct ieee80211_hw *hw,
 			 "Set Network type to AP!\n");
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Network type %d not support!\n", type);
+		pr_err("Network type %d not support!\n", type);
 		return 1;
 		break;
 	}
@@ -1987,7 +1982,7 @@ void rtl88ee_read_eeprom_info(struct ieee80211_hw *hw)
 		rtlefuse->autoload_failflag = false;
 		_rtl88ee_read_adapter_info(hw);
 	} else {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+		pr_err("Autoload ERR!!\n");
 	}
 	_rtl88ee_hal_customized_behavior(hw);
 }
@@ -2354,8 +2349,7 @@ void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key_index,
 			enc_algo = CAM_AES;
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "switch case %#x not processed\n", enc_algo);
+			pr_err("switch case %#x not processed\n", enc_algo);
 			enc_algo = CAM_TKIP;
 			break;
 		}
@@ -2373,9 +2367,7 @@ void rtl88ee_set_key(struct ieee80211_hw *hw, u32 key_index,
 					entry_id =
 					  rtl_cam_get_free_entry(hw, p_macaddr);
 					if (entry_id >=  TOTAL_CAM_ENTRY) {
-						RT_TRACE(rtlpriv, COMP_SEC,
-							 DBG_EMERG,
-							 "Can not find free hw security cam entry\n");
+						pr_err("Can not find free hw security cam entry\n");
 						return;
 					}
 				} else {
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
index ece8691..c6d6a16 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/phy.c
@@ -176,7 +176,7 @@ static u32 _rtl88e_phy_rf_serial_read(struct ieee80211_hw *hw,
 	offset &= 0xff;
 	newoffset = offset;
 	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+		pr_err("return all one\n");
 		return 0xFFFFFFFF;
 	}
 	tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
@@ -220,7 +220,7 @@ static void _rtl88e_phy_rf_serial_write(struct ieee80211_hw *hw,
 	struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
 
 	if (RT_CANNOT_IO(hw)) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+		pr_err("stop\n");
 		return;
 	}
 	offset &= 0xff;
@@ -373,7 +373,7 @@ static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw)
 
 	rtstatus = phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_PHY_REG);
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!\n");
+		pr_err("Write BB Reg Fail!!\n");
 		return false;
 	}
 
@@ -383,13 +383,13 @@ static bool _rtl88e_phy_bb8188e_config_parafile(struct ieee80211_hw *hw)
 		  phy_config_bb_with_pghdr(hw, BASEBAND_CONFIG_PHY_REG);
 	}
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!\n");
+		pr_err("BB_PG Reg Fail!!\n");
 		return false;
 	}
 	rtstatus =
 	  phy_config_bb_with_headerfile(hw, BASEBAND_CONFIG_AGC_TAB);
 	if (!rtstatus) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+		pr_err("AGC Table Fail\n");
 		return false;
 	}
 	rtlphy->cck_high_power =
@@ -1095,8 +1095,7 @@ void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
 						      (u8 *)&iotype);
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Unknown Scan Backup operation.\n");
+			pr_err("Unknown Scan Backup operation.\n");
 			break;
 		}
 	}
@@ -1137,8 +1136,7 @@ void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 		rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+		pr_err("unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
 		break;
 	}
 
@@ -1162,8 +1160,7 @@ void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 			       HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+		pr_err("unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
 		break;
 	}
 	rtl88e_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
@@ -1303,8 +1300,7 @@ static bool _rtl88e_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
 			currentcmd = &postcommoncmd[*step];
 			break;
 		default:
-			RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-				 "Invalid 'stage' = %d, Check it!\n", *stage);
+			pr_err("Invalid 'stage' = %d, Check it!\n", *stage);
 			return true;
 		}
 
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c
index 26ac4c2..30798b1 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/rf.c
@@ -51,8 +51,7 @@ void rtl88e_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
 			      rtlphy->rfreg_chnlval[0]);
 		break;
 	default:
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "unknown bandwidth: %#X\n", bandwidth);
+		pr_err("unknown bandwidth: %#X\n", bandwidth);
 		break;
 	}
 }
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
index f361808..276c745 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c
@@ -165,8 +165,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
 	/* for firmware buf */
 	rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
 	if (!rtlpriv->rtlhal.pfirmware) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Can't alloc buffer for fw.\n");
+		pr_info("Can't alloc buffer for fw.\n");
 		return 1;
 	}
 
@@ -177,8 +176,7 @@ int rtl88e_init_sw_vars(struct ieee80211_hw *hw)
 				      rtlpriv->io.dev, GFP_KERNEL, hw,
 				      rtl_fw_cb);
 	if (err) {
-		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-			 "Failed to request firmware!\n");
+		pr_info("Failed to request firmware!\n");
 		return 1;
 	}
 
@@ -278,7 +276,7 @@ static struct rtl_mod_params rtl88ee_mod_params = {
 	.swctrl_lps = false,
 	.fwctrl_lps = false,
 	.msi_support = true,
-	.debug = DBG_EMERG,
+	.debug = 0,
 };
 
 static const struct rtl_hal_cfg rtl88ee_hal_cfg = {
-- 
2.10.2

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox