From 5841958f26277407782807249c0dfb150743bc04 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Fri, 27 Jun 2014 14:19:30 +0200 Subject: [PATCH] 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 --- src/ap/drv_callbacks.c | 17 +++++++++++++ src/ap/hostapd.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++---- src/ap/hostapd.h | 3 +++ src/drivers/driver.h | 3 ++- 4 files changed, 83 insertions(+), 6 deletions(-) diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index ac5732c..93804de 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -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; diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 4c648b1..55b7ced 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -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 */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index d413f7e..3c8727b 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -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 */ diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 33f53af..352c163 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -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, -- 2.1.4