hostapd: Use channel switch fallback on error

It's worth giving a try to fallback to re-starting BSSes at least once
hoping it works out instead of just leaving BSSes disabled.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
This commit is contained in:
Michal Kazior 2014-06-27 14:19:30 +02:00 committed by Jouni Malinen
parent 8974620e3e
commit 5841958f26
4 changed files with 83 additions and 6 deletions

View file

@ -885,6 +885,20 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd,
#ifdef NEED_AP_MLME
static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped",
hapd->conf->iface);
if (hapd->csa_in_progress) {
wpa_printf(MSG_INFO, "CSA failed (%s was stopped)",
hapd->conf->iface);
hostapd_switch_channel_fallback(hapd->iface,
&hapd->cs_freq_params);
}
}
static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
struct dfs_event *radar)
{
@ -1072,6 +1086,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
hostapd_event_get_survey(hapd, &data->survey_results);
break;
#ifdef NEED_AP_MLME
case EVENT_INTERFACE_UNAVAILABLE:
hostapd_event_iface_unavailable(hapd);
break;
case EVENT_DFS_RADAR_DETECTED:
if (!data)
break;

View file

@ -2280,13 +2280,13 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
if (!params->channel) {
/* check if the new channel is supported by hw */
channel = hostapd_hw_get_channel(hapd, params->freq);
if (!channel)
return -1;
} else {
channel = params->channel;
params->channel = hostapd_hw_get_channel(hapd, params->freq);
}
channel = params->channel;
if (!channel)
return -1;
/* if a pointer to old_params is provided we save previous state */
if (old_params) {
old_params->channel = conf->channel;
@ -2381,4 +2381,60 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
return 0;
}
void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params)
{
int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT;
unsigned int i;
wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes");
if (freq_params->center_freq1)
vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5;
if (freq_params->center_freq2)
vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5;
switch (freq_params->bandwidth) {
case 0:
case 20:
case 40:
vht_bw = VHT_CHANWIDTH_USE_HT;
break;
case 80:
if (freq_params->center_freq2)
vht_bw = VHT_CHANWIDTH_80P80MHZ;
else
vht_bw = VHT_CHANWIDTH_80MHZ;
break;
case 160:
vht_bw = VHT_CHANWIDTH_160MHZ;
break;
default:
wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d",
freq_params->bandwidth);
break;
}
iface->freq = freq_params->freq;
iface->conf->channel = freq_params->channel;
iface->conf->secondary_channel = freq_params->sec_channel_offset;
iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx;
iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx;
iface->conf->vht_oper_chwidth = vht_bw;
iface->conf->ieee80211n = freq_params->ht_enabled;
iface->conf->ieee80211ac = freq_params->vht_enabled;
/*
* cs_params must not be cleared earlier because the freq_params
* argument may actually point to one of these.
*/
for (i = 0; i < iface->num_bss; i++)
hostapd_cleanup_cs_params(iface->bss[i]);
hostapd_disable_iface(iface);
hostapd_enable_iface(iface);
}
#endif /* NEED_AP_MLME */

View file

@ -397,6 +397,9 @@ void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s);
const char * hostapd_state_text(enum hostapd_iface_state s);
int hostapd_switch_channel(struct hostapd_data *hapd,
struct csa_settings *settings);
void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
/* utils.c */

View file

@ -3316,7 +3316,8 @@ enum wpa_event_type {
* the driver does not support radar detection and another virtual
* interfaces caused the operating channel to change. Other similar
* resource conflicts could also trigger this for station mode
* interfaces.
* interfaces. This event can be propagated when channel switching
* fails.
*/
EVENT_INTERFACE_UNAVAILABLE,