From 4d5bda5fca79c221f7714ffb85114d7b6bf4f9ff Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Tue, 28 Aug 2012 16:14:13 +0300 Subject: [PATCH] Interworking: Add optional use of network selection on normal scans auto_interworking=1 configuration parameter can be used to request wpa_supplicant to use Interworking network selection automatically as a part of the normal (non-Interworking) network selection if the scan results do not match with enabled networks. This makes scanning work similarly to the "interworking_select auto" command. Signed-hostap: Jouni Malinen --- wpa_supplicant/README-HS20 | 33 ++++++++++++++++++++++++++++++ wpa_supplicant/config.c | 1 + wpa_supplicant/config.h | 11 ++++++++++ wpa_supplicant/config_file.c | 3 +++ wpa_supplicant/events.c | 14 +++++++++++++ wpa_supplicant/interworking.c | 15 ++++++++++++-- wpa_supplicant/interworking.h | 1 + wpa_supplicant/scan.c | 3 +++ wpa_supplicant/wpa_supplicant.conf | 8 ++++++++ wpa_supplicant/wpa_supplicant_i.h | 1 + 10 files changed, 88 insertions(+), 2 deletions(-) diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20 index 0181e8bad..feb904900 100644 --- a/wpa_supplicant/README-HS20 +++ b/wpa_supplicant/README-HS20 @@ -24,6 +24,31 @@ standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std 802.11-2012. +wpa_supplicant network selection +-------------------------------- + +Interworking support added option for configuring credentials that can +work with multiple networks as an alternative to configuration of +network blocks (e.g., per-SSID parameters). When requested to perform +network selection, wpa_supplicant picks the highest priority enabled +network block or credential. If a credential is picked (based on ANQP +information from APs), a temporary network block is created +automatically for the matching network. This temporary network block is +used similarly to the network blocks that can be configured by the user, +but it is not stored into the configuration file and is meant to be used +only for temporary period of time since a new one can be created +whenever needed based on ANQP information and the credential. + +By default, wpa_supplicant is not using automatic network selection +unless requested explicitly with the interworking_select command. This +can be changed with the auto_interworking=1 parameter to perform network +selection automatically whenever trying to find a network for connection +and none of the enabled network blocks match with the scan results. This +case works similarly to "interworking_select auto", i.e., wpa_supplicant +will internally determine which network or credential is going to be +used based on configured priorities, scan results, and ANQP information. + + wpa_supplicant configuration ---------------------------- @@ -65,6 +90,14 @@ hs20=1 # This value controls the Access Network Type value in Probe Request frames. #access_network_type=15 +# Automatic network selection behavior +# 0 = do not automatically go through Interworking network selection +# (i.e., require explicit interworking_select command for this; default) +# 1 = perform Interworking network selection if one or more +# credentials have been configured and scan did not find a +# matching network block +#auto_interworking=0 + Credentials can be pre-configured for automatic network selection: diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index cecf648d2..c970745cf 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -3010,6 +3010,7 @@ static const struct global_parse_data global_fields[] = { { BIN(wps_nfc_dev_pw), 0 }, { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }, { INT(p2p_go_max_inactivity), 0 }, + { INT_RANGE(auto_interworking, 0, 1), 0 }, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index c3c90e2eb..b889ab814 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -736,6 +736,17 @@ struct wpa_config { int p2p_go_max_inactivity; struct hostapd_wmm_ac_params wmm_ac_params[4]; + + /** + * auto_interworking - Whether to use network selection automatically + * + * 0 = do not automatically go through Interworking network selection + * (i.e., require explicit interworking_select command for this) + * 1 = perform Interworking network selection if one or more + * credentials have been configured and scan did not find a + * matching network block + */ + int auto_interworking; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index bd59a8073..531957a94 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -916,6 +916,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY) fprintf(f, "p2p_go_max_inactivity=%d\n", config->p2p_go_max_inactivity); + if (config->auto_interworking) + fprintf(f, "auto_interworking=%d\n", + config->auto_interworking); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index cddcce72d..517e11f72 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -41,6 +41,7 @@ #include "bss.h" #include "scan.h" #include "offchannel.h" +#include "interworking.h" static int wpas_temp_disabled(struct wpa_supplicant *wpa_s, @@ -1204,6 +1205,19 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, return 0; } #endif /* CONFIG_P2P */ +#ifdef CONFIG_INTERWORKING + if (wpa_s->conf->auto_interworking && + wpa_s->conf->interworking && + wpa_s->conf->cred) { + wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: " + "start ANQP fetch since no matching " + "networks found"); + wpa_s->network_select = 1; + wpa_s->auto_network_select = 1; + interworking_start_fetch_anqp(wpa_s); + return 0; + } +#endif /* CONFIG_INTERWORKING */ if (wpa_supplicant_req_sched_scan(wpa_s)) wpa_supplicant_req_new_scan(wpa_s, timeout_sec, timeout_usec); diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 11c57b4a7..7b5b20eb7 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -1411,7 +1411,9 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) type = "unknown"; wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s", MAC2STR(bss->bssid), type); - if (wpa_s->auto_select) { + if (wpa_s->auto_select || + (wpa_s->conf->auto_interworking && + wpa_s->auto_network_select)) { if (selected == NULL || cred->priority > selected_prio) { selected = bss; @@ -1446,6 +1448,14 @@ static void interworking_select_network(struct wpa_supplicant *wpa_s) return; } + if (wpa_s->auto_network_select) { + wpa_printf(MSG_DEBUG, "Interworking: Continue " + "scanning after ANQP fetch"); + wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, + 0); + return; + } + wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network " "with matching credentials found"); } @@ -1490,7 +1500,7 @@ static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s) } -static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) +void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; @@ -1748,6 +1758,7 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select) { interworking_stop_fetch_anqp(wpa_s); wpa_s->network_select = 1; + wpa_s->auto_network_select = 0; wpa_s->auto_select = !!auto_select; wpa_printf(MSG_DEBUG, "Interworking: Start scan for network " "selection"); diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h index 60566e5a2..cb8438e66 100644 --- a/wpa_supplicant/interworking.h +++ b/wpa_supplicant/interworking.h @@ -24,5 +24,6 @@ int interworking_fetch_anqp(struct wpa_supplicant *wpa_s); void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s); int interworking_select(struct wpa_supplicant *wpa_s, int auto_select); int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); +void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s); #endif /* INTERWORKING_H */ diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 93d152ed9..71e7d8d4d 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -89,6 +89,9 @@ int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s) count++; ssid = ssid->next; } + if (wpa_s->conf->cred && wpa_s->conf->interworking && + wpa_s->conf->auto_interworking) + count++; return count; } diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 4cf0ce1f1..2c07fd0a8 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -277,6 +277,14 @@ fast_reauth=1 # is enabled. # hessid=00:11:22:33:44:55 +# Automatic network selection behavior +# 0 = do not automatically go through Interworking network selection +# (i.e., require explicit interworking_select command for this; default) +# 1 = perform Interworking network selection if one or more +# credentials have been configured and scan did not find a +# matching network block +#auto_interworking=0 + # credential block # # Each credential used for automatic network selection is configured as a set diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 4494bcccc..01d67d945 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -570,6 +570,7 @@ struct wpa_supplicant { unsigned int fetch_anqp_in_progress:1; unsigned int network_select:1; unsigned int auto_select:1; + unsigned int auto_network_select:1; #endif /* CONFIG_INTERWORKING */ unsigned int drv_capa_known;