Currently irrespective of dfs domain and radar detection activity
pre-CAC results for a wiphy are retained till the wiphy is detroyed.
This may not be preferred in non-ETSI dfs domain where pre-CAC is not
explicitly mentioned in the respective DFS requirement spec. This patch
set modifies the current behaviour of pre-CAC for non-ETSI domain by
giving 2 seconds grace period for dfs master interface to start operating
on the CAC completed channel.
This patch set also adds support to share dfs channel state across
multiple radios of the same regulatory configuration.
Vasanthakumar Thiagarajan (3):
cfg80211: Make pre-CAC results valid only for ETSI domain
cfg80211: Disallow moving out of operating DFS channel in non-ETSI
cfg80211: Share Channel DFS state across wiphys of same DFS domain
include/uapi/linux/nl80211.h | 5 ++
net/wireless/ap.c | 5 ++
net/wireless/chan.c | 112 ++++++++++++++++++++++++++++++
net/wireless/core.c | 37 ++++++++++
net/wireless/core.h | 13 ++++
net/wireless/ibss.c | 1 +
net/wireless/mesh.c | 1 +
net/wireless/mlme.c | 52 +++++++++++---
net/wireless/nl80211.c | 38 +++++++++++
net/wireless/reg.c | 159 +++++++++++++++++++++++++++++++++++++++++++
net/wireless/reg.h | 36 ++++++++++
11 files changed, 449 insertions(+), 10 deletions(-)
--
1.9.1
DFS requirement for ETSI domain (section 4.7.1.4 in
ETSI EN 301 893 V1.8.1) is the only one which explicitly
states that once DFS channel is marked as available afer
the CAC, this channel will remain in available state even
moving to a different operating channel. But the same is
not explicitly stated in FCC DFS requirement. Also, Pre-CAC
requriements are not explicitly mentioned in FCC requirement.
Current implementation in keeping DFS channel in available
state is same as described in ETSI domain.
For ETSI DFS domain, this patch gives a grace period of 2 seconds
since the completion of successful CAC before moving the channel's
DFS state to 'usable' from 'available' state. The same grace period
is checked against the channel's dfs_state_entered timestamp while
deciding if a DFS channel is available for operation. There is a new
radar event, NL80211_RADAR_PRE_CAC_EXPIRED, reported when DFS channel
is moved from available to usable state after the grace period. Also
make sure the DFS channel state is reset to usable once the beaconing
operation on that channel is brought down (like stop_ap, leave_ibss
and leave_mesh) in non-ETSI domain.
Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
---
include/uapi/linux/nl80211.h | 5 +++
net/wireless/ap.c | 5 +++
net/wireless/chan.c | 96 ++++++++++++++++++++++++++++++++++++++++++++
net/wireless/core.h | 7 ++++
net/wireless/ibss.c | 1 +
net/wireless/mesh.c | 1 +
net/wireless/mlme.c | 41 ++++++++++++++-----
net/wireless/reg.c | 47 ++++++++++++++++++++++
net/wireless/reg.h | 14 +++++++
9 files changed, 208 insertions(+), 9 deletions(-)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d6c62ee..9d2d2b1 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -4893,12 +4893,17 @@ enum nl80211_smps_mode {
* change to the channel status.
* @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is
* over, channel becomes usable.
+ * @NL80211_RADAR_PRE_CAC_EXPIRED: Channel Availability Check done on this
+ * non-operating channel is expired and no longer valid. New CAC must
+ * be done on this channel before starting the operation. This is not
+ * applicable for ETSI dfs domain where pre-CAC is valid for ever.
*/
enum nl80211_radar_event {
NL80211_RADAR_DETECTED,
NL80211_RADAR_CAC_FINISHED,
NL80211_RADAR_CAC_ABORTED,
NL80211_RADAR_NOP_FINISHED,
+ NL80211_RADAR_PRE_CAC_EXPIRED,
};
/**
diff --git a/net/wireless/ap.c b/net/wireless/ap.c
index bdad1f9..25666d3 100644
--- a/net/wireless/ap.c
+++ b/net/wireless/ap.c
@@ -32,6 +32,11 @@ int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
rdev_set_qos_map(rdev, dev, NULL);
if (notify)
nl80211_send_ap_stopped(wdev);
+
+ /* Should we apply the grace period during beaconing interface
+ * shutdown also?
+ */
+ cfg80211_sched_dfs_chan_update(rdev);
}
return err;
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 5497d022..090309a 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -456,6 +456,102 @@ bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
return (r1 + r2 > 0);
}
+static bool cfg80211_5ghz_sub_chan(struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel *chan)
+{
+ u32 start_freq_seg0 = 0, end_freq_seg0 = 0;
+ u32 start_freq_seg1 = 0, end_freq_seg1 = 0;
+
+ if (chandef->chan->center_freq == chan->center_freq)
+ return true;
+
+ switch (chandef->width) {
+ case NL80211_CHAN_WIDTH_40:
+ start_freq_seg0 = chandef->center_freq1 - 20;
+ end_freq_seg0 = chandef->center_freq1 + 20;
+ break;
+ case NL80211_CHAN_WIDTH_80P80:
+ start_freq_seg1 = chandef->center_freq2 - 40;
+ end_freq_seg1 = chandef->center_freq2 + 40;
+ /* fall through */
+ case NL80211_CHAN_WIDTH_80:
+ start_freq_seg0 = chandef->center_freq1 - 40;
+ end_freq_seg0 = chandef->center_freq1 + 40;
+ break;
+ case NL80211_CHAN_WIDTH_160:
+ start_freq_seg0 = chandef->center_freq1 - 80;
+ end_freq_seg0 = chandef->center_freq1 + 80;
+ break;
+ case NL80211_CHAN_WIDTH_20_NOHT:
+ case NL80211_CHAN_WIDTH_20:
+ case NL80211_CHAN_WIDTH_5:
+ case NL80211_CHAN_WIDTH_10:
+ break;
+ }
+
+ if (chan->center_freq > start_freq_seg0 &&
+ chan->center_freq < end_freq_seg0)
+ return true;
+
+ return chan->center_freq > start_freq_seg1 &&
+ chan->center_freq < end_freq_seg1;
+}
+
+bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
+{
+ bool active = false;
+
+ if (!wdev->chandef.chan)
+ return false;
+
+ switch (wdev->iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ active = wdev->beacon_interval != 0;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ active = wdev->ssid_len != 0;
+ break;
+ case NL80211_IFTYPE_MESH_POINT:
+ active = wdev->mesh_id_len != 0;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_OCB:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_MONITOR:
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_WDS:
+ case NL80211_IFTYPE_P2P_DEVICE:
+ case NL80211_IFTYPE_NAN:
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NUM_NL80211_IFTYPES:
+ WARN_ON(1);
+ }
+
+ return active;
+}
+
+bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
+ struct ieee80211_channel *chan)
+{
+ struct wireless_dev *wdev;
+
+ ASSERT_RTNL();
+
+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
+ return false;
+
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
+ if (!cfg80211_beaconing_iface_active(wdev))
+ continue;
+
+ if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
+ return true;
+ }
+
+ return false;
+}
static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
u32 center_freq,
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 58ca206..327fe95 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -459,6 +459,13 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
const struct cfg80211_chan_def *chandef);
+void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
+
+bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
+ struct ieee80211_channel *chan);
+
+bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev);
+
static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
{
unsigned long end = jiffies;
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 364f900..10bf040 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -190,6 +190,7 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
if (!nowext)
wdev->wext.ibss.ssid_len = 0;
#endif
+ cfg80211_sched_dfs_chan_update(rdev);
}
void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
index 2d8518a..ec0b1c2 100644
--- a/net/wireless/mesh.c
+++ b/net/wireless/mesh.c
@@ -262,6 +262,7 @@ int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
wdev->beacon_interval = 0;
memset(&wdev->chandef, 0, sizeof(wdev->chandef));
rdev_set_qos_map(rdev, dev, NULL);
+ cfg80211_sched_dfs_chan_update(rdev);
}
return err;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 22b3d99..3c7e155 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -745,6 +745,12 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm,
}
EXPORT_SYMBOL(cfg80211_rx_mgmt);
+void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev)
+{
+ cancel_delayed_work(&rdev->dfs_update_channels_wk);
+ queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk, 0);
+}
+
void cfg80211_dfs_channels_update_work(struct work_struct *work)
{
struct delayed_work *delayed_work = to_delayed_work(work);
@@ -755,6 +761,8 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
struct wiphy *wiphy;
bool check_again = false;
unsigned long timeout, next_time = 0;
+ unsigned long time_dfs_update;
+ enum nl80211_radar_event radar_event;
int bandid, i;
rdev = container_of(delayed_work, struct cfg80211_registered_device,
@@ -770,11 +778,28 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
for (i = 0; i < sband->n_channels; i++) {
c = &sband->channels[i];
- if (c->dfs_state != NL80211_DFS_UNAVAILABLE)
+ if (!(c->flags & IEEE80211_CHAN_RADAR))
+ continue;
+
+ if (c->dfs_state != NL80211_DFS_UNAVAILABLE &&
+ c->dfs_state != NL80211_DFS_AVAILABLE)
continue;
- timeout = c->dfs_state_entered + msecs_to_jiffies(
- IEEE80211_DFS_MIN_NOP_TIME_MS);
+ if (c->dfs_state == NL80211_DFS_UNAVAILABLE) {
+ time_dfs_update = IEEE80211_DFS_MIN_NOP_TIME_MS;
+ radar_event = NL80211_RADAR_NOP_FINISHED;
+ } else {
+ if (regulatory_pre_cac_allowed(wiphy) ||
+ cfg80211_5ghz_any_wiphy_oper_chan(wiphy, c))
+ continue;
+
+ time_dfs_update =
+ regulatory_get_pre_cac_timeout(wiphy);
+ radar_event = NL80211_RADAR_PRE_CAC_EXPIRED;
+ }
+
+ timeout = c->dfs_state_entered +
+ msecs_to_jiffies(time_dfs_update);
if (time_after_eq(jiffies, timeout)) {
c->dfs_state = NL80211_DFS_USABLE;
@@ -784,8 +809,8 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
NL80211_CHAN_NO_HT);
nl80211_radar_notify(rdev, &chandef,
- NL80211_RADAR_NOP_FINISHED,
- NULL, GFP_ATOMIC);
+ radar_event, NULL,
+ GFP_ATOMIC);
continue;
}
@@ -810,7 +835,6 @@ void cfg80211_radar_event(struct wiphy *wiphy,
gfp_t gfp)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
- unsigned long timeout;
trace_cfg80211_radar_event(wiphy, chandef);
@@ -820,9 +844,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
*/
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
- timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
- queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
- timeout);
+ cfg80211_sched_dfs_chan_update(rdev);
nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
}
@@ -851,6 +873,7 @@ void cfg80211_cac_event(struct net_device *netdev,
msecs_to_jiffies(wdev->cac_time_ms);
WARN_ON(!time_after_eq(jiffies, timeout));
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
+ cfg80211_sched_dfs_chan_update(rdev);
break;
case NL80211_RADAR_CAC_ABORTED:
break;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 753efcd..6d0d004 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -3120,6 +3120,53 @@ bool regulatory_indoor_allowed(void)
return reg_is_indoor;
}
+/*
+ * Grace period to timeout pre-CAC results on the dfs channels. This timeout
+ * value is used for Non-ETSI domain.
+ * TODO: May be make this timeout available through regdb?
+ */
+#define REG_PRE_CAC_EXPIRY_GRACE_MS 2000
+
+bool regulatory_pre_cac_allowed(struct wiphy *wiphy)
+{
+ const struct ieee80211_regdomain *regd = NULL;
+ const struct ieee80211_regdomain *wiphy_regd = NULL;
+ bool pre_cac_allowed = false;
+
+ rcu_read_lock();
+
+ regd = rcu_dereference(cfg80211_regdomain);
+ wiphy_regd = rcu_dereference(wiphy->regd);
+ if (!wiphy_regd) {
+ if (regd->dfs_region == NL80211_DFS_ETSI)
+ pre_cac_allowed = true;
+
+ rcu_read_unlock();
+
+ return pre_cac_allowed;
+ }
+
+ if (regd->dfs_region == wiphy_regd->dfs_region &&
+ wiphy_regd->dfs_region == NL80211_DFS_ETSI)
+ pre_cac_allowed = true;
+
+ rcu_read_unlock();
+
+ return pre_cac_allowed;
+}
+
+unsigned long regulatory_get_pre_cac_timeout(struct wiphy *wiphy)
+{
+ if (!regulatory_pre_cac_allowed(wiphy))
+ return REG_PRE_CAC_EXPIRY_GRACE_MS;
+
+ /*
+ * Return the maximum pre-CAC timeout when pre-CAC is allowed
+ * in the current dfs domain (ETSI).
+ */
+ return -1;
+}
+
int __init regulatory_init(void)
{
int err = 0;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index f6ced31..1fded3d 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -143,4 +143,18 @@ void regulatory_hint_country_ie(struct wiphy *wiphy,
*/
bool regulatory_indoor_allowed(void);
+/**
+ * regulatory_pre_cac_allowed - if pre-CAC allowed in the current dfs domain
+ * @wiphy: wiphy for which pre-CAC capability is checked.
+
+ * Pre-CAC is allowed only in ETSI domain.
+ */
+bool regulatory_pre_cac_allowed(struct wiphy *wiphy);
+
+/**
+ * regulatory_get_pre_cac_timeout - time in msec to timeout pre-CAC results
+ * @wiphy: wiphy for which pre-CAC timeout is needed. This timeout value is
+ * applied on the dfs channels associated to this wiphy.
+ */
+unsigned long regulatory_get_pre_cac_timeout(struct wiphy *wiphy);
#endif /* __NET_WIRELESS_REG_H */
--
1.9.1
> + /* Should we apply the grace period during beaconing
> interface
> + * shutdown also?
> + */
> + cfg80211_sched_dfs_chan_update(rdev);
It might make some sense, say if hostapd crashes and you restart it
automatically or something?
> return err;
> diff --git a/net/wireless/chan.c b/net/wireless/chan.c
> index 5497d022..090309a 100644
> --- a/net/wireless/chan.c
> +++ b/net/wireless/chan.c
> @@ -456,6 +456,102 @@ bool cfg80211_chandef_dfs_usable(struct wiphy
> *wiphy,
> return (r1 + r2 > 0);
> }
>
> +static bool cfg80211_5ghz_sub_chan(struct cfg80211_chan_def
> *chandef,
> + struct ieee80211_channel *chan)
This could use some explanation, and I don't see anything that's really
5 GHz specific in here, so why that in the function name?
> + u32 start_freq_seg0 = 0, end_freq_seg0 = 0;
> + u32 start_freq_seg1 = 0, end_freq_seg1 = 0;
> +
> + if (chandef->chan->center_freq == chan->center_freq)
> + return true;
> +
> + switch (chandef->width) {
> + case NL80211_CHAN_WIDTH_40:
> + start_freq_seg0 = chandef->center_freq1 - 20;
> + end_freq_seg0 = chandef->center_freq1 + 20;
> + break;
> + case NL80211_CHAN_WIDTH_80P80:
> + start_freq_seg1 = chandef->center_freq2 - 40;
> + end_freq_seg1 = chandef->center_freq2 + 40;
> + /* fall through */
> + case NL80211_CHAN_WIDTH_80:
> + start_freq_seg0 = chandef->center_freq1 - 40;
> + end_freq_seg0 = chandef->center_freq1 + 40;
> + break;
> + case NL80211_CHAN_WIDTH_160:
> + start_freq_seg0 = chandef->center_freq1 - 80;
> + end_freq_seg0 = chandef->center_freq1 + 80;
> + break;
> + case NL80211_CHAN_WIDTH_20_NOHT:
> + case NL80211_CHAN_WIDTH_20:
> + case NL80211_CHAN_WIDTH_5:
> + case NL80211_CHAN_WIDTH_10:
> + break;
> + }
> +
> + if (chan->center_freq > start_freq_seg0 &&
> + chan->center_freq < end_freq_seg0)
> + return true;
> +
> + return chan->center_freq > start_freq_seg1 &&
> + chan->center_freq < end_freq_seg1;
> +}
It's also written pretty oddly... The 5/10/20 cases could return
immediately, the start/end could be replaced by width, and the
initializations wouldn't be needed at all ... I think we can do better
here.
> +bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
> + struct ieee80211_channel
> *chan)
Again, nothing 5 GHz specific.
> + struct wireless_dev *wdev;
> +
> + ASSERT_RTNL();
> +
> + if (!(chan->flags & IEEE80211_CHAN_RADAR))
> + return false;
> +
> + list_for_each_entry(wdev, &wiphy->wdev_list, list) {
> + if (!cfg80211_beaconing_iface_active(wdev))
> + continue;
> +
> + if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
> + return true;
> + }
> +
> + return false;
> +}
>
> static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
> u32 center_freq,
> diff --git a/net/wireless/core.h b/net/wireless/core.h
> index 58ca206..327fe95 100644
> --- a/net/wireless/core.h
> +++ b/net/wireless/core.h
> @@ -459,6 +459,13 @@ void cfg80211_set_dfs_state(struct wiphy *wiphy,
> cfg80211_chandef_dfs_cac_time(struct wiphy *wiphy,
> const struct cfg80211_chan_def
> *chandef);
>
> +void cfg80211_sched_dfs_chan_update(struct
> cfg80211_registered_device *rdev);
> +
> +bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
> + struct ieee80211_channel
> *chan);
> +
> +bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev);
> +
> static inline unsigned int elapsed_jiffies_msecs(unsigned long
> start)
> {
> unsigned long end = jiffies;
> diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
> index 364f900..10bf040 100644
> --- a/net/wireless/ibss.c
> +++ b/net/wireless/ibss.c
> @@ -190,6 +190,7 @@ static void __cfg80211_clear_ibss(struct
> net_device *dev, bool nowext)
> if (!nowext)
> wdev->wext.ibss.ssid_len = 0;
> #endif
> + cfg80211_sched_dfs_chan_update(rdev);
> }
>
> void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
> diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c
> index 2d8518a..ec0b1c2 100644
> --- a/net/wireless/mesh.c
> +++ b/net/wireless/mesh.c
> @@ -262,6 +262,7 @@ int __cfg80211_leave_mesh(struct
> cfg80211_registered_device *rdev,
> wdev->beacon_interval = 0;
> memset(&wdev->chandef, 0, sizeof(wdev->chandef));
> rdev_set_qos_map(rdev, dev, NULL);
> + cfg80211_sched_dfs_chan_update(rdev);
> }
>
> return err;
> diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
> index 22b3d99..3c7e155 100644
> --- a/net/wireless/mlme.c
> +++ b/net/wireless/mlme.c
> @@ -745,6 +745,12 @@ bool cfg80211_rx_mgmt(struct wireless_dev *wdev,
> int freq, int sig_mbm,
> }
> EXPORT_SYMBOL(cfg80211_rx_mgmt);
>
> +void cfg80211_sched_dfs_chan_update(struct
> cfg80211_registered_device *rdev)
> +{
> + cancel_delayed_work(&rdev->dfs_update_channels_wk);
> + queue_delayed_work(cfg80211_wq, &rdev-
> >dfs_update_channels_wk, 0);
> +}
This uses 0.
> @@ -820,9 +844,7 @@ void cfg80211_radar_event(struct wiphy *wiphy,
> */
> cfg80211_set_dfs_state(wiphy, chandef,
> NL80211_DFS_UNAVAILABLE);
>
> - timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
> - queue_delayed_work(cfg80211_wq, &rdev-
> >dfs_update_channels_wk,
> - timeout);
> + cfg80211_sched_dfs_chan_update(rdev);
But this didn't - why does that change?
> +unsigned long regulatory_get_pre_cac_timeout(struct wiphy *wiphy)
> +{
> + if (!regulatory_pre_cac_allowed(wiphy))
> + return REG_PRE_CAC_EXPIRY_GRACE_MS;
> +
> + /*
> + * Return the maximum pre-CAC timeout when pre-CAC is
> allowed
> + * in the current dfs domain (ETSI).
> + */
> + return -1;
> +}
Don't ever return -1, that's -EPERM and not really what you want
anyway.
In fact, this doesn't even make sense, since the only caller already
checks regulatory_pre_cac_allowed() before calling this.
johannes
Sharing DFS channel state across multiple wiphys (radios) could
be useful with multiple radios on the system. When one radio
completes CAC and marks the channel available another radio
can use this information and start beaconing without really doing
CAC.
Whenever there is a state change in DFS channel associated to
a particular wiphy the the same state change is propagated to
other wiphys having the same DFS reg domain configuration.
Also when a new wiphy is created the DFS channel state of
other existing wiphys of same DFS domain is copied.
Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
---
net/wireless/chan.c | 24 +++++++++--
net/wireless/core.c | 37 +++++++++++++++++
net/wireless/core.h | 6 +++
net/wireless/mlme.c | 11 +++++-
net/wireless/reg.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++
net/wireless/reg.h | 22 +++++++++++
6 files changed, 207 insertions(+), 5 deletions(-)
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 090309a..40f1097 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -532,21 +532,37 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
return active;
}
+static bool cfg80211_5ghz_is_wiphy_oper_chan(struct wiphy *wiphy,
+ struct ieee80211_channel *chan)
+{
+ struct wireless_dev *wdev;
+
+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
+ if (!cfg80211_beaconing_iface_active(wdev))
+ continue;
+
+ if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
+ return true;
+ }
+
+ return false;
+}
+
bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
struct ieee80211_channel *chan)
{
- struct wireless_dev *wdev;
+ struct cfg80211_registered_device *rdev;
ASSERT_RTNL();
if (!(chan->flags & IEEE80211_CHAN_RADAR))
return false;
- list_for_each_entry(wdev, &wiphy->wdev_list, list) {
- if (!cfg80211_beaconing_iface_active(wdev))
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
continue;
- if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
+ if (cfg80211_5ghz_is_wiphy_oper_chan(&rdev->wiphy, chan))
return true;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 903fc419..c3fe44b 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -357,6 +357,38 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
rtnl_unlock();
}
+static void cfg80211_propagate_radar_detect_wk(struct work_struct *work)
+{
+ struct cfg80211_registered_device *rdev;
+
+ rdev = container_of(work, struct cfg80211_registered_device,
+ porpagate_radar_detect_wk);
+
+ rtnl_lock();
+
+ regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->radar_chandef,
+ NL80211_DFS_UNAVAILABLE,
+ NL80211_RADAR_DETECTED);
+
+ rtnl_unlock();
+}
+
+static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
+{
+ struct cfg80211_registered_device *rdev;
+
+ rdev = container_of(work, struct cfg80211_registered_device,
+ propagate_cac_done_wk);
+
+ rtnl_lock();
+
+ regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->cac_done_chandef,
+ NL80211_DFS_AVAILABLE,
+ NL80211_RADAR_CAC_FINISHED);
+
+ rtnl_unlock();
+}
+
/* exported functions */
struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -456,6 +488,9 @@ 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->porpagate_radar_detect_wk,
+ cfg80211_propagate_radar_detect_wk);
+ INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk);
#ifdef CONFIG_CFG80211_DEFAULT_PS
rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -914,6 +949,8 @@ void wiphy_unregister(struct wiphy *wiphy)
flush_work(&rdev->destroy_work);
flush_work(&rdev->sched_scan_stop_wk);
flush_work(&rdev->mlme_unreg_wk);
+ flush_work(&rdev->porpagate_radar_detect_wk);
+ flush_work(&rdev->propagate_cac_done_wk);
#ifdef CONFIG_PM
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 327fe95..607c8be 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -97,6 +97,12 @@ struct cfg80211_registered_device {
struct work_struct sched_scan_stop_wk;
+ struct cfg80211_chan_def radar_chandef;
+ struct work_struct porpagate_radar_detect_wk;
+
+ struct cfg80211_chan_def cac_done_chandef;
+ struct work_struct propagate_cac_done_wk;
+
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __aligned(NETDEV_ALIGN);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 3c7e155..596d523 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -18,7 +18,6 @@
#include "nl80211.h"
#include "rdev-ops.h"
-
void cfg80211_rx_assoc_resp(struct net_device *dev, struct cfg80211_bss *bss,
const u8 *buf, size_t len, int uapsd_queues)
{
@@ -811,6 +810,10 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
nl80211_radar_notify(rdev, &chandef,
radar_event, NULL,
GFP_ATOMIC);
+
+ regulatory_propagate_dfs_state(wiphy, &chandef,
+ c->dfs_state,
+ radar_event);
continue;
}
@@ -847,6 +850,9 @@ void cfg80211_radar_event(struct wiphy *wiphy,
cfg80211_sched_dfs_chan_update(rdev);
nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
+
+ memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def));
+ queue_work(cfg80211_wq, &rdev->porpagate_radar_detect_wk);
}
EXPORT_SYMBOL(cfg80211_radar_event);
@@ -873,6 +879,9 @@ void cfg80211_cac_event(struct net_device *netdev,
msecs_to_jiffies(wdev->cac_time_ms);
WARN_ON(!time_after_eq(jiffies, timeout));
cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
+ memcpy(&rdev->cac_done_chandef, chandef,
+ sizeof(struct cfg80211_chan_def));
+ queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
cfg80211_sched_dfs_chan_update(rdev);
break;
case NL80211_RADAR_CAC_ABORTED:
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 6d0d004..e41ffff 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2067,6 +2067,83 @@ static void reg_set_request_processed(void)
return REG_REQ_IGNORE;
}
+bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2)
+{
+ const struct ieee80211_regdomain *wiphy1_regd = NULL;
+ const struct ieee80211_regdomain *wiphy2_regd = NULL;
+ const struct ieee80211_regdomain *cfg80211_regd = NULL;
+ bool dfs_domain_same = false;
+
+ rcu_read_lock();
+
+ cfg80211_regd = rcu_dereference(cfg80211_regdomain);
+ wiphy1_regd = rcu_dereference(wiphy1->regd);
+ if (!wiphy1_regd)
+ wiphy1_regd = cfg80211_regd;
+
+ wiphy2_regd = rcu_dereference(wiphy2->regd);
+ if (!wiphy2_regd)
+ wiphy2_regd = cfg80211_regd;
+
+ if (wiphy1_regd->dfs_region == wiphy2_regd->dfs_region)
+ dfs_domain_same = true;
+
+ rcu_read_unlock();
+
+ return dfs_domain_same;
+}
+
+static void reg_copy_dfs_chan_state(struct ieee80211_channel *dst_chan,
+ struct ieee80211_channel *src_chan)
+{
+ if (!(dst_chan->flags & IEEE80211_CHAN_RADAR) ||
+ !(src_chan->flags & IEEE80211_CHAN_RADAR))
+ return;
+
+ if (dst_chan->flags & IEEE80211_CHAN_DISABLED ||
+ src_chan->flags & IEEE80211_CHAN_DISABLED)
+ return;
+
+ if (src_chan->center_freq == dst_chan->center_freq &&
+ dst_chan->dfs_state == NL80211_DFS_USABLE) {
+ dst_chan->dfs_state = src_chan->dfs_state;
+ dst_chan->dfs_state_entered = src_chan->dfs_state_entered;
+ }
+}
+
+static void wiphy_share_dfs_chan_state(struct wiphy *dst_wiphy,
+ struct wiphy *src_wiphy)
+{
+ struct ieee80211_supported_band *src_sband, *dst_sband;
+ int i, j;
+
+ dst_sband = dst_wiphy->bands[NL80211_BAND_5GHZ];
+ src_sband = src_wiphy->bands[NL80211_BAND_5GHZ];
+ if (!dst_sband || !src_sband)
+ return;
+
+ if (!reg_dfs_domain_same(dst_wiphy, src_wiphy))
+ return;
+
+ for (i = 0; i < dst_sband->n_channels; i++)
+ for (j = 0; j < src_sband->n_channels; j++)
+ reg_copy_dfs_chan_state(&dst_sband->channels[i],
+ &src_sband->channels[j]);
+}
+
+static void wiphy_all_share_dfs_chan_state(struct wiphy *wiphy)
+{
+ struct cfg80211_registered_device *rdev;
+
+ ASSERT_RTNL();
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ if (wiphy == &rdev->wiphy)
+ continue;
+ wiphy_share_dfs_chan_state(wiphy, &rdev->wiphy);
+ }
+}
+
/* This processes *all* regulatory hints */
static void reg_process_hint(struct regulatory_request *reg_request)
{
@@ -2110,6 +2187,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
if (treatment == REG_REQ_ALREADY_SET && wiphy &&
wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
wiphy_update_regulatory(wiphy, reg_request->initiator);
+ wiphy_all_share_dfs_chan_state(wiphy);
reg_check_channels();
}
@@ -3061,6 +3139,7 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
lr = get_last_request();
wiphy_update_regulatory(wiphy, lr->initiator);
+ wiphy_all_share_dfs_chan_state(wiphy);
}
void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -3167,6 +3246,39 @@ unsigned long regulatory_get_pre_cac_timeout(struct wiphy *wiphy)
return -1;
}
+void regulatory_propagate_dfs_state(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_dfs_state dfs_state,
+ enum nl80211_radar_event event)
+{
+ struct cfg80211_registered_device *rdev;
+
+ ASSERT_RTNL();
+
+ if (WARN_ON(!(chandef->chan->flags & IEEE80211_CHAN_RADAR)))
+ return;
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ if (wiphy == &rdev->wiphy)
+ continue;
+
+ if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
+ continue;
+
+ if (!ieee80211_get_channel(&rdev->wiphy,
+ chandef->chan->center_freq))
+ continue;
+
+ cfg80211_set_dfs_state(&rdev->wiphy, chandef, dfs_state);
+
+ if (event == NL80211_RADAR_DETECTED ||
+ event == NL80211_RADAR_CAC_FINISHED)
+ cfg80211_sched_dfs_chan_update(rdev);
+
+ nl80211_radar_notify(rdev, chandef, event, NULL, GFP_KERNEL);
+ }
+}
+
int __init regulatory_init(void)
{
int err = 0;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index 1fded3d..d9c7eff 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -157,4 +157,26 @@ void regulatory_hint_country_ie(struct wiphy *wiphy,
* applied on the dfs channels associated to this wiphy.
*/
unsigned long regulatory_get_pre_cac_timeout(struct wiphy *wiphy);
+
+/**
+ * regulatory_propagate_dfs_state - Propagate DFS channel state to other wiphys
+ * @wiphy - wiphy on which radar is detected and the event will be propagated
+ * to other available wiphys having the same DFS domain
+ * @chandef - Channel definition of radar detected channel
+ * @dfs_state - DFS channel state to be set
+ * @event - Type of radar event which triggered this DFS state change
+ *
+ * This function should be called with rtnl lock held.
+ */
+void regulatory_propagate_dfs_state(struct wiphy *wiphy,
+ struct cfg80211_chan_def *chandef,
+ enum nl80211_dfs_state dfs_state,
+ enum nl80211_radar_event event);
+
+/**
+ * reg_dfs_domain_same - Checks if both wiphy have same DFS domain configured
+ * @wiphy1 - wiphy it's dfs_region to be checked against that of wiphy2
+ * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1
+ */
+bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
#endif /* __NET_WIRELESS_REG_H */
--
1.9.1
T24gVGh1cnNkYXkgMjYgSmFudWFyeSAyMDE3IDAzOjExIFBNLCBKb2hhbm5lcyBCZXJnIHdyb3Rl
Og0KPiBPbiBXZWQsIDIwMTctMDEtMjUgYXQgMTc6MDEgKzA1MzAsIFZhc2FudGhha3VtYXIgVGhp
YWdhcmFqYW4gd3JvdGU6DQo+PiBTaGFyaW5nIERGUyBjaGFubmVsIHN0YXRlIGFjcm9zcyBtdWx0
aXBsZSB3aXBoeXMgKHJhZGlvcykgY291bGQNCj4+IGJlIHVzZWZ1bCB3aXRoIG11bHRpcGxlIHJh
ZGlvcyBvbiB0aGUgc3lzdGVtLiBXaGVuIG9uZSByYWRpbw0KPj4gY29tcGxldGVzIENBQyBhbmQg
bWFya3MgdGhlIGNoYW5uZWwgYXZhaWxhYmxlIGFub3RoZXIgcmFkaW8NCj4+IGNhbiB1c2UgdGhp
cyBpbmZvcm1hdGlvbiBhbmQgc3RhcnQgYmVhY29uaW5nIHdpdGhvdXQgcmVhbGx5IGRvaW5nDQo+
PiBDQUMuDQo+Pg0KPj4gV2hlbmV2ZXIgdGhlcmUgaXMgYSBzdGF0ZSBjaGFuZ2UgaW4gREZTIGNo
YW5uZWwgYXNzb2NpYXRlZCB0bw0KPj4gYSBwYXJ0aWN1bGFyIHdpcGh5IHRoZSB0aGUgc2FtZSBz
dGF0ZSBjaGFuZ2UgaXMgcHJvcGFnYXRlZCB0bw0KPj4gb3RoZXIgd2lwaHlzIGhhdmluZyB0aGUg
c2FtZSBERlMgcmVnIGRvbWFpbiBjb25maWd1cmF0aW9uLg0KPj4gQWxzbyB3aGVuIGEgbmV3IHdp
cGh5IGlzIGNyZWF0ZWQgdGhlIERGUyBjaGFubmVsIHN0YXRlIG9mDQo+PiBvdGhlciBleGlzdGlu
ZyB3aXBoeXMgb2Ygc2FtZSBERlMgZG9tYWluIGlzIGNvcGllZC4NCj4+DQo+PiBTaWduZWQtb2Zm
LWJ5OiBWYXNhbnRoYWt1bWFyIFRoaWFnYXJhamFuIDx2dGhpYWdhckBxdGkucXVhbGNvbW0uY29t
Pg0KPj4gLS0tDQo+PiAgIG5ldC93aXJlbGVzcy9jaGFuLmMgfCAgMjQgKysrKysrKysrLS0NCj4+
ICAgbmV0L3dpcmVsZXNzL2NvcmUuYyB8ICAzNyArKysrKysrKysrKysrKysrKw0KPj4gICBuZXQv
d2lyZWxlc3MvY29yZS5oIHwgICA2ICsrKw0KPj4gICBuZXQvd2lyZWxlc3MvbWxtZS5jIHwgIDEx
ICsrKysrLQ0KPj4gICBuZXQvd2lyZWxlc3MvcmVnLmMgIHwgMTEyDQo+PiArKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrDQo+PiAgIG5ldC93aXJlbGVz
cy9yZWcuaCAgfCAgMjIgKysrKysrKysrKysNCj4+ICAgNiBmaWxlcyBjaGFuZ2VkLCAyMDcgaW5z
ZXJ0aW9ucygrKSwgNSBkZWxldGlvbnMoLSkNCj4+DQo+PiBkaWZmIC0tZ2l0IGEvbmV0L3dpcmVs
ZXNzL2NoYW4uYyBiL25ldC93aXJlbGVzcy9jaGFuLmMNCj4+IGluZGV4IDA5MDMwOWEuLjQwZjEw
OTcgMTAwNjQ0DQo+PiAtLS0gYS9uZXQvd2lyZWxlc3MvY2hhbi5jDQo+PiArKysgYi9uZXQvd2ly
ZWxlc3MvY2hhbi5jDQo+PiBAQCAtNTMyLDIxICs1MzIsMzcgQEAgYm9vbCBjZmc4MDIxMV9iZWFj
b25pbmdfaWZhY2VfYWN0aXZlKHN0cnVjdA0KPj4gd2lyZWxlc3NfZGV2ICp3ZGV2KQ0KPj4gICAJ
cmV0dXJuIGFjdGl2ZTsNCj4+ICAgfQ0KPj4NCj4+ICtzdGF0aWMgYm9vbCBjZmc4MDIxMV81Z2h6
X2lzX3dpcGh5X29wZXJfY2hhbihzdHJ1Y3Qgd2lwaHkgKndpcGh5LA0KPj4gKwkJCQkJICAgICBz
dHJ1Y3QNCj4+IGllZWU4MDIxMV9jaGFubmVsICpjaGFuKQ0KPg0KPiBhZ2Fpbiwgbm90aGluZyBy
ZWFsbHkgNSBHSHogc3BlY2lmaWMgaGVyZSwgYWZhaWN0Pw0KDQpTdXJlLg0KDQo+DQo+PiArCXN0
cnVjdCB3aXJlbGVzc19kZXYgKndkZXY7DQo+PiArDQo+PiArCWxpc3RfZm9yX2VhY2hfZW50cnko
d2RldiwgJndpcGh5LT53ZGV2X2xpc3QsIGxpc3QpIHsNCj4+ICsJCWlmICghY2ZnODAyMTFfYmVh
Y29uaW5nX2lmYWNlX2FjdGl2ZSh3ZGV2KSkNCj4+ICsJCQljb250aW51ZTsNCj4+ICsNCj4+ICsJ
CWlmIChjZmc4MDIxMV81Z2h6X3N1Yl9jaGFuKCZ3ZGV2LT5jaGFuZGVmLCBjaGFuKSkNCj4+ICsJ
CQlyZXR1cm4gdHJ1ZTsNCj4+ICsJfQ0KPj4gKw0KPj4gKwlyZXR1cm4gZmFsc2U7DQo+PiArfQ0K
Pj4gKw0KPj4gICBib29sIGNmZzgwMjExXzVnaHpfYW55X3dpcGh5X29wZXJfY2hhbihzdHJ1Y3Qg
d2lwaHkgKndpcGh5LA0KPj4gICAJCQkJICAgICAgIHN0cnVjdCBpZWVlODAyMTFfY2hhbm5lbA0K
Pj4gKmNoYW4pDQo+PiAgIHsNCj4+IC0Jc3RydWN0IHdpcmVsZXNzX2RldiAqd2RldjsNCj4+ICsJ
c3RydWN0IGNmZzgwMjExX3JlZ2lzdGVyZWRfZGV2aWNlICpyZGV2Ow0KPj4NCj4+ICAgCUFTU0VS
VF9SVE5MKCk7DQo+Pg0KPj4gICAJaWYgKCEoY2hhbi0+ZmxhZ3MgJiBJRUVFODAyMTFfQ0hBTl9S
QURBUikpDQo+PiAgIAkJcmV0dXJuIGZhbHNlOw0KPj4NCj4+IC0JbGlzdF9mb3JfZWFjaF9lbnRy
eSh3ZGV2LCAmd2lwaHktPndkZXZfbGlzdCwgbGlzdCkgew0KPj4gLQkJaWYgKCFjZmc4MDIxMV9i
ZWFjb25pbmdfaWZhY2VfYWN0aXZlKHdkZXYpKQ0KPj4gKwlsaXN0X2Zvcl9lYWNoX2VudHJ5KHJk
ZXYsICZjZmc4MDIxMV9yZGV2X2xpc3QsIGxpc3QpIHsNCj4+ICsJCWlmICghcmVnX2Rmc19kb21h
aW5fc2FtZSh3aXBoeSwgJnJkZXYtPndpcGh5KSkNCj4+ICAgCQkJY29udGludWU7DQo+Pg0KPj4g
LQkJaWYgKGNmZzgwMjExXzVnaHpfc3ViX2NoYW4oJndkZXYtPmNoYW5kZWYsIGNoYW4pKQ0KPj4g
KwkJaWYgKGNmZzgwMjExXzVnaHpfaXNfd2lwaHlfb3Blcl9jaGFuKCZyZGV2LT53aXBoeSwNCj4+
IGNoYW4pKQ0KPj4gICAJCQlyZXR1cm4gdHJ1ZTsNCj4+ICAgCX0NCj4+DQo+PiBkaWZmIC0tZ2l0
IGEvbmV0L3dpcmVsZXNzL2NvcmUuYyBiL25ldC93aXJlbGVzcy9jb3JlLmMNCj4+IGluZGV4IDkw
M2ZjNDE5Li5jM2ZlNDRiIDEwMDY0NA0KPj4gLS0tIGEvbmV0L3dpcmVsZXNzL2NvcmUuYw0KPj4g
KysrIGIvbmV0L3dpcmVsZXNzL2NvcmUuYw0KPj4gQEAgLTM1Nyw2ICszNTcsMzggQEAgc3RhdGlj
IHZvaWQgY2ZnODAyMTFfc2NoZWRfc2Nhbl9zdG9wX3drKHN0cnVjdA0KPj4gd29ya19zdHJ1Y3Qg
KndvcmspDQo+PiAgIAlydG5sX3VubG9jaygpOw0KPj4gICB9DQo+Pg0KPj4gK3N0YXRpYyB2b2lk
IGNmZzgwMjExX3Byb3BhZ2F0ZV9yYWRhcl9kZXRlY3Rfd2soc3RydWN0IHdvcmtfc3RydWN0DQo+
PiAqd29yaykNCj4+ICt7DQo+PiArCXN0cnVjdCBjZmc4MDIxMV9yZWdpc3RlcmVkX2RldmljZSAq
cmRldjsNCj4+ICsNCj4+ICsJcmRldiA9IGNvbnRhaW5lcl9vZih3b3JrLCBzdHJ1Y3QgY2ZnODAy
MTFfcmVnaXN0ZXJlZF9kZXZpY2UsDQo+PiArCQkJICAgIHBvcnBhZ2F0ZV9yYWRhcl9kZXRlY3Rf
d2spOw0KPj4gKw0KPj4gKwlydG5sX2xvY2soKTsNCj4+ICsNCj4+ICsJcmVndWxhdG9yeV9wcm9w
YWdhdGVfZGZzX3N0YXRlKCZyZGV2LT53aXBoeSwgJnJkZXYtDQo+Pj4gcmFkYXJfY2hhbmRlZiwN
Cj4+ICsJCQkJICAgICAgIE5MODAyMTFfREZTX1VOQVZBSUxBQkxFLA0KPj4gKwkJCQkgICAgICAg
Tkw4MDIxMV9SQURBUl9ERVRFQ1RFRCk7DQo+PiArDQo+PiArCXJ0bmxfdW5sb2NrKCk7DQo+PiAr
fQ0KPj4gKw0KPj4gK3N0YXRpYyB2b2lkIGNmZzgwMjExX3Byb3BhZ2F0ZV9jYWNfZG9uZV93ayhz
dHJ1Y3Qgd29ya19zdHJ1Y3QgKndvcmspDQo+PiArew0KPj4gKwlzdHJ1Y3QgY2ZnODAyMTFfcmVn
aXN0ZXJlZF9kZXZpY2UgKnJkZXY7DQo+PiArDQo+PiArCXJkZXYgPSBjb250YWluZXJfb2Yod29y
aywgc3RydWN0IGNmZzgwMjExX3JlZ2lzdGVyZWRfZGV2aWNlLA0KPj4gKwkJCSAgICBwcm9wYWdh
dGVfY2FjX2RvbmVfd2spOw0KPj4gKw0KPj4gKwlydG5sX2xvY2soKTsNCj4+ICsNCj4+ICsJcmVn
dWxhdG9yeV9wcm9wYWdhdGVfZGZzX3N0YXRlKCZyZGV2LT53aXBoeSwgJnJkZXYtDQo+Pj4gY2Fj
X2RvbmVfY2hhbmRlZiwNCj4+ICsJCQkJICAgICAgIE5MODAyMTFfREZTX0FWQUlMQUJMRSwNCj4+
ICsJCQkJICAgICAgIE5MODAyMTFfUkFEQVJfQ0FDX0ZJTklTSEVEKTsNCj4+ICsNCj4+ICsJcnRu
bF91bmxvY2soKTsNCj4+ICt9DQo+PiArDQo+PiAgIC8qIGV4cG9ydGVkIGZ1bmN0aW9ucyAqLw0K
Pj4NCj4+ICAgc3RydWN0IHdpcGh5ICp3aXBoeV9uZXdfbm0oY29uc3Qgc3RydWN0IGNmZzgwMjEx
X29wcyAqb3BzLCBpbnQNCj4+IHNpemVvZl9wcml2LA0KPj4gQEAgLTQ1Niw2ICs0ODgsOSBAQCBz
dHJ1Y3Qgd2lwaHkgKndpcGh5X25ld19ubShjb25zdCBzdHJ1Y3QNCj4+IGNmZzgwMjExX29wcyAq
b3BzLCBpbnQgc2l6ZW9mX3ByaXYsDQo+PiAgIAlzcGluX2xvY2tfaW5pdCgmcmRldi0+ZGVzdHJv
eV9saXN0X2xvY2spOw0KPj4gICAJSU5JVF9XT1JLKCZyZGV2LT5kZXN0cm95X3dvcmssIGNmZzgw
MjExX2Rlc3Ryb3lfaWZhY2Vfd2spOw0KPj4gICAJSU5JVF9XT1JLKCZyZGV2LT5zY2hlZF9zY2Fu
X3N0b3Bfd2ssDQo+PiBjZmc4MDIxMV9zY2hlZF9zY2FuX3N0b3Bfd2spOw0KPj4gKwlJTklUX1dP
UksoJnJkZXYtPnBvcnBhZ2F0ZV9yYWRhcl9kZXRlY3Rfd2ssDQo+PiArCQkgIGNmZzgwMjExX3By
b3BhZ2F0ZV9yYWRhcl9kZXRlY3Rfd2spOw0KPj4gKwlJTklUX1dPUksoJnJkZXYtPnByb3BhZ2F0
ZV9jYWNfZG9uZV93aywNCj4+IGNmZzgwMjExX3Byb3BhZ2F0ZV9jYWNfZG9uZV93ayk7DQo+Pg0K
Pj4gICAjaWZkZWYgQ09ORklHX0NGRzgwMjExX0RFRkFVTFRfUFMNCj4+ICAgCXJkZXYtPndpcGh5
LmZsYWdzIHw9IFdJUEhZX0ZMQUdfUFNfT05fQllfREVGQVVMVDsNCj4+IEBAIC05MTQsNiArOTQ5
LDggQEAgdm9pZCB3aXBoeV91bnJlZ2lzdGVyKHN0cnVjdCB3aXBoeSAqd2lwaHkpDQo+PiAgIAlm
bHVzaF93b3JrKCZyZGV2LT5kZXN0cm95X3dvcmspOw0KPj4gICAJZmx1c2hfd29yaygmcmRldi0+
c2NoZWRfc2Nhbl9zdG9wX3drKTsNCj4+ICAgCWZsdXNoX3dvcmsoJnJkZXYtPm1sbWVfdW5yZWdf
d2spOw0KPj4gKwlmbHVzaF93b3JrKCZyZGV2LT5wb3JwYWdhdGVfcmFkYXJfZGV0ZWN0X3drKTsN
Cj4NCj4gdHlwbzogcHJvcGFnYXRlLg0KPg0KPj4gKwlmbHVzaF93b3JrKCZyZGV2LT5wcm9wYWdh
dGVfY2FjX2RvbmVfd2spOw0KPg0KPiBZb3UgZ290IGl0IHJpZ2h0IGhlcmUgOikNCg0KVGhhbmtz
LCBzb21lIHNlYXJjaCByZXBsYWNlIGlzc3VlLg0KDQo+DQo+PiAgICNpZmRlZiBDT05GSUdfUE0N
Cj4+ICAgCWlmIChyZGV2LT53aXBoeS53b3dsYW5fY29uZmlnICYmIHJkZXYtPm9wcy0+c2V0X3dh
a2V1cCkNCj4+IGRpZmYgLS1naXQgYS9uZXQvd2lyZWxlc3MvY29yZS5oIGIvbmV0L3dpcmVsZXNz
L2NvcmUuaA0KPj4gaW5kZXggMzI3ZmU5NS4uNjA3YzhiZSAxMDA2NDQNCj4+IC0tLSBhL25ldC93
aXJlbGVzcy9jb3JlLmgNCj4+ICsrKyBiL25ldC93aXJlbGVzcy9jb3JlLmgNCj4+IEBAIC05Nyw2
ICs5NywxMiBAQCBzdHJ1Y3QgY2ZnODAyMTFfcmVnaXN0ZXJlZF9kZXZpY2Ugew0KPj4NCj4+ICAg
CXN0cnVjdCB3b3JrX3N0cnVjdCBzY2hlZF9zY2FuX3N0b3Bfd2s7DQo+Pg0KPj4gKwlzdHJ1Y3Qg
Y2ZnODAyMTFfY2hhbl9kZWYgcmFkYXJfY2hhbmRlZjsNCj4+ICsJc3RydWN0IHdvcmtfc3RydWN0
IHBvcnBhZ2F0ZV9yYWRhcl9kZXRlY3Rfd2s7DQo+DQo+IFNpbmNlIGl0IGNvbXBpbGVkLCB0aGUg
dHlwbyBleGlzdHMgZXZlcnl3aGVyZSB0aGlzIGlzIHJlZmVyZW5jZWQuDQo+DQo+PiArKysgYi9u
ZXQvd2lyZWxlc3MvbWxtZS5jDQo+PiBAQCAtMTgsNyArMTgsNiBAQA0KPj4gICAjaW5jbHVkZSAi
bmw4MDIxMS5oIg0KPj4gICAjaW5jbHVkZSAicmRldi1vcHMuaCINCj4+DQo+PiAtDQo+PiAgIHZv
aWQgY2ZnODAyMTFfcnhfYXNzb2NfcmVzcChzdHJ1Y3QgbmV0X2RldmljZSAqZGV2LCBzdHJ1Y3QN
Cj4+IGNmZzgwMjExX2JzcyAqYnNzLA0KPg0KPiBwbGVhc2UgZG9uJ3QgbWFrZSB1bnJlbGF0ZWQg
ImNsZWFudXBzIi4NCg0KT29wcywgc29ycnkuDQoNCj4NCj4+ICtib29sIHJlZ19kZnNfZG9tYWlu
X3NhbWUoc3RydWN0IHdpcGh5ICp3aXBoeTEsIHN0cnVjdCB3aXBoeSAqd2lwaHkyKQ0KPj4gK3sN
Cj4+ICsJY29uc3Qgc3RydWN0IGllZWU4MDIxMV9yZWdkb21haW4gKndpcGh5MV9yZWdkID0gTlVM
TDsNCj4+ICsJY29uc3Qgc3RydWN0IGllZWU4MDIxMV9yZWdkb21haW4gKndpcGh5Ml9yZWdkID0g
TlVMTDsNCj4+ICsJY29uc3Qgc3RydWN0IGllZWU4MDIxMV9yZWdkb21haW4gKmNmZzgwMjExX3Jl
Z2QgPSBOVUxMOw0KPj4gKwlib29sIGRmc19kb21haW5fc2FtZSA9IGZhbHNlOw0KPg0KPiBZb3Ug
Y2FuIHJlbW92ZSB0aGF0IGluaXRpYWxpemVyLA0KPg0KPj4gKwlyY3VfcmVhZF9sb2NrKCk7DQo+
PiArDQo+PiArCWNmZzgwMjExX3JlZ2QgPSByY3VfZGVyZWZlcmVuY2UoY2ZnODAyMTFfcmVnZG9t
YWluKTsNCj4+ICsJd2lwaHkxX3JlZ2QgPSByY3VfZGVyZWZlcmVuY2Uod2lwaHkxLT5yZWdkKTsN
Cj4+ICsJaWYgKCF3aXBoeTFfcmVnZCkNCj4+ICsJCXdpcGh5MV9yZWdkID0gY2ZnODAyMTFfcmVn
ZDsNCj4+ICsNCj4+ICsJd2lwaHkyX3JlZ2QgPSByY3VfZGVyZWZlcmVuY2Uod2lwaHkyLT5yZWdk
KTsNCj4+ICsJaWYgKCF3aXBoeTJfcmVnZCkNCj4+ICsJCXdpcGh5Ml9yZWdkID0gY2ZnODAyMTFf
cmVnZDsNCj4+ICsNCj4+ICsJaWYgKHdpcGh5MV9yZWdkLT5kZnNfcmVnaW9uID09IHdpcGh5Ml9y
ZWdkLT5kZnNfcmVnaW9uKQ0KPj4gKwkJZGZzX2RvbWFpbl9zYW1lID0gdHJ1ZTsNCj4NCj4gYW5k
IGp1c3QgYXNzaWduDQo+IAlkZnNfZG9tYWluX3NhbWUgPSB3aXBoeTEuLi4gPT0gd2lwaHkyLi4u
Ow0KDQpPay4NCg0KPg0KPj4gK3N0YXRpYyB2b2lkIHdpcGh5X3NoYXJlX2Rmc19jaGFuX3N0YXRl
KHN0cnVjdCB3aXBoeSAqZHN0X3dpcGh5LA0KPj4gKwkJCQkgICAgICAgc3RydWN0IHdpcGh5ICpz
cmNfd2lwaHkpDQo+PiArew0KPj4gKwlzdHJ1Y3QgaWVlZTgwMjExX3N1cHBvcnRlZF9iYW5kICpz
cmNfc2JhbmQsICpkc3Rfc2JhbmQ7DQo+PiArCWludCBpLCBqOw0KPj4gKw0KPj4gKwlkc3Rfc2Jh
bmQgPSBkc3Rfd2lwaHktPmJhbmRzW05MODAyMTFfQkFORF81R0haXTsNCj4+ICsJc3JjX3NiYW5k
ID0gc3JjX3dpcGh5LT5iYW5kc1tOTDgwMjExX0JBTkRfNUdIWl07DQo+PiArCWlmICghZHN0X3Ni
YW5kIHx8ICFzcmNfc2JhbmQpDQo+PiArCQlyZXR1cm47DQo+DQo+IFdoeSBtYWtlIHRoaXMgNSBH
SHogc3BlY2lmaWM/IFBlcmhhcHMgc29tZSBraW5kIG9mIHJhZGFyIHN0dWZmIHdpbGwNCj4gZXhp
c3QgaW4gZnV0dXJlIGJhbmRzIHRvby4gSXQgc2hvdWxkbid0IHJlYWxseSBjb3N0IG11Y2ggdG8g
aXRlcmF0ZSBhbGwNCj4gdGhlIGJhbmRzLCBJIHRoaW5rPw0KDQpHb2luZyBvdmVyIGFsbCB0aGUg
YmFuZHMgc2hvdWxkIG5vdCBiZSBhbiBpc3N1ZSwgaSdsbCBtYWtlIHRoZSBjaGFuZ2UuDQoNClRo
YW5rcywNCg0KVmFzYW50aA0K
> +static bool cfg80211_off_channel_oper_allowed(struct wireless_dev
> *wdev)
> +{
> + if (!cfg80211_beaconing_iface_active(wdev))
> + return true;
> +
> + if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
> + return true;
That could use some locking assertions. Maybe also in the
cfg80211_beaconing_iface_active() function you introduced in the
previous patch.
> + if (!cfg80211_off_channel_oper_allowed(wdev)) {
> + struct ieee80211_channel *chan;
> +
> + if (request->n_channels != 1) {
> + err = -EBUSY;
> + goto out_free;
> + }
> +
> + chan = request->channels[0];
> + if (chan->center_freq != wdev->chandef.chan-
> >center_freq) {
> + err = -EBUSY;
> + goto out_free;
> + }
> + }
I'm not convinced you even hold the relevant locks here, though off the
top of my head I'm not even sure which are needed.
> i = 0;
> if (n_ssids) {
> nla_for_each_nested(attr, info-
> >attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
> @@ -9053,6 +9079,7 @@ static int nl80211_remain_on_channel(struct
> sk_buff *skb,
> struct cfg80211_registered_device *rdev = info->user_ptr[0];
> struct wireless_dev *wdev = info->user_ptr[1];
> struct cfg80211_chan_def chandef;
> + const struct cfg80211_chan_def *compat_chandef;
> struct sk_buff *msg;
> void *hdr;
> u64 cookie;
> @@ -9081,6 +9108,14 @@ static int nl80211_remain_on_channel(struct
> sk_buff *skb,
> if (err)
> return err;
>
> + if (!(cfg80211_off_channel_oper_allowed(wdev) ||
> + cfg80211_chandef_identical(&wdev->chandef, &chandef)))
I'd prefer to write that as !off_channel && !chandef_identical, seems
easier to understand here.
johannes
T24gVGh1cnNkYXkgMjYgSmFudWFyeSAyMDE3IDAzOjA0IFBNLCBKb2hhbm5lcyBCZXJnIHdyb3Rl
Og0KPg0KPj4gKwkJLyogU2hvdWxkIHdlIGFwcGx5IHRoZSBncmFjZSBwZXJpb2QgZHVyaW5nIGJl
YWNvbmluZw0KPj4gaW50ZXJmYWNlDQo+PiArCQkgKiBzaHV0ZG93biBhbHNvPw0KPj4gKwkJICov
DQo+PiArCQljZmc4MDIxMV9zY2hlZF9kZnNfY2hhbl91cGRhdGUocmRldik7DQo+DQo+IEl0IG1p
Z2h0IG1ha2Ugc29tZSBzZW5zZSwgc2F5IGlmIGhvc3RhcGQgY3Jhc2hlcyBhbmQgeW91IHJlc3Rh
cnQgaXQNCj4gYXV0b21hdGljYWxseSBvciBzb21ldGhpbmc/DQoNClN1cmUuIEluaXRpYWxseSBp
dCBsb29rZWQgdHJpY2t5IHRvIGhhbmRsZSB0aGlzLiBCdXQgSSBndWVzcyB3ZSBjYW4gc3RvcmUN
CnRoZSBERlMgY2hhbm5lbCBhbmQgdGhlIHRpbWUgc3RhbXAgKHJkZXYgc3BlY2lmaWMpIHdoZW4g
dGhlIGJlYWNvbmluZyBpbnRlcmZhY2UNCmlzIGJyb3VnaHQgZG93bi4gY2ZnODAyMTFfZGZzX2No
YW5uZWxzX3VwZGF0ZV93b3JrKCkgY2FuIHVzZSB0aGVzZSBpbmZvcm1hdGlvbg0KYW5kIGFwcGx5
IHRoZSBncmFjZSBwZXJpb2QgYmVmb3JlIHNldHRpbmcgdGhlIERGUyBjaGFubmVsIHN0YXRlIGJh
Y2sgdG8gJ3VzYWJsZScuDQoNCj4NCj4+ICAgCXJldHVybiBlcnI7DQo+PiBkaWZmIC0tZ2l0IGEv
bmV0L3dpcmVsZXNzL2NoYW4uYyBiL25ldC93aXJlbGVzcy9jaGFuLmMNCj4+IGluZGV4IDU0OTdk
MDIyLi4wOTAzMDlhIDEwMDY0NA0KPj4gLS0tIGEvbmV0L3dpcmVsZXNzL2NoYW4uYw0KPj4gKysr
IGIvbmV0L3dpcmVsZXNzL2NoYW4uYw0KPj4gQEAgLTQ1Niw2ICs0NTYsMTAyIEBAIGJvb2wgY2Zn
ODAyMTFfY2hhbmRlZl9kZnNfdXNhYmxlKHN0cnVjdCB3aXBoeQ0KPj4gKndpcGh5LA0KPj4gICAJ
cmV0dXJuIChyMSArIHIyID4gMCk7DQo+PiAgIH0NCj4+DQo+PiArc3RhdGljIGJvb2wgY2ZnODAy
MTFfNWdoel9zdWJfY2hhbihzdHJ1Y3QgY2ZnODAyMTFfY2hhbl9kZWYNCj4+ICpjaGFuZGVmLA0K
Pj4gKwkJCQkgICBzdHJ1Y3QgaWVlZTgwMjExX2NoYW5uZWwgKmNoYW4pDQo+DQo+IFRoaXMgY291
bGQgdXNlIHNvbWUgZXhwbGFuYXRpb24sIGFuZCBJIGRvbid0IHNlZSBhbnl0aGluZyB0aGF0J3Mg
cmVhbGx5DQo+IDUgR0h6IHNwZWNpZmljIGluIGhlcmUsIHNvIHdoeSB0aGF0IGluIHRoZSBmdW5j
dGlvbiBuYW1lPw0KDQpTdXJlLg0KDQo+DQo+PiArCXUzMiBzdGFydF9mcmVxX3NlZzAgPSAwLCBl
bmRfZnJlcV9zZWcwID0gMDsNCj4+ICsJdTMyIHN0YXJ0X2ZyZXFfc2VnMSA9IDAsIGVuZF9mcmVx
X3NlZzEgPSAwOw0KPj4gKw0KPj4gKwlpZiAoY2hhbmRlZi0+Y2hhbi0+Y2VudGVyX2ZyZXEgPT0g
Y2hhbi0+Y2VudGVyX2ZyZXEpDQo+PiArCQlyZXR1cm4gdHJ1ZTsNCj4+ICsNCj4+ICsJc3dpdGNo
IChjaGFuZGVmLT53aWR0aCkgew0KPj4gKwljYXNlIE5MODAyMTFfQ0hBTl9XSURUSF80MDoNCj4+
ICsJCXN0YXJ0X2ZyZXFfc2VnMCA9IGNoYW5kZWYtPmNlbnRlcl9mcmVxMSAtIDIwOw0KPj4gKwkJ
ZW5kX2ZyZXFfc2VnMCA9IGNoYW5kZWYtPmNlbnRlcl9mcmVxMSArIDIwOw0KPj4gKwkJYnJlYWs7
DQo+PiArCWNhc2UgTkw4MDIxMV9DSEFOX1dJRFRIXzgwUDgwOg0KPj4gKwkJc3RhcnRfZnJlcV9z
ZWcxID0gY2hhbmRlZi0+Y2VudGVyX2ZyZXEyIC0gNDA7DQo+PiArCQllbmRfZnJlcV9zZWcxID0g
Y2hhbmRlZi0+Y2VudGVyX2ZyZXEyICsgNDA7DQo+PiArCQkvKiBmYWxsIHRocm91Z2ggKi8NCj4+
ICsJY2FzZSBOTDgwMjExX0NIQU5fV0lEVEhfODA6DQo+PiArCQlzdGFydF9mcmVxX3NlZzAgPSBj
aGFuZGVmLT5jZW50ZXJfZnJlcTEgLSA0MDsNCj4+ICsJCWVuZF9mcmVxX3NlZzAgPSBjaGFuZGVm
LT5jZW50ZXJfZnJlcTEgKyA0MDsNCj4+ICsJCWJyZWFrOw0KPj4gKwljYXNlIE5MODAyMTFfQ0hB
Tl9XSURUSF8xNjA6DQo+PiArCQlzdGFydF9mcmVxX3NlZzAgPSBjaGFuZGVmLT5jZW50ZXJfZnJl
cTEgLSA4MDsNCj4+ICsJCWVuZF9mcmVxX3NlZzAgPSBjaGFuZGVmLT5jZW50ZXJfZnJlcTEgKyA4
MDsNCj4+ICsJCWJyZWFrOw0KPj4gKwljYXNlIE5MODAyMTFfQ0hBTl9XSURUSF8yMF9OT0hUOg0K
Pj4gKwljYXNlIE5MODAyMTFfQ0hBTl9XSURUSF8yMDoNCj4+ICsJY2FzZSBOTDgwMjExX0NIQU5f
V0lEVEhfNToNCj4+ICsJY2FzZSBOTDgwMjExX0NIQU5fV0lEVEhfMTA6DQo+PiArCQlicmVhazsN
Cj4+ICsJfQ0KPj4gKw0KPj4gKwlpZiAoY2hhbi0+Y2VudGVyX2ZyZXEgPiBzdGFydF9mcmVxX3Nl
ZzAgJiYNCj4+ICsJICAgIGNoYW4tPmNlbnRlcl9mcmVxIDwgZW5kX2ZyZXFfc2VnMCkNCj4+ICsJ
CXJldHVybiB0cnVlOw0KPj4gKw0KPj4gKwlyZXR1cm4gY2hhbi0+Y2VudGVyX2ZyZXEgPiBzdGFy
dF9mcmVxX3NlZzEgJiYNCj4+ICsJCWNoYW4tPmNlbnRlcl9mcmVxIDwgZW5kX2ZyZXFfc2VnMTsN
Cj4+ICt9DQo+DQo+IEl0J3MgYWxzbyB3cml0dGVuIHByZXR0eSBvZGRseS4uLiBUaGUgNS8xMC8y
MCBjYXNlcyBjb3VsZCByZXR1cm4NCj4gaW1tZWRpYXRlbHksIHRoZSBzdGFydC9lbmQgY291bGQg
YmUgcmVwbGFjZWQgYnkgd2lkdGgsIGFuZCB0aGUNCj4gaW5pdGlhbGl6YXRpb25zIHdvdWxkbid0
IGJlIG5lZWRlZCBhdCBhbGwgLi4uIEkgdGhpbmsgd2UgY2FuIGRvIGJldHRlcg0KPiBoZXJlLg0K
DQpTdXJlLCBJJ2xsIGltcHJvdmUgdGhpcyBmdW5jdGlvbi4NCg0KPg0KPj4gK2Jvb2wgY2ZnODAy
MTFfNWdoel9hbnlfd2lwaHlfb3Blcl9jaGFuKHN0cnVjdCB3aXBoeSAqd2lwaHksDQo+PiArCQkJ
CSAgICAgICBzdHJ1Y3QgaWVlZTgwMjExX2NoYW5uZWwNCj4+ICpjaGFuKQ0KPg0KPiBBZ2Fpbiwg
bm90aGluZyA1IEdIeiBzcGVjaWZpYy4NCg0KT2suDQoNCj4NCj4+ICsJc3RydWN0IHdpcmVsZXNz
X2RldiAqd2RldjsNCj4+ICsNCj4+ICsJQVNTRVJUX1JUTkwoKTsNCj4+ICsNCj4+ICsJaWYgKCEo
Y2hhbi0+ZmxhZ3MgJiBJRUVFODAyMTFfQ0hBTl9SQURBUikpDQo+PiArCQlyZXR1cm4gZmFsc2U7
DQo+PiArDQo+PiArCWxpc3RfZm9yX2VhY2hfZW50cnkod2RldiwgJndpcGh5LT53ZGV2X2xpc3Qs
IGxpc3QpIHsNCj4+ICsJCWlmICghY2ZnODAyMTFfYmVhY29uaW5nX2lmYWNlX2FjdGl2ZSh3ZGV2
KSkNCj4+ICsJCQljb250aW51ZTsNCj4+ICsNCj4+ICsJCWlmIChjZmc4MDIxMV81Z2h6X3N1Yl9j
aGFuKCZ3ZGV2LT5jaGFuZGVmLCBjaGFuKSkNCj4+ICsJCQlyZXR1cm4gdHJ1ZTsNCj4+ICsJfQ0K
Pj4gKw0KPj4gKwlyZXR1cm4gZmFsc2U7DQo+PiArfQ0KPj4NCj4+ICAgc3RhdGljIGJvb2wgY2Zn
ODAyMTFfZ2V0X2NoYW5zX2Rmc19hdmFpbGFibGUoc3RydWN0IHdpcGh5ICp3aXBoeSwNCj4+ICAg
CQkJCQkgICAgIHUzMiBjZW50ZXJfZnJlcSwNCj4+IGRpZmYgLS1naXQgYS9uZXQvd2lyZWxlc3Mv
Y29yZS5oIGIvbmV0L3dpcmVsZXNzL2NvcmUuaA0KPj4gaW5kZXggNThjYTIwNi4uMzI3ZmU5NSAx
MDA2NDQNCj4+IC0tLSBhL25ldC93aXJlbGVzcy9jb3JlLmgNCj4+ICsrKyBiL25ldC93aXJlbGVz
cy9jb3JlLmgNCj4+IEBAIC00NTksNiArNDU5LDEzIEBAIHZvaWQgY2ZnODAyMTFfc2V0X2Rmc19z
dGF0ZShzdHJ1Y3Qgd2lwaHkgKndpcGh5LA0KPj4gICBjZmc4MDIxMV9jaGFuZGVmX2Rmc19jYWNf
dGltZShzdHJ1Y3Qgd2lwaHkgKndpcGh5LA0KPj4gICAJCQkgICAgICBjb25zdCBzdHJ1Y3QgY2Zn
ODAyMTFfY2hhbl9kZWYNCj4+ICpjaGFuZGVmKTsNCj4+DQo+PiArdm9pZCBjZmc4MDIxMV9zY2hl
ZF9kZnNfY2hhbl91cGRhdGUoc3RydWN0DQo+PiBjZmc4MDIxMV9yZWdpc3RlcmVkX2RldmljZSAq
cmRldik7DQo+PiArDQo+PiArYm9vbCBjZmc4MDIxMV81Z2h6X2FueV93aXBoeV9vcGVyX2NoYW4o
c3RydWN0IHdpcGh5ICp3aXBoeSwNCj4+ICsJCQkJICAgICAgIHN0cnVjdCBpZWVlODAyMTFfY2hh
bm5lbA0KPj4gKmNoYW4pOw0KPj4gKw0KPj4gK2Jvb2wgY2ZnODAyMTFfYmVhY29uaW5nX2lmYWNl
X2FjdGl2ZShzdHJ1Y3Qgd2lyZWxlc3NfZGV2ICp3ZGV2KTsNCj4+ICsNCj4+ICAgc3RhdGljIGlu
bGluZSB1bnNpZ25lZCBpbnQgZWxhcHNlZF9qaWZmaWVzX21zZWNzKHVuc2lnbmVkIGxvbmcNCj4+
IHN0YXJ0KQ0KPj4gICB7DQo+PiAgIAl1bnNpZ25lZCBsb25nIGVuZCA9IGppZmZpZXM7DQo+PiBk
aWZmIC0tZ2l0IGEvbmV0L3dpcmVsZXNzL2lic3MuYyBiL25ldC93aXJlbGVzcy9pYnNzLmMNCj4+
IGluZGV4IDM2NGY5MDAuLjEwYmYwNDAgMTAwNjQ0DQo+PiAtLS0gYS9uZXQvd2lyZWxlc3MvaWJz
cy5jDQo+PiArKysgYi9uZXQvd2lyZWxlc3MvaWJzcy5jDQo+PiBAQCAtMTkwLDYgKzE5MCw3IEBA
IHN0YXRpYyB2b2lkIF9fY2ZnODAyMTFfY2xlYXJfaWJzcyhzdHJ1Y3QNCj4+IG5ldF9kZXZpY2Ug
KmRldiwgYm9vbCBub3dleHQpDQo+PiAgIAlpZiAoIW5vd2V4dCkNCj4+ICAgCQl3ZGV2LT53ZXh0
Lmlic3Muc3NpZF9sZW4gPSAwOw0KPj4gICAjZW5kaWYNCj4+ICsJY2ZnODAyMTFfc2NoZWRfZGZz
X2NoYW5fdXBkYXRlKHJkZXYpOw0KPj4gICB9DQo+Pg0KPj4gICB2b2lkIGNmZzgwMjExX2NsZWFy
X2lic3Moc3RydWN0IG5ldF9kZXZpY2UgKmRldiwgYm9vbCBub3dleHQpDQo+PiBkaWZmIC0tZ2l0
IGEvbmV0L3dpcmVsZXNzL21lc2guYyBiL25ldC93aXJlbGVzcy9tZXNoLmMNCj4+IGluZGV4IDJk
ODUxOGEuLmVjMGIxYzIgMTAwNjQ0DQo+PiAtLS0gYS9uZXQvd2lyZWxlc3MvbWVzaC5jDQo+PiAr
KysgYi9uZXQvd2lyZWxlc3MvbWVzaC5jDQo+PiBAQCAtMjYyLDYgKzI2Miw3IEBAIGludCBfX2Nm
ZzgwMjExX2xlYXZlX21lc2goc3RydWN0DQo+PiBjZmc4MDIxMV9yZWdpc3RlcmVkX2RldmljZSAq
cmRldiwNCj4+ICAgCQl3ZGV2LT5iZWFjb25faW50ZXJ2YWwgPSAwOw0KPj4gICAJCW1lbXNldCgm
d2Rldi0+Y2hhbmRlZiwgMCwgc2l6ZW9mKHdkZXYtPmNoYW5kZWYpKTsNCj4+ICAgCQlyZGV2X3Nl
dF9xb3NfbWFwKHJkZXYsIGRldiwgTlVMTCk7DQo+PiArCQljZmc4MDIxMV9zY2hlZF9kZnNfY2hh
bl91cGRhdGUocmRldik7DQo+PiAgIAl9DQo+Pg0KPj4gICAJcmV0dXJuIGVycjsNCj4+IGRpZmYg
LS1naXQgYS9uZXQvd2lyZWxlc3MvbWxtZS5jIGIvbmV0L3dpcmVsZXNzL21sbWUuYw0KPj4gaW5k
ZXggMjJiM2Q5OS4uM2M3ZTE1NSAxMDA2NDQNCj4+IC0tLSBhL25ldC93aXJlbGVzcy9tbG1lLmMN
Cj4+ICsrKyBiL25ldC93aXJlbGVzcy9tbG1lLmMNCj4+IEBAIC03NDUsNiArNzQ1LDEyIEBAIGJv
b2wgY2ZnODAyMTFfcnhfbWdtdChzdHJ1Y3Qgd2lyZWxlc3NfZGV2ICp3ZGV2LA0KPj4gaW50IGZy
ZXEsIGludCBzaWdfbWJtLA0KPj4gICB9DQo+PiAgIEVYUE9SVF9TWU1CT0woY2ZnODAyMTFfcnhf
bWdtdCk7DQo+Pg0KPj4gK3ZvaWQgY2ZnODAyMTFfc2NoZWRfZGZzX2NoYW5fdXBkYXRlKHN0cnVj
dA0KPj4gY2ZnODAyMTFfcmVnaXN0ZXJlZF9kZXZpY2UgKnJkZXYpDQo+PiArew0KPj4gKwljYW5j
ZWxfZGVsYXllZF93b3JrKCZyZGV2LT5kZnNfdXBkYXRlX2NoYW5uZWxzX3drKTsNCj4+ICsJcXVl
dWVfZGVsYXllZF93b3JrKGNmZzgwMjExX3dxLCAmcmRldi0NCj4+PiBkZnNfdXBkYXRlX2NoYW5u
ZWxzX3drLCAwKTsNCj4+ICt9DQo+DQo+IFRoaXMgdXNlcyAwLg0KPg0KPj4gQEAgLTgyMCw5ICs4
NDQsNyBAQCB2b2lkIGNmZzgwMjExX3JhZGFyX2V2ZW50KHN0cnVjdCB3aXBoeSAqd2lwaHksDQo+
PiAgIAkgKi8NCj4+ICAgCWNmZzgwMjExX3NldF9kZnNfc3RhdGUod2lwaHksIGNoYW5kZWYsDQo+
PiBOTDgwMjExX0RGU19VTkFWQUlMQUJMRSk7DQo+Pg0KPj4gLQl0aW1lb3V0ID0gbXNlY3NfdG9f
amlmZmllcyhJRUVFODAyMTFfREZTX01JTl9OT1BfVElNRV9NUyk7DQo+PiAtCXF1ZXVlX2RlbGF5
ZWRfd29yayhjZmc4MDIxMV93cSwgJnJkZXYtDQo+Pj4gZGZzX3VwZGF0ZV9jaGFubmVsc193aywN
Cj4+IC0JCQkgICB0aW1lb3V0KTsNCj4+ICsJY2ZnODAyMTFfc2NoZWRfZGZzX2NoYW5fdXBkYXRl
KHJkZXYpOw0KPg0KPiBCdXQgdGhpcyBkaWRuJ3QgLSB3aHkgZG9lcyB0aGF0IGNoYW5nZT8NCg0K
U2luY2UgY2ZnODAyMTFfZGZzX2NoYW5uZWxzX3VwZGF0ZV93b3JrKCkgY2FuIGJlIHNjaGVkdWxl
ZCBtdWx0aXBsZSB0aW1lcyB0byBydW4gYXQNCmRpZmZlcmVudCBwb2ludCBvZiB0aW1lICgyIHNl
Y3MgLSB0byBleHBpcmUgY2FjIGZvciBub24tRVRTSSwgMzAgKiA2MCBzZWNzIC0gdG8gY2xlYXIN
Ck5PTCksIGNmZzgwMjExX3NjaGVkX2Rmc19jaGFuX3VwZGF0ZShyZGV2KSBpcyBhZGRlZCB0byBt
YWtlIHN1cmUgdGhlIHdvcmtlciBjYW4gYWxzbw0KYmUgZmlyZWQgYXQgbmVhcmVyIHRpbWUgc3Rh
bXAgd2hlbiBpdCBpcyBhbHJlYWR5IHBlbmRpbmcgdG8gcnVuIGF0IGFmdGVyIGEgcmVsYXRpdmVs
eQ0KbGF0ZXIgcG9pbnQgb2YgdGltZS4gY2ZnODAyMTFfZGZzX2NoYW5uZWxzX3VwZGF0ZV93b3Jr
KCkgdXNlcyB0aGUgdGltZSBzdGFtcCBvZiBjaGFubmVsDQpERlMgc3RhdGUgKGRmc19zdGF0ZV9l
bnRlcmVkKSB0byBzZXQgdGhlIG5leHQgREZTIHN0YXRlIGFuZC9vciByZS1zY2hlZHVsZSB0aGUg
d29ya2VyDQpsYXRlci4NCg0KPg0KPj4gK3Vuc2lnbmVkIGxvbmcgcmVndWxhdG9yeV9nZXRfcHJl
X2NhY190aW1lb3V0KHN0cnVjdCB3aXBoeSAqd2lwaHkpDQo+PiArew0KPj4gKwlpZiAoIXJlZ3Vs
YXRvcnlfcHJlX2NhY19hbGxvd2VkKHdpcGh5KSkNCj4+ICsJCXJldHVybiBSRUdfUFJFX0NBQ19F
WFBJUllfR1JBQ0VfTVM7DQo+PiArDQo+PiArCS8qDQo+PiArCSAqIFJldHVybiB0aGUgbWF4aW11
bSBwcmUtQ0FDIHRpbWVvdXQgd2hlbiBwcmUtQ0FDIGlzDQo+PiBhbGxvd2VkDQo+PiArCSAqIGlu
IHRoZSBjdXJyZW50IGRmcyBkb21haW4gKEVUU0kpLg0KPj4gKwkgKi8NCj4+ICsJcmV0dXJuIC0x
Ow0KPj4gK30NCj4NCj4gRG9uJ3QgZXZlciByZXR1cm4gLTEsIHRoYXQncyAtRVBFUk0gYW5kIG5v
dCByZWFsbHkgd2hhdCB5b3Ugd2FudA0KPiBhbnl3YXkuDQo+DQoNClN1cmUsIHNpbmNlIHRoZSBy
ZXR1cm4gdGltZSBpcyB1bnNpZ25lZCBsb25nIEkgY2hvc2UgdG8gdXNlIC0xLiBJJ2xsIHJlbW92
ZQ0KdGhpcyBmdW5jdGlvbiBhcyBtZW50aW9uZWQgaW4gYmVsb3cgY29tbWVudC4NCg0KDQo+IElu
IGZhY3QsIHRoaXMgZG9lc24ndCBldmVuIG1ha2Ugc2Vuc2UsIHNpbmNlIHRoZSBvbmx5IGNhbGxl
ciBhbHJlYWR5DQo+IGNoZWNrcyByZWd1bGF0b3J5X3ByZV9jYWNfYWxsb3dlZCgpIGJlZm9yZSBj
YWxsaW5nIHRoaXMuDQoNClN1cmUuIEkgb3JpZ2luYWxseSB0aG91Z2h0IGEgaGVscGVyIGxpa2Ug
dGhpcyB3b3VsZCBiZSB1c2VkIG11bHRpcGxlIHBsYWNlcy4NCkJ1dCBpdCBpcyBub3QgdGhlIGNh
c2Ugbm93IGFuZCBiZWluZyB1c2VkIGluIHNpbmdsZSBwbGFjZS4NCg0KDQpUaGFua3MsDQoNClZh
c2FudGg=
T24gVGh1cnNkYXkgMjYgSmFudWFyeSAyMDE3IDAzOjA2IFBNLCBKb2hhbm5lcyBCZXJnIHdyb3Rl
Og0KPg0KPj4gK3N0YXRpYyBib29sIGNmZzgwMjExX29mZl9jaGFubmVsX29wZXJfYWxsb3dlZChz
dHJ1Y3Qgd2lyZWxlc3NfZGV2DQo+PiAqd2RldikNCj4+ICt7DQo+PiArCWlmICghY2ZnODAyMTFf
YmVhY29uaW5nX2lmYWNlX2FjdGl2ZSh3ZGV2KSkNCj4+ICsJCXJldHVybiB0cnVlOw0KPj4gKw0K
Pj4gKwlpZiAoISh3ZGV2LT5jaGFuZGVmLmNoYW4tPmZsYWdzICYgSUVFRTgwMjExX0NIQU5fUkFE
QVIpKQ0KPj4gKwkJcmV0dXJuIHRydWU7DQo+DQo+IFRoYXQgY291bGQgdXNlIHNvbWUgbG9ja2lu
ZyBhc3NlcnRpb25zLiBNYXliZSBhbHNvIGluIHRoZQ0KPiBjZmc4MDIxMV9iZWFjb25pbmdfaWZh
Y2VfYWN0aXZlKCkgZnVuY3Rpb24geW91IGludHJvZHVjZWQgaW4gdGhlDQo+IHByZXZpb3VzIHBh
dGNoLg0KDQpPay4NCg0KPg0KPj4gKwlpZiAoIWNmZzgwMjExX29mZl9jaGFubmVsX29wZXJfYWxs
b3dlZCh3ZGV2KSkgew0KPj4gKwkJc3RydWN0IGllZWU4MDIxMV9jaGFubmVsICpjaGFuOw0KPj4g
Kw0KPj4gKwkJaWYgKHJlcXVlc3QtPm5fY2hhbm5lbHMgIT0gMSkgew0KPj4gKwkJCWVyciA9IC1F
QlVTWTsNCj4+ICsJCQlnb3RvIG91dF9mcmVlOw0KPj4gKwkJfQ0KPj4gKw0KPj4gKwkJY2hhbiA9
IHJlcXVlc3QtPmNoYW5uZWxzWzBdOw0KPj4gKwkJaWYgKGNoYW4tPmNlbnRlcl9mcmVxICE9IHdk
ZXYtPmNoYW5kZWYuY2hhbi0NCj4+PiBjZW50ZXJfZnJlcSkgew0KPj4gKwkJCWVyciA9IC1FQlVT
WTsNCj4+ICsJCQlnb3RvIG91dF9mcmVlOw0KPj4gKwkJfQ0KPj4gKwl9DQo+DQo+IEknbSBub3Qg
Y29udmluY2VkIHlvdSBldmVuIGhvbGQgdGhlIHJlbGV2YW50IGxvY2tzIGhlcmUsIHRob3VnaCBv
ZmYgdGhlDQo+IHRvcCBvZiBteSBoZWFkIEknbSBub3QgZXZlbiBzdXJlIHdoaWNoIGFyZSBuZWVk
ZWQuDQoNClRoYW5rcyBmb3IgcG9pbnRpbmcgaXQsIGl0IHNob3VsZCBiZSB3aXRoaW4gd2Rldl9s
b2NrKCkuDQoNCj4NCj4+ICAgCWkgPSAwOw0KPj4gICAJaWYgKG5fc3NpZHMpIHsNCj4+ICAgCQlu
bGFfZm9yX2VhY2hfbmVzdGVkKGF0dHIsIGluZm8tDQo+Pj4gYXR0cnNbTkw4MDIxMV9BVFRSX1ND
QU5fU1NJRFNdLCB0bXApIHsNCj4+IEBAIC05MDUzLDYgKzkwNzksNyBAQCBzdGF0aWMgaW50IG5s
ODAyMTFfcmVtYWluX29uX2NoYW5uZWwoc3RydWN0DQo+PiBza19idWZmICpza2IsDQo+PiAgIAlz
dHJ1Y3QgY2ZnODAyMTFfcmVnaXN0ZXJlZF9kZXZpY2UgKnJkZXYgPSBpbmZvLT51c2VyX3B0clsw
XTsNCj4+ICAgCXN0cnVjdCB3aXJlbGVzc19kZXYgKndkZXYgPSBpbmZvLT51c2VyX3B0clsxXTsN
Cj4+ICAgCXN0cnVjdCBjZmc4MDIxMV9jaGFuX2RlZiBjaGFuZGVmOw0KPj4gKwljb25zdCBzdHJ1
Y3QgY2ZnODAyMTFfY2hhbl9kZWYgKmNvbXBhdF9jaGFuZGVmOw0KPj4gICAJc3RydWN0IHNrX2J1
ZmYgKm1zZzsNCj4+ICAgCXZvaWQgKmhkcjsNCj4+ICAgCXU2NCBjb29raWU7DQo+PiBAQCAtOTA4
MSw2ICs5MTA4LDE0IEBAIHN0YXRpYyBpbnQgbmw4MDIxMV9yZW1haW5fb25fY2hhbm5lbChzdHJ1
Y3QNCj4+IHNrX2J1ZmYgKnNrYiwNCj4+ICAgCWlmIChlcnIpDQo+PiAgIAkJcmV0dXJuIGVycjsN
Cj4+DQo+PiArCWlmICghKGNmZzgwMjExX29mZl9jaGFubmVsX29wZXJfYWxsb3dlZCh3ZGV2KSB8
fA0KPj4gKwkgICAgICBjZmc4MDIxMV9jaGFuZGVmX2lkZW50aWNhbCgmd2Rldi0+Y2hhbmRlZiwg
JmNoYW5kZWYpKSkNCj4NCj4gSSdkIHByZWZlciB0byB3cml0ZSB0aGF0IGFzICFvZmZfY2hhbm5l
bCAmJiAhY2hhbmRlZl9pZGVudGljYWwsIHNlZW1zDQo+IGVhc2llciB0byB1bmRlcnN0YW5kIGhl
cmUuDQoNCk9rLg0KDQoNClRoYW5rcywNCg0KVmFzYW50aA0K
On Wednesday 25 January 2017 11:50 PM, Jean-Pierre Tosoni wrote:
>> -----Message d'origine-----
>> De : [email protected] [mailto:linux-wireless-
>> [email protected]] De la part de Vasanthakumar Thiagarajan
>> Envoy=E9 : mercredi 25 janvier 2017 12:31
>> =C0 : [email protected]
>> Cc : [email protected]; Vasanthakumar Thiagarajan
>> Objet : [RFC 2/3] cfg80211: Disallow moving out of operating DFS channel
>> in non-ETSI
>>
>> For non-ETSI regulatory domain, CAC result on DFS channel may not be val=
id
>> once moving out of that channel (as done during remain-on-channel,
>> scannning and off-channel tx).
>> Running CAC on an operating DFS channel after every off-channel operatio=
n
>> will only add complexity and disturb the current link. Better do not all=
ow
>> any off-channel switch from a DFS operating channel in non-ETSI domain.
>>
>
> Moving out should be forbidden only to "master" devices i.e. AP, mesh,
> ad-hoc.
> "Slave" devices i.e. client stations, are not responsible for detecting
> radars, hence, they can do an off-channel scan and go back to a "DFS
> operating channel" without waiting for CAC.
>
> It looks like your patch would forbid multichannel scan ?
>
>
No, this patch forbids off-channel switch only for DFS master device.
cfg80211_beaconing_iface_active() checks if it is a beaconing interface.
I'll mention this in the commit log.
Vasanth
> -----Message d'origine-----
> De?: [email protected] [mailto:linux-wireless-
> [email protected]] De la part de Vasanthakumar Thiagarajan
> Envoy??: mercredi 25 janvier 2017 12:31
> ??: [email protected]
> Cc?: [email protected]; Vasanthakumar Thiagarajan
> Objet?: [RFC 2/3] cfg80211: Disallow moving out of operating DFS channel
> in non-ETSI
>
> For non-ETSI regulatory domain, CAC result on DFS channel may not be valid
> once moving out of that channel (as done during remain-on-channel,
> scannning and off-channel tx).
> Running CAC on an operating DFS channel after every off-channel operation
> will only add complexity and disturb the current link. Better do not allow
> any off-channel switch from a DFS operating channel in non-ETSI domain.
>
Moving out should be forbidden only to "master" devices i.e. AP, mesh,
ad-hoc.
"Slave" devices i.e. client stations, are not responsible for detecting
radars, hence, they can do an off-channel scan and go back to a "DFS
operating channel" without waiting for CAC.
It looks like your patch would forbid multichannel scan ?
> Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
> ---
> net/wireless/nl80211.c | 38 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 38 insertions(+)
>
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index
> 63dfa60..c614af4 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -6506,6 +6506,17 @@ static int nl80211_parse_random_mac(struct nlattr
> **attrs,
> return 0;
> }
>
> +static bool cfg80211_off_channel_oper_allowed(struct wireless_dev
> +*wdev) {
> + if (!cfg80211_beaconing_iface_active(wdev))
> + return true;
> +
> + if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
> + return true;
> +
> + return regulatory_pre_cac_allowed(wdev->wiphy);
> +}
> +
> static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info
> *info) {
> struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -
> 6631,6 +6642,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb,
> struct genl_info *info)
>
> request->n_channels = i;
>
> + if (!cfg80211_off_channel_oper_allowed(wdev)) {
> + struct ieee80211_channel *chan;
> +
> + if (request->n_channels != 1) {
> + err = -EBUSY;
> + goto out_free;
> + }
> +
> + chan = request->channels[0];
> + if (chan->center_freq != wdev->chandef.chan->center_freq) {
> + err = -EBUSY;
> + goto out_free;
> + }
> + }
> +
> i = 0;
> if (n_ssids) {
> nla_for_each_nested(attr, info-
> >attrs[NL80211_ATTR_SCAN_SSIDS], tmp) { @@ -9053,6 +9079,7 @@ static int
> nl80211_remain_on_channel(struct sk_buff *skb,
> struct cfg80211_registered_device *rdev = info->user_ptr[0];
> struct wireless_dev *wdev = info->user_ptr[1];
> struct cfg80211_chan_def chandef;
> + const struct cfg80211_chan_def *compat_chandef;
> struct sk_buff *msg;
> void *hdr;
> u64 cookie;
> @@ -9081,6 +9108,14 @@ static int nl80211_remain_on_channel(struct sk_buff
> *skb,
> if (err)
> return err;
>
> + if (!(cfg80211_off_channel_oper_allowed(wdev) ||
> + cfg80211_chandef_identical(&wdev->chandef, &chandef))) {
> + compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
> + &chandef);
> + if (compat_chandef != &chandef)
> + return -EBUSY;
> + }
> +
> msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> if (!msg)
> return -ENOMEM;
> @@ -9256,6 +9291,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb,
> struct genl_info *info)
> if (!chandef.chan && params.offchan)
> return -EINVAL;
>
> + if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev))
> + return -EBUSY;
> +
> params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
> params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
>
> --
> 1.9.1
For non-ETSI regulatory domain, CAC result on DFS channel
may not be valid once moving out of that channel (as done
during remain-on-channel, scannning and off-channel tx).
Running CAC on an operating DFS channel after every off-channel
operation will only add complexity and disturb the current
link. Better do not allow any off-channel switch from a DFS
operating channel in non-ETSI domain.
Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
---
net/wireless/nl80211.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 63dfa60..c614af4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6506,6 +6506,17 @@ static int nl80211_parse_random_mac(struct nlattr **attrs,
return 0;
}
+static bool cfg80211_off_channel_oper_allowed(struct wireless_dev *wdev)
+{
+ if (!cfg80211_beaconing_iface_active(wdev))
+ return true;
+
+ if (!(wdev->chandef.chan->flags & IEEE80211_CHAN_RADAR))
+ return true;
+
+ return regulatory_pre_cac_allowed(wdev->wiphy);
+}
+
static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -6631,6 +6642,21 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
request->n_channels = i;
+ if (!cfg80211_off_channel_oper_allowed(wdev)) {
+ struct ieee80211_channel *chan;
+
+ if (request->n_channels != 1) {
+ err = -EBUSY;
+ goto out_free;
+ }
+
+ chan = request->channels[0];
+ if (chan->center_freq != wdev->chandef.chan->center_freq) {
+ err = -EBUSY;
+ goto out_free;
+ }
+ }
+
i = 0;
if (n_ssids) {
nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
@@ -9053,6 +9079,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct wireless_dev *wdev = info->user_ptr[1];
struct cfg80211_chan_def chandef;
+ const struct cfg80211_chan_def *compat_chandef;
struct sk_buff *msg;
void *hdr;
u64 cookie;
@@ -9081,6 +9108,14 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
if (err)
return err;
+ if (!(cfg80211_off_channel_oper_allowed(wdev) ||
+ cfg80211_chandef_identical(&wdev->chandef, &chandef))) {
+ compat_chandef = cfg80211_chandef_compatible(&wdev->chandef,
+ &chandef);
+ if (compat_chandef != &chandef)
+ return -EBUSY;
+ }
+
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
@@ -9256,6 +9291,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
if (!chandef.chan && params.offchan)
return -EINVAL;
+ if (params.offchan && !cfg80211_off_channel_oper_allowed(wdev))
+ return -EBUSY;
+
params.buf = nla_data(info->attrs[NL80211_ATTR_FRAME]);
params.len = nla_len(info->attrs[NL80211_ATTR_FRAME]);
--
1.9.1
On Wed, 2017-01-25 at 17:01 +0530, Vasanthakumar Thiagarajan wrote:
> Sharing DFS channel state across multiple wiphys (radios) could
> be useful with multiple radios on the system. When one radio
> completes CAC and marks the channel available another radio
> can use this information and start beaconing without really doing
> CAC.
>
> Whenever there is a state change in DFS channel associated to
> a particular wiphy the the same state change is propagated to
> other wiphys having the same DFS reg domain configuration.
> Also when a new wiphy is created the DFS channel state of
> other existing wiphys of same DFS domain is copied.
>
> Signed-off-by: Vasanthakumar Thiagarajan <[email protected]>
> ---
> net/wireless/chan.c | 24 +++++++++--
> net/wireless/core.c | 37 +++++++++++++++++
> net/wireless/core.h | 6 +++
> net/wireless/mlme.c | 11 +++++-
> net/wireless/reg.c | 112
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
> net/wireless/reg.h | 22 +++++++++++
> 6 files changed, 207 insertions(+), 5 deletions(-)
>
> diff --git a/net/wireless/chan.c b/net/wireless/chan.c
> index 090309a..40f1097 100644
> --- a/net/wireless/chan.c
> +++ b/net/wireless/chan.c
> @@ -532,21 +532,37 @@ bool cfg80211_beaconing_iface_active(struct
> wireless_dev *wdev)
> return active;
> }
>
> +static bool cfg80211_5ghz_is_wiphy_oper_chan(struct wiphy *wiphy,
> + struct
> ieee80211_channel *chan)
again, nothing really 5 GHz specific here, afaict?
> + struct wireless_dev *wdev;
> +
> + list_for_each_entry(wdev, &wiphy->wdev_list, list) {
> + if (!cfg80211_beaconing_iface_active(wdev))
> + continue;
> +
> + if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
> + return true;
> + }
> +
> + return false;
> +}
> +
> bool cfg80211_5ghz_any_wiphy_oper_chan(struct wiphy *wiphy,
> struct ieee80211_channel
> *chan)
> {
> - struct wireless_dev *wdev;
> + struct cfg80211_registered_device *rdev;
>
> ASSERT_RTNL();
>
> if (!(chan->flags & IEEE80211_CHAN_RADAR))
> return false;
>
> - list_for_each_entry(wdev, &wiphy->wdev_list, list) {
> - if (!cfg80211_beaconing_iface_active(wdev))
> + list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
> + if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
> continue;
>
> - if (cfg80211_5ghz_sub_chan(&wdev->chandef, chan))
> + if (cfg80211_5ghz_is_wiphy_oper_chan(&rdev->wiphy,
> chan))
> return true;
> }
>
> diff --git a/net/wireless/core.c b/net/wireless/core.c
> index 903fc419..c3fe44b 100644
> --- a/net/wireless/core.c
> +++ b/net/wireless/core.c
> @@ -357,6 +357,38 @@ static void cfg80211_sched_scan_stop_wk(struct
> work_struct *work)
> rtnl_unlock();
> }
>
> +static void cfg80211_propagate_radar_detect_wk(struct work_struct
> *work)
> +{
> + struct cfg80211_registered_device *rdev;
> +
> + rdev = container_of(work, struct cfg80211_registered_device,
> + porpagate_radar_detect_wk);
> +
> + rtnl_lock();
> +
> + regulatory_propagate_dfs_state(&rdev->wiphy, &rdev-
> >radar_chandef,
> + NL80211_DFS_UNAVAILABLE,
> + NL80211_RADAR_DETECTED);
> +
> + rtnl_unlock();
> +}
> +
> +static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
> +{
> + struct cfg80211_registered_device *rdev;
> +
> + rdev = container_of(work, struct cfg80211_registered_device,
> + propagate_cac_done_wk);
> +
> + rtnl_lock();
> +
> + regulatory_propagate_dfs_state(&rdev->wiphy, &rdev-
> >cac_done_chandef,
> + NL80211_DFS_AVAILABLE,
> + NL80211_RADAR_CAC_FINISHED);
> +
> + rtnl_unlock();
> +}
> +
> /* exported functions */
>
> struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int
> sizeof_priv,
> @@ -456,6 +488,9 @@ 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->porpagate_radar_detect_wk,
> + cfg80211_propagate_radar_detect_wk);
> + INIT_WORK(&rdev->propagate_cac_done_wk,
> cfg80211_propagate_cac_done_wk);
>
> #ifdef CONFIG_CFG80211_DEFAULT_PS
> rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
> @@ -914,6 +949,8 @@ void wiphy_unregister(struct wiphy *wiphy)
> flush_work(&rdev->destroy_work);
> flush_work(&rdev->sched_scan_stop_wk);
> flush_work(&rdev->mlme_unreg_wk);
> + flush_work(&rdev->porpagate_radar_detect_wk);
typo: propagate.
> + flush_work(&rdev->propagate_cac_done_wk);
You got it right here :)
> #ifdef CONFIG_PM
> if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
> diff --git a/net/wireless/core.h b/net/wireless/core.h
> index 327fe95..607c8be 100644
> --- a/net/wireless/core.h
> +++ b/net/wireless/core.h
> @@ -97,6 +97,12 @@ struct cfg80211_registered_device {
>
> struct work_struct sched_scan_stop_wk;
>
> + struct cfg80211_chan_def radar_chandef;
> + struct work_struct porpagate_radar_detect_wk;
Since it compiled, the typo exists everywhere this is referenced.
> +++ b/net/wireless/mlme.c
> @@ -18,7 +18,6 @@
> #include "nl80211.h"
> #include "rdev-ops.h"
>
> -
> void cfg80211_rx_assoc_resp(struct net_device *dev, struct
> cfg80211_bss *bss,
please don't make unrelated "cleanups".
> +bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2)
> +{
> + const struct ieee80211_regdomain *wiphy1_regd = NULL;
> + const struct ieee80211_regdomain *wiphy2_regd = NULL;
> + const struct ieee80211_regdomain *cfg80211_regd = NULL;
> + bool dfs_domain_same = false;
You can remove that initializer,
> + rcu_read_lock();
> +
> + cfg80211_regd = rcu_dereference(cfg80211_regdomain);
> + wiphy1_regd = rcu_dereference(wiphy1->regd);
> + if (!wiphy1_regd)
> + wiphy1_regd = cfg80211_regd;
> +
> + wiphy2_regd = rcu_dereference(wiphy2->regd);
> + if (!wiphy2_regd)
> + wiphy2_regd = cfg80211_regd;
> +
> + if (wiphy1_regd->dfs_region == wiphy2_regd->dfs_region)
> + dfs_domain_same = true;
and just assign
dfs_domain_same = wiphy1... == wiphy2...;
> +static void wiphy_share_dfs_chan_state(struct wiphy *dst_wiphy,
> + struct wiphy *src_wiphy)
> +{
> + struct ieee80211_supported_band *src_sband, *dst_sband;
> + int i, j;
> +
> + dst_sband = dst_wiphy->bands[NL80211_BAND_5GHZ];
> + src_sband = src_wiphy->bands[NL80211_BAND_5GHZ];
> + if (!dst_sband || !src_sband)
> + return;
Why make this 5 GHz specific? Perhaps some kind of radar stuff will
exist in future bands too. It shouldn't really cost much to iterate all
the bands, I think?
johannes