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