DFS: Fix HT40/VHT calculation

Decouple HT/VHT offset/center-freq calculations from channel lookup.
This will be necessary for further improvements on the DFS codebase.

Signed-hostap: Michal Kazior <michal.kazior@tieto.com>
This commit is contained in:
Michal Kazior 2013-10-31 14:46:09 +02:00 committed by Jouni Malinen
parent a1ddc79adf
commit 32595da608

View File

@ -94,6 +94,13 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
} }
/*
* The function assumes HT40+ operation.
* Make sure to adjust the following variables after calling this:
* - hapd->secondary_channel
* - hapd->vht_oper_centr_freq_seg0_idx
* - hapd->vht_oper_centr_freq_seg1_idx
*/
static int dfs_find_channel(struct hostapd_data *hapd, static int dfs_find_channel(struct hostapd_data *hapd,
struct hostapd_channel_data **ret_chan, struct hostapd_channel_data **ret_chan,
int idx) int idx)
@ -126,9 +133,6 @@ static int dfs_find_channel(struct hostapd_data *hapd,
} }
if (j != n_chans) if (j != n_chans)
continue; continue;
/* Set HT40+ */
hapd->iconf->secondary_channel = 1;
} }
if (ret_chan && idx == channel_idx) { if (ret_chan && idx == channel_idx) {
@ -144,7 +148,9 @@ static int dfs_find_channel(struct hostapd_data *hapd,
static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd, static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd,
struct hostapd_channel_data *chan) struct hostapd_channel_data *chan,
u8 *vht_oper_centr_freq_seg0_idx,
u8 *vht_oper_centr_freq_seg1_idx)
{ {
if (!hapd->iconf->ieee80211ac) if (!hapd->iconf->ieee80211ac)
return; return;
@ -152,31 +158,31 @@ static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd,
if (!chan) if (!chan)
return; return;
*vht_oper_centr_freq_seg1_idx = 0;
switch (hapd->iconf->vht_oper_chwidth) { switch (hapd->iconf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT: case VHT_CHANWIDTH_USE_HT:
if (hapd->iconf->secondary_channel == 1) if (hapd->iconf->secondary_channel == 1)
hapd->iconf->vht_oper_centr_freq_seg0_idx = *vht_oper_centr_freq_seg0_idx = chan->chan + 2;
chan->chan + 2;
else if (hapd->iconf->secondary_channel == -1) else if (hapd->iconf->secondary_channel == -1)
hapd->iconf->vht_oper_centr_freq_seg0_idx = *vht_oper_centr_freq_seg0_idx = chan->chan - 2;
chan->chan - 2;
else else
hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan; *vht_oper_centr_freq_seg0_idx = chan->chan;
break; break;
case VHT_CHANWIDTH_80MHZ: case VHT_CHANWIDTH_80MHZ:
hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 6; *vht_oper_centr_freq_seg0_idx = chan->chan + 6;
break; break;
case VHT_CHANWIDTH_160MHZ: case VHT_CHANWIDTH_160MHZ:
hapd->iconf->vht_oper_centr_freq_seg0_idx = *vht_oper_centr_freq_seg0_idx = chan->chan + 14;
chan->chan + 14;
break; break;
default: default:
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
break; break;
} }
wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d", wpa_printf(MSG_DEBUG, "DFS adjusting VHT center frequency: %d, %d",
hapd->iconf->vht_oper_centr_freq_seg0_idx); *vht_oper_centr_freq_seg0_idx,
*vht_oper_centr_freq_seg1_idx);
} }
@ -295,12 +301,16 @@ static int dfs_check_chans_unavailable(struct hostapd_data *hapd,
} }
static struct hostapd_channel_data * dfs_get_valid_channel( static struct hostapd_channel_data *
struct hostapd_data *hapd) dfs_get_valid_channel(struct hostapd_data *hapd,
int *secondary_channel,
u8 *vht_oper_centr_freq_seg0_idx,
u8 *vht_oper_centr_freq_seg1_idx)
{ {
struct hostapd_hw_modes *mode; struct hostapd_hw_modes *mode;
struct hostapd_channel_data *chan = NULL; struct hostapd_channel_data *chan = NULL;
int channel_idx, new_channel_idx; int num_available_chandefs;
int chan_idx;
u32 _rand; u32 _rand;
wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); wpa_printf(MSG_DEBUG, "DFS: Selecting random channel");
@ -312,16 +322,24 @@ static struct hostapd_channel_data * dfs_get_valid_channel(
if (mode->mode != HOSTAPD_MODE_IEEE80211A) if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return NULL; return NULL;
/* get random available channel */ /* Get the count first */
channel_idx = dfs_find_channel(hapd, NULL, 0); num_available_chandefs = dfs_find_channel(hapd, NULL, 0);
if (channel_idx > 0) { if (num_available_chandefs == 0)
os_get_random((u8 *) &_rand, sizeof(_rand)); return NULL;
new_channel_idx = _rand % channel_idx;
dfs_find_channel(hapd, &chan, new_channel_idx);
}
/* VHT */ os_get_random((u8 *) &_rand, sizeof(_rand));
dfs_adjust_vht_center_freq(hapd, chan); chan_idx = _rand % num_available_chandefs;
dfs_find_channel(hapd, &chan, chan_idx);
/* dfs_find_channel() calculations assume HT40+ */
if (hapd->iconf->secondary_channel)
*secondary_channel = 1;
else
*secondary_channel = 0;
dfs_adjust_vht_center_freq(hapd, chan,
vht_oper_centr_freq_seg0_idx,
vht_oper_centr_freq_seg1_idx);
return chan; return chan;
} }
@ -513,13 +531,20 @@ int hostapd_handle_dfs(struct hostapd_data *hapd)
wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s", wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
res, res ? "yes": "no"); res, res ? "yes": "no");
if (res) { if (res) {
channel = dfs_get_valid_channel(hapd); int sec;
u8 cf1, cf2;
channel = dfs_get_valid_channel(hapd, &sec, &cf1, &cf2);
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;
} }
hapd->iconf->channel = channel->chan;
hapd->iface->freq = channel->freq; hapd->iface->freq = channel->freq;
hapd->iconf->channel = channel->chan;
hapd->iconf->secondary_channel = sec;
hapd->iconf->vht_oper_centr_freq_seg0_idx = cf1;
hapd->iconf->vht_oper_centr_freq_seg1_idx = cf2;
} }
} while (res); } while (res);
@ -563,13 +588,24 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_data *hapd)
{ {
struct hostapd_channel_data *channel; struct hostapd_channel_data *channel;
int err = 1; int err = 1;
int secondary_channel;
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
wpa_printf(MSG_DEBUG, "%s called", __func__); wpa_printf(MSG_DEBUG, "%s called", __func__);
channel = dfs_get_valid_channel(hapd); channel = dfs_get_valid_channel(hapd, &secondary_channel,
&vht_oper_centr_freq_seg0_idx,
&vht_oper_centr_freq_seg1_idx);
if (channel) { if (channel) {
hapd->iconf->channel = channel->chan; hapd->iconf->channel = channel->chan;
hapd->iface->freq = channel->freq; hapd->iconf->secondary_channel = secondary_channel;
hapd->iconf->vht_oper_centr_freq_seg0_idx =
vht_oper_centr_freq_seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx =
vht_oper_centr_freq_seg1_idx;
err = 0; err = 0;
} else {
wpa_printf(MSG_ERROR, "No valid channel available");
} }
if (!hapd->cac_started) { if (!hapd->cac_started) {