diff mbox

[v2,3/4] cfg80211: allow wiphy specific regdomain management

Message ID 1415895219-19848-3-git-send-email-arik@wizery.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Arik Nemtsov Nov. 13, 2014, 4:13 p.m. UTC
From: Jonathan Doron <jond@wizery.com>

Add a new regulatory flag that allows a driver to manage regdomain
changes/updates for its own wiphy.
In this case the regdomain is local to the driver, and it does not use
the shared cfg80211 regdomain. It also implies that the driver does not
wish to get regulatory updates generated by other wiphys or by usermode.

A new API lets the driver send a complete regdomain, to be applied on
its wiphy only.

After a wiphy-specific regdomain change takes place, usermode will get
a new type of change notification. The regulatory core also takes care
enforce regulatory restrictions, in case some interfaces are on
forbidden channels.

Signed-off-by: Jonathan Doron <jonathanx.doron@intel.com>
Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
---
 include/net/cfg80211.h       | 14 ++++++++
 include/net/regulatory.h     |  9 +++++
 include/uapi/linux/nl80211.h |  5 +++
 net/wireless/core.c          |  7 ++++
 net/wireless/nl80211.c       | 80 ++++++++++++++++++++++++++++++++++----------
 net/wireless/nl80211.h       |  1 +
 net/wireless/reg.c           | 59 ++++++++++++++++++++++++++++++++
 7 files changed, 157 insertions(+), 18 deletions(-)

Comments

Luis Chamberlain Nov. 13, 2014, 11:11 p.m. UTC | #1
On Thu, Nov 13, 2014 at 06:13:38PM +0200, Arik Nemtsov wrote:
> From: Jonathan Doron <jond@wizery.com>
> 
> Add a new regulatory flag that allows a driver to manage regdomain
> changes/updates for its own wiphy.
> In this case the regdomain is local to the driver, and it does not use
> the shared cfg80211 regdomain. It also implies that the driver does not
> wish to get regulatory updates generated by other wiphys or by usermode.

I'd like you to be clearer on this both on the commit log and also
on the documentation:

--
Using this mean you are using your very own regulatory rule
interpretations, vetting of your own regulatory rules then is
completely on the driver / firmware using this. Any heuristics
about regulatory that cfg80211 can help with is completely
ignored.
--

There are gains by using cfg80211 and the work we have put into
cfg80211's regulatory infrastructure, we want folks to evaluate
not using it before discarding it, and ensure folks understand
the risks and issues that might come up if they don't gain any
help from cfg80211.

> A new API lets the driver send a complete regdomain, to be applied on
> its wiphy only.
> 
> After a wiphy-specific regdomain change takes place, usermode will get
> a new type of change notification. The regulatory core also takes care
> enforce regulatory restrictions, in case some interfaces are on
> forbidden channels.

I want you to also address what happens when two different devices
are used on a system that don't use the same mechanism. For instance,
one device may use this feature, another set may use the cfg80211
regulatory code. The implications are that the devices using this
new feature are not learning or gaining any information from the
core, its own its own. This is another reason that not using the
cfg80211 regulatory information is a poor architectural choice,
it doesn't scale well. I last considered simply disallowing such
combinations because of this very reason -- but since you are
separating this now I am OK with it -- I just want to ensure it is
crystal clear of the downfall to this long term architecturally.

In short: its fucking stupid.

I want folks to think very fucking hard before being stupid.

Please help with that.

