2 * Interworking (IEEE 802.11u)
3 * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
12 #include "common/ieee802_11_defs.h"
13 #include "common/gas.h"
14 #include "common/wpa_ctrl.h"
15 #include "utils/pcsc_funcs.h"
16 #include "utils/eloop.h"
17 #include "drivers/driver.h"
18 #include "eap_common/eap_defs.h"
19 #include "eap_peer/eap.h"
20 #include "eap_peer/eap_methods.h"
21 #include "wpa_supplicant_i.h"
23 #include "config_ssid.h"
27 #include "gas_query.h"
28 #include "hs20_supplicant.h"
29 #include "interworking.h"
32 #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
33 #define INTERWORKING_3GPP
35 #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
36 #define INTERWORKING_3GPP
38 #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
39 #define INTERWORKING_3GPP
44 static void interworking_next_anqp_fetch(struct wpa_supplicant
*wpa_s
);
45 static struct wpa_cred
* interworking_credentials_available_realm(
46 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
);
47 static struct wpa_cred
* interworking_credentials_available_3gpp(
48 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
);
51 static void interworking_reconnect(struct wpa_supplicant
*wpa_s
)
53 if (wpa_s
->wpa_state
>= WPA_AUTHENTICATING
) {
54 wpa_supplicant_cancel_sched_scan(wpa_s
);
55 wpa_supplicant_deauthenticate(wpa_s
,
56 WLAN_REASON_DEAUTH_LEAVING
);
58 wpa_s
->disconnected
= 0;
59 wpa_s
->reassociate
= 1;
61 if (wpa_supplicant_fast_associate(wpa_s
) >= 0)
64 wpa_supplicant_req_scan(wpa_s
, 0, 0);
68 static struct wpabuf
* anqp_build_req(u16 info_ids
[], size_t num_ids
,
75 buf
= gas_anqp_build_initial_req(0, 4 + num_ids
* 2 +
76 (extra
? wpabuf_len(extra
) : 0));
80 len_pos
= gas_anqp_add_element(buf
, ANQP_QUERY_LIST
);
81 for (i
= 0; i
< num_ids
; i
++)
82 wpabuf_put_le16(buf
, info_ids
[i
]);
83 gas_anqp_set_element_len(buf
, len_pos
);
85 wpabuf_put_buf(buf
, extra
);
87 gas_anqp_set_len(buf
);
93 static void interworking_anqp_resp_cb(void *ctx
, const u8
*dst
,
95 enum gas_query_result result
,
96 const struct wpabuf
*adv_proto
,
97 const struct wpabuf
*resp
,
100 struct wpa_supplicant
*wpa_s
= ctx
;
102 anqp_resp_cb(wpa_s
, dst
, dialog_token
, result
, adv_proto
, resp
,
104 interworking_next_anqp_fetch(wpa_s
);
108 static int cred_with_roaming_consortium(struct wpa_supplicant
*wpa_s
)
110 struct wpa_cred
*cred
;
112 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
113 if (cred
->roaming_consortium_len
)
115 if (cred
->required_roaming_consortium_len
)
122 static int cred_with_3gpp(struct wpa_supplicant
*wpa_s
)
124 struct wpa_cred
*cred
;
126 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
127 if (cred
->pcsc
|| cred
->imsi
)
134 static int cred_with_nai_realm(struct wpa_supplicant
*wpa_s
)
136 struct wpa_cred
*cred
;
138 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
139 if (cred
->pcsc
|| cred
->imsi
)
141 if (!cred
->eap_method
)
143 if (cred
->realm
&& cred
->roaming_consortium_len
== 0)
150 static int cred_with_domain(struct wpa_supplicant
*wpa_s
)
152 struct wpa_cred
*cred
;
154 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
155 if (cred
->domain
|| cred
->pcsc
|| cred
->imsi
)
162 static int additional_roaming_consortiums(struct wpa_bss
*bss
)
165 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
166 if (ie
== NULL
|| ie
[1] == 0)
168 return ie
[2]; /* Number of ANQP OIs */
172 static void interworking_continue_anqp(void *eloop_ctx
, void *sock_ctx
)
174 struct wpa_supplicant
*wpa_s
= eloop_ctx
;
175 interworking_next_anqp_fetch(wpa_s
);
179 static int interworking_anqp_send_req(struct wpa_supplicant
*wpa_s
,
186 size_t num_info_ids
= 0;
187 struct wpabuf
*extra
= NULL
;
188 int all
= wpa_s
->fetch_all_anqp
;
190 wpa_printf(MSG_DEBUG
, "Interworking: ANQP Query Request to " MACSTR
,
191 MAC2STR(bss
->bssid
));
192 wpa_s
->interworking_gas_bss
= bss
;
194 info_ids
[num_info_ids
++] = ANQP_CAPABILITY_LIST
;
196 info_ids
[num_info_ids
++] = ANQP_VENUE_NAME
;
197 info_ids
[num_info_ids
++] = ANQP_NETWORK_AUTH_TYPE
;
199 if (all
|| (cred_with_roaming_consortium(wpa_s
) &&
200 additional_roaming_consortiums(bss
)))
201 info_ids
[num_info_ids
++] = ANQP_ROAMING_CONSORTIUM
;
203 info_ids
[num_info_ids
++] = ANQP_IP_ADDR_TYPE_AVAILABILITY
;
204 if (all
|| cred_with_nai_realm(wpa_s
))
205 info_ids
[num_info_ids
++] = ANQP_NAI_REALM
;
206 if (all
|| cred_with_3gpp(wpa_s
))
207 info_ids
[num_info_ids
++] = ANQP_3GPP_CELLULAR_NETWORK
;
208 if (all
|| cred_with_domain(wpa_s
))
209 info_ids
[num_info_ids
++] = ANQP_DOMAIN_NAME
;
210 wpa_hexdump(MSG_DEBUG
, "Interworking: ANQP Query info",
211 (u8
*) info_ids
, num_info_ids
* 2);
214 if (wpa_bss_get_vendor_ie(bss
, HS20_IE_VENDOR_TYPE
)) {
217 extra
= wpabuf_alloc(100);
221 len_pos
= gas_anqp_add_element(extra
, ANQP_VENDOR_SPECIFIC
);
222 wpabuf_put_be24(extra
, OUI_WFA
);
223 wpabuf_put_u8(extra
, HS20_ANQP_OUI_TYPE
);
224 wpabuf_put_u8(extra
, HS20_STYPE_QUERY_LIST
);
225 wpabuf_put_u8(extra
, 0); /* Reserved */
226 wpabuf_put_u8(extra
, HS20_STYPE_CAPABILITY_LIST
);
229 HS20_STYPE_OPERATOR_FRIENDLY_NAME
);
230 wpabuf_put_u8(extra
, HS20_STYPE_WAN_METRICS
);
231 wpabuf_put_u8(extra
, HS20_STYPE_CONNECTION_CAPABILITY
);
232 wpabuf_put_u8(extra
, HS20_STYPE_OPERATING_CLASS
);
234 gas_anqp_set_element_len(extra
, len_pos
);
236 #endif /* CONFIG_HS20 */
238 buf
= anqp_build_req(info_ids
, num_info_ids
, extra
);
243 res
= gas_query_req(wpa_s
->gas
, bss
->bssid
, bss
->freq
, buf
,
244 interworking_anqp_resp_cb
, wpa_s
);
246 wpa_printf(MSG_DEBUG
, "ANQP: Failed to send Query Request");
249 eloop_register_timeout(0, 0, interworking_continue_anqp
, wpa_s
,
252 wpa_printf(MSG_DEBUG
, "ANQP: Query started with dialog token "
259 struct nai_realm_eap
{
262 enum nai_realm_eap_auth_inner_non_eap inner_non_eap
;
264 u8 tunneled_cred_type
;
271 struct nai_realm_eap
*eap
;
275 static void nai_realm_free(struct nai_realm
*realms
, u16 count
)
281 for (i
= 0; i
< count
; i
++) {
282 os_free(realms
[i
].eap
);
283 os_free(realms
[i
].realm
);
289 static const u8
* nai_realm_parse_eap(struct nai_realm_eap
*e
, const u8
*pos
,
292 u8 elen
, auth_count
, a
;
296 wpa_printf(MSG_DEBUG
, "No room for EAP Method fixed fields");
301 if (pos
+ elen
> end
|| elen
< 2) {
302 wpa_printf(MSG_DEBUG
, "No room for EAP Method subfield");
308 wpa_printf(MSG_DEBUG
, "EAP Method: len=%u method=%u auth_count=%u",
309 elen
, e
->method
, auth_count
);
311 for (a
= 0; a
< auth_count
; a
++) {
314 if (pos
+ 2 > end
|| pos
+ 2 + pos
[1] > end
) {
315 wpa_printf(MSG_DEBUG
, "No room for Authentication "
316 "Parameter subfield");
324 case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH
:
327 e
->inner_non_eap
= *pos
;
328 if (e
->method
!= EAP_TYPE_TTLS
)
331 case NAI_REALM_INNER_NON_EAP_PAP
:
332 wpa_printf(MSG_DEBUG
, "EAP-TTLS/PAP");
334 case NAI_REALM_INNER_NON_EAP_CHAP
:
335 wpa_printf(MSG_DEBUG
, "EAP-TTLS/CHAP");
337 case NAI_REALM_INNER_NON_EAP_MSCHAP
:
338 wpa_printf(MSG_DEBUG
, "EAP-TTLS/MSCHAP");
340 case NAI_REALM_INNER_NON_EAP_MSCHAPV2
:
341 wpa_printf(MSG_DEBUG
, "EAP-TTLS/MSCHAPV2");
345 case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD
:
348 e
->inner_method
= *pos
;
349 wpa_printf(MSG_DEBUG
, "Inner EAP method: %u",
352 case NAI_REALM_EAP_AUTH_CRED_TYPE
:
356 wpa_printf(MSG_DEBUG
, "Credential Type: %u",
359 case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE
:
362 e
->tunneled_cred_type
= *pos
;
363 wpa_printf(MSG_DEBUG
, "Tunneled EAP Method Credential "
364 "Type: %u", e
->tunneled_cred_type
);
367 wpa_printf(MSG_DEBUG
, "Unsupported Authentication "
368 "Parameter: id=%u len=%u", id
, len
);
369 wpa_hexdump(MSG_DEBUG
, "Authentication Parameter "
381 static const u8
* nai_realm_parse_realm(struct nai_realm
*r
, const u8
*pos
,
389 wpa_printf(MSG_DEBUG
, "No room for NAI Realm Data "
394 len
= WPA_GET_LE16(pos
); /* NAI Realm Data field Length */
396 if (pos
+ len
> end
|| len
< 3) {
397 wpa_printf(MSG_DEBUG
, "No room for NAI Realm Data "
399 len
, (unsigned int) (end
- pos
));
404 r
->encoding
= *pos
++;
406 if (pos
+ realm_len
> f_end
) {
407 wpa_printf(MSG_DEBUG
, "No room for NAI Realm "
409 realm_len
, (unsigned int) (f_end
- pos
));
412 wpa_hexdump_ascii(MSG_DEBUG
, "NAI Realm", pos
, realm_len
);
413 r
->realm
= dup_binstr(pos
, realm_len
);
414 if (r
->realm
== NULL
)
418 if (pos
+ 1 > f_end
) {
419 wpa_printf(MSG_DEBUG
, "No room for EAP Method Count");
422 r
->eap_count
= *pos
++;
423 wpa_printf(MSG_DEBUG
, "EAP Count: %u", r
->eap_count
);
424 if (pos
+ r
->eap_count
* 3 > f_end
) {
425 wpa_printf(MSG_DEBUG
, "No room for EAP Methods");
428 r
->eap
= os_calloc(r
->eap_count
, sizeof(struct nai_realm_eap
));
432 for (e
= 0; e
< r
->eap_count
; e
++) {
433 pos
= nai_realm_parse_eap(&r
->eap
[e
], pos
, f_end
);
442 static struct nai_realm
* nai_realm_parse(struct wpabuf
*anqp
, u16
*count
)
444 struct nai_realm
*realm
;
448 if (anqp
== NULL
|| wpabuf_len(anqp
) < 2)
451 pos
= wpabuf_head_u8(anqp
);
452 end
= pos
+ wpabuf_len(anqp
);
453 num
= WPA_GET_LE16(pos
);
454 wpa_printf(MSG_DEBUG
, "NAI Realm Count: %u", num
);
457 if (num
* 5 > end
- pos
) {
458 wpa_printf(MSG_DEBUG
, "Invalid NAI Realm Count %u - not "
459 "enough data (%u octets) for that many realms",
460 num
, (unsigned int) (end
- pos
));
464 realm
= os_calloc(num
, sizeof(struct nai_realm
));
468 for (i
= 0; i
< num
; i
++) {
469 pos
= nai_realm_parse_realm(&realm
[i
], pos
, end
);
471 nai_realm_free(realm
, num
);
481 static int nai_realm_match(struct nai_realm
*realm
, const char *home_realm
)
483 char *tmp
, *pos
, *end
;
486 if (realm
->realm
== NULL
|| home_realm
== NULL
)
489 if (os_strchr(realm
->realm
, ';') == NULL
)
490 return os_strcasecmp(realm
->realm
, home_realm
) == 0;
492 tmp
= os_strdup(realm
->realm
);
498 end
= os_strchr(pos
, ';');
501 if (os_strcasecmp(pos
, home_realm
) == 0) {
516 static int nai_realm_cred_username(struct nai_realm_eap
*eap
)
518 if (eap_get_name(EAP_VENDOR_IETF
, eap
->method
) == NULL
)
519 return 0; /* method not supported */
521 if (eap
->method
!= EAP_TYPE_TTLS
&& eap
->method
!= EAP_TYPE_PEAP
) {
522 /* Only tunneled methods with username/password supported */
526 if (eap
->method
== EAP_TYPE_PEAP
) {
527 if (eap
->inner_method
&&
528 eap_get_name(EAP_VENDOR_IETF
, eap
->inner_method
) == NULL
)
530 if (!eap
->inner_method
&&
531 eap_get_name(EAP_VENDOR_IETF
, EAP_TYPE_MSCHAPV2
) == NULL
)
535 if (eap
->method
== EAP_TYPE_TTLS
) {
536 if (eap
->inner_method
== 0 && eap
->inner_non_eap
== 0)
537 return 1; /* Assume TTLS/MSCHAPv2 is used */
538 if (eap
->inner_method
&&
539 eap_get_name(EAP_VENDOR_IETF
, eap
->inner_method
) == NULL
)
541 if (eap
->inner_non_eap
&&
542 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_PAP
&&
543 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_CHAP
&&
544 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_MSCHAP
&&
545 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_MSCHAPV2
)
549 if (eap
->inner_method
&&
550 eap
->inner_method
!= EAP_TYPE_GTC
&&
551 eap
->inner_method
!= EAP_TYPE_MSCHAPV2
)
558 static int nai_realm_cred_cert(struct nai_realm_eap
*eap
)
560 if (eap_get_name(EAP_VENDOR_IETF
, eap
->method
) == NULL
)
561 return 0; /* method not supported */
563 if (eap
->method
!= EAP_TYPE_TLS
) {
564 /* Only EAP-TLS supported for credential authentication */
572 static struct nai_realm_eap
* nai_realm_find_eap(struct wpa_cred
*cred
,
573 struct nai_realm
*realm
)
578 cred
->username
== NULL
||
579 cred
->username
[0] == '\0' ||
580 ((cred
->password
== NULL
||
581 cred
->password
[0] == '\0') &&
582 (cred
->private_key
== NULL
||
583 cred
->private_key
[0] == '\0')))
586 for (e
= 0; e
< realm
->eap_count
; e
++) {
587 struct nai_realm_eap
*eap
= &realm
->eap
[e
];
588 if (cred
->password
&& cred
->password
[0] &&
589 nai_realm_cred_username(eap
))
591 if (cred
->private_key
&& cred
->private_key
[0] &&
592 nai_realm_cred_cert(eap
))
600 #ifdef INTERWORKING_3GPP
602 static int plmn_id_match(struct wpabuf
*anqp
, const char *imsi
, int mnc_len
)
604 u8 plmn
[3], plmn2
[3];
609 * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
610 * operator is allowed to include only two digits of the MNC, so allow
611 * matches based on both two and three digit MNC assumptions. Since some
612 * SIM/USIM cards may not expose MNC length conveniently, we may be
613 * provided the default MNC length 3 here and as such, checking with MNC
614 * length 2 is justifiable even though 3GPP TS 24.234 does not mention
615 * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
616 * with otherwise matching values would not be good idea in general, so
617 * this should not result in selecting incorrect networks.
619 /* Match with 3 digit MNC */
620 plmn
[0] = (imsi
[0] - '0') | ((imsi
[1] - '0') << 4);
621 plmn
[1] = (imsi
[2] - '0') | ((imsi
[5] - '0') << 4);
622 plmn
[2] = (imsi
[3] - '0') | ((imsi
[4] - '0') << 4);
623 /* Match with 2 digit MNC */
624 plmn2
[0] = (imsi
[0] - '0') | ((imsi
[1] - '0') << 4);
625 plmn2
[1] = (imsi
[2] - '0') | 0xf0;
626 plmn2
[2] = (imsi
[3] - '0') | ((imsi
[4] - '0') << 4);
630 pos
= wpabuf_head_u8(anqp
);
631 end
= pos
+ wpabuf_len(anqp
);
635 wpa_printf(MSG_DEBUG
, "Unsupported GUD version 0x%x", *pos
);
640 if (pos
+ udhl
> end
) {
641 wpa_printf(MSG_DEBUG
, "Invalid UDHL");
646 wpa_printf(MSG_DEBUG
, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
647 plmn
[0], plmn
[1], plmn
[2], plmn2
[0], plmn2
[1], plmn2
[2],
650 while (pos
+ 2 <= end
) {
659 if (iei
== 0 && len
> 0) {
662 wpa_hexdump(MSG_DEBUG
, "Interworking: PLMN List information element",
665 for (i
= 0; i
< num
; i
++) {
668 if (os_memcmp(pos
, plmn
, 3) == 0 ||
669 os_memcmp(pos
, plmn2
, 3) == 0)
670 return 1; /* Found matching PLMN */
674 wpa_hexdump(MSG_DEBUG
, "Interworking: Unrecognized 3GPP information element",
685 static int build_root_nai(char *nai
, size_t nai_len
, const char *imsi
,
686 size_t mnc_len
, char prefix
)
688 const char *sep
, *msin
;
690 size_t msin_len
, plmn_len
;
693 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
695 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
696 * <MNC> is zero-padded to three digits in case two-digit MNC is used
699 if (imsi
== NULL
|| os_strlen(imsi
) > 16) {
700 wpa_printf(MSG_DEBUG
, "No valid IMSI available");
703 sep
= os_strchr(imsi
, '-');
705 plmn_len
= sep
- imsi
;
707 } else if (mnc_len
&& os_strlen(imsi
) >= 3 + mnc_len
) {
708 plmn_len
= 3 + mnc_len
;
709 msin
= imsi
+ plmn_len
;
712 if (plmn_len
!= 5 && plmn_len
!= 6)
714 msin_len
= os_strlen(msin
);
720 os_memcpy(pos
, imsi
, plmn_len
);
722 os_memcpy(pos
, msin
, msin_len
);
724 pos
+= os_snprintf(pos
, end
- pos
, "@wlan.mnc");
734 pos
+= os_snprintf(pos
, end
- pos
, ".mcc%c%c%c.3gppnetwork.org",
735 imsi
[0], imsi
[1], imsi
[2]);
741 static int set_root_nai(struct wpa_ssid
*ssid
, const char *imsi
, char prefix
)
744 if (build_root_nai(nai
, sizeof(nai
), imsi
, 0, prefix
) < 0)
746 return wpa_config_set_quoted(ssid
, "identity", nai
);
749 #endif /* INTERWORKING_3GPP */
752 static int interworking_set_hs20_params(struct wpa_supplicant
*wpa_s
,
753 struct wpa_ssid
*ssid
)
755 if (wpa_config_set(ssid
, "key_mgmt",
756 wpa_s
->conf
->pmf
!= NO_MGMT_FRAME_PROTECTION
?
757 "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
759 if (wpa_config_set(ssid
, "proto", "RSN", 0) < 0)
761 if (wpa_config_set(ssid
, "pairwise", "CCMP", 0) < 0)
767 static int interworking_connect_3gpp(struct wpa_supplicant
*wpa_s
,
768 struct wpa_cred
*cred
,
771 #ifdef INTERWORKING_3GPP
772 struct wpa_ssid
*ssid
;
778 if (bss
->anqp
== NULL
|| bss
->anqp
->anqp_3gpp
== NULL
)
781 ie
= wpa_bss_get_ie(bss
, WLAN_EID_SSID
);
784 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
" (3GPP)",
785 MAC2STR(bss
->bssid
));
787 ssid
= wpa_config_add_network(wpa_s
->conf
);
790 ssid
->parent_cred
= cred
;
792 wpas_notify_network_added(wpa_s
, ssid
);
793 wpa_config_set_network_defaults(ssid
);
794 ssid
->priority
= cred
->priority
;
796 ssid
->ssid
= os_zalloc(ie
[1] + 1);
797 if (ssid
->ssid
== NULL
)
799 os_memcpy(ssid
->ssid
, ie
+ 2, ie
[1]);
800 ssid
->ssid_len
= ie
[1];
802 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
805 eap_type
= EAP_TYPE_SIM
;
806 if (cred
->pcsc
&& wpa_s
->scard
&& scard_supports_umts(wpa_s
->scard
))
807 eap_type
= EAP_TYPE_AKA
;
808 if (cred
->eap_method
&& cred
->eap_method
[0].vendor
== EAP_VENDOR_IETF
) {
809 if (cred
->eap_method
[0].method
== EAP_TYPE_SIM
||
810 cred
->eap_method
[0].method
== EAP_TYPE_AKA
||
811 cred
->eap_method
[0].method
== EAP_TYPE_AKA_PRIME
)
812 eap_type
= cred
->eap_method
[0].method
;
818 res
= wpa_config_set(ssid
, "eap", "SIM", 0);
822 res
= wpa_config_set(ssid
, "eap", "AKA", 0);
824 case EAP_TYPE_AKA_PRIME
:
826 res
= wpa_config_set(ssid
, "eap", "AKA'", 0);
833 wpa_printf(MSG_DEBUG
, "Selected EAP method (%d) not supported",
838 if (!cred
->pcsc
&& set_root_nai(ssid
, cred
->imsi
, prefix
) < 0) {
839 wpa_printf(MSG_DEBUG
, "Failed to set Root NAI");
843 if (cred
->milenage
&& cred
->milenage
[0]) {
844 if (wpa_config_set_quoted(ssid
, "password",
847 } else if (cred
->pcsc
) {
848 if (wpa_config_set_quoted(ssid
, "pcsc", "") < 0)
850 if (wpa_s
->conf
->pcsc_pin
&&
851 wpa_config_set_quoted(ssid
, "pin", wpa_s
->conf
->pcsc_pin
)
856 if (cred
->password
&& cred
->password
[0] &&
857 wpa_config_set_quoted(ssid
, "password", cred
->password
) < 0)
860 wpa_config_update_prio_list(wpa_s
->conf
);
861 interworking_reconnect(wpa_s
);
866 wpas_notify_network_removed(wpa_s
, ssid
);
867 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
868 #endif /* INTERWORKING_3GPP */
873 static int roaming_consortium_element_match(const u8
*ie
, const u8
*rc_id
,
883 end
= ie
+ 2 + ie
[1];
885 /* Roaming Consortium element:
887 * OI #1 and #2 lengths
888 * OI #1, [OI #2], [OI #3]
894 pos
++; /* skip Number of ANQP OIs */
896 if (pos
+ (lens
& 0x0f) + (lens
>> 4) > end
)
899 if ((lens
& 0x0f) == rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
903 if ((lens
>> 4) == rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
907 if (pos
< end
&& (size_t) (end
- pos
) == rc_len
&&
908 os_memcmp(pos
, rc_id
, rc_len
) == 0)
915 static int roaming_consortium_anqp_match(const struct wpabuf
*anqp
,
916 const u8
*rc_id
, size_t rc_len
)
924 pos
= wpabuf_head(anqp
);
925 end
= pos
+ wpabuf_len(anqp
);
927 /* Set of <OI Length, OI> duples */
932 if (len
== rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
941 static int roaming_consortium_match(const u8
*ie
, const struct wpabuf
*anqp
,
942 const u8
*rc_id
, size_t rc_len
)
944 return roaming_consortium_element_match(ie
, rc_id
, rc_len
) ||
945 roaming_consortium_anqp_match(anqp
, rc_id
, rc_len
);
949 static int cred_no_required_oi_match(struct wpa_cred
*cred
, struct wpa_bss
*bss
)
953 if (cred
->required_roaming_consortium_len
== 0)
956 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
959 (bss
->anqp
== NULL
|| bss
->anqp
->roaming_consortium
== NULL
))
962 return !roaming_consortium_match(ie
,
964 bss
->anqp
->roaming_consortium
: NULL
,
965 cred
->required_roaming_consortium
,
966 cred
->required_roaming_consortium_len
);
970 static int cred_excluded_ssid(struct wpa_cred
*cred
, struct wpa_bss
*bss
)
974 if (!cred
->excluded_ssid
)
977 for (i
= 0; i
< cred
->num_excluded_ssid
; i
++) {
978 struct excluded_ssid
*e
= &cred
->excluded_ssid
[i
];
979 if (bss
->ssid_len
== e
->ssid_len
&&
980 os_memcmp(bss
->ssid
, e
->ssid
, e
->ssid_len
) == 0)
988 static struct wpa_cred
* interworking_credentials_available_roaming_consortium(
989 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
991 struct wpa_cred
*cred
, *selected
= NULL
;
994 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
997 (bss
->anqp
== NULL
|| bss
->anqp
->roaming_consortium
== NULL
))
1000 if (wpa_s
->conf
->cred
== NULL
)
1003 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1004 if (cred
->roaming_consortium_len
== 0)
1007 if (!roaming_consortium_match(ie
,
1009 bss
->anqp
->roaming_consortium
:
1011 cred
->roaming_consortium
,
1012 cred
->roaming_consortium_len
))
1015 if (cred_excluded_ssid(cred
, bss
))
1017 if (cred_no_required_oi_match(cred
, bss
))
1020 if (selected
== NULL
||
1021 selected
->priority
< cred
->priority
)
1029 static int interworking_set_eap_params(struct wpa_ssid
*ssid
,
1030 struct wpa_cred
*cred
, int ttls
)
1032 if (cred
->eap_method
) {
1033 ttls
= cred
->eap_method
->vendor
== EAP_VENDOR_IETF
&&
1034 cred
->eap_method
->method
== EAP_TYPE_TTLS
;
1036 os_free(ssid
->eap
.eap_methods
);
1037 ssid
->eap
.eap_methods
=
1038 os_malloc(sizeof(struct eap_method_type
) * 2);
1039 if (ssid
->eap
.eap_methods
== NULL
)
1041 os_memcpy(ssid
->eap
.eap_methods
, cred
->eap_method
,
1042 sizeof(*cred
->eap_method
));
1043 ssid
->eap
.eap_methods
[1].vendor
= EAP_VENDOR_IETF
;
1044 ssid
->eap
.eap_methods
[1].method
= EAP_TYPE_NONE
;
1047 if (ttls
&& cred
->username
&& cred
->username
[0]) {
1050 /* Use anonymous NAI in Phase 1 */
1051 pos
= os_strchr(cred
->username
, '@');
1053 size_t buflen
= 9 + os_strlen(pos
) + 1;
1054 anon
= os_malloc(buflen
);
1057 os_snprintf(anon
, buflen
, "anonymous%s", pos
);
1058 } else if (cred
->realm
) {
1059 size_t buflen
= 10 + os_strlen(cred
->realm
) + 1;
1060 anon
= os_malloc(buflen
);
1063 os_snprintf(anon
, buflen
, "anonymous@%s", cred
->realm
);
1065 anon
= os_strdup("anonymous");
1069 if (wpa_config_set_quoted(ssid
, "anonymous_identity", anon
) <
1077 if (cred
->username
&& cred
->username
[0] &&
1078 wpa_config_set_quoted(ssid
, "identity", cred
->username
) < 0)
1081 if (cred
->password
&& cred
->password
[0]) {
1082 if (cred
->ext_password
&&
1083 wpa_config_set(ssid
, "password", cred
->password
, 0) < 0)
1085 if (!cred
->ext_password
&&
1086 wpa_config_set_quoted(ssid
, "password", cred
->password
) <
1091 if (cred
->client_cert
&& cred
->client_cert
[0] &&
1092 wpa_config_set_quoted(ssid
, "client_cert", cred
->client_cert
) < 0)
1096 if (cred
->private_key
&&
1097 os_strncmp(cred
->private_key
, "keystore://", 11) == 0) {
1098 /* Use OpenSSL engine configuration for Android keystore */
1099 if (wpa_config_set_quoted(ssid
, "engine_id", "keystore") < 0 ||
1100 wpa_config_set_quoted(ssid
, "key_id",
1101 cred
->private_key
+ 11) < 0 ||
1102 wpa_config_set(ssid
, "engine", "1", 0) < 0)
1105 #endif /* ANDROID */
1106 if (cred
->private_key
&& cred
->private_key
[0] &&
1107 wpa_config_set_quoted(ssid
, "private_key", cred
->private_key
) < 0)
1110 if (cred
->private_key_passwd
&& cred
->private_key_passwd
[0] &&
1111 wpa_config_set_quoted(ssid
, "private_key_passwd",
1112 cred
->private_key_passwd
) < 0)
1116 os_free(ssid
->eap
.phase1
);
1117 ssid
->eap
.phase1
= os_strdup(cred
->phase1
);
1120 os_free(ssid
->eap
.phase2
);
1121 ssid
->eap
.phase2
= os_strdup(cred
->phase2
);
1124 if (cred
->ca_cert
&& cred
->ca_cert
[0] &&
1125 wpa_config_set_quoted(ssid
, "ca_cert", cred
->ca_cert
) < 0)
1128 if (cred
->domain_suffix_match
&& cred
->domain_suffix_match
[0] &&
1129 wpa_config_set_quoted(ssid
, "domain_suffix_match",
1130 cred
->domain_suffix_match
) < 0)
1137 static int interworking_connect_roaming_consortium(
1138 struct wpa_supplicant
*wpa_s
, struct wpa_cred
*cred
,
1139 struct wpa_bss
*bss
, const u8
*ssid_ie
)
1141 struct wpa_ssid
*ssid
;
1143 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
" based on "
1144 "roaming consortium match", MAC2STR(bss
->bssid
));
1146 ssid
= wpa_config_add_network(wpa_s
->conf
);
1149 ssid
->parent_cred
= cred
;
1150 wpas_notify_network_added(wpa_s
, ssid
);
1151 wpa_config_set_network_defaults(ssid
);
1152 ssid
->priority
= cred
->priority
;
1153 ssid
->temporary
= 1;
1154 ssid
->ssid
= os_zalloc(ssid_ie
[1] + 1);
1155 if (ssid
->ssid
== NULL
)
1157 os_memcpy(ssid
->ssid
, ssid_ie
+ 2, ssid_ie
[1]);
1158 ssid
->ssid_len
= ssid_ie
[1];
1160 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
1163 if (cred
->eap_method
== NULL
) {
1164 wpa_printf(MSG_DEBUG
, "Interworking: No EAP method set for "
1165 "credential using roaming consortium");
1169 if (interworking_set_eap_params(
1171 cred
->eap_method
->vendor
== EAP_VENDOR_IETF
&&
1172 cred
->eap_method
->method
== EAP_TYPE_TTLS
) < 0)
1175 wpa_config_update_prio_list(wpa_s
->conf
);
1176 interworking_reconnect(wpa_s
);
1181 wpas_notify_network_removed(wpa_s
, ssid
);
1182 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
1187 int interworking_connect(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1189 struct wpa_cred
*cred
, *cred_rc
, *cred_3gpp
;
1190 struct wpa_ssid
*ssid
;
1191 struct nai_realm
*realm
;
1192 struct nai_realm_eap
*eap
= NULL
;
1197 if (wpa_s
->conf
->cred
== NULL
|| bss
== NULL
)
1199 ie
= wpa_bss_get_ie(bss
, WLAN_EID_SSID
);
1200 if (ie
== NULL
|| ie
[1] == 0) {
1201 wpa_printf(MSG_DEBUG
, "Interworking: No SSID known for "
1202 MACSTR
, MAC2STR(bss
->bssid
));
1206 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) {
1208 * We currently support only HS 2.0 networks and those are
1209 * required to use WPA2-Enterprise.
1211 wpa_printf(MSG_DEBUG
, "Interworking: Network does not use "
1216 cred_rc
= interworking_credentials_available_roaming_consortium(wpa_s
,
1219 wpa_printf(MSG_DEBUG
, "Interworking: Highest roaming "
1220 "consortium matching credential priority %d",
1224 cred
= interworking_credentials_available_realm(wpa_s
, bss
);
1226 wpa_printf(MSG_DEBUG
, "Interworking: Highest NAI Realm list "
1227 "matching credential priority %d",
1231 cred_3gpp
= interworking_credentials_available_3gpp(wpa_s
, bss
);
1233 wpa_printf(MSG_DEBUG
, "Interworking: Highest 3GPP matching "
1234 "credential priority %d", cred_3gpp
->priority
);
1238 (cred
== NULL
|| cred_rc
->priority
>= cred
->priority
) &&
1239 (cred_3gpp
== NULL
|| cred_rc
->priority
>= cred_3gpp
->priority
))
1240 return interworking_connect_roaming_consortium(wpa_s
, cred_rc
,
1244 (cred
== NULL
|| cred_3gpp
->priority
>= cred
->priority
)) {
1245 return interworking_connect_3gpp(wpa_s
, cred_3gpp
, bss
);
1249 wpa_printf(MSG_DEBUG
, "Interworking: No matching credentials "
1250 "found for " MACSTR
, MAC2STR(bss
->bssid
));
1254 realm
= nai_realm_parse(bss
->anqp
? bss
->anqp
->nai_realm
: NULL
,
1256 if (realm
== NULL
) {
1257 wpa_printf(MSG_DEBUG
, "Interworking: Could not parse NAI "
1258 "Realm list from " MACSTR
, MAC2STR(bss
->bssid
));
1262 for (i
= 0; i
< count
; i
++) {
1263 if (!nai_realm_match(&realm
[i
], cred
->realm
))
1265 eap
= nai_realm_find_eap(cred
, &realm
[i
]);
1271 wpa_printf(MSG_DEBUG
, "Interworking: No matching credentials "
1272 "and EAP method found for " MACSTR
,
1273 MAC2STR(bss
->bssid
));
1274 nai_realm_free(realm
, count
);
1278 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
,
1279 MAC2STR(bss
->bssid
));
1281 ssid
= wpa_config_add_network(wpa_s
->conf
);
1283 nai_realm_free(realm
, count
);
1286 ssid
->parent_cred
= cred
;
1287 wpas_notify_network_added(wpa_s
, ssid
);
1288 wpa_config_set_network_defaults(ssid
);
1289 ssid
->priority
= cred
->priority
;
1290 ssid
->temporary
= 1;
1291 ssid
->ssid
= os_zalloc(ie
[1] + 1);
1292 if (ssid
->ssid
== NULL
)
1294 os_memcpy(ssid
->ssid
, ie
+ 2, ie
[1]);
1295 ssid
->ssid_len
= ie
[1];
1297 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
1300 if (wpa_config_set(ssid
, "eap", eap_get_name(EAP_VENDOR_IETF
,
1301 eap
->method
), 0) < 0)
1304 switch (eap
->method
) {
1306 if (eap
->inner_method
) {
1307 os_snprintf(buf
, sizeof(buf
), "\"autheap=%s\"",
1308 eap_get_name(EAP_VENDOR_IETF
,
1309 eap
->inner_method
));
1310 if (wpa_config_set(ssid
, "phase2", buf
, 0) < 0)
1314 switch (eap
->inner_non_eap
) {
1315 case NAI_REALM_INNER_NON_EAP_PAP
:
1316 if (wpa_config_set(ssid
, "phase2", "\"auth=PAP\"", 0) <
1320 case NAI_REALM_INNER_NON_EAP_CHAP
:
1321 if (wpa_config_set(ssid
, "phase2", "\"auth=CHAP\"", 0)
1325 case NAI_REALM_INNER_NON_EAP_MSCHAP
:
1326 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAP\"",
1330 case NAI_REALM_INNER_NON_EAP_MSCHAPV2
:
1331 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAPV2\"",
1336 /* EAP params were not set - assume TTLS/MSCHAPv2 */
1337 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAPV2\"",
1344 os_snprintf(buf
, sizeof(buf
), "\"auth=%s\"",
1345 eap_get_name(EAP_VENDOR_IETF
,
1348 EAP_TYPE_MSCHAPV2
));
1349 if (wpa_config_set(ssid
, "phase2", buf
, 0) < 0)
1356 if (interworking_set_eap_params(ssid
, cred
,
1357 eap
->method
== EAP_TYPE_TTLS
) < 0)
1360 nai_realm_free(realm
, count
);
1362 wpa_config_update_prio_list(wpa_s
->conf
);
1363 interworking_reconnect(wpa_s
);
1368 wpas_notify_network_removed(wpa_s
, ssid
);
1369 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
1370 nai_realm_free(realm
, count
);
1375 static struct wpa_cred
* interworking_credentials_available_3gpp(
1376 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1378 struct wpa_cred
*selected
= NULL
;
1379 #ifdef INTERWORKING_3GPP
1380 struct wpa_cred
*cred
;
1383 if (bss
->anqp
== NULL
|| bss
->anqp
->anqp_3gpp
== NULL
)
1386 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1394 if (cred
->pcsc
&& wpa_s
->conf
->pcsc_reader
&& wpa_s
->scard
&&
1397 mnc_len
= wpa_s
->mnc_len
;
1400 #endif /* PCSC_FUNCS */
1401 #ifdef CONFIG_EAP_PROXY
1402 if (cred
->pcsc
&& wpa_s
->mnc_len
> 0 && wpa_s
->imsi
[0]) {
1404 mnc_len
= wpa_s
->mnc_len
;
1407 #endif /* CONFIG_EAP_PROXY */
1409 if (cred
->imsi
== NULL
|| !cred
->imsi
[0] ||
1410 (!wpa_s
->conf
->external_sim
&&
1411 (cred
->milenage
== NULL
|| !cred
->milenage
[0])))
1414 sep
= os_strchr(cred
->imsi
, '-');
1416 (sep
- cred
->imsi
!= 5 && sep
- cred
->imsi
!= 6))
1418 mnc_len
= sep
- cred
->imsi
- 3;
1419 os_memcpy(imsi_buf
, cred
->imsi
, 3 + mnc_len
);
1421 msin_len
= os_strlen(cred
->imsi
);
1422 if (3 + mnc_len
+ msin_len
>= sizeof(imsi_buf
) - 1)
1423 msin_len
= sizeof(imsi_buf
) - 3 - mnc_len
- 1;
1424 os_memcpy(&imsi_buf
[3 + mnc_len
], sep
, msin_len
);
1425 imsi_buf
[3 + mnc_len
+ msin_len
] = '\0';
1428 #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
1430 #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
1431 wpa_printf(MSG_DEBUG
, "Interworking: Parsing 3GPP info from "
1432 MACSTR
, MAC2STR(bss
->bssid
));
1433 ret
= plmn_id_match(bss
->anqp
->anqp_3gpp
, imsi
, mnc_len
);
1434 wpa_printf(MSG_DEBUG
, "PLMN match %sfound", ret
? "" : "not ");
1436 if (cred_excluded_ssid(cred
, bss
))
1438 if (cred_no_required_oi_match(cred
, bss
))
1440 if (selected
== NULL
||
1441 selected
->priority
< cred
->priority
)
1445 #endif /* INTERWORKING_3GPP */
1450 static struct wpa_cred
* interworking_credentials_available_realm(
1451 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1453 struct wpa_cred
*cred
, *selected
= NULL
;
1454 struct nai_realm
*realm
;
1457 if (bss
->anqp
== NULL
|| bss
->anqp
->nai_realm
== NULL
)
1460 if (wpa_s
->conf
->cred
== NULL
)
1463 wpa_printf(MSG_DEBUG
, "Interworking: Parsing NAI Realm list from "
1464 MACSTR
, MAC2STR(bss
->bssid
));
1465 realm
= nai_realm_parse(bss
->anqp
->nai_realm
, &count
);
1466 if (realm
== NULL
) {
1467 wpa_printf(MSG_DEBUG
, "Interworking: Could not parse NAI "
1468 "Realm list from " MACSTR
, MAC2STR(bss
->bssid
));
1472 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1473 if (cred
->realm
== NULL
)
1476 for (i
= 0; i
< count
; i
++) {
1477 if (!nai_realm_match(&realm
[i
], cred
->realm
))
1479 if (nai_realm_find_eap(cred
, &realm
[i
])) {
1480 if (cred_excluded_ssid(cred
, bss
))
1482 if (cred_no_required_oi_match(cred
, bss
))
1484 if (selected
== NULL
||
1485 selected
->priority
< cred
->priority
)
1492 nai_realm_free(realm
, count
);
1498 static struct wpa_cred
* interworking_credentials_available(
1499 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1501 struct wpa_cred
*cred
, *cred2
;
1503 cred
= interworking_credentials_available_realm(wpa_s
, bss
);
1504 cred2
= interworking_credentials_available_3gpp(wpa_s
, bss
);
1505 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1510 cred2
= interworking_credentials_available_roaming_consortium(wpa_s
,
1512 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1521 static int domain_name_list_contains(struct wpabuf
*domain_names
,
1524 const u8
*pos
, *end
;
1527 len
= os_strlen(domain
);
1528 pos
= wpabuf_head(domain_names
);
1529 end
= pos
+ wpabuf_len(domain_names
);
1531 while (pos
+ 1 < end
) {
1532 if (pos
+ 1 + pos
[0] > end
)
1535 wpa_hexdump_ascii(MSG_DEBUG
, "Interworking: AP domain name",
1537 if (pos
[0] == len
&&
1538 os_strncasecmp(domain
, (const char *) (pos
+ 1), len
) == 0)
1548 int interworking_home_sp_cred(struct wpa_supplicant
*wpa_s
,
1549 struct wpa_cred
*cred
,
1550 struct wpabuf
*domain_names
)
1553 #ifdef INTERWORKING_3GPP
1554 char nai
[100], *realm
;
1561 else if (cred
->pcsc
&& wpa_s
->conf
->pcsc_reader
&&
1562 wpa_s
->scard
&& wpa_s
->imsi
[0]) {
1564 mnc_len
= wpa_s
->mnc_len
;
1566 #endif /* CONFIG_PCSC */
1567 #ifdef CONFIG_EAP_PROXY
1568 else if (cred
->pcsc
&& wpa_s
->mnc_len
> 0 && wpa_s
->imsi
[0]) {
1570 mnc_len
= wpa_s
->mnc_len
;
1572 #endif /* CONFIG_EAP_PROXY */
1574 imsi
&& build_root_nai(nai
, sizeof(nai
), imsi
, mnc_len
, 0) == 0) {
1575 realm
= os_strchr(nai
, '@');
1578 wpa_printf(MSG_DEBUG
, "Interworking: Search for match "
1579 "with SIM/USIM domain %s", realm
);
1581 domain_name_list_contains(domain_names
, realm
))
1584 #endif /* INTERWORKING_3GPP */
1586 if (domain_names
== NULL
|| cred
->domain
== NULL
)
1589 for (i
= 0; i
< cred
->num_domain
; i
++) {
1590 wpa_printf(MSG_DEBUG
, "Interworking: Search for match with "
1591 "home SP FQDN %s", cred
->domain
[i
]);
1592 if (domain_name_list_contains(domain_names
, cred
->domain
[i
]))
1600 static int interworking_home_sp(struct wpa_supplicant
*wpa_s
,
1601 struct wpabuf
*domain_names
)
1603 struct wpa_cred
*cred
;
1605 if (domain_names
== NULL
|| wpa_s
->conf
->cred
== NULL
)
1608 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1609 int res
= interworking_home_sp_cred(wpa_s
, cred
, domain_names
);
1618 static int interworking_find_network_match(struct wpa_supplicant
*wpa_s
)
1620 struct wpa_bss
*bss
;
1621 struct wpa_ssid
*ssid
;
1623 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1624 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
) {
1625 if (wpas_network_disabled(wpa_s
, ssid
) ||
1626 ssid
->mode
!= WPAS_MODE_INFRA
)
1628 if (ssid
->ssid_len
!= bss
->ssid_len
||
1629 os_memcmp(ssid
->ssid
, bss
->ssid
, ssid
->ssid_len
) !=
1633 * TODO: Consider more accurate matching of security
1634 * configuration similarly to what is done in events.c
1644 static void interworking_select_network(struct wpa_supplicant
*wpa_s
)
1646 struct wpa_bss
*bss
, *selected
= NULL
, *selected_home
= NULL
;
1647 int selected_prio
= -999999, selected_home_prio
= -999999;
1648 unsigned int count
= 0;
1651 struct wpa_cred
*cred
;
1653 wpa_s
->network_select
= 0;
1655 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1656 cred
= interworking_credentials_available(wpa_s
, bss
);
1659 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) {
1661 * We currently support only HS 2.0 networks and those
1662 * are required to use WPA2-Enterprise.
1664 wpa_printf(MSG_DEBUG
, "Interworking: Credential match "
1665 "with " MACSTR
" but network does not use "
1666 "RSN", MAC2STR(bss
->bssid
));
1670 res
= interworking_home_sp(wpa_s
, bss
->anqp
?
1671 bss
->anqp
->domain_name
: NULL
);
1678 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_AP MACSTR
" type=%s",
1679 MAC2STR(bss
->bssid
), type
);
1680 if (wpa_s
->auto_select
||
1681 (wpa_s
->conf
->auto_interworking
&&
1682 wpa_s
->auto_network_select
)) {
1683 if (selected
== NULL
||
1684 cred
->priority
> selected_prio
) {
1686 selected_prio
= cred
->priority
;
1689 (selected_home
== NULL
||
1690 cred
->priority
> selected_home_prio
)) {
1691 selected_home
= bss
;
1692 selected_home_prio
= cred
->priority
;
1697 if (selected_home
&& selected_home
!= selected
&&
1698 selected_home_prio
>= selected_prio
) {
1699 /* Prefer network operated by the Home SP */
1700 selected
= selected_home
;
1705 * No matching network was found based on configured
1706 * credentials. Check whether any of the enabled network blocks
1707 * have matching APs.
1709 if (interworking_find_network_match(wpa_s
)) {
1710 wpa_printf(MSG_DEBUG
, "Interworking: Possible BSS "
1711 "match for enabled network configurations");
1712 if (wpa_s
->auto_select
)
1713 interworking_reconnect(wpa_s
);
1717 if (wpa_s
->auto_network_select
) {
1718 wpa_printf(MSG_DEBUG
, "Interworking: Continue "
1719 "scanning after ANQP fetch");
1720 wpa_supplicant_req_scan(wpa_s
, wpa_s
->scan_interval
,
1725 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_NO_MATCH
"No network "
1726 "with matching credentials found");
1730 interworking_connect(wpa_s
, selected
);
1734 static struct wpa_bss_anqp
*
1735 interworking_match_anqp_info(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1737 struct wpa_bss
*other
;
1739 if (is_zero_ether_addr(bss
->hessid
))
1740 return NULL
; /* Cannot be in the same homegenous ESS */
1742 dl_list_for_each(other
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1745 if (other
->anqp
== NULL
)
1747 if (other
->anqp
->roaming_consortium
== NULL
&&
1748 other
->anqp
->nai_realm
== NULL
&&
1749 other
->anqp
->anqp_3gpp
== NULL
&&
1750 other
->anqp
->domain_name
== NULL
)
1752 if (!(other
->flags
& WPA_BSS_ANQP_FETCH_TRIED
))
1754 if (os_memcmp(bss
->hessid
, other
->hessid
, ETH_ALEN
) != 0)
1756 if (bss
->ssid_len
!= other
->ssid_len
||
1757 os_memcmp(bss
->ssid
, other
->ssid
, bss
->ssid_len
) != 0)
1760 wpa_printf(MSG_DEBUG
, "Interworking: Share ANQP data with "
1761 "already fetched BSSID " MACSTR
" and " MACSTR
,
1762 MAC2STR(other
->bssid
), MAC2STR(bss
->bssid
));
1763 other
->anqp
->users
++;
1771 static void interworking_next_anqp_fetch(struct wpa_supplicant
*wpa_s
)
1773 struct wpa_bss
*bss
;
1777 if (eloop_terminated() || !wpa_s
->fetch_anqp_in_progress
)
1780 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1781 if (!(bss
->caps
& IEEE80211_CAP_ESS
))
1783 ie
= wpa_bss_get_ie(bss
, WLAN_EID_EXT_CAPAB
);
1784 if (ie
== NULL
|| ie
[1] < 4 || !(ie
[5] & 0x80))
1785 continue; /* AP does not support Interworking */
1787 if (!(bss
->flags
& WPA_BSS_ANQP_FETCH_TRIED
)) {
1788 if (bss
->anqp
== NULL
) {
1789 bss
->anqp
= interworking_match_anqp_info(wpa_s
,
1792 /* Shared data already fetched */
1795 bss
->anqp
= wpa_bss_anqp_alloc();
1796 if (bss
->anqp
== NULL
)
1800 bss
->flags
|= WPA_BSS_ANQP_FETCH_TRIED
;
1801 wpa_msg(wpa_s
, MSG_INFO
, "Starting ANQP fetch for "
1802 MACSTR
, MAC2STR(bss
->bssid
));
1803 interworking_anqp_send_req(wpa_s
, bss
);
1809 wpa_msg(wpa_s
, MSG_INFO
, "ANQP fetch completed");
1810 wpa_s
->fetch_anqp_in_progress
= 0;
1811 if (wpa_s
->network_select
)
1812 interworking_select_network(wpa_s
);
1817 void interworking_start_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1819 struct wpa_bss
*bss
;
1821 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
)
1822 bss
->flags
&= ~WPA_BSS_ANQP_FETCH_TRIED
;
1824 wpa_s
->fetch_anqp_in_progress
= 1;
1825 interworking_next_anqp_fetch(wpa_s
);
1829 int interworking_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1831 if (wpa_s
->fetch_anqp_in_progress
|| wpa_s
->network_select
)
1834 wpa_s
->network_select
= 0;
1835 wpa_s
->fetch_all_anqp
= 1;
1837 interworking_start_fetch_anqp(wpa_s
);
1843 void interworking_stop_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1845 if (!wpa_s
->fetch_anqp_in_progress
)
1848 wpa_s
->fetch_anqp_in_progress
= 0;
1852 int anqp_send_req(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
1853 u16 info_ids
[], size_t num_ids
)
1858 struct wpa_bss
*bss
;
1861 freq
= wpa_s
->assoc_freq
;
1862 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
1864 wpa_bss_anqp_unshare_alloc(bss
);
1870 wpa_printf(MSG_DEBUG
, "ANQP: Query Request to " MACSTR
" for %u id(s)",
1871 MAC2STR(dst
), (unsigned int) num_ids
);
1873 buf
= anqp_build_req(info_ids
, num_ids
, NULL
);
1877 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, anqp_resp_cb
, wpa_s
);
1879 wpa_printf(MSG_DEBUG
, "ANQP: Failed to send Query Request");
1883 wpa_printf(MSG_DEBUG
, "ANQP: Query started with dialog token "
1890 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant
*wpa_s
,
1891 struct wpa_bss
*bss
, const u8
*sa
,
1893 const u8
*data
, size_t slen
)
1895 const u8
*pos
= data
;
1896 struct wpa_bss_anqp
*anqp
= NULL
;
1899 #endif /* CONFIG_HS20 */
1905 case ANQP_CAPABILITY_LIST
:
1906 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1907 " ANQP Capability list", MAC2STR(sa
));
1909 case ANQP_VENUE_NAME
:
1910 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1911 " Venue Name", MAC2STR(sa
));
1912 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Venue Name", pos
, slen
);
1914 wpabuf_free(anqp
->venue_name
);
1915 anqp
->venue_name
= wpabuf_alloc_copy(pos
, slen
);
1918 case ANQP_NETWORK_AUTH_TYPE
:
1919 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1920 " Network Authentication Type information",
1922 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Network Authentication "
1925 wpabuf_free(anqp
->network_auth_type
);
1926 anqp
->network_auth_type
= wpabuf_alloc_copy(pos
, slen
);
1929 case ANQP_ROAMING_CONSORTIUM
:
1930 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1931 " Roaming Consortium list", MAC2STR(sa
));
1932 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Roaming Consortium",
1935 wpabuf_free(anqp
->roaming_consortium
);
1936 anqp
->roaming_consortium
= wpabuf_alloc_copy(pos
, slen
);
1939 case ANQP_IP_ADDR_TYPE_AVAILABILITY
:
1940 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1941 " IP Address Type Availability information",
1943 wpa_hexdump(MSG_MSGDUMP
, "ANQP: IP Address Availability",
1946 wpabuf_free(anqp
->ip_addr_type_availability
);
1947 anqp
->ip_addr_type_availability
=
1948 wpabuf_alloc_copy(pos
, slen
);
1951 case ANQP_NAI_REALM
:
1952 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1953 " NAI Realm list", MAC2STR(sa
));
1954 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: NAI Realm", pos
, slen
);
1956 wpabuf_free(anqp
->nai_realm
);
1957 anqp
->nai_realm
= wpabuf_alloc_copy(pos
, slen
);
1960 case ANQP_3GPP_CELLULAR_NETWORK
:
1961 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1962 " 3GPP Cellular Network information", MAC2STR(sa
));
1963 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: 3GPP Cellular Network",
1966 wpabuf_free(anqp
->anqp_3gpp
);
1967 anqp
->anqp_3gpp
= wpabuf_alloc_copy(pos
, slen
);
1970 case ANQP_DOMAIN_NAME
:
1971 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1972 " Domain Name list", MAC2STR(sa
));
1973 wpa_hexdump_ascii(MSG_MSGDUMP
, "ANQP: Domain Name", pos
, slen
);
1975 wpabuf_free(anqp
->domain_name
);
1976 anqp
->domain_name
= wpabuf_alloc_copy(pos
, slen
);
1979 case ANQP_VENDOR_SPECIFIC
:
1983 switch (WPA_GET_BE24(pos
)) {
1995 case HS20_ANQP_OUI_TYPE
:
1996 hs20_parse_rx_hs20_anqp_resp(wpa_s
, sa
, pos
,
2000 wpa_printf(MSG_DEBUG
, "HS20: Unsupported ANQP "
2001 "vendor type %u", type
);
2005 #endif /* CONFIG_HS20 */
2007 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported "
2008 "vendor-specific ANQP OUI %06x",
2014 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported ANQP Info ID "
2021 void anqp_resp_cb(void *ctx
, const u8
*dst
, u8 dialog_token
,
2022 enum gas_query_result result
,
2023 const struct wpabuf
*adv_proto
,
2024 const struct wpabuf
*resp
, u16 status_code
)
2026 struct wpa_supplicant
*wpa_s
= ctx
;
2031 struct wpa_bss
*bss
= NULL
, *tmp
;
2033 if (result
!= GAS_QUERY_SUCCESS
)
2036 pos
= wpabuf_head(adv_proto
);
2037 if (wpabuf_len(adv_proto
) < 4 || pos
[0] != WLAN_EID_ADV_PROTO
||
2038 pos
[1] < 2 || pos
[3] != ACCESS_NETWORK_QUERY_PROTOCOL
) {
2039 wpa_printf(MSG_DEBUG
, "ANQP: Unexpected Advertisement "
2040 "Protocol in response");
2045 * If possible, select the BSS entry based on which BSS entry was used
2046 * for the request. This can help in cases where multiple BSS entries
2047 * may exist for the same AP.
2049 dl_list_for_each_reverse(tmp
, &wpa_s
->bss
, struct wpa_bss
, list
) {
2050 if (tmp
== wpa_s
->interworking_gas_bss
&&
2051 os_memcmp(tmp
->bssid
, dst
, ETH_ALEN
) == 0) {
2057 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2059 pos
= wpabuf_head(resp
);
2060 end
= pos
+ wpabuf_len(resp
);
2063 if (pos
+ 4 > end
) {
2064 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element");
2067 info_id
= WPA_GET_LE16(pos
);
2069 slen
= WPA_GET_LE16(pos
);
2071 if (pos
+ slen
> end
) {
2072 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element length "
2073 "for Info ID %u", info_id
);
2076 interworking_parse_rx_anqp_resp(wpa_s
, bss
, dst
, info_id
, pos
,
2083 static void interworking_scan_res_handler(struct wpa_supplicant
*wpa_s
,
2084 struct wpa_scan_results
*scan_res
)
2086 wpa_printf(MSG_DEBUG
, "Interworking: Scan results available - start "
2088 interworking_start_fetch_anqp(wpa_s
);
2092 int interworking_select(struct wpa_supplicant
*wpa_s
, int auto_select
)
2094 interworking_stop_fetch_anqp(wpa_s
);
2095 wpa_s
->network_select
= 1;
2096 wpa_s
->auto_network_select
= 0;
2097 wpa_s
->auto_select
= !!auto_select
;
2098 wpa_s
->fetch_all_anqp
= 0;
2099 wpa_printf(MSG_DEBUG
, "Interworking: Start scan for network "
2101 wpa_s
->scan_res_handler
= interworking_scan_res_handler
;
2102 wpa_s
->scan_req
= MANUAL_SCAN_REQ
;
2103 wpa_supplicant_req_scan(wpa_s
, 0, 0);
2109 static void gas_resp_cb(void *ctx
, const u8
*addr
, u8 dialog_token
,
2110 enum gas_query_result result
,
2111 const struct wpabuf
*adv_proto
,
2112 const struct wpabuf
*resp
, u16 status_code
)
2114 struct wpa_supplicant
*wpa_s
= ctx
;
2116 wpa_msg(wpa_s
, MSG_INFO
, GAS_RESPONSE_INFO
"addr=" MACSTR
2117 " dialog_token=%d status_code=%d resp_len=%d",
2118 MAC2STR(addr
), dialog_token
, status_code
,
2119 resp
? (int) wpabuf_len(resp
) : -1);
2123 wpabuf_free(wpa_s
->last_gas_resp
);
2124 wpa_s
->last_gas_resp
= wpabuf_dup(resp
);
2125 if (wpa_s
->last_gas_resp
== NULL
)
2127 os_memcpy(wpa_s
->last_gas_addr
, addr
, ETH_ALEN
);
2128 wpa_s
->last_gas_dialog_token
= dialog_token
;
2132 int gas_send_request(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
2133 const struct wpabuf
*adv_proto
,
2134 const struct wpabuf
*query
)
2139 struct wpa_bss
*bss
;
2142 u8 query_resp_len_limit
= 0, pame_bi
= 0;
2144 freq
= wpa_s
->assoc_freq
;
2145 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2151 wpa_printf(MSG_DEBUG
, "GAS request to " MACSTR
" (freq %d MHz)",
2152 MAC2STR(dst
), freq
);
2153 wpa_hexdump_buf(MSG_DEBUG
, "Advertisement Protocol ID", adv_proto
);
2154 wpa_hexdump_buf(MSG_DEBUG
, "GAS Query", query
);
2156 len
= 3 + wpabuf_len(adv_proto
) + 2;
2158 len
+= wpabuf_len(query
);
2159 buf
= gas_build_initial_req(0, len
);
2163 /* Advertisement Protocol IE */
2164 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2165 wpabuf_put_u8(buf
, 1 + wpabuf_len(adv_proto
)); /* Length */
2166 wpabuf_put_u8(buf
, (query_resp_len_limit
& 0x7f) |
2167 (pame_bi
? 0x80 : 0));
2168 wpabuf_put_buf(buf
, adv_proto
);
2172 wpabuf_put_le16(buf
, wpabuf_len(query
));
2173 wpabuf_put_buf(buf
, query
);
2175 wpabuf_put_le16(buf
, 0);
2177 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, gas_resp_cb
, wpa_s
);
2179 wpa_printf(MSG_DEBUG
, "GAS: Failed to send Query Request");
2183 wpa_printf(MSG_DEBUG
, "GAS: Query started with dialog token "