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