> Signed-off-by: Jonathan Doron <jonathanx.doron@intel.com>
> Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
> ---
>  include/net/cfg80211.h       | 14 ++++++++
>  include/net/regulatory.h     |  9 +++++
>  include/uapi/linux/nl80211.h |  5 +++
>  net/wireless/core.c          |  7 ++++
>  net/wireless/nl80211.c       | 80 ++++++++++++++++++++++++++++++++++----------
>  net/wireless/nl80211.h       |  1 +
>  net/wireless/reg.c           | 59 ++++++++++++++++++++++++++++++++
>  7 files changed, 157 insertions(+), 18 deletions(-)
> 
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index 220d5f5..dd4f811 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -3728,6 +3728,20 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
>  int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
>  
>  /**
> + * regulatory_set_wiphy_regd_rtnl - set regdom info for self managed drivers
> + * @wiphy: the wireless device we want to process the regulatory domain on
> + * @rd: the regulatory domain informatoin to use for this wiphy
> + *
> + * Set the regulatory domain information for self managed drivers, only they
> + * can use this function.
> + * This function requires the caller to hold the rtnl_lock.

This documentation is lacking a lot of information. Please fell it with
information as to reasoning for why folks may go down this path as well
as well as caveats. The combination of devices is of particular concern
and it should be made clear.

> + *
> + * Return: 0 on success. -EINVAL, -EPERM
> + */
> +int regulatory_set_wiphy_regd_rtnl(struct wiphy *wiphy,
> +				   struct ieee80211_regdomain *rd);
> +
> +/**
>   * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
>   * @wiphy: the wireless device we want to process the regulatory domain on
>   * @regd: the custom regulatory domain to use for this wiphy
> diff --git a/include/net/regulatory.h b/include/net/regulatory.h
> index 701177c..42345f4 100644
> --- a/include/net/regulatory.h
> +++ b/include/net/regulatory.h
> @@ -141,6 +141,14 @@ struct regulatory_request {
>   *	change, the interfaces are given a grace period to disconnect or move
>   *	to an allowed channels. Interfaces on forbidden channels are forcibly
>   *	disconnected.
> + * @REGULATORY_WIPHY_SELF_MANAGED: for devices that employ wiphy-specific
> + *	regdom management. These devices will ignore all regdom changes not
> + *	originating from their own wiphy. This flag is incompatible with the
> + *	flags: %REGULATORY_CUSTOM_REG, %REGULATORY_STRICT_REG,
> + *	%REGULATORY_COUNTRY_IE_FOLLOW_POWER, %REGULATORY_COUNTRY_IE_IGNORE and
> + *	%REGULATORY_DISABLE_BEACON_HINTS. Mixing any of the above flags with
> + *	this flag will result in a failure to register the wiphy. This flag
> + *	implies %REGULATORY_DISABLE_BEACON_HINTS.

Please discourage such use.

>   */
>  enum ieee80211_regulatory_flags {
>  	REGULATORY_CUSTOM_REG			= BIT(0),
> @@ -150,6 +158,7 @@ enum ieee80211_regulatory_flags {
>  	REGULATORY_COUNTRY_IE_IGNORE		= BIT(4),
>  	REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
>  	REGULATORY_ENFORCE_CHANNELS             = BIT(6),
> +	REGULATORY_WIPHY_SELF_MANAGED		= BIT(7),
>  };
>  
>  struct ieee80211_freq_range {
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index 442369f..f050dcb 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -762,6 +762,9 @@
>   * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
>   *	network is determined by the network interface.
>   *
> + * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
> + *	for indicating changes for devices with wiphy-specific regdom management
> + *
>   * @NL80211_CMD_MAX: highest used command number
>   * @__NL80211_CMD_AFTER_LAST: internal use
>   */
> @@ -943,6 +946,8 @@ enum nl80211_commands {
>  
>  	NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
>  
> +	NL80211_CMD_WIPHY_REG_CHANGE,
> +
>  	/* add new commands above here */
>  
>  	/* used to define NL80211_CMD_MAX below */
> diff --git a/net/wireless/core.c b/net/wireless/core.c
> index a4d2792..656a1b1 100644
> --- a/net/wireless/core.c
> +++ b/net/wireless/core.c
> @@ -541,6 +541,13 @@ int wiphy_register(struct wiphy *wiphy)
>  		    !wiphy->wowlan->tcp))
>  		return -EINVAL;
>  #endif
> +	if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
> +		    (wiphy->regulatory_flags &
> +		     (REGULATORY_CUSTOM_REG | REGULATORY_STRICT_REG |
> +		      REGULATORY_COUNTRY_IE_FOLLOW_POWER |
> +		      REGULATORY_COUNTRY_IE_IGNORE |
> +		      REGULATORY_DISABLE_BEACON_HINTS))))
> +		return -EINVAL;

