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