[RFC v2 PATCH 2/2] wpa_supplicant: Enable Automatic Channel Selection support for AP mode

Jouni Malinen j at w1.fi
Thu Dec 24 12:17:29 PST 2015


On Fri, Nov 27, 2015 at 12:40:37PM +0100, Ulrich Ölmann wrote:
> Since hostapd supports ACS now, let's enable its support into
> wpa_supplicant when going on AP mode.

This needs some more rebasing to build cleanly on top of the current
tree to address the new hostapd_acs_channel_selected() function and
event.

> diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
> +ifdef CONFIG_ACS
> +CFLAGS += -DCONFIG_ACS
> +OBJS += ../src/ap/acs.o
> +LIBS += -lm
> +endif

Android.mk should have same changes.

> diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
> @@ -210,6 +210,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
> +#ifdef CONFIG_ACS
> +	/* Setting channel to 0 in order to enable ACS */
> +	if (ssid->acs)
> +		conf->channel = 0;
> +#endif
> +
>  	if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
>  		return -1;

This does not work at least when HT support is enabled. That clearing of
conf->channel needs to be moved after this call to
wpa_supplicant_conf_ap_ht().

> diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
> @@ -1920,6 +1920,9 @@ static const struct parse_data ssid_fields[] = {
> +#ifdef CONFIG_ACS
> +	{ INT_RANGE(acs, 0, 1) },
> +#endif /* CONFIG_ACS */

This is missing a matching change in config_file.c to write the new
network profile parameter.

> diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
> @@ -431,6 +431,18 @@ struct wpa_ssid {
> +	/**
> +	 * ACS - Automatic Channel Selection for AP mode
> +	 *
> +	 * If present, it will be handled together with frequency.
> +	 * frequency will be used to determine hardware mode only, when it is
> +	 * used for both hardware mode and channel when used alone. This will
> +	 * force the channel to be set to 0, thus enabling ACS.
> +	 */
> +	int acs;

This does not really sound like the cleanest way of configuring hw
mode.. Maybe something with the new acs parameter could do than assuming
frequency is used in a way that get replaced by ACS.. Anyway, I guess
I'm going to go with this for now.

This is what I currently have in my pending branch:

 src/ap/drv_callbacks.c       |  4 ++--
 src/ap/hostapd.h             |  2 ++
 wpa_supplicant/Android.mk    |  6 ++++++
 wpa_supplicant/Makefile      |  6 ++++++
 wpa_supplicant/ap.c          | 10 ++++++++++
 wpa_supplicant/config.c      |  3 +++
 wpa_supplicant/config_file.c |  3 +++
 wpa_supplicant/config_ssid.h | 12 ++++++++++++
 wpa_supplicant/defconfig     | 26 ++++++++++++++++++++++++++
 wpa_supplicant/events.c      |  8 ++++++++
 10 files changed, 78 insertions(+), 2 deletions(-)

diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 9208569..aad0d81 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -549,8 +549,8 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
 
 
 #ifdef CONFIG_ACS
-static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
-					 struct acs_selected_channels *acs_res)
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+				  struct acs_selected_channels *acs_res)
 {
 	int ret, i;
 
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index a664644..7b59f80 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -496,6 +496,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
 struct survey_results;
 void hostapd_event_get_survey(struct hostapd_iface *iface,
 			      struct survey_results *survey_results);
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+				  struct acs_selected_channels *acs_res);
 
 const struct hostapd_eap_user *
 hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index a558bbe..72af838 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -857,6 +857,12 @@ OBJS += src/ap/peerkey_auth.c
 endif
 endif
 
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
 ifdef CONFIG_PCSC
 # PC/SC interface for smartcards (USIM, GSM SIM)
 L_CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 6bab7d1..1d85958 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -884,6 +884,12 @@ OBJS += ../src/ap/peerkey_auth.o
 endif
 endif
 
+ifdef CONFIG_ACS
+CFLAGS += -DCONFIG_ACS
+OBJS += ../src/ap/acs.o
+LIBS += -lm
+endif
+
 ifdef CONFIG_PCSC
 # PC/SC interface for smartcards (USIM, GSM SIM)
 CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 27fa2a9..29eeb49 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -213,6 +213,14 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
 	if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
 		return -1;
 