Look at all those heuristics go away... That's alot. The documetnation should
reflect all this not being used because of this decision. I also want you to
think of the issues that may come up when combining devices that, one that
uses this feature and one that does not.

  Luis

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arik Nemtsov Nov. 16, 2014, 11:06 a.m. UTC | #2
On Fri, Nov 14, 2014 at 1:11 AM, Luis R. Rodriguez <mcgrof@suse.com> wrote:
> On Thu, Nov 13, 2014 at 06:13:38PM +0200, Arik Nemtsov wrote:
>> From: Jonathan Doron <jond@wizery.com>
>>
>> Add a new regulatory flag that allows a driver to manage regdomain
>> changes/updates for its own wiphy.
>> In this case the regdomain is local to the driver, and it does not use
>> the shared cfg80211 regdomain. It also implies that the driver does not
>> wish to get regulatory updates generated by other wiphys or by usermode.
>
> I'd like you to be clearer on this both on the commit log and also
> on the documentation:
>
> --
> Using this mean you are using your very own regulatory rule
> interpretations, vetting of your own regulatory rules then is
> completely on the driver / firmware using this. Any heuristics
> about regulatory that cfg80211 can help with is completely
> ignored.
> --
>
> There are gains by using cfg80211 and the work we have put into
> cfg80211's regulatory infrastructure, we want folks to evaluate
> not using it before discarding it, and ensure folks understand
> the risks and issues that might come up if they don't gain any
> help from cfg80211.
>
>> A new API lets the driver send a complete regdomain, to be applied on
>> its wiphy only.
>>
>> After a wiphy-specific regdomain change takes place, usermode will get
>> a new type of change notification. The regulatory core also takes care
>> enforce regulatory restrictions, in case some interfaces are on
>> forbidden channels.
>
> I want you to also address what happens when two different devices
> are used on a system that don't use the same mechanism. For instance,
> one device may use this feature, another set may use the cfg80211
> regulatory code. The implications are that the devices using this
> new feature are not learning or gaining any information from the
> core, its own its own. This is another reason that not using the
> cfg80211 regulatory information is a poor architectural choice,
> it doesn't scale well. I last considered simply disallowing such
> combinations because of this very reason -- but since you are
> separating this now I am OK with it -- I just want to ensure it is
> crystal clear of the downfall to this long term architecturally.
>
> In short: its fucking stupid.
>
> I want folks to think very fucking hard before being stupid.
>
> Please help with that.

I'll try to beef up the commit message.

