diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/wireless/chan.c | 74 | ||||
-rw-r--r-- | net/wireless/core.h | 13 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 2 |
3 files changed, 88 insertions, 1 deletions
diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 1d25a462b145..96c97800e247 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c | |||
@@ -351,6 +351,80 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy, | |||
351 | } | 351 | } |
352 | EXPORT_SYMBOL(cfg80211_chandef_dfs_required); | 352 | EXPORT_SYMBOL(cfg80211_chandef_dfs_required); |
353 | 353 | ||
354 | static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy, | ||
355 | u32 center_freq, | ||
356 | u32 bandwidth) | ||
357 | { | ||
358 | struct ieee80211_channel *c; | ||
359 | u32 freq, start_freq, end_freq; | ||
360 | int count = 0; | ||
361 | |||
362 | start_freq = cfg80211_get_start_freq(center_freq, bandwidth); | ||
363 | end_freq = cfg80211_get_end_freq(center_freq, bandwidth); | ||
364 | |||
365 | /* | ||
366 | * Check entire range of channels for the bandwidth. | ||
367 | * Check all channels are DFS channels (DFS_USABLE or | ||
368 | * DFS_AVAILABLE). Return number of usable channels | ||
369 | * (require CAC). Allow DFS and non-DFS channel mix. | ||
370 | */ | ||
371 | for (freq = start_freq; freq <= end_freq; freq += 20) { | ||
372 | c = ieee80211_get_channel(wiphy, freq); | ||
373 | if (!c) | ||
374 | return -EINVAL; | ||
375 | |||
376 | if (c->flags & IEEE80211_CHAN_DISABLED) | ||
377 | return -EINVAL; | ||
378 | |||
379 | if (c->flags & IEEE80211_CHAN_RADAR) { | ||
380 | if (c->dfs_state == NL80211_DFS_UNAVAILABLE) | ||
381 | return -EINVAL; | ||
382 | |||
383 | if (c->dfs_state == NL80211_DFS_USABLE) | ||
384 | count++; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | return count; | ||
389 | } | ||
390 | |||
391 | bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, | ||
392 | const struct cfg80211_chan_def *chandef) | ||
393 | { | ||
394 | int width; | ||
395 | int r1, r2 = 0; | ||
396 | |||
397 | if (WARN_ON(!cfg80211_chandef_valid(chandef))) | ||
398 | return false; | ||
399 | |||
400 | width = cfg80211_chandef_get_width(chandef); | ||
401 | if (width < 0) | ||
402 | return false; | ||
403 | |||
404 | r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1, | ||
405 | width); | ||
406 | |||
407 | if (r1 < 0) | ||
408 | return false; | ||
409 | |||
410 | switch (chandef->width) { | ||
411 | case NL80211_CHAN_WIDTH_80P80: | ||
412 | WARN_ON(!chandef->center_freq2); | ||
413 | r2 = cfg80211_get_chans_dfs_usable(wiphy, | ||
414 | chandef->center_freq2, | ||
415 | width); | ||
416 | if (r2 < 0) | ||
417 | return false; | ||
418 | break; | ||
419 | default: | ||
420 | WARN_ON(chandef->center_freq2); | ||
421 | break; | ||
422 | } | ||
423 | |||
424 | return (r1 + r2 > 0); | ||
425 | } | ||
426 | |||
427 | |||
354 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, | 428 | static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy, |
355 | u32 center_freq, u32 bandwidth, | 429 | u32 center_freq, u32 bandwidth, |
356 | u32 prohibited_flags) | 430 | u32 prohibited_flags) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index eb0f7a3a25a9..2888867ee7c5 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -382,6 +382,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, | |||
382 | enum cfg80211_chan_mode chanmode, | 382 | enum cfg80211_chan_mode chanmode, |
383 | u8 radar_detect); | 383 | u8 radar_detect); |
384 | 384 | ||
385 | /** | ||
386 | * cfg80211_chandef_dfs_usable - checks if chandef is DFS usable | ||
387 | * @wiphy: the wiphy to validate against | ||
388 | * @chandef: the channel definition to check | ||
389 | * | ||
390 | * Checks if chandef is usable and we can/need start CAC on such channel. | ||
391 | * | ||
392 | * Return: Return true if all channels available and at least | ||
393 | * one channel require CAC (NL80211_DFS_USABLE) | ||
394 | */ | ||
395 | bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy, | ||
396 | const struct cfg80211_chan_def *chandef); | ||
397 | |||
385 | void cfg80211_set_dfs_state(struct wiphy *wiphy, | 398 | void cfg80211_set_dfs_state(struct wiphy *wiphy, |
386 | const struct cfg80211_chan_def *chandef, | 399 | const struct cfg80211_chan_def *chandef, |
387 | enum nl80211_dfs_state dfs_state); | 400 | enum nl80211_dfs_state dfs_state); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 41af3a0e9961..e2bb4276af1a 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -5651,7 +5651,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb, | |||
5651 | if (err == 0) | 5651 | if (err == 0) |
5652 | return -EINVAL; | 5652 | return -EINVAL; |
5653 | 5653 | ||
5654 | if (chandef.chan->dfs_state != NL80211_DFS_USABLE) | 5654 | if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) |
5655 | return -EINVAL; | 5655 | return -EINVAL; |
5656 | 5656 | ||
5657 | if (!rdev->ops->start_radar_detection) | 5657 | if (!rdev->ops->start_radar_detection) |