+#ifdef CONFIG_ACS
+	if (ssid->acs) {
+		/* Setting channel to 0 in order to enable ACS */
+		conf->channel = 0;
+		wpa_printf(MSG_DEBUG, "Use automatic channel selection");
+	}
+#endif /* CONFIG_ACS */
+
 	if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
 		conf->ieee80211h = 1;
 		conf->ieee80211d = 1;
@@ -559,6 +567,8 @@ static void wpas_ap_configured_cb(void *ctx)
 	struct wpa_supplicant *wpa_s = ctx;
 
 	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+	if (wpa_s->current_ssid && wpa_s->current_ssid->acs)
+		wpa_s->assoc_freq = wpa_s->ap_iface->freq;
 
 	if (wpa_s->ap_configured_cb)
 		wpa_s->ap_configured_cb(wpa_s->ap_configured_cb_ctx,
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index f2ae4fd..85717e9 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1920,6 +1920,9 @@ static const struct parse_data ssid_fields[] = {
 	{ INT_RANGE(mixed_cell, 0, 1) },
 	{ INT_RANGE(frequency, 0, 65000) },
 	{ INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_ACS
+	{ INT_RANGE(acs, 0, 1) },
+#endif /* CONFIG_ACS */
 #ifdef CONFIG_MESH
 	{ FUNC(mesh_basic_rates) },
 	{ INT(dot11MeshMaxRetries) },
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 80e3e56..6ea113e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -747,6 +747,9 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
 	INT(no_auto_peer);
 	INT(frequency);
 	INT(fixed_freq);
+#ifdef CONFIG_ACS
+	INT(acs);
+#endif /* CONFIG_ACS */
 	write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
 	INT(disabled);
 	INT(peerkey);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index de8157a..b296826 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -431,6 +431,18 @@ struct wpa_ssid {
 	 */
 	int fixed_freq;
 
+#ifdef CONFIG_ACS
+	/**
+	 * ACS - Automatic Channel Selection for AP mode
+	 *
+	 * If present, it will be handled together with frequency.
+	 * frequency will be used to determine hardware mode only, when it is
+	 * used for both hardware mode and channel when used alone. This will
+	 * force the channel to be set to 0, thus enabling ACS.
+	 */
+	int acs;
+#endif /* CONFIG_ACS */
+
 	/**
 	 * mesh_basic_rates - BSS Basic rate set for mesh network
 	 *
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index e2e4bdc..8b1d121 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -513,3 +513,29 @@ CONFIG_PEERKEY=y
 
 # OS X builds. This is only for building eapol_test.
 #CONFIG_OSX=y
+
+# Automatic Channel Selection
+# This will allow wpa_supplicant to pick the channel automatically when channel
+# is set to "0".
+#
+# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative
+# to "channel=0". This would enable us to eventually add other ACS algorithms in
+# similar way.
+#
+# Automatic selection is currently only done through initialization, later on
+# we hope to do background checks to keep us moving to more ideal channels as
+# time goes by. ACS is currently only supported through the nl80211 driver and
+# your driver must have survey dump capability that is filled by the driver
+# during scanning.
+#
+# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with
+# a newly to create wpa_supplicant.conf variable acs_num_scans.
+#
+# Supported ACS drivers:
+# * ath9k
+# * ath5k
+# * ath10k
+#
+# For more details refer to:
+# http://wireless.kernel.org/en/users/Documentation/acs
+#CONFIG_ACS=y
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 43f3d9b..2870e89 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3946,6 +3946,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 					 &data->survey_results);
 #endif /* CONFIG_AP */
 		break;
+	case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_ACS
+		if (!wpa_s->ap_iface)
+			break;
+		hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
+					     &data->acs_selected_channels);
+#endif /* CONFIG_ACS */
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
-- 
1.9.1

-- 
Jouni Malinen                                            PGP id EFC895FA



More information about the Hostap mailing list