diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index e51024554..3485bd497 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -282,6 +282,15 @@ #define INTERWORKING_ANO_ESR 0x40 #define INTERWORKING_ANO_UESA 0x80 +#define INTERWORKING_ANT_PRIVATE 0 +#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1 +#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2 +#define INTERWORKING_ANT_FREE_PUBLIC 3 +#define INTERWORKING_ANT_PERSONAL_DEVICE 4 +#define INTERWORKING_ANT_EMERGENCY_SERVICES 5 +#define INTERWORKING_ANT_TEST 6 +#define INTERWORKING_ANT_WILDCARD 15 + /* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */ enum adv_proto_id { ACCESS_NETWORK_QUERY_PROTOCOL = 0, diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 8bf792755..1ec7b6820 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -209,6 +209,11 @@ CFLAGS += -DCONFIG_P2P_STRICT endif endif +ifdef CONFIG_INTERWORKING +CFLAGS += -DCONFIG_INTERWORKING +NEED_GAS=y +endif + ifdef CONFIG_NO_WPA2 CFLAGS += -DCONFIG_NO_WPA2 endif diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 7ec45310b..31ce26ff7 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -2381,6 +2381,20 @@ static int wpa_config_process_sec_device_type( #endif /* CONFIG_P2P */ +static int wpa_config_process_hessid( + const struct global_parse_data *data, + struct wpa_config *config, int line, const char *pos) +{ + if (hwaddr_aton2(pos, config->hessid) < 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'", + line, pos); + return -1; + } + + return 0; +} + + #ifdef OFFSET #undef OFFSET #endif /* OFFSET */ @@ -2445,7 +2459,9 @@ static const struct global_parse_data global_fields[] = { { INT(bss_expiration_scan_count), 0 }, { INT_RANGE(filter_ssids, 0, 1), 0 }, { INT(max_num_sta), 0 }, - { INT_RANGE(disassoc_low_ack, 0, 1), 0 } + { INT_RANGE(disassoc_low_ack, 0, 1), 0 }, + { INT_RANGE(interworking, 0, 1), 0 }, + { FUNC(hessid), 0 } }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 2bc05dac6..300cf2856 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -426,6 +426,20 @@ struct wpa_config { * disassoc_low_ack - Disassocicate stations with massive packet loss */ int disassoc_low_ack; + + /** + * interworking - Whether Interworking (IEEE 802.11u) is enabled + */ + int interworking; + + /** + * hessid - Homogenous ESS identifier + * + * If this is set (any octet is non-zero), scans will be used to + * request response only from BSSes belonging to the specified + * Homogeneous ESS. This is used only if interworking is enabled. + */ + u8 hessid[ETH_ALEN]; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 2d5fdd6a0..a5d08430e 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -703,6 +703,10 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) fprintf(f, "max_num_sta=%u\n", config->max_num_sta); if (config->disassoc_low_ack) fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack); + if (config->interworking) + fprintf(f, "interworking=%u\n", config->interworking); + if (!is_zero_ether_addr(config->hessid)) + fprintf(f, "hessid=" MACSTR "\n", MAC2STR(config->hessid)); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 452bdeb58..022e9987d 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -457,3 +457,9 @@ CONFIG_PEERKEY=y # IEEE 802.11n (High Throughput) support (mainly for AP mode) #CONFIG_IEEE80211N=y + +# Interworking (IEEE 802.11u) +# This can be used to enable functionality to improve interworking with +# external networks (GAS/ANQP to learn more about the networks and network +# selection based on available credentials). +#CONFIG_INTERWORKING=y diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 67f46ed2d..2d3a38f92 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -354,41 +354,73 @@ static void wpa_supplicant_optimize_freqs( } +#ifdef CONFIG_INTERWORKING +static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s, + struct wpabuf *buf) +{ + if (wpa_s->conf->interworking == 0) + return; + + wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB); + wpabuf_put_u8(buf, 4); + wpabuf_put_u8(buf, 0x00); + wpabuf_put_u8(buf, 0x00); + wpabuf_put_u8(buf, 0x00); + wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */ + + wpabuf_put_u8(buf, WLAN_EID_INTERWORKING); + wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 : + 1 + ETH_ALEN); + wpabuf_put_u8(buf, INTERWORKING_ANT_WILDCARD); + /* No Venue Info */ + if (!is_zero_ether_addr(wpa_s->conf->hessid)) + wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN); +} +#endif /* CONFIG_INTERWORKING */ + + static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params) { - struct wpabuf *wps_ie = NULL; + struct wpabuf *extra_ie = NULL; #ifdef CONFIG_WPS int wps = 0; enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO; +#endif /* CONFIG_WPS */ +#ifdef CONFIG_INTERWORKING + if (wpa_s->conf->interworking && + wpabuf_resize(&extra_ie, 100) == 0) + wpas_add_interworking_elements(wpa_s, extra_ie); +#endif /* CONFIG_INTERWORKING */ + +#ifdef CONFIG_WPS wps = wpas_wps_in_use(wpa_s, &req_type); if (wps) { + struct wpabuf *wps_ie; wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev, wpa_s->wps->uuid, req_type, 0, NULL); if (wps_ie) { - params->extra_ies = wpabuf_head(wps_ie); - params->extra_ies_len = wpabuf_len(wps_ie); + if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0) + wpabuf_put_buf(extra_ie, wps_ie); + wpabuf_free(wps_ie); } } #ifdef CONFIG_P2P - if (wps_ie) { + if (wps) { size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p); - if (wpabuf_resize(&wps_ie, ielen) == 0) { - wpas_p2p_scan_ie(wpa_s, wps_ie); - params->extra_ies = wpabuf_head(wps_ie); - params->extra_ies_len = wpabuf_len(wps_ie); - } + if (wpabuf_resize(&extra_ie, ielen) == 0) + wpas_p2p_scan_ie(wpa_s, extra_ie); } #endif /* CONFIG_P2P */ #endif /* CONFIG_WPS */ - return wps_ie; + return extra_ie; } @@ -397,7 +429,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) struct wpa_supplicant *wpa_s = eloop_ctx; struct wpa_ssid *ssid; int scan_req = 0, ret; - struct wpabuf *wps_ie; + struct wpabuf *extra_ie; struct wpa_driver_scan_params params; size_t max_ssids; enum wpa_states prev_state; @@ -558,7 +590,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) } wpa_supplicant_optimize_freqs(wpa_s, ¶ms); - wps_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms); + extra_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms); if (params.freqs == NULL && wpa_s->next_scan_freqs) { wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously " @@ -570,10 +602,14 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) params.filter_ssids = wpa_supplicant_build_filter_ssids( wpa_s->conf, ¶ms.num_filter_ssids); + if (extra_ie) { + params.extra_ies = wpabuf_head(extra_ie); + params.extra_ies_len = wpabuf_len(extra_ie); + } ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms); - wpabuf_free(wps_ie); + wpabuf_free(extra_ie); os_free(params.freqs); os_free(params.filter_ssids); diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index a7c3fccce..12dd7fd8c 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -228,6 +228,17 @@ fast_reauth=1 #filter_ssids=0 +# Interworking (IEEE 802.11u) + +# Enable Interworking +# interworking=1 + +# Homogenous ESS identifier +# If this is set, scans will be used to request response only from BSSes +# belonging to the specified Homogeneous ESS. This is used only if interworking +# is enabled. +# hessid=00:11:22:33:44:55 + # network block # # Each network (usually AP's sharing the same SSID) is configured as a separate