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