DFS: Allow skipping radar channels

This is needed for AP CSA. Since CSA must happen immediately after radar
is detected there's no time to perform CAC. Thus, radar channels must be
disabled when looking for a new channel to escape to after a radar is
detected.

Signed-hostap: Michal Kazior <michal.kazior@tieto.com>
This commit is contained in:
Michal Kazior 2013-11-25 20:16:13 +01:00 committed by Jouni Malinen
parent 8d1fdde7f0
commit b72f949b07

View file

@ -44,8 +44,17 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface)
} }
static int dfs_channel_available(struct hostapd_channel_data *chan) static int dfs_channel_available(struct hostapd_channel_data *chan,
int skip_radar)
{ {
/*
* When radar detection happens, CSA is performed. However, there's no
* time for CAC, so radar channels must be skipped when finding a new
* channel for CSA.
*/
if (skip_radar && chan->flag & HOSTAPD_CHAN_RADAR)
return 0;
if (chan->flag & HOSTAPD_CHAN_DISABLED) if (chan->flag & HOSTAPD_CHAN_DISABLED)
return 0; return 0;
if ((chan->flag & HOSTAPD_CHAN_RADAR) && if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
@ -96,7 +105,8 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
static int dfs_chan_range_available(struct hostapd_hw_modes *mode, static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans) int first_chan_idx, int num_chans,
int skip_radar)
{ {
struct hostapd_channel_data *first_chan, *chan; struct hostapd_channel_data *first_chan, *chan;
int i; int i;
@ -112,7 +122,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
if (first_chan->freq + i * 20 != chan->freq) if (first_chan->freq + i * 20 != chan->freq)
return 0; return 0;
if (!dfs_channel_available(chan)) if (!dfs_channel_available(chan, skip_radar))
return 0; return 0;
} }
@ -129,7 +139,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
*/ */
static int dfs_find_channel(struct hostapd_iface *iface, static int dfs_find_channel(struct hostapd_iface *iface,
struct hostapd_channel_data **ret_chan, struct hostapd_channel_data **ret_chan,
int idx) int idx, int skip_radar)
{ {
struct hostapd_hw_modes *mode; struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan; struct hostapd_channel_data *chan;
@ -149,7 +159,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
continue; continue;
/* Skip incompatible chandefs */ /* Skip incompatible chandefs */
if (!dfs_chan_range_available(mode, i, n_chans)) if (!dfs_chan_range_available(mode, i, n_chans, skip_radar))
continue; continue;
if (ret_chan && idx == channel_idx) { if (ret_chan && idx == channel_idx) {
@ -322,7 +332,8 @@ static struct hostapd_channel_data *
dfs_get_valid_channel(struct hostapd_iface *iface, dfs_get_valid_channel(struct hostapd_iface *iface,
int *secondary_channel, int *secondary_channel,
u8 *vht_oper_centr_freq_seg0_idx, u8 *vht_oper_centr_freq_seg0_idx,
u8 *vht_oper_centr_freq_seg1_idx) u8 *vht_oper_centr_freq_seg1_idx,
int skip_radar)
{ {
struct hostapd_hw_modes *mode; struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL; struct hostapd_channel_data *chan = NULL;
@ -340,13 +351,13 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
return NULL; return NULL;
/* Get the count first */ /* Get the count first */
num_available_chandefs = dfs_find_channel(iface, NULL, 0); num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
if (num_available_chandefs == 0) if (num_available_chandefs == 0)
return NULL; return NULL;
os_get_random((u8 *) &_rand, sizeof(_rand)); os_get_random((u8 *) &_rand, sizeof(_rand));
chan_idx = _rand % num_available_chandefs; chan_idx = _rand % num_available_chandefs;
dfs_find_channel(iface, &chan, chan_idx); dfs_find_channel(iface, &chan, chan_idx, skip_radar);
/* dfs_find_channel() calculations assume HT40+ */ /* dfs_find_channel() calculations assume HT40+ */
if (iface->conf->secondary_channel) if (iface->conf->secondary_channel)
@ -518,6 +529,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
{ {
struct hostapd_channel_data *channel; struct hostapd_channel_data *channel;
int res, n_chans, start_chan_idx; int res, n_chans, start_chan_idx;
int skip_radar = 0;
iface->cac_started = 0; iface->cac_started = 0;
@ -555,7 +567,8 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
int sec; int sec;
u8 cf1, cf2; u8 cf1, cf2;
channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2); channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
skip_radar);
if (!channel) { if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel"); wpa_printf(MSG_ERROR, "could not get valid channel");
return -1; return -1;
@ -621,11 +634,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
int secondary_channel; int secondary_channel;
u8 vht_oper_centr_freq_seg0_idx; u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx; u8 vht_oper_centr_freq_seg1_idx;
int skip_radar = 1;
wpa_printf(MSG_DEBUG, "%s called", __func__); wpa_printf(MSG_DEBUG, "%s called", __func__);
channel = dfs_get_valid_channel(iface, &secondary_channel, channel = dfs_get_valid_channel(iface, &secondary_channel,
&vht_oper_centr_freq_seg0_idx, &vht_oper_centr_freq_seg0_idx,
&vht_oper_centr_freq_seg1_idx); &vht_oper_centr_freq_seg1_idx,
skip_radar);
if (channel) { if (channel) {
wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
channel->chan); channel->chan);