diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 549bba9c4..8988bf926 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1408,6 +1408,42 @@ fail: #endif /* CONFIG_INTERWORKING */ +#ifdef CONFIG_HS20 +static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf, + int line) +{ + u8 *conn_cap; + char *pos; + + if (bss->hs20_connection_capability_len >= 0xfff0) + return -1; + + conn_cap = os_realloc(bss->hs20_connection_capability, + bss->hs20_connection_capability_len + 4); + if (conn_cap == NULL) + return -1; + + bss->hs20_connection_capability = conn_cap; + conn_cap += bss->hs20_connection_capability_len; + pos = buf; + conn_cap[0] = atoi(pos); + pos = os_strchr(pos, ':'); + if (pos == NULL) + return -1; + pos++; + WPA_PUT_LE16(conn_cap + 1, atoi(pos)); + pos = os_strchr(pos, ':'); + if (pos == NULL) + return -1; + pos++; + conn_cap[3] = atoi(pos); + bss->hs20_connection_capability_len += 4; + + return 0; +} +#endif /* CONFIG_HS20 */ + + #ifdef CONFIG_WPS_NFC static struct wpabuf * hostapd_parse_bin(const char *buf) { @@ -2573,6 +2609,11 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->hs20 = atoi(pos); } else if (os_strcmp(buf, "disable_dgaf") == 0) { bss->disable_dgaf = atoi(pos); + } else if (os_strcmp(buf, "hs20_conn_capab") == 0) { + if (hs20_parse_conn_capab(bss, pos, line) < 0) { + errors++; + return errors; + } } else if (os_strcmp(buf, "hs20_operating_class") == 0) { u8 *oper_class; size_t oper_class_len; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 04474ba93..aa90d78bb 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -1400,6 +1400,19 @@ own_ip_addr=127.0.0.1 # forging such frames to other stations in the BSS. #disable_dgaf=1 +# Connection Capability +# This can be used to advertise what type of IP traffic can be sent through the +# hotspot (e.g., due to firewall allowing/blocking protocols/ports). +# format: :: +# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP +# Port Number: 0..65535 +# Status: 0 = Closed, 1 = Open, 2 = Unknown +# Each hs20_conn_capab line is added to the list of advertised tuples. +#hs20_conn_capab=1:0:2 +#hs20_conn_capab=6:22:1 +#hs20_conn_capab=17:5060:0 + + # Operating Class Indication # List of operating classes the BSSes in this ESS use. The Global operating # classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 8f6a6e844..c4aabdad4 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -507,6 +507,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf) #endif /* CONFIG_RADIUS_TEST */ #ifdef CONFIG_HS20 + os_free(conf->hs20_connection_capability); os_free(conf->hs20_operating_class); #endif /* CONFIG_HS20 */ } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 221ebe2df..ebc1b9599 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -410,6 +410,8 @@ struct hostapd_bss_config { #ifdef CONFIG_HS20 int hs20; int disable_dgaf; + u8 *hs20_connection_capability; + size_t hs20_connection_capability_len; u8 *hs20_operating_class; u8 hs20_operating_class_len; #endif /* CONFIG_HS20 */ diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index c8bfa111f..f914eefef 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -139,6 +139,8 @@ static void anqp_add_hs_capab_list(struct hostapd_data *hapd, wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); wpabuf_put_u8(buf, 0); /* Reserved */ wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST); + if (hapd->conf->hs20_connection_capability) + wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); if (hapd->conf->hs20_operating_class) wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS); gas_anqp_set_element_len(buf, len); @@ -253,6 +255,22 @@ static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf) } +static void anqp_add_connection_capability(struct hostapd_data *hapd, + struct wpabuf *buf) +{ + if (hapd->conf->hs20_connection_capability) { + u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC); + wpabuf_put_be24(buf, OUI_WFA); + wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE); + wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY); + wpabuf_put_u8(buf, 0); /* Reserved */ + wpabuf_put_data(buf, hapd->conf->hs20_connection_capability, + hapd->conf->hs20_connection_capability_len); + gas_anqp_set_element_len(buf, len); + } +} + + static void anqp_add_operating_class(struct hostapd_data *hapd, struct wpabuf *buf) { @@ -297,6 +315,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, if (request & ANQP_REQ_HS_CAPABILITY_LIST) anqp_add_hs_capab_list(hapd, buf); + if (request & ANQP_REQ_CONNECTION_CAPABILITY) + anqp_add_connection_capability(hapd, buf); if (request & ANQP_REQ_OPERATING_CLASS) anqp_add_operating_class(hapd, buf); @@ -410,6 +430,12 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List", 1, 0, 0, qi); break; + case HS20_STYPE_CONNECTION_CAPABILITY: + set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY, + "Connection Capability", + hapd->conf->hs20_connection_capability != NULL, + 0, 0, qi); + break; case HS20_STYPE_OPERATING_CLASS: set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class", hapd->conf->hs20_operating_class != NULL, diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h index 369daad48..e6e373995 100644 --- a/src/ap/gas_serv.h +++ b/src/ap/gas_serv.h @@ -25,6 +25,8 @@ (1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST)) #define ANQP_REQ_HS_CAPABILITY_LIST \ (0x10000 << HS20_STYPE_CAPABILITY_LIST) +#define ANQP_REQ_CONNECTION_CAPABILITY \ + (0x10000 << HS20_STYPE_CONNECTION_CAPABILITY) #define ANQP_REQ_OPERATING_CLASS \ (0x10000 << HS20_STYPE_OPERATING_CLASS)