diff mbox

[v2,1/4] cfg80211: leave invalid channels on regdomain change

Message ID 1415895219-19848-1-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
When the regulatory settings change, some channels might become invalid.
Disconnect interfaces acting on these channels, after giving userspace
code a grace period to leave them.

Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/regulatory.h |   6 +++
 net/wireless/reg.c       | 101 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 106 insertions(+), 1 deletion(-)

Comments

Luis Chamberlain Nov. 13, 2014, 10:45 p.m. UTC | #1
Johannes, Jouni, please review the comment about WLAN_REASON_DEAUTH_LEAVING
below.

On Thu, Nov 13, 2014 at 06:13:36PM +0200, Arik Nemtsov wrote:
> When the regulatory settings change, some channels might become invalid.
> Disconnect interfaces acting on these channels, after giving userspace
> code a grace period to leave them.
> 
> Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com>
> Reviewed-by: Johannes Berg <johannes.berg@intel.com>
> ---
>  include/net/regulatory.h |   6 +++
>  net/wireless/reg.c       | 101 ++++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 106 insertions(+), 1 deletion(-)
> 
> diff --git a/include/net/regulatory.h b/include/net/regulatory.h
> index dad7ab2..701177c 100644
> --- a/include/net/regulatory.h
> +++ b/include/net/regulatory.h
> @@ -136,6 +136,11 @@ struct regulatory_request {
>   *      otherwise initiating radiation is not allowed. This will enable the
>   *      relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
>   *      option
> + * @REGULATORY_ENFORCE_CHANNELS: the regulatory core will make sure all
> + *	interfaces on this wiphy reside on allowed channels. Upon a regdomain
> + *	change, the interfaces are given a grace period to disconnect or move
> + *	to an allowed channels. Interfaces on forbidden channels are forcibly
> + *	disconnected.

I don't like this name, it would seem folks not using this don't
get to enforce channels, and that's not right, this is a feature,
and in fact I am not sure why this is being implemented as optional
rather than a standard feature. Care to explain the reasoning there?

> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> index 7449a8c..6459ddd 100644
> --- a/net/wireless/reg.c
> +++ b/net/wireless/reg.c
> @@ -56,6 +56,7 @@
>  #include <net/cfg80211.h>
>  #include "core.h"
>  #include "reg.h"
> +#include "rdev-ops.h"
>  #include "regdb.h"
>  #include "nl80211.h"
>  
> @@ -66,6 +67,12 @@
>  #define REG_DBG_PRINT(args...)
>  #endif
>  
> +/*
> + * Grace period we give before making sure all current interfaces reside on
> + * channels allowed by the current regulatory domain.
> + */
> +#define REG_ENFORCE_GRACE_MS 60000
> +
>  /**
>   * enum reg_request_treatment - regulatory request treatment
>   *
> @@ -210,6 +217,9 @@ struct reg_beacon {
>  	struct ieee80211_channel chan;
>  };
>  
> +static void reg_check_chans_work(struct work_struct *work);
> +static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
> +
>  static void reg_todo(struct work_struct *work);
>  static DECLARE_WORK(reg_work, reg_todo);
>  
> @@ -1518,6 +1528,90 @@ static void reg_call_notifier(struct wiphy *wiphy,
>  		wiphy->reg_notifier(wiphy, request);
>  }
>  
> +static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
> +{
> +	struct ieee80211_channel *ch;
> +	struct cfg80211_chan_def chandef;
> +	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
> +	bool ret = true;
> +
> +	wdev_lock(wdev);
> +
> +	if (!wdev->netdev || !netif_running(wdev->netdev))
> +		goto out;
> +
> +	switch (wdev->iftype) {
> +	case NL80211_IFTYPE_AP:
> +	case NL80211_IFTYPE_P2P_GO:
> +		if (!wdev->beacon_interval)
> +			goto out;
> +
> +		ret = cfg80211_reg_can_beacon(wiphy,
> +					      &wdev->chandef, wdev->iftype);
> +		break;
> +	case NL80211_IFTYPE_STATION:
> +	case NL80211_IFTYPE_P2P_CLIENT:
> +		if (!wdev->current_bss ||
> +		    !wdev->current_bss->pub.channel)
> +			goto out;
> +
> +		ch = wdev->current_bss->pub.channel;
> +		if (rdev->ops->get_channel &&
> +		    !rdev_get_channel(rdev, wdev, &chandef))
> +			ret = cfg80211_chandef_usable(wiphy, &chandef,
> +						      IEEE80211_CHAN_DISABLED);
> +		else
> +			ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
> +		break;
> +	default:
> +		/* others not implemented for now */
> +		pr_info("Regulatory channel check not implemented for mode %d\n",
> +			wdev->iftype);

I feel you are being lazy here, come on, think of it and address it.
It can't be that hard. In fact cfg80211_leave() already deals with
all the logic to leave properly for all types of interfaces, you
just have to come up with the logic to know things should kick
the device off. Its not that hard.

> +		break;
> +	}
> +
> +out:
> +	wdev_unlock(wdev);
> +	return ret;
> +}
> +
> +static void reg_leave_invalid_chans(struct wiphy *wiphy)
> +{
> +	struct wireless_dev *wdev;
> +	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
> +
> +	ASSERT_RTNL();
> +
> +	list_for_each_entry(wdev, &rdev->wdev_list, list)
> +		if (!reg_wdev_chan_valid(wiphy, wdev))
> +			cfg80211_leave(rdev, wdev);
> +}

