Coverage Report

Created: 2025-10-28 06:59

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