1/*
2 * Interworking (IEEE 802.11u)
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 "common/wpa_ctrl.h"
15#include "utils/pcsc_funcs.h"
16#include "utils/eloop.h"
17#include "drivers/driver.h"
18#include "eap_common/eap_defs.h"
19#include "eap_peer/eap.h"
20#include "eap_peer/eap_methods.h"
21#include "wpa_supplicant_i.h"
22#include "config.h"
23#include "config_ssid.h"
24#include "bss.h"
25#include "scan.h"
26#include "notify.h"
27#include "gas_query.h"
28#include "hs20_supplicant.h"
29#include "interworking.h"
30
31
32#if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
33#define INTERWORKING_3GPP
34#else
35#if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
36#define INTERWORKING_3GPP
37#else
38#if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
39#define INTERWORKING_3GPP
40#endif
41#endif
42#endif
43
44static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
45
46
47static void interworking_reconnect(struct wpa_supplicant *wpa_s)
48{
49	if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
50		wpa_supplicant_cancel_sched_scan(wpa_s);
51		wpa_supplicant_deauthenticate(wpa_s,
52					      WLAN_REASON_DEAUTH_LEAVING);
53	}
54	wpa_s->disconnected = 0;
55	wpa_s->reassociate = 1;
56
57	if (wpa_s->last_scan_res_used > 0) {
58		struct os_time now;
59		os_get_time(&now);
60		if (now.sec - wpa_s->last_scan.sec <= 5) {
61			wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
62				   "are fresh - connect without new scan");
63			if (wpas_select_network_from_last_scan(wpa_s) >= 0)
64				return;
65		}
66	}
67
68	wpa_supplicant_req_scan(wpa_s, 0, 0);
69}
70
71
72static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
73				      struct wpabuf *extra)
74{
75	struct wpabuf *buf;
76	size_t i;
77	u8 *len_pos;
78
79	buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
80					 (extra ? wpabuf_len(extra) : 0));
81	if (buf == NULL)
82		return NULL;
83
84	len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
85	for (i = 0; i < num_ids; i++)
86		wpabuf_put_le16(buf, info_ids[i]);
87	gas_anqp_set_element_len(buf, len_pos);
88	if (extra)
89		wpabuf_put_buf(buf, extra);
90
91	gas_anqp_set_len(buf);
92
93	return buf;
94}
95
96
97static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
98				      u8 dialog_token,
99				      enum gas_query_result result,
100				      const struct wpabuf *adv_proto,
101				      const struct wpabuf *resp,
102				      u16 status_code)
103{
104	struct wpa_supplicant *wpa_s = ctx;
105
106	anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
107		     status_code);
108	interworking_next_anqp_fetch(wpa_s);
109}
110
111
112static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
113{
114	struct wpa_cred *cred;
115
116	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
117		if (cred->roaming_consortium_len)
118			return 1;
119	}
120	return 0;
121}
122
123
124static int cred_with_3gpp(struct wpa_supplicant *wpa_s)
125{
126	struct wpa_cred *cred;
127
128	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
129		if (cred->pcsc || cred->imsi)
130			return 1;
131	}
132	return 0;
133}
134
135
136static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
137{
138	struct wpa_cred *cred;
139
140	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
141		if (cred->pcsc || cred->imsi)
142			continue;
143		if (!cred->eap_method)
144			return 1;
145		if (cred->realm && cred->roaming_consortium_len == 0)
146			return 1;
147	}
148	return 0;
149}
150
151
152static int cred_with_domain(struct wpa_supplicant *wpa_s)
153{
154	struct wpa_cred *cred;
155
156	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
157		if (cred->domain || cred->pcsc || cred->imsi)
158			return 1;
159	}
160	return 0;
161}
162
163
164static int additional_roaming_consortiums(struct wpa_bss *bss)
165{
166	const u8 *ie;
167	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
168	if (ie == NULL || ie[1] == 0)
169		return 0;
170	return ie[2]; /* Number of ANQP OIs */
171}
172
173
174static void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx)
175{
176	struct wpa_supplicant *wpa_s = eloop_ctx;
177	interworking_next_anqp_fetch(wpa_s);
178}
179
180
181static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
182				      struct wpa_bss *bss)
183{
184	struct wpabuf *buf;
185	int ret = 0;
186	int res;
187	u16 info_ids[8];
188	size_t num_info_ids = 0;
189	struct wpabuf *extra = NULL;
190	int all = wpa_s->fetch_all_anqp;
191
192	wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
193		   MAC2STR(bss->bssid));
194
195	info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
196	if (all) {
197		info_ids[num_info_ids++] = ANQP_VENUE_NAME;
198		info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
199	}
200	if (all || (cred_with_roaming_consortium(wpa_s) &&
201		    additional_roaming_consortiums(bss)))
202		info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
203	if (all)
204		info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
205	if (all || cred_with_nai_realm(wpa_s))
206		info_ids[num_info_ids++] = ANQP_NAI_REALM;
207	if (all || cred_with_3gpp(wpa_s))
208		info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
209	if (all || cred_with_domain(wpa_s))
210		info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
211	wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
212		    (u8 *) info_ids, num_info_ids * 2);
213
214#ifdef CONFIG_HS20
215	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
216		u8 *len_pos;
217
218		extra = wpabuf_alloc(100);
219		if (!extra)
220			return -1;
221
222		len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC);
223		wpabuf_put_be24(extra, OUI_WFA);
224		wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE);
225		wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
226		wpabuf_put_u8(extra, 0); /* Reserved */
227		wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
228		if (all) {
229			wpabuf_put_u8(extra,
230				      HS20_STYPE_OPERATOR_FRIENDLY_NAME);
231			wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
232			wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
233			wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
234		}
235		gas_anqp_set_element_len(extra, len_pos);
236	}
237#endif /* CONFIG_HS20 */
238
239	buf = anqp_build_req(info_ids, num_info_ids, extra);
240	wpabuf_free(extra);
241	if (buf == NULL)
242		return -1;
243
244	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
245			    interworking_anqp_resp_cb, wpa_s);
246	if (res < 0) {
247		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
248		ret = -1;
249		eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
250				       NULL);
251	} else
252		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
253			   "%u", res);
254
255	wpabuf_free(buf);
256	return ret;
257}
258
259
260struct nai_realm_eap {
261	u8 method;
262	u8 inner_method;
263	enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
264	u8 cred_type;
265	u8 tunneled_cred_type;
266};
267
268struct nai_realm {
269	u8 encoding;
270	char *realm;
271	u8 eap_count;
272	struct nai_realm_eap *eap;
273};
274
275
276static void nai_realm_free(struct nai_realm *realms, u16 count)
277{
278	u16 i;
279
280	if (realms == NULL)
281		return;
282	for (i = 0; i < count; i++) {
283		os_free(realms[i].eap);
284		os_free(realms[i].realm);
285	}
286	os_free(realms);
287}
288
289
290static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
291				      const u8 *end)
292{
293	u8 elen, auth_count, a;
294	const u8 *e_end;
295
296	if (pos + 3 > end) {
297		wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
298		return NULL;
299	}
300
301	elen = *pos++;
302	if (pos + elen > end || elen < 2) {
303		wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
304		return NULL;
305	}
306	e_end = pos + elen;
307	e->method = *pos++;
308	auth_count = *pos++;
309	wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
310		   elen, e->method, auth_count);
311
312	for (a = 0; a < auth_count; a++) {
313		u8 id, len;
314
315		if (pos + 2 > end || pos + 2 + pos[1] > end) {
316			wpa_printf(MSG_DEBUG, "No room for Authentication "
317				   "Parameter subfield");
318			return NULL;
319		}
320
321		id = *pos++;
322		len = *pos++;
323
324		switch (id) {
325		case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
326			if (len < 1)
327				break;
328			e->inner_non_eap = *pos;
329			if (e->method != EAP_TYPE_TTLS)
330				break;
331			switch (*pos) {
332			case NAI_REALM_INNER_NON_EAP_PAP:
333				wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
334				break;
335			case NAI_REALM_INNER_NON_EAP_CHAP:
336				wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
337				break;
338			case NAI_REALM_INNER_NON_EAP_MSCHAP:
339				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
340				break;
341			case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
342				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
343				break;
344			}
345			break;
346		case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
347			if (len < 1)
348				break;
349			e->inner_method = *pos;
350			wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
351				   e->inner_method);
352			break;
353		case NAI_REALM_EAP_AUTH_CRED_TYPE:
354			if (len < 1)
355				break;
356			e->cred_type = *pos;
357			wpa_printf(MSG_DEBUG, "Credential Type: %u",
358				   e->cred_type);
359			break;
360		case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
361			if (len < 1)
362				break;
363			e->tunneled_cred_type = *pos;
364			wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
365				   "Type: %u", e->tunneled_cred_type);
366			break;
367		default:
368			wpa_printf(MSG_DEBUG, "Unsupported Authentication "
369				   "Parameter: id=%u len=%u", id, len);
370			wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
371				    "Value", pos, len);
372			break;
373		}
374
375		pos += len;
376	}
377
378	return e_end;
379}
380
381
382static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
383					const u8 *end)
384{
385	u16 len;
386	const u8 *f_end;
387	u8 realm_len, e;
388
389	if (end - pos < 4) {
390		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
391			   "fixed fields");
392		return NULL;
393	}
394
395	len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
396	pos += 2;
397	if (pos + len > end || len < 3) {
398		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
399			   "(len=%u; left=%u)",
400			   len, (unsigned int) (end - pos));
401		return NULL;
402	}
403	f_end = pos + len;
404
405	r->encoding = *pos++;
406	realm_len = *pos++;
407	if (pos + realm_len > f_end) {
408		wpa_printf(MSG_DEBUG, "No room for NAI Realm "
409			   "(len=%u; left=%u)",
410			   realm_len, (unsigned int) (f_end - pos));
411		return NULL;
412	}
413	wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
414	r->realm = os_malloc(realm_len + 1);
415	if (r->realm == NULL)
416		return NULL;
417	os_memcpy(r->realm, pos, realm_len);
418	r->realm[realm_len] = '\0';
419	pos += realm_len;
420
421	if (pos + 1 > f_end) {
422		wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
423		return NULL;
424	}
425	r->eap_count = *pos++;
426	wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
427	if (pos + r->eap_count * 3 > f_end) {
428		wpa_printf(MSG_DEBUG, "No room for EAP Methods");
429		return NULL;
430	}
431	r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
432	if (r->eap == NULL)
433		return NULL;
434
435	for (e = 0; e < r->eap_count; e++) {
436		pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
437		if (pos == NULL)
438			return NULL;
439	}
440
441	return f_end;
442}
443
444
445static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
446{
447	struct nai_realm *realm;
448	const u8 *pos, *end;
449	u16 i, num;
450
451	if (anqp == NULL || wpabuf_len(anqp) < 2)
452		return NULL;
453
454	pos = wpabuf_head_u8(anqp);
455	end = pos + wpabuf_len(anqp);
456	num = WPA_GET_LE16(pos);
457	wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
458	pos += 2;
459
460	if (num * 5 > end - pos) {
461		wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
462			   "enough data (%u octets) for that many realms",
463			   num, (unsigned int) (end - pos));
464		return NULL;
465	}
466
467	realm = os_calloc(num, sizeof(struct nai_realm));
468	if (realm == NULL)
469		return NULL;
470
471	for (i = 0; i < num; i++) {
472		pos = nai_realm_parse_realm(&realm[i], pos, end);
473		if (pos == NULL) {
474			nai_realm_free(realm, num);
475			return NULL;
476		}
477	}
478
479	*count = num;
480	return realm;
481}
482
483
484static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
485{
486	char *tmp, *pos, *end;
487	int match = 0;
488
489	if (realm->realm == NULL || home_realm == NULL)
490		return 0;
491
492	if (os_strchr(realm->realm, ';') == NULL)
493		return os_strcasecmp(realm->realm, home_realm) == 0;
494
495	tmp = os_strdup(realm->realm);
496	if (tmp == NULL)
497		return 0;
498
499	pos = tmp;
500	while (*pos) {
501		end = os_strchr(pos, ';');
502		if (end)
503			*end = '\0';
504		if (os_strcasecmp(pos, home_realm) == 0) {
505			match = 1;
506			break;
507		}
508		if (end == NULL)
509			break;
510		pos = end + 1;
511	}
512
513	os_free(tmp);
514
515	return match;
516}
517
518
519static int nai_realm_cred_username(struct nai_realm_eap *eap)
520{
521	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
522		return 0; /* method not supported */
523
524	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
525		/* Only tunneled methods with username/password supported */
526		return 0;
527	}
528
529	if (eap->method == EAP_TYPE_PEAP) {
530		if (eap->inner_method &&
531		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
532			return 0;
533		if (!eap->inner_method &&
534		    eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
535			return 0;
536	}
537
538	if (eap->method == EAP_TYPE_TTLS) {
539		if (eap->inner_method == 0 && eap->inner_non_eap == 0)
540			return 1; /* Assume TTLS/MSCHAPv2 is used */
541		if (eap->inner_method &&
542		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
543			return 0;
544		if (eap->inner_non_eap &&
545		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
546		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
547		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
548		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
549			return 0;
550	}
551
552	if (eap->inner_method &&
553	    eap->inner_method != EAP_TYPE_GTC &&
554	    eap->inner_method != EAP_TYPE_MSCHAPV2)
555		return 0;
556
557	return 1;
558}
559
560
561static int nai_realm_cred_cert(struct nai_realm_eap *eap)
562{
563	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
564		return 0; /* method not supported */
565
566	if (eap->method != EAP_TYPE_TLS) {
567		/* Only EAP-TLS supported for credential authentication */
568		return 0;
569	}
570
571	return 1;
572}
573
574
575static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
576						 struct nai_realm *realm)
577{
578	u8 e;
579
580	if (cred == NULL ||
581	    cred->username == NULL ||
582	    cred->username[0] == '\0' ||
583	    ((cred->password == NULL ||
584	      cred->password[0] == '\0') &&
585	     (cred->private_key == NULL ||
586	      cred->private_key[0] == '\0')))
587		return NULL;
588
589	for (e = 0; e < realm->eap_count; e++) {
590		struct nai_realm_eap *eap = &realm->eap[e];
591		if (cred->password && cred->password[0] &&
592		    nai_realm_cred_username(eap))
593			return eap;
594		if (cred->private_key && cred->private_key[0] &&
595		    nai_realm_cred_cert(eap))
596			return eap;
597	}
598
599	return NULL;
600}
601
602
603#ifdef INTERWORKING_3GPP
604
605static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
606{
607	u8 plmn[3];
608	const u8 *pos, *end;
609	u8 udhl;
610
611	/* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
612	plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
613	plmn[1] = imsi[2] - '0';
614	/* default to MNC length 3 if unknown */
615	if (mnc_len != 2)
616		plmn[1] |= (imsi[5] - '0') << 4;
617	else
618		plmn[1] |= 0xf0;
619	plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
620
621	if (anqp == NULL)
622		return 0;
623	pos = wpabuf_head_u8(anqp);
624	end = pos + wpabuf_len(anqp);
625	if (pos + 2 > end)
626		return 0;
627	if (*pos != 0) {
628		wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
629		return 0;
630	}
631	pos++;
632	udhl = *pos++;
633	if (pos + udhl > end) {
634		wpa_printf(MSG_DEBUG, "Invalid UDHL");
635		return 0;
636	}
637	end = pos + udhl;
638
639	while (pos + 2 <= end) {
640		u8 iei, len;
641		const u8 *l_end;
642		iei = *pos++;
643		len = *pos++ & 0x7f;
644		if (pos + len > end)
645			break;
646		l_end = pos + len;
647
648		if (iei == 0 && len > 0) {
649			/* PLMN List */
650			u8 num, i;
651			num = *pos++;
652			for (i = 0; i < num; i++) {
653				if (pos + 3 > end)
654					break;
655				if (os_memcmp(pos, plmn, 3) == 0)
656					return 1; /* Found matching PLMN */
657				pos += 3;
658			}
659		}
660
661		pos = l_end;
662	}
663
664	return 0;
665}
666
667
668static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
669			  size_t mnc_len, char prefix)
670{
671	const char *sep, *msin;
672	char *end, *pos;
673	size_t msin_len, plmn_len;
674
675	/*
676	 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
677	 * Root NAI:
678	 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
679	 * <MNC> is zero-padded to three digits in case two-digit MNC is used
680	 */
681
682	if (imsi == NULL || os_strlen(imsi) > 16) {
683		wpa_printf(MSG_DEBUG, "No valid IMSI available");
684		return -1;
685	}
686	sep = os_strchr(imsi, '-');
687	if (sep) {
688		plmn_len = sep - imsi;
689		msin = sep + 1;
690	} else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
691		plmn_len = 3 + mnc_len;
692		msin = imsi + plmn_len;
693	} else
694		return -1;
695	if (plmn_len != 5 && plmn_len != 6)
696		return -1;
697	msin_len = os_strlen(msin);
698
699	pos = nai;
700	end = nai + nai_len;
701	if (prefix)
702		*pos++ = prefix;
703	os_memcpy(pos, imsi, plmn_len);
704	pos += plmn_len;
705	os_memcpy(pos, msin, msin_len);
706	pos += msin_len;
707	pos += os_snprintf(pos, end - pos, "@wlan.mnc");
708	if (plmn_len == 5) {
709		*pos++ = '0';
710		*pos++ = imsi[3];
711		*pos++ = imsi[4];
712	} else {
713		*pos++ = imsi[3];
714		*pos++ = imsi[4];
715		*pos++ = imsi[5];
716	}
717	pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
718			   imsi[0], imsi[1], imsi[2]);
719
720	return 0;
721}
722
723
724static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
725{
726	char nai[100];
727	if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
728		return -1;
729	return wpa_config_set_quoted(ssid, "identity", nai);
730}
731
732#endif /* INTERWORKING_3GPP */
733
734
735static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
736					struct wpa_ssid *ssid)
737{
738	if (wpa_config_set(ssid, "key_mgmt",
739			   wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
740			   "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
741		return -1;
742	if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
743		return -1;
744	if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
745		return -1;
746	return 0;
747}
748
749
750static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
751				     struct wpa_bss *bss)
752{
753#ifdef INTERWORKING_3GPP
754	struct wpa_cred *cred;
755	struct wpa_ssid *ssid;
756	const u8 *ie;
757	int eap_type;
758	int res;
759	char prefix;
760
761	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
762		return -1;
763
764	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
765		char *sep;
766		const char *imsi;
767		int mnc_len;
768
769#ifdef PCSC_FUNCS
770		if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
771		    wpa_s->imsi[0]) {
772			imsi = wpa_s->imsi;
773			mnc_len = wpa_s->mnc_len;
774			goto compare;
775		}
776#endif /* PCSC_FUNCS */
777
778		if (cred->imsi == NULL || !cred->imsi[0] ||
779		    cred->milenage == NULL || !cred->milenage[0])
780			continue;
781
782		sep = os_strchr(cred->imsi, '-');
783		if (sep == NULL ||
784		    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
785			continue;
786		mnc_len = sep - cred->imsi - 3;
787		imsi = cred->imsi;
788
789#ifdef PCSC_FUNCS
790	compare:
791#endif /* PCSC_FUNCS */
792		if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
793			break;
794	}
795	if (cred == NULL)
796		return -1;
797
798	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
799	if (ie == NULL)
800		return -1;
801	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
802		   MAC2STR(bss->bssid));
803
804	ssid = wpa_config_add_network(wpa_s->conf);
805	if (ssid == NULL)
806		return -1;
807	ssid->parent_cred = cred;
808
809	wpas_notify_network_added(wpa_s, ssid);
810	wpa_config_set_network_defaults(ssid);
811	ssid->priority = cred->priority;
812	ssid->temporary = 1;
813	ssid->ssid = os_zalloc(ie[1] + 1);
814	if (ssid->ssid == NULL)
815		goto fail;
816	os_memcpy(ssid->ssid, ie + 2, ie[1]);
817	ssid->ssid_len = ie[1];
818
819	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
820		goto fail;
821
822	eap_type = EAP_TYPE_SIM;
823	if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
824		eap_type = EAP_TYPE_AKA;
825	if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
826		if (cred->eap_method[0].method == EAP_TYPE_SIM ||
827		    cred->eap_method[0].method == EAP_TYPE_AKA ||
828		    cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
829			eap_type = cred->eap_method[0].method;
830	}
831
832	switch (eap_type) {
833	case EAP_TYPE_SIM:
834		prefix = '1';
835		res = wpa_config_set(ssid, "eap", "SIM", 0);
836		break;
837	case EAP_TYPE_AKA:
838		prefix = '0';
839		res = wpa_config_set(ssid, "eap", "AKA", 0);
840		break;
841	case EAP_TYPE_AKA_PRIME:
842		prefix = '6';
843		res = wpa_config_set(ssid, "eap", "AKA'", 0);
844		break;
845	default:
846		res = -1;
847		break;
848	}
849	if (res < 0) {
850		wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
851			   eap_type);
852		goto fail;
853	}
854
855	if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
856		wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
857		goto fail;
858	}
859
860	if (cred->milenage && cred->milenage[0]) {
861		if (wpa_config_set_quoted(ssid, "password",
862					  cred->milenage) < 0)
863			goto fail;
864	} else if (cred->pcsc) {
865		if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
866			goto fail;
867		if (wpa_s->conf->pcsc_pin &&
868		    wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
869		    < 0)
870			goto fail;
871	}
872
873	if (cred->password && cred->password[0] &&
874	    wpa_config_set_quoted(ssid, "password", cred->password) < 0)
875		goto fail;
876
877	wpa_config_update_prio_list(wpa_s->conf);
878	interworking_reconnect(wpa_s);
879
880	return 0;
881
882fail:
883	wpas_notify_network_removed(wpa_s, ssid);
884	wpa_config_remove_network(wpa_s->conf, ssid->id);
885#endif /* INTERWORKING_3GPP */
886	return -1;
887}
888
889
890static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
891					    size_t rc_len)
892{
893	const u8 *pos, *end;
894	u8 lens;
895
896	if (ie == NULL)
897		return 0;
898
899	pos = ie + 2;
900	end = ie + 2 + ie[1];
901
902	/* Roaming Consortium element:
903	 * Number of ANQP OIs
904	 * OI #1 and #2 lengths
905	 * OI #1, [OI #2], [OI #3]
906	 */
907
908	if (pos + 2 > end)
909		return 0;
910
911	pos++; /* skip Number of ANQP OIs */
912	lens = *pos++;
913	if (pos + (lens & 0x0f) + (lens >> 4) > end)
914		return 0;
915
916	if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
917		return 1;
918	pos += lens & 0x0f;
919
920	if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
921		return 1;
922	pos += lens >> 4;
923
924	if (pos < end && (size_t) (end - pos) == rc_len &&
925	    os_memcmp(pos, rc_id, rc_len) == 0)
926		return 1;
927
928	return 0;
929}
930
931
932static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
933					 const u8 *rc_id, size_t rc_len)
934{
935	const u8 *pos, *end;
936	u8 len;
937
938	if (anqp == NULL)
939		return 0;
940
941	pos = wpabuf_head(anqp);
942	end = pos + wpabuf_len(anqp);
943
944	/* Set of <OI Length, OI> duples */
945	while (pos < end) {
946		len = *pos++;
947		if (pos + len > end)
948			break;
949		if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
950			return 1;
951		pos += len;
952	}
953
954	return 0;
955}
956
957
958static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
959				    const u8 *rc_id, size_t rc_len)
960{
961	return roaming_consortium_element_match(ie, rc_id, rc_len) ||
962		roaming_consortium_anqp_match(anqp, rc_id, rc_len);
963}
964
965
966static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
967{
968	size_t i;
969
970	if (!cred->excluded_ssid)
971		return 0;
972
973	for (i = 0; i < cred->num_excluded_ssid; i++) {
974		struct excluded_ssid *e = &cred->excluded_ssid[i];
975		if (bss->ssid_len == e->ssid_len &&
976		    os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0)
977			return 1;
978	}
979
980	return 0;
981}
982
983
984static struct wpa_cred * interworking_credentials_available_roaming_consortium(
985	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
986{
987	struct wpa_cred *cred, *selected = NULL;
988	const u8 *ie;
989
990	ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
991
992	if (ie == NULL &&
993	    (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
994		return NULL;
995
996	if (wpa_s->conf->cred == NULL)
997		return NULL;
998
999	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1000		if (cred->roaming_consortium_len == 0)
1001			continue;
1002
1003		if (!roaming_consortium_match(ie,
1004					      bss->anqp ?
1005					      bss->anqp->roaming_consortium :
1006					      NULL,
1007					      cred->roaming_consortium,
1008					      cred->roaming_consortium_len))
1009			continue;
1010
1011		if (cred_excluded_ssid(cred, bss))
1012			continue;
1013
1014		if (selected == NULL ||
1015		    selected->priority < cred->priority)
1016			selected = cred;
1017	}
1018
1019	return selected;
1020}
1021
1022
1023static int interworking_set_eap_params(struct wpa_ssid *ssid,
1024				       struct wpa_cred *cred, int ttls)
1025{
1026	if (cred->eap_method) {
1027		ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
1028			cred->eap_method->method == EAP_TYPE_TTLS;
1029
1030		os_free(ssid->eap.eap_methods);
1031		ssid->eap.eap_methods =
1032			os_malloc(sizeof(struct eap_method_type) * 2);
1033		if (ssid->eap.eap_methods == NULL)
1034			return -1;
1035		os_memcpy(ssid->eap.eap_methods, cred->eap_method,
1036			  sizeof(*cred->eap_method));
1037		ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
1038		ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
1039	}
1040
1041	if (ttls && cred->username && cred->username[0]) {
1042		const char *pos;
1043		char *anon;
1044		/* Use anonymous NAI in Phase 1 */
1045		pos = os_strchr(cred->username, '@');
1046		if (pos) {
1047			size_t buflen = 9 + os_strlen(pos) + 1;
1048			anon = os_malloc(buflen);
1049			if (anon == NULL)
1050				return -1;
1051			os_snprintf(anon, buflen, "anonymous%s", pos);
1052		} else if (cred->realm) {
1053			size_t buflen = 10 + os_strlen(cred->realm) + 1;
1054			anon = os_malloc(buflen);
1055			if (anon == NULL)
1056				return -1;
1057			os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
1058		} else {
1059			anon = os_strdup("anonymous");
1060			if (anon == NULL)
1061				return -1;
1062		}
1063		if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
1064		    0) {
1065			os_free(anon);
1066			return -1;
1067		}
1068		os_free(anon);
1069	}
1070
1071	if (cred->username && cred->username[0] &&
1072	    wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
1073		return -1;
1074
1075	if (cred->password && cred->password[0]) {
1076		if (cred->ext_password &&
1077		    wpa_config_set(ssid, "password", cred->password, 0) < 0)
1078			return -1;
1079		if (!cred->ext_password &&
1080		    wpa_config_set_quoted(ssid, "password", cred->password) <
1081		    0)
1082			return -1;
1083	}
1084
1085	if (cred->client_cert && cred->client_cert[0] &&
1086	    wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
1087		return -1;
1088
1089#ifdef ANDROID
1090	if (cred->private_key &&
1091	    os_strncmp(cred->private_key, "keystore://", 11) == 0) {
1092		/* Use OpenSSL engine configuration for Android keystore */
1093		if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
1094		    wpa_config_set_quoted(ssid, "key_id",
1095					  cred->private_key + 11) < 0 ||
1096		    wpa_config_set(ssid, "engine", "1", 0) < 0)
1097			return -1;
1098	} else
1099#endif /* ANDROID */
1100	if (cred->private_key && cred->private_key[0] &&
1101	    wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
1102		return -1;
1103
1104	if (cred->private_key_passwd && cred->private_key_passwd[0] &&
1105	    wpa_config_set_quoted(ssid, "private_key_passwd",
1106				  cred->private_key_passwd) < 0)
1107		return -1;
1108
1109	if (cred->phase1) {
1110		os_free(ssid->eap.phase1);
1111		ssid->eap.phase1 = os_strdup(cred->phase1);
1112	}
1113	if (cred->phase2) {
1114		os_free(ssid->eap.phase2);
1115		ssid->eap.phase2 = os_strdup(cred->phase2);
1116	}
1117
1118	if (cred->ca_cert && cred->ca_cert[0] &&
1119	    wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
1120		return -1;
1121
1122	return 0;
1123}
1124
1125
1126static int interworking_connect_roaming_consortium(
1127	struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
1128	struct wpa_bss *bss, const u8 *ssid_ie)
1129{
1130	struct wpa_ssid *ssid;
1131
1132	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
1133		   "roaming consortium match", MAC2STR(bss->bssid));
1134
1135	ssid = wpa_config_add_network(wpa_s->conf);
1136	if (ssid == NULL)
1137		return -1;
1138	ssid->parent_cred = cred;
1139	wpas_notify_network_added(wpa_s, ssid);
1140	wpa_config_set_network_defaults(ssid);
1141	ssid->priority = cred->priority;
1142	ssid->temporary = 1;
1143	ssid->ssid = os_zalloc(ssid_ie[1] + 1);
1144	if (ssid->ssid == NULL)
1145		goto fail;
1146	os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
1147	ssid->ssid_len = ssid_ie[1];
1148
1149	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
1150		goto fail;
1151
1152	if (cred->eap_method == NULL) {
1153		wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
1154			   "credential using roaming consortium");
1155		goto fail;
1156	}
1157
1158	if (interworking_set_eap_params(
1159		    ssid, cred,
1160		    cred->eap_method->vendor == EAP_VENDOR_IETF &&
1161		    cred->eap_method->method == EAP_TYPE_TTLS) < 0)
1162		goto fail;
1163
1164	wpa_config_update_prio_list(wpa_s->conf);
1165	interworking_reconnect(wpa_s);
1166
1167	return 0;
1168
1169fail:
1170	wpas_notify_network_removed(wpa_s, ssid);
1171	wpa_config_remove_network(wpa_s->conf, ssid->id);
1172	return -1;
1173}
1174
1175
1176int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1177{
1178	struct wpa_cred *cred;
1179	struct wpa_ssid *ssid;
1180	struct nai_realm *realm;
1181	struct nai_realm_eap *eap = NULL;
1182	u16 count, i;
1183	char buf[100];
1184	const u8 *ie;
1185
1186	if (wpa_s->conf->cred == NULL || bss == NULL)
1187		return -1;
1188	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
1189	if (ie == NULL || ie[1] == 0) {
1190		wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
1191			   MACSTR, MAC2STR(bss->bssid));
1192		return -1;
1193	}
1194
1195	if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
1196		/*
1197		 * We currently support only HS 2.0 networks and those are
1198		 * required to use WPA2-Enterprise.
1199		 */
1200		wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
1201			   "RSN");
1202		return -1;
1203	}
1204
1205	cred = interworking_credentials_available_roaming_consortium(wpa_s,
1206								     bss);
1207	if (cred)
1208		return interworking_connect_roaming_consortium(wpa_s, cred,
1209							       bss, ie);
1210
1211	realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
1212				&count);
1213	if (realm == NULL) {
1214		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
1215			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
1216		count = 0;
1217	}
1218
1219	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1220		for (i = 0; i < count; i++) {
1221			if (!nai_realm_match(&realm[i], cred->realm))
1222				continue;
1223			eap = nai_realm_find_eap(cred, &realm[i]);
1224			if (eap)
1225				break;
1226		}
1227		if (eap)
1228			break;
1229	}
1230
1231	if (!eap) {
1232		if (interworking_connect_3gpp(wpa_s, bss) == 0) {
1233			if (realm)
1234				nai_realm_free(realm, count);
1235			return 0;
1236		}
1237
1238		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
1239			   "and EAP method found for " MACSTR,
1240			   MAC2STR(bss->bssid));
1241		nai_realm_free(realm, count);
1242		return -1;
1243	}
1244
1245	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
1246		   MAC2STR(bss->bssid));
1247
1248	ssid = wpa_config_add_network(wpa_s->conf);
1249	if (ssid == NULL) {
1250		nai_realm_free(realm, count);
1251		return -1;
1252	}
1253	ssid->parent_cred = cred;
1254	wpas_notify_network_added(wpa_s, ssid);
1255	wpa_config_set_network_defaults(ssid);
1256	ssid->priority = cred->priority;
1257	ssid->temporary = 1;
1258	ssid->ssid = os_zalloc(ie[1] + 1);
1259	if (ssid->ssid == NULL)
1260		goto fail;
1261	os_memcpy(ssid->ssid, ie + 2, ie[1]);
1262	ssid->ssid_len = ie[1];
1263
1264	if (interworking_set_hs20_params(wpa_s, ssid) < 0)
1265		goto fail;
1266
1267	if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
1268						     eap->method), 0) < 0)
1269		goto fail;
1270
1271	switch (eap->method) {
1272	case EAP_TYPE_TTLS:
1273		if (eap->inner_method) {
1274			os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
1275				    eap_get_name(EAP_VENDOR_IETF,
1276						 eap->inner_method));
1277			if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
1278				goto fail;
1279			break;
1280		}
1281		switch (eap->inner_non_eap) {
1282		case NAI_REALM_INNER_NON_EAP_PAP:
1283			if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
1284			    0)
1285				goto fail;
1286			break;
1287		case NAI_REALM_INNER_NON_EAP_CHAP:
1288			if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
1289			    < 0)
1290				goto fail;
1291			break;
1292		case NAI_REALM_INNER_NON_EAP_MSCHAP:
1293			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
1294					   0) < 0)
1295				goto fail;
1296			break;
1297		case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
1298			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
1299					   0) < 0)
1300				goto fail;
1301			break;
1302		default:
1303			/* EAP params were not set - assume TTLS/MSCHAPv2 */
1304			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
1305					   0) < 0)
1306				goto fail;
1307			break;
1308		}
1309		break;
1310	case EAP_TYPE_PEAP:
1311		os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
1312			    eap_get_name(EAP_VENDOR_IETF,
1313					 eap->inner_method ?
1314					 eap->inner_method :
1315					 EAP_TYPE_MSCHAPV2));
1316		if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
1317			goto fail;
1318		break;
1319	case EAP_TYPE_TLS:
1320		break;
1321	}
1322
1323	if (interworking_set_eap_params(ssid, cred,
1324					eap->method == EAP_TYPE_TTLS) < 0)
1325		goto fail;
1326
1327	nai_realm_free(realm, count);
1328
1329	wpa_config_update_prio_list(wpa_s->conf);
1330	interworking_reconnect(wpa_s);
1331
1332	return 0;
1333
1334fail:
1335	wpas_notify_network_removed(wpa_s, ssid);
1336	wpa_config_remove_network(wpa_s->conf, ssid->id);
1337	nai_realm_free(realm, count);
1338	return -1;
1339}
1340
1341
1342static struct wpa_cred * interworking_credentials_available_3gpp(
1343	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1344{
1345	struct wpa_cred *cred, *selected = NULL;
1346	int ret;
1347
1348#ifdef INTERWORKING_3GPP
1349	if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
1350		return NULL;
1351
1352	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1353		char *sep;
1354		const char *imsi;
1355		int mnc_len;
1356
1357#ifdef PCSC_FUNCS
1358		if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
1359		    wpa_s->imsi[0]) {
1360			imsi = wpa_s->imsi;
1361			mnc_len = wpa_s->mnc_len;
1362			goto compare;
1363		}
1364#endif /* PCSC_FUNCS */
1365
1366		if (cred->imsi == NULL || !cred->imsi[0] ||
1367		    cred->milenage == NULL || !cred->milenage[0])
1368			continue;
1369
1370		sep = os_strchr(cred->imsi, '-');
1371		if (sep == NULL ||
1372		    (sep - cred->imsi != 5 && sep - cred->imsi != 6))
1373			continue;
1374		mnc_len = sep - cred->imsi - 3;
1375		imsi = cred->imsi;
1376
1377#ifdef PCSC_FUNCS
1378	compare:
1379#endif /* PCSC_FUNCS */
1380		wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
1381			   MACSTR, MAC2STR(bss->bssid));
1382		ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
1383		wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
1384		if (ret) {
1385			if (cred_excluded_ssid(cred, bss))
1386				continue;
1387			if (selected == NULL ||
1388			    selected->priority < cred->priority)
1389				selected = cred;
1390		}
1391	}
1392#endif /* INTERWORKING_3GPP */
1393	return selected;
1394}
1395
1396
1397static struct wpa_cred * interworking_credentials_available_realm(
1398	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1399{
1400	struct wpa_cred *cred, *selected = NULL;
1401	struct nai_realm *realm;
1402	u16 count, i;
1403
1404	if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
1405		return NULL;
1406
1407	if (wpa_s->conf->cred == NULL)
1408		return NULL;
1409
1410	wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
1411		   MACSTR, MAC2STR(bss->bssid));
1412	realm = nai_realm_parse(bss->anqp->nai_realm, &count);
1413	if (realm == NULL) {
1414		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
1415			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
1416		return NULL;
1417	}
1418
1419	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1420		if (cred->realm == NULL)
1421			continue;
1422
1423		for (i = 0; i < count; i++) {
1424			if (!nai_realm_match(&realm[i], cred->realm))
1425				continue;
1426			if (nai_realm_find_eap(cred, &realm[i])) {
1427				if (cred_excluded_ssid(cred, bss))
1428					continue;
1429				if (selected == NULL ||
1430				    selected->priority < cred->priority)
1431					selected = cred;
1432				break;
1433			}
1434		}
1435	}
1436
1437	nai_realm_free(realm, count);
1438
1439	return selected;
1440}
1441
1442
1443static struct wpa_cred * interworking_credentials_available(
1444	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1445{
1446	struct wpa_cred *cred, *cred2;
1447
1448	cred = interworking_credentials_available_realm(wpa_s, bss);
1449	cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
1450	if (cred && cred2 && cred2->priority >= cred->priority)
1451		cred = cred2;
1452	if (!cred)
1453		cred = cred2;
1454
1455	cred2 = interworking_credentials_available_roaming_consortium(wpa_s,
1456								      bss);
1457	if (cred && cred2 && cred2->priority >= cred->priority)
1458		cred = cred2;
1459	if (!cred)
1460		cred = cred2;
1461
1462	return cred;
1463}
1464
1465
1466static int domain_name_list_contains(struct wpabuf *domain_names,
1467				     const char *domain)
1468{
1469	const u8 *pos, *end;
1470	size_t len;
1471
1472	len = os_strlen(domain);
1473	pos = wpabuf_head(domain_names);
1474	end = pos + wpabuf_len(domain_names);
1475
1476	while (pos + 1 < end) {
1477		if (pos + 1 + pos[0] > end)
1478			break;
1479
1480		wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
1481				  pos + 1, pos[0]);
1482		if (pos[0] == len &&
1483		    os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
1484			return 1;
1485
1486		pos += 1 + pos[0];
1487	}
1488
1489	return 0;
1490}
1491
1492
1493int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
1494			      struct wpa_cred *cred,
1495			      struct wpabuf *domain_names)
1496{
1497#ifdef INTERWORKING_3GPP
1498	char nai[100], *realm;
1499
1500	char *imsi = NULL;
1501	int mnc_len = 0;
1502	if (cred->imsi)
1503		imsi = cred->imsi;
1504#ifdef CONFIG_PCSC
1505	else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
1506		 wpa_s->scard && wpa_s->imsi[0]) {
1507		imsi = wpa_s->imsi;
1508		mnc_len = wpa_s->mnc_len;
1509	}
1510#endif /* CONFIG_PCSC */
1511	if (domain_names &&
1512	    imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
1513		realm = os_strchr(nai, '@');
1514		if (realm)
1515			realm++;
1516		wpa_printf(MSG_DEBUG, "Interworking: Search for match "
1517			   "with SIM/USIM domain %s", realm);
1518		if (realm &&
1519		    domain_name_list_contains(domain_names, realm))
1520			return 1;
1521	}
1522#endif /* INTERWORKING_3GPP */
1523
1524	if (domain_names == NULL || cred->domain == NULL)
1525		return 0;
1526
1527	wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
1528		   "home SP FQDN %s", cred->domain);
1529	if (domain_name_list_contains(domain_names, cred->domain))
1530		return 1;
1531
1532	return 0;
1533}
1534
1535
1536static int interworking_home_sp(struct wpa_supplicant *wpa_s,
1537				struct wpabuf *domain_names)
1538{
1539	struct wpa_cred *cred;
1540
1541	if (domain_names == NULL || wpa_s->conf->cred == NULL)
1542		return -1;
1543
1544	for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1545		int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
1546		if (res)
1547			return res;
1548	}
1549
1550	return 0;
1551}
1552
1553
1554static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
1555{
1556	struct wpa_bss *bss;
1557	struct wpa_ssid *ssid;
1558
1559	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1560		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1561			if (wpas_network_disabled(wpa_s, ssid) ||
1562			    ssid->mode != WPAS_MODE_INFRA)
1563				continue;
1564			if (ssid->ssid_len != bss->ssid_len ||
1565			    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
1566			    0)
1567				continue;
1568			/*
1569			 * TODO: Consider more accurate matching of security
1570			 * configuration similarly to what is done in events.c
1571			 */
1572			return 1;
1573		}
1574	}
1575
1576	return 0;
1577}
1578
1579
1580static void interworking_select_network(struct wpa_supplicant *wpa_s)
1581{
1582	struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
1583	int selected_prio = -999999, selected_home_prio = -999999;
1584	unsigned int count = 0;
1585	const char *type;
1586	int res;
1587	struct wpa_cred *cred;
1588
1589	wpa_s->network_select = 0;
1590
1591	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1592		cred = interworking_credentials_available(wpa_s, bss);
1593		if (!cred)
1594			continue;
1595		if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
1596			/*
1597			 * We currently support only HS 2.0 networks and those
1598			 * are required to use WPA2-Enterprise.
1599			 */
1600			wpa_printf(MSG_DEBUG, "Interworking: Credential match "
1601				   "with " MACSTR " but network does not use "
1602				   "RSN", MAC2STR(bss->bssid));
1603			continue;
1604		}
1605		count++;
1606		res = interworking_home_sp(wpa_s, bss->anqp ?
1607					   bss->anqp->domain_name : NULL);
1608		if (res > 0)
1609			type = "home";
1610		else if (res == 0)
1611			type = "roaming";
1612		else
1613			type = "unknown";
1614		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
1615			MAC2STR(bss->bssid), type);
1616		if (wpa_s->auto_select ||
1617		    (wpa_s->conf->auto_interworking &&
1618		     wpa_s->auto_network_select)) {
1619			if (selected == NULL ||
1620			    cred->priority > selected_prio) {
1621				selected = bss;
1622				selected_prio = cred->priority;
1623			}
1624			if (res > 0 &&
1625			    (selected_home == NULL ||
1626			     cred->priority > selected_home_prio)) {
1627				selected_home = bss;
1628				selected_home_prio = cred->priority;
1629			}
1630		}
1631	}
1632
1633	if (selected_home && selected_home != selected &&
1634	    selected_home_prio >= selected_prio) {
1635		/* Prefer network operated by the Home SP */
1636		selected = selected_home;
1637	}
1638
1639	if (count == 0) {
1640		/*
1641		 * No matching network was found based on configured
1642		 * credentials. Check whether any of the enabled network blocks
1643		 * have matching APs.
1644		 */
1645		if (interworking_find_network_match(wpa_s)) {
1646			wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
1647				   "match for enabled network configurations");
1648			if (wpa_s->auto_select)
1649				interworking_reconnect(wpa_s);
1650			return;
1651		}
1652
1653		if (wpa_s->auto_network_select) {
1654			wpa_printf(MSG_DEBUG, "Interworking: Continue "
1655				   "scanning after ANQP fetch");
1656			wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
1657						0);
1658			return;
1659		}
1660
1661		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
1662			"with matching credentials found");
1663	}
1664
1665	if (selected)
1666		interworking_connect(wpa_s, selected);
1667}
1668
1669
1670static struct wpa_bss_anqp *
1671interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1672{
1673	struct wpa_bss *other;
1674
1675	if (is_zero_ether_addr(bss->hessid))
1676		return NULL; /* Cannot be in the same homegenous ESS */
1677
1678	dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
1679		if (other == bss)
1680			continue;
1681		if (other->anqp == NULL)
1682			continue;
1683		if (other->anqp->roaming_consortium == NULL &&
1684		    other->anqp->nai_realm == NULL &&
1685		    other->anqp->anqp_3gpp == NULL &&
1686		    other->anqp->domain_name == NULL)
1687			continue;
1688		if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
1689			continue;
1690		if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
1691			continue;
1692		if (bss->ssid_len != other->ssid_len ||
1693		    os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
1694			continue;
1695
1696		wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
1697			   "already fetched BSSID " MACSTR " and " MACSTR,
1698			   MAC2STR(other->bssid), MAC2STR(bss->bssid));
1699		other->anqp->users++;
1700		return other->anqp;
1701	}
1702
1703	return NULL;
1704}
1705
1706
1707static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
1708{
1709	struct wpa_bss *bss;
1710	int found = 0;
1711	const u8 *ie;
1712
1713	if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
1714		return;
1715
1716	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1717		if (!(bss->caps & IEEE80211_CAP_ESS))
1718			continue;
1719		ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
1720		if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
1721			continue; /* AP does not support Interworking */
1722
1723		if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
1724			if (bss->anqp == NULL) {
1725				bss->anqp = interworking_match_anqp_info(wpa_s,
1726									 bss);
1727				if (bss->anqp) {
1728					/* Shared data already fetched */
1729					continue;
1730				}
1731				bss->anqp = wpa_bss_anqp_alloc();
1732				if (bss->anqp == NULL)
1733					break;
1734			}
1735			found++;
1736			bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
1737			wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
1738				MACSTR, MAC2STR(bss->bssid));
1739			interworking_anqp_send_req(wpa_s, bss);
1740			break;
1741		}
1742	}
1743
1744	if (found == 0) {
1745		wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
1746		wpa_s->fetch_anqp_in_progress = 0;
1747		if (wpa_s->network_select)
1748			interworking_select_network(wpa_s);
1749	}
1750}
1751
1752
1753void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
1754{
1755	struct wpa_bss *bss;
1756
1757	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
1758		bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
1759
1760	wpa_s->fetch_anqp_in_progress = 1;
1761	interworking_next_anqp_fetch(wpa_s);
1762}
1763
1764
1765int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
1766{
1767	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
1768		return 0;
1769
1770	wpa_s->network_select = 0;
1771	wpa_s->fetch_all_anqp = 1;
1772
1773	interworking_start_fetch_anqp(wpa_s);
1774
1775	return 0;
1776}
1777
1778
1779void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
1780{
1781	if (!wpa_s->fetch_anqp_in_progress)
1782		return;
1783
1784	wpa_s->fetch_anqp_in_progress = 0;
1785}
1786
1787
1788int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
1789		  u16 info_ids[], size_t num_ids)
1790{
1791	struct wpabuf *buf;
1792	int ret = 0;
1793	int freq;
1794	struct wpa_bss *bss;
1795	int res;
1796
1797	freq = wpa_s->assoc_freq;
1798	bss = wpa_bss_get_bssid(wpa_s, dst);
1799	if (bss) {
1800		wpa_bss_anqp_unshare_alloc(bss);
1801		freq = bss->freq;
1802	}
1803	if (freq <= 0)
1804		return -1;
1805
1806	wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
1807		   MAC2STR(dst), (unsigned int) num_ids);
1808
1809	buf = anqp_build_req(info_ids, num_ids, NULL);
1810	if (buf == NULL)
1811		return -1;
1812
1813	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
1814	if (res < 0) {
1815		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
1816		ret = -1;
1817	} else
1818		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
1819			   "%u", res);
1820
1821	wpabuf_free(buf);
1822	return ret;
1823}
1824
1825
1826static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
1827					    const u8 *sa, u16 info_id,
1828					    const u8 *data, size_t slen)
1829{
1830	const u8 *pos = data;
1831	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
1832	struct wpa_bss_anqp *anqp = NULL;
1833#ifdef CONFIG_HS20
1834	u8 type;
1835#endif /* CONFIG_HS20 */
1836
1837	if (bss)
1838		anqp = bss->anqp;
1839
1840	switch (info_id) {
1841	case ANQP_CAPABILITY_LIST:
1842		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1843			" ANQP Capability list", MAC2STR(sa));
1844		break;
1845	case ANQP_VENUE_NAME:
1846		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1847			" Venue Name", MAC2STR(sa));
1848		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
1849		if (anqp) {
1850			wpabuf_free(anqp->venue_name);
1851			anqp->venue_name = wpabuf_alloc_copy(pos, slen);
1852		}
1853		break;
1854	case ANQP_NETWORK_AUTH_TYPE:
1855		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1856			" Network Authentication Type information",
1857			MAC2STR(sa));
1858		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
1859				  "Type", pos, slen);
1860		if (anqp) {
1861			wpabuf_free(anqp->network_auth_type);
1862			anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
1863		}
1864		break;
1865	case ANQP_ROAMING_CONSORTIUM:
1866		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1867			" Roaming Consortium list", MAC2STR(sa));
1868		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
1869				  pos, slen);
1870		if (anqp) {
1871			wpabuf_free(anqp->roaming_consortium);
1872			anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
1873		}
1874		break;
1875	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
1876		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1877			" IP Address Type Availability information",
1878			MAC2STR(sa));
1879		wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
1880			    pos, slen);
1881		if (anqp) {
1882			wpabuf_free(anqp->ip_addr_type_availability);
1883			anqp->ip_addr_type_availability =
1884				wpabuf_alloc_copy(pos, slen);
1885		}
1886		break;
1887	case ANQP_NAI_REALM:
1888		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1889			" NAI Realm list", MAC2STR(sa));
1890		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
1891		if (anqp) {
1892			wpabuf_free(anqp->nai_realm);
1893			anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
1894		}
1895		break;
1896	case ANQP_3GPP_CELLULAR_NETWORK:
1897		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1898			" 3GPP Cellular Network information", MAC2STR(sa));
1899		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
1900				  pos, slen);
1901		if (anqp) {
1902			wpabuf_free(anqp->anqp_3gpp);
1903			anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
1904		}
1905		break;
1906	case ANQP_DOMAIN_NAME:
1907		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
1908			" Domain Name list", MAC2STR(sa));
1909		wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
1910		if (anqp) {
1911			wpabuf_free(anqp->domain_name);
1912			anqp->domain_name = wpabuf_alloc_copy(pos, slen);
1913		}
1914		break;
1915	case ANQP_VENDOR_SPECIFIC:
1916		if (slen < 3)
1917			return;
1918
1919		switch (WPA_GET_BE24(pos)) {
1920#ifdef CONFIG_HS20
1921		case OUI_WFA:
1922			pos += 3;
1923			slen -= 3;
1924
1925			if (slen < 1)
1926				return;
1927			type = *pos++;
1928			slen--;
1929
1930			switch (type) {
1931			case HS20_ANQP_OUI_TYPE:
1932				hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
1933							     slen);
1934				break;
1935			default:
1936				wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
1937					   "vendor type %u", type);
1938				break;
1939			}
1940			break;
1941#endif /* CONFIG_HS20 */
1942		default:
1943			wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
1944				   "vendor-specific ANQP OUI %06x",
1945				   WPA_GET_BE24(pos));
1946			return;
1947		}
1948		break;
1949	default:
1950		wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
1951			   "%u", info_id);
1952		break;
1953	}
1954}
1955
1956
1957void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
1958		  enum gas_query_result result,
1959		  const struct wpabuf *adv_proto,
1960		  const struct wpabuf *resp, u16 status_code)
1961{
1962	struct wpa_supplicant *wpa_s = ctx;
1963	const u8 *pos;
1964	const u8 *end;
1965	u16 info_id;
1966	u16 slen;
1967
1968	if (result != GAS_QUERY_SUCCESS)
1969		return;
1970
1971	pos = wpabuf_head(adv_proto);
1972	if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
1973	    pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
1974		wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
1975			   "Protocol in response");
1976		return;
1977	}
1978
1979	pos = wpabuf_head(resp);
1980	end = pos + wpabuf_len(resp);
1981
1982	while (pos < end) {
1983		if (pos + 4 > end) {
1984			wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
1985			break;
1986		}
1987		info_id = WPA_GET_LE16(pos);
1988		pos += 2;
1989		slen = WPA_GET_LE16(pos);
1990		pos += 2;
1991		if (pos + slen > end) {
1992			wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
1993				   "for Info ID %u", info_id);
1994			break;
1995		}
1996		interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
1997						slen);
1998		pos += slen;
1999	}
2000}
2001
2002
2003static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
2004					  struct wpa_scan_results *scan_res)
2005{
2006	wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
2007		   "ANQP fetch");
2008	interworking_start_fetch_anqp(wpa_s);
2009}
2010
2011
2012int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
2013{
2014	interworking_stop_fetch_anqp(wpa_s);
2015	wpa_s->network_select = 1;
2016	wpa_s->auto_network_select = 0;
2017	wpa_s->auto_select = !!auto_select;
2018	wpa_s->fetch_all_anqp = 0;
2019	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
2020		   "selection");
2021	wpa_s->scan_res_handler = interworking_scan_res_handler;
2022	wpa_s->scan_req = MANUAL_SCAN_REQ;
2023	wpa_supplicant_req_scan(wpa_s, 0, 0);
2024
2025	return 0;
2026}
2027
2028
2029static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
2030			enum gas_query_result result,
2031			const struct wpabuf *adv_proto,
2032			const struct wpabuf *resp, u16 status_code)
2033{
2034	struct wpa_supplicant *wpa_s = ctx;
2035
2036	wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
2037		" dialog_token=%d status_code=%d resp_len=%d",
2038		MAC2STR(addr), dialog_token, status_code,
2039		resp ? (int) wpabuf_len(resp) : -1);
2040	if (!resp)
2041		return;
2042
2043	wpabuf_free(wpa_s->last_gas_resp);
2044	wpa_s->last_gas_resp = wpabuf_dup(resp);
2045	if (wpa_s->last_gas_resp == NULL)
2046		return;
2047	os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
2048	wpa_s->last_gas_dialog_token = dialog_token;
2049}
2050
2051
2052int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
2053		     const struct wpabuf *adv_proto,
2054		     const struct wpabuf *query)
2055{
2056	struct wpabuf *buf;
2057	int ret = 0;
2058	int freq;
2059	struct wpa_bss *bss;
2060	int res;
2061	size_t len;
2062	u8 query_resp_len_limit = 0, pame_bi = 0;
2063
2064	freq = wpa_s->assoc_freq;
2065	bss = wpa_bss_get_bssid(wpa_s, dst);
2066	if (bss)
2067		freq = bss->freq;
2068	if (freq <= 0)
2069		return -1;
2070
2071	wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
2072		   MAC2STR(dst), freq);
2073	wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
2074	wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
2075
2076	len = 3 + wpabuf_len(adv_proto) + 2;
2077	if (query)
2078		len += wpabuf_len(query);
2079	buf = gas_build_initial_req(0, len);
2080	if (buf == NULL)
2081		return -1;
2082
2083	/* Advertisement Protocol IE */
2084	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
2085	wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
2086	wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
2087		      (pame_bi ? 0x80 : 0));
2088	wpabuf_put_buf(buf, adv_proto);
2089
2090	/* GAS Query */
2091	if (query) {
2092		wpabuf_put_le16(buf, wpabuf_len(query));
2093		wpabuf_put_buf(buf, query);
2094	} else
2095		wpabuf_put_le16(buf, 0);
2096
2097	res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
2098	if (res < 0) {
2099		wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
2100		ret = -1;
2101	} else
2102		wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
2103			   "%u", res);
2104
2105	wpabuf_free(buf);
2106	return ret;
2107}
2108