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