]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa/wpa_supplicant/interworking.c
amd64: allow gdb(4) to write to most registers
[FreeBSD/FreeBSD.git] / contrib / wpa / wpa_supplicant / interworking.c
1 /*
2  * Interworking (IEEE 802.11u)
3  * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
4  * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
5  *
6  * This software may be distributed under the terms of the BSD license.
7  * See README for more details.
8  */
9
10 #include "includes.h"
11
12 #include "common.h"
13 #include "common/ieee802_11_defs.h"
14 #include "common/gas.h"
15 #include "common/wpa_ctrl.h"
16 #include "utils/pcsc_funcs.h"
17 #include "utils/eloop.h"
18 #include "drivers/driver.h"
19 #include "eap_common/eap_defs.h"
20 #include "eap_peer/eap.h"
21 #include "eap_peer/eap_methods.h"
22 #include "eapol_supp/eapol_supp_sm.h"
23 #include "rsn_supp/wpa.h"
24 #include "wpa_supplicant_i.h"
25 #include "config.h"
26 #include "config_ssid.h"
27 #include "bss.h"
28 #include "scan.h"
29 #include "notify.h"
30 #include "driver_i.h"
31 #include "gas_query.h"
32 #include "hs20_supplicant.h"
33 #include "interworking.h"
34
35
36 #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
37 #define INTERWORKING_3GPP
38 #else
39 #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
40 #define INTERWORKING_3GPP
41 #else
42 #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
43 #define INTERWORKING_3GPP
44 #endif
45 #endif
46 #endif
47
48 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
49 static struct wpa_cred * interworking_credentials_available_realm(
50         struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
51         int *excluded);
52 static struct wpa_cred * interworking_credentials_available_3gpp(
53         struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
54         int *excluded);
55
56
57 static int cred_prio_cmp(const struct wpa_cred *a, const struct wpa_cred *b)
58 {
59         if (a->priority > b->priority)
60                 return 1;
61         if (a->priority < b->priority)
62                 return -1;
63         if (a->provisioning_sp == NULL || b->provisioning_sp == NULL ||
64             os_strcmp(a->provisioning_sp, b->provisioning_sp) != 0)
65                 return 0;
66         if (a->sp_priority < b->sp_priority)
67                 return 1;
68         if (a->sp_priority > b->sp_priority)
69                 return -1;
70         return 0;
71 }
72
73
74 static void interworking_reconnect(struct wpa_supplicant *wpa_s)
75 {
76         unsigned int tried;
77
78         if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
79                 wpa_supplicant_cancel_sched_scan(wpa_s);
80                 wpa_s->own_disconnect_req = 1;
81                 wpa_supplicant_deauthenticate(wpa_s,
82                                               WLAN_REASON_DEAUTH_LEAVING);
83         }
84         wpa_s->disconnected = 0;
85         wpa_s->reassociate = 1;
86         tried = wpa_s->interworking_fast_assoc_tried;
87         wpa_s->interworking_fast_assoc_tried = 1;
88
89         if (!tried && wpa_supplicant_fast_associate(wpa_s) >= 0)
90                 return;
91
92         wpa_s->interworking_fast_assoc_tried = 0;
93         wpa_supplicant_req_scan(wpa_s, 0, 0);
94 }
95
96
97 static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
98                                       struct wpabuf *extra)
99 {
100         struct wpabuf *buf;
101         size_t i;
102         u8 *len_pos;
103
104         buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
105                                          (extra ? wpabuf_len(extra) : 0));
106         if (buf == NULL)
107                 return NULL;
108
109         if (num_ids > 0) {
110                 len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
111                 for (i = 0; i < num_ids; i++)
112                         wpabuf_put_le16(buf, info_ids[i]);
113                 gas_anqp_set_element_len(buf, len_pos);
114         }
115         if (extra)
116                 wpabuf_put_buf(buf, extra);
117
118         gas_anqp_set_len(buf);
119
120         return buf;
121 }
122
123
124 static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
125                                       u8 dialog_token,
126                                       enum gas_query_result result,
127                                       const struct wpabuf *adv_proto,
128                                       const struct wpabuf *resp,
129                                       u16 status_code)
130 {
131         struct wpa_supplicant *wpa_s = ctx;
132
133         wpa_printf(MSG_DEBUG, "ANQP: Response callback dst=" MACSTR
134                    " dialog_token=%u result=%d status_code=%u",
135                    MAC2STR(dst), dialog_token, result, status_code);
136         anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
137                      status_code);
138         interworking_next_anqp_fetch(wpa_s);
139 }
140
141
142 static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
143 {
144         struct wpa_cred *cred;
145
146         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
147                 if (cred->roaming_consortium_len)
148                         return 1;
149                 if (cred->required_roaming_consortium_len)
150                         return 1;
151                 if (cred->num_roaming_consortiums)
152                         return 1;
153         }
154         return 0;
155 }
156
157
158 static int cred_with_3gpp(struct wpa_supplicant *wpa_s)
159 {
160         struct wpa_cred *cred;
161
162         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
163                 if (cred->pcsc || cred->imsi)
164                         return 1;
165         }
166         return 0;
167 }
168
169
170 static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
171 {
172         struct wpa_cred *cred;
173
174         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
175                 if (cred->pcsc || cred->imsi)
176                         continue;
177                 if (!cred->eap_method)
178                         return 1;
179                 if (cred->realm && cred->roaming_consortium_len == 0)
180                         return 1;
181         }
182         return 0;
183 }
184
185
186 static int cred_with_domain(struct wpa_supplicant *wpa_s)
187 {
188         struct wpa_cred *cred;
189
190         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
191                 if (cred->domain || cred->pcsc || cred->imsi ||
192                     cred->roaming_partner)
193                         return 1;
194         }
195         return 0;
196 }
197
198
199 #ifdef CONFIG_HS20
200
201 static int cred_with_min_backhaul(struct wpa_supplicant *wpa_s)
202 {
203         struct wpa_cred *cred;
204
205         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
206                 if (cred->min_dl_bandwidth_home ||
207                     cred->min_ul_bandwidth_home ||
208                     cred->min_dl_bandwidth_roaming ||
209                     cred->min_ul_bandwidth_roaming)
210                         return 1;
211         }
212         return 0;
213 }
214
215
216 static int cred_with_conn_capab(struct wpa_supplicant *wpa_s)
217 {
218         struct wpa_cred *cred;
219
220         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
221                 if (cred->num_req_conn_capab)
222                         return 1;
223         }
224         return 0;
225 }
226
227 #endif /* CONFIG_HS20 */
228
229
230 static int additional_roaming_consortiums(struct wpa_bss *bss)
231 {
232         const u8 *ie;
233         ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
234         if (ie == NULL || ie[1] == 0)
235                 return 0;
236         return ie[2]; /* Number of ANQP OIs */
237 }
238
239
240 static void interworking_continue_anqp(void *eloop_ctx, void *sock_ctx)
241 {
242         struct wpa_supplicant *wpa_s = eloop_ctx;
243         interworking_next_anqp_fetch(wpa_s);
244 }
245
246
247 static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
248                                       struct wpa_bss *bss)
249 {
250         struct wpabuf *buf;
251         int ret = 0;
252         int res;
253         u16 info_ids[8];
254         size_t num_info_ids = 0;
255         struct wpabuf *extra = NULL;
256         int all = wpa_s->fetch_all_anqp;
257
258         wpa_msg(wpa_s, MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
259                 MAC2STR(bss->bssid));
260         wpa_s->interworking_gas_bss = bss;
261
262         info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
263         if (all) {
264                 info_ids[num_info_ids++] = ANQP_VENUE_NAME;
265                 info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
266         }
267         if (all || (cred_with_roaming_consortium(wpa_s) &&
268                     additional_roaming_consortiums(bss)))
269                 info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
270         if (all)
271                 info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
272         if (all || cred_with_nai_realm(wpa_s))
273                 info_ids[num_info_ids++] = ANQP_NAI_REALM;
274         if (all || cred_with_3gpp(wpa_s)) {
275                 info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
276                 wpa_supplicant_scard_init(wpa_s, NULL);
277         }
278         if (all || cred_with_domain(wpa_s))
279                 info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
280         wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
281                     (u8 *) info_ids, num_info_ids * 2);
282
283 #ifdef CONFIG_HS20
284         if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
285                 u8 *len_pos;
286
287                 extra = wpabuf_alloc(100);
288                 if (!extra)
289                         return -1;
290
291                 len_pos = gas_anqp_add_element(extra, ANQP_VENDOR_SPECIFIC);
292                 wpabuf_put_be24(extra, OUI_WFA);
293                 wpabuf_put_u8(extra, HS20_ANQP_OUI_TYPE);
294                 wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
295                 wpabuf_put_u8(extra, 0); /* Reserved */
296                 wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
297                 if (all)
298                         wpabuf_put_u8(extra,
299                                       HS20_STYPE_OPERATOR_FRIENDLY_NAME);
300                 if (all || cred_with_min_backhaul(wpa_s))
301                         wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
302                 if (all || cred_with_conn_capab(wpa_s))
303                         wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
304                 if (all)
305                         wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
306                 if (all) {
307                         wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_LIST);
308                         wpabuf_put_u8(extra, HS20_STYPE_OSU_PROVIDERS_NAI_LIST);
309                 }
310                 gas_anqp_set_element_len(extra, len_pos);
311         }
312 #endif /* CONFIG_HS20 */
313
314         buf = anqp_build_req(info_ids, num_info_ids, extra);
315         wpabuf_free(extra);
316         if (buf == NULL)
317                 return -1;
318
319         res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, 0, buf,
320                             interworking_anqp_resp_cb, wpa_s);
321         if (res < 0) {
322                 wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
323                 wpabuf_free(buf);
324                 ret = -1;
325                 eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s,
326                                        NULL);
327         } else
328                 wpa_msg(wpa_s, MSG_DEBUG,
329                         "ANQP: Query started with dialog token %u", res);
330
331         return ret;
332 }
333
334
335 struct nai_realm_eap {
336         u8 method;
337         u8 inner_method;
338         enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
339         u8 cred_type;
340         u8 tunneled_cred_type;
341 };
342
343 struct nai_realm {
344         u8 encoding;
345         char *realm;
346         u8 eap_count;
347         struct nai_realm_eap *eap;
348 };
349
350
351 static void nai_realm_free(struct nai_realm *realms, u16 count)
352 {
353         u16 i;
354
355         if (realms == NULL)
356                 return;
357         for (i = 0; i < count; i++) {
358                 os_free(realms[i].eap);
359                 os_free(realms[i].realm);
360         }
361         os_free(realms);
362 }
363
364
365 static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
366                                       const u8 *end)
367 {
368         u8 elen, auth_count, a;
369         const u8 *e_end;
370
371         if (end - pos < 3) {
372                 wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
373                 return NULL;
374         }
375
376         elen = *pos++;
377         if (elen > end - pos || elen < 2) {
378                 wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
379                 return NULL;
380         }
381         e_end = pos + elen;
382         e->method = *pos++;
383         auth_count = *pos++;
384         wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
385                    elen, e->method, auth_count);
386
387         for (a = 0; a < auth_count; a++) {
388                 u8 id, len;
389
390                 if (end - pos < 2) {
391                         wpa_printf(MSG_DEBUG,
392                                    "No room for Authentication Parameter subfield header");
393                         return NULL;
394                 }
395
396                 id = *pos++;
397                 len = *pos++;
398                 if (len > end - pos) {
399                         wpa_printf(MSG_DEBUG,
400                                    "No room for Authentication Parameter subfield");
401                         return NULL;
402                 }
403
404                 switch (id) {
405                 case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
406                         if (len < 1)
407                                 break;
408                         e->inner_non_eap = *pos;
409                         if (e->method != EAP_TYPE_TTLS)
410                                 break;
411                         switch (*pos) {
412                         case NAI_REALM_INNER_NON_EAP_PAP:
413                                 wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
414                                 break;
415                         case NAI_REALM_INNER_NON_EAP_CHAP:
416                                 wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
417                                 break;
418                         case NAI_REALM_INNER_NON_EAP_MSCHAP:
419                                 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
420                                 break;
421                         case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
422                                 wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
423                                 break;
424                         }
425                         break;
426                 case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
427                         if (len < 1)
428                                 break;
429                         e->inner_method = *pos;
430                         wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
431                                    e->inner_method);
432                         break;
433                 case NAI_REALM_EAP_AUTH_CRED_TYPE:
434                         if (len < 1)
435                                 break;
436                         e->cred_type = *pos;
437                         wpa_printf(MSG_DEBUG, "Credential Type: %u",
438                                    e->cred_type);
439                         break;
440                 case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
441                         if (len < 1)
442                                 break;
443                         e->tunneled_cred_type = *pos;
444                         wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
445                                    "Type: %u", e->tunneled_cred_type);
446                         break;
447                 default:
448                         wpa_printf(MSG_DEBUG, "Unsupported Authentication "
449                                    "Parameter: id=%u len=%u", id, len);
450                         wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
451                                     "Value", pos, len);
452                         break;
453                 }
454
455                 pos += len;
456         }
457
458         return e_end;
459 }
460
461
462 static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
463                                         const u8 *end)
464 {
465         u16 len;
466         const u8 *f_end;
467         u8 realm_len, e;
468
469         if (end - pos < 4) {
470                 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
471                            "fixed fields");
472                 return NULL;
473         }
474
475         len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
476         pos += 2;
477         if (len > end - pos || len < 3) {
478                 wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
479                            "(len=%u; left=%u)",
480                            len, (unsigned int) (end - pos));
481                 return NULL;
482         }
483         f_end = pos + len;
484
485         r->encoding = *pos++;
486         realm_len = *pos++;
487         if (realm_len > f_end - pos) {
488                 wpa_printf(MSG_DEBUG, "No room for NAI Realm "
489                            "(len=%u; left=%u)",
490                            realm_len, (unsigned int) (f_end - pos));
491                 return NULL;
492         }
493         wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
494         r->realm = dup_binstr(pos, realm_len);
495         if (r->realm == NULL)
496                 return NULL;
497         pos += realm_len;
498
499         if (f_end - pos < 1) {
500                 wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
501                 return NULL;
502         }
503         r->eap_count = *pos++;
504         wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
505         if (r->eap_count * 3 > f_end - pos) {
506                 wpa_printf(MSG_DEBUG, "No room for EAP Methods");
507                 return NULL;
508         }
509         r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
510         if (r->eap == NULL)
511                 return NULL;
512
513         for (e = 0; e < r->eap_count; e++) {
514                 pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
515                 if (pos == NULL)
516                         return NULL;
517         }
518
519         return f_end;
520 }
521
522
523 static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
524 {
525         struct nai_realm *realm;
526         const u8 *pos, *end;
527         u16 i, num;
528         size_t left;
529
530         if (anqp == NULL)
531                 return NULL;
532         left = wpabuf_len(anqp);
533         if (left < 2)
534                 return NULL;
535
536         pos = wpabuf_head_u8(anqp);
537         end = pos + left;
538         num = WPA_GET_LE16(pos);
539         wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
540         pos += 2;
541         left -= 2;
542
543         if (num > left / 5) {
544                 wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
545                            "enough data (%u octets) for that many realms",
546                            num, (unsigned int) left);
547                 return NULL;
548         }
549
550         realm = os_calloc(num, sizeof(struct nai_realm));
551         if (realm == NULL)
552                 return NULL;
553
554         for (i = 0; i < num; i++) {
555                 pos = nai_realm_parse_realm(&realm[i], pos, end);
556                 if (pos == NULL) {
557                         nai_realm_free(realm, num);
558                         return NULL;
559                 }
560         }
561
562         *count = num;
563         return realm;
564 }
565
566
567 static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
568 {
569         char *tmp, *pos, *end;
570         int match = 0;
571
572         if (realm->realm == NULL || home_realm == NULL)
573                 return 0;
574
575         if (os_strchr(realm->realm, ';') == NULL)
576                 return os_strcasecmp(realm->realm, home_realm) == 0;
577
578         tmp = os_strdup(realm->realm);
579         if (tmp == NULL)
580                 return 0;
581
582         pos = tmp;
583         while (*pos) {
584                 end = os_strchr(pos, ';');
585                 if (end)
586                         *end = '\0';
587                 if (os_strcasecmp(pos, home_realm) == 0) {
588                         match = 1;
589                         break;
590                 }
591                 if (end == NULL)
592                         break;
593                 pos = end + 1;
594         }
595
596         os_free(tmp);
597
598         return match;
599 }
600
601
602 static int nai_realm_cred_username(struct wpa_supplicant *wpa_s,
603                                    struct nai_realm_eap *eap)
604 {
605         if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
606                 wpa_msg(wpa_s, MSG_DEBUG,
607                         "nai-realm-cred-username: EAP method not supported: %d",
608                         eap->method);
609                 return 0; /* method not supported */
610         }
611
612         if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP &&
613             eap->method != EAP_TYPE_FAST) {
614                 /* Only tunneled methods with username/password supported */
615                 wpa_msg(wpa_s, MSG_DEBUG,
616                         "nai-realm-cred-username: Method: %d is not TTLS, PEAP, or FAST",
617                         eap->method);
618                 return 0;
619         }
620
621         if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) {
622                 if (eap->inner_method &&
623                     eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
624                         wpa_msg(wpa_s, MSG_DEBUG,
625                                 "nai-realm-cred-username: PEAP/FAST: Inner method not supported: %d",
626                                 eap->inner_method);
627                         return 0;
628                 }
629                 if (!eap->inner_method &&
630                     eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) {
631                         wpa_msg(wpa_s, MSG_DEBUG,
632                                 "nai-realm-cred-username: MSCHAPv2 not supported");
633                         return 0;
634                 }
635         }
636
637         if (eap->method == EAP_TYPE_TTLS) {
638                 if (eap->inner_method == 0 && eap->inner_non_eap == 0)
639                         return 1; /* Assume TTLS/MSCHAPv2 is used */
640                 if (eap->inner_method &&
641                     eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) {
642                         wpa_msg(wpa_s, MSG_DEBUG,
643                                 "nai-realm-cred-username: TTLS, but inner not supported: %d",
644                                 eap->inner_method);
645                         return 0;
646                 }
647                 if (eap->inner_non_eap &&
648                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
649                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
650                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
651                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) {
652                         wpa_msg(wpa_s, MSG_DEBUG,
653                                 "nai-realm-cred-username: TTLS, inner-non-eap not supported: %d",
654                                 eap->inner_non_eap);
655                         return 0;
656                 }
657         }
658
659         if (eap->inner_method &&
660             eap->inner_method != EAP_TYPE_GTC &&
661             eap->inner_method != EAP_TYPE_MSCHAPV2) {
662                 wpa_msg(wpa_s, MSG_DEBUG,
663                         "nai-realm-cred-username: inner-method not GTC or MSCHAPv2: %d",
664                         eap->inner_method);
665                 return 0;
666         }
667
668         return 1;
669 }
670
671
672 static int nai_realm_cred_cert(struct wpa_supplicant *wpa_s,
673                                struct nai_realm_eap *eap)
674 {
675         if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) {
676                 wpa_msg(wpa_s, MSG_DEBUG,
677                         "nai-realm-cred-cert: Method not supported: %d",
678                         eap->method);
679                 return 0; /* method not supported */
680         }
681
682         if (eap->method != EAP_TYPE_TLS) {
683                 /* Only EAP-TLS supported for credential authentication */
684                 wpa_msg(wpa_s, MSG_DEBUG,
685                         "nai-realm-cred-cert: Method not TLS: %d",
686                         eap->method);
687                 return 0;
688         }
689
690         return 1;
691 }
692
693
694 static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
695                                                  struct wpa_cred *cred,
696                                                  struct nai_realm *realm)
697 {
698         u8 e;
699
700         if (cred->username == NULL ||
701             cred->username[0] == '\0' ||
702             ((cred->password == NULL ||
703               cred->password[0] == '\0') &&
704              (cred->private_key == NULL ||
705               cred->private_key[0] == '\0'))) {
706                 wpa_msg(wpa_s, MSG_DEBUG,
707                         "nai-realm-find-eap: incomplete cred info: username: %s  password: %s private_key: %s",
708                         cred->username ? cred->username : "NULL",
709                         cred->password ? cred->password : "NULL",
710                         cred->private_key ? cred->private_key : "NULL");
711                 return NULL;
712         }
713
714         for (e = 0; e < realm->eap_count; e++) {
715                 struct nai_realm_eap *eap = &realm->eap[e];
716                 if (cred->password && cred->password[0] &&
717                     nai_realm_cred_username(wpa_s, eap))
718                         return eap;
719                 if (cred->private_key && cred->private_key[0] &&
720                     nai_realm_cred_cert(wpa_s, eap))
721                         return eap;
722         }
723
724         return NULL;
725 }
726
727
728 #ifdef INTERWORKING_3GPP
729
730 static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
731 {
732         u8 plmn[3], plmn2[3];
733         const u8 *pos, *end;
734         u8 udhl;
735
736         /*
737          * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
738          * operator is allowed to include only two digits of the MNC, so allow
739          * matches based on both two and three digit MNC assumptions. Since some
740          * SIM/USIM cards may not expose MNC length conveniently, we may be
741          * provided the default MNC length 3 here and as such, checking with MNC
742          * length 2 is justifiable even though 3GPP TS 24.234 does not mention
743          * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
744          * with otherwise matching values would not be good idea in general, so
745          * this should not result in selecting incorrect networks.
746          */
747         /* Match with 3 digit MNC */
748         plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
749         plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
750         plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
751         /* Match with 2 digit MNC */
752         plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
753         plmn2[1] = (imsi[2] - '0') | 0xf0;
754         plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
755
756         if (anqp == NULL)
757                 return 0;
758         pos = wpabuf_head_u8(anqp);
759         end = pos + wpabuf_len(anqp);
760         if (end - pos < 2)
761                 return 0;
762         if (*pos != 0) {
763                 wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
764                 return 0;
765         }
766         pos++;
767         udhl = *pos++;
768         if (udhl > end - pos) {
769                 wpa_printf(MSG_DEBUG, "Invalid UDHL");
770                 return 0;
771         }
772         end = pos + udhl;
773
774         wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
775                    plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
776                    imsi, mnc_len);
777
778         while (end - pos >= 2) {
779                 u8 iei, len;
780                 const u8 *l_end;
781                 iei = *pos++;
782                 len = *pos++ & 0x7f;
783                 if (len > end - pos)
784                         break;
785                 l_end = pos + len;
786
787                 if (iei == 0 && len > 0) {
788                         /* PLMN List */
789                         u8 num, i;
790                         wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
791                                     pos, len);
792                         num = *pos++;
793                         for (i = 0; i < num; i++) {
794                                 if (l_end - pos < 3)
795                                         break;
796                                 if (os_memcmp(pos, plmn, 3) == 0 ||
797                                     os_memcmp(pos, plmn2, 3) == 0)
798                                         return 1; /* Found matching PLMN */
799                                 pos += 3;
800                         }
801                 } else {
802                         wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
803                                     pos, len);
804                 }
805
806                 pos = l_end;
807         }
808
809         return 0;
810 }
811
812
813 static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
814                           size_t mnc_len, char prefix)
815 {
816         const char *sep, *msin;
817         char *end, *pos;
818         size_t msin_len, plmn_len;
819
820         /*
821          * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
822          * Root NAI:
823          * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
824          * <MNC> is zero-padded to three digits in case two-digit MNC is used
825          */
826
827         if (imsi == NULL || os_strlen(imsi) > 16) {
828                 wpa_printf(MSG_DEBUG, "No valid IMSI available");
829                 return -1;
830         }
831         sep = os_strchr(imsi, '-');
832         if (sep) {
833                 plmn_len = sep - imsi;
834                 msin = sep + 1;
835         } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
836                 plmn_len = 3 + mnc_len;
837                 msin = imsi + plmn_len;
838         } else
839                 return -1;
840         if (plmn_len != 5 && plmn_len != 6)
841                 return -1;
842         msin_len = os_strlen(msin);
843
844         pos = nai;
845         end = nai + nai_len;
846         if (prefix)
847                 *pos++ = prefix;
848         os_memcpy(pos, imsi, plmn_len);
849         pos += plmn_len;
850         os_memcpy(pos, msin, msin_len);
851         pos += msin_len;
852         pos += os_snprintf(pos, end - pos, "@wlan.mnc");
853         if (plmn_len == 5) {
854                 *pos++ = '0';
855                 *pos++ = imsi[3];
856                 *pos++ = imsi[4];
857         } else {
858                 *pos++ = imsi[3];
859                 *pos++ = imsi[4];
860                 *pos++ = imsi[5];
861         }
862         os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
863                     imsi[0], imsi[1], imsi[2]);
864
865         return 0;
866 }
867
868
869 static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
870 {
871         char nai[100];
872         if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
873                 return -1;
874         return wpa_config_set_quoted(ssid, "identity", nai);
875 }
876
877 #endif /* INTERWORKING_3GPP */
878
879
880 static int already_connected(struct wpa_supplicant *wpa_s,
881                              struct wpa_cred *cred, struct wpa_bss *bss)
882 {
883         struct wpa_ssid *ssid, *sel_ssid;
884         struct wpa_bss *selected;
885
886         if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
887                 return 0;
888
889         ssid = wpa_s->current_ssid;
890         if (ssid->parent_cred != cred)
891                 return 0;
892
893         if (ssid->ssid_len != bss->ssid_len ||
894             os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
895                 return 0;
896
897         sel_ssid = NULL;
898         selected = wpa_supplicant_pick_network(wpa_s, &sel_ssid);
899         if (selected && sel_ssid && sel_ssid->priority > ssid->priority)
900                 return 0; /* higher priority network in scan results */
901
902         return 1;
903 }
904
905
906 static void remove_duplicate_network(struct wpa_supplicant *wpa_s,
907                                      struct wpa_cred *cred,
908                                      struct wpa_bss *bss)
909 {
910         struct wpa_ssid *ssid;
911
912         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
913                 if (ssid->parent_cred != cred)
914                         continue;
915                 if (ssid->ssid_len != bss->ssid_len ||
916                     os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
917                         continue;
918
919                 break;
920         }
921
922         if (ssid == NULL)
923                 return;
924
925         wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
926
927         if (ssid == wpa_s->current_ssid) {
928                 wpa_sm_set_config(wpa_s->wpa, NULL);
929                 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
930                 wpa_s->own_disconnect_req = 1;
931                 wpa_supplicant_deauthenticate(wpa_s,
932                                               WLAN_REASON_DEAUTH_LEAVING);
933         }
934
935         wpas_notify_network_removed(wpa_s, ssid);
936         wpa_config_remove_network(wpa_s->conf, ssid->id);
937 }
938
939
940 static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
941                                         struct wpa_ssid *ssid)
942 {
943         const char *key_mgmt = NULL;
944 #ifdef CONFIG_IEEE80211R
945         int res;
946         struct wpa_driver_capa capa;
947
948         res = wpa_drv_get_capa(wpa_s, &capa);
949         if (res == 0 && capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) {
950                 key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
951                         "WPA-EAP WPA-EAP-SHA256 FT-EAP" :
952                         "WPA-EAP FT-EAP";
953         }
954 #endif /* CONFIG_IEEE80211R */
955
956         if (!key_mgmt)
957                 key_mgmt = wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
958                         "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP";
959         if (wpa_config_set(ssid, "key_mgmt", key_mgmt, 0) < 0 ||
960             wpa_config_set(ssid, "proto", "RSN", 0) < 0 ||
961             wpa_config_set(ssid, "ieee80211w", "1", 0) < 0 ||
962             wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
963                 return -1;
964         return 0;
965 }
966
967
968 static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
969                                      struct wpa_cred *cred,
970                                      struct wpa_bss *bss, int only_add)
971 {
972 #ifdef INTERWORKING_3GPP
973         struct wpa_ssid *ssid;
974         int eap_type;
975         int res;
976         char prefix;
977
978         if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
979                 return -1;
980
981         wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
982                 " (3GPP)", MAC2STR(bss->bssid));
983
984         if (already_connected(wpa_s, cred, bss)) {
985                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
986                         MAC2STR(bss->bssid));
987                 return wpa_s->current_ssid->id;
988         }
989
990         remove_duplicate_network(wpa_s, cred, bss);
991
992         ssid = wpa_config_add_network(wpa_s->conf);
993         if (ssid == NULL)
994                 return -1;
995         ssid->parent_cred = cred;
996
997         wpas_notify_network_added(wpa_s, ssid);
998         wpa_config_set_network_defaults(ssid);
999         ssid->priority = cred->priority;
1000         ssid->temporary = 1;
1001         ssid->ssid = os_zalloc(bss->ssid_len + 1);
1002         if (ssid->ssid == NULL)
1003                 goto fail;
1004         os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
1005         ssid->ssid_len = bss->ssid_len;
1006         ssid->eap.sim_num = cred->sim_num;
1007
1008         if (interworking_set_hs20_params(wpa_s, ssid) < 0)
1009                 goto fail;
1010
1011         eap_type = EAP_TYPE_SIM;
1012         if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
1013                 eap_type = EAP_TYPE_AKA;
1014         if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
1015                 if (cred->eap_method[0].method == EAP_TYPE_SIM ||
1016                     cred->eap_method[0].method == EAP_TYPE_AKA ||
1017                     cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
1018                         eap_type = cred->eap_method[0].method;
1019         }
1020
1021         switch (eap_type) {
1022         case EAP_TYPE_SIM:
1023                 prefix = '1';
1024                 res = wpa_config_set(ssid, "eap", "SIM", 0);
1025                 break;
1026         case EAP_TYPE_AKA:
1027                 prefix = '0';
1028                 res = wpa_config_set(ssid, "eap", "AKA", 0);
1029                 break;
1030         case EAP_TYPE_AKA_PRIME:
1031                 prefix = '6';
1032                 res = wpa_config_set(ssid, "eap", "AKA'", 0);
1033                 break;
1034         default:
1035                 res = -1;
1036                 break;
1037         }
1038         if (res < 0) {
1039                 wpa_msg(wpa_s, MSG_DEBUG,
1040                         "Selected EAP method (%d) not supported", eap_type);
1041                 goto fail;
1042         }
1043
1044         if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
1045                 wpa_msg(wpa_s, MSG_DEBUG, "Failed to set Root NAI");
1046                 goto fail;
1047         }
1048
1049         if (cred->milenage && cred->milenage[0]) {
1050                 if (wpa_config_set_quoted(ssid, "password",
1051                                           cred->milenage) < 0)
1052                         goto fail;
1053         } else if (cred->pcsc) {
1054                 if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
1055                         goto fail;
1056                 if (wpa_s->conf->pcsc_pin &&
1057                     wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
1058                     < 0)
1059                         goto fail;
1060         }
1061
1062         wpa_s->next_ssid = ssid;
1063         wpa_config_update_prio_list(wpa_s->conf);
1064         if (!only_add)
1065                 interworking_reconnect(wpa_s);
1066
1067         return ssid->id;
1068
1069 fail:
1070         wpas_notify_network_removed(wpa_s, ssid);
1071         wpa_config_remove_network(wpa_s->conf, ssid->id);
1072 #endif /* INTERWORKING_3GPP */
1073         return -1;
1074 }
1075
1076
1077 static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
1078                                             size_t rc_len)
1079 {
1080         const u8 *pos, *end;
1081         u8 lens;
1082
1083         if (ie == NULL)
1084                 return 0;
1085
1086         pos = ie + 2;
1087         end = ie + 2 + ie[1];
1088
1089         /* Roaming Consortium element:
1090          * Number of ANQP OIs
1091          * OI #1 and #2 lengths
1092          * OI #1, [OI #2], [OI #3]
1093          */
1094
1095         if (end - pos < 2)
1096                 return 0;
1097
1098         pos++; /* skip Number of ANQP OIs */
1099         lens = *pos++;
1100         if ((lens & 0x0f) + (lens >> 4) > end - pos)
1101                 return 0;
1102
1103         if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
1104                 return 1;
1105         pos += lens & 0x0f;
1106
1107         if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
1108                 return 1;
1109         pos += lens >> 4;
1110
1111         if (pos < end && (size_t) (end - pos) == rc_len &&
1112             os_memcmp(pos, rc_id, rc_len) == 0)
1113                 return 1;
1114
1115         return 0;
1116 }
1117
1118
1119 static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
1120                                          const u8 *rc_id, size_t rc_len)
1121 {
1122         const u8 *pos, *end;
1123         u8 len;
1124
1125         if (anqp == NULL)
1126                 return 0;
1127
1128         pos = wpabuf_head(anqp);
1129         end = pos + wpabuf_len(anqp);
1130
1131         /* Set of <OI Length, OI> duples */
1132         while (pos < end) {
1133                 len = *pos++;
1134                 if (len > end - pos)
1135                         break;
1136                 if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
1137                         return 1;
1138                 pos += len;
1139         }
1140
1141         return 0;
1142 }
1143
1144
1145 static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
1146                                     const u8 *rc_id, size_t rc_len)
1147 {
1148         return roaming_consortium_element_match(ie, rc_id, rc_len) ||
1149                 roaming_consortium_anqp_match(anqp, rc_id, rc_len);
1150 }
1151
1152
1153 static int cred_roaming_consortiums_match(const u8 *ie,
1154                                           const struct wpabuf *anqp,
1155                                           const struct wpa_cred *cred)
1156 {
1157         unsigned int i;
1158
1159         for (i = 0; i < cred->num_roaming_consortiums; i++) {
1160                 if (roaming_consortium_match(ie, anqp,
1161                                              cred->roaming_consortiums[i],
1162                                              cred->roaming_consortiums_len[i]))
1163                         return 1;
1164         }
1165
1166         return 0;
1167 }
1168
1169
1170 static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
1171 {
1172         const u8 *ie;
1173
1174         if (cred->required_roaming_consortium_len == 0)
1175                 return 0;
1176
1177         ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
1178
1179         if (ie == NULL &&
1180             (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
1181                 return 1;
1182
1183         return !roaming_consortium_match(ie,
1184                                          bss->anqp ?
1185                                          bss->anqp->roaming_consortium : NULL,
1186                                          cred->required_roaming_consortium,
1187                                          cred->required_roaming_consortium_len);
1188 }
1189
1190
1191 static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
1192 {
1193         size_t i;
1194
1195         if (!cred->excluded_ssid)
1196                 return 0;
1197
1198         for (i = 0; i < cred->num_excluded_ssid; i++) {
1199                 struct excluded_ssid *e = &cred->excluded_ssid[i];
1200                 if (bss->ssid_len == e->ssid_len &&
1201                     os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0)
1202                         return 1;
1203         }
1204
1205         return 0;
1206 }
1207
1208
1209 static int cred_below_min_backhaul(struct wpa_supplicant *wpa_s,
1210                                    struct wpa_cred *cred, struct wpa_bss *bss)
1211 {
1212 #ifdef CONFIG_HS20
1213         int res;
1214         unsigned int dl_bandwidth, ul_bandwidth;
1215         const u8 *wan;
1216         u8 wan_info, dl_load, ul_load;
1217         u16 lmd;
1218         u32 ul_speed, dl_speed;
1219
1220         if (!cred->min_dl_bandwidth_home &&
1221             !cred->min_ul_bandwidth_home &&
1222             !cred->min_dl_bandwidth_roaming &&
1223             !cred->min_ul_bandwidth_roaming)
1224                 return 0; /* No bandwidth constraint specified */
1225
1226         if (bss->anqp == NULL || bss->anqp->hs20_wan_metrics == NULL)
1227                 return 0; /* No WAN Metrics known - ignore constraint */
1228
1229         wan = wpabuf_head(bss->anqp->hs20_wan_metrics);
1230         wan_info = wan[0];
1231         if (wan_info & BIT(3))
1232                 return 1; /* WAN link at capacity */
1233         lmd = WPA_GET_LE16(wan + 11);
1234         if (lmd == 0)
1235                 return 0; /* Downlink/Uplink Load was not measured */
1236         dl_speed = WPA_GET_LE32(wan + 1);
1237         ul_speed = WPA_GET_LE32(wan + 5);
1238         dl_load = wan[9];
1239         ul_load = wan[10];
1240
1241         if (dl_speed >= 0xffffff)
1242                 dl_bandwidth = dl_speed / 255 * (255 - dl_load);
1243         else
1244                 dl_bandwidth = dl_speed * (255 - dl_load) / 255;
1245
1246         if (ul_speed >= 0xffffff)
1247                 ul_bandwidth = ul_speed / 255 * (255 - ul_load);
1248         else
1249                 ul_bandwidth = ul_speed * (255 - ul_load) / 255;
1250
1251         res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
1252                                         bss->anqp->domain_name : NULL);
1253         if (res > 0) {
1254                 if (cred->min_dl_bandwidth_home > dl_bandwidth)
1255                         return 1;
1256                 if (cred->min_ul_bandwidth_home > ul_bandwidth)
1257                         return 1;
1258         } else {
1259                 if (cred->min_dl_bandwidth_roaming > dl_bandwidth)
1260                         return 1;
1261                 if (cred->min_ul_bandwidth_roaming > ul_bandwidth)
1262                         return 1;
1263         }
1264 #endif /* CONFIG_HS20 */
1265
1266         return 0;
1267 }
1268
1269
1270 static int cred_over_max_bss_load(struct wpa_supplicant *wpa_s,
1271                                   struct wpa_cred *cred, struct wpa_bss *bss)
1272 {
1273         const u8 *ie;
1274         int res;
1275
1276         if (!cred->max_bss_load)
1277                 return 0; /* No BSS Load constraint specified */
1278
1279         ie = wpa_bss_get_ie(bss, WLAN_EID_BSS_LOAD);
1280         if (ie == NULL || ie[1] < 3)
1281                 return 0; /* No BSS Load advertised */
1282
1283         res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
1284                                         bss->anqp->domain_name : NULL);
1285         if (res <= 0)
1286                 return 0; /* Not a home network */
1287
1288         return ie[4] > cred->max_bss_load;
1289 }
1290
1291
1292 #ifdef CONFIG_HS20
1293
1294 static int has_proto_match(const u8 *pos, const u8 *end, u8 proto)
1295 {
1296         while (end - pos >= 4) {
1297                 if (pos[0] == proto && pos[3] == 1 /* Open */)
1298                         return 1;
1299                 pos += 4;
1300         }
1301
1302         return 0;
1303 }
1304
1305
1306 static int has_proto_port_match(const u8 *pos, const u8 *end, u8 proto,
1307                                 u16 port)
1308 {
1309         while (end - pos >= 4) {
1310                 if (pos[0] == proto && WPA_GET_LE16(&pos[1]) == port &&
1311                     pos[3] == 1 /* Open */)
1312                         return 1;
1313                 pos += 4;
1314         }
1315
1316         return 0;
1317 }
1318
1319 #endif /* CONFIG_HS20 */
1320
1321
1322 static int cred_conn_capab_missing(struct wpa_supplicant *wpa_s,
1323                                    struct wpa_cred *cred, struct wpa_bss *bss)
1324 {
1325 #ifdef CONFIG_HS20
1326         int res;
1327         const u8 *capab, *end;
1328         unsigned int i, j;
1329         int *ports;
1330
1331         if (!cred->num_req_conn_capab)
1332                 return 0; /* No connection capability constraint specified */
1333
1334         if (bss->anqp == NULL || bss->anqp->hs20_connection_capability == NULL)
1335                 return 0; /* No Connection Capability known - ignore constraint
1336                            */
1337
1338         res = interworking_home_sp_cred(wpa_s, cred, bss->anqp ?
1339                                         bss->anqp->domain_name : NULL);
1340         if (res > 0)
1341                 return 0; /* No constraint in home network */
1342
1343         capab = wpabuf_head(bss->anqp->hs20_connection_capability);
1344         end = capab + wpabuf_len(bss->anqp->hs20_connection_capability);
1345
1346         for (i = 0; i < cred->num_req_conn_capab; i++) {
1347                 ports = cred->req_conn_capab_port[i];
1348                 if (!ports) {
1349                         if (!has_proto_match(capab, end,
1350                                              cred->req_conn_capab_proto[i]))
1351                                 return 1;
1352                 } else {
1353                         for (j = 0; ports[j] > -1; j++) {
1354                                 if (!has_proto_port_match(
1355                                             capab, end,
1356                                             cred->req_conn_capab_proto[i],
1357                                             ports[j]))
1358                                         return 1;
1359                         }
1360                 }
1361         }
1362 #endif /* CONFIG_HS20 */
1363
1364         return 0;
1365 }
1366
1367
1368 static struct wpa_cred * interworking_credentials_available_roaming_consortium(
1369         struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
1370         int *excluded)
1371 {
1372         struct wpa_cred *cred, *selected = NULL;
1373         const u8 *ie;
1374         const struct wpabuf *anqp;
1375         int is_excluded = 0;
1376
1377         ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
1378         anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
1379
1380         if (!ie && !anqp)
1381                 return NULL;
1382
1383         if (wpa_s->conf->cred == NULL)
1384                 return NULL;
1385
1386         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1387                 if (cred->roaming_consortium_len == 0 &&
1388                     cred->num_roaming_consortiums == 0)
1389                         continue;
1390
1391                 if (!cred->eap_method)
1392                         continue;
1393
1394                 if ((cred->roaming_consortium_len == 0 ||
1395                      !roaming_consortium_match(ie, anqp,
1396                                                cred->roaming_consortium,
1397                                                cred->roaming_consortium_len)) &&
1398                     !cred_roaming_consortiums_match(ie, anqp, cred))
1399                         continue;
1400
1401                 if (cred_no_required_oi_match(cred, bss))
1402                         continue;
1403                 if (!ignore_bw && cred_below_min_backhaul(wpa_s, cred, bss))
1404                         continue;
1405                 if (!ignore_bw && cred_over_max_bss_load(wpa_s, cred, bss))
1406                         continue;
1407                 if (!ignore_bw && cred_conn_capab_missing(wpa_s, cred, bss))
1408                         continue;
1409                 if (cred_excluded_ssid(cred, bss)) {
1410                         if (excluded == NULL)
1411                                 continue;
1412                         if (selected == NULL) {
1413                                 selected = cred;
1414                                 is_excluded = 1;
1415                         }
1416                 } else {
1417                         if (selected == NULL || is_excluded ||
1418                             cred_prio_cmp(selected, cred) < 0) {
1419                                 selected = cred;
1420                                 is_excluded = 0;
1421                         }
1422                 }
1423         }
1424
1425         if (excluded)
1426                 *excluded = is_excluded;
1427
1428         return selected;
1429 }
1430
1431
1432 static int interworking_set_eap_params(struct wpa_ssid *ssid,
1433                                        struct wpa_cred *cred, int ttls)
1434 {
1435         if (cred->eap_method) {
1436                 ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
1437                         cred->eap_method->method == EAP_TYPE_TTLS;
1438
1439                 os_free(ssid->eap.eap_methods);
1440                 ssid->eap.eap_methods =
1441                         os_malloc(sizeof(struct eap_method_type) * 2);
1442                 if (ssid->eap.eap_methods == NULL)
1443                         return -1;
1444                 os_memcpy(ssid->eap.eap_methods, cred->eap_method,
1445                           sizeof(*cred->eap_method));
1446                 ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
1447                 ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
1448         }
1449
1450         if (ttls && cred->username && cred->username[0]) {
1451                 const char *pos;
1452                 char *anon;
1453                 /* Use anonymous NAI in Phase 1 */
1454                 pos = os_strchr(cred->username, '@');
1455                 if (pos) {
1456                         size_t buflen = 9 + os_strlen(pos) + 1;
1457                         anon = os_malloc(buflen);
1458                         if (anon == NULL)
1459                                 return -1;
1460                         os_snprintf(anon, buflen, "anonymous%s", pos);
1461                 } else if (cred->realm) {
1462                         size_t buflen = 10 + os_strlen(cred->realm) + 1;
1463                         anon = os_malloc(buflen);
1464                         if (anon == NULL)
1465                                 return -1;
1466                         os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
1467                 } else {
1468                         anon = os_strdup("anonymous");
1469                         if (anon == NULL)
1470                                 return -1;
1471                 }
1472                 if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
1473                     0) {
1474                         os_free(anon);
1475                         return -1;
1476                 }
1477                 os_free(anon);
1478         }
1479
1480         if (!ttls && cred->username && cred->username[0] && cred->realm &&
1481             !os_strchr(cred->username, '@')) {
1482                 char *id;
1483                 size_t buflen;
1484                 int res;
1485
1486                 buflen = os_strlen(cred->username) + 1 +
1487                         os_strlen(cred->realm) + 1;
1488
1489                 id = os_malloc(buflen);
1490                 if (!id)
1491                         return -1;
1492                 os_snprintf(id, buflen, "%s@%s", cred->username, cred->realm);
1493                 res = wpa_config_set_quoted(ssid, "identity", id);
1494                 os_free(id);
1495                 if (res < 0)
1496                         return -1;
1497         } else if (cred->username && cred->username[0] &&
1498             wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
1499                 return -1;
1500
1501         if (cred->password && cred->password[0]) {
1502                 if (cred->ext_password &&
1503                     wpa_config_set(ssid, "password", cred->password, 0) < 0)
1504                         return -1;
1505                 if (!cred->ext_password &&
1506                     wpa_config_set_quoted(ssid, "password", cred->password) <
1507                     0)
1508                         return -1;
1509         }
1510
1511         if (cred->client_cert && cred->client_cert[0] &&
1512             wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
1513                 return -1;
1514
1515 #ifdef ANDROID
1516         if (cred->private_key &&
1517             os_strncmp(cred->private_key, "keystore://", 11) == 0) {
1518                 /* Use OpenSSL engine configuration for Android keystore */
1519                 if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
1520                     wpa_config_set_quoted(ssid, "key_id",
1521                                           cred->private_key + 11) < 0 ||
1522                     wpa_config_set(ssid, "engine", "1", 0) < 0)
1523                         return -1;
1524         } else
1525 #endif /* ANDROID */
1526         if (cred->private_key && cred->private_key[0] &&
1527             wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
1528                 return -1;
1529
1530         if (cred->private_key_passwd && cred->private_key_passwd[0] &&
1531             wpa_config_set_quoted(ssid, "private_key_passwd",
1532                                   cred->private_key_passwd) < 0)
1533                 return -1;
1534
1535         if (cred->phase1) {
1536                 os_free(ssid->eap.phase1);
1537                 ssid->eap.phase1 = os_strdup(cred->phase1);
1538         }
1539         if (cred->phase2) {
1540                 os_free(ssid->eap.phase2);
1541                 ssid->eap.phase2 = os_strdup(cred->phase2);
1542         }
1543
1544         if (cred->ca_cert && cred->ca_cert[0] &&
1545             wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
1546                 return -1;
1547
1548         if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
1549             wpa_config_set_quoted(ssid, "domain_suffix_match",
1550                                   cred->domain_suffix_match) < 0)
1551                 return -1;
1552
1553         ssid->eap.ocsp = cred->ocsp;
1554
1555         return 0;
1556 }
1557
1558
1559 static int interworking_connect_roaming_consortium(
1560         struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
1561         struct wpa_bss *bss, int only_add)
1562 {
1563         struct wpa_ssid *ssid;
1564         const u8 *ie;
1565         const struct wpabuf *anqp;
1566         unsigned int i;
1567
1568         wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR
1569                 " based on roaming consortium match", MAC2STR(bss->bssid));
1570
1571         if (already_connected(wpa_s, cred, bss)) {
1572                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
1573                         MAC2STR(bss->bssid));
1574                 return wpa_s->current_ssid->id;
1575         }
1576
1577         remove_duplicate_network(wpa_s, cred, bss);
1578
1579         ssid = wpa_config_add_network(wpa_s->conf);
1580         if (ssid == NULL)
1581                 return -1;
1582         ssid->parent_cred = cred;
1583         wpas_notify_network_added(wpa_s, ssid);
1584         wpa_config_set_network_defaults(ssid);
1585         ssid->priority = cred->priority;
1586         ssid->temporary = 1;
1587         ssid->ssid = os_zalloc(bss->ssid_len + 1);
1588         if (ssid->ssid == NULL)
1589                 goto fail;
1590         os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
1591         ssid->ssid_len = bss->ssid_len;
1592
1593         if (interworking_set_hs20_params(wpa_s, ssid) < 0)
1594                 goto fail;
1595
1596         ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
1597         anqp = bss->anqp ? bss->anqp->roaming_consortium : NULL;
1598         for (i = 0; (ie || anqp) && i < cred->num_roaming_consortiums; i++) {
1599                 if (!roaming_consortium_match(
1600                             ie, anqp, cred->roaming_consortiums[i],
1601                             cred->roaming_consortiums_len[i]))
1602                         continue;
1603
1604                 ssid->roaming_consortium_selection =
1605                         os_malloc(cred->roaming_consortiums_len[i]);
1606                 if (!ssid->roaming_consortium_selection)
1607                         goto fail;
1608                 os_memcpy(ssid->roaming_consortium_selection,
1609                           cred->roaming_consortiums[i],
1610                           cred->roaming_consortiums_len[i]);
1611                 ssid->roaming_consortium_selection_len =
1612                         cred->roaming_consortiums_len[i];
1613                 break;
1614         }
1615
1616         if (cred->eap_method == NULL) {
1617                 wpa_msg(wpa_s, MSG_DEBUG,
1618                         "Interworking: No EAP method set for credential using roaming consortium");
1619                 goto fail;
1620         }
1621
1622         if (interworking_set_eap_params(
1623                     ssid, cred,
1624                     cred->eap_method->vendor == EAP_VENDOR_IETF &&
1625                     cred->eap_method->method == EAP_TYPE_TTLS) < 0)
1626                 goto fail;
1627
1628         wpa_s->next_ssid = ssid;
1629         wpa_config_update_prio_list(wpa_s->conf);
1630         if (!only_add)
1631                 interworking_reconnect(wpa_s);
1632
1633         return ssid->id;
1634
1635 fail:
1636         wpas_notify_network_removed(wpa_s, ssid);
1637         wpa_config_remove_network(wpa_s->conf, ssid->id);
1638         return -1;
1639 }
1640
1641
1642 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
1643                          int only_add)
1644 {
1645         struct wpa_cred *cred, *cred_rc, *cred_3gpp;
1646         struct wpa_ssid *ssid;
1647         struct nai_realm *realm;
1648         struct nai_realm_eap *eap = NULL;
1649         u16 count, i;
1650         char buf[100];
1651         int excluded = 0, *excl = &excluded;
1652         const char *name;
1653
1654         if (wpa_s->conf->cred == NULL || bss == NULL)
1655                 return -1;
1656         if (disallowed_bssid(wpa_s, bss->bssid) ||
1657             disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
1658                 wpa_msg(wpa_s, MSG_DEBUG,
1659                         "Interworking: Reject connection to disallowed BSS "
1660                         MACSTR, MAC2STR(bss->bssid));
1661                 return -1;
1662         }
1663
1664         wpa_printf(MSG_DEBUG, "Interworking: Considering BSS " MACSTR
1665                    " for connection",
1666                    MAC2STR(bss->bssid));
1667
1668         if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
1669                 /*
1670                  * We currently support only HS 2.0 networks and those are
1671                  * required to use WPA2-Enterprise.
1672                  */
1673                 wpa_msg(wpa_s, MSG_DEBUG,
1674                         "Interworking: Network does not use RSN");
1675                 return -1;
1676         }
1677
1678         cred_rc = interworking_credentials_available_roaming_consortium(
1679                 wpa_s, bss, 0, excl);
1680         if (cred_rc) {
1681                 wpa_msg(wpa_s, MSG_DEBUG,
1682                         "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d",
1683                         cred_rc->priority, cred_rc->sp_priority);
1684                 if (excl && !(*excl))
1685                         excl = NULL;
1686         }
1687
1688         cred = interworking_credentials_available_realm(wpa_s, bss, 0, excl);
1689         if (cred) {
1690                 wpa_msg(wpa_s, MSG_DEBUG,
1691                         "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d",
1692                         cred->priority, cred->sp_priority);
1693                 if (excl && !(*excl))
1694                         excl = NULL;
1695         }
1696
1697         cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss, 0,
1698                                                             excl);
1699         if (cred_3gpp) {
1700                 wpa_msg(wpa_s, MSG_DEBUG,
1701                         "Interworking: Highest 3GPP matching credential priority %d sp_priority %d",
1702                         cred_3gpp->priority, cred_3gpp->sp_priority);
1703                 if (excl && !(*excl))
1704                         excl = NULL;
1705         }
1706
1707         if (!cred_rc && !cred && !cred_3gpp) {
1708                 wpa_msg(wpa_s, MSG_DEBUG,
1709                         "Interworking: No full credential matches - consider options without BW(etc.) limits");
1710                 cred_rc = interworking_credentials_available_roaming_consortium(
1711                         wpa_s, bss, 1, excl);
1712                 if (cred_rc) {
1713                         wpa_msg(wpa_s, MSG_DEBUG,
1714                                 "Interworking: Highest roaming consortium matching credential priority %d sp_priority %d (ignore BW)",
1715                                 cred_rc->priority, cred_rc->sp_priority);
1716                         if (excl && !(*excl))
1717                                 excl = NULL;
1718                 }
1719
1720                 cred = interworking_credentials_available_realm(wpa_s, bss, 1,
1721                                                                 excl);
1722                 if (cred) {
1723                         wpa_msg(wpa_s, MSG_DEBUG,
1724                                 "Interworking: Highest NAI Realm list matching credential priority %d sp_priority %d (ignore BW)",
1725                                 cred->priority, cred->sp_priority);
1726                         if (excl && !(*excl))
1727                                 excl = NULL;
1728                 }
1729
1730                 cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss,
1731                                                                     1, excl);
1732                 if (cred_3gpp) {
1733                         wpa_msg(wpa_s, MSG_DEBUG,
1734                                 "Interworking: Highest 3GPP matching credential priority %d sp_priority %d (ignore BW)",
1735                                 cred_3gpp->priority, cred_3gpp->sp_priority);
1736                         if (excl && !(*excl))
1737                                 excl = NULL;
1738                 }
1739         }
1740
1741         if (cred_rc &&
1742             (cred == NULL || cred_prio_cmp(cred_rc, cred) >= 0) &&
1743             (cred_3gpp == NULL || cred_prio_cmp(cred_rc, cred_3gpp) >= 0))
1744                 return interworking_connect_roaming_consortium(wpa_s, cred_rc,
1745                                                                bss, only_add);
1746
1747         if (cred_3gpp &&
1748             (cred == NULL || cred_prio_cmp(cred_3gpp, cred) >= 0)) {
1749                 return interworking_connect_3gpp(wpa_s, cred_3gpp, bss,
1750                                                  only_add);
1751         }
1752
1753         if (cred == NULL) {
1754                 wpa_msg(wpa_s, MSG_DEBUG,
1755                         "Interworking: No matching credentials found for "
1756                         MACSTR, MAC2STR(bss->bssid));
1757                 return -1;
1758         }
1759
1760         realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
1761                                 &count);
1762         if (realm == NULL) {
1763                 wpa_msg(wpa_s, MSG_DEBUG,
1764                         "Interworking: Could not parse NAI Realm list from "
1765                         MACSTR, MAC2STR(bss->bssid));
1766                 return -1;
1767         }
1768
1769         for (i = 0; i < count; i++) {
1770                 if (!nai_realm_match(&realm[i], cred->realm))
1771                         continue;
1772                 eap = nai_realm_find_eap(wpa_s, cred, &realm[i]);
1773                 if (eap)
1774                         break;
1775         }
1776
1777         if (!eap) {
1778                 wpa_msg(wpa_s, MSG_DEBUG,
1779                         "Interworking: No matching credentials and EAP method found for "
1780                         MACSTR, MAC2STR(bss->bssid));
1781                 nai_realm_free(realm, count);
1782                 return -1;
1783         }
1784
1785         wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Connect with " MACSTR,
1786                 MAC2STR(bss->bssid));
1787
1788         if (already_connected(wpa_s, cred, bss)) {
1789                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
1790                         MAC2STR(bss->bssid));
1791                 nai_realm_free(realm, count);
1792                 return 0;
1793         }
1794
1795         remove_duplicate_network(wpa_s, cred, bss);
1796
1797         ssid = wpa_config_add_network(wpa_s->conf);
1798         if (ssid == NULL) {
1799                 nai_realm_free(realm, count);
1800                 return -1;
1801         }
1802         ssid->parent_cred = cred;
1803         wpas_notify_network_added(wpa_s, ssid);
1804         wpa_config_set_network_defaults(ssid);
1805         ssid->priority = cred->priority;
1806         ssid->temporary = 1;
1807         ssid->ssid = os_zalloc(bss->ssid_len + 1);
1808         if (ssid->ssid == NULL)
1809                 goto fail;
1810         os_memcpy(ssid->ssid, bss->ssid, bss->ssid_len);
1811         ssid->ssid_len = bss->ssid_len;
1812
1813         if (interworking_set_hs20_params(wpa_s, ssid) < 0)
1814                 goto fail;
1815
1816         if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
1817                                                      eap->method), 0) < 0)
1818                 goto fail;
1819
1820         switch (eap->method) {
1821         case EAP_TYPE_TTLS:
1822                 if (eap->inner_method) {
1823                         name = eap_get_name(EAP_VENDOR_IETF, eap->inner_method);
1824                         if (!name)
1825                                 goto fail;
1826                         os_snprintf(buf, sizeof(buf), "\"autheap=%s\"", name);
1827                         if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
1828                                 goto fail;
1829                         break;
1830                 }
1831                 switch (eap->inner_non_eap) {
1832                 case NAI_REALM_INNER_NON_EAP_PAP:
1833                         if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
1834                             0)
1835                                 goto fail;
1836                         break;
1837                 case NAI_REALM_INNER_NON_EAP_CHAP:
1838                         if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
1839                             < 0)
1840                                 goto fail;
1841                         break;
1842                 case NAI_REALM_INNER_NON_EAP_MSCHAP:
1843                         if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
1844                                            0) < 0)
1845                                 goto fail;
1846                         break;
1847                 case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
1848                         if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
1849                                            0) < 0)
1850                                 goto fail;
1851                         break;
1852                 default:
1853                         /* EAP params were not set - assume TTLS/MSCHAPv2 */
1854                         if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
1855                                            0) < 0)
1856                                 goto fail;
1857                         break;
1858                 }
1859                 break;
1860         case EAP_TYPE_PEAP:
1861         case EAP_TYPE_FAST:
1862                 if (wpa_config_set(ssid, "phase1", "\"fast_provisioning=2\"",
1863                                    0) < 0)
1864                         goto fail;
1865                 if (wpa_config_set(ssid, "pac_file",
1866                                    "\"blob://pac_interworking\"", 0) < 0)
1867                         goto fail;
1868                 name = eap_get_name(EAP_VENDOR_IETF,
1869                                     eap->inner_method ? eap->inner_method :
1870                                     EAP_TYPE_MSCHAPV2);
1871                 if (name == NULL)
1872                         goto fail;
1873                 os_snprintf(buf, sizeof(buf), "\"auth=%s\"", name);
1874                 if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
1875                         goto fail;
1876                 break;
1877         case EAP_TYPE_TLS:
1878                 break;
1879         }
1880
1881         if (interworking_set_eap_params(ssid, cred,
1882                                         eap->method == EAP_TYPE_TTLS) < 0)
1883                 goto fail;
1884
1885         nai_realm_free(realm, count);
1886
1887         wpa_s->next_ssid = ssid;
1888         wpa_config_update_prio_list(wpa_s->conf);
1889         if (!only_add)
1890                 interworking_reconnect(wpa_s);
1891
1892         return ssid->id;
1893
1894 fail:
1895         wpas_notify_network_removed(wpa_s, ssid);
1896         wpa_config_remove_network(wpa_s->conf, ssid->id);
1897         nai_realm_free(realm, count);
1898         return -1;
1899 }
1900
1901
1902 #ifdef PCSC_FUNCS
1903 static int interworking_pcsc_read_imsi(struct wpa_supplicant *wpa_s)
1904 {
1905         size_t len;
1906
1907         if (wpa_s->imsi[0] && wpa_s->mnc_len)
1908                 return 0;
1909
1910         len = sizeof(wpa_s->imsi) - 1;
1911         if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
1912                 scard_deinit(wpa_s->scard);
1913                 wpa_s->scard = NULL;
1914                 wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
1915                 return -1;
1916         }
1917         wpa_s->imsi[len] = '\0';
1918         wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
1919         wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
1920                    wpa_s->imsi, wpa_s->mnc_len);
1921
1922         return 0;
1923 }
1924 #endif /* PCSC_FUNCS */
1925
1926
1927 static struct wpa_cred * interworking_credentials_available_3gpp(
1928         struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
1929         int *excluded)
1930 {
1931         struct wpa_cred *selected = NULL;
1932 #ifdef INTERWORKING_3GPP
1933         struct wpa_cred *cred;
1934         int ret;
1935         int is_excluded = 0;
1936
1937         if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) {
1938                 wpa_msg(wpa_s, MSG_DEBUG,
1939                         "interworking-avail-3gpp: not avail, anqp: %p  anqp_3gpp: %p",
1940                         bss->anqp, bss->anqp ? bss->anqp->anqp_3gpp : NULL);
1941                 return NULL;
1942         }
1943
1944 #ifdef CONFIG_EAP_PROXY
1945         if (!wpa_s->imsi[0]) {
1946                 size_t len;
1947                 wpa_msg(wpa_s, MSG_DEBUG,
1948                         "Interworking: IMSI not available - try to read again through eap_proxy");
1949                 wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, -1,
1950                                                              wpa_s->imsi,
1951                                                              &len);
1952                 if (wpa_s->mnc_len > 0) {
1953                         wpa_s->imsi[len] = '\0';
1954                         wpa_msg(wpa_s, MSG_DEBUG,
1955                                 "eap_proxy: IMSI %s (MNC length %d)",
1956                                 wpa_s->imsi, wpa_s->mnc_len);
1957                 } else {
1958                         wpa_msg(wpa_s, MSG_DEBUG,
1959                                 "eap_proxy: IMSI not available");
1960                 }
1961         }
1962 #endif /* CONFIG_EAP_PROXY */
1963
1964         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1965                 char *sep;
1966                 const char *imsi;
1967                 int mnc_len;
1968                 char imsi_buf[16];
1969                 size_t msin_len;
1970
1971 #ifdef PCSC_FUNCS
1972                 if (cred->pcsc && wpa_s->scard) {
1973                         if (interworking_pcsc_read_imsi(wpa_s) < 0)
1974                                 continue;
1975                         imsi = wpa_s->imsi;
1976                         mnc_len = wpa_s->mnc_len;
1977                         goto compare;
1978                 }
1979 #endif /* PCSC_FUNCS */
1980 #ifdef CONFIG_EAP_PROXY
1981                 if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
1982                         imsi = wpa_s->imsi;
1983                         mnc_len = wpa_s->mnc_len;
1984                         goto compare;
1985                 }
1986 #endif /* CONFIG_EAP_PROXY */
1987
1988                 if (cred->imsi == NULL || !cred->imsi[0] ||
1989                     (!wpa_s->conf->external_sim &&
1990                      (cred->milenage == NULL || !cred->milenage[0])))
1991                         continue;
1992
1993                 sep = os_strchr(cred->imsi, '-');
1994                 if (sep == NULL ||
1995                     (sep - cred->imsi != 5 && sep - cred->imsi != 6))
1996                         continue;
1997                 mnc_len = sep - cred->imsi - 3;
1998                 os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
1999                 sep++;
2000                 msin_len = os_strlen(cred->imsi);
2001                 if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
2002                         msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
2003                 os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
2004                 imsi_buf[3 + mnc_len + msin_len] = '\0';
2005                 imsi = imsi_buf;
2006
2007 #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
2008         compare:
2009 #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
2010                 wpa_msg(wpa_s, MSG_DEBUG,
2011                         "Interworking: Parsing 3GPP info from " MACSTR,
2012                         MAC2STR(bss->bssid));
2013                 ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
2014                 wpa_msg(wpa_s, MSG_DEBUG, "PLMN match %sfound",
2015                         ret ? "" : "not ");
2016                 if (ret) {
2017                         if (cred_no_required_oi_match(cred, bss))
2018                                 continue;
2019                         if (!ignore_bw &&
2020                             cred_below_min_backhaul(wpa_s, cred, bss))
2021                                 continue;
2022                         if (!ignore_bw &&
2023                             cred_over_max_bss_load(wpa_s, cred, bss))
2024                                 continue;
2025                         if (!ignore_bw &&
2026                             cred_conn_capab_missing(wpa_s, cred, bss))
2027                                 continue;
2028                         if (cred_excluded_ssid(cred, bss)) {
2029                                 if (excluded == NULL)
2030                                         continue;
2031                                 if (selected == NULL) {
2032                                         selected = cred;
2033                                         is_excluded = 1;
2034                                 }
2035                         } else {
2036                                 if (selected == NULL || is_excluded ||
2037                                     cred_prio_cmp(selected, cred) < 0) {
2038                                         selected = cred;
2039                                         is_excluded = 0;
2040                                 }
2041                         }
2042                 }
2043         }
2044
2045         if (excluded)
2046                 *excluded = is_excluded;
2047 #endif /* INTERWORKING_3GPP */
2048         return selected;
2049 }
2050
2051
2052 static struct wpa_cred * interworking_credentials_available_realm(
2053         struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
2054         int *excluded)
2055 {
2056         struct wpa_cred *cred, *selected = NULL;
2057         struct nai_realm *realm;
2058         u16 count, i;
2059         int is_excluded = 0;
2060
2061         if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
2062                 return NULL;
2063
2064         if (wpa_s->conf->cred == NULL)
2065                 return NULL;
2066
2067         wpa_msg(wpa_s, MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
2068                 MACSTR, MAC2STR(bss->bssid));
2069         realm = nai_realm_parse(bss->anqp->nai_realm, &count);
2070         if (realm == NULL) {
2071                 wpa_msg(wpa_s, MSG_DEBUG,
2072                         "Interworking: Could not parse NAI Realm list from "
2073                         MACSTR, MAC2STR(bss->bssid));
2074                 return NULL;
2075         }
2076
2077         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
2078                 if (cred->realm == NULL)
2079                         continue;
2080
2081                 for (i = 0; i < count; i++) {
2082                         if (!nai_realm_match(&realm[i], cred->realm))
2083                                 continue;
2084                         if (nai_realm_find_eap(wpa_s, cred, &realm[i])) {
2085                                 if (cred_no_required_oi_match(cred, bss))
2086                                         continue;
2087                                 if (!ignore_bw &&
2088                                     cred_below_min_backhaul(wpa_s, cred, bss))
2089                                         continue;
2090                                 if (!ignore_bw &&
2091                                     cred_over_max_bss_load(wpa_s, cred, bss))
2092                                         continue;
2093                                 if (!ignore_bw &&
2094                                     cred_conn_capab_missing(wpa_s, cred, bss))
2095                                         continue;
2096                                 if (cred_excluded_ssid(cred, bss)) {
2097                                         if (excluded == NULL)
2098                                                 continue;
2099                                         if (selected == NULL) {
2100                                                 selected = cred;
2101                                                 is_excluded = 1;
2102                                         }
2103                                 } else {
2104                                         if (selected == NULL || is_excluded ||
2105                                             cred_prio_cmp(selected, cred) < 0)
2106                                         {
2107                                                 selected = cred;
2108                                                 is_excluded = 0;
2109                                         }
2110                                 }
2111                                 break;
2112                         } else {
2113                                 wpa_msg(wpa_s, MSG_DEBUG,
2114                                         "Interworking: realm-find-eap returned false");
2115                         }
2116                 }
2117         }
2118
2119         nai_realm_free(realm, count);
2120
2121         if (excluded)
2122                 *excluded = is_excluded;
2123
2124         return selected;
2125 }
2126
2127
2128 static struct wpa_cred * interworking_credentials_available_helper(
2129         struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int ignore_bw,
2130         int *excluded)
2131 {
2132         struct wpa_cred *cred, *cred2;
2133         int excluded1, excluded2 = 0;
2134
2135         if (disallowed_bssid(wpa_s, bss->bssid) ||
2136             disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
2137                 wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
2138                            MACSTR, MAC2STR(bss->bssid));
2139                 return NULL;
2140         }
2141
2142         cred = interworking_credentials_available_realm(wpa_s, bss, ignore_bw,
2143                                                         &excluded1);
2144         cred2 = interworking_credentials_available_3gpp(wpa_s, bss, ignore_bw,
2145                                                         &excluded2);
2146         if (cred && cred2 &&
2147             (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) {
2148                 cred = cred2;
2149                 excluded1 = excluded2;
2150         }
2151         if (!cred) {
2152                 cred = cred2;
2153                 excluded1 = excluded2;
2154         }
2155
2156         cred2 = interworking_credentials_available_roaming_consortium(
2157                 wpa_s, bss, ignore_bw, &excluded2);
2158         if (cred && cred2 &&
2159             (cred_prio_cmp(cred2, cred) >= 0 || (!excluded2 && excluded1))) {
2160                 cred = cred2;
2161                 excluded1 = excluded2;
2162         }
2163         if (!cred) {
2164                 cred = cred2;
2165                 excluded1 = excluded2;
2166         }
2167
2168         if (excluded)
2169                 *excluded = excluded1;
2170         return cred;
2171 }
2172
2173
2174 static struct wpa_cred * interworking_credentials_available(
2175         struct wpa_supplicant *wpa_s, struct wpa_bss *bss, int *excluded)
2176 {
2177         struct wpa_cred *cred;
2178
2179         if (excluded)
2180                 *excluded = 0;
2181         cred = interworking_credentials_available_helper(wpa_s, bss, 0,
2182                                                          excluded);
2183         if (cred)
2184                 return cred;
2185         return interworking_credentials_available_helper(wpa_s, bss, 1,
2186                                                          excluded);
2187 }
2188
2189
2190 int domain_name_list_contains(struct wpabuf *domain_names,
2191                               const char *domain, int exact_match)
2192 {
2193         const u8 *pos, *end;
2194         size_t len;
2195
2196         len = os_strlen(domain);
2197         pos = wpabuf_head(domain_names);
2198         end = pos + wpabuf_len(domain_names);
2199
2200         while (end - pos > 1) {
2201                 u8 elen;
2202
2203                 elen = *pos++;
2204                 if (elen > end - pos)
2205                         break;
2206
2207                 wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
2208                                   pos, elen);
2209                 if (elen == len &&
2210                     os_strncasecmp(domain, (const char *) pos, len) == 0)
2211                         return 1;
2212                 if (!exact_match && elen > len && pos[elen - len - 1] == '.') {
2213                         const char *ap = (const char *) pos;
2214                         int offset = elen - len;
2215
2216                         if (os_strncasecmp(domain, ap + offset, len) == 0)
2217                                 return 1;
2218                 }
2219
2220                 pos += elen;
2221         }
2222
2223         return 0;
2224 }
2225
2226
2227 int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
2228                               struct wpa_cred *cred,
2229                               struct wpabuf *domain_names)
2230 {
2231         size_t i;
2232         int ret = -1;
2233 #ifdef INTERWORKING_3GPP
2234         char nai[100], *realm;
2235
2236         char *imsi = NULL;
2237         int mnc_len = 0;
2238         if (cred->imsi)
2239                 imsi = cred->imsi;
2240 #ifdef PCSC_FUNCS
2241         else if (cred->pcsc && wpa_s->scard) {
2242                 if (interworking_pcsc_read_imsi(wpa_s) < 0)
2243                         return -1;
2244                 imsi = wpa_s->imsi;
2245                 mnc_len = wpa_s->mnc_len;
2246         }
2247 #endif /* PCSC_FUNCS */
2248 #ifdef CONFIG_EAP_PROXY
2249         else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
2250                 imsi = wpa_s->imsi;
2251                 mnc_len = wpa_s->mnc_len;
2252         }
2253 #endif /* CONFIG_EAP_PROXY */
2254         if (domain_names &&
2255             imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
2256                 realm = os_strchr(nai, '@');
2257                 if (realm)
2258                         realm++;
2259                 wpa_msg(wpa_s, MSG_DEBUG,
2260                         "Interworking: Search for match with SIM/USIM domain %s",
2261                         realm);
2262                 if (realm &&
2263                     domain_name_list_contains(domain_names, realm, 1))
2264                         return 1;
2265                 if (realm)
2266                         ret = 0;
2267         }
2268 #endif /* INTERWORKING_3GPP */
2269
2270         if (domain_names == NULL || cred->domain == NULL)
2271                 return ret;
2272
2273         for (i = 0; i < cred->num_domain; i++) {
2274                 wpa_msg(wpa_s, MSG_DEBUG,
2275                         "Interworking: Search for match with home SP FQDN %s",
2276                         cred->domain[i]);
2277                 if (domain_name_list_contains(domain_names, cred->domain[i], 1))
2278                         return 1;
2279         }
2280
2281         return 0;
2282 }
2283
2284
2285 static int interworking_home_sp(struct wpa_supplicant *wpa_s,
2286                                 struct wpabuf *domain_names)
2287 {
2288         struct wpa_cred *cred;
2289
2290         if (domain_names == NULL || wpa_s->conf->cred == NULL)
2291                 return -1;
2292
2293         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
2294                 int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
2295                 if (res)
2296                         return res;
2297         }
2298
2299         return 0;
2300 }
2301
2302
2303 static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
2304 {
2305         struct wpa_bss *bss;
2306         struct wpa_ssid *ssid;
2307
2308         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2309                 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
2310                         if (wpas_network_disabled(wpa_s, ssid) ||
2311                             ssid->mode != WPAS_MODE_INFRA)
2312                                 continue;
2313                         if (ssid->ssid_len != bss->ssid_len ||
2314                             os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
2315                             0)
2316                                 continue;
2317                         /*
2318                          * TODO: Consider more accurate matching of security
2319                          * configuration similarly to what is done in events.c
2320                          */
2321                         return 1;
2322                 }
2323         }
2324
2325         return 0;
2326 }
2327
2328
2329 static int roaming_partner_match(struct wpa_supplicant *wpa_s,
2330                                  struct roaming_partner *partner,
2331                                  struct wpabuf *domain_names)
2332 {
2333         wpa_printf(MSG_DEBUG, "Interworking: Comparing roaming_partner info fqdn='%s' exact_match=%d priority=%u country='%s'",
2334                    partner->fqdn, partner->exact_match, partner->priority,
2335                    partner->country);
2336         wpa_hexdump_ascii(MSG_DEBUG, "Interworking: Domain names",
2337                           wpabuf_head(domain_names),
2338                           wpabuf_len(domain_names));
2339         if (!domain_name_list_contains(domain_names, partner->fqdn,
2340                                        partner->exact_match))
2341                 return 0;
2342         /* TODO: match Country */
2343         return 1;
2344 }
2345
2346
2347 static u8 roaming_prio(struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
2348                        struct wpa_bss *bss)
2349 {
2350         size_t i;
2351
2352         if (bss->anqp == NULL || bss->anqp->domain_name == NULL) {
2353                 wpa_printf(MSG_DEBUG, "Interworking: No ANQP domain name info -> use default roaming partner priority 128");
2354                 return 128; /* cannot check preference with domain name */
2355         }
2356
2357         if (interworking_home_sp_cred(wpa_s, cred, bss->anqp->domain_name) > 0)
2358         {
2359                 wpa_printf(MSG_DEBUG, "Interworking: Determined to be home SP -> use maximum preference 0 as roaming partner priority");
2360                 return 0; /* max preference for home SP network */
2361         }
2362
2363         for (i = 0; i < cred->num_roaming_partner; i++) {
2364                 if (roaming_partner_match(wpa_s, &cred->roaming_partner[i],
2365                                           bss->anqp->domain_name)) {
2366                         wpa_printf(MSG_DEBUG, "Interworking: Roaming partner preference match - priority %u",
2367                                    cred->roaming_partner[i].priority);
2368                         return cred->roaming_partner[i].priority;
2369                 }
2370         }
2371
2372         wpa_printf(MSG_DEBUG, "Interworking: No roaming partner preference match - use default roaming partner priority 128");
2373         return 128;
2374 }
2375
2376
2377 static struct wpa_bss * pick_best_roaming_partner(struct wpa_supplicant *wpa_s,
2378                                                   struct wpa_bss *selected,
2379                                                   struct wpa_cred *cred)
2380 {
2381         struct wpa_bss *bss;
2382         u8 best_prio, prio;
2383         struct wpa_cred *cred2;
2384
2385         /*
2386          * Check if any other BSS is operated by a more preferred roaming
2387          * partner.
2388          */
2389
2390         best_prio = roaming_prio(wpa_s, cred, selected);
2391         wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for selected BSS "
2392                    MACSTR " (cred=%d)", best_prio, MAC2STR(selected->bssid),
2393                    cred->id);
2394
2395         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2396                 if (bss == selected)
2397                         continue;
2398                 cred2 = interworking_credentials_available(wpa_s, bss, NULL);
2399                 if (!cred2)
2400                         continue;
2401                 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN))
2402                         continue;
2403                 prio = roaming_prio(wpa_s, cred2, bss);
2404                 wpa_printf(MSG_DEBUG, "Interworking: roaming_prio=%u for BSS "
2405                            MACSTR " (cred=%d)", prio, MAC2STR(bss->bssid),
2406                            cred2->id);
2407                 if (prio < best_prio) {
2408                         int bh1, bh2, load1, load2, conn1, conn2;
2409                         bh1 = cred_below_min_backhaul(wpa_s, cred, selected);
2410                         load1 = cred_over_max_bss_load(wpa_s, cred, selected);
2411                         conn1 = cred_conn_capab_missing(wpa_s, cred, selected);
2412                         bh2 = cred_below_min_backhaul(wpa_s, cred2, bss);
2413                         load2 = cred_over_max_bss_load(wpa_s, cred2, bss);
2414                         conn2 = cred_conn_capab_missing(wpa_s, cred2, bss);
2415                         wpa_printf(MSG_DEBUG, "Interworking: old: %d %d %d  new: %d %d %d",
2416                                    bh1, load1, conn1, bh2, load2, conn2);
2417                         if (bh1 || load1 || conn1 || !(bh2 || load2 || conn2)) {
2418                                 wpa_printf(MSG_DEBUG, "Interworking: Better roaming partner " MACSTR " selected", MAC2STR(bss->bssid));
2419                                 best_prio = prio;
2420                                 selected = bss;
2421                         }
2422                 }
2423         }
2424
2425         return selected;
2426 }
2427
2428
2429 static void interworking_select_network(struct wpa_supplicant *wpa_s)
2430 {
2431         struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
2432         struct wpa_bss *selected2 = NULL, *selected2_home = NULL;
2433         unsigned int count = 0;
2434         const char *type;
2435         int res;
2436         struct wpa_cred *cred, *selected_cred = NULL;
2437         struct wpa_cred *selected_home_cred = NULL;
2438         struct wpa_cred *selected2_cred = NULL;
2439         struct wpa_cred *selected2_home_cred = NULL;
2440
2441         wpa_s->network_select = 0;
2442
2443         wpa_printf(MSG_DEBUG, "Interworking: Select network (auto_select=%d)",
2444                    wpa_s->auto_select);
2445         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2446                 int excluded = 0;
2447                 int bh, bss_load, conn_capab;
2448                 cred = interworking_credentials_available(wpa_s, bss,
2449                                                           &excluded);
2450                 if (!cred)
2451                         continue;
2452
2453                 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
2454                         /*
2455                          * We currently support only HS 2.0 networks and those
2456                          * are required to use WPA2-Enterprise.
2457                          */
2458                         wpa_msg(wpa_s, MSG_DEBUG,
2459                                 "Interworking: Credential match with " MACSTR
2460                                 " but network does not use RSN",
2461                                 MAC2STR(bss->bssid));
2462                         continue;
2463                 }
2464                 if (!excluded)
2465                         count++;
2466                 res = interworking_home_sp(wpa_s, bss->anqp ?
2467                                            bss->anqp->domain_name : NULL);
2468                 if (res > 0)
2469                         type = "home";
2470                 else if (res == 0)
2471                         type = "roaming";
2472                 else
2473                         type = "unknown";
2474                 bh = cred_below_min_backhaul(wpa_s, cred, bss);
2475                 bss_load = cred_over_max_bss_load(wpa_s, cred, bss);
2476                 conn_capab = cred_conn_capab_missing(wpa_s, cred, bss);
2477                 wpa_msg(wpa_s, MSG_INFO, "%s" MACSTR " type=%s%s%s%s id=%d priority=%d sp_priority=%d",
2478                         excluded ? INTERWORKING_BLACKLISTED : INTERWORKING_AP,
2479                         MAC2STR(bss->bssid), type,
2480                         bh ? " below_min_backhaul=1" : "",
2481                         bss_load ? " over_max_bss_load=1" : "",
2482                         conn_capab ? " conn_capab_missing=1" : "",
2483                         cred->id, cred->priority, cred->sp_priority);
2484                 if (excluded)
2485                         continue;
2486                 if (wpa_s->auto_select ||
2487                     (wpa_s->conf->auto_interworking &&
2488                      wpa_s->auto_network_select)) {
2489                         if (bh || bss_load || conn_capab) {
2490                                 if (selected2_cred == NULL ||
2491                                     cred_prio_cmp(cred, selected2_cred) > 0) {
2492                                         wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2");
2493                                         selected2 = bss;
2494                                         selected2_cred = cred;
2495                                 }
2496                                 if (res > 0 &&
2497                                     (selected2_home_cred == NULL ||
2498                                      cred_prio_cmp(cred, selected2_home_cred) >
2499                                      0)) {
2500                                         wpa_printf(MSG_DEBUG, "Interworking: Mark as selected2_home");
2501                                         selected2_home = bss;
2502                                         selected2_home_cred = cred;
2503                                 }
2504                         } else {
2505                                 if (selected_cred == NULL ||
2506                                     cred_prio_cmp(cred, selected_cred) > 0) {
2507                                         wpa_printf(MSG_DEBUG, "Interworking: Mark as selected");
2508                                         selected = bss;
2509                                         selected_cred = cred;
2510                                 }
2511                                 if (res > 0 &&
2512                                     (selected_home_cred == NULL ||
2513                                      cred_prio_cmp(cred, selected_home_cred) >
2514                                      0)) {
2515                                         wpa_printf(MSG_DEBUG, "Interworking: Mark as selected_home");
2516                                         selected_home = bss;
2517                                         selected_home_cred = cred;
2518                                 }
2519                         }
2520                 }
2521         }
2522
2523         if (selected_home && selected_home != selected &&
2524             selected_home_cred &&
2525             (selected_cred == NULL ||
2526              cred_prio_cmp(selected_home_cred, selected_cred) >= 0)) {
2527                 /* Prefer network operated by the Home SP */
2528                 wpa_printf(MSG_DEBUG, "Interworking: Overrided selected with selected_home");
2529                 selected = selected_home;
2530                 selected_cred = selected_home_cred;
2531         }
2532
2533         if (!selected) {
2534                 if (selected2_home) {
2535                         wpa_printf(MSG_DEBUG, "Interworking: Use home BSS with BW limit mismatch since no other network could be selected");
2536                         selected = selected2_home;
2537                         selected_cred = selected2_home_cred;
2538                 } else if (selected2) {
2539                         wpa_printf(MSG_DEBUG, "Interworking: Use visited BSS with BW limit mismatch since no other network could be selected");
2540                         selected = selected2;
2541                         selected_cred = selected2_cred;
2542                 }
2543         }
2544
2545         if (count == 0) {
2546                 /*
2547                  * No matching network was found based on configured
2548                  * credentials. Check whether any of the enabled network blocks
2549                  * have matching APs.
2550                  */
2551                 if (interworking_find_network_match(wpa_s)) {
2552                         wpa_msg(wpa_s, MSG_DEBUG,
2553                                 "Interworking: Possible BSS match for enabled network configurations");
2554                         if (wpa_s->auto_select) {
2555                                 interworking_reconnect(wpa_s);
2556                                 return;
2557                         }
2558                 }
2559
2560                 if (wpa_s->auto_network_select) {
2561                         wpa_msg(wpa_s, MSG_DEBUG,
2562                                 "Interworking: Continue scanning after ANQP fetch");
2563                         wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
2564                                                 0);
2565                         return;
2566                 }
2567
2568                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
2569                         "with matching credentials found");
2570                 if (wpa_s->wpa_state == WPA_SCANNING)
2571                         wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
2572         }
2573
2574         if (selected) {
2575                 wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR,
2576                            MAC2STR(selected->bssid));
2577                 selected = pick_best_roaming_partner(wpa_s, selected,
2578                                                      selected_cred);
2579                 wpa_printf(MSG_DEBUG, "Interworking: Selected " MACSTR
2580                            " (after best roaming partner selection)",
2581                            MAC2STR(selected->bssid));
2582                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_SELECTED MACSTR,
2583                         MAC2STR(selected->bssid));
2584                 interworking_connect(wpa_s, selected, 0);
2585         } else if (wpa_s->wpa_state == WPA_SCANNING)
2586                 wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
2587 }
2588
2589
2590 static struct wpa_bss_anqp *
2591 interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
2592 {
2593         struct wpa_bss *other;
2594
2595         if (is_zero_ether_addr(bss->hessid))
2596                 return NULL; /* Cannot be in the same homegenous ESS */
2597
2598         dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
2599                 if (other == bss)
2600                         continue;
2601                 if (other->anqp == NULL)
2602                         continue;
2603                 if (other->anqp->roaming_consortium == NULL &&
2604                     other->anqp->nai_realm == NULL &&
2605                     other->anqp->anqp_3gpp == NULL &&
2606                     other->anqp->domain_name == NULL)
2607                         continue;
2608                 if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
2609                         continue;
2610                 if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
2611                         continue;
2612                 if (bss->ssid_len != other->ssid_len ||
2613                     os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
2614                         continue;
2615
2616                 wpa_msg(wpa_s, MSG_DEBUG,
2617                         "Interworking: Share ANQP data with already fetched BSSID "
2618                         MACSTR " and " MACSTR,
2619                         MAC2STR(other->bssid), MAC2STR(bss->bssid));
2620                 other->anqp->users++;
2621                 return other->anqp;
2622         }
2623
2624         return NULL;
2625 }
2626
2627
2628 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
2629 {
2630         struct wpa_bss *bss;
2631         int found = 0;
2632
2633         wpa_printf(MSG_DEBUG, "Interworking: next_anqp_fetch - "
2634                    "fetch_anqp_in_progress=%d fetch_osu_icon_in_progress=%d",
2635                    wpa_s->fetch_anqp_in_progress,
2636                    wpa_s->fetch_osu_icon_in_progress);
2637
2638         if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress) {
2639                 wpa_printf(MSG_DEBUG, "Interworking: Stop next-ANQP-fetch");
2640                 return;
2641         }
2642
2643 #ifdef CONFIG_HS20
2644         if (wpa_s->fetch_osu_icon_in_progress) {
2645                 wpa_printf(MSG_DEBUG, "Interworking: Next icon (in progress)");
2646                 hs20_next_osu_icon(wpa_s);
2647                 return;
2648         }
2649 #endif /* CONFIG_HS20 */
2650
2651         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
2652                 if (!(bss->caps & IEEE80211_CAP_ESS))
2653                         continue;
2654                 if (!wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_INTERWORKING))
2655                         continue; /* AP does not support Interworking */
2656                 if (disallowed_bssid(wpa_s, bss->bssid) ||
2657                     disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
2658                         continue; /* Disallowed BSS */
2659
2660                 if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
2661                         if (bss->anqp == NULL) {
2662                                 bss->anqp = interworking_match_anqp_info(wpa_s,
2663                                                                          bss);
2664                                 if (bss->anqp) {
2665                                         /* Shared data already fetched */
2666                                         continue;
2667                                 }
2668                                 bss->anqp = wpa_bss_anqp_alloc();
2669                                 if (bss->anqp == NULL)
2670                                         break;
2671                         }
2672                         found++;
2673                         bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
2674                         wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
2675                                 MACSTR " (HESSID " MACSTR ")",
2676                                 MAC2STR(bss->bssid), MAC2STR(bss->hessid));
2677                         interworking_anqp_send_req(wpa_s, bss);
2678                         break;
2679                 }
2680         }
2681
2682         if (found == 0) {
2683 #ifdef CONFIG_HS20
2684                 if (wpa_s->fetch_osu_info) {
2685                         if (wpa_s->num_prov_found == 0 &&
2686                             wpa_s->fetch_osu_waiting_scan &&
2687                             wpa_s->num_osu_scans < 3) {
2688                                 wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again");
2689                                 hs20_start_osu_scan(wpa_s);
2690                                 return;
2691                         }
2692                         wpa_printf(MSG_DEBUG, "Interworking: Next icon");
2693                         hs20_osu_icon_fetch(wpa_s);
2694                         return;
2695                 }
2696 #endif /* CONFIG_HS20 */
2697                 wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
2698                 wpa_s->fetch_anqp_in_progress = 0;
2699                 if (wpa_s->network_select)
2700                         interworking_select_network(wpa_s);
2701         }
2702 }
2703
2704
2705 void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
2706 {
2707         struct wpa_bss *bss;
2708
2709         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
2710                 bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
2711
2712         wpa_s->fetch_anqp_in_progress = 1;
2713
2714         /*
2715          * Start actual ANQP operation from eloop call to make sure the loop
2716          * does not end up using excessive recursion.
2717          */
2718         eloop_register_timeout(0, 0, interworking_continue_anqp, wpa_s, NULL);
2719 }
2720
2721
2722 int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
2723 {
2724         if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
2725                 return 0;
2726
2727         wpa_s->network_select = 0;
2728         wpa_s->fetch_all_anqp = 1;
2729         wpa_s->fetch_osu_info = 0;
2730
2731         interworking_start_fetch_anqp(wpa_s);
2732
2733         return 0;
2734 }
2735
2736
2737 void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
2738 {
2739         if (!wpa_s->fetch_anqp_in_progress)
2740                 return;
2741
2742         wpa_s->fetch_anqp_in_progress = 0;
2743 }
2744
2745
2746 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
2747                   u16 info_ids[], size_t num_ids, u32 subtypes,
2748                   u32 mbo_subtypes)
2749 {
2750         struct wpabuf *buf;
2751         struct wpabuf *extra_buf = NULL;
2752         int ret = 0;
2753         int freq;
2754         struct wpa_bss *bss;
2755         int res;
2756
2757         bss = wpa_bss_get_bssid(wpa_s, dst);
2758         if (!bss) {
2759                 wpa_printf(MSG_WARNING,
2760                            "ANQP: Cannot send query to unknown BSS "
2761                            MACSTR, MAC2STR(dst));
2762                 return -1;
2763         }
2764
2765         wpa_bss_anqp_unshare_alloc(bss);
2766         freq = bss->freq;
2767
2768         wpa_msg(wpa_s, MSG_DEBUG,
2769                 "ANQP: Query Request to " MACSTR " for %u id(s)",
2770                 MAC2STR(dst), (unsigned int) num_ids);
2771
2772 #ifdef CONFIG_HS20
2773         if (subtypes != 0) {
2774                 extra_buf = wpabuf_alloc(100);
2775                 if (extra_buf == NULL)
2776                         return -1;
2777                 hs20_put_anqp_req(subtypes, NULL, 0, extra_buf);
2778         }
2779 #endif /* CONFIG_HS20 */
2780
2781 #ifdef CONFIG_MBO
2782         if (mbo_subtypes) {
2783                 struct wpabuf *mbo;
2784
2785                 mbo = mbo_build_anqp_buf(wpa_s, bss, mbo_subtypes);
2786                 if (mbo) {
2787                         if (wpabuf_resize(&extra_buf, wpabuf_len(mbo))) {
2788                                 wpabuf_free(extra_buf);
2789                                 wpabuf_free(mbo);
2790                                 return -1;
2791                         }
2792                         wpabuf_put_buf(extra_buf, mbo);
2793                         wpabuf_free(mbo);
2794                 }
2795         }
2796 #endif /* CONFIG_MBO */
2797
2798         buf = anqp_build_req(info_ids, num_ids, extra_buf);
2799         wpabuf_free(extra_buf);
2800         if (buf == NULL)
2801                 return -1;
2802
2803         res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
2804         if (res < 0) {
2805                 wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Failed to send Query Request");
2806                 wpabuf_free(buf);
2807                 ret = -1;
2808         } else {
2809                 wpa_msg(wpa_s, MSG_DEBUG,
2810                         "ANQP: Query started with dialog token %u", res);
2811         }
2812
2813         return ret;
2814 }
2815
2816
2817 static void anqp_add_extra(struct wpa_supplicant *wpa_s,
2818                            struct wpa_bss_anqp *anqp, u16 info_id,
2819                            const u8 *data, size_t slen)
2820 {
2821         struct wpa_bss_anqp_elem *tmp, *elem = NULL;
2822
2823         if (!anqp)
2824                 return;
2825
2826         dl_list_for_each(tmp, &anqp->anqp_elems, struct wpa_bss_anqp_elem,
2827                          list) {
2828                 if (tmp->infoid == info_id) {
2829                         elem = tmp;
2830                         break;
2831                 }
2832         }
2833
2834         if (!elem) {
2835                 elem = os_zalloc(sizeof(*elem));
2836                 if (!elem)
2837                         return;
2838                 elem->infoid = info_id;
2839                 dl_list_add(&anqp->anqp_elems, &elem->list);
2840         } else {
2841                 wpabuf_free(elem->payload);
2842         }
2843
2844         elem->payload = wpabuf_alloc_copy(data, slen);
2845         if (!elem->payload) {
2846                 dl_list_del(&elem->list);
2847                 os_free(elem);
2848         }
2849 }
2850
2851
2852 static void interworking_parse_venue_url(struct wpa_supplicant *wpa_s,
2853                                          const u8 *data, size_t len)
2854 {
2855         const u8 *pos = data, *end = data + len;
2856         char url[255];
2857
2858         while (end - pos >= 2) {
2859                 u8 slen, num;
2860
2861                 slen = *pos++;
2862                 if (slen < 1 || slen > end - pos) {
2863                         wpa_printf(MSG_DEBUG,
2864                                    "ANQP: Truncated Venue URL Duple field");
2865                         return;
2866                 }
2867
2868                 num = *pos++;
2869                 os_memcpy(url, pos, slen - 1);
2870                 url[slen - 1] = '\0';
2871                 wpa_msg(wpa_s, MSG_INFO, RX_VENUE_URL "%u %s", num, url);
2872                 pos += slen - 1;
2873         }
2874 }
2875
2876
2877 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
2878                                             struct wpa_bss *bss, const u8 *sa,
2879                                             u16 info_id,
2880                                             const u8 *data, size_t slen,
2881                                             u8 dialog_token)
2882 {
2883         const u8 *pos = data;
2884         struct wpa_bss_anqp *anqp = NULL;
2885         u8 type;
2886
2887         if (bss)
2888                 anqp = bss->anqp;
2889
2890         switch (info_id) {
2891         case ANQP_CAPABILITY_LIST:
2892                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2893                         " ANQP Capability list", MAC2STR(sa));
2894                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Capability list",
2895                                   pos, slen);
2896                 if (anqp) {
2897                         wpabuf_free(anqp->capability_list);
2898                         anqp->capability_list = wpabuf_alloc_copy(pos, slen);
2899                 }
2900                 break;
2901         case ANQP_VENUE_NAME:
2902                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2903                         " Venue Name", MAC2STR(sa));
2904                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
2905                 if (anqp) {
2906                         wpabuf_free(anqp->venue_name);
2907                         anqp->venue_name = wpabuf_alloc_copy(pos, slen);
2908                 }
2909                 break;
2910         case ANQP_NETWORK_AUTH_TYPE:
2911                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2912                         " Network Authentication Type information",
2913                         MAC2STR(sa));
2914                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
2915                                   "Type", pos, slen);
2916                 if (anqp) {
2917                         wpabuf_free(anqp->network_auth_type);
2918                         anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
2919                 }
2920                 break;
2921         case ANQP_ROAMING_CONSORTIUM:
2922                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2923                         " Roaming Consortium list", MAC2STR(sa));
2924                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
2925                                   pos, slen);
2926                 if (anqp) {
2927                         wpabuf_free(anqp->roaming_consortium);
2928                         anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
2929                 }
2930                 break;
2931         case ANQP_IP_ADDR_TYPE_AVAILABILITY:
2932                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2933                         " IP Address Type Availability information",
2934                         MAC2STR(sa));
2935                 wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
2936                             pos, slen);
2937                 if (anqp) {
2938                         wpabuf_free(anqp->ip_addr_type_availability);
2939                         anqp->ip_addr_type_availability =
2940                                 wpabuf_alloc_copy(pos, slen);
2941                 }
2942                 break;
2943         case ANQP_NAI_REALM:
2944                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2945                         " NAI Realm list", MAC2STR(sa));
2946                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
2947                 if (anqp) {
2948                         wpabuf_free(anqp->nai_realm);
2949                         anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
2950                 }
2951                 break;
2952         case ANQP_3GPP_CELLULAR_NETWORK:
2953                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2954                         " 3GPP Cellular Network information", MAC2STR(sa));
2955                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
2956                                   pos, slen);
2957                 if (anqp) {
2958                         wpabuf_free(anqp->anqp_3gpp);
2959                         anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
2960                 }
2961                 break;
2962         case ANQP_DOMAIN_NAME:
2963                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2964                         " Domain Name list", MAC2STR(sa));
2965                 wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
2966                 if (anqp) {
2967                         wpabuf_free(anqp->domain_name);
2968                         anqp->domain_name = wpabuf_alloc_copy(pos, slen);
2969                 }
2970                 break;
2971 #ifdef CONFIG_FILS
2972         case ANQP_FILS_REALM_INFO:
2973                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR
2974                         " FILS Realm Information", MAC2STR(sa));
2975                 wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: FILS Realm Information",
2976                         pos, slen);
2977                 if (anqp) {
2978                         wpabuf_free(anqp->fils_realm_info);
2979                         anqp->fils_realm_info = wpabuf_alloc_copy(pos, slen);
2980                 }
2981                 break;
2982 #endif /* CONFIG_FILS */
2983         case ANQP_VENUE_URL:
2984                 wpa_msg(wpa_s, MSG_INFO, RX_ANQP MACSTR " Venue URL",
2985                         MAC2STR(sa));
2986                 anqp_add_extra(wpa_s, anqp, info_id, pos, slen);
2987
2988                 if (!pmf_in_use(wpa_s, sa)) {
2989                         wpa_printf(MSG_DEBUG,
2990                                    "ANQP: Ignore Venue URL since PMF was not enabled");
2991                         break;
2992                 }
2993                 interworking_parse_venue_url(wpa_s, pos, slen);
2994                 break;
2995         case ANQP_VENDOR_SPECIFIC:
2996                 if (slen < 3)
2997                         return;
2998
2999                 switch (WPA_GET_BE24(pos)) {
3000                 case OUI_WFA:
3001                         pos += 3;
3002                         slen -= 3;
3003
3004                         if (slen < 1)
3005                                 return;
3006                         type = *pos++;
3007                         slen--;
3008
3009                         switch (type) {
3010 #ifdef CONFIG_HS20
3011                         case HS20_ANQP_OUI_TYPE:
3012                                 hs20_parse_rx_hs20_anqp_resp(wpa_s, bss, sa,
3013                                                              pos, slen,
3014                                                              dialog_token);
3015                                 break;
3016 #endif /* CONFIG_HS20 */
3017 #ifdef CONFIG_MBO
3018                         case MBO_ANQP_OUI_TYPE:
3019                                 mbo_parse_rx_anqp_resp(wpa_s, bss, sa,
3020                                                        pos, slen);
3021                                 break;
3022 #endif /* CONFIG_MBO */
3023                         default:
3024                                 wpa_msg(wpa_s, MSG_DEBUG,
3025                                         "ANQP: Unsupported ANQP vendor type %u",
3026                                         type);
3027                                 break;
3028                         }
3029                         break;
3030                 default:
3031                         wpa_msg(wpa_s, MSG_DEBUG,
3032                                 "Interworking: Unsupported vendor-specific ANQP OUI %06x",
3033                                 WPA_GET_BE24(pos));
3034                         return;
3035                 }
3036                 break;
3037         default:
3038                 wpa_msg(wpa_s, MSG_DEBUG,
3039                         "Interworking: Unsupported ANQP Info ID %u", info_id);
3040                 anqp_add_extra(wpa_s, anqp, info_id, data, slen);
3041                 break;
3042         }
3043 }
3044
3045
3046 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
3047                   enum gas_query_result result,
3048                   const struct wpabuf *adv_proto,
3049                   const struct wpabuf *resp, u16 status_code)
3050 {
3051         struct wpa_supplicant *wpa_s = ctx;
3052         const u8 *pos;
3053         const u8 *end;
3054         u16 info_id;
3055         u16 slen;
3056         struct wpa_bss *bss = NULL, *tmp;
3057         const char *anqp_result = "SUCCESS";
3058
3059         wpa_printf(MSG_DEBUG, "Interworking: anqp_resp_cb dst=" MACSTR
3060                    " dialog_token=%u result=%d status_code=%u",
3061                    MAC2STR(dst), dialog_token, result, status_code);
3062         if (result != GAS_QUERY_SUCCESS) {
3063 #ifdef CONFIG_HS20
3064                 if (wpa_s->fetch_osu_icon_in_progress)
3065                         hs20_icon_fetch_failed(wpa_s);
3066 #endif /* CONFIG_HS20 */
3067                 anqp_result = "FAILURE";
3068                 goto out;
3069         }
3070
3071         pos = wpabuf_head(adv_proto);
3072         if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
3073             pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
3074                 wpa_msg(wpa_s, MSG_DEBUG,
3075                         "ANQP: Unexpected Advertisement Protocol in response");
3076 #ifdef CONFIG_HS20
3077                 if (wpa_s->fetch_osu_icon_in_progress)
3078                         hs20_icon_fetch_failed(wpa_s);
3079 #endif /* CONFIG_HS20 */
3080                 anqp_result = "INVALID_FRAME";
3081                 goto out;
3082         }
3083
3084         /*
3085          * If possible, select the BSS entry based on which BSS entry was used
3086          * for the request. This can help in cases where multiple BSS entries
3087          * may exist for the same AP.
3088          */
3089         dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
3090                 if (tmp == wpa_s->interworking_gas_bss &&
3091                     os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
3092                         bss = tmp;
3093                         break;
3094                 }
3095         }
3096         if (bss == NULL)
3097                 bss = wpa_bss_get_bssid(wpa_s, dst);
3098
3099         pos = wpabuf_head(resp);
3100         end = pos + wpabuf_len(resp);
3101
3102         while (pos < end) {
3103                 unsigned int left = end - pos;
3104
3105                 if (left < 4) {
3106                         wpa_msg(wpa_s, MSG_DEBUG, "ANQP: Invalid element");
3107                         anqp_result = "INVALID_FRAME";
3108                         goto out_parse_done;
3109                 }
3110                 info_id = WPA_GET_LE16(pos);
3111                 pos += 2;
3112                 slen = WPA_GET_LE16(pos);
3113                 pos += 2;
3114                 left -= 4;
3115                 if (left < slen) {
3116                         wpa_msg(wpa_s, MSG_DEBUG,
3117                                 "ANQP: Invalid element length for Info ID %u",
3118                                 info_id);
3119                         anqp_result = "INVALID_FRAME";
3120                         goto out_parse_done;
3121                 }
3122                 interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
3123                                                 slen, dialog_token);
3124                 pos += slen;
3125         }
3126
3127 out_parse_done:
3128 #ifdef CONFIG_HS20
3129         hs20_notify_parse_done(wpa_s);
3130 #endif /* CONFIG_HS20 */
3131 out:
3132         wpa_msg(wpa_s, MSG_INFO, ANQP_QUERY_DONE "addr=" MACSTR " result=%s",
3133                 MAC2STR(dst), anqp_result);
3134 }
3135
3136
3137 static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
3138                                           struct wpa_scan_results *scan_res)
3139 {
3140         wpa_msg(wpa_s, MSG_DEBUG,
3141                 "Interworking: Scan results available - start ANQP fetch");
3142         interworking_start_fetch_anqp(wpa_s);
3143 }
3144
3145
3146 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select,
3147                         int *freqs)
3148 {
3149         interworking_stop_fetch_anqp(wpa_s);
3150         wpa_s->network_select = 1;
3151         wpa_s->auto_network_select = 0;
3152         wpa_s->auto_select = !!auto_select;
3153         wpa_s->fetch_all_anqp = 0;
3154         wpa_s->fetch_osu_info = 0;
3155         wpa_msg(wpa_s, MSG_DEBUG,
3156                 "Interworking: Start scan for network selection");
3157         wpa_s->scan_res_handler = interworking_scan_res_handler;
3158         wpa_s->normal_scans = 0;
3159         wpa_s->scan_req = MANUAL_SCAN_REQ;
3160         os_free(wpa_s->manual_scan_freqs);
3161         wpa_s->manual_scan_freqs = freqs;
3162         wpa_s->after_wps = 0;
3163         wpa_s->known_wps_freq = 0;
3164         wpa_supplicant_req_scan(wpa_s, 0, 0);
3165
3166         return 0;
3167 }
3168
3169
3170 static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
3171                         enum gas_query_result result,
3172                         const struct wpabuf *adv_proto,
3173                         const struct wpabuf *resp, u16 status_code)
3174 {
3175         struct wpa_supplicant *wpa_s = ctx;
3176         struct wpabuf *n;
3177
3178         wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
3179                 " dialog_token=%d status_code=%d resp_len=%d",
3180                 MAC2STR(addr), dialog_token, status_code,
3181                 resp ? (int) wpabuf_len(resp) : -1);
3182         if (!resp)
3183                 return;
3184
3185         n = wpabuf_dup(resp);
3186         if (n == NULL)
3187                 return;
3188         wpabuf_free(wpa_s->prev_gas_resp);
3189         wpa_s->prev_gas_resp = wpa_s->last_gas_resp;
3190         os_memcpy(wpa_s->prev_gas_addr, wpa_s->last_gas_addr, ETH_ALEN);
3191         wpa_s->prev_gas_dialog_token = wpa_s->last_gas_dialog_token;
3192         wpa_s->last_gas_resp = n;
3193         os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
3194         wpa_s->last_gas_dialog_token = dialog_token;
3195 }
3196
3197
3198 int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
3199                      const struct wpabuf *adv_proto,
3200                      const struct wpabuf *query)
3201 {
3202         struct wpabuf *buf;
3203         int ret = 0;
3204         int freq;
3205         struct wpa_bss *bss;
3206         int res;
3207         size_t len;
3208         u8 query_resp_len_limit = 0;
3209
3210         freq = wpa_s->assoc_freq;
3211         bss = wpa_bss_get_bssid(wpa_s, dst);
3212         if (bss)
3213                 freq = bss->freq;
3214         if (freq <= 0)
3215                 return -1;
3216
3217         wpa_msg(wpa_s, MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
3218                 MAC2STR(dst), freq);
3219         wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
3220         wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
3221
3222         len = 3 + wpabuf_len(adv_proto) + 2;
3223         if (query)
3224                 len += wpabuf_len(query);
3225         buf = gas_build_initial_req(0, len);
3226         if (buf == NULL)
3227                 return -1;
3228
3229         /* Advertisement Protocol IE */
3230         wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
3231         wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
3232         wpabuf_put_u8(buf, query_resp_len_limit & 0x7f);
3233         wpabuf_put_buf(buf, adv_proto);
3234
3235         /* GAS Query */
3236         if (query) {
3237                 wpabuf_put_le16(buf, wpabuf_len(query));
3238                 wpabuf_put_buf(buf, query);
3239         } else
3240                 wpabuf_put_le16(buf, 0);
3241
3242         res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, gas_resp_cb, wpa_s);
3243         if (res < 0) {
3244                 wpa_msg(wpa_s, MSG_DEBUG, "GAS: Failed to send Query Request");
3245                 wpabuf_free(buf);
3246                 ret = -1;
3247         } else
3248                 wpa_msg(wpa_s, MSG_DEBUG,
3249                         "GAS: Query started with dialog token %u", res);
3250
3251         return ret;
3252 }