|
@@ -2067,6 +2067,88 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
|
|
return REG_REQ_IGNORE;
|
|
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;
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+
|
|
|
|
+ dfs_domain_same = wiphy1_regd->dfs_region == wiphy2_regd->dfs_region;
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+ struct ieee80211_channel *src_chan, *dst_chan;
|
|
|
|
+ int i, j, band;
|
|
|
|
+
|
|
|
|
+ if (!reg_dfs_domain_same(dst_wiphy, src_wiphy))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
|
|
|
|
+ dst_sband = dst_wiphy->bands[band];
|
|
|
|
+ src_sband = src_wiphy->bands[band];
|
|
|
|
+ if (!dst_sband || !src_sband)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < dst_sband->n_channels; i++) {
|
|
|
|
+ dst_chan = &dst_sband->channels[i];
|
|
|
|
+ for (j = 0; j < src_sband->n_channels; j++) {
|
|
|
|
+ src_chan = &src_sband->channels[j];
|
|
|
|
+ reg_copy_dfs_chan_state(dst_chan, src_chan);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+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 */
|
|
/* This processes *all* regulatory hints */
|
|
static void reg_process_hint(struct regulatory_request *reg_request)
|
|
static void reg_process_hint(struct regulatory_request *reg_request)
|
|
{
|
|
{
|
|
@@ -2110,6 +2192,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
|
|
if (treatment == REG_REQ_ALREADY_SET && wiphy &&
|
|
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);
|
|
wiphy_update_regulatory(wiphy, reg_request->initiator);
|
|
|
|
+ wiphy_all_share_dfs_chan_state(wiphy);
|
|
reg_check_channels();
|
|
reg_check_channels();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3061,6 +3144,7 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
|
|
|
|
|
|
lr = get_last_request();
|
|
lr = get_last_request();
|
|
wiphy_update_regulatory(wiphy, lr->initiator);
|
|
wiphy_update_regulatory(wiphy, lr->initiator);
|
|
|
|
+ wiphy_all_share_dfs_chan_state(wiphy);
|
|
}
|
|
}
|
|
|
|
|
|
void wiphy_regulatory_deregister(struct wiphy *wiphy)
|
|
void wiphy_regulatory_deregister(struct wiphy *wiphy)
|
|
@@ -3148,6 +3232,42 @@ bool regulatory_pre_cac_allowed(struct wiphy *wiphy)
|
|
return pre_cac_allowed;
|
|
return pre_cac_allowed;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+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(!cfg80211_chandef_valid(chandef)))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ 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 __init regulatory_init(void)
|
|
{
|
|
{
|
|
int err = 0;
|
|
int err = 0;
|