Coverage Report

Created: 2023-03-26 06:22

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