aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de>2013-02-08 12:16:19 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-15 03:40:18 -0500
commit04f39047af2a6df64b763ea5a271db24879d0391 (patch)
tree883a946e25f18e27abad2ed487a4ed4c88ff349c
parent2a0e047ed62f20664005881b8e7f9328f910316a (diff)
nl80211/cfg80211: add radar detection command/event
Add new NL80211_CMD_RADAR_DETECT, which starts the Channel Availability Check (CAC). This command will also notify the usermode about events (CAC finished, CAC aborted, radar detected, NOP finished). Once radar detection has started it should continuously monitor for radars as long as the channel is active. This patch enables DFS for AP mode in nl80211/cfg80211. Based on original patch by Victor Goldenshtein <victorg@ti.com> Signed-off-by: Simon Wunderlich <siwu@hrz.tu-chemnitz.de> [remove WIPHY_FLAG_HAS_RADAR_DETECT again -- my mistake] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--include/net/cfg80211.h46
-rw-r--r--include/uapi/linux/nl80211.h61
-rw-r--r--net/wireless/chan.c129
-rw-r--r--net/wireless/core.c3
-rw-r--r--net/wireless/core.h28
-rw-r--r--net/wireless/mlme.c120
-rw-r--r--net/wireless/nl80211.c135
-rw-r--r--net/wireless/nl80211.h7
-rw-r--r--net/wireless/reg.c3
-rw-r--r--net/wireless/scan.c10
-rw-r--r--net/wireless/trace.h45
11 files changed, 570 insertions, 17 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7e6569e1f16f..ee11a3db730b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -114,6 +114,9 @@ enum ieee80211_channel_flags {
114#define IEEE80211_CHAN_NO_HT40 \ 114#define IEEE80211_CHAN_NO_HT40 \
115 (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) 115 (IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
116 116
117#define IEEE80211_DFS_MIN_CAC_TIME_MS 60000
118#define IEEE80211_DFS_MIN_NOP_TIME_MS (30 * 60 * 1000)
119
117/** 120/**
118 * struct ieee80211_channel - channel definition 121 * struct ieee80211_channel - channel definition
119 * 122 *
@@ -134,6 +137,9 @@ enum ieee80211_channel_flags {
134 * to enable this, this is useful only on 5 GHz band. 137 * to enable this, this is useful only on 5 GHz band.
135 * @orig_mag: internal use 138 * @orig_mag: internal use
136 * @orig_mpwr: internal use 139 * @orig_mpwr: internal use
140 * @dfs_state: current state of this channel. Only relevant if radar is required
141 * on this channel.
142 * @dfs_state_entered: timestamp (jiffies) when the dfs state was entered.
137 */ 143 */
138struct ieee80211_channel { 144struct ieee80211_channel {
139 enum ieee80211_band band; 145 enum ieee80211_band band;
@@ -146,6 +152,8 @@ struct ieee80211_channel {
146 bool beacon_found; 152 bool beacon_found;
147 u32 orig_flags; 153 u32 orig_flags;
148 int orig_mag, orig_mpwr; 154 int orig_mag, orig_mpwr;
155 enum nl80211_dfs_state dfs_state;
156 unsigned long dfs_state_entered;
149}; 157};
150 158
151/** 159/**
@@ -569,6 +577,7 @@ struct cfg80211_acl_data {
569 * @p2p_opp_ps: P2P opportunistic PS 577 * @p2p_opp_ps: P2P opportunistic PS
570 * @acl: ACL configuration used by the drivers which has support for 578 * @acl: ACL configuration used by the drivers which has support for
571 * MAC address based access control 579 * MAC address based access control
580 * @radar_required: set if radar detection is required
572 */ 581 */
573struct cfg80211_ap_settings { 582struct cfg80211_ap_settings {
574 struct cfg80211_chan_def chandef; 583 struct cfg80211_chan_def chandef;
@@ -586,6 +595,7 @@ struct cfg80211_ap_settings {
586 u8 p2p_ctwindow; 595 u8 p2p_ctwindow;
587 bool p2p_opp_ps; 596 bool p2p_opp_ps;
588 const struct cfg80211_acl_data *acl; 597 const struct cfg80211_acl_data *acl;
598 bool radar_required;
589}; 599};
590 600
591/** 601/**
@@ -1909,6 +1919,8 @@ struct cfg80211_gtk_rekey_data {
1909 * this new list replaces the existing one. Driver has to clear its ACL 1919 * this new list replaces the existing one. Driver has to clear its ACL
1910 * when number of MAC addresses entries is passed as 0. Drivers which 1920 * when number of MAC addresses entries is passed as 0. Drivers which
1911 * advertise the support for MAC based ACL have to implement this callback. 1921 * advertise the support for MAC based ACL have to implement this callback.
1922 *
1923 * @start_radar_detection: Start radar detection in the driver.
1912 */ 1924 */
1913struct cfg80211_ops { 1925struct cfg80211_ops {
1914 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); 1926 int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2132,6 +2144,10 @@ struct cfg80211_ops {
2132 2144
2133 int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev, 2145 int (*set_mac_acl)(struct wiphy *wiphy, struct net_device *dev,
2134 const struct cfg80211_acl_data *params); 2146 const struct cfg80211_acl_data *params);
2147
2148 int (*start_radar_detection)(struct wiphy *wiphy,
2149 struct net_device *dev,
2150 struct cfg80211_chan_def *chandef);
2135}; 2151};
2136 2152
2137/* 2153/*
@@ -2715,6 +2731,8 @@ struct cfg80211_cached_keys;
2715 * beacons, 0 when not valid 2731 * beacons, 0 when not valid
2716 * @address: The address for this device, valid only if @netdev is %NULL 2732 * @address: The address for this device, valid only if @netdev is %NULL
2717 * @p2p_started: true if this is a P2P Device that has been started 2733 * @p2p_started: true if this is a P2P Device that has been started
2734 * @cac_started: true if DFS channel availability check has been started
2735 * @cac_start_time: timestamp (jiffies) when the dfs state was entered.
2718 */ 2736 */
2719struct wireless_dev { 2737struct wireless_dev {
2720 struct wiphy *wiphy; 2738 struct wiphy *wiphy;
@@ -2766,6 +2784,9 @@ struct wireless_dev {
2766 2784
2767 u32 ap_unexpected_nlportid; 2785 u32 ap_unexpected_nlportid;
2768 2786
2787 bool cac_started;
2788 unsigned long cac_start_time;
2789
2769#ifdef CONFIG_CFG80211_WEXT 2790#ifdef CONFIG_CFG80211_WEXT
2770 /* wext data */ 2791 /* wext data */
2771 struct { 2792 struct {
@@ -3755,6 +3776,31 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
3755 gfp_t gfp); 3776 gfp_t gfp);
3756 3777
3757/** 3778/**
3779 * cfg80211_radar_event - radar detection event
3780 * @wiphy: the wiphy
3781 * @chandef: chandef for the current channel
3782 * @gfp: context flags
3783 *
3784 * This function is called when a radar is detected on the current chanenl.
3785 */
3786void cfg80211_radar_event(struct wiphy *wiphy,
3787 struct cfg80211_chan_def *chandef, gfp_t gfp);
3788
3789/**
3790 * cfg80211_cac_event - Channel availability check (CAC) event
3791 * @netdev: network device
3792 * @event: type of event
3793 * @gfp: context flags
3794 *
3795 * This function is called when a Channel availability check (CAC) is finished
3796 * or aborted. This must be called to notify the completion of a CAC process,
3797 * also by full-MAC drivers.
3798 */
3799void cfg80211_cac_event(struct net_device *netdev,
3800 enum nl80211_radar_event event, gfp_t gfp);
3801
3802
3803/**
3758 * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer 3804 * cfg80211_cqm_pktloss_notify - notify userspace about packetloss to peer
3759 * @dev: network device 3805 * @dev: network device
3760 * @peer: peer's MAC address 3806 * @peer: peer's MAC address
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 5309b34930ea..90b7af86f392 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -603,6 +603,14 @@
603 * command is used in AP/P2P GO mode. Driver has to make sure to clear its 603 * command is used in AP/P2P GO mode. Driver has to make sure to clear its
604 * ACL list during %NL80211_CMD_STOP_AP. 604 * ACL list during %NL80211_CMD_STOP_AP.
605 * 605 *
606 * @NL80211_CMD_RADAR_DETECT: Start a Channel availability check (CAC). Once
607 * a radar is detected or the channel availability scan (CAC) has finished
608 * or was aborted, or a radar was detected, usermode will be notified with
609 * this event. This command is also used to notify userspace about radars
610 * while operating on this channel.
611 * %NL80211_ATTR_RADAR_EVENT is used to inform about the type of the
612 * event.
613 *
606 * @NL80211_CMD_MAX: highest used command number 614 * @NL80211_CMD_MAX: highest used command number
607 * @__NL80211_CMD_AFTER_LAST: internal use 615 * @__NL80211_CMD_AFTER_LAST: internal use
608 */ 616 */
@@ -755,6 +763,8 @@ enum nl80211_commands {
755 763
756 NL80211_CMD_SET_MAC_ACL, 764 NL80211_CMD_SET_MAC_ACL,
757 765
766 NL80211_CMD_RADAR_DETECT,
767
758 /* add new commands above here */ 768 /* add new commands above here */
759 769
760 /* used to define NL80211_CMD_MAX below */ 770 /* used to define NL80211_CMD_MAX below */
@@ -1342,6 +1352,9 @@ enum nl80211_commands {
1342 * number of MAC addresses that a device can support for MAC 1352 * number of MAC addresses that a device can support for MAC
1343 * ACL. 1353 * ACL.
1344 * 1354 *
1355 * @NL80211_ATTR_RADAR_EVENT: Type of radar event for notification to userspace,
1356 * contains a value of enum nl80211_radar_event (u32).
1357 *
1345 * @NL80211_ATTR_MAX: highest attribute number currently defined 1358 * @NL80211_ATTR_MAX: highest attribute number currently defined
1346 * @__NL80211_ATTR_AFTER_LAST: internal use 1359 * @__NL80211_ATTR_AFTER_LAST: internal use
1347 */ 1360 */
@@ -1620,6 +1633,8 @@ enum nl80211_attrs {
1620 1633
1621 NL80211_ATTR_MAC_ACL_MAX, 1634 NL80211_ATTR_MAC_ACL_MAX,
1622 1635
1636 NL80211_ATTR_RADAR_EVENT,
1637
1623 /* add attributes here, update the policy in nl80211.c */ 1638 /* add attributes here, update the policy in nl80211.c */
1624 1639
1625 __NL80211_ATTR_AFTER_LAST, 1640 __NL80211_ATTR_AFTER_LAST,
@@ -2022,6 +2037,10 @@ enum nl80211_band_attr {
2022 * on this channel in current regulatory domain. 2037 * on this channel in current regulatory domain.
2023 * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm 2038 * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
2024 * (100 * dBm). 2039 * (100 * dBm).
2040 * @NL80211_FREQUENCY_ATTR_DFS_STATE: current state for DFS
2041 * (enum nl80211_dfs_state)
2042 * @NL80211_FREQUENCY_ATTR_DFS_TIME: time in miliseconds for how long
2043 * this channel is in this DFS state.
2025 * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number 2044 * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
2026 * currently defined 2045 * currently defined
2027 * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use 2046 * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
@@ -2034,6 +2053,8 @@ enum nl80211_frequency_attr {
2034 NL80211_FREQUENCY_ATTR_NO_IBSS, 2053 NL80211_FREQUENCY_ATTR_NO_IBSS,
2035 NL80211_FREQUENCY_ATTR_RADAR, 2054 NL80211_FREQUENCY_ATTR_RADAR,
2036 NL80211_FREQUENCY_ATTR_MAX_TX_POWER, 2055 NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
2056 NL80211_FREQUENCY_ATTR_DFS_STATE,
2057 NL80211_FREQUENCY_ATTR_DFS_TIME,
2037 2058
2038 /* keep last */ 2059 /* keep last */
2039 __NL80211_FREQUENCY_ATTR_AFTER_LAST, 2060 __NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -3489,4 +3510,44 @@ enum nl80211_acl_policy {
3489 NL80211_ACL_POLICY_DENY_UNLESS_LISTED, 3510 NL80211_ACL_POLICY_DENY_UNLESS_LISTED,
3490}; 3511};
3491 3512
3513/**
3514 * enum nl80211_radar_event - type of radar event for DFS operation
3515 *
3516 * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace
3517 * about detected radars or success of the channel available check (CAC)
3518 *
3519 * @NL80211_RADAR_DETECTED: A radar pattern has been detected. The channel is
3520 * now unusable.
3521 * @NL80211_RADAR_CAC_FINISHED: Channel Availability Check has been finished,
3522 * the channel is now available.
3523 * @NL80211_RADAR_CAC_ABORTED: Channel Availability Check has been aborted, no
3524 * change to the channel status.
3525 * @NL80211_RADAR_NOP_FINISHED: The Non-Occupancy Period for this channel is
3526 * over, channel becomes usable.
3527 */
3528enum nl80211_radar_event {
3529 NL80211_RADAR_DETECTED,
3530 NL80211_RADAR_CAC_FINISHED,
3531 NL80211_RADAR_CAC_ABORTED,
3532 NL80211_RADAR_NOP_FINISHED,
3533};
3534
3535/**
3536 * enum nl80211_dfs_state - DFS states for channels
3537 *
3538 * Channel states used by the DFS code.
3539 *
3540 * @IEEE80211_DFS_USABLE: The channel can be used, but channel availability
3541 * check (CAC) must be performed before using it for AP or IBSS.
3542 * @IEEE80211_DFS_UNAVAILABLE: A radar has been detected on this channel, it
3543 * is therefore marked as not available.
3544 * @IEEE80211_DFS_AVAILABLE: The channel has been CAC checked and is available.
3545 */
3546
3547enum nl80211_dfs_state {
3548 NL80211_DFS_USABLE,
3549 NL80211_DFS_UNAVAILABLE,
3550 NL80211_DFS_AVAILABLE,
3551};
3552
3492#endif /* __LINUX_NL80211_H */ 3553#endif /* __LINUX_NL80211_H */
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 396373f3ec26..810c23cfb894 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -147,6 +147,32 @@ static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
147 } 147 }
148} 148}
149 149
150static int cfg80211_chandef_get_width(const struct cfg80211_chan_def *c)
151{
152 int width;
153
154 switch (c->width) {
155 case NL80211_CHAN_WIDTH_20:
156 case NL80211_CHAN_WIDTH_20_NOHT:
157 width = 20;
158 break;
159 case NL80211_CHAN_WIDTH_40:
160 width = 40;
161 break;
162 case NL80211_CHAN_WIDTH_80P80:
163 case NL80211_CHAN_WIDTH_80:
164 width = 80;
165 break;
166 case NL80211_CHAN_WIDTH_160:
167 width = 160;
168 break;
169 default:
170 WARN_ON_ONCE(1);
171 return -1;
172 }
173 return width;
174}
175
150const struct cfg80211_chan_def * 176const struct cfg80211_chan_def *
151cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1, 177cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
152 const struct cfg80211_chan_def *c2) 178 const struct cfg80211_chan_def *c2)
@@ -192,6 +218,93 @@ cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
192} 218}
193EXPORT_SYMBOL(cfg80211_chandef_compatible); 219EXPORT_SYMBOL(cfg80211_chandef_compatible);
194 220
221static void cfg80211_set_chans_dfs_state(struct wiphy *wiphy, u32 center_freq,
222 u32 bandwidth,
223 enum nl80211_dfs_state dfs_state)
224{
225 struct ieee80211_channel *c;
226 u32 freq;
227
228 for (freq = center_freq - bandwidth/2 + 10;
229 freq <= center_freq + bandwidth/2 - 10;
230 freq += 20) {
231 c = ieee80211_get_channel(wiphy, freq);
232 if (!c || !(c->flags & IEEE80211_CHAN_RADAR))
233 continue;
234
235 c->dfs_state = dfs_state;
236 c->dfs_state_entered = jiffies;
237 }
238}
239
240void cfg80211_set_dfs_state(struct wiphy *wiphy,
241 const struct cfg80211_chan_def *chandef,
242 enum nl80211_dfs_state dfs_state)
243{
244 int width;
245
246 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
247 return;
248
249 width = cfg80211_chandef_get_width(chandef);
250 if (width < 0)
251 return;
252
253 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq1,
254 width, dfs_state);
255
256 if (!chandef->center_freq2)
257 return;
258 cfg80211_set_chans_dfs_state(wiphy, chandef->center_freq2,
259 width, dfs_state);
260}
261
262static int cfg80211_get_chans_dfs_required(struct wiphy *wiphy,
263 u32 center_freq,
264 u32 bandwidth)
265{
266 struct ieee80211_channel *c;
267 u32 freq;
268
269 for (freq = center_freq - bandwidth/2 + 10;
270 freq <= center_freq + bandwidth/2 - 10;
271 freq += 20) {
272 c = ieee80211_get_channel(wiphy, freq);
273 if (!c)
274 return -EINVAL;
275
276 if (c->flags & IEEE80211_CHAN_RADAR)
277 return 1;
278 }
279 return 0;
280}
281
282
283int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
284 const struct cfg80211_chan_def *chandef)
285{
286 int width;
287 int r;
288
289 if (WARN_ON(!cfg80211_chandef_valid(chandef)))
290 return -EINVAL;
291
292 width = cfg80211_chandef_get_width(chandef);
293 if (width < 0)
294 return -EINVAL;
295
296 r = cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq1,
297 width);
298 if (r)
299 return r;
300
301 if (!chandef->center_freq2)
302 return 0;
303
304 return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
305 width);
306}
307
195static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, 308static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
196 u32 center_freq, u32 bandwidth, 309 u32 center_freq, u32 bandwidth,
197 u32 prohibited_flags) 310 u32 prohibited_flags)
@@ -203,7 +316,16 @@ static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
203 freq <= center_freq + bandwidth/2 - 10; 316 freq <= center_freq + bandwidth/2 - 10;
204 freq += 20) { 317 freq += 20) {
205 c = ieee80211_get_channel(wiphy, freq); 318 c = ieee80211_get_channel(wiphy, freq);
206 if (!c || c->flags & prohibited_flags) 319 if (!c)
320 return false;
321
322 /* check for radar flags */
323 if ((prohibited_flags & c->flags & IEEE80211_CHAN_RADAR) &&
324 (c->dfs_state != NL80211_DFS_AVAILABLE))
325 return false;
326
327 /* check for the other flags */
328 if (c->flags & prohibited_flags & ~IEEE80211_CHAN_RADAR)
207 return false; 329 return false;
208 } 330 }
209 331
@@ -344,7 +466,10 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
344 break; 466 break;
345 case NL80211_IFTYPE_AP: 467 case NL80211_IFTYPE_AP:
346 case NL80211_IFTYPE_P2P_GO: 468 case NL80211_IFTYPE_P2P_GO:
347 if (wdev->beacon_interval) { 469 if (wdev->cac_started) {
470 *chan = wdev->channel;
471 *chanmode = CHAN_MODE_SHARED;
472 } else if (wdev->beacon_interval) {
348 *chan = wdev->channel; 473 *chan = wdev->channel;
349 *chanmode = CHAN_MODE_SHARED; 474 *chanmode = CHAN_MODE_SHARED;
350 } 475 }
diff --git a/net/wireless/core.c b/net/wireless/core.c
index f0a1bbe95cff..922002105062 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -324,6 +324,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
324 INIT_LIST_HEAD(&rdev->bss_list); 324 INIT_LIST_HEAD(&rdev->bss_list);
325 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); 325 INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
326 INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); 326 INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
327 INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk,
328 cfg80211_dfs_channels_update_work);
327#ifdef CONFIG_CFG80211_WEXT 329#ifdef CONFIG_CFG80211_WEXT
328 rdev->wiphy.wext = &cfg80211_wext_handler; 330 rdev->wiphy.wext = &cfg80211_wext_handler;
329#endif 331#endif
@@ -695,6 +697,7 @@ void wiphy_unregister(struct wiphy *wiphy)
695 flush_work(&rdev->scan_done_wk); 697 flush_work(&rdev->scan_done_wk);
696 cancel_work_sync(&rdev->conn_work); 698 cancel_work_sync(&rdev->conn_work);
697 flush_work(&rdev->event_work); 699 flush_work(&rdev->event_work);
700 cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
698 701
699 if (rdev->wowlan && rdev->ops->set_wakeup) 702 if (rdev->wowlan && rdev->ops->set_wakeup)
700 rdev_set_wakeup(rdev, false); 703 rdev_set_wakeup(rdev, false);
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 949c9573d8d7..3aec0e429d8a 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -86,6 +86,8 @@ struct cfg80211_registered_device {
86 86
87 struct cfg80211_wowlan *wowlan; 87 struct cfg80211_wowlan *wowlan;
88 88
89 struct delayed_work dfs_update_channels_wk;
90
89 /* must be last because of the way we do wiphy_priv(), 91 /* must be last because of the way we do wiphy_priv(),
90 * and it should at least be aligned to NETDEV_ALIGN */ 92 * and it should at least be aligned to NETDEV_ALIGN */
91 struct wiphy wiphy __aligned(NETDEV_ALIGN); 93 struct wiphy wiphy __aligned(NETDEV_ALIGN);
@@ -431,6 +433,22 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
431 enum cfg80211_chan_mode chanmode, 433 enum cfg80211_chan_mode chanmode,
432 u8 radar_detect); 434 u8 radar_detect);
433 435
436/**
437 * cfg80211_chandef_dfs_required - checks if radar detection is required
438 * @wiphy: the wiphy to validate against
439 * @chandef: the channel definition to check
440 * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
441 */
442int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
443 const struct cfg80211_chan_def *c);
444
445void cfg80211_set_dfs_state(struct wiphy *wiphy,
446 const struct cfg80211_chan_def *chandef,
447 enum nl80211_dfs_state dfs_state);
448
449void cfg80211_dfs_channels_update_work(struct work_struct *work);
450
451
434static inline int 452static inline int
435cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, 453cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
436 struct wireless_dev *wdev, 454 struct wireless_dev *wdev,
@@ -457,6 +475,16 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
457 chan, chanmode, 0); 475 chan, chanmode, 0);
458} 476}
459 477
478static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
479{
480 unsigned long end = jiffies;
481
482 if (end >= start)
483 return jiffies_to_msecs(end - start);
484
485 return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
486}
487
460void 488void
461cfg80211_get_chan_state(struct wireless_dev *wdev, 489cfg80211_get_chan_state(struct wireless_dev *wdev,
462 struct ieee80211_channel **chan, 490 struct ieee80211_channel **chan,
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 8e6920728c43..caddca35d686 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -987,3 +987,123 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
987 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp); 987 nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
988} 988}
989EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify); 989EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
990
991void cfg80211_dfs_channels_update_work(struct work_struct *work)
992{
993 struct delayed_work *delayed_work;
994 struct cfg80211_registered_device *rdev;
995 struct cfg80211_chan_def chandef;
996 struct ieee80211_supported_band *sband;
997 struct ieee80211_channel *c;
998 struct wiphy *wiphy;
999 bool check_again = false;
1000 unsigned long timeout, next_time = 0;
1001 int bandid, i;
1002
1003 delayed_work = container_of(work, struct delayed_work, work);
1004 rdev = container_of(delayed_work, struct cfg80211_registered_device,
1005 dfs_update_channels_wk);
1006 wiphy = &rdev->wiphy;
1007
1008 mutex_lock(&cfg80211_mutex);
1009 for (bandid = 0; bandid < IEEE80211_NUM_BANDS; bandid++) {
1010 sband = wiphy->bands[bandid];
1011 if (!sband)
1012 continue;
1013
1014 for (i = 0; i < sband->n_channels; i++) {
1015 c = &sband->channels[i];
1016
1017 if (c->dfs_state != NL80211_DFS_UNAVAILABLE)
1018 continue;
1019
1020 timeout = c->dfs_state_entered +
1021 IEEE80211_DFS_MIN_NOP_TIME_MS;
1022
1023 if (time_after_eq(jiffies, timeout)) {
1024 c->dfs_state = NL80211_DFS_USABLE;
1025 cfg80211_chandef_create(&chandef, c,
1026 NL80211_CHAN_NO_HT);
1027
1028 nl80211_radar_notify(rdev, &chandef,
1029 NL80211_RADAR_NOP_FINISHED,
1030 NULL, GFP_ATOMIC);
1031 continue;
1032 }
1033
1034 if (!check_again)
1035 next_time = timeout - jiffies;
1036 else
1037 next_time = min(next_time, timeout - jiffies);
1038 check_again = true;
1039 }
1040 }
1041 mutex_unlock(&cfg80211_mutex);
1042
1043 /* reschedule if there are other channels waiting to be cleared again */
1044 if (check_again)
1045 queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
1046 next_time);
1047}
1048
1049
1050void cfg80211_radar_event(struct wiphy *wiphy,
1051 struct cfg80211_chan_def *chandef,
1052 gfp_t gfp)
1053{
1054 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
1055 unsigned long timeout;
1056
1057 trace_cfg80211_radar_event(wiphy, chandef);
1058
1059 /* only set the chandef supplied channel to unavailable, in
1060 * case the radar is detected on only one of multiple channels
1061 * spanned by the chandef.
1062 */
1063 cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
1064
1065 timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_NOP_TIME_MS);
1066 queue_delayed_work(cfg80211_wq, &rdev->dfs_update_channels_wk,
1067 timeout);
1068
1069 nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
1070}
1071EXPORT_SYMBOL(cfg80211_radar_event);
1072
1073void cfg80211_cac_event(struct net_device *netdev,
1074 enum nl80211_radar_event event, gfp_t gfp)
1075{
1076 struct wireless_dev *wdev = netdev->ieee80211_ptr;
1077 struct wiphy *wiphy = wdev->wiphy;
1078 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
1079 struct cfg80211_chan_def chandef;
1080 unsigned long timeout;
1081
1082 trace_cfg80211_cac_event(netdev, event);
1083
1084 if (WARN_ON(!wdev->cac_started))
1085 return;
1086
1087 if (WARN_ON(!wdev->channel))
1088 return;
1089
1090 cfg80211_chandef_create(&chandef, wdev->channel, NL80211_CHAN_NO_HT);
1091
1092 switch (event) {
1093 case NL80211_RADAR_CAC_FINISHED:
1094 timeout = wdev->cac_start_time +
1095 msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
1096 WARN_ON(!time_after_eq(jiffies, timeout));
1097 cfg80211_set_dfs_state(wiphy, &chandef, NL80211_DFS_AVAILABLE);
1098 break;
1099 case NL80211_RADAR_CAC_ABORTED:
1100 break;
1101 default:
1102 WARN_ON(1);
1103 return;
1104 }
1105 wdev->cac_started = false;
1106
1107 nl80211_radar_notify(rdev, &chandef, event, netdev, gfp);
1108}
1109EXPORT_SYMBOL(cfg80211_cac_event);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index d29a461b4981..c1e18ccf4049 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -552,9 +552,16 @@ static int nl80211_msg_put_channel(struct sk_buff *msg,
552 if ((chan->flags & IEEE80211_CHAN_NO_IBSS) && 552 if ((chan->flags & IEEE80211_CHAN_NO_IBSS) &&
553 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS)) 553 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_IBSS))
554 goto nla_put_failure; 554 goto nla_put_failure;
555 if ((chan->flags & IEEE80211_CHAN_RADAR) && 555 if (chan->flags & IEEE80211_CHAN_RADAR) {
556 nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) 556 u32 time = elapsed_jiffies_msecs(chan->dfs_state_entered);
557 goto nla_put_failure; 557 if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR))
558 goto nla_put_failure;
559 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_STATE,
560 chan->dfs_state))
561 goto nla_put_failure;
562 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_DFS_TIME, time))
563 goto nla_put_failure;
564 }
558 565
559 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, 566 if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
560 DBM_TO_MBM(chan->max_power))) 567 DBM_TO_MBM(chan->max_power)))
@@ -2775,6 +2782,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2775 struct wireless_dev *wdev = dev->ieee80211_ptr; 2782 struct wireless_dev *wdev = dev->ieee80211_ptr;
2776 struct cfg80211_ap_settings params; 2783 struct cfg80211_ap_settings params;
2777 int err; 2784 int err;
2785 u8 radar_detect_width = 0;
2778 2786
2779 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && 2787 if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
2780 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) 2788 dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
@@ -2893,9 +2901,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
2893 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef)) 2901 if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
2894 return -EINVAL; 2902 return -EINVAL;
2895 2903
2904 err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
2905 if (err < 0)
2906 return err;
2907 if (err) {
2908 radar_detect_width = BIT(params.chandef.width);
2909 params.radar_required = true;
2910 }
2911
2896 mutex_lock(&rdev->devlist_mtx); 2912 mutex_lock(&rdev->devlist_mtx);
2897 err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan, 2913 err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
2898 CHAN_MODE_SHARED); 2914 params.chandef.chan,
2915 CHAN_MODE_SHARED,
2916 radar_detect_width);
2899 mutex_unlock(&rdev->devlist_mtx); 2917 mutex_unlock(&rdev->devlist_mtx);
2900 2918
2901 if (err) 2919 if (err)
@@ -5055,6 +5073,54 @@ static int nl80211_stop_sched_scan(struct sk_buff *skb,
5055 return err; 5073 return err;
5056} 5074}
5057 5075
5076static int nl80211_start_radar_detection(struct sk_buff *skb,
5077 struct genl_info *info)
5078{
5079 struct cfg80211_registered_device *rdev = info->user_ptr[0];
5080 struct net_device *dev = info->user_ptr[1];
5081 struct wireless_dev *wdev = dev->ieee80211_ptr;
5082 struct cfg80211_chan_def chandef;
5083 int err;
5084
5085 err = nl80211_parse_chandef(rdev, info, &chandef);
5086 if (err)
5087 return err;
5088
5089 if (wdev->cac_started)
5090 return -EBUSY;
5091
5092 err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef);
5093 if (err < 0)
5094 return err;
5095
5096 if (err == 0)
5097 return -EINVAL;
5098
5099 if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
5100 return -EINVAL;
5101
5102 if (!rdev->ops->start_radar_detection)
5103 return -EOPNOTSUPP;
5104
5105 mutex_lock(&rdev->devlist_mtx);
5106 err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
5107 chandef.chan, CHAN_MODE_SHARED,
5108 BIT(chandef.width));
5109 if (err)
5110 goto err_locked;
5111
5112 err = rdev->ops->start_radar_detection(&rdev->wiphy, dev, &chandef);
5113 if (!err) {
5114 wdev->channel = chandef.chan;
5115 wdev->cac_started = true;
5116 wdev->cac_start_time = jiffies;
5117 }
5118err_locked:
5119 mutex_unlock(&rdev->devlist_mtx);
5120
5121 return err;
5122}
5123
5058static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb, 5124static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
5059 u32 seq, int flags, 5125 u32 seq, int flags,
5060 struct cfg80211_registered_device *rdev, 5126 struct cfg80211_registered_device *rdev,
@@ -8305,6 +8371,14 @@ static struct genl_ops nl80211_ops[] = {
8305 .internal_flags = NL80211_FLAG_NEED_NETDEV | 8371 .internal_flags = NL80211_FLAG_NEED_NETDEV |
8306 NL80211_FLAG_NEED_RTNL, 8372 NL80211_FLAG_NEED_RTNL,
8307 }, 8373 },
8374 {
8375 .cmd = NL80211_CMD_RADAR_DETECT,
8376 .doit = nl80211_start_radar_detection,
8377 .policy = nl80211_policy,
8378 .flags = GENL_ADMIN_PERM,
8379 .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
8380 NL80211_FLAG_NEED_RTNL,
8381 },
8308}; 8382};
8309 8383
8310static struct genl_multicast_group nl80211_mlme_mcgrp = { 8384static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -9502,6 +9576,57 @@ nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev,
9502} 9576}
9503 9577
9504void 9578void
9579nl80211_radar_notify(struct cfg80211_registered_device *rdev,
9580 struct cfg80211_chan_def *chandef,
9581 enum nl80211_radar_event event,
9582 struct net_device *netdev, gfp_t gfp)
9583{
9584 struct sk_buff *msg;
9585 void *hdr;
9586
9587 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
9588 if (!msg)
9589 return;
9590
9591 hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_RADAR_DETECT);
9592 if (!hdr) {
9593 nlmsg_free(msg);
9594 return;
9595 }
9596
9597 if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
9598 goto nla_put_failure;
9599
9600 /* NOP and radar events don't need a netdev parameter */
9601 if (netdev) {
9602 struct wireless_dev *wdev = netdev->ieee80211_ptr;
9603
9604 if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
9605 nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
9606 goto nla_put_failure;
9607 }
9608
9609 if (nla_put_u32(msg, NL80211_ATTR_RADAR_EVENT, event))
9610 goto nla_put_failure;
9611
9612 if (nl80211_send_chandef(msg, chandef))
9613 goto nla_put_failure;
9614
9615 if (genlmsg_end(msg, hdr) < 0) {
9616 nlmsg_free(msg);
9617 return;
9618 }
9619
9620 genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
9621 nl80211_mlme_mcgrp.id, gfp);
9622 return;
9623
9624 nla_put_failure:
9625 genlmsg_cancel(msg, hdr);
9626 nlmsg_free(msg);
9627}
9628
9629void
9505nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, 9630nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
9506 struct net_device *netdev, const u8 *peer, 9631 struct net_device *netdev, const u8 *peer,
9507 u32 num_packets, gfp_t gfp) 9632 u32 num_packets, gfp_t gfp)
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index 2acba8477e9d..b061da4919e1 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -108,6 +108,13 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
108 struct net_device *netdev, 108 struct net_device *netdev,
109 enum nl80211_cqm_rssi_threshold_event rssi_event, 109 enum nl80211_cqm_rssi_threshold_event rssi_event,
110 gfp_t gfp); 110 gfp_t gfp);
111
112void
113nl80211_radar_notify(struct cfg80211_registered_device *rdev,
114 struct cfg80211_chan_def *chandef,
115 enum nl80211_radar_event event,
116 struct net_device *netdev, gfp_t gfp);
117
111void 118void
112nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, 119nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
113 struct net_device *netdev, const u8 *peer, 120 struct net_device *netdev, const u8 *peer,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 08d3da2c70ab..e97d5b071ab6 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -884,6 +884,9 @@ static void handle_channel(struct wiphy *wiphy,
884 return; 884 return;
885 } 885 }
886 886
887 chan->dfs_state = NL80211_DFS_USABLE;
888 chan->dfs_state_entered = jiffies;
889
887 chan->beacon_found = false; 890 chan->beacon_found = false;
888 chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags); 891 chan->flags = flags | bw_flags | map_regdom_flags(reg_rule->flags);
889 chan->max_antenna_gain = 892 chan->max_antenna_gain =
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index d0fc6da2d097..f0d9b5154bab 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1210,16 +1210,6 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
1210 } 1210 }
1211} 1211}
1212 1212
1213static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
1214{
1215 unsigned long end = jiffies;
1216
1217 if (end >= start)
1218 return jiffies_to_msecs(end - start);
1219
1220 return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
1221}
1222
1223static char * 1213static char *
1224ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, 1214ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
1225 struct cfg80211_internal_bss *bss, char *current_ev, 1215 struct cfg80211_internal_bss *bss, char *current_ev,
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index c9cafb0ea95f..b7a531380e19 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -2051,6 +2051,21 @@ TRACE_EVENT(cfg80211_reg_can_beacon,
2051 WIPHY_PR_ARG, CHAN_DEF_PR_ARG) 2051 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
2052); 2052);
2053 2053
2054TRACE_EVENT(cfg80211_chandef_dfs_required,
2055 TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
2056 TP_ARGS(wiphy, chandef),
2057 TP_STRUCT__entry(
2058 WIPHY_ENTRY
2059 CHAN_DEF_ENTRY
2060 ),
2061 TP_fast_assign(
2062 WIPHY_ASSIGN;
2063 CHAN_DEF_ASSIGN(chandef);
2064 ),
2065 TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
2066 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
2067);
2068
2054TRACE_EVENT(cfg80211_ch_switch_notify, 2069TRACE_EVENT(cfg80211_ch_switch_notify,
2055 TP_PROTO(struct net_device *netdev, 2070 TP_PROTO(struct net_device *netdev,
2056 struct cfg80211_chan_def *chandef), 2071 struct cfg80211_chan_def *chandef),
@@ -2067,6 +2082,36 @@ TRACE_EVENT(cfg80211_ch_switch_notify,
2067 NETDEV_PR_ARG, CHAN_DEF_PR_ARG) 2082 NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
2068); 2083);
2069 2084
2085TRACE_EVENT(cfg80211_radar_event,
2086 TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
2087 TP_ARGS(wiphy, chandef),
2088 TP_STRUCT__entry(
2089 WIPHY_ENTRY
2090 CHAN_DEF_ENTRY
2091 ),
2092 TP_fast_assign(
2093 WIPHY_ASSIGN;
2094 CHAN_DEF_ASSIGN(chandef);
2095 ),
2096 TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
2097 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
2098);
2099
2100TRACE_EVENT(cfg80211_cac_event,
2101 TP_PROTO(struct net_device *netdev, enum nl80211_radar_event evt),
2102 TP_ARGS(netdev, evt),
2103 TP_STRUCT__entry(
2104 NETDEV_ENTRY
2105 __field(enum nl80211_radar_event, evt)
2106 ),
2107 TP_fast_assign(
2108 NETDEV_ASSIGN;
2109 __entry->evt = evt;
2110 ),
2111 TP_printk(NETDEV_PR_FMT ", event: %d",
2112 NETDEV_PR_ARG, __entry->evt)
2113);
2114
2070DECLARE_EVENT_CLASS(cfg80211_rx_evt, 2115DECLARE_EVENT_CLASS(cfg80211_rx_evt,
2071 TP_PROTO(struct net_device *netdev, const u8 *addr), 2116 TP_PROTO(struct net_device *netdev, const u8 *addr),
2072 TP_ARGS(netdev, addr), 2117 TP_ARGS(netdev, addr),