>> Signed-off-by: Jonathan Doron <jonathanx.doron@intel.com>
>> Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
>> ---
>>  include/net/cfg80211.h       | 14 ++++++++
>>  include/net/regulatory.h     |  9 +++++
>>  include/uapi/linux/nl80211.h |  5 +++
>>  net/wireless/core.c          |  7 ++++
>>  net/wireless/nl80211.c       | 80 ++++++++++++++++++++++++++++++++++----------
>>  net/wireless/nl80211.h       |  1 +
>>  net/wireless/reg.c           | 59 ++++++++++++++++++++++++++++++++
>>  7 files changed, 157 insertions(+), 18 deletions(-)
>>
>> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
>> index 220d5f5..dd4f811 100644
>> --- a/include/net/cfg80211.h
>> +++ b/include/net/cfg80211.h
>> @@ -3728,6 +3728,20 @@ const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
>>  int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
>>
>>  /**
>> + * regulatory_set_wiphy_regd_rtnl - set regdom info for self managed drivers
>> + * @wiphy: the wireless device we want to process the regulatory domain on
>> + * @rd: the regulatory domain informatoin to use for this wiphy
>> + *
>> + * Set the regulatory domain information for self managed drivers, only they
>> + * can use this function.
>> + * This function requires the caller to hold the rtnl_lock.
>
> This documentation is lacking a lot of information. Please fell it with
> information as to reasoning for why folks may go down this path as well
> as well as caveats. The combination of devices is of particular concern
> and it should be made clear.

I'll clarify it.

>
>> + *
>> + * Return: 0 on success. -EINVAL, -EPERM
>> + */
>> +int regulatory_set_wiphy_regd_rtnl(struct wiphy *wiphy,
>> +                                struct ieee80211_regdomain *rd);
>> +
>> +/**
>>   * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
>>   * @wiphy: the wireless device we want to process the regulatory domain on
>>   * @regd: the custom regulatory domain to use for this wiphy
>> diff --git a/include/net/regulatory.h b/include/net/regulatory.h
>> index 701177c..42345f4 100644
>> --- a/include/net/regulatory.h
>> +++ b/include/net/regulatory.h
>> @@ -141,6 +141,14 @@ struct regulatory_request {
>>   *   change, the interfaces are given a grace period to disconnect or move
>>   *   to an allowed channels. Interfaces on forbidden channels are forcibly
>>   *   disconnected.
>> + * @REGULATORY_WIPHY_SELF_MANAGED: for devices that employ wiphy-specific
>> + *   regdom management. These devices will ignore all regdom changes not
>> + *   originating from their own wiphy. This flag is incompatible with the
>> + *   flags: %REGULATORY_CUSTOM_REG, %REGULATORY_STRICT_REG,
>> + *   %REGULATORY_COUNTRY_IE_FOLLOW_POWER, %REGULATORY_COUNTRY_IE_IGNORE and
>> + *   %REGULATORY_DISABLE_BEACON_HINTS. Mixing any of the above flags with
>> + *   this flag will result in a failure to register the wiphy. This flag
>> + *   implies %REGULATORY_DISABLE_BEACON_HINTS.
>
> Please discourage such use.

Will do.

>
>>   */
>>  enum ieee80211_regulatory_flags {
>>       REGULATORY_CUSTOM_REG                   = BIT(0),
>> @@ -150,6 +158,7 @@ enum ieee80211_regulatory_flags {
>>       REGULATORY_COUNTRY_IE_IGNORE            = BIT(4),
>>       REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
>>       REGULATORY_ENFORCE_CHANNELS             = BIT(6),
>> +     REGULATORY_WIPHY_SELF_MANAGED           = BIT(7),
>>  };
>>
>>  struct ieee80211_freq_range {
>> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
>> index 442369f..f050dcb 100644
>> --- a/include/uapi/linux/nl80211.h
>> +++ b/include/uapi/linux/nl80211.h
>> @@ -762,6 +762,9 @@
>>   * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
>>   *   network is determined by the network interface.
>>   *
>> + * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
>> + *   for indicating changes for devices with wiphy-specific regdom management
>> + *
>>   * @NL80211_CMD_MAX: highest used command number
>>   * @__NL80211_CMD_AFTER_LAST: internal use
>>   */
>> @@ -943,6 +946,8 @@ enum nl80211_commands {
>>
>>       NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
>>
>> +     NL80211_CMD_WIPHY_REG_CHANGE,
>> +
>>       /* add new commands above here */
>>
>>       /* used to define NL80211_CMD_MAX below */
>> diff --git a/net/wireless/core.c b/net/wireless/core.c
>> index a4d2792..656a1b1 100644
>> --- a/net/wireless/core.c
>> +++ b/net/wireless/core.c
>> @@ -541,6 +541,13 @@ int wiphy_register(struct wiphy *wiphy)
>>                   !wiphy->wowlan->tcp))
>>               return -EINVAL;
>>  #endif
>> +     if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
>> +                 (wiphy->regulatory_flags &
>> +                  (REGULATORY_CUSTOM_REG | REGULATORY_STRICT_REG |
>> +                   REGULATORY_COUNTRY_IE_FOLLOW_POWER |
>> +                   REGULATORY_COUNTRY_IE_IGNORE |
>> +                   REGULATORY_DISABLE_BEACON_HINTS))))
>> +             return -EINVAL;
>
> Look at all those heuristics go away... That's alot. The documetnation should
> reflect all this not being used because of this decision. I also want you to
> think of the issues that may come up when combining devices that, one that
> uses this feature and one that does not.

Since this is a private regdomain, I guess this just means the
cfg80211 using device will be alone in the system for all regulatory
purposes.
I don't really see possible interoperability issues here. Am I missing
something?

