diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 6ba5aae1b..409d6cebf 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1376,6 +1376,44 @@ static int parse_venue_name(struct hostapd_bss_config *bss, char *pos, } +static int parse_venue_url(struct hostapd_bss_config *bss, char *pos, + int line) +{ + char *sep; + size_t nlen; + struct hostapd_venue_url *url; + int ret = -1; + + sep = os_strchr(pos, ':'); + if (!sep) + goto fail; + *sep++ = '\0'; + + nlen = os_strlen(sep); + if (nlen > 254) + goto fail; + + url = os_realloc_array(bss->venue_url, bss->venue_url_count + 1, + sizeof(struct hostapd_venue_url)); + if (!url) + goto fail; + + bss->venue_url = url; + url = &bss->venue_url[bss->venue_url_count++]; + + url->venue_number = atoi(pos); + url->url_len = nlen; + os_memcpy(url->url, sep, nlen); + + ret = 0; +fail: + if (ret) + wpa_printf(MSG_ERROR, "Line %d: Invalid venue_url '%s'", + line, pos); + return ret; +} + + static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf, int line) { @@ -3380,6 +3418,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "venue_name") == 0) { if (parse_venue_name(bss, pos, line) < 0) return 1; + } else if (os_strcmp(buf, "venue_url") == 0) { + if (parse_venue_url(bss, pos, line) < 0) + return 1; } else if (os_strcmp(buf, "network_auth_type") == 0) { u8 auth_type; u16 redirect_url_len; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 73e8fc39f..0843a40e3 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1972,6 +1972,15 @@ own_ip_addr=127.0.0.1 # (double quoted string, printf-escaped string) #venue_name=P"eng:Example\nvenue" +# Venue URL information +# This parameter can be used to configure one or more Venue URL Duples to +# provide additional information corresponding to Venue Name information. +# Each entry has a Venue Number value separated by colon from the Venue URL +# string. Venue Number indicates the corresponding venue_name entry (1 = 1st +# venue_name, 2 = 2nd venue_name, and so on; 0 = no matching venue_name) +#venue_url=1:http://www.example.com/info-eng +#venue_url=2:http://www.example.com/info-fin + # Network Authentication Type # This parameter indicates what type of network authentication is used in the # network. diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 085ad7ac9..dcc5ca60f 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -577,6 +577,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->roaming_consortium); os_free(conf->venue_name); + os_free(conf->venue_url); os_free(conf->nai_realm_data); os_free(conf->network_auth_type); os_free(conf->anqp_3gpp_cell_net); diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 304378234..77812ba93 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -201,6 +201,12 @@ struct hostapd_lang_string { u8 name[252]; }; +struct hostapd_venue_url { + u8 venue_number; + u8 url_len; + u8 url[254]; +}; + #define MAX_NAI_REALMS 10 #define MAX_NAI_REALMLEN 255 #define MAX_NAI_EAP_METHODS 5 @@ -504,6 +510,10 @@ struct hostapd_bss_config { unsigned int venue_name_count; struct hostapd_lang_string *venue_name; + /* Venue URL duples */ + unsigned int venue_url_count; + struct hostapd_venue_url *venue_url; + /* IEEE 802.11u - Network Authentication Type */ u8 *network_auth_type; size_t network_auth_type_len; diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index 6f27b966c..53702e0f2 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -288,7 +288,7 @@ static void anqp_add_capab_list(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ if (get_anqp_elem(hapd, ANQP_CAG)) wpabuf_put_le16(buf, ANQP_CAG); - if (get_anqp_elem(hapd, ANQP_VENUE_URL)) + if (hapd->conf->venue_url || get_anqp_elem(hapd, ANQP_VENUE_URL)) wpabuf_put_le16(buf, ANQP_VENUE_URL); if (get_anqp_elem(hapd, ANQP_ADVICE_OF_CHARGE)) wpabuf_put_le16(buf, ANQP_ADVICE_OF_CHARGE); @@ -328,6 +328,29 @@ static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf) } +static void anqp_add_venue_url(struct hostapd_data *hapd, struct wpabuf *buf) +{ + if (anqp_add_override(hapd, buf, ANQP_VENUE_URL)) + return; + + if (hapd->conf->venue_url) { + u8 *len; + unsigned int i; + + len = gas_anqp_add_element(buf, ANQP_VENUE_URL); + for (i = 0; i < hapd->conf->venue_url_count; i++) { + struct hostapd_venue_url *url; + + url = &hapd->conf->venue_url[i]; + wpabuf_put_u8(buf, 1 + url->url_len); + wpabuf_put_u8(buf, url->venue_number); + wpabuf_put_data(buf, url->url, url->url_len); + } + gas_anqp_set_element_len(buf, len); + } +} + + static void anqp_add_network_auth_type(struct hostapd_data *hapd, struct wpabuf *buf) { @@ -946,6 +969,10 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, continue; } #endif /* CONFIG_FILS */ + if (extra_req[i] == ANQP_VENUE_URL) { + anqp_add_venue_url(hapd, buf); + continue; + } anqp_add_elem(hapd, buf, extra_req[i]); } @@ -1082,7 +1109,10 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, "ANQP: FILS Realm Information (local)"); } else #endif /* CONFIG_FILS */ - if (!get_anqp_elem(hapd, info_id)) { + if (info_id == ANQP_VENUE_URL && hapd->conf->venue_url) { + wpa_printf(MSG_DEBUG, + "ANQP: Venue URL (local)"); + } else if (!get_anqp_elem(hapd, info_id)) { wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u", info_id); break;