Kind of sad we only have WLAN_REASON_DEAUTH_LEAVING and we
only use this for STAs. You are providing an event for
this trigger so could be understood by the supplicant that
this happened for this reason but I think it'd be a lot
nicer to unify this as part of a disconnect. Johannes,
Jouni, thought?

  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 a.m. UTC | #2
On Fri, Nov 14, 2014 at 12:45 AM, Luis R. Rodriguez <mcgrof@suse.com> wrote:
>> + * @REGULATORY_ENFORCE_CHANNELS: the regulatory core will make sure all
>> + *   interfaces on this wiphy reside on allowed channels. Upon a regdomain
>> + *   change, the interfaces are given a grace period to disconnect or move
>> + *   to an allowed channels. Interfaces on forbidden channels are forcibly
>> + *   disconnected.
>
> I don't like this name, it would seem folks not using this don't
> get to enforce channels, and that's not right, this is a feature,
> and in fact I am not sure why this is being implemented as optional
> rather than a standard feature. Care to explain the reasoning there?

This is a big change in behavior. It can hurt certification tests etc.
I believe a chip vendor should opt-in for this change. Otherwise we
risk bad user experience.

>
>> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
>> index 7449a8c..6459ddd 100644
>> --- a/net/wireless/reg.c
>> +++ b/net/wireless/reg.c
>> @@ -56,6 +56,7 @@
>>  #include <net/cfg80211.h>
>>  #include "core.h"
>>  #include "reg.h"
>> +#include "rdev-ops.h"
>>  #include "regdb.h"
>>  #include "nl80211.h"
>>
>> @@ -66,6 +67,12 @@
>>  #define REG_DBG_PRINT(args...)
>>  #endif
>>
>> +/*
>> + * Grace period we give before making sure all current interfaces reside on
>> + * channels allowed by the current regulatory domain.
>> + */
>> +#define REG_ENFORCE_GRACE_MS 60000
>> +
>>  /**
>>   * enum reg_request_treatment - regulatory request treatment
>>   *
>> @@ -210,6 +217,9 @@ struct reg_beacon {
>>       struct ieee80211_channel chan;
>>  };
>>
>> +static void reg_check_chans_work(struct work_struct *work);
>> +static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
>> +
>>  static void reg_todo(struct work_struct *work);
>>  static DECLARE_WORK(reg_work, reg_todo);
>>
>> @@ -1518,6 +1528,90 @@ static void reg_call_notifier(struct wiphy *wiphy,
>>               wiphy->reg_notifier(wiphy, request);
>>  }
>>
>> +static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
>> +{
>> +     struct ieee80211_channel *ch;
>> +     struct cfg80211_chan_def chandef;
>> +     struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
>> +     bool ret = true;
>> +
>> +     wdev_lock(wdev);
>> +
>> +     if (!wdev->netdev || !netif_running(wdev->netdev))
>> +             goto out;
>> +
>> +     switch (wdev->iftype) {
>> +     case NL80211_IFTYPE_AP:
>> +     case NL80211_IFTYPE_P2P_GO:
>> +             if (!wdev->beacon_interval)
>> +                     goto out;
>> +
>> +             ret = cfg80211_reg_can_beacon(wiphy,
>> +                                           &wdev->chandef, wdev->iftype);
>> +             break;
>> +     case NL80211_IFTYPE_STATION:
>> +     case NL80211_IFTYPE_P2P_CLIENT:
>> +             if (!wdev->current_bss ||
>> +                 !wdev->current_bss->pub.channel)
>> +                     goto out;
>> +
>> +             ch = wdev->current_bss->pub.channel;
>> +             if (rdev->ops->get_channel &&
>> +                 !rdev_get_channel(rdev, wdev, &chandef))
>> +                     ret = cfg80211_chandef_usable(wiphy, &chandef,
>> +                                                   IEEE80211_CHAN_DISABLED);
>> +             else
>> +                     ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
>> +             break;
>> +     default:
>> +             /* others not implemented for now */
>> +             pr_info("Regulatory channel check not implemented for mode %d\n",
>> +                     wdev->iftype);
>
> I feel you are being lazy here, come on, think of it and address it.
> It can't be that hard. In fact cfg80211_leave() already deals with
> all the logic to leave properly for all types of interfaces, you
> just have to come up with the logic to know things should kick
> the device off. Its not that hard.

