6f50c9726722079dfa938957d39d5447a1dafbe7
[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                 /* Only tunneled methods with username/password supported */
525                 return 0;
526         }
527
528         if (eap->method == EAP_TYPE_PEAP) {
529                 if (eap->inner_method &&
530                     eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
531                         return 0;
532                 if (!eap->inner_method &&
533                     eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL)
534                         return 0;
535         }
536
537         if (eap->method == EAP_TYPE_TTLS) {
538                 if (eap->inner_method == 0 && eap->inner_non_eap == 0)
539                         return 1; /* Assume TTLS/MSCHAPv2 is used */
540                 if (eap->inner_method &&
541                     eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
542                         return 0;
543                 if (eap->inner_non_eap &&
544                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
545                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
546                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
547                     eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
548                         return 0;
549         }
550
551         if (eap->inner_method &&
552             eap->inner_method != EAP_TYPE_GTC &&
553             eap->inner_method != EAP_TYPE_MSCHAPV2)
554                 return 0;
555
556         return 1;
557 }
558
559
560 static int nai_realm_cred_cert(struct nai_realm_eap *eap)
561 {
562         if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
563                 return 0; /* method not supported */
564
565         if (eap->method != EAP_TYPE_TLS) {
566                 /* Only EAP-TLS supported for credential authentication */
567                 return 0;
568         }
569
570         return 1;
571 }
572
573
574 static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
575                                                  struct nai_realm *realm)
576 {
577         u8 e;
578
579         if (cred == NULL ||
580             cred->username == NULL ||
581             cred->username[0] == '\0' ||
582             ((cred->password == NULL ||
583               cred->password[0] == '\0') &&
584              (cred->private_key == NULL ||
585               cred->private_key[0] == '\0')))
586                 return NULL;
587
588         for (e = 0; e < realm->eap_count; e++) {
589                 struct nai_realm_eap *eap = &realm->eap[e];
590                 if (cred->password && cred->password[0] &&
591                     nai_realm_cred_username(eap))
592                         return eap;
593                 if (cred->private_key && cred->private_key[0] &&
594                     nai_realm_cred_cert(eap))
595                         return eap;
596         }
597
598         return NULL;
599 }
600
601
602 #ifdef INTERWORKING_3GPP
603
604 static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
605 {
606         u8 plmn[3], plmn2[3];
607         const u8 *pos, *end;
608         u8 udhl;
609
610         /*
611          * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
612          * operator is allowed to include only two digits of the MNC, so allow
613          * matches based on both two and three digit MNC assumptions. Since some
614          * SIM/USIM cards may not expose MNC length conveniently, we may be
615          * provided the default MNC length 3 here and as such, checking with MNC
616          * length 2 is justifiable even though 3GPP TS 24.234 does not mention
617          * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
618          * with otherwise matching values would not be good idea in general, so
619          * this should not result in selecting incorrect networks.
620          */
621         /* Match with 3 digit MNC */
622         plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
623         plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
624         plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
625         /* Match with 2 digit MNC */
626         plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
627         plmn2[1] = (imsi[2] - '0') | 0xf0;
628         plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
629
630         if (anqp == NULL)
631                 return 0;
632         pos = wpabuf_head_u8(anqp);
633         end = pos + wpabuf_len(anqp);
634         if (pos + 2 > end)
635                 return 0;
636         if (*pos != 0) {
637                 wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
638                 return 0;
639         }
640         pos++;
641         udhl = *pos++;
642         if (pos + udhl > end) {
643                 wpa_printf(MSG_DEBUG, "Invalid UDHL");
644                 return 0;
645         }
646         end = pos + udhl;
647
648         wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
649                    plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
650                    imsi, mnc_len);
651
652         while (pos + 2 <= end) {
653                 u8 iei, len;
654                 const u8 *l_end;
655                 iei = *pos++;
656                 len = *pos++ & 0x7f;
657                 if (pos + len > end)
658                         break;
659                 l_end = pos + len;
660
661                 if (iei == 0 && len > 0) {
662                         /* PLMN List */
663                         u8 num, i;
664                         wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
665                                     pos, len);
666                         num = *pos++;
667                         for (i = 0; i < num; i++) {
668                                 if (pos + 3 > l_end)
669                                         break;
670                                 if (os_memcmp(pos, plmn, 3) == 0 ||
671                                     os_memcmp(pos, plmn2, 3) == 0)
672                                         return 1; /* Found matching PLMN */
673                                 pos += 3;
674                         }
675                 } else {
676                         wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
677                                     pos, len);
678                 }
679
680                 pos = l_end;
681         }
682
683         return 0;
684 }
685
686
687 static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
688                           size_t mnc_len, char prefix)
689 {
690         const char *sep, *msin;
691         char *end, *pos;
692         size_t msin_len, plmn_len;
693
694         /*
695          * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
696          * Root NAI:
697          * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
698          * <MNC> is zero-padded to three digits in case two-digit MNC is used
699          */
700
701         if (imsi == NULL || os_strlen(imsi) > 16) {
702                 wpa_printf(MSG_DEBUG, "No valid IMSI available");
703                 return -1;
704         }
705         sep = os_strchr(imsi, '-');
706         if (sep) {
707                 plmn_len = sep - imsi;
708                 msin = sep + 1;
709         } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
710                 plmn_len = 3 + mnc_len;
711                 msin = imsi + plmn_len;
712         } else
713                 return -1;
714         if (plmn_len != 5 && plmn_len != 6)
715                 return -1;
716         msin_len = os_strlen(msin);
717
718         pos = nai;
719         end = nai + nai_len;
720         if (prefix)
721                 *pos++ = prefix;
722         os_memcpy(pos, imsi, plmn_len);
723         pos += plmn_len;
724         os_memcpy(pos, msin, msin_len);
725         pos += msin_len;
726         pos += os_snprintf(pos, end - pos, "@wlan.mnc");
727         if (plmn_len == 5) {
728                 *pos++ = '0';
729                 *pos++ = imsi[3];
730                 *pos++ = imsi[4];
731         } else {
732                 *pos++ = imsi[3];
733                 *pos++ = imsi[4];
734                 *pos++ = imsi[5];
735         }
736         pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
737                            imsi[0], imsi[1], imsi[2]);
738
739         return 0;
740 }
741
742
743 static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
744 {
745         char nai[100];
746         if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
747                 return -1;
748         return wpa_config_set_quoted(ssid, "identity", nai);
749 }
750
751 #endif /* INTERWORKING_3GPP */
752
753
754 static int already_connected(struct wpa_supplicant *wpa_s,
755                              struct wpa_cred *cred, struct wpa_bss *bss)
756 {
757         struct wpa_ssid *ssid;
758
759         if (wpa_s->wpa_state < WPA_ASSOCIATED || wpa_s->current_ssid == NULL)
760                 return 0;
761
762         ssid = wpa_s->current_ssid;
763         if (ssid->parent_cred != cred)
764                 return 0;
765
766         if (ssid->ssid_len != bss->ssid_len ||
767             os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
768                 return 0;
769
770         return 1;
771 }
772
773
774 static void remove_duplicate_network(struct wpa_supplicant *wpa_s,
775                                      struct wpa_cred *cred,
776                                      struct wpa_bss *bss)
777 {
778         struct wpa_ssid *ssid;
779
780         for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
781                 if (ssid->parent_cred != cred)
782                         continue;
783                 if (ssid->ssid_len != bss->ssid_len ||
784                     os_memcmp(ssid->ssid, bss->ssid, bss->ssid_len) != 0)
785                         continue;
786
787                 break;
788         }
789
790         if (ssid == NULL)
791                 return;
792
793         wpa_printf(MSG_DEBUG, "Interworking: Remove duplicate network entry for the same credential");
794
795         if (ssid == wpa_s->current_ssid) {
796                 wpa_sm_set_config(wpa_s->wpa, NULL);
797                 eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
798                 wpa_supplicant_deauthenticate(wpa_s,
799                                               WLAN_REASON_DEAUTH_LEAVING);
800         }
801
802         wpas_notify_network_removed(wpa_s, ssid);
803         wpa_config_remove_network(wpa_s->conf, ssid->id);
804 }
805
806
807 static int interworking_set_hs20_params(struct wpa_supplicant *wpa_s,
808                                         struct wpa_ssid *ssid)
809 {
810         if (wpa_config_set(ssid, "key_mgmt",
811                            wpa_s->conf->pmf != NO_MGMT_FRAME_PROTECTION ?
812                            "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
813                 return -1;
814         if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
815                 return -1;
816         if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
817                 return -1;
818         return 0;
819 }
820
821
822 static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
823                                      struct wpa_cred *cred,
824                                      struct wpa_bss *bss)
825 {
826 #ifdef INTERWORKING_3GPP
827         struct wpa_ssid *ssid;
828         const u8 *ie;
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         ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
837         if (ie == NULL)
838                 return -1;
839         wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
840                    MAC2STR(bss->bssid));
841
842         if (already_connected(wpa_s, cred, bss)) {
843                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
844                         MAC2STR(bss->bssid));
845                 return 0;
846         }
847
848         remove_duplicate_network(wpa_s, cred, bss);
849
850         ssid = wpa_config_add_network(wpa_s->conf);
851         if (ssid == NULL)
852                 return -1;
853         ssid->parent_cred = cred;
854
855         wpas_notify_network_added(wpa_s, ssid);
856         wpa_config_set_network_defaults(ssid);
857         ssid->priority = cred->priority;
858         ssid->temporary = 1;
859         ssid->ssid = os_zalloc(ie[1] + 1);
860         if (ssid->ssid == NULL)
861                 goto fail;
862         os_memcpy(ssid->ssid, ie + 2, ie[1]);
863         ssid->ssid_len = ie[1];
864
865         if (interworking_set_hs20_params(wpa_s, ssid) < 0)
866                 goto fail;
867
868         eap_type = EAP_TYPE_SIM;
869         if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
870                 eap_type = EAP_TYPE_AKA;
871         if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
872                 if (cred->eap_method[0].method == EAP_TYPE_SIM ||
873                     cred->eap_method[0].method == EAP_TYPE_AKA ||
874                     cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
875                         eap_type = cred->eap_method[0].method;
876         }
877
878         switch (eap_type) {
879         case EAP_TYPE_SIM:
880                 prefix = '1';
881                 res = wpa_config_set(ssid, "eap", "SIM", 0);
882                 break;
883         case EAP_TYPE_AKA:
884                 prefix = '0';
885                 res = wpa_config_set(ssid, "eap", "AKA", 0);
886                 break;
887         case EAP_TYPE_AKA_PRIME:
888                 prefix = '6';
889                 res = wpa_config_set(ssid, "eap", "AKA'", 0);
890                 break;
891         default:
892                 res = -1;
893                 break;
894         }
895         if (res < 0) {
896                 wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
897                            eap_type);
898                 goto fail;
899         }
900
901         if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
902                 wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
903                 goto fail;
904         }
905
906         if (cred->milenage && cred->milenage[0]) {
907                 if (wpa_config_set_quoted(ssid, "password",
908                                           cred->milenage) < 0)
909                         goto fail;
910         } else if (cred->pcsc) {
911                 if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
912                         goto fail;
913                 if (wpa_s->conf->pcsc_pin &&
914                     wpa_config_set_quoted(ssid, "pin", wpa_s->conf->pcsc_pin)
915                     < 0)
916                         goto fail;
917         }
918
919         if (cred->password && cred->password[0] &&
920             wpa_config_set_quoted(ssid, "password", cred->password) < 0)
921                 goto fail;
922
923         wpa_config_update_prio_list(wpa_s->conf);
924         interworking_reconnect(wpa_s);
925
926         return 0;
927
928 fail:
929         wpas_notify_network_removed(wpa_s, ssid);
930         wpa_config_remove_network(wpa_s->conf, ssid->id);
931 #endif /* INTERWORKING_3GPP */
932         return -1;
933 }
934
935
936 static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
937                                             size_t rc_len)
938 {
939         const u8 *pos, *end;
940         u8 lens;
941
942         if (ie == NULL)
943                 return 0;
944
945         pos = ie + 2;
946         end = ie + 2 + ie[1];
947
948         /* Roaming Consortium element:
949          * Number of ANQP OIs
950          * OI #1 and #2 lengths
951          * OI #1, [OI #2], [OI #3]
952          */
953
954         if (pos + 2 > end)
955                 return 0;
956
957         pos++; /* skip Number of ANQP OIs */
958         lens = *pos++;
959         if (pos + (lens & 0x0f) + (lens >> 4) > end)
960                 return 0;
961
962         if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
963                 return 1;
964         pos += lens & 0x0f;
965
966         if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
967                 return 1;
968         pos += lens >> 4;
969
970         if (pos < end && (size_t) (end - pos) == rc_len &&
971             os_memcmp(pos, rc_id, rc_len) == 0)
972                 return 1;
973
974         return 0;
975 }
976
977
978 static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
979                                          const u8 *rc_id, size_t rc_len)
980 {
981         const u8 *pos, *end;
982         u8 len;
983
984         if (anqp == NULL)
985                 return 0;
986
987         pos = wpabuf_head(anqp);
988         end = pos + wpabuf_len(anqp);
989
990         /* Set of <OI Length, OI> duples */
991         while (pos < end) {
992                 len = *pos++;
993                 if (pos + len > end)
994                         break;
995                 if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
996                         return 1;
997                 pos += len;
998         }
999
1000         return 0;
1001 }
1002
1003
1004 static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
1005                                     const u8 *rc_id, size_t rc_len)
1006 {
1007         return roaming_consortium_element_match(ie, rc_id, rc_len) ||
1008                 roaming_consortium_anqp_match(anqp, rc_id, rc_len);
1009 }
1010
1011
1012 static int cred_no_required_oi_match(struct wpa_cred *cred, struct wpa_bss *bss)
1013 {
1014         const u8 *ie;
1015
1016         if (cred->required_roaming_consortium_len == 0)
1017                 return 0;
1018
1019         ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
1020
1021         if (ie == NULL &&
1022             (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
1023                 return 1;
1024
1025         return !roaming_consortium_match(ie,
1026                                          bss->anqp ?
1027                                          bss->anqp->roaming_consortium : NULL,
1028                                          cred->required_roaming_consortium,
1029                                          cred->required_roaming_consortium_len);
1030 }
1031
1032
1033 static int cred_excluded_ssid(struct wpa_cred *cred, struct wpa_bss *bss)
1034 {
1035         size_t i;
1036
1037         if (!cred->excluded_ssid)
1038                 return 0;
1039
1040         for (i = 0; i < cred->num_excluded_ssid; i++) {
1041                 struct excluded_ssid *e = &cred->excluded_ssid[i];
1042                 if (bss->ssid_len == e->ssid_len &&
1043                     os_memcmp(bss->ssid, e->ssid, e->ssid_len) == 0)
1044                         return 1;
1045         }
1046
1047         return 0;
1048 }
1049
1050
1051 static struct wpa_cred * interworking_credentials_available_roaming_consortium(
1052         struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1053 {
1054         struct wpa_cred *cred, *selected = NULL;
1055         const u8 *ie;
1056
1057         ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
1058
1059         if (ie == NULL &&
1060             (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
1061                 return NULL;
1062
1063         if (wpa_s->conf->cred == NULL)
1064                 return NULL;
1065
1066         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1067                 if (cred->roaming_consortium_len == 0)
1068                         continue;
1069
1070                 if (!roaming_consortium_match(ie,
1071                                               bss->anqp ?
1072                                               bss->anqp->roaming_consortium :
1073                                               NULL,
1074                                               cred->roaming_consortium,
1075                                               cred->roaming_consortium_len))
1076                         continue;
1077
1078                 if (cred_excluded_ssid(cred, bss))
1079                         continue;
1080                 if (cred_no_required_oi_match(cred, bss))
1081                         continue;
1082
1083                 if (selected == NULL ||
1084                     selected->priority < cred->priority)
1085                         selected = cred;
1086         }
1087
1088         return selected;
1089 }
1090
1091
1092 static int interworking_set_eap_params(struct wpa_ssid *ssid,
1093                                        struct wpa_cred *cred, int ttls)
1094 {
1095         if (cred->eap_method) {
1096                 ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
1097                         cred->eap_method->method == EAP_TYPE_TTLS;
1098
1099                 os_free(ssid->eap.eap_methods);
1100                 ssid->eap.eap_methods =
1101                         os_malloc(sizeof(struct eap_method_type) * 2);
1102                 if (ssid->eap.eap_methods == NULL)
1103                         return -1;
1104                 os_memcpy(ssid->eap.eap_methods, cred->eap_method,
1105                           sizeof(*cred->eap_method));
1106                 ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
1107                 ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
1108         }
1109
1110         if (ttls && cred->username && cred->username[0]) {
1111                 const char *pos;
1112                 char *anon;
1113                 /* Use anonymous NAI in Phase 1 */
1114                 pos = os_strchr(cred->username, '@');
1115                 if (pos) {
1116                         size_t buflen = 9 + os_strlen(pos) + 1;
1117                         anon = os_malloc(buflen);
1118                         if (anon == NULL)
1119                                 return -1;
1120                         os_snprintf(anon, buflen, "anonymous%s", pos);
1121                 } else if (cred->realm) {
1122                         size_t buflen = 10 + os_strlen(cred->realm) + 1;
1123                         anon = os_malloc(buflen);
1124                         if (anon == NULL)
1125                                 return -1;
1126                         os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
1127                 } else {
1128                         anon = os_strdup("anonymous");
1129                         if (anon == NULL)
1130                                 return -1;
1131                 }
1132                 if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
1133                     0) {
1134                         os_free(anon);
1135                         return -1;
1136                 }
1137                 os_free(anon);
1138         }
1139
1140         if (cred->username && cred->username[0] &&
1141             wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
1142                 return -1;
1143
1144         if (cred->password && cred->password[0]) {
1145                 if (cred->ext_password &&
1146                     wpa_config_set(ssid, "password", cred->password, 0) < 0)
1147                         return -1;
1148                 if (!cred->ext_password &&
1149                     wpa_config_set_quoted(ssid, "password", cred->password) <
1150                     0)
1151                         return -1;
1152         }
1153
1154         if (cred->client_cert && cred->client_cert[0] &&
1155             wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
1156                 return -1;
1157
1158 #ifdef ANDROID
1159         if (cred->private_key &&
1160             os_strncmp(cred->private_key, "keystore://", 11) == 0) {
1161                 /* Use OpenSSL engine configuration for Android keystore */
1162                 if (wpa_config_set_quoted(ssid, "engine_id", "keystore") < 0 ||
1163                     wpa_config_set_quoted(ssid, "key_id",
1164                                           cred->private_key + 11) < 0 ||
1165                     wpa_config_set(ssid, "engine", "1", 0) < 0)
1166                         return -1;
1167         } else
1168 #endif /* ANDROID */
1169         if (cred->private_key && cred->private_key[0] &&
1170             wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
1171                 return -1;
1172
1173         if (cred->private_key_passwd && cred->private_key_passwd[0] &&
1174             wpa_config_set_quoted(ssid, "private_key_passwd",
1175                                   cred->private_key_passwd) < 0)
1176                 return -1;
1177
1178         if (cred->phase1) {
1179                 os_free(ssid->eap.phase1);
1180                 ssid->eap.phase1 = os_strdup(cred->phase1);
1181         }
1182         if (cred->phase2) {
1183                 os_free(ssid->eap.phase2);
1184                 ssid->eap.phase2 = os_strdup(cred->phase2);
1185         }
1186
1187         if (cred->ca_cert && cred->ca_cert[0] &&
1188             wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
1189                 return -1;
1190
1191         if (cred->domain_suffix_match && cred->domain_suffix_match[0] &&
1192             wpa_config_set_quoted(ssid, "domain_suffix_match",
1193                                   cred->domain_suffix_match) < 0)
1194                 return -1;
1195
1196         return 0;
1197 }
1198
1199
1200 static int interworking_connect_roaming_consortium(
1201         struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
1202         struct wpa_bss *bss, const u8 *ssid_ie)
1203 {
1204         struct wpa_ssid *ssid;
1205
1206         wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
1207                    "roaming consortium match", MAC2STR(bss->bssid));
1208
1209         if (already_connected(wpa_s, cred, bss)) {
1210                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
1211                         MAC2STR(bss->bssid));
1212                 return 0;
1213         }
1214
1215         remove_duplicate_network(wpa_s, cred, bss);
1216
1217         ssid = wpa_config_add_network(wpa_s->conf);
1218         if (ssid == NULL)
1219                 return -1;
1220         ssid->parent_cred = cred;
1221         wpas_notify_network_added(wpa_s, ssid);
1222         wpa_config_set_network_defaults(ssid);
1223         ssid->priority = cred->priority;
1224         ssid->temporary = 1;
1225         ssid->ssid = os_zalloc(ssid_ie[1] + 1);
1226         if (ssid->ssid == NULL)
1227                 goto fail;
1228         os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
1229         ssid->ssid_len = ssid_ie[1];
1230
1231         if (interworking_set_hs20_params(wpa_s, ssid) < 0)
1232                 goto fail;
1233
1234         if (cred->eap_method == NULL) {
1235                 wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
1236                            "credential using roaming consortium");
1237                 goto fail;
1238         }
1239
1240         if (interworking_set_eap_params(
1241                     ssid, cred,
1242                     cred->eap_method->vendor == EAP_VENDOR_IETF &&
1243                     cred->eap_method->method == EAP_TYPE_TTLS) < 0)
1244                 goto fail;
1245
1246         wpa_config_update_prio_list(wpa_s->conf);
1247         interworking_reconnect(wpa_s);
1248
1249         return 0;
1250
1251 fail:
1252         wpas_notify_network_removed(wpa_s, ssid);
1253         wpa_config_remove_network(wpa_s->conf, ssid->id);
1254         return -1;
1255 }
1256
1257
1258 int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1259 {
1260         struct wpa_cred *cred, *cred_rc, *cred_3gpp;
1261         struct wpa_ssid *ssid;
1262         struct nai_realm *realm;
1263         struct nai_realm_eap *eap = NULL;
1264         u16 count, i;
1265         char buf[100];
1266         const u8 *ie;
1267
1268         if (wpa_s->conf->cred == NULL || bss == NULL)
1269                 return -1;
1270         if (disallowed_bssid(wpa_s, bss->bssid) ||
1271             disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
1272                 wpa_printf(MSG_DEBUG, "Interworking: Reject connection to disallowed BSS "
1273                            MACSTR, MAC2STR(bss->bssid));
1274                 return -1;
1275         }
1276         ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
1277         if (ie == NULL || ie[1] == 0) {
1278                 wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
1279                            MACSTR, MAC2STR(bss->bssid));
1280                 return -1;
1281         }
1282
1283         if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
1284                 /*
1285                  * We currently support only HS 2.0 networks and those are
1286                  * required to use WPA2-Enterprise.
1287                  */
1288                 wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
1289                            "RSN");
1290                 return -1;
1291         }
1292
1293         cred_rc = interworking_credentials_available_roaming_consortium(wpa_s,
1294                                                                         bss);
1295         if (cred_rc) {
1296                 wpa_printf(MSG_DEBUG, "Interworking: Highest roaming "
1297                            "consortium matching credential priority %d",
1298                            cred_rc->priority);
1299         }
1300
1301         cred = interworking_credentials_available_realm(wpa_s, bss);
1302         if (cred) {
1303                 wpa_printf(MSG_DEBUG, "Interworking: Highest NAI Realm list "
1304                            "matching credential priority %d",
1305                            cred->priority);
1306         }
1307
1308         cred_3gpp = interworking_credentials_available_3gpp(wpa_s, bss);
1309         if (cred_3gpp) {
1310                 wpa_printf(MSG_DEBUG, "Interworking: Highest 3GPP matching "
1311                            "credential priority %d", cred_3gpp->priority);
1312         }
1313
1314         if (cred_rc &&
1315             (cred == NULL || cred_rc->priority >= cred->priority) &&
1316             (cred_3gpp == NULL || cred_rc->priority >= cred_3gpp->priority))
1317                 return interworking_connect_roaming_consortium(wpa_s, cred_rc,
1318                                                                bss, ie);
1319
1320         if (cred_3gpp &&
1321             (cred == NULL || cred_3gpp->priority >= cred->priority)) {
1322                 return interworking_connect_3gpp(wpa_s, cred_3gpp, bss);
1323         }
1324
1325         if (cred == NULL) {
1326                 wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
1327                            "found for " MACSTR, MAC2STR(bss->bssid));
1328                 return -1;
1329         }
1330
1331         realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
1332                                 &count);
1333         if (realm == NULL) {
1334                 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
1335                            "Realm list from " MACSTR, MAC2STR(bss->bssid));
1336                 return -1;
1337         }
1338
1339         for (i = 0; i < count; i++) {
1340                 if (!nai_realm_match(&realm[i], cred->realm))
1341                         continue;
1342                 eap = nai_realm_find_eap(cred, &realm[i]);
1343                 if (eap)
1344                         break;
1345         }
1346
1347         if (!eap) {
1348                 wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
1349                            "and EAP method found for " MACSTR,
1350                            MAC2STR(bss->bssid));
1351                 nai_realm_free(realm, count);
1352                 return -1;
1353         }
1354
1355         wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
1356                    MAC2STR(bss->bssid));
1357
1358         if (already_connected(wpa_s, cred, bss)) {
1359                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_ALREADY_CONNECTED MACSTR,
1360                         MAC2STR(bss->bssid));
1361                 nai_realm_free(realm, count);
1362                 return 0;
1363         }
1364
1365         remove_duplicate_network(wpa_s, cred, bss);
1366
1367         ssid = wpa_config_add_network(wpa_s->conf);
1368         if (ssid == NULL) {
1369                 nai_realm_free(realm, count);
1370                 return -1;
1371         }
1372         ssid->parent_cred = cred;
1373         wpas_notify_network_added(wpa_s, ssid);
1374         wpa_config_set_network_defaults(ssid);
1375         ssid->priority = cred->priority;
1376         ssid->temporary = 1;
1377         ssid->ssid = os_zalloc(ie[1] + 1);
1378         if (ssid->ssid == NULL)
1379                 goto fail;
1380         os_memcpy(ssid->ssid, ie + 2, ie[1]);
1381         ssid->ssid_len = ie[1];
1382
1383         if (interworking_set_hs20_params(wpa_s, ssid) < 0)
1384                 goto fail;
1385
1386         if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
1387                                                      eap->method), 0) < 0)
1388                 goto fail;
1389
1390         switch (eap->method) {
1391         case EAP_TYPE_TTLS:
1392                 if (eap->inner_method) {
1393                         os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
1394                                     eap_get_name(EAP_VENDOR_IETF,
1395                                                  eap->inner_method));
1396                         if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
1397                                 goto fail;
1398                         break;
1399                 }
1400                 switch (eap->inner_non_eap) {
1401                 case NAI_REALM_INNER_NON_EAP_PAP:
1402                         if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
1403                             0)
1404                                 goto fail;
1405                         break;
1406                 case NAI_REALM_INNER_NON_EAP_CHAP:
1407                         if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
1408                             < 0)
1409                                 goto fail;
1410                         break;
1411                 case NAI_REALM_INNER_NON_EAP_MSCHAP:
1412                         if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAP\"",
1413                                            0) < 0)
1414                                 goto fail;
1415                         break;
1416                 case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
1417                         if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
1418                                            0) < 0)
1419                                 goto fail;
1420                         break;
1421                 default:
1422                         /* EAP params were not set - assume TTLS/MSCHAPv2 */
1423                         if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
1424                                            0) < 0)
1425                                 goto fail;
1426                         break;
1427                 }
1428                 break;
1429         case EAP_TYPE_PEAP:
1430                 os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
1431                             eap_get_name(EAP_VENDOR_IETF,
1432                                          eap->inner_method ?
1433                                          eap->inner_method :
1434                                          EAP_TYPE_MSCHAPV2));
1435                 if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
1436                         goto fail;
1437                 break;
1438         case EAP_TYPE_TLS:
1439                 break;
1440         }
1441
1442         if (interworking_set_eap_params(ssid, cred,
1443                                         eap->method == EAP_TYPE_TTLS) < 0)
1444                 goto fail;
1445
1446         nai_realm_free(realm, count);
1447
1448         wpa_config_update_prio_list(wpa_s->conf);
1449         interworking_reconnect(wpa_s);
1450
1451         return 0;
1452
1453 fail:
1454         wpas_notify_network_removed(wpa_s, ssid);
1455         wpa_config_remove_network(wpa_s->conf, ssid->id);
1456         nai_realm_free(realm, count);
1457         return -1;
1458 }
1459
1460
1461 static struct wpa_cred * interworking_credentials_available_3gpp(
1462         struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1463 {
1464         struct wpa_cred *selected = NULL;
1465 #ifdef INTERWORKING_3GPP
1466         struct wpa_cred *cred;
1467         int ret;
1468
1469         if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
1470                 return NULL;
1471
1472 #ifdef CONFIG_EAP_PROXY
1473         if (!wpa_s->imsi[0]) {
1474                 size_t len;
1475                 wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy");
1476                 wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol,
1477                                                              wpa_s->imsi,
1478                                                              &len);
1479                 if (wpa_s->mnc_len > 0) {
1480                         wpa_s->imsi[len] = '\0';
1481                         wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)",
1482                                    wpa_s->imsi, wpa_s->mnc_len);
1483                 } else {
1484                         wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available");
1485                 }
1486         }
1487 #endif /* CONFIG_EAP_PROXY */
1488
1489         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1490                 char *sep;
1491                 const char *imsi;
1492                 int mnc_len;
1493                 char imsi_buf[16];
1494                 size_t msin_len;
1495
1496 #ifdef PCSC_FUNCS
1497                 if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
1498                     wpa_s->imsi[0]) {
1499                         imsi = wpa_s->imsi;
1500                         mnc_len = wpa_s->mnc_len;
1501                         goto compare;
1502                 }
1503 #endif /* PCSC_FUNCS */
1504 #ifdef CONFIG_EAP_PROXY
1505                 if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
1506                         imsi = wpa_s->imsi;
1507                         mnc_len = wpa_s->mnc_len;
1508                         goto compare;
1509                 }
1510 #endif /* CONFIG_EAP_PROXY */
1511
1512                 if (cred->imsi == NULL || !cred->imsi[0] ||
1513                     (!wpa_s->conf->external_sim &&
1514                      (cred->milenage == NULL || !cred->milenage[0])))
1515                         continue;
1516
1517                 sep = os_strchr(cred->imsi, '-');
1518                 if (sep == NULL ||
1519                     (sep - cred->imsi != 5 && sep - cred->imsi != 6))
1520                         continue;
1521                 mnc_len = sep - cred->imsi - 3;
1522                 os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
1523                 sep++;
1524                 msin_len = os_strlen(cred->imsi);
1525                 if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
1526                         msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
1527                 os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
1528                 imsi_buf[3 + mnc_len + msin_len] = '\0';
1529                 imsi = imsi_buf;
1530
1531 #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
1532         compare:
1533 #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
1534                 wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
1535                            MACSTR, MAC2STR(bss->bssid));
1536                 ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
1537                 wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
1538                 if (ret) {
1539                         if (cred_excluded_ssid(cred, bss))
1540                                 continue;
1541                         if (cred_no_required_oi_match(cred, bss))
1542                                 continue;
1543                         if (selected == NULL ||
1544                             selected->priority < cred->priority)
1545                                 selected = cred;
1546                 }
1547         }
1548 #endif /* INTERWORKING_3GPP */
1549         return selected;
1550 }
1551
1552
1553 static struct wpa_cred * interworking_credentials_available_realm(
1554         struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1555 {
1556         struct wpa_cred *cred, *selected = NULL;
1557         struct nai_realm *realm;
1558         u16 count, i;
1559
1560         if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
1561                 return NULL;
1562
1563         if (wpa_s->conf->cred == NULL)
1564                 return NULL;
1565
1566         wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
1567                    MACSTR, MAC2STR(bss->bssid));
1568         realm = nai_realm_parse(bss->anqp->nai_realm, &count);
1569         if (realm == NULL) {
1570                 wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
1571                            "Realm list from " MACSTR, MAC2STR(bss->bssid));
1572                 return NULL;
1573         }
1574
1575         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1576                 if (cred->realm == NULL)
1577                         continue;
1578
1579                 for (i = 0; i < count; i++) {
1580                         if (!nai_realm_match(&realm[i], cred->realm))
1581                                 continue;
1582                         if (nai_realm_find_eap(cred, &realm[i])) {
1583                                 if (cred_excluded_ssid(cred, bss))
1584                                         continue;
1585                                 if (cred_no_required_oi_match(cred, bss))
1586                                         continue;
1587                                 if (selected == NULL ||
1588                                     selected->priority < cred->priority)
1589                                         selected = cred;
1590                                 break;
1591                         }
1592                 }
1593         }
1594
1595         nai_realm_free(realm, count);
1596
1597         return selected;
1598 }
1599
1600
1601 static struct wpa_cred * interworking_credentials_available(
1602         struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1603 {
1604         struct wpa_cred *cred, *cred2;
1605
1606         if (disallowed_bssid(wpa_s, bss->bssid) ||
1607             disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
1608                 wpa_printf(MSG_DEBUG, "Interworking: Ignore disallowed BSS "
1609                            MACSTR, MAC2STR(bss->bssid));
1610                 return NULL;
1611         }
1612
1613         cred = interworking_credentials_available_realm(wpa_s, bss);
1614         cred2 = interworking_credentials_available_3gpp(wpa_s, bss);
1615         if (cred && cred2 && cred2->priority >= cred->priority)
1616                 cred = cred2;
1617         if (!cred)
1618                 cred = cred2;
1619
1620         cred2 = interworking_credentials_available_roaming_consortium(wpa_s,
1621                                                                       bss);
1622         if (cred && cred2 && cred2->priority >= cred->priority)
1623                 cred = cred2;
1624         if (!cred)
1625                 cred = cred2;
1626
1627         return cred;
1628 }
1629
1630
1631 static int domain_name_list_contains(struct wpabuf *domain_names,
1632                                      const char *domain)
1633 {
1634         const u8 *pos, *end;
1635         size_t len;
1636
1637         len = os_strlen(domain);
1638         pos = wpabuf_head(domain_names);
1639         end = pos + wpabuf_len(domain_names);
1640
1641         while (pos + 1 < end) {
1642                 if (pos + 1 + pos[0] > end)
1643                         break;
1644
1645                 wpa_hexdump_ascii(MSG_DEBUG, "Interworking: AP domain name",
1646                                   pos + 1, pos[0]);
1647                 if (pos[0] == len &&
1648                     os_strncasecmp(domain, (const char *) (pos + 1), len) == 0)
1649                         return 1;
1650
1651                 pos += 1 + pos[0];
1652         }
1653
1654         return 0;
1655 }
1656
1657
1658 int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
1659                               struct wpa_cred *cred,
1660                               struct wpabuf *domain_names)
1661 {
1662         size_t i;
1663         int ret = -1;
1664 #ifdef INTERWORKING_3GPP
1665         char nai[100], *realm;
1666
1667         char *imsi = NULL;
1668         int mnc_len = 0;
1669         if (cred->imsi)
1670                 imsi = cred->imsi;
1671 #ifdef CONFIG_PCSC
1672         else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
1673                  wpa_s->scard && wpa_s->imsi[0]) {
1674                 imsi = wpa_s->imsi;
1675                 mnc_len = wpa_s->mnc_len;
1676         }
1677 #endif /* CONFIG_PCSC */
1678 #ifdef CONFIG_EAP_PROXY
1679         else if (cred->pcsc && wpa_s->mnc_len > 0 && wpa_s->imsi[0]) {
1680                 imsi = wpa_s->imsi;
1681                 mnc_len = wpa_s->mnc_len;
1682         }
1683 #endif /* CONFIG_EAP_PROXY */
1684         if (domain_names &&
1685             imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0) == 0) {
1686                 realm = os_strchr(nai, '@');
1687                 if (realm)
1688                         realm++;
1689                 wpa_printf(MSG_DEBUG, "Interworking: Search for match "
1690                            "with SIM/USIM domain %s", realm);
1691                 if (realm &&
1692                     domain_name_list_contains(domain_names, realm))
1693                         return 1;
1694                 if (realm)
1695                         ret = 0;
1696         }
1697 #endif /* INTERWORKING_3GPP */
1698
1699         if (domain_names == NULL || cred->domain == NULL)
1700                 return ret;
1701
1702         for (i = 0; i < cred->num_domain; i++) {
1703                 wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
1704                            "home SP FQDN %s", cred->domain[i]);
1705                 if (domain_name_list_contains(domain_names, cred->domain[i]))
1706                         return 1;
1707         }
1708
1709         return 0;
1710 }
1711
1712
1713 static int interworking_home_sp(struct wpa_supplicant *wpa_s,
1714                                 struct wpabuf *domain_names)
1715 {
1716         struct wpa_cred *cred;
1717
1718         if (domain_names == NULL || wpa_s->conf->cred == NULL)
1719                 return -1;
1720
1721         for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
1722                 int res = interworking_home_sp_cred(wpa_s, cred, domain_names);
1723                 if (res)
1724                         return res;
1725         }
1726
1727         return 0;
1728 }
1729
1730
1731 static int interworking_find_network_match(struct wpa_supplicant *wpa_s)
1732 {
1733         struct wpa_bss *bss;
1734         struct wpa_ssid *ssid;
1735
1736         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1737                 for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
1738                         if (wpas_network_disabled(wpa_s, ssid) ||
1739                             ssid->mode != WPAS_MODE_INFRA)
1740                                 continue;
1741                         if (ssid->ssid_len != bss->ssid_len ||
1742                             os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) !=
1743                             0)
1744                                 continue;
1745                         /*
1746                          * TODO: Consider more accurate matching of security
1747                          * configuration similarly to what is done in events.c
1748                          */
1749                         return 1;
1750                 }
1751         }
1752
1753         return 0;
1754 }
1755
1756
1757 static void interworking_select_network(struct wpa_supplicant *wpa_s)
1758 {
1759         struct wpa_bss *bss, *selected = NULL, *selected_home = NULL;
1760         int selected_prio = -999999, selected_home_prio = -999999;
1761         unsigned int count = 0;
1762         const char *type;
1763         int res;
1764         struct wpa_cred *cred;
1765
1766         wpa_s->network_select = 0;
1767
1768         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1769                 cred = interworking_credentials_available(wpa_s, bss);
1770                 if (!cred)
1771                         continue;
1772                 if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
1773                         /*
1774                          * We currently support only HS 2.0 networks and those
1775                          * are required to use WPA2-Enterprise.
1776                          */
1777                         wpa_printf(MSG_DEBUG, "Interworking: Credential match "
1778                                    "with " MACSTR " but network does not use "
1779                                    "RSN", MAC2STR(bss->bssid));
1780                         continue;
1781                 }
1782                 count++;
1783                 res = interworking_home_sp(wpa_s, bss->anqp ?
1784                                            bss->anqp->domain_name : NULL);
1785                 if (res > 0)
1786                         type = "home";
1787                 else if (res == 0)
1788                         type = "roaming";
1789                 else
1790                         type = "unknown";
1791                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
1792                         MAC2STR(bss->bssid), type);
1793                 if (wpa_s->auto_select ||
1794                     (wpa_s->conf->auto_interworking &&
1795                      wpa_s->auto_network_select)) {
1796                         if (selected == NULL ||
1797                             cred->priority > selected_prio) {
1798                                 selected = bss;
1799                                 selected_prio = cred->priority;
1800                         }
1801                         if (res > 0 &&
1802                             (selected_home == NULL ||
1803                              cred->priority > selected_home_prio)) {
1804                                 selected_home = bss;
1805                                 selected_home_prio = cred->priority;
1806                         }
1807                 }
1808         }
1809
1810         if (selected_home && selected_home != selected &&
1811             selected_home_prio >= selected_prio) {
1812                 /* Prefer network operated by the Home SP */
1813                 selected = selected_home;
1814         }
1815
1816         if (count == 0) {
1817                 /*
1818                  * No matching network was found based on configured
1819                  * credentials. Check whether any of the enabled network blocks
1820                  * have matching APs.
1821                  */
1822                 if (interworking_find_network_match(wpa_s)) {
1823                         wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
1824                                    "match for enabled network configurations");
1825                         if (wpa_s->auto_select)
1826                                 interworking_reconnect(wpa_s);
1827                         return;
1828                 }
1829
1830                 if (wpa_s->auto_network_select) {
1831                         wpa_printf(MSG_DEBUG, "Interworking: Continue "
1832                                    "scanning after ANQP fetch");
1833                         wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
1834                                                 0);
1835                         return;
1836                 }
1837
1838                 wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
1839                         "with matching credentials found");
1840         }
1841
1842         if (selected)
1843                 interworking_connect(wpa_s, selected);
1844 }
1845
1846
1847 static struct wpa_bss_anqp *
1848 interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
1849 {
1850         struct wpa_bss *other;
1851
1852         if (is_zero_ether_addr(bss->hessid))
1853                 return NULL; /* Cannot be in the same homegenous ESS */
1854
1855         dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
1856                 if (other == bss)
1857                         continue;
1858                 if (other->anqp == NULL)
1859                         continue;
1860                 if (other->anqp->roaming_consortium == NULL &&
1861                     other->anqp->nai_realm == NULL &&
1862                     other->anqp->anqp_3gpp == NULL &&
1863                     other->anqp->domain_name == NULL)
1864                         continue;
1865                 if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
1866                         continue;
1867                 if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
1868                         continue;
1869                 if (bss->ssid_len != other->ssid_len ||
1870                     os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
1871                         continue;
1872
1873                 wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
1874                            "already fetched BSSID " MACSTR " and " MACSTR,
1875                            MAC2STR(other->bssid), MAC2STR(bss->bssid));
1876                 other->anqp->users++;
1877                 return other->anqp;
1878         }
1879
1880         return NULL;
1881 }
1882
1883
1884 static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
1885 {
1886         struct wpa_bss *bss;
1887         int found = 0;
1888         const u8 *ie;
1889
1890         if (eloop_terminated() || !wpa_s->fetch_anqp_in_progress)
1891                 return;
1892
1893         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1894                 if (!(bss->caps & IEEE80211_CAP_ESS))
1895                         continue;
1896                 ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
1897                 if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
1898                         continue; /* AP does not support Interworking */
1899                 if (disallowed_bssid(wpa_s, bss->bssid) ||
1900                     disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len))
1901                         continue; /* Disallowed BSS */
1902
1903                 if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
1904                         if (bss->anqp == NULL) {
1905                                 bss->anqp = interworking_match_anqp_info(wpa_s,
1906                                                                          bss);
1907                                 if (bss->anqp) {
1908                                         /* Shared data already fetched */
1909                                         continue;
1910                                 }
1911                                 bss->anqp = wpa_bss_anqp_alloc();
1912                                 if (bss->anqp == NULL)
1913                                         break;
1914                         }
1915                         found++;
1916                         bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
1917                         wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
1918                                 MACSTR, MAC2STR(bss->bssid));
1919                         interworking_anqp_send_req(wpa_s, bss);
1920                         break;
1921                 }
1922         }
1923
1924         if (found == 0) {
1925                 wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
1926                 wpa_s->fetch_anqp_in_progress = 0;
1927                 if (wpa_s->network_select)
1928                         interworking_select_network(wpa_s);
1929         }
1930 }
1931
1932
1933 void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
1934 {
1935         struct wpa_bss *bss;
1936
1937         dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
1938                 bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
1939
1940         wpa_s->fetch_anqp_in_progress = 1;
1941         interworking_next_anqp_fetch(wpa_s);
1942 }
1943
1944
1945 int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
1946 {
1947         if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
1948                 return 0;
1949
1950         wpa_s->network_select = 0;
1951         wpa_s->fetch_all_anqp = 1;
1952
1953         interworking_start_fetch_anqp(wpa_s);
1954
1955         return 0;
1956 }
1957
1958
1959 void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
1960 {
1961         if (!wpa_s->fetch_anqp_in_progress)
1962                 return;
1963
1964         wpa_s->fetch_anqp_in_progress = 0;
1965 }
1966
1967
1968 int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
1969                   u16 info_ids[], size_t num_ids)
1970 {
1971         struct wpabuf *buf;
1972         int ret = 0;
1973         int freq;
1974         struct wpa_bss *bss;
1975         int res;
1976
1977         freq = wpa_s->assoc_freq;
1978         bss = wpa_bss_get_bssid(wpa_s, dst);
1979         if (bss) {
1980                 wpa_bss_anqp_unshare_alloc(bss);
1981                 freq = bss->freq;
1982         }
1983         if (freq <= 0)
1984                 return -1;
1985
1986         wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
1987                    MAC2STR(dst), (unsigned int) num_ids);
1988
1989         buf = anqp_build_req(info_ids, num_ids, NULL);
1990         if (buf == NULL)
1991                 return -1;
1992
1993         res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
1994         if (res < 0) {
1995                 wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
1996                 wpabuf_free(buf);
1997                 ret = -1;
1998         } else
1999                 wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
2000                            "%u", res);
2001
2002         return ret;
2003 }
2004
2005
2006 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
2007                                             struct wpa_bss *bss, const u8 *sa,
2008                                             u16 info_id,
2009                                             const u8 *data, size_t slen)
2010 {
2011         const u8 *pos = data;
2012         struct wpa_bss_anqp *anqp = NULL;
2013 #ifdef CONFIG_HS20
2014         u8 type;
2015 #endif /* CONFIG_HS20 */
2016
2017         if (bss)
2018                 anqp = bss->anqp;
2019
2020         switch (info_id) {
2021         case ANQP_CAPABILITY_LIST:
2022                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2023                         " ANQP Capability list", MAC2STR(sa));
2024                 break;
2025         case ANQP_VENUE_NAME:
2026                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2027                         " Venue Name", MAC2STR(sa));
2028                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
2029                 if (anqp) {
2030                         wpabuf_free(anqp->venue_name);
2031                         anqp->venue_name = wpabuf_alloc_copy(pos, slen);
2032                 }
2033                 break;
2034         case ANQP_NETWORK_AUTH_TYPE:
2035                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2036                         " Network Authentication Type information",
2037                         MAC2STR(sa));
2038                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
2039                                   "Type", pos, slen);
2040                 if (anqp) {
2041                         wpabuf_free(anqp->network_auth_type);
2042                         anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
2043                 }
2044                 break;
2045         case ANQP_ROAMING_CONSORTIUM:
2046                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2047                         " Roaming Consortium list", MAC2STR(sa));
2048                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
2049                                   pos, slen);
2050                 if (anqp) {
2051                         wpabuf_free(anqp->roaming_consortium);
2052                         anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
2053                 }
2054                 break;
2055         case ANQP_IP_ADDR_TYPE_AVAILABILITY:
2056                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2057                         " IP Address Type Availability information",
2058                         MAC2STR(sa));
2059                 wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
2060                             pos, slen);
2061                 if (anqp) {
2062                         wpabuf_free(anqp->ip_addr_type_availability);
2063                         anqp->ip_addr_type_availability =
2064                                 wpabuf_alloc_copy(pos, slen);
2065                 }
2066                 break;
2067         case ANQP_NAI_REALM:
2068                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2069                         " NAI Realm list", MAC2STR(sa));
2070                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
2071                 if (anqp) {
2072                         wpabuf_free(anqp->nai_realm);
2073                         anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
2074                 }
2075                 break;
2076         case ANQP_3GPP_CELLULAR_NETWORK:
2077                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2078                         " 3GPP Cellular Network information", MAC2STR(sa));
2079                 wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
2080                                   pos, slen);
2081                 if (anqp) {
2082                         wpabuf_free(anqp->anqp_3gpp);
2083                         anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
2084                 }
2085                 break;
2086         case ANQP_DOMAIN_NAME:
2087                 wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
2088                         " Domain Name list", MAC2STR(sa));
2089                 wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
2090                 if (anqp) {
2091                         wpabuf_free(anqp->domain_name);
2092                         anqp->domain_name = wpabuf_alloc_copy(pos, slen);
2093                 }
2094                 break;
2095         case ANQP_VENDOR_SPECIFIC:
2096                 if (slen < 3)
2097                         return;
2098
2099                 switch (WPA_GET_BE24(pos)) {
2100 #ifdef CONFIG_HS20
2101                 case OUI_WFA:
2102                         pos += 3;
2103                         slen -= 3;
2104
2105                         if (slen < 1)
2106                                 return;
2107                         type = *pos++;
2108                         slen--;
2109
2110                         switch (type) {
2111                         case HS20_ANQP_OUI_TYPE:
2112                                 hs20_parse_rx_hs20_anqp_resp(wpa_s, sa, pos,
2113                                                              slen);
2114                                 break;
2115                         default:
2116                                 wpa_printf(MSG_DEBUG, "HS20: Unsupported ANQP "
2117                                            "vendor type %u", type);
2118                                 break;
2119                         }
2120                         break;
2121 #endif /* CONFIG_HS20 */
2122                 default:
2123                         wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
2124                                    "vendor-specific ANQP OUI %06x",
2125                                    WPA_GET_BE24(pos));
2126                         return;
2127                 }
2128                 break;
2129         default:
2130                 wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
2131                            "%u", info_id);
2132                 break;
2133         }
2134 }
2135
2136
2137 void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
2138                   enum gas_query_result result,
2139                   const struct wpabuf *adv_proto,
2140                   const struct wpabuf *resp, u16 status_code)
2141 {
2142         struct wpa_supplicant *wpa_s = ctx;
2143         const u8 *pos;
2144         const u8 *end;
2145         u16 info_id;
2146         u16 slen;
2147         struct wpa_bss *bss = NULL, *tmp;
2148
2149         if (result != GAS_QUERY_SUCCESS)
2150                 return;
2151
2152         pos = wpabuf_head(adv_proto);
2153         if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
2154             pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
2155                 wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
2156                            "Protocol in response");
2157                 return;
2158         }
2159
2160         /*
2161          * If possible, select the BSS entry based on which BSS entry was used
2162          * for the request. This can help in cases where multiple BSS entries
2163          * may exist for the same AP.
2164          */
2165         dl_list_for_each_reverse(tmp, &wpa_s->bss, struct wpa_bss, list) {
2166                 if (tmp == wpa_s->interworking_gas_bss &&
2167                     os_memcmp(tmp->bssid, dst, ETH_ALEN) == 0) {
2168                         bss = tmp;
2169                         break;
2170                 }
2171         }
2172         if (bss == NULL)
2173                 bss = wpa_bss_get_bssid(wpa_s, dst);
2174
2175         pos = wpabuf_head(resp);
2176         end = pos + wpabuf_len(resp);
2177
2178         while (pos < end) {
2179                 if (pos + 4 > end) {
2180                         wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
2181                         break;
2182                 }
2183                 info_id = WPA_GET_LE16(pos);
2184                 pos += 2;
2185                 slen = WPA_GET_LE16(pos);
2186                 pos += 2;
2187                 if (pos + slen > end) {
2188                         wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
2189                                    "for Info ID %u", info_id);
2190                         break;
2191                 }
2192                 interworking_parse_rx_anqp_resp(wpa_s, bss, dst, info_id, pos,
2193                                                 slen);
2194                 pos += slen;
2195         }
2196 }
2197
2198
2199 static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
2200                                           struct wpa_scan_results *scan_res)
2201 {
2202         wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
2203                    "ANQP fetch");
2204         interworking_start_fetch_anqp(wpa_s);
2205 }
2206
2207
2208 int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
2209 {
2210         interworking_stop_fetch_anqp(wpa_s);
2211         wpa_s->network_select = 1;
2212         wpa_s->auto_network_select = 0;
2213         wpa_s->auto_select = !!auto_select;
2214         wpa_s->fetch_all_anqp = 0;
2215         wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
2216                    "selection");
2217         wpa_s->scan_res_handler = interworking_scan_res_handler;
2218         wpa_s->normal_scans = 0;
2219         wpa_s->scan_req = MANUAL_SCAN_REQ;
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 }