Cumulative patch from commit f10ff62e4eda7917a8e28fe492fd98723a5e97c4

f10ff62 Describe preferred mechanism for submitting contributions
fcdb359 Use "STATUS-NO_EVENTS" instead of "STATUS" in get_wpa_status function
73ed03f wpa_supplicant: Add GTK RSC relaxation workaround
ea6030c Restore previous wpa_state in scan-only result handler
1e74ae4 WNM: Clear BSS TM data if already associated with preferred candidate
d129b02 EAP-pwd: Add support for Brainpool Elliptic Curves
a34eace dbus: Remove unused dict helper functions
cdcb2d0 wpa_cli: Add support for vendor_elem_* commands
17b7032 EAP peer: Clear ignore flag in INITIALIZE state
1f1e619 Add test programs for checking libwpa_client linking
736b7cb wpa_supplicant/Makefile: Fix libwpa_client build
2e38079 TLS: Fix memory leak with multiple TLS server instances
7b0f550 eap_sim_db: Implement eap_sim_db_expire_pending()
45c3e72 Add frequency to operating class determination for 5 GHz 100..140
e50c50d dbus: Expose interface globals via D-Bus properties
1aa0fb7 dbus: Pass property description to getters/setters
c93b7e1 RSN: Check result of EAPOL-Key frame send request
95be79f Allow -1 as value to disable frag_threshold
bc50bb0 Extend the range of values for the RTS threshold
053693d hostapd: Add feature to start all interfaces at the same time in sync
9578413 Reserve QCA vendor specific nl80211 commands 110..114
5d4c508 Assign QCA commands and attributes for Tx power scaling and OTA testing
5d1d69a P2P: Filter control chars in group client device name similarly to peer
f67d1a0 TDLS: Do not send error case of TPK M3 if TX fails
1248e58 wpa_supplicant: Reopen debug log file upon receipt of SIGHUP signal
d8fd633 Do not write ERROR level log entries if debug file is not used
67deaa5 l2_packet: Add build option to disable Linux packet socket workaround
fa46426 RSN: Do not try to connect if PMF disabled and AP requires it
8acbe7f WNM: Verify WNM Sleep Mode element length
dacd789 WNM: Mark set TFS buffer const
...
f24b979 OpenSSL: Merge error returns
84d6a17 TLS: Remove unused tls_capabilities()
7867227 ms_funcs: Merge similar return cases
3596361 hw_features: Merge similar return case in check_40mhz_2g4()
aac1efe Reject the initial 4-way handshake if initial GTK setup fails
2da5256 Add backtrace-based error path testing mechanism
55413ce P2P: Do not allow 40 MHz co-ex PRI/SEC switch to force MCC

Next patches were skipped due to explicit cherry-pick:
bddc51e RSN: Stop connection attempt on apparent PMK mismatch
3fdaaa8 Throttle control interface event message bursts
a530fe7 Add wpa_supplicant EVENT_TEST control interface command
ee1e3f5 hostapd: Global control interface notifications
2e95cfc Add debug prints for wpa_supplicant ctrl_iface socket send operations
ce7d0eb Update AP WPA/RSN IE on all associations if driver can select BSS
844dfeb QCA vendor command support to set band to driver

Change-Id: I909996c5afcd3b5d123ea1e23c0e1212021f7625
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 9d19f98..4bcdf6f 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -167,27 +167,107 @@
 #endif /* CONFIG_HS20 */
 
 