I don't want to add modes I cannot test with HW I have. I think that's
irresponsible, especially when the side-effects are disconnections.
I can add IBSS as well with the HW I have, but that's about it.

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
Johannes Berg Nov. 20, 2014, 3:17 p.m. UTC | #3
On Thu, 2014-11-13 at 18:13 +0200, Arik Nemtsov wrote:
> When the regulatory settings change, some channels might become invalid.
> Disconnect interfaces acting on these channels, after giving userspace
> code a grace period to leave them.

So as we discussed, I think you should add a note here that the flag
only works for some interface types, and prohibit setting the flag when
unsupported ones are supported. Then you can also remove the message and
just put in a WARN_ON(1) or something since you can't really get to that
code path.

IMHO that's a reasonable trade-off between generalisation and not doing
all the work now especially since you can't validate it over Intel hw
for other interface types - if anyone else needs/wants the flag then
they can add those interface types and change the conditions.

johannes

--
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
Johannes Berg Nov. 20, 2014, 3:17 p.m. UTC | #4
On Sun, 2014-11-16 at 13:00 +0200, Arik Nemtsov wrote:

> I don't want to add modes I cannot test with HW I have. I think that's
> irresponsible, especially when the side-effects are disconnections.
> I can add IBSS as well with the HW I have, but that's about it.

Oops, my other reply was meant to go here...

johannes

--
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:35 p.m. UTC | #5
On Sun, Nov 16, 2014 at 01:00:16PM +0200, Arik Nemtsov wrote:
> On Fri, Nov 14, 2014 at 12:45 AM, Luis R. Rodriguez <mcgrof@suse.com> wrote:
> >> + * @REGULATORY_ENFORCE_CHANNELS: the regulatory core will make sure all
> >> + *   interfaces on this wiphy reside on allowed channels. Upon a regdomain
> >> + *   change, the interfaces are given a grace period to disconnect or move
> >> + *   to an allowed channels. Interfaces on forbidden channels are forcibly
> >> + *   disconnected.
> >
> > I don't like this name, it would seem folks not using this don't
> > get to enforce channels, and that's not right, this is a feature,
> > and in fact I am not sure why this is being implemented as optional
> > rather than a standard feature. Care to explain the reasoning there?
> 
> This is a big change in behavior. It can hurt certification tests etc.
> I believe a chip vendor should opt-in for this change. Otherwise we
> risk bad user experience.

It really should only kick you off of channels you are not allowed to use,
I welcome this change and think it is important as a standard feature.
Please rename to REGULATORY_IGNORE_STALE_KICKOFF and make the behaviour
change to ignore the kick off rather than opt-in. We take measures to
operate properly regulatory and this change helps in that direction, we
want opt-in features to let folks that know what they are doing ingore
certain fatures.

