Home | History | Annotate | Download | only in ap
      1 /*
      2  * Generic advertisement service (GAS) server
      3  * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
      4  *
      5  * This software may be distributed under the terms of the BSD license.
      6  * See README for more details.
      7  */
      8 
      9 #include "includes.h"
     10 
     11 #include "common.h"
     12 #include "common/ieee802_11_defs.h"
     13 #include "common/gas.h"
     14 #include "utils/eloop.h"
     15 #include "hostapd.h"
     16 #include "ap_config.h"
     17 #include "ap_drv_ops.h"
     18 #include "sta_info.h"
     19 #include "gas_serv.h"
     20 
     21 
     22 static struct gas_dialog_info *
     23 gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
     24 {
     25 	struct sta_info *sta;
     26 	struct gas_dialog_info *dia = NULL;
     27 	int i, j;
     28 
     29 	sta = ap_get_sta(hapd, addr);
     30 	if (!sta) {
     31 		/*
     32 		 * We need a STA entry to be able to maintain state for
     33 		 * the GAS query.
     34 		 */
     35 		wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
     36 			   "GAS query");
     37 		sta = ap_sta_add(hapd, addr);
     38 		if (!sta) {
     39 			wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
     40 				   " for GAS query", MAC2STR(addr));
     41 			return NULL;
     42 		}
     43 		sta->flags |= WLAN_STA_GAS;
     44 		/*
     45 		 * The default inactivity is 300 seconds. We don't need
     46 		 * it to be that long.
     47 		 */
     48 		ap_sta_session_timeout(hapd, sta, 5);
     49 	}
     50 
     51 	if (sta->gas_dialog == NULL) {
     52 		sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
     53 					    sizeof(struct gas_dialog_info));
     54 		if (sta->gas_dialog == NULL)
     55 			return NULL;
     56 	}
     57 
     58 	for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
     59 		if (i == GAS_DIALOG_MAX)
     60 			i = 0;
     61 		if (sta->gas_dialog[i].valid)
     62 			continue;
     63 		dia = &sta->gas_dialog[i];
     64 		dia->valid = 1;
     65 		dia->index = i;
     66 		dia->dialog_token = dialog_token;
     67 		sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
     68 		return dia;
     69 	}
     70 
     71 	wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
     72 		MACSTR " dialog_token %u. Consider increasing "
     73 		"GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
     74 
     75 	return NULL;
     76 }
     77 
     78 
     79 struct gas_dialog_info *
     80 gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
     81 		     u8 dialog_token)
     82 {
     83 	struct sta_info *sta;
     84 	int i;
     85 
     86 	sta = ap_get_sta(hapd, addr);
     87 	if (!sta) {
     88 		wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
     89 			   MAC2STR(addr));
     90 		return NULL;
     91 	}
     92 	for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
     93 		if (sta->gas_dialog[i].dialog_token != dialog_token ||
     94 		    !sta->gas_dialog[i].valid)
     95 			continue;
     96 		return &sta->gas_dialog[i];
     97 	}
     98 	wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
     99 		   MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
    100 	return NULL;
    101 }
    102 
    103 
    104 void gas_serv_dialog_clear(struct gas_dialog_info *dia)
    105 {
    106 	wpabuf_free(dia->sd_resp);
    107 	os_memset(dia, 0, sizeof(*dia));
    108 }
    109 
    110 
    111 static void gas_serv_free_dialogs(struct hostapd_data *hapd,
    112 				  const u8 *sta_addr)
    113 {
    114 	struct sta_info *sta;
    115 	int i;
    116 
    117 	sta = ap_get_sta(hapd, sta_addr);
    118 	if (sta == NULL || sta->gas_dialog == NULL)
    119 		return;
    120 
    121 	for (i = 0; i < GAS_DIALOG_MAX; i++) {
    122 		if (sta->gas_dialog[i].valid)
    123 			return;
    124 	}
    125 
    126 	os_free(sta->gas_dialog);
    127 	sta->gas_dialog = NULL;
    128 }
    129 
    130 
    131 #ifdef CONFIG_HS20
    132 static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
    133 				   struct wpabuf *buf)
    134 {
    135 	u8 *len;
    136 
    137 	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
    138 	wpabuf_put_be24(buf, OUI_WFA);
    139 	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
    140 	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
    141 	wpabuf_put_u8(buf, 0); /* Reserved */
    142 	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
    143 	if (hapd->conf->hs20_oper_friendly_name)
    144 		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
    145 	if (hapd->conf->hs20_wan_metrics)
    146 		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
    147 	if (hapd->conf->hs20_connection_capability)
    148 		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
    149 	if (hapd->conf->nai_realm_data)
    150 		wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
    151 	if (hapd->conf->hs20_operating_class)
    152 		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
    153 	gas_anqp_set_element_len(buf, len);
    154 }
    155 #endif /* CONFIG_HS20 */
    156 
    157 
    158 static void anqp_add_capab_list(struct hostapd_data *hapd,
    159 				struct wpabuf *buf)
    160 {
    161 	u8 *len;
    162 
    163 	len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
    164 	wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
    165 	if (hapd->conf->venue_name)
    166 		wpabuf_put_le16(buf, ANQP_VENUE_NAME);
    167 	if (hapd->conf->network_auth_type)
    168 		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
    169 	if (hapd->conf->roaming_consortium)
    170 		wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
    171 	if (hapd->conf->ipaddr_type_configured)
    172 		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
    173 	if (hapd->conf->nai_realm_data)
    174 		wpabuf_put_le16(buf, ANQP_NAI_REALM);
    175 	if (hapd->conf->anqp_3gpp_cell_net)
    176 		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
    177 	if (hapd->conf->domain_name)
    178 		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
    179 #ifdef CONFIG_HS20
    180 	anqp_add_hs_capab_list(hapd, buf);
    181 #endif /* CONFIG_HS20 */
    182 	gas_anqp_set_element_len(buf, len);
    183 }
    184 
    185 
    186 static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
    187 {
    188 	if (hapd->conf->venue_name) {
    189 		u8 *len;
    190 		unsigned int i;
    191 		len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
    192 		wpabuf_put_u8(buf, hapd->conf->venue_group);
    193 		wpabuf_put_u8(buf, hapd->conf->venue_type);
    194 		for (i = 0; i < hapd->conf->venue_name_count; i++) {
    195 			struct hostapd_lang_string *vn;
    196 			vn = &hapd->conf->venue_name[i];
    197 			wpabuf_put_u8(buf, 3 + vn->name_len);
    198 			wpabuf_put_data(buf, vn->lang, 3);
    199 			wpabuf_put_data(buf, vn->name, vn->name_len);
    200 		}
    201 		gas_anqp_set_element_len(buf, len);
    202 	}
    203 }
    204 
    205 
    206 static void anqp_add_network_auth_type(struct hostapd_data *hapd,
    207 				       struct wpabuf *buf)
    208 {
    209 	if (hapd->conf->network_auth_type) {
    210 		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
    211 		wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
    212 		wpabuf_put_data(buf, hapd->conf->network_auth_type,
    213 				hapd->conf->network_auth_type_len);
    214 	}
    215 }
    216 
    217 
    218 static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
    219 					struct wpabuf *buf)
    220 {
    221 	unsigned int i;
    222 	u8 *len;
    223 
    224 	len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
    225 	for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
    226 		struct hostapd_roaming_consortium *rc;
    227 		rc = &hapd->conf->roaming_consortium[i];
    228 		wpabuf_put_u8(buf, rc->len);
    229 		wpabuf_put_data(buf, rc->oi, rc->len);
    230 	}
    231 	gas_anqp_set_element_len(buf, len);
    232 }
    233 
    234 
    235 static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
    236 					       struct wpabuf *buf)
    237 {
    238 	if (hapd->conf->ipaddr_type_configured) {
    239 		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
    240 		wpabuf_put_le16(buf, 1);
    241 		wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
    242 	}
    243 }
    244 
    245 
    246 static void anqp_add_nai_realm_eap(struct wpabuf *buf,
    247 				   struct hostapd_nai_realm_data *realm)
    248 {
    249 	unsigned int i, j;
    250 
    251 	wpabuf_put_u8(buf, realm->eap_method_count);
    252 
    253 	for (i = 0; i < realm->eap_method_count; i++) {
    254 		struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
    255 		wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
    256 		wpabuf_put_u8(buf, eap->eap_method);
    257 		wpabuf_put_u8(buf, eap->num_auths);
    258 		for (j = 0; j < eap->num_auths; j++) {
    259 			wpabuf_put_u8(buf, eap->auth_id[j]);
    260 			wpabuf_put_u8(buf, 1);
    261 			wpabuf_put_u8(buf, eap->auth_val[j]);
    262 		}
    263 	}
    264 }
    265 
    266 
    267 static void anqp_add_nai_realm_data(struct wpabuf *buf,
    268 				    struct hostapd_nai_realm_data *realm,
    269 				    unsigned int realm_idx)
    270 {
    271 	u8 *realm_data_len;
    272 
    273 	wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
    274 		   (int) os_strlen(realm->realm[realm_idx]));
    275 	realm_data_len = wpabuf_put(buf, 2);
    276 	wpabuf_put_u8(buf, realm->encoding);
    277 	wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
    278 	wpabuf_put_str(buf, realm->realm[realm_idx]);
    279 	anqp_add_nai_realm_eap(buf, realm);
    280 	gas_anqp_set_element_len(buf, realm_data_len);
    281 }
    282 
    283 
    284 static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
    285 					   struct wpabuf *buf,
    286 					   const u8 *home_realm,
    287 					   size_t home_realm_len)
    288 {
    289 	unsigned int i, j, k;
    290 	u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
    291 	struct hostapd_nai_realm_data *realm;
    292 	const u8 *pos, *realm_name, *end;
    293 	struct {
    294 		unsigned int realm_data_idx;
    295 		unsigned int realm_idx;
    296 	} matches[10];
    297 
    298 	pos = home_realm;
    299 	end = pos + home_realm_len;
    300 	if (pos + 1 > end) {
    301 		wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
    302 			    home_realm, home_realm_len);
    303 		return -1;
    304 	}
    305 	num_realms = *pos++;
    306 
    307 	for (i = 0; i < num_realms && num_matching < 10; i++) {
    308 		if (pos + 2 > end) {
    309 			wpa_hexdump(MSG_DEBUG,
    310 				    "Truncated NAI Home Realm Query",
    311 				    home_realm, home_realm_len);
    312 			return -1;
    313 		}
    314 		encoding = *pos++;
    315 		realm_len = *pos++;
    316 		if (pos + realm_len > end) {
    317 			wpa_hexdump(MSG_DEBUG,
    318 				    "Truncated NAI Home Realm Query",
    319 				    home_realm, home_realm_len);
    320 			return -1;
    321 		}
    322 		realm_name = pos;
    323 		for (j = 0; j < hapd->conf->nai_realm_count &&
    324 			     num_matching < 10; j++) {
    325 			const u8 *rpos, *rend;
    326 			realm = &hapd->conf->nai_realm_data[j];
    327 			if (encoding != realm->encoding)
    328 				continue;
    329 
    330 			rpos = realm_name;
    331 			while (rpos < realm_name + realm_len &&
    332 			       num_matching < 10) {
    333 				for (rend = rpos;
    334 				     rend < realm_name + realm_len; rend++) {
    335 					if (*rend == ';')
    336 						break;
    337 				}
    338 				for (k = 0; k < MAX_NAI_REALMS &&
    339 					     realm->realm[k] &&
    340 					     num_matching < 10; k++) {
    341 					if ((int) os_strlen(realm->realm[k]) !=
    342 					    rend - rpos ||
    343 					    os_strncmp((char *) rpos,
    344 						       realm->realm[k],
    345 						       rend - rpos) != 0)
    346 						continue;
    347 					matches[num_matching].realm_data_idx =
    348 						j;
    349 					matches[num_matching].realm_idx = k;
    350 					num_matching++;
    351 				}
    352 				rpos = rend + 1;
    353 			}
    354 		}
    355 		pos += realm_len;
    356 	}
    357 
    358 	realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
    359 	wpabuf_put_le16(buf, num_matching);
    360 
    361 	/*
    362 	 * There are two ways to format. 1. each realm in a NAI Realm Data unit
    363 	 * 2. all realms that share the same EAP methods in a NAI Realm Data
    364 	 * unit. The first format is likely to be bigger in size than the
    365 	 * second, but may be easier to parse and process by the receiver.
    366 	 */
    367 	for (i = 0; i < num_matching; i++) {
    368 		wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
    369 			   matches[i].realm_data_idx, matches[i].realm_idx);
    370 		realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
    371 		anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
    372 	}
    373 	gas_anqp_set_element_len(buf, realm_list_len);
    374 	return 0;
    375 }
    376 
    377 
    378 static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
    379 			       const u8 *home_realm, size_t home_realm_len,
    380 			       int nai_realm, int nai_home_realm)
    381 {
    382 	if (nai_realm && hapd->conf->nai_realm_data) {
    383 		u8 *len;
    384 		unsigned int i, j;
    385 		len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
    386 		wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
    387 		for (i = 0; i < hapd->conf->nai_realm_count; i++) {
    388 			u8 *realm_data_len, *realm_len;
    389 			struct hostapd_nai_realm_data *realm;
    390 
    391 			realm = &hapd->conf->nai_realm_data[i];
    392 			realm_data_len = wpabuf_put(buf, 2);
    393 			wpabuf_put_u8(buf, realm->encoding);
    394 			realm_len = wpabuf_put(buf, 1);
    395 			for (j = 0; realm->realm[j]; j++) {
    396 				if (j > 0)
    397 					wpabuf_put_u8(buf, ';');
    398 				wpabuf_put_str(buf, realm->realm[j]);
    399 			}
    400 			*realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
    401 			anqp_add_nai_realm_eap(buf, realm);
    402 			gas_anqp_set_element_len(buf, realm_data_len);
    403 		}
    404 		gas_anqp_set_element_len(buf, len);
    405 	} else if (nai_home_realm && hapd->conf->nai_realm_data) {
    406 		hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
    407 						home_realm_len);
    408 	}
    409 }
    410 
    411 
    412 static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
    413 					   struct wpabuf *buf)
    414 {
    415 	if (hapd->conf->anqp_3gpp_cell_net) {
    416 		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
    417 		wpabuf_put_le16(buf,
    418 				hapd->conf->anqp_3gpp_cell_net_len);
    419 		wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
    420 				hapd->conf->anqp_3gpp_cell_net_len);
    421 	}
    422 }
    423 
    424 
    425 static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
    426 {
    427 	if (hapd->conf->domain_name) {
    428 		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
    429 		wpabuf_put_le16(buf, hapd->conf->domain_name_len);
    430 		wpabuf_put_data(buf, hapd->conf->domain_name,
    431 				hapd->conf->domain_name_len);
    432 	}
    433 }
    434 
    435 
    436 #ifdef CONFIG_HS20
    437 
    438 static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
    439 					    struct wpabuf *buf)
    440 {
    441 	if (hapd->conf->hs20_oper_friendly_name) {
    442 		u8 *len;
    443 		unsigned int i;
    444 		len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
    445 		wpabuf_put_be24(buf, OUI_WFA);
    446 		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
    447 		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
    448 		wpabuf_put_u8(buf, 0); /* Reserved */
    449 		for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
    450 		{
    451 			struct hostapd_lang_string *vn;
    452 			vn = &hapd->conf->hs20_oper_friendly_name[i];
    453 			wpabuf_put_u8(buf, 3 + vn->name_len);
    454 			wpabuf_put_data(buf, vn->lang, 3);
    455 			wpabuf_put_data(buf, vn->name, vn->name_len);
    456 		}
    457 		gas_anqp_set_element_len(buf, len);
    458 	}
    459 }
    460 
    461 
    462 static void anqp_add_wan_metrics(struct hostapd_data *hapd,
    463 				 struct wpabuf *buf)
    464 {
    465 	if (hapd->conf->hs20_wan_metrics) {
    466 		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
    467 		wpabuf_put_be24(buf, OUI_WFA);
    468 		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
    469 		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
    470 		wpabuf_put_u8(buf, 0); /* Reserved */
    471 		wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
    472 		gas_anqp_set_element_len(buf, len);
    473 	}
    474 }
    475 
    476 
    477 static void anqp_add_connection_capability(struct hostapd_data *hapd,
    478 					   struct wpabuf *buf)
    479 {
    480 	if (hapd->conf->hs20_connection_capability) {
    481 		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
    482 		wpabuf_put_be24(buf, OUI_WFA);
    483 		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
    484 		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
    485 		wpabuf_put_u8(buf, 0); /* Reserved */
    486 		wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
    487 				hapd->conf->hs20_connection_capability_len);
    488 		gas_anqp_set_element_len(buf, len);
    489 	}
    490 }
    491 
    492 
    493 static void anqp_add_operating_class(struct hostapd_data *hapd,
    494 				     struct wpabuf *buf)
    495 {
    496 	if (hapd->conf->hs20_operating_class) {
    497 		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
    498 		wpabuf_put_be24(buf, OUI_WFA);
    499 		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
    500 		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
    501 		wpabuf_put_u8(buf, 0); /* Reserved */
    502 		wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
    503 				hapd->conf->hs20_operating_class_len);
    504 		gas_anqp_set_element_len(buf, len);
    505 	}
    506 }
    507 
    508 #endif /* CONFIG_HS20 */
    509 
    510 
    511 static struct wpabuf *
    512 gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
    513 				unsigned int request,
    514 				struct gas_dialog_info *di,
    515 				const u8 *home_realm, size_t home_realm_len)
    516 {
    517 	struct wpabuf *buf;
    518 
    519 	buf = wpabuf_alloc(1400);
    520 	if (buf == NULL)
    521 		return NULL;
    522 
    523 	if (request & ANQP_REQ_CAPABILITY_LIST)
    524 		anqp_add_capab_list(hapd, buf);
    525 	if (request & ANQP_REQ_VENUE_NAME)
    526 		anqp_add_venue_name(hapd, buf);
    527 	if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
    528 		anqp_add_network_auth_type(hapd, buf);
    529 	if (request & ANQP_REQ_ROAMING_CONSORTIUM)
    530 		anqp_add_roaming_consortium(hapd, buf);
    531 	if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
    532 		anqp_add_ip_addr_type_availability(hapd, buf);
    533 	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
    534 		anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
    535 				   request & ANQP_REQ_NAI_REALM,
    536 				   request & ANQP_REQ_NAI_HOME_REALM);
    537 	if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
    538 		anqp_add_3gpp_cellular_network(hapd, buf);
    539 	if (request & ANQP_REQ_DOMAIN_NAME)
    540 		anqp_add_domain_name(hapd, buf);
    541 
    542 #ifdef CONFIG_HS20
    543 	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
    544 		anqp_add_hs_capab_list(hapd, buf);
    545 	if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
    546 		anqp_add_operator_friendly_name(hapd, buf);
    547 	if (request & ANQP_REQ_WAN_METRICS)
    548 		anqp_add_wan_metrics(hapd, buf);
    549 	if (request & ANQP_REQ_CONNECTION_CAPABILITY)
    550 		anqp_add_connection_capability(hapd, buf);
    551 	if (request & ANQP_REQ_OPERATING_CLASS)
    552 		anqp_add_operating_class(hapd, buf);
    553 #endif /* CONFIG_HS20 */
    554 
    555 	return buf;
    556 }
    557 
    558 
    559 static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
    560 {
    561 	struct gas_dialog_info *dia = eloop_data;
    562 
    563 	wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
    564 		   "dialog token %d", dia->dialog_token);
    565 
    566 	gas_serv_dialog_clear(dia);
    567 }
    568 
    569 
    570 struct anqp_query_info {
    571 	unsigned int request;
    572 	unsigned int remote_request;
    573 	const u8 *home_realm_query;
    574 	size_t home_realm_query_len;
    575 	u16 remote_delay;
    576 };
    577 
    578 
    579 static void set_anqp_req(unsigned int bit, const char *name, int local,
    580 			 unsigned int remote, u16 remote_delay,
    581 			 struct anqp_query_info *qi)
    582 {
    583 	qi->request |= bit;
    584 	if (local) {
    585 		wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
    586 	} else if (bit & remote) {
    587 		wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
    588 		qi->remote_request |= bit;
    589 		if (remote_delay > qi->remote_delay)
    590 			qi->remote_delay = remote_delay;
    591 	} else {
    592 		wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
    593 	}
    594 }
    595 
    596 
    597 static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
    598 				  struct anqp_query_info *qi)
    599 {
    600 	switch (info_id) {
    601 	case ANQP_CAPABILITY_LIST:
    602 		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
    603 			     0, qi);
    604 		break;
    605 	case ANQP_VENUE_NAME:
    606 		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
    607 			     hapd->conf->venue_name != NULL, 0, 0, qi);
    608 		break;
    609 	case ANQP_NETWORK_AUTH_TYPE:
    610 		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
    611 			     hapd->conf->network_auth_type != NULL,
    612 			     0, 0, qi);
    613 		break;
    614 	case ANQP_ROAMING_CONSORTIUM:
    615 		set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
    616 			     hapd->conf->roaming_consortium != NULL, 0, 0, qi);
    617 		break;
    618 	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
    619 		set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
    620 			     "IP Addr Type Availability",
    621 			     hapd->conf->ipaddr_type_configured,
    622 			     0, 0, qi);
    623 		break;
    624 	case ANQP_NAI_REALM:
    625 		set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
    626 			     hapd->conf->nai_realm_data != NULL,
    627 			     0, 0, qi);
    628 		break;
    629 	case ANQP_3GPP_CELLULAR_NETWORK:
    630 		set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
    631 			     "3GPP Cellular Network",
    632 			     hapd->conf->anqp_3gpp_cell_net != NULL,
    633 			     0, 0, qi);
    634 		break;
    635 	case ANQP_DOMAIN_NAME:
    636 		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
    637 			     hapd->conf->domain_name != NULL,
    638 			     0, 0, qi);
    639 		break;
    640 	default:
    641 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
    642 			   info_id);
    643 		break;
    644 	}
    645 }
    646 
    647 
    648 static void rx_anqp_query_list(struct hostapd_data *hapd,
    649 			       const u8 *pos, const u8 *end,
    650 			       struct anqp_query_info *qi)
    651 {
    652 	wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
    653 		   (unsigned int) (end - pos) / 2);
    654 
    655 	while (pos + 2 <= end) {
    656 		rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
    657 		pos += 2;
    658 	}
    659 }
    660 
    661 
    662 #ifdef CONFIG_HS20
    663 
    664 static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
    665 				  struct anqp_query_info *qi)
    666 {
    667 	switch (subtype) {
    668 	case HS20_STYPE_CAPABILITY_LIST:
    669 		set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
    670 			     1, 0, 0, qi);
    671 		break;
    672 	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
    673 		set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
    674 			     "Operator Friendly Name",
    675 			     hapd->conf->hs20_oper_friendly_name != NULL,
    676 			     0, 0, qi);
    677 		break;
    678 	case HS20_STYPE_WAN_METRICS:
    679 		set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
    680 			     hapd->conf->hs20_wan_metrics != NULL,
    681 			     0, 0, qi);
    682 		break;
    683 	case HS20_STYPE_CONNECTION_CAPABILITY:
    684 		set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
    685 			     "Connection Capability",
    686 			     hapd->conf->hs20_connection_capability != NULL,
    687 			     0, 0, qi);
    688 		break;
    689 	case HS20_STYPE_OPERATING_CLASS:
    690 		set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
    691 			     hapd->conf->hs20_operating_class != NULL,
    692 			     0, 0, qi);
    693 		break;
    694 	default:
    695 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
    696 			   subtype);
    697 		break;
    698 	}
    699 }
    700 
    701 
    702 static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
    703 				      const u8 *pos, const u8 *end,
    704 				      struct anqp_query_info *qi)
    705 {
    706 	qi->request |= ANQP_REQ_NAI_HOME_REALM;
    707 	qi->home_realm_query = pos;
    708 	qi->home_realm_query_len = end - pos;
    709 	if (hapd->conf->nai_realm_data != NULL) {
    710 		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
    711 			   "(local)");
    712 	} else {
    713 		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
    714 			   "available");
    715 	}
    716 }
    717 
    718 
    719 static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
    720 				    const u8 *pos, const u8 *end,
    721 				    struct anqp_query_info *qi)
    722 {
    723 	u32 oui;
    724 	u8 subtype;
    725 
    726 	if (pos + 4 > end) {
    727 		wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
    728 			   "Query element");
    729 		return;
    730 	}
    731 
    732 	oui = WPA_GET_BE24(pos);
    733 	pos += 3;
    734 	if (oui != OUI_WFA) {
    735 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
    736 			   oui);
    737 		return;
    738 	}
    739 
    740 	if (*pos != HS20_ANQP_OUI_TYPE) {
    741 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
    742 			   *pos);
    743 		return;
    744 	}
    745 	pos++;
    746 
    747 	if (pos + 1 >= end)
    748 		return;
    749 
    750 	subtype = *pos++;
    751 	pos++; /* Reserved */
    752 	switch (subtype) {
    753 	case HS20_STYPE_QUERY_LIST:
    754 		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
    755 		while (pos < end) {
    756 			rx_anqp_hs_query_list(hapd, *pos, qi);
    757 			pos++;
    758 		}
    759 		break;
    760 	case HS20_STYPE_NAI_HOME_REALM_QUERY:
    761 		rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
    762 		break;
    763 	default:
    764 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
    765 			   "%u", subtype);
    766 		break;
    767 	}
    768 }
    769 
    770 #endif /* CONFIG_HS20 */
    771 
    772 
    773 static void gas_serv_req_local_processing(struct hostapd_data *hapd,
    774 					  const u8 *sa, u8 dialog_token,
    775 					  struct anqp_query_info *qi)
    776 {
    777 	struct wpabuf *buf, *tx_buf;
    778 
    779 	buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
    780 					      qi->home_realm_query,
    781 					      qi->home_realm_query_len);
    782 	wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
    783 			buf);
    784 	if (!buf)
    785 		return;
    786 
    787 	if (wpabuf_len(buf) > hapd->gas_frag_limit ||
    788 	    hapd->conf->gas_comeback_delay) {
    789 		struct gas_dialog_info *di;
    790 		u16 comeback_delay = 1;
    791 
    792 		if (hapd->conf->gas_comeback_delay) {
    793 			/* Testing - allow overriding of the delay value */
    794 			comeback_delay = hapd->conf->gas_comeback_delay;
    795 		}
    796 
    797 		wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
    798 			   "initial response - use GAS comeback");
    799 		di = gas_dialog_create(hapd, sa, dialog_token);
    800 		if (!di) {
    801 			wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
    802 				   "for " MACSTR " (dialog token %u)",
    803 				   MAC2STR(sa), dialog_token);
    804 			wpabuf_free(buf);
    805 			return;
    806 		}
    807 		di->sd_resp = buf;
    808 		di->sd_resp_pos = 0;
    809 		tx_buf = gas_anqp_build_initial_resp_buf(
    810 			dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
    811 			NULL);
    812 	} else {
    813 		wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
    814 		tx_buf = gas_anqp_build_initial_resp_buf(
    815 			dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
    816 		wpabuf_free(buf);
    817 	}
    818 	if (!tx_buf)
    819 		return;
    820 
    821 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
    822 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
    823 	wpabuf_free(tx_buf);
    824 }
    825 
    826 
    827 static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
    828 					const u8 *sa,
    829 					const u8 *data, size_t len)
    830 {
    831 	const u8 *pos = data;
    832 	const u8 *end = data + len;
    833 	const u8 *next;
    834 	u8 dialog_token;
    835 	u16 slen;
    836 	struct anqp_query_info qi;
    837 	const u8 *adv_proto;
    838 
    839 	if (len < 1 + 2)
    840 		return;
    841 
    842 	os_memset(&qi, 0, sizeof(qi));
    843 
    844 	dialog_token = *pos++;
    845 	wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    846 		"GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
    847 		MAC2STR(sa), dialog_token);
    848 
    849 	if (*pos != WLAN_EID_ADV_PROTO) {
    850 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    851 			"GAS: Unexpected IE in GAS Initial Request: %u", *pos);
    852 		return;
    853 	}
    854 	adv_proto = pos++;
    855 
    856 	slen = *pos++;
    857 	next = pos + slen;
    858 	if (next > end || slen < 2) {
    859 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    860 			"GAS: Invalid IE in GAS Initial Request");
    861 		return;
    862 	}
    863 	pos++; /* skip QueryRespLenLimit and PAME-BI */
    864 
    865 	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
    866 		struct wpabuf *buf;
    867 		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    868 			"GAS: Unsupported GAS advertisement protocol id %u",
    869 			*pos);
    870 		if (sa[0] & 0x01)
    871 			return; /* Invalid source address - drop silently */
    872 		buf = gas_build_initial_resp(
    873 			dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
    874 			0, 2 + slen + 2);
    875 		if (buf == NULL)
    876 			return;
    877 		wpabuf_put_data(buf, adv_proto, 2 + slen);
    878 		wpabuf_put_le16(buf, 0); /* Query Response Length */
    879 		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
    880 					wpabuf_head(buf), wpabuf_len(buf));
    881 		wpabuf_free(buf);
    882 		return;
    883 	}
    884 
    885 	pos = next;
    886 	/* Query Request */
    887 	if (pos + 2 > end)
    888 		return;
    889 	slen = WPA_GET_LE16(pos);
    890 	pos += 2;
    891 	if (pos + slen > end)
    892 		return;
    893 	end = pos + slen;
    894 
    895 	/* ANQP Query Request */
    896 	while (pos < end) {
    897 		u16 info_id, elen;
    898 
    899 		if (pos + 4 > end)
    900 			return;
    901 
    902 		info_id = WPA_GET_LE16(pos);
    903 		pos += 2;
    904 		elen = WPA_GET_LE16(pos);
    905 		pos += 2;
    906 
    907 		if (pos + elen > end) {
    908 			wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
    909 			return;
    910 		}
    911 
    912 		switch (info_id) {
    913 		case ANQP_QUERY_LIST:
    914 			rx_anqp_query_list(hapd, pos, pos + elen, &qi);
    915 			break;
    916 #ifdef CONFIG_HS20
    917 		case ANQP_VENDOR_SPECIFIC:
    918 			rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
    919 			break;
    920 #endif /* CONFIG_HS20 */
    921 		default:
    922 			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
    923 				   "Request element %u", info_id);
    924 			break;
    925 		}
    926 
    927 		pos += elen;
    928 	}
    929 
    930 	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
    931 }
    932 
    933 
    934 void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
    935 			      struct gas_dialog_info *dialog)
    936 {
    937 	struct wpabuf *buf, *tx_buf;
    938 	u8 dialog_token = dialog->dialog_token;
    939 	size_t frag_len;
    940 
    941 	if (dialog->sd_resp == NULL) {
    942 		buf = gas_serv_build_gas_resp_payload(hapd,
    943 						      dialog->all_requested,
    944 						      dialog, NULL, 0);
    945 		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
    946 			buf);
    947 		if (!buf)
    948 			goto tx_gas_response_done;
    949 		dialog->sd_resp = buf;
    950 		dialog->sd_resp_pos = 0;
    951 	}
    952 	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
    953 	if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
    954 	    hapd->conf->gas_comeback_delay) {
    955 		u16 comeback_delay_tus = dialog->comeback_delay +
    956 			GAS_SERV_COMEBACK_DELAY_FUDGE;
    957 		u32 comeback_delay_secs, comeback_delay_usecs;
    958 
    959 		if (hapd->conf->gas_comeback_delay) {
    960 			/* Testing - allow overriding of the delay value */
    961 			comeback_delay_tus = hapd->conf->gas_comeback_delay;
    962 		}
    963 
    964 		wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
    965 			   "%u) and comeback delay %u, "
    966 			   "requesting comebacks", (unsigned int) frag_len,
    967 			   (unsigned int) hapd->gas_frag_limit,
    968 			   dialog->comeback_delay);
    969 		tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
    970 							 WLAN_STATUS_SUCCESS,
    971 							 comeback_delay_tus,
    972 							 NULL);
    973 		if (tx_buf) {
    974 			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
    975 				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
    976 			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
    977 						dst,
    978 						wpabuf_head(tx_buf),
    979 						wpabuf_len(tx_buf));
    980 		}
    981 		wpabuf_free(tx_buf);
    982 
    983 		/* start a timer of 1.5 * comeback-delay */
    984 		comeback_delay_tus = comeback_delay_tus +
    985 			(comeback_delay_tus / 2);
    986 		comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
    987 		comeback_delay_usecs = (comeback_delay_tus * 1024) -
    988 			(comeback_delay_secs * 1000000);
    989 		eloop_register_timeout(comeback_delay_secs,
    990 				       comeback_delay_usecs,
    991 				       gas_serv_clear_cached_ies, dialog,
    992 				       NULL);
    993 		goto tx_gas_response_done;
    994 	}
    995 
    996 	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
    997 				dialog->sd_resp_pos, frag_len);
    998 	if (buf == NULL) {
    999 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
   1000 			"failed");
   1001 		goto tx_gas_response_done;
   1002 	}
   1003 	tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
   1004 						 WLAN_STATUS_SUCCESS, 0, buf);
   1005 	wpabuf_free(buf);
   1006 	if (tx_buf == NULL)
   1007 		goto tx_gas_response_done;
   1008 	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
   1009 		"Response (frag_id %d frag_len %d)",
   1010 		dialog->sd_frag_id, (int) frag_len);
   1011 	dialog->sd_frag_id++;
   1012 
   1013 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
   1014 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
   1015 	wpabuf_free(tx_buf);
   1016 tx_gas_response_done:
   1017 	gas_serv_clear_cached_ies(dialog, NULL);
   1018 }
   1019 
   1020 
   1021 static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
   1022 					 const u8 *sa,
   1023 					 const u8 *data, size_t len)
   1024 {
   1025 	struct gas_dialog_info *dialog;
   1026 	struct wpabuf *buf, *tx_buf;
   1027 	u8 dialog_token;
   1028 	size_t frag_len;
   1029 	int more = 0;
   1030 
   1031 	wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
   1032 	if (len < 1)
   1033 		return;
   1034 	dialog_token = *data;
   1035 	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
   1036 		dialog_token);
   1037 
   1038 	dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
   1039 	if (!dialog) {
   1040 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
   1041 			"response fragment for " MACSTR " dialog token %u",
   1042 			MAC2STR(sa), dialog_token);
   1043 
   1044 		if (sa[0] & 0x01)
   1045 			return; /* Invalid source address - drop silently */
   1046 		tx_buf = gas_anqp_build_comeback_resp_buf(
   1047 			dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
   1048 			0, NULL);
   1049 		if (tx_buf == NULL)
   1050 			return;
   1051 		goto send_resp;
   1052 	}
   1053 
   1054 	if (dialog->sd_resp == NULL) {
   1055 		wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
   1056 			   dialog->requested, dialog->received);
   1057 		if ((dialog->requested & dialog->received) !=
   1058 		    dialog->requested) {
   1059 			wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
   1060 				   "from remote processing");
   1061 			gas_serv_dialog_clear(dialog);
   1062 			tx_buf = gas_anqp_build_comeback_resp_buf(
   1063 				dialog_token,
   1064 				WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
   1065 				NULL);
   1066 			if (tx_buf == NULL)
   1067 				return;
   1068 			goto send_resp;
   1069 		}
   1070 
   1071 		buf = gas_serv_build_gas_resp_payload(hapd,
   1072 						      dialog->all_requested,
   1073 						      dialog, NULL, 0);
   1074 		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
   1075 			buf);
   1076 		if (!buf)
   1077 			goto rx_gas_comeback_req_done;
   1078 		dialog->sd_resp = buf;
   1079 		dialog->sd_resp_pos = 0;
   1080 	}
   1081 	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
   1082 	if (frag_len > hapd->gas_frag_limit) {
   1083 		frag_len = hapd->gas_frag_limit;
   1084 		more = 1;
   1085 	}
   1086 	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
   1087 		(unsigned int) frag_len);
   1088 	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
   1089 				dialog->sd_resp_pos, frag_len);
   1090 	if (buf == NULL) {
   1091 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
   1092 			"buffer");
   1093 		goto rx_gas_comeback_req_done;
   1094 	}
   1095 	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
   1096 						  WLAN_STATUS_SUCCESS,
   1097 						  dialog->sd_frag_id,
   1098 						  more, 0, buf);
   1099 	wpabuf_free(buf);
   1100 	if (tx_buf == NULL)
   1101 		goto rx_gas_comeback_req_done;
   1102 	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
   1103 		"(frag_id %d more=%d frag_len=%d)",
   1104 		dialog->sd_frag_id, more, (int) frag_len);
   1105 	dialog->sd_frag_id++;
   1106 	dialog->sd_resp_pos += frag_len;
   1107 
   1108 	if (more) {
   1109 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
   1110 			"to be sent",
   1111 			(int) (wpabuf_len(dialog->sd_resp) -
   1112 			       dialog->sd_resp_pos));
   1113 	} else {
   1114 		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
   1115 			"SD response sent");
   1116 		gas_serv_dialog_clear(dialog);
   1117 		gas_serv_free_dialogs(hapd, sa);
   1118 	}
   1119 
   1120 send_resp:
   1121 	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
   1122 				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
   1123 	wpabuf_free(tx_buf);
   1124 	return;
   1125 
   1126 rx_gas_comeback_req_done:
   1127 	gas_serv_clear_cached_ies(dialog, NULL);
   1128 }
   1129 
   1130 
   1131 static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
   1132 				      int freq)
   1133 {
   1134 	struct hostapd_data *hapd = ctx;
   1135 	const struct ieee80211_mgmt *mgmt;
   1136 	size_t hdr_len;
   1137 	const u8 *sa, *data;
   1138 
   1139 	mgmt = (const struct ieee80211_mgmt *) buf;
   1140 	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
   1141 	if (hdr_len > len)
   1142 		return;
   1143 	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
   1144 		return;
   1145 	sa = mgmt->sa;
   1146 	len -= hdr_len;
   1147 	data = &mgmt->u.action.u.public_action.action;
   1148 	switch (data[0]) {
   1149 	case WLAN_PA_GAS_INITIAL_REQ:
   1150 		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
   1151 		break;
   1152 	case WLAN_PA_GAS_COMEBACK_REQ:
   1153 		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
   1154 		break;
   1155 	}
   1156 }
   1157 
   1158 
   1159 int gas_serv_init(struct hostapd_data *hapd)
   1160 {
   1161 	hapd->public_action_cb2 = gas_serv_rx_public_action;
   1162 	hapd->public_action_cb2_ctx = hapd;
   1163 	hapd->gas_frag_limit = 1400;
   1164 	if (hapd->conf->gas_frag_limit > 0)
   1165 		hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
   1166 	return 0;
   1167 }
   1168 
   1169 
   1170 void gas_serv_deinit(struct hostapd_data *hapd)
   1171 {
   1172 }
   1173