cfg80211: DFS check chandef usable before CAC
Check chandef we get in CAC request is usable for CAC. All channels have to be DFS channels. Allow DFS_USABLE and DFS_AVAILABLE channels mix. At least one channel has to be DFS_USABLE (require CAC). Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com> Reviewed-by: Luis R. Rodriguez <mcgrof@do-not-panic.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
committed by
Johannes Berg
parent
40d1ba63ff
commit
fe7c3a1f20
@@ -351,6 +351,80 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
|
EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
|
||||||
|
|
||||||
|
static int cfg80211_get_chans_dfs_usable(struct wiphy *wiphy,
|
||||||
|
u32 center_freq,
|
||||||
|
u32 bandwidth)
|
||||||
|
{
|
||||||
|
struct ieee80211_channel *c;
|
||||||
|
u32 freq, start_freq, end_freq;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
start_freq = cfg80211_get_start_freq(center_freq, bandwidth);
|
||||||
|
end_freq = cfg80211_get_end_freq(center_freq, bandwidth);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check entire range of channels for the bandwidth.
|
||||||
|
* Check all channels are DFS channels (DFS_USABLE or
|
||||||
|
* DFS_AVAILABLE). Return number of usable channels
|
||||||
|
* (require CAC). Allow DFS and non-DFS channel mix.
|
||||||
|
*/
|
||||||
|
for (freq = start_freq; freq <= end_freq; freq += 20) {
|
||||||
|
c = ieee80211_get_channel(wiphy, freq);
|
||||||
|
if (!c)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (c->flags & IEEE80211_CHAN_DISABLED)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (c->flags & IEEE80211_CHAN_RADAR) {
|
||||||
|
if (c->dfs_state == NL80211_DFS_UNAVAILABLE)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (c->dfs_state == NL80211_DFS_USABLE)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
|
||||||
|
const struct cfg80211_chan_def *chandef)
|
||||||
|
{
|
||||||
|
int width;
|
||||||
|
int r1, r2 = 0;
|
||||||
|
|
||||||
|
if (WARN_ON(!cfg80211_chandef_valid(chandef)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
width = cfg80211_chandef_get_width(chandef);
|
||||||
|
if (width < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
r1 = cfg80211_get_chans_dfs_usable(wiphy, chandef->center_freq1,
|
||||||
|
width);
|
||||||
|
|
||||||
|
if (r1 < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (chandef->width) {
|
||||||
|
case NL80211_CHAN_WIDTH_80P80:
|
||||||
|
WARN_ON(!chandef->center_freq2);
|
||||||
|
r2 = cfg80211_get_chans_dfs_usable(wiphy,
|
||||||
|
chandef->center_freq2,
|
||||||
|
width);
|
||||||
|
if (r2 < 0)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
WARN_ON(chandef->center_freq2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (r1 + r2 > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
|
static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
|
||||||
u32 center_freq, u32 bandwidth,
|
u32 center_freq, u32 bandwidth,
|
||||||
u32 prohibited_flags)
|
u32 prohibited_flags)
|
||||||
|
@@ -382,6 +382,19 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
|||||||
enum cfg80211_chan_mode chanmode,
|
enum cfg80211_chan_mode chanmode,
|
||||||
u8 radar_detect);
|
u8 radar_detect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* cfg80211_chandef_dfs_usable - checks if chandef is DFS usable
|
||||||
|
* @wiphy: the wiphy to validate against
|
||||||
|
* @chandef: the channel definition to check
|
||||||
|
*
|
||||||
|
* Checks if chandef is usable and we can/need start CAC on such channel.
|
||||||
|
*
|
||||||
|
* Return: Return true if all channels available and at least
|
||||||
|
* one channel require CAC (NL80211_DFS_USABLE)
|
||||||
|
*/
|
||||||
|
bool cfg80211_chandef_dfs_usable(struct wiphy *wiphy,
|
||||||
|
const struct cfg80211_chan_def *chandef);
|
||||||
|
|
||||||
void cfg80211_set_dfs_state(struct wiphy *wiphy,
|
void cfg80211_set_dfs_state(struct wiphy *wiphy,
|
||||||
const struct cfg80211_chan_def *chandef,
|
const struct cfg80211_chan_def *chandef,
|
||||||
enum nl80211_dfs_state dfs_state);
|
enum nl80211_dfs_state dfs_state);
|
||||||
|
@@ -5651,7 +5651,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
|
|||||||
if (err == 0)
|
if (err == 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (chandef.chan->dfs_state != NL80211_DFS_USABLE)
|
if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!rdev->ops->start_radar_detection)
|
if (!rdev->ops->start_radar_detection)
|
||||||
|
Reference in New Issue
Block a user