Arik
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Luis Chamberlain Nov. 20, 2014, 8:27 p.m. UTC | #3
On Sun, Nov 16, 2014 at 01:06:00PM +0200, Arik Nemtsov wrote:
> On Fri, Nov 14, 2014 at 1:11 AM, Luis R. Rodriguez <mcgrof@suse.com> wrote:
> >> index a4d2792..656a1b1 100644
> >> --- a/net/wireless/core.c
> >> +++ b/net/wireless/core.c
> >> @@ -541,6 +541,13 @@ int wiphy_register(struct wiphy *wiphy)
> >>                   !wiphy->wowlan->tcp))
> >>               return -EINVAL;
> >>  #endif
> >> +     if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
> >> +                 (wiphy->regulatory_flags &
> >> +                  (REGULATORY_CUSTOM_REG | REGULATORY_STRICT_REG |
> >> +                   REGULATORY_COUNTRY_IE_FOLLOW_POWER |
> >> +                   REGULATORY_COUNTRY_IE_IGNORE |
> >> +                   REGULATORY_DISABLE_BEACON_HINTS))))
> >> +             return -EINVAL;
> >
> > Look at all those heuristics go away... That's alot. The documetnation should
> > reflect all this not being used because of this decision. I also want you to
> > think of the issues that may come up when combining devices that, one that
> > uses this feature and one that does not.
> 
> Since this is a private regdomain, I guess this just means the
> cfg80211 using device will be alone in the system for all regulatory
> purposes.
> I don't really see possible interoperability issues here. Am I missing
> something?

It means you can technically end up with two devices that operate with
different interpretation of rules, this can mean for example that some
expectations of having two devices may fail and since this will be all hard
coded you can't fix it.  The worst of the issues will be caused by the fact
that we simply won't know what issues will creep up until the two data sets
conflict and create an unexpected user facing issue. This is precicely why
having support for querying information about all regulatory data is critical,
and I'm glad you are doing that work.

What will happen when say a user / user interface wants to restrict all devices
to say a country like Israel, 'iw reg set IL' is used, so the cfg80211 regulatory
abiding devices follow the rules, but this Intel device does not?

 Luis
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Arik Nemtsov Nov. 21, 2014, 9:17 a.m. UTC | #4
On Thu, Nov 20, 2014 at 10:27 PM, Luis R. Rodriguez <mcgrof@suse.com> wrote:
> On Sun, Nov 16, 2014 at 01:06:00PM +0200, Arik Nemtsov wrote:
>> On Fri, Nov 14, 2014 at 1:11 AM, Luis R. Rodriguez <mcgrof@suse.com> wrote:
>> >> index a4d2792..656a1b1 100644
>> >> --- a/net/wireless/core.c
>> >> +++ b/net/wireless/core.c
>> >> @@ -541,6 +541,13 @@ int wiphy_register(struct wiphy *wiphy)
>> >>                   !wiphy->wowlan->tcp))
>> >>               return -EINVAL;
>> >>  #endif
>> >> +     if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
>> >> +                 (wiphy->regulatory_flags &
>> >> +                  (REGULATORY_CUSTOM_REG | REGULATORY_STRICT_REG |
>> >> +                   REGULATORY_COUNTRY_IE_FOLLOW_POWER |
>> >> +                   REGULATORY_COUNTRY_IE_IGNORE |
>> >> +                   REGULATORY_DISABLE_BEACON_HINTS))))
>> >> +             return -EINVAL;
>> >
>> > Look at all those heuristics go away... That's alot. The documetnation should
>> > reflect all this not being used because of this decision. I also want you to
>> > think of the issues that may come up when combining devices that, one that
>> > uses this feature and one that does not.
>>
>> Since this is a private regdomain, I guess this just means the
>> cfg80211 using device will be alone in the system for all regulatory
>> purposes.
>> I don't really see possible interoperability issues here. Am I missing
>> something?
>
> It means you can technically end up with two devices that operate with
> different interpretation of rules, this can mean for example that some
> expectations of having two devices may fail and since this will be all hard
> coded you can't fix it.  The worst of the issues will be caused by the fact
> that we simply won't know what issues will creep up until the two data sets
> conflict and create an unexpected user facing issue. This is precicely why
> having support for querying information about all regulatory data is critical,
> and I'm glad you are doing that work.
>
> What will happen when say a user / user interface wants to restrict all devices
> to say a country like Israel, 'iw reg set IL' is used, so the cfg80211 regulatory
> abiding devices follow the rules, but this Intel device does not?

It's nice that you've used IL in your example :)

An Intel device would basically stay in mode "00" until the FW decides
via a modem or other indication that it is in IL. At that point we
will send regulatory_hint_regd() notification.
The Intel device doesn't use/trust other devices.

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