> >> diff --git a/net/wireless/reg.c b/net/wireless/reg.c
> >> index 7449a8c..6459ddd 100644
> >> --- a/net/wireless/reg.c
> >> +++ b/net/wireless/reg.c
> >> @@ -56,6 +56,7 @@
> >>  #include <net/cfg80211.h>
> >>  #include "core.h"
> >>  #include "reg.h"
> >> +#include "rdev-ops.h"
> >>  #include "regdb.h"
> >>  #include "nl80211.h"
> >>
> >> @@ -66,6 +67,12 @@
> >>  #define REG_DBG_PRINT(args...)
> >>  #endif
> >>
> >> +/*
> >> + * Grace period we give before making sure all current interfaces reside on
> >> + * channels allowed by the current regulatory domain.
> >> + */
> >> +#define REG_ENFORCE_GRACE_MS 60000
> >> +
> >>  /**
> >>   * enum reg_request_treatment - regulatory request treatment
> >>   *
> >> @@ -210,6 +217,9 @@ struct reg_beacon {
> >>       struct ieee80211_channel chan;
> >>  };
> >>
> >> +static void reg_check_chans_work(struct work_struct *work);
> >> +static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
> >> +
> >>  static void reg_todo(struct work_struct *work);
> >>  static DECLARE_WORK(reg_work, reg_todo);
> >>
> >> @@ -1518,6 +1528,90 @@ static void reg_call_notifier(struct wiphy *wiphy,
> >>               wiphy->reg_notifier(wiphy, request);
> >>  }
> >>
> >> +static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
> >> +{
> >> +     struct ieee80211_channel *ch;
> >> +     struct cfg80211_chan_def chandef;
> >> +     struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
> >> +     bool ret = true;
> >> +
> >> +     wdev_lock(wdev);
> >> +
> >> +     if (!wdev->netdev || !netif_running(wdev->netdev))
> >> +             goto out;
> >> +
> >> +     switch (wdev->iftype) {
> >> +     case NL80211_IFTYPE_AP:
> >> +     case NL80211_IFTYPE_P2P_GO:
> >> +             if (!wdev->beacon_interval)
> >> +                     goto out;
> >> +
> >> +             ret = cfg80211_reg_can_beacon(wiphy,
> >> +                                           &wdev->chandef, wdev->iftype);
> >> +             break;
> >> +     case NL80211_IFTYPE_STATION:
> >> +     case NL80211_IFTYPE_P2P_CLIENT:
> >> +             if (!wdev->current_bss ||
> >> +                 !wdev->current_bss->pub.channel)
> >> +                     goto out;
> >> +
> >> +             ch = wdev->current_bss->pub.channel;
> >> +             if (rdev->ops->get_channel &&
> >> +                 !rdev_get_channel(rdev, wdev, &chandef))
> >> +                     ret = cfg80211_chandef_usable(wiphy, &chandef,
> >> +                                                   IEEE80211_CHAN_DISABLED);
> >> +             else
> >> +                     ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
> >> +             break;
> >> +     default:
> >> +             /* others not implemented for now */
> >> +             pr_info("Regulatory channel check not implemented for mode %d\n",
> >> +                     wdev->iftype);
> >
> > I feel you are being lazy here, come on, think of it and address it.
> > It can't be that hard. In fact cfg80211_leave() already deals with
> > all the logic to leave properly for all types of interfaces, you
> > just have to come up with the logic to know things should kick
> > the device off. Its not that hard.
> 
> I don't want to add modes I cannot test with HW I have. I think that's
> irresponsible, especially when the side-effects are disconnections.
> I can add IBSS as well with the HW I have, but that's about it.

I'd like to see IBSS and Mesh considered and addressed.

  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
Luis Chamberlain Nov. 20, 2014, 8:38 p.m. UTC | #6
On Thu, Nov 20, 2014 at 04:17:00PM +0100, Johannes Berg wrote:
> On Thu, 2014-11-13 at 18:13 +0200, Arik Nemtsov wrote:
> > When the regulatory settings change, some channels might become invalid.
> > Disconnect interfaces acting on these channels, after giving userspace
> > code a grace period to leave them.
> 
> So as we discussed, I think you should add a note here that the flag
> only works for some interface types, and prohibit setting the flag when
> unsupported ones are supported. Then you can also remove the message and
> just put in a WARN_ON(1) or something since you can't really get to that
> code path.
> 
> IMHO that's a reasonable trade-off between generalisation and not doing
> all the work now especially since you can't validate it over Intel hw
> for other interface types - if anyone else needs/wants the flag then
> they can add those interface types and change the conditions.

I'd prefer to see this addressed if possible and the flag to let one to
opt out rather than opt in.

  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
