Search Linux Wireless

Re: [PATCH 2/5] cfg80211: allow drivers to provide regulatory settings

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

 



On 11-06-14 08:55, Arik Nemtsov wrote:
Define a new wiphy callback allowing drivers to provide regulatory
settings.

Only The first wiphy registered with this callback will be able to provide
regulatory domain info. If such a wiphy exists, it takes precedence over
other data sources.

I should probably dig through linux-wireless archive for background info, but how is this different from the wiphy_apply_custom_regulatory() call. Is this for devices that have a regulatory database of sorts in the device firmware?

Regards,
Arend

Change-Id: If8f8faf1d127120ae464b45098c5edbc5aee3dc0
Signed-off-by: Arik Nemtsov <arikx.nemtsov@xxxxxxxxx>
Reviewed-on: https://gerrit.rds.intel.com/32858
Tested-by: IWL Jenkins
Reviewed-by: Johannes Berg <johannes.berg@xxxxxxxxx>
---
  include/net/cfg80211.h | 16 +++++++++++++
  net/wireless/reg.c     | 65 +++++++++++++++++++++++++++++++++++++++++++++-----
  2 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 5c17b1f..b8f0269 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2950,6 +2950,19 @@ struct wiphy_vendor_command {
   *	low rssi when a frame is heard on different channel, then it should set
   *	this variable to the maximal offset for which it can compensate.
   *	This value should be set in MHz.
+ * @get_regd: a driver callback to for publishing regulatory information.
+ *	By implementing this callback, a wiphy indicates it will provide
+ *	regulatory information. The callback must be set before the wiphy is
+ *	is registered. Only the first wiphy with this callback will be called
+ *	to provide a regdomain on country-code changes.
+ *	Returns A driver allocated regdomain structure. The alpha2 in the
+ *	returned regdomain can be different from the one given via the alpha2
+ *	argument, if the argument contains "99", meaning unknown.
+ *	If an ERR_PTR is returned the regulatory core will consult other
+ *	sources for the regdomain info (internal regdb and CRDA). Returning
+ *	NULL will cause the regdomain to remain the same. The callee will
+ *	return a struct allocated with kmalloc(). After the struct is returned,
+ *	the regulatory core is responsible for freeing it.
   */
  struct wiphy {
  	/* assign these fields before you register the wiphy */
@@ -3033,6 +3046,9 @@ struct wiphy {
  	void (*reg_notifier)(struct wiphy *wiphy,
  			     struct regulatory_request *request);

+	struct ieee80211_regdomain * (*get_regd)(struct wiphy *wiphy,
+						 const char *alpha2);
+
  	/* fields below are read-only, assigned by cfg80211 */

  	const struct ieee80211_regdomain __rcu *regd;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index efd6d0d..e2f33d7 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -78,6 +78,8 @@
   *	further processing is required, i.e., not need to update last_request
   *	etc. This should be used for user hints that do not provide an alpha2
   *	but some other type of regulatory hint, i.e., indoor operation.
+ * @REG_REQ_HANDLED: a request was handled synchronously. No need to set
+ *	timeouts and potentially revert to the default settings.
   */
  enum reg_request_treatment {
  	REG_REQ_OK,
@@ -85,6 +87,7 @@ enum reg_request_treatment {
  	REG_REQ_INTERSECT,
  	REG_REQ_ALREADY_SET,
  	REG_REQ_USER_HINT_HANDLED,
+	REG_REQ_HANDLED,
  };

  static struct regulatory_request core_request_world = {
@@ -129,6 +132,15 @@ static int reg_num_devs_support_basehint;
   */
  static bool reg_is_indoor;

+/*
+ * Wiphy with a get_regd() callback that can provide regulatory information
+ * when the country code changes. Only the first wiphy registered with the
+ * get_regd callback will be called to provide a regdomain on country-code
+ * changes.
+ * (protected by RTNL)
+ */
+static struct wiphy *regd_info_wiphy;
+
  static const struct ieee80211_regdomain *get_cfg80211_regdom(void)
  {
  	return rtnl_dereference(cfg80211_regdomain);
@@ -538,9 +550,39 @@ static int call_crda(const char *alpha2)
  	return kobject_uevent_env(&reg_pdev->dev.kobj, KOBJ_CHANGE, env);
  }

+static int call_wiphy_regd_info(const char *alpha2)
+{
+	struct ieee80211_regdomain *regd;
+
+	if (!regd_info_wiphy)
+		return -ENOENT;
+
+	/* can happen if the driver removes the callback at runtime */
+	if (WARN_ON(!regd_info_wiphy->get_regd))
+		return -EINVAL;
+
+	regd = regd_info_wiphy->get_regd(regd_info_wiphy, alpha2);
+	if (IS_ERR(regd))
+		return -EIO;
+
+	if (regd)
+		set_regdom(regd);
+
+	return 0;
+}
+
  static enum reg_request_treatment
-reg_call_crda(struct regulatory_request *request)
+reg_get_regdom_data(struct regulatory_request *request)
  {
+	ASSERT_RTNL();
+
+	/*
+	 * A wiphy wishing to set the regdomain takes precedence. Note the
+	 * regdomain setting happens synchronously inside.
+	 */
+	if (!call_wiphy_regd_info(request->alpha2))
+		return REG_REQ_HANDLED;
+
  	if (call_crda(request->alpha2))
  		return REG_REQ_IGNORE;
  	return REG_REQ_OK;
@@ -1641,7 +1683,7 @@ reg_process_hint_core(struct regulatory_request *core_request)

  	reg_update_last_request(core_request);

-	return reg_call_crda(core_request);
+	return reg_get_regdom_data(core_request);
  }

  static enum reg_request_treatment
@@ -1715,7 +1757,7 @@ reg_process_hint_user(struct regulatory_request *user_request)
  	user_alpha2[0] = user_request->alpha2[0];
  	user_alpha2[1] = user_request->alpha2[1];

-	return reg_call_crda(user_request);
+	return reg_get_regdom_data(user_request);
  }

  static enum reg_request_treatment
@@ -1764,6 +1806,7 @@ reg_process_hint_driver(struct wiphy *wiphy,
  		break;
  	case REG_REQ_IGNORE:
  	case REG_REQ_USER_HINT_HANDLED:
+	case REG_REQ_HANDLED:
  		reg_free_request(driver_request);
  		return treatment;
  	case REG_REQ_INTERSECT:
@@ -1794,7 +1837,7 @@ reg_process_hint_driver(struct wiphy *wiphy,
  		return treatment;
  	}

-	return reg_call_crda(driver_request);
+	return reg_get_regdom_data(driver_request);
  }

  static enum reg_request_treatment
@@ -1864,6 +1907,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
  		break;
  	case REG_REQ_IGNORE:
  	case REG_REQ_USER_HINT_HANDLED:
+	case REG_REQ_HANDLED:
  		/* fall through */
  	case REG_REQ_ALREADY_SET:
  		reg_free_request(country_ie_request);
@@ -1883,7 +1927,7 @@ reg_process_hint_country_ie(struct wiphy *wiphy,

  	reg_update_last_request(country_ie_request);

-	return reg_call_crda(country_ie_request);
+	return reg_get_regdom_data(country_ie_request);
  }

  /* This processes *all* regulatory hints */
@@ -1903,7 +1947,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
  		treatment = reg_process_hint_user(reg_request);
  		if (treatment == REG_REQ_IGNORE ||
  		    treatment == REG_REQ_ALREADY_SET ||
-		    treatment == REG_REQ_USER_HINT_HANDLED)
+		    treatment == REG_REQ_USER_HINT_HANDLED ||
+		    treatment == REG_REQ_HANDLED)
  			return;
  		queue_delayed_work(system_power_efficient_wq,
  				   &reg_timeout, msecs_to_jiffies(3142));
@@ -2684,6 +2729,9 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
  {
  	struct regulatory_request *lr;

+	if (wiphy->get_regd && !regd_info_wiphy)
+		regd_info_wiphy = wiphy;
+
  	if (!reg_dev_ignore_cell_hint(wiphy))
  		reg_num_devs_support_basehint++;

@@ -2696,6 +2744,8 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
  	struct wiphy *request_wiphy = NULL;
  	struct regulatory_request *lr;

+	ASSERT_RTNL();
+
  	lr = get_last_request();

  	if (!reg_dev_ignore_cell_hint(wiphy))
@@ -2704,6 +2754,9 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
  	rcu_free_regdom(get_wiphy_regdom(wiphy));
  	RCU_INIT_POINTER(wiphy->regd, NULL);

+	if (wiphy == regd_info_wiphy)
+		regd_info_wiphy = NULL;
+
  	if (lr)
  		request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);



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




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

  Powered by Linux