Patch

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 220d5f5..dd4f811 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3728,6 +3728,20 @@  const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
 int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 
 /**
+ * regulatory_set_wiphy_regd_rtnl - set regdom info for self managed drivers
+ * @wiphy: the wireless device we want to process the regulatory domain on
+ * @rd: the regulatory domain informatoin to use for this wiphy
+ *
+ * Set the regulatory domain information for self managed drivers, only they
+ * can use this function.
+ * This function requires the caller to hold the rtnl_lock.
+ *
+ * Return: 0 on success. -EINVAL, -EPERM
+ */
+int regulatory_set_wiphy_regd_rtnl(struct wiphy *wiphy,
+				   struct ieee80211_regdomain *rd);
+
+/**
  * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
  * @wiphy: the wireless device we want to process the regulatory domain on
  * @regd: the custom regulatory domain to use for this wiphy
diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index 701177c..42345f4 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -141,6 +141,14 @@  struct regulatory_request {
  *	change, the interfaces are given a grace period to disconnect or move
  *	to an allowed channels. Interfaces on forbidden channels are forcibly
  *	disconnected.
+ * @REGULATORY_WIPHY_SELF_MANAGED: for devices that employ wiphy-specific
+ *	regdom management. These devices will ignore all regdom changes not
+ *	originating from their own wiphy. This flag is incompatible with the
+ *	flags: %REGULATORY_CUSTOM_REG, %REGULATORY_STRICT_REG,
+ *	%REGULATORY_COUNTRY_IE_FOLLOW_POWER, %REGULATORY_COUNTRY_IE_IGNORE and
+ *	%REGULATORY_DISABLE_BEACON_HINTS. Mixing any of the above flags with
+ *	this flag will result in a failure to register the wiphy. This flag
+ *	implies %REGULATORY_DISABLE_BEACON_HINTS.
  */
 enum ieee80211_regulatory_flags {
 	REGULATORY_CUSTOM_REG			= BIT(0),
@@ -150,6 +158,7 @@  enum ieee80211_regulatory_flags {
 	REGULATORY_COUNTRY_IE_IGNORE		= BIT(4),
 	REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
 	REGULATORY_ENFORCE_CHANNELS             = BIT(6),
+	REGULATORY_WIPHY_SELF_MANAGED		= BIT(7),
 };
 
 struct ieee80211_freq_range {
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 442369f..f050dcb 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -762,6 +762,9 @@ 
  * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
  *	network is determined by the network interface.
  *
+ * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
+ *	for indicating changes for devices with wiphy-specific regdom management
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -943,6 +946,8 @@  enum nl80211_commands {
 
 	NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
 
+	NL80211_CMD_WIPHY_REG_CHANGE,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a4d2792..656a1b1 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -541,6 +541,13 @@  int wiphy_register(struct wiphy *wiphy)
 		    !wiphy->wowlan->tcp))
 		return -EINVAL;
 #endif
+	if (WARN_ON((wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) &&
+		    (wiphy->regulatory_flags &
+		     (REGULATORY_CUSTOM_REG | REGULATORY_STRICT_REG |
+		      REGULATORY_COUNTRY_IE_FOLLOW_POWER |
+		      REGULATORY_COUNTRY_IE_IGNORE |
+		      REGULATORY_DISABLE_BEACON_HINTS))))
+		return -EINVAL;
 
 	if (WARN_ON(wiphy->coalesce &&
 		    (!wiphy->coalesce->n_rules ||
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d0a8361..3a422e6 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -10659,25 +10659,9 @@  void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 				NL80211_MCGRP_SCAN, GFP_KERNEL);
 }
 
-/*
- * This can happen on global regulatory changes or device specific settings
- * based on custom world regulatory domains.
- */
-void nl80211_send_reg_change_event(struct regulatory_request *request)
+static bool nl80211_reg_change_event_fill(struct sk_buff *msg,
+					  struct regulatory_request *request)
 {
-	struct sk_buff *msg;
-	void *hdr;
-
-	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!msg)
-		return;
-
-	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
-	if (!hdr) {
-		nlmsg_free(msg);
-		return;
-	}
-
 	/* Userspace can always count this one always being set */
 	if (nla_put_u8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator))
 		goto nla_put_failure;
@@ -10707,6 +10691,66 @@  void nl80211_send_reg_change_event(struct regulatory_request *request)
 	    nla_put_u32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx))
 		goto nla_put_failure;
 
