aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>2017-02-27 06:34:35 -0500
committerJohannes Berg <johannes.berg@intel.com>2017-03-06 07:54:20 -0500
commit8976672736d6089ae011fda3482e30e4380276f8 (patch)
tree9504bcc8b250ed1cf266c9083cef2909771a1cca
parent34373d12f3cbb74960a73431138ef619d857996f (diff)
cfg80211: Share Channel DFS state across wiphys of same DFS domain
Sharing DFS channel state across multiple wiphys (radios) could be useful with multiple radios on the system. When one radio completes CAC and markes 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 <vthiagar@qti.qualcomm.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/wireless/chan.c30
-rw-r--r--net/wireless/core.c37
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/mlme.c10
-rw-r--r--net/wireless/reg.c120
-rw-r--r--net/wireless/reg.h22
6 files changed, 218 insertions, 7 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 099f13c0c39e..b8aa5a7d5c77 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -531,16 +531,11 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
531 return active; 531 return active;
532} 532}
533 533
534bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, 534static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
535 struct ieee80211_channel *chan) 535 struct ieee80211_channel *chan)
536{ 536{
537 struct wireless_dev *wdev; 537 struct wireless_dev *wdev;
538 538
539 ASSERT_RTNL();
540
541 if (!(chan->flags & IEEE80211_CHAN_RADAR))
542 return false;
543
544 list_for_each_entry(wdev, &wiphy->wdev_list, list) { 539 list_for_each_entry(wdev, &wiphy->wdev_list, list) {
545 wdev_lock(wdev); 540 wdev_lock(wdev);
546 if (!cfg80211_beaconing_iface_active(wdev)) { 541 if (!cfg80211_beaconing_iface_active(wdev)) {
@@ -558,6 +553,27 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
558 return false; 553 return false;
559} 554}
560 555
556bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
557 struct ieee80211_channel *chan)
558{
559 struct cfg80211_registered_device *rdev;
560
561 ASSERT_RTNL();
562
563 if (!(chan->flags & IEEE80211_CHAN_RADAR))
564 return false;
565
566 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
567 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
568 continue;
569
570 if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
571 return true;
572 }
573
574 return false;
575}
576
561static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy, 577static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
562 u32 center_freq, 578 u32 center_freq,
563 u32 bandwidth) 579 u32 bandwidth)
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 76e664144c8e..b1a028d381ef 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)
357 rtnl_unlock(); 357 rtnl_unlock();
358} 358}
359 359
360static void cfg80211_propagate_radar_detect_wk(struct work_struct *work)
361{
362 struct cfg80211_registered_device *rdev;
363
364 rdev = container_of(work, struct cfg80211_registered_device,
365 propagate_radar_detect_wk);
366
367 rtnl_lock();
368
369 regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->radar_chandef,
370 NL80211_DFS_UNAVAILABLE,
371 NL80211_RADAR_DETECTED);
372
373 rtnl_unlock();
374}
375
376static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
377{
378 struct cfg80211_registered_device *rdev;
379
380 rdev = container_of(work, struct cfg80211_registered_device,
381 propagate_cac_done_wk);
382
383 rtnl_lock();
384
385 regulatory_propagate_dfs_state(&rdev->wiphy, &rdev->cac_done_chandef,
386 NL80211_DFS_AVAILABLE,
387 NL80211_RADAR_CAC_FINISHED);
388
389 rtnl_unlock();
390}
391
360/* exported functions */ 392/* exported functions */
361 393
362struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, 394struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -456,6 +488,9 @@ use_default_name:
456 spin_lock_init(&rdev->destroy_list_lock); 488 spin_lock_init(&rdev->destroy_list_lock);
457 INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk); 489 INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
458 INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk); 490 INIT_WORK(&rdev->sched_scan_stop_wk, cfg80211_sched_scan_stop_wk);
491 INIT_WORK(&rdev->propagate_radar_detect_wk,
492 cfg80211_propagate_radar_detect_wk);
493 INIT_WORK(&rdev->propagate_cac_done_wk, cfg80211_propagate_cac_done_wk);
459 494
460#ifdef CONFIG_CFG80211_DEFAULT_PS 495#ifdef CONFIG_CFG80211_DEFAULT_PS
461 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; 496 rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -915,6 +950,8 @@ void wiphy_unregister(struct wiphy *wiphy)
915 flush_work(&rdev->destroy_work); 950 flush_work(&rdev->destroy_work);
916 flush_work(&rdev->sched_scan_stop_wk); 951 flush_work(&rdev->sched_scan_stop_wk);
917 flush_work(&rdev->mlme_unreg_wk); 952 flush_work(&rdev->mlme_unreg_wk);
953 flush_work(&rdev->propagate_radar_detect_wk);
954 flush_work(&rdev->propagate_cac_done_wk);
918 955
919#ifdef CONFIG_PM 956#ifdef CONFIG_PM
920 if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) 957 if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 519a29ebde5b..a2fe8fc93283 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -97,6 +97,12 @@ struct cfg80211_registered_device {
97 97
98 struct work_struct sched_scan_stop_wk; 98 struct work_struct sched_scan_stop_wk;
99 99
100 struct cfg80211_chan_def radar_chandef;
101 struct work_struct propagate_radar_detect_wk;
102
103 struct cfg80211_chan_def cac_done_chandef;
104 struct work_struct propagate_cac_done_wk;
105
100 /* must be last because of the way we do wiphy_priv(), 106 /* must be last because of the way we do wiphy_priv(),
101 * and it should at least be aligned to NETDEV_ALIGN */ 107 * and it should at least be aligned to NETDEV_ALIGN */
102 struct wiphy wiphy __aligned(NETDEV_ALIGN); 108 struct wiphy wiphy __aligned(NETDEV_ALIGN);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index cd29366a5206..01ce4a69e44d 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -810,6 +810,10 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
810 nl80211_radar_notify(rdev, &chandef, 810 nl80211_radar_notify(rdev, &chandef,
811 radar_event, NULL, 811 radar_event, NULL,
812 GFP_ATOMIC); 812 GFP_ATOMIC);
813
814 regulatory_propagate_dfs_state(wiphy, &chandef,
815 c->dfs_state,
816 radar_event);
813 continue; 817 continue;
814 } 818 }
815 819
@@ -846,6 +850,9 @@ void cfg80211_radar_event(struct wiphy *wiphy,
846 cfg80211_sched_dfs_chan_update(rdev); 850 cfg80211_sched_dfs_chan_update(rdev);
847 851
848 nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); 852 nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
853
854 memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def));
855 queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
849} 856}
850EXPORT_SYMBOL(cfg80211_radar_event); 857EXPORT_SYMBOL(cfg80211_radar_event);
851 858
@@ -872,6 +879,9 @@ void cfg80211_cac_event(struct net_device *netdev,
872 msecs_to_jiffies(wdev->cac_time_ms); 879 msecs_to_jiffies(wdev->cac_time_ms);
873 WARN_ON(!time_after_eq(jiffies, timeout)); 880 WARN_ON(!time_after_eq(jiffies, timeout));
874 cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); 881 cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
882 memcpy(&rdev->cac_done_chandef, chandef,
883 sizeof(struct cfg80211_chan_def));
884 queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
875 cfg80211_sched_dfs_chan_update(rdev); 885 cfg80211_sched_dfs_chan_update(rdev);
876 break; 886 break;
877 case NL80211_RADAR_CAC_ABORTED: 887 case NL80211_RADAR_CAC_ABORTED:
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index e59b192459e8..a38f315819cd 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2067,6 +2067,88 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
2067 return REG_REQ_IGNORE; 2067 return REG_REQ_IGNORE;
2068} 2068}
2069 2069
2070bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2)
2071{
2072 const struct ieee80211_regdomain *wiphy1_regd = NULL;
2073 const struct ieee80211_regdomain *wiphy2_regd = NULL;
2074 const struct ieee80211_regdomain *cfg80211_regd = NULL;
2075 bool dfs_domain_same;
2076
2077 rcu_read_lock();
2078
2079 cfg80211_regd = rcu_dereference(cfg80211_regdomain);
2080 wiphy1_regd = rcu_dereference(wiphy1->regd);
2081 if (!wiphy1_regd)
2082 wiphy1_regd = cfg80211_regd;
2083
2084 wiphy2_regd = rcu_dereference(wiphy2->regd);
2085 if (!wiphy2_regd)
2086 wiphy2_regd = cfg80211_regd;
2087
2088 dfs_domain_same = wiphy1_regd->dfs_region == wiphy2_regd->dfs_region;
2089
2090 rcu_read_unlock();
2091
2092 return dfs_domain_same;
2093}
2094
2095static void reg_copy_dfs_chan_state(struct ieee80211_channel *dst_chan,
2096 struct ieee80211_channel *src_chan)
2097{
2098 if (!(dst_chan->flags & IEEE80211_CHAN_RADAR) ||
2099 !(src_chan->flags & IEEE80211_CHAN_RADAR))
2100 return;
2101
2102 if (dst_chan->flags & IEEE80211_CHAN_DISABLED ||
2103 src_chan->flags & IEEE80211_CHAN_DISABLED)
2104 return;
2105
2106 if (src_chan->center_freq == dst_chan->center_freq &&
2107 dst_chan->dfs_state == NL80211_DFS_USABLE) {
2108 dst_chan->dfs_state = src_chan->dfs_state;
2109 dst_chan->dfs_state_entered = src_chan->dfs_state_entered;
2110 }
2111}
2112
2113static void wiphy_share_dfs_chan_state(struct wiphy *dst_wiphy,
2114 struct wiphy *src_wiphy)
2115{
2116 struct ieee80211_supported_band *src_sband, *dst_sband;
2117 struct ieee80211_channel *src_chan, *dst_chan;
2118 int i, j, band;
2119
2120 if (!reg_dfs_domain_same(dst_wiphy, src_wiphy))
2121 return;
2122
2123 for (band = 0; band < NUM_NL80211_BANDS; band++) {
2124 dst_sband = dst_wiphy->bands[band];
2125 src_sband = src_wiphy->bands[band];
2126 if (!dst_sband || !src_sband)
2127 continue;
2128
2129 for (i = 0; i < dst_sband->n_channels; i++) {
2130 dst_chan = &dst_sband->channels[i];
2131 for (j = 0; j < src_sband->n_channels; j++) {
2132 src_chan = &src_sband->channels[j];
2133 reg_copy_dfs_chan_state(dst_chan, src_chan);
2134 }
2135 }
2136 }
2137}
2138
2139static void wiphy_all_share_dfs_chan_state(struct wiphy *wiphy)
2140{
2141 struct cfg80211_registered_device *rdev;
2142
2143 ASSERT_RTNL();
2144
2145 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
2146 if (wiphy == &rdev->wiphy)
2147 continue;
2148 wiphy_share_dfs_chan_state(wiphy, &rdev->wiphy);
2149 }
2150}
2151
2070/* This processes *all* regulatory hints */ 2152/* This processes *all* regulatory hints */
2071static void reg_process_hint(struct regulatory_request *reg_request) 2153static void reg_process_hint(struct regulatory_request *reg_request)
2072{ 2154{
@@ -2110,6 +2192,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
2110 if (treatment == REG_REQ_ALREADY_SET && wiphy && 2192 if (treatment == REG_REQ_ALREADY_SET && wiphy &&
2111 wiphy->regulatory_flags & REGULATORY_STRICT_REG) { 2193 wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
2112 wiphy_update_regulatory(wiphy, reg_request->initiator); 2194 wiphy_update_regulatory(wiphy, reg_request->initiator);
2195 wiphy_all_share_dfs_chan_state(wiphy);
2113 reg_check_channels(); 2196 reg_check_channels();
2114 } 2197 }
2115 2198
@@ -3061,6 +3144,7 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
3061 3144
3062 lr = get_last_request(); 3145 lr = get_last_request();
3063 wiphy_update_regulatory(wiphy, lr->initiator); 3146 wiphy_update_regulatory(wiphy, lr->initiator);
3147 wiphy_all_share_dfs_chan_state(wiphy);
3064} 3148}
3065 3149
3066void wiphy_regulatory_deregister(struct wiphy *wiphy) 3150void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -3148,6 +3232,42 @@ bool regulatory_pre_cac_allowed(struct wiphy *wiphy)
3148 return pre_cac_allowed; 3232 return pre_cac_allowed;
3149} 3233}
3150 3234
3235void regulatory_propagate_dfs_state(struct wiphy *wiphy,
3236 struct cfg80211_chan_def *chandef,
3237 enum nl80211_dfs_state dfs_state,
3238 enum nl80211_radar_event event)
3239{
3240 struct cfg80211_registered_device *rdev;
3241
3242 ASSERT_RTNL();
3243
3244 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
3245 return;
3246
3247 if (WARN_ON(!(chandef->chan->flags & IEEE80211_CHAN_RADAR)))
3248 return;
3249
3250 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
3251 if (wiphy == &rdev->wiphy)
3252 continue;
3253
3254 if (!reg_dfs_domain_same(wiphy, &rdev->wiphy))
3255 continue;
3256
3257 if (!ieee80211_get_channel(&rdev->wiphy,
3258 chandef->chan->center_freq))
3259 continue;
3260
3261 cfg80211_set_dfs_state(&rdev->wiphy, chandef, dfs_state);
3262
3263 if (event == NL80211_RADAR_DETECTED ||
3264 event == NL80211_RADAR_CAC_FINISHED)
3265 cfg80211_sched_dfs_chan_update(rdev);
3266
3267 nl80211_radar_notify(rdev, chandef, event, NULL, GFP_KERNEL);
3268 }
3269}
3270
3151int __init regulatory_init(void) 3271int __init regulatory_init(void)
3152{ 3272{
3153 int err = 0; 3273 int err = 0;
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index ff078f093989..ca7fedf2e7a1 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -157,4 +157,26 @@ bool regulatory_indoor_allowed(void);
157 * Pre-CAC is allowed only in ETSI domain. 157 * Pre-CAC is allowed only in ETSI domain.
158 */ 158 */
159bool regulatory_pre_cac_allowed(struct wiphy *wiphy); 159bool regulatory_pre_cac_allowed(struct wiphy *wiphy);
160
161/**
162 * regulatory_propagate_dfs_state - Propagate DFS channel state to other wiphys
163 * @wiphy - wiphy on which radar is detected and the event will be propagated
164 * to other available wiphys having the same DFS domain
165 * @chandef - Channel definition of radar detected channel
166 * @dfs_state - DFS channel state to be set
167 * @event - Type of radar event which triggered this DFS state change
168 *
169 * This function should be called with rtnl lock held.
170 */
171void regulatory_propagate_dfs_state(struct wiphy *wiphy,
172 struct cfg80211_chan_def *chandef,
173 enum nl80211_dfs_state dfs_state,
174 enum nl80211_radar_event event);
175
176/**
177 * reg_dfs_domain_same - Checks if both wiphy have same DFS domain configured
178 * @wiphy1 - wiphy it's dfs_region to be checked against that of wiphy2
179 * @wiphy2 - wiphy it's dfs_region to be checked against that of wiphy1
180 */
181bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
160#endif /* __NET_WIRELESS_REG_H */ 182#endif /* __NET_WIRELESS_REG_H */