Skip to content

Commit 8976672

Browse files
Vasanthakumar Thiagarajanjmberg-intel
authored andcommitted
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>
1 parent 34373d1 commit 8976672

6 files changed

Lines changed: 218 additions & 7 deletions

File tree

net/wireless/chan.c

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -531,16 +531,11 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
531531
return active;
532532
}
533533

534-
bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
535-
struct ieee80211_channel *chan)
534+
static bool cfg80211_is_wiphy_oper_chan(struct wiphy *wiphy,
535+
struct ieee80211_channel *chan)
536536
{
537537
struct wireless_dev *wdev;
538538

539-
ASSERT_RTNL();
540-
541-
if (!(chan->flags & IEEE80211_CHAN_RADAR))
542-
return false;
543-
544539
list_for_each_entry(wdev, &wiphy->wdev_list, list) {
545540
wdev_lock(wdev);
546541
if (!cfg80211_beaconing_iface_active(wdev)) {
@@ -558,6 +553,27 @@ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
558553
return false;
559554
}
560555

556+
bool 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+
561577
static bool cfg80211_get_chans_dfs_available(struct wiphy *wiphy,
562578
u32 center_freq,
563579
u32 bandwidth)

net/wireless/core.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,38 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
357357
rtnl_unlock();
358358
}
359359

360+
static 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+
376+
static 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+
360392
/* exported functions */
361393

362394
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,
456488
spin_lock_init(&rdev->destroy_list_lock);
457489
INIT_WORK(&rdev->destroy_work, cfg80211_destroy_iface_wk);
458490
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);
459494

460495
#ifdef CONFIG_CFG80211_DEFAULT_PS
461496
rdev->wiphy.flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -915,6 +950,8 @@ void wiphy_unregister(struct wiphy *wiphy)
915950
flush_work(&rdev->destroy_work);
916951
flush_work(&rdev->sched_scan_stop_wk);
917952
flush_work(&rdev->mlme_unreg_wk);
953+
flush_work(&rdev->propagate_radar_detect_wk);
954+
flush_work(&rdev->propagate_cac_done_wk);
918955

919956
#ifdef CONFIG_PM
920957
if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)

net/wireless/core.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@ struct cfg80211_registered_device {
9797

9898
struct work_struct sched_scan_stop_wk;
9999

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+
100106
/* must be last because of the way we do wiphy_priv(),
101107
* and it should at least be aligned to NETDEV_ALIGN */
102108
struct wiphy wiphy __aligned(NETDEV_ALIGN);

net/wireless/mlme.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,10 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
810810
nl80211_radar_notify(rdev, &chandef,
811811
radar_event, NULL,
812812
GFP_ATOMIC);
813+
814+
regulatory_propagate_dfs_state(wiphy, &chandef,
815+
c->dfs_state,
816+
radar_event);
813817
continue;
814818
}
815819

@@ -846,6 +850,9 @@ void cfg80211_radar_event(struct wiphy *wiphy,
846850
cfg80211_sched_dfs_chan_update(rdev);
847851

848852
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);
849856
}
850857
EXPORT_SYMBOL(cfg80211_radar_event);
851858

@@ -872,6 +879,9 @@ void cfg80211_cac_event(struct net_device *netdev,
872879
msecs_to_jiffies(wdev->cac_time_ms);
873880
WARN_ON(!time_after_eq(jiffies, timeout));
874881
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);
875885
cfg80211_sched_dfs_chan_update(rdev);
876886
break;
877887
case NL80211_RADAR_CAC_ABORTED:

net/wireless/reg.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,88 @@ reg_process_hint_country_ie(struct wiphy *wiphy,
20672067
return REG_REQ_IGNORE;
20682068
}
20692069

2070+
bool 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+
2095+
static 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+
2113+
static 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+
2139+
static 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+
20702152
/* This processes *all* regulatory hints */
20712153
static void reg_process_hint(struct regulatory_request *reg_request)
20722154
{
@@ -2110,6 +2192,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
21102192
if (treatment == REG_REQ_ALREADY_SET && wiphy &&
21112193
wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
21122194
wiphy_update_regulatory(wiphy, reg_request->initiator);
2195+
wiphy_all_share_dfs_chan_state(wiphy);
21132196
reg_check_channels();
21142197
}
21152198

@@ -3061,6 +3144,7 @@ void wiphy_regulatory_register(struct wiphy *wiphy)
30613144

30623145
lr = get_last_request();
30633146
wiphy_update_regulatory(wiphy, lr->initiator);
3147+
wiphy_all_share_dfs_chan_state(wiphy);
30643148
}
30653149

30663150
void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -3148,6 +3232,42 @@ bool regulatory_pre_cac_allowed(struct wiphy *wiphy)
31483232
return pre_cac_allowed;
31493233
}
31503234

3235+
void 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+
31513271
int __init regulatory_init(void)
31523272
{
31533273
int err = 0;

net/wireless/reg.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,26 @@ bool regulatory_indoor_allowed(void);
157157
* Pre-CAC is allowed only in ETSI domain.
158158
*/
159159
bool 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+
*/
171+
void 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+
*/
181+
bool reg_dfs_domain_same(struct wiphy *wiphy1, struct wiphy *wiphy2);
160182
#endif /* __NET_WIRELESS_REG_H */

0 commit comments

Comments
 (0)