+	return true;
+
+nla_put_failure:
+	return false;
+}
+
+/*
+ * This can happen on global regulatory changes or device specific settings
+ * based on custom world regulatory domains.
+ */
+void nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	if (nl80211_reg_change_event_fill(msg, request) == false)
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	rcu_read_lock();
+	genlmsg_multicast_allns(&nl80211_fam, msg, 0,
+				NL80211_MCGRP_REGULATORY, GFP_ATOMIC);
+	rcu_read_unlock();
+
+	return;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	nlmsg_free(msg);
+}
+
+void nl80211_send_wiphy_reg_change_event(struct regulatory_request *request)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return;
+
+	hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_WIPHY_REG_CHANGE);
+	if (!hdr) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	if (nl80211_reg_change_event_fill(msg, request) == false)
+		goto nla_put_failure;
+
 	genlmsg_end(msg, hdr);
 
 	rcu_read_lock();
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 7ad70d6..b91b9c5 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -18,6 +18,7 @@  void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
 void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
 				     struct net_device *netdev);
 void nl80211_send_reg_change_event(struct regulatory_request *request);
+void nl80211_send_wiphy_reg_change_event(struct regulatory_request *request);
 void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
 			  struct net_device *netdev,
 			  const u8 *buf, size_t len, gfp_t gfp);
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 174d8f82..4ee282d 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1307,6 +1307,9 @@  static bool ignore_reg_update(struct wiphy *wiphy,
 {
 	struct regulatory_request *lr = get_last_request();
 
+	if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+		return true;
+
 	if (!lr) {
 		REG_DBG_PRINT("Ignoring regulatory request set by %s "
 			      "since last_request is not set\n",
@@ -1370,6 +1373,9 @@  static void handle_reg_beacon(struct wiphy *wiphy, unsigned int chan_idx,
 	sband = wiphy->bands[reg_beacon->chan.band];
 	chan = &sband->channels[chan_idx];
 
+	if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+		return;
+
 	if (likely(chan->center_freq != reg_beacon->chan.center_freq))
 		return;
 
@@ -2426,6 +2432,9 @@  static void restore_regulatory_settings(bool reset_user)
 	world_alpha2[1] = cfg80211_world_regdom->alpha2[1];
 
 	list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+		if (rdev->wiphy.regulatory_flags &
+		    REGULATORY_WIPHY_SELF_MANAGED)
+			continue;
 		if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)
 			restore_custom_reg_settings(&rdev->wiphy);
 	}
@@ -2829,6 +2838,56 @@  int set_regdom(const struct ieee80211_regdomain *rd)
 	return 0;
 }
 
+int regulatory_set_wiphy_regd_rtnl(struct wiphy *wiphy,
+				   struct ieee80211_regdomain *rd)
+{
+	const struct ieee80211_regdomain *regd;
+	const struct ieee80211_regdomain *tmp;
+	enum ieee80211_band band;
+	struct regulatory_request request = {};
+
+	if (WARN_ON(!wiphy || !rd))
+		return -EINVAL;
+
+	if (WARN(wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED,
+		 "wiphy should have REGULATORY_WIPHY_SELF_MANAGED\n"))
+		return -EPERM;
+
+	WARN_ON_ONCE(!lockdep_rtnl_is_held());
+
+	if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) {
+		print_regdomain_info(rd);
+		return -EINVAL;
+	}
+
+	regd = reg_copy_regd(rd);
+	if (IS_ERR(regd))
+		return PTR_ERR(regd);
+
+	tmp = get_wiphy_regdom(wiphy);
+	rcu_assign_pointer(wiphy->regd, regd);
+	rcu_free_regdom(tmp);
+
+	for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+		handle_band_custom(wiphy,
+				   wiphy->bands[band],
+				   regd);
+	}
+
+	reg_process_ht_flags(wiphy);
+
+	request.wiphy_idx = get_wiphy_idx(wiphy);
+	request.alpha2[0] = rd->alpha2[0];
+	request.alpha2[1] = rd->alpha2[1];
+	request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+
+	nl80211_send_wiphy_reg_change_event(&request);
+
+	reg_check_channels();
+	return 0;
+}
+EXPORT_SYMBOL(regulatory_set_wiphy_regd_rtnl);
+
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
 	struct regulatory_request *lr;