Johannes Berg Nov. 20, 2014, 8:38 p.m. UTC | #7
On Thu, 2014-11-20 at 21:35 +0100, Luis R. Rodriguez wrote:

> It really should only kick you off of channels you are not allowed to use,
> I welcome this change and think it is important as a standard feature.
> Please rename to REGULATORY_IGNORE_STALE_KICKOFF and make the behaviour
> change to ignore the kick off rather than opt-in. We take measures to
> operate properly regulatory and this change helps in that direction, we
> want opt-in features to let folks that know what they are doing ingore
> certain fatures.

> > I don't want to add modes I cannot test with HW I have. I think that's
> > irresponsible, especially when the side-effects are disconnections.
> > I can add IBSS as well with the HW I have, but that's about it.
> 
> I'd like to see IBSS and Mesh considered and addressed.

And I want a cookie :-)

I outlined what I'll accept in my other email, and since I think it's
unreasonable to force Arik to revamp the whole thing the behaviour will
have to stay opt-in, at least until all modes are addressed, at which
point the flag could even go away.

johannes

--
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:56 p.m. UTC | #8
On Thu, Nov 20, 2014 at 09:38:53PM +0100, Johannes Berg wrote:
> On Thu, 2014-11-20 at 21:35 +0100, Luis R. Rodriguez wrote:
> 
> > It really should only kick you off of channels you are not allowed to use,
> > I welcome this change and think it is important as a standard feature.
> > Please rename to REGULATORY_IGNORE_STALE_KICKOFF and make the behaviour
> > change to ignore the kick off rather than opt-in. We take measures to
> > operate properly regulatory and this change helps in that direction, we
> > want opt-in features to let folks that know what they are doing ingore
> > certain fatures.
> 
> > > I don't want to add modes I cannot test with HW I have. I think that's
> > > irresponsible, especially when the side-effects are disconnections.
> > > I can add IBSS as well with the HW I have, but that's about it.
> > 
> > I'd like to see IBSS and Mesh considered and addressed.
> 
> And I want a cookie :-)
> 
> I outlined what I'll accept in my other email, and since I think it's
> unreasonable to force Arik to revamp the whole thing the behaviour will
> have to stay opt-in, at least until all modes are addressed, at which
> point the flag could even go away.

Fine..

  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
diff mbox

Patch

