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