+static struct anqp_element * get_anqp_elem(struct hostapd_data *hapd,
+					   u16 infoid)
+{
+	struct anqp_element *elem;
+
+	dl_list_for_each(elem, &hapd->conf->anqp_elem, struct anqp_element,
+			 list) {
+		if (elem->infoid == infoid)
+			return elem;
+	}
+
+	return NULL;
+}
+
+
+static void anqp_add_elem(struct hostapd_data *hapd, struct wpabuf *buf,
+			  u16 infoid)
+{
+	struct anqp_element *elem;
+
+	elem = get_anqp_elem(hapd, infoid);
+	if (!elem)
+		return;
+	if (wpabuf_tailroom(buf) < 2 + 2 + wpabuf_len(elem->payload)) {
+		wpa_printf(MSG_DEBUG, "ANQP: No room for InfoID %u payload",
+			   infoid);
+		return;
+	}
+
+	wpabuf_put_le16(buf, infoid);
+	wpabuf_put_le16(buf, wpabuf_len(elem->payload));
+	wpabuf_put_buf(buf, elem->payload);
+}
+
+
+static int anqp_add_override(struct hostapd_data *hapd, struct wpabuf *buf,
+			     u16 infoid)
+{
+	if (get_anqp_elem(hapd, infoid)) {
+		anqp_add_elem(hapd, buf, infoid);
+		return 1;
+	}
+
+	return 0;
+}
+
+
 static void anqp_add_capab_list(struct hostapd_data *hapd,
 				struct wpabuf *buf)
 {
 	u8 *len;
+	u16 id;
+
+	if (anqp_add_override(hapd, buf, ANQP_CAPABILITY_LIST))
+		return;
 
 	len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
 	wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
-	if (hapd->conf->venue_name)
+	if (hapd->conf->venue_name || get_anqp_elem(hapd, ANQP_VENUE_NAME))
 		wpabuf_put_le16(buf, ANQP_VENUE_NAME);
-	if (hapd->conf->network_auth_type)
+	if (get_anqp_elem(hapd, ANQP_EMERGENCY_CALL_NUMBER))
+		wpabuf_put_le16(buf, ANQP_EMERGENCY_CALL_NUMBER);
+	if (hapd->conf->network_auth_type ||
+	    get_anqp_elem(hapd, ANQP_NETWORK_AUTH_TYPE))
 		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
-	if (hapd->conf->roaming_consortium)
+	if (hapd->conf->roaming_consortium ||
+	    get_anqp_elem(hapd, ANQP_ROAMING_CONSORTIUM))
 		wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
-	if (hapd->conf->ipaddr_type_configured)
+	if (hapd->conf->ipaddr_type_configured ||
+	    get_anqp_elem(hapd, ANQP_IP_ADDR_TYPE_AVAILABILITY))
 		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
-	if (hapd->conf->nai_realm_data)
+	if (hapd->conf->nai_realm_data ||
+	    get_anqp_elem(hapd, ANQP_NAI_REALM))
 		wpabuf_put_le16(buf, ANQP_NAI_REALM);
-	if (hapd->conf->anqp_3gpp_cell_net)
+	if (hapd->conf->anqp_3gpp_cell_net ||
+	    get_anqp_elem(hapd, ANQP_3GPP_CELLULAR_NETWORK))
 		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
-	if (hapd->conf->domain_name)
+	if (get_anqp_elem(hapd, ANQP_AP_GEOSPATIAL_LOCATION))
+		wpabuf_put_le16(buf, ANQP_AP_GEOSPATIAL_LOCATION);
+	if (get_anqp_elem(hapd, ANQP_AP_CIVIC_LOCATION))
+		wpabuf_put_le16(buf, ANQP_AP_CIVIC_LOCATION);
+	if (get_anqp_elem(hapd, ANQP_AP_LOCATION_PUBLIC_URI))
+		wpabuf_put_le16(buf, ANQP_AP_LOCATION_PUBLIC_URI);
+	if (hapd->conf->domain_name || get_anqp_elem(hapd, ANQP_DOMAIN_NAME))
 		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+	if (get_anqp_elem(hapd, ANQP_EMERGENCY_ALERT_URI))
+		wpabuf_put_le16(buf, ANQP_EMERGENCY_ALERT_URI);
+	if (get_anqp_elem(hapd, ANQP_EMERGENCY_NAI))
+		wpabuf_put_le16(buf, ANQP_EMERGENCY_NAI);
+	if (get_anqp_elem(hapd, ANQP_NEIGHBOR_REPORT))
+		wpabuf_put_le16(buf, ANQP_NEIGHBOR_REPORT);
+	for (id = 273; id < 277; id++) {
+		if (get_anqp_elem(hapd, id))
+			wpabuf_put_le16(buf, id);
+	}
+	if (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);
+	if (get_anqp_elem(hapd, ANQP_LOCAL_CONTENT))
+		wpabuf_put_le16(buf, ANQP_LOCAL_CONTENT);
 #ifdef CONFIG_HS20
 	anqp_add_hs_capab_list(hapd, buf);
 #endif /* CONFIG_HS20 */
@@ -197,6 +277,9 @@
 
 static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
 {
+	if (anqp_add_override(hapd, buf, ANQP_VENUE_NAME))
+		return;
+
 	if (hapd->conf->venue_name) {
 		u8 *len;
 		unsigned int i;
@@ -218,6 +301,9 @@
 static void anqp_add_network_auth_type(struct hostapd_data *hapd,
 				       struct wpabuf *buf)
 {
+	if (anqp_add_override(hapd, buf, ANQP_NETWORK_AUTH_TYPE))
+		return;
+
 	if (hapd->conf->network_auth_type) {
 		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
 		wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
@@ -233,6 +319,9 @@
 	unsigned int i;
 	u8 *len;
 
+	if (anqp_add_override(hapd, buf, ANQP_ROAMING_CONSORTIUM))
+		return;
+
 	len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
 	for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
 		struct hostapd_roaming_consortium *rc;
@@ -247,6 +336,9 @@
 static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
 					       struct wpabuf *buf)
 {
+	if (anqp_add_override(hapd, buf, ANQP_IP_ADDR_TYPE_AVAILABILITY))
+		return;
+
 	if (hapd->conf->ipaddr_type_configured) {
 		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
 		wpabuf_put_le16(buf, 1);
@@ -309,7 +401,7 @@
 
 	pos = home_realm;
 	end = pos + home_realm_len;
-	if (pos + 1 > end) {
+	if (end - pos < 1) {
 		wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
 			    home_realm, home_realm_len);
 		return -1;
@@ -317,7 +409,7 @@
 	num_realms = *pos++;
 
 	for (i = 0; i < num_realms && num_matching < 10; i++) {
-		if (pos + 2 > end) {
+		if (end - pos < 2) {
 			wpa_hexdump(MSG_DEBUG,
 				    "Truncated NAI Home Realm Query",
 				    home_realm, home_realm_len);
@@ -325,7 +417,7 @@
 		}
 		encoding = *pos++;
 		realm_len = *pos++;
-		if (pos + realm_len > end) {
+		if (realm_len > end - pos) {
 			wpa_hexdump(MSG_DEBUG,
 				    "Truncated NAI Home Realm Query",
 				    home_realm, home_realm_len);
@@ -391,6 +483,10 @@
 			       const u8 *home_realm, size_t home_realm_len,
 			       int nai_realm, int nai_home_realm)
 {
+	if (nai_realm && !nai_home_realm &&
+	    anqp_add_override(hapd, buf, ANQP_NAI_REALM))
+		return;
+
 	if (nai_realm && hapd->conf->nai_realm_data) {
 		u8 *len;
 		unsigned int i, j;
@@ -424,6 +520,9 @@
 static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
 					   struct wpabuf *buf)
 {
+	if (anqp_add_override(hapd, buf, ANQP_3GPP_CELLULAR_NETWORK))
+		return;
+
 	if (hapd->conf->anqp_3gpp_cell_net) {
 		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
 		wpabuf_put_le16(buf,
@@ -436,6 +535,9 @@
 
 static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
 {
+	if (anqp_add_override(hapd, buf, ANQP_DOMAIN_NAME))
+		return;
+
 	if (hapd->conf->domain_name) {
 		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
 		wpabuf_put_le16(buf, hapd->conf->domain_name_len);
@@ -687,16 +789,20 @@
 gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
 				unsigned int request,
 				const u8 *home_realm, size_t home_realm_len,
-				const u8 *icon_name, size_t icon_name_len)
+				const u8 *icon_name, size_t icon_name_len,
+				const u16 *extra_req,
+				unsigned int num_extra_req)
 {
 	struct wpabuf *buf;
 	size_t len;
+	unsigned int i;
 
 	len = 1400;
 	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
 		len += 1000;
 	if (request & ANQP_REQ_ICON_REQUEST)
 		len += 65536;
+	len += num_extra_req * 1000;
 
 	buf = wpabuf_alloc(len);
 	if (buf == NULL)
@@ -706,6 +812,8 @@
 		anqp_add_capab_list(hapd, buf);
 	if (request & ANQP_REQ_VENUE_NAME)
 		anqp_add_venue_name(hapd, buf);
+	if (request & ANQP_REQ_EMERGENCY_CALL_NUMBER)
+		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_CALL_NUMBER);
 	if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
 		anqp_add_network_auth_type(hapd, buf);
 	if (request & ANQP_REQ_ROAMING_CONSORTIUM)
@@ -718,8 +826,23 @@
 				   request & ANQP_REQ_NAI_HOME_REALM);
 	if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
 		anqp_add_3gpp_cellular_network(hapd, buf);
+	if (request & ANQP_REQ_AP_GEOSPATIAL_LOCATION)
+		anqp_add_elem(hapd, buf, ANQP_AP_GEOSPATIAL_LOCATION);
+	if (request & ANQP_REQ_AP_CIVIC_LOCATION)
+		anqp_add_elem(hapd, buf, ANQP_AP_CIVIC_LOCATION);
+	if (request & ANQP_REQ_AP_LOCATION_PUBLIC_URI)
+		anqp_add_elem(hapd, buf, ANQP_AP_LOCATION_PUBLIC_URI);
 	if (request & ANQP_REQ_DOMAIN_NAME)
 		anqp_add_domain_name(hapd, buf);
+	if (request & ANQP_REQ_EMERGENCY_ALERT_URI)
+		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_ALERT_URI);
+	if (request & ANQP_REQ_TDLS_CAPABILITY)
+		anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
+	if (request & ANQP_REQ_EMERGENCY_NAI)
+		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
+
+	for (i = 0; i < num_extra_req; i++)
+		anqp_add_elem(hapd, buf, extra_req[i]);
 
 #ifdef CONFIG_HS20
 	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
@@ -742,6 +865,8 @@
 }
 
 
+#define ANQP_MAX_EXTRA_REQ 20
+
 struct anqp_query_info {
 	unsigned int request;
 	const u8 *home_realm_query;
@@ -749,6 +874,8 @@
 	const u8 *icon_name;
 	size_t icon_name_len;
 	int p2p_sd;
+	u16 extra_req[ANQP_MAX_EXTRA_REQ];
+	unsigned int num_extra_req;
 };
 
 
@@ -776,6 +903,11 @@
 		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
 			     hapd->conf->venue_name != NULL, qi);
 		break;
+	case ANQP_EMERGENCY_CALL_NUMBER:
+		set_anqp_req(ANQP_REQ_EMERGENCY_CALL_NUMBER,
+			     "Emergency Call Number",
+			     get_anqp_elem(hapd, info_id) != NULL, qi);
+		break;
 	case ANQP_NETWORK_AUTH_TYPE:
 		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
 			     hapd->conf->network_auth_type != NULL, qi);
@@ -798,13 +930,55 @@
 			     "3GPP Cellular Network",
 			     hapd->conf->anqp_3gpp_cell_net != NULL, qi);
 		break;
+	case ANQP_AP_GEOSPATIAL_LOCATION:
+		set_anqp_req(ANQP_REQ_AP_GEOSPATIAL_LOCATION,
+			     "AP Geospatial Location",
+			     get_anqp_elem(hapd, info_id) != NULL, qi);
+		break;
+	case ANQP_AP_CIVIC_LOCATION:
+		set_anqp_req(ANQP_REQ_AP_CIVIC_LOCATION,
+			     "AP Civic Location",
+			     get_anqp_elem(hapd, info_id) != NULL, qi);
+		break;
+	case ANQP_AP_LOCATION_PUBLIC_URI:
+		set_anqp_req(ANQP_REQ_AP_LOCATION_PUBLIC_URI,
+			     "AP Location Public URI",
+			     get_anqp_elem(hapd, info_id) != NULL, qi);
+		break;
 	case ANQP_DOMAIN_NAME:
 		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
 			     hapd->conf->domain_name != NULL, qi);
 		break;
+	case ANQP_EMERGENCY_ALERT_URI:
+		set_anqp_req(ANQP_REQ_EMERGENCY_ALERT_URI,
+			     "Emergency Alert URI",
+			     get_anqp_elem(hapd, info_id) != NULL, qi);
+		break;
+	case ANQP_TDLS_CAPABILITY:
+		set_anqp_req(ANQP_REQ_TDLS_CAPABILITY,
+			     "TDLS Capability",
+			     get_anqp_elem(hapd, info_id) != NULL, qi);
+		break;
+	case ANQP_EMERGENCY_NAI:
+		set_anqp_req(ANQP_REQ_EMERGENCY_NAI,
+			     "Emergency NAI",
+			     get_anqp_elem(hapd, info_id) != NULL, qi);
+		break;
 	default:
-		wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
-			   info_id);
+		if (!get_anqp_elem(hapd, info_id)) {
+			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+				   info_id);
+			break;
+		}
+		if (qi->num_extra_req == ANQP_MAX_EXTRA_REQ) {
+			wpa_printf(MSG_DEBUG,
+				   "ANQP: No more room for extra requests - ignore Info Id %u",
+				   info_id);
+			break;
+		}
+		wpa_printf(MSG_DEBUG, "ANQP: Info Id %u (local)", info_id);
+		qi->extra_req[qi->num_extra_req] = info_id;
+		qi->num_extra_req++;
 		break;
 	}
 }
@@ -817,7 +991,7 @@
 	wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
 		   (unsigned int) (end - pos) / 2);
 
-	while (pos + 2 <= end) {
+	while (end - pos >= 2) {
 		rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
 		pos += 2;
 	}
@@ -906,7 +1080,7 @@
 	u32 oui;
 	u8 subtype;
 
-	if (pos + 4 > end) {
+	if (end - pos < 4) {
 		wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
 			   "Query element");
 		return;
@@ -942,7 +1116,7 @@
 	}
 	pos++;
 
-	if (pos + 1 >= end)
+	if (end - pos <= 1)
 		return;
 
 	subtype = *pos++;
@@ -980,7 +1154,8 @@
 	buf = gas_serv_build_gas_resp_payload(hapd, qi->request,
 					      qi->home_realm_query,
 					      qi->home_realm_query_len,
-					      qi->icon_name, qi->icon_name_len);
+					      qi->icon_name, qi->icon_name_len,
+					      qi->extra_req, qi->num_extra_req);
 	wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
 			buf);
 	if (!buf)
@@ -1069,12 +1244,12 @@
 	adv_proto = pos++;
 
 	slen = *pos++;
-	next = pos + slen;
-	if (next > end || slen < 2) {
+	if (slen > end - pos || slen < 2) {
 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
 			"GAS: Invalid IE in GAS Initial Request");
 		return;
 	}
+	next = pos + slen;
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
@@ -1101,11 +1276,11 @@
 
 	pos = next;
 	/* Query Request */
-	if (pos + 2 > end)
+	if (end - pos < 2)
 		return;
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
-	if (pos + slen > end)
+	if (slen > end - pos)
 		return;
 	end = pos + slen;
 
@@ -1113,7 +1288,7 @@
 	while (pos < end) {
 		u16 info_id, elen;
 
-		if (pos + 4 > end)
+		if (end - pos < 4)
 			return;
 
 		info_id = WPA_GET_LE16(pos);
@@ -1121,7 +1296,7 @@
 		elen = WPA_GET_LE16(pos);
 		pos += 2;
 
-		if (pos + elen > end) {
+		if (elen > end - pos) {
 			wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
 			return;
 		}