diff --git a/include/net/regulatory.h b/include/net/regulatory.h
index dad7ab2..701177c 100644
--- a/include/net/regulatory.h
+++ b/include/net/regulatory.h
@@ -136,6 +136,11 @@  struct regulatory_request {
  *      otherwise initiating radiation is not allowed. This will enable the
  *      relaxations enabled under the CFG80211_REG_RELAX_NO_IR configuration
  *      option
+ * @REGULATORY_ENFORCE_CHANNELS: the regulatory core will make sure all
+ *	interfaces on this wiphy reside on allowed channels. Upon a regdomain
+ *	change, the interfaces are given a grace period to disconnect or move
+ *	to an allowed channels. Interfaces on forbidden channels are forcibly
+ *	disconnected.
  */
 enum ieee80211_regulatory_flags {
 	REGULATORY_CUSTOM_REG			= BIT(0),
@@ -144,6 +149,7 @@  enum ieee80211_regulatory_flags {
 	REGULATORY_COUNTRY_IE_FOLLOW_POWER	= BIT(3),
 	REGULATORY_COUNTRY_IE_IGNORE		= BIT(4),
 	REGULATORY_ENABLE_RELAX_NO_IR           = BIT(5),
+	REGULATORY_ENFORCE_CHANNELS             = BIT(6),
 };
 
 struct ieee80211_freq_range {
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 7449a8c..6459ddd 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -56,6 +56,7 @@ 
 #include <net/cfg80211.h>
 #include "core.h"
 #include "reg.h"
+#include "rdev-ops.h"
 #include "regdb.h"
 #include "nl80211.h"
 
@@ -66,6 +67,12 @@ 
 #define REG_DBG_PRINT(args...)
 #endif
 
+/*
+ * Grace period we give before making sure all current interfaces reside on
+ * channels allowed by the current regulatory domain.
+ */
+#define REG_ENFORCE_GRACE_MS 60000
+
 /**
  * enum reg_request_treatment - regulatory request treatment
  *
@@ -210,6 +217,9 @@  struct reg_beacon {
 	struct ieee80211_channel chan;
 };
 
+static void reg_check_chans_work(struct work_struct *work);
+static DECLARE_DELAYED_WORK(reg_check_chans, reg_check_chans_work);
+
 static void reg_todo(struct work_struct *work);
 static DECLARE_WORK(reg_work, reg_todo);
 
@@ -1518,6 +1528,90 @@  static void reg_call_notifier(struct wiphy *wiphy,
 		wiphy->reg_notifier(wiphy, request);
 }
 
+static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+	struct ieee80211_channel *ch;
+	struct cfg80211_chan_def chandef;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	bool ret = true;
+
+	wdev_lock(wdev);
+
+	if (!wdev->netdev || !netif_running(wdev->netdev))
+		goto out;
+
+	switch (wdev->iftype) {
+	case NL80211_IFTYPE_AP:
+	case NL80211_IFTYPE_P2P_GO:
+		if (!wdev->beacon_interval)
+			goto out;
+
+		ret = cfg80211_reg_can_beacon(wiphy,
+					      &wdev->chandef, wdev->iftype);
+		break;
+	case NL80211_IFTYPE_STATION:
+	case NL80211_IFTYPE_P2P_CLIENT:
+		if (!wdev->current_bss ||
+		    !wdev->current_bss->pub.channel)
+			goto out;
+
+		ch = wdev->current_bss->pub.channel;
+		if (rdev->ops->get_channel &&
+		    !rdev_get_channel(rdev, wdev, &chandef))
+			ret = cfg80211_chandef_usable(wiphy, &chandef,
+						      IEEE80211_CHAN_DISABLED);
+		else
+			ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
+		break;
+	default:
+		/* others not implemented for now */
+		pr_info("Regulatory channel check not implemented for mode %d\n",
+			wdev->iftype);
+		break;
+	}
+
+out:
+	wdev_unlock(wdev);
+	return ret;
+}
+
+static void reg_leave_invalid_chans(struct wiphy *wiphy)
+{
+	struct wireless_dev *wdev;
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+	ASSERT_RTNL();
+
+	list_for_each_entry(wdev, &rdev->wdev_list, list)
+		if (!reg_wdev_chan_valid(wiphy, wdev))
+			cfg80211_leave(rdev, wdev);
+}
+
+static void reg_check_chans_work(struct work_struct *work)
+{
+	struct cfg80211_registered_device *rdev;
+
+	REG_DBG_PRINT("Verifying active interfaces after reg change\n");
+	rtnl_lock();
+
+	list_for_each_entry(rdev, &cfg80211_rdev_list, list)
+		if (rdev->wiphy.regulatory_flags & REGULATORY_ENFORCE_CHANNELS)
+			reg_leave_invalid_chans(&rdev->wiphy);
+
+	rtnl_unlock();
+}
+
+static void reg_check_channels(void)
+{
+	/*
+	 * Give usermode a chance to do something nicer (move to another
+	 * channel, orderly disconnection), before forcing a disconnection.
+	 */
+	mod_delayed_work(system_power_efficient_wq,
+			 &reg_check_chans,
+			 msecs_to_jiffies(REG_ENFORCE_GRACE_MS));
+}
+
 static void wiphy_update_regulatory(struct wiphy *wiphy,
 				    enum nl80211_reg_initiator initiator)
 {
@@ -1557,6 +1651,8 @@  static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
 		wiphy = &rdev->wiphy;
 		wiphy_update_regulatory(wiphy, initiator);
 	}
+
+	reg_check_channels();
 }
 
 static void handle_channel_custom(struct wiphy *wiphy,
@@ -1963,8 +2059,10 @@  static void reg_process_hint(struct regulatory_request *reg_request)
 
 	/* This is required so that the orig_* parameters are saved */
 	if (treatment == REG_REQ_ALREADY_SET && wiphy &&
-	    wiphy->regulatory_flags & REGULATORY_STRICT_REG)
+	    wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
 		wiphy_update_regulatory(wiphy, reg_request->initiator);
+		reg_check_channels();
+	}
 
 	return;
 
@@ -2845,6 +2943,7 @@  void regulatory_exit(void)
 
 	cancel_work_sync(&reg_work);
 	cancel_delayed_work_sync(&reg_timeout);
+	cancel_delayed_work_sync(&reg_check_chans);
 
 	/* Lock to suppress warnings */
 	rtnl_lock();