[PATCH 4/4] hostapd: Use channel switch fallback on error

Michal Kazior michal.kazior
Wed Jun 25 04:20:26 PDT 2014


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 at tieto.com>
---
 src/ap/drv_callbacks.c | 11 +++++++++++
 src/ap/hostapd.c       | 51 +++++++++++++++++++++++++++++++++++++++++++++-----
 src/ap/hostapd.h       |  8 ++++++++
 src/drivers/driver.h   |  3 ++-
 4 files changed, 67 insertions(+), 6 deletions(-)

diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index ac5732c..561cbf9 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -885,6 +885,14 @@ 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 is unavailable -- stopped");
+	hostapd_switch_channel_fallback(hapd);
+}
+
+
 static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd,
 					     struct dfs_event *radar)
 {
@@ -1072,6 +1080,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 4da5a3d..c504364 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;
@@ -2363,11 +2363,25 @@ void hostapd_cleanup_cs_params(struct hostapd_data *hapd)
 int hostapd_switch_channel(struct hostapd_data *hapd,
 			   struct csa_settings *settings)
 {
+	struct hostapd_iface *iface = hapd->iface;
 	int ret;
+
 	ret = hostapd_fill_csa_settings(hapd, settings);
 	if (ret)
 		return ret;
 
+	iface->csa_freq = settings->freq_params.freq;
+	iface->csa_channel = settings->freq_params.channel;
+	iface->csa_secondary_channel = settings->freq_params.sec_channel_offset;
+
+	if (settings->freq_params.center_freq1)
+		iface->csa_vht_oper_centr_freq_seg0_idx =
+			36 + (settings->freq_params.center_freq1 - 5180) / 5;
+
+	if (settings->freq_params.center_freq2)
+		iface->csa_vht_oper_centr_freq_seg1_idx =
+			36 + (settings->freq_params.center_freq2 - 5180) / 5;
+
 	ret = hostapd_drv_switch_channel(hapd, settings);
 	free_beacon_data(&settings->beacon_csa);
 	free_beacon_data(&settings->beacon_after);
@@ -2382,4 +2396,31 @@ int hostapd_switch_channel(struct hostapd_data *hapd,
 	return 0;
 }
 
+void hostapd_switch_channel_fallback(struct hostapd_data *hapd)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	int i;
+
+	if (!hapd->csa_in_progress)
+		return;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		iface->bss[i]->csa_in_progress = 0;
+		iface->bss[i]->cs_freq_params.freq = 0;
+	}
+
+	wpa_printf(MSG_WARNING, "CSA failed, trying fallback by toggling interface");
+
+	iface->freq = iface->csa_freq;
+	iface->conf->channel = iface->csa_channel;
+	iface->conf->secondary_channel = iface->csa_secondary_channel;
+	iface->conf->vht_oper_centr_freq_seg0_idx =
+		iface->csa_vht_oper_centr_freq_seg0_idx;
+	iface->conf->vht_oper_centr_freq_seg1_idx =
+		iface->csa_vht_oper_centr_freq_seg1_idx;
+
+	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..011dc51 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -362,6 +362,13 @@ struct hostapd_iface {
 	unsigned int acs_num_completed_scans;
 #endif /* CONFIG_ACS */
 
+	/* channel switch parameters - used for fallback if CSA itself fails */
+	int csa_freq;
+	short csa_channel;
+	int csa_secondary_channel;
+	u8 csa_vht_oper_centr_freq_seg0_idx;
+	u8 csa_vht_oper_centr_freq_seg1_idx;
+
 	void (*scan_cb)(struct hostapd_iface *iface);
 	int num_ht40_scan_tries;
 };
@@ -397,6 +404,7 @@ 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_data *hapd);
 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,
 
-- 
1.8.5.3




More information about the Hostap mailing list