2 * Interworking (IEEE 802.11u)
3 * Copyright (c) 2011-2013, 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 "eapol_supp/eapol_supp_sm.h"
22 #include "rsn_supp/wpa.h"
23 #include "wpa_supplicant_i.h"
25 #include "config_ssid.h"
29 #include "gas_query.h"
30 #include "hs20_supplicant.h"
31 #include "interworking.h"
34 #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
35 #define INTERWORKING_3GPP
37 #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
38 #define INTERWORKING_3GPP
40 #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
41 #define INTERWORKING_3GPP
46 static void interworking_next_anqp_fetch(struct wpa_supplicant
*wpa_s
);
47 static struct wpa_cred
* interworking_credentials_available_realm(
48 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
);
49 static struct wpa_cred
* interworking_credentials_available_3gpp(
50 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
);
53 static void interworking_reconnect(struct wpa_supplicant
*wpa_s
)
55 if (wpa_s
->wpa_state
>= WPA_AUTHENTICATING
) {
56 wpa_supplicant_cancel_sched_scan(wpa_s
);
57 wpa_supplicant_deauthenticate(wpa_s
,
58 WLAN_REASON_DEAUTH_LEAVING
);
60 wpa_s
->disconnected
= 0;
61 wpa_s
->reassociate
= 1;
63 if (wpa_supplicant_fast_associate(wpa_s
) >= 0)
66 wpa_supplicant_req_scan(wpa_s
, 0, 0);
70 static struct wpabuf
* anqp_build_req(u16 info_ids
[], size_t num_ids
,
77 buf
= gas_anqp_build_initial_req(0, 4 + num_ids
* 2 +
78 (extra
? wpabuf_len(extra
) : 0));
82 len_pos
= gas_anqp_add_element(buf
, ANQP_QUERY_LIST
);
83 for (i
= 0; i
< num_ids
; i
++)
84 wpabuf_put_le16(buf
, info_ids
[i
]);
85 gas_anqp_set_element_len(buf
, len_pos
);
87 wpabuf_put_buf(buf
, extra
);
89 gas_anqp_set_len(buf
);
95 static void interworking_anqp_resp_cb(void *ctx
, const u8
*dst
,
97 enum gas_query_result result
,
98 const struct wpabuf
*adv_proto
,
99 const struct wpabuf
*resp
,
102 struct wpa_supplicant
*wpa_s
= ctx
;
104 anqp_resp_cb(wpa_s
, dst
, dialog_token
, result
, adv_proto
, resp
,
106 interworking_next_anqp_fetch(wpa_s
);
110 static int cred_with_roaming_consortium(struct wpa_supplicant
*wpa_s
)
112 struct wpa_cred
*cred
;
114 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
115 if (cred
->roaming_consortium_len
)
117 if (cred
->required_roaming_consortium_len
)
124 static int cred_with_3gpp(struct wpa_supplicant
*wpa_s
)
126 struct wpa_cred
*cred
;
128 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
129 if (cred
->pcsc
|| cred
->imsi
)
136 static int cred_with_nai_realm(struct wpa_supplicant
*wpa_s
)
138 struct wpa_cred
*cred
;
140 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
141 if (cred
->pcsc
|| cred
->imsi
)
143 if (!cred
->eap_method
)
145 if (cred
->realm
&& cred
->roaming_consortium_len
== 0)
152 static int cred_with_domain(struct wpa_supplicant
*wpa_s
)
154 struct wpa_cred
*cred
;
156 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
157 if (cred
->domain
|| cred
->pcsc
|| cred
->imsi
)
164 static int additional_roaming_consortiums(struct wpa_bss
*bss
)
167 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
168 if (ie
== NULL
|| ie
[1] == 0)
170 return ie
[2]; /* Number of ANQP OIs */
174 static void interworking_continue_anqp(void *eloop_ctx
, void *sock_ctx
)
176 struct wpa_supplicant
*wpa_s
= eloop_ctx
;
177 interworking_next_anqp_fetch(wpa_s
);
181 static int interworking_anqp_send_req(struct wpa_supplicant
*wpa_s
,
188 size_t num_info_ids
= 0;
189 struct wpabuf
*extra
= NULL
;
190 int all
= wpa_s
->fetch_all_anqp
;
192 wpa_printf(MSG_DEBUG
, "Interworking: ANQP Query Request to " MACSTR
,
193 MAC2STR(bss
->bssid
));
194 wpa_s
->interworking_gas_bss
= bss
;
196 info_ids
[num_info_ids
++] = ANQP_CAPABILITY_LIST
;
198 info_ids
[num_info_ids
++] = ANQP_VENUE_NAME
;
199 info_ids
[num_info_ids
++] = ANQP_NETWORK_AUTH_TYPE
;
201 if (all
|| (cred_with_roaming_consortium(wpa_s
) &&
202 additional_roaming_consortiums(bss
)))
203 info_ids
[num_info_ids
++] = ANQP_ROAMING_CONSORTIUM
;
205 info_ids
[num_info_ids
++] = ANQP_IP_ADDR_TYPE_AVAILABILITY
;
206 if (all
|| cred_with_nai_realm(wpa_s
))
207 info_ids
[num_info_ids
++] = ANQP_NAI_REALM
;
208 if (all
|| cred_with_3gpp(wpa_s
))
209 info_ids
[num_info_ids
++] = ANQP_3GPP_CELLULAR_NETWORK
;
210 if (all
|| cred_with_domain(wpa_s
))
211 info_ids
[num_info_ids
++] = ANQP_DOMAIN_NAME
;
212 wpa_hexdump(MSG_DEBUG
, "Interworking: ANQP Query info",
213 (u8
*) info_ids
, num_info_ids
* 2);
216 if (wpa_bss_get_vendor_ie(bss
, HS20_IE_VENDOR_TYPE
)) {
219 extra
= wpabuf_alloc(100);
223 len_pos
= gas_anqp_add_element(extra
, ANQP_VENDOR_SPECIFIC
);
224 wpabuf_put_be24(extra
, OUI_WFA
);
225 wpabuf_put_u8(extra
, HS20_ANQP_OUI_TYPE
);
226 wpabuf_put_u8(extra
, HS20_STYPE_QUERY_LIST
);
227 wpabuf_put_u8(extra
, 0); /* Reserved */
228 wpabuf_put_u8(extra
, HS20_STYPE_CAPABILITY_LIST
);
231 HS20_STYPE_OPERATOR_FRIENDLY_NAME
);
232 wpabuf_put_u8(extra
, HS20_STYPE_WAN_METRICS
);
233 wpabuf_put_u8(extra
, HS20_STYPE_CONNECTION_CAPABILITY
);
234 wpabuf_put_u8(extra
, HS20_STYPE_OPERATING_CLASS
);
236 gas_anqp_set_element_len(extra
, len_pos
);
238 #endif /* CONFIG_HS20 */
240 buf
= anqp_build_req(info_ids
, num_info_ids
, extra
);
245 res
= gas_query_req(wpa_s
->gas
, bss
->bssid
, bss
->freq
, buf
,
246 interworking_anqp_resp_cb
, wpa_s
);
248 wpa_printf(MSG_DEBUG
, "ANQP: Failed to send Query Request");
251 eloop_register_timeout(0, 0, interworking_continue_anqp
, wpa_s
,
254 wpa_printf(MSG_DEBUG
, "ANQP: Query started with dialog token "
261 struct nai_realm_eap
{
264 enum nai_realm_eap_auth_inner_non_eap inner_non_eap
;
266 u8 tunneled_cred_type
;
273 struct nai_realm_eap
*eap
;
277 static void nai_realm_free(struct nai_realm
*realms
, u16 count
)
283 for (i
= 0; i
< count
; i
++) {
284 os_free(realms
[i
].eap
);
285 os_free(realms
[i
].realm
);
291 static const u8
* nai_realm_parse_eap(struct nai_realm_eap
*e
, const u8
*pos
,
294 u8 elen
, auth_count
, a
;
298 wpa_printf(MSG_DEBUG
, "No room for EAP Method fixed fields");
303 if (pos
+ elen
> end
|| elen
< 2) {
304 wpa_printf(MSG_DEBUG
, "No room for EAP Method subfield");
310 wpa_printf(MSG_DEBUG
, "EAP Method: len=%u method=%u auth_count=%u",
311 elen
, e
->method
, auth_count
);
313 for (a
= 0; a
< auth_count
; a
++) {
316 if (pos
+ 2 > end
|| pos
+ 2 + pos
[1] > end
) {
317 wpa_printf(MSG_DEBUG
, "No room for Authentication "
318 "Parameter subfield");
326 case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH
:
329 e
->inner_non_eap
= *pos
;
330 if (e
->method
!= EAP_TYPE_TTLS
)
333 case NAI_REALM_INNER_NON_EAP_PAP
:
334 wpa_printf(MSG_DEBUG
, "EAP-TTLS/PAP");
336 case NAI_REALM_INNER_NON_EAP_CHAP
:
337 wpa_printf(MSG_DEBUG
, "EAP-TTLS/CHAP");
339 case NAI_REALM_INNER_NON_EAP_MSCHAP
:
340 wpa_printf(MSG_DEBUG
, "EAP-TTLS/MSCHAP");
342 case NAI_REALM_INNER_NON_EAP_MSCHAPV2
:
343 wpa_printf(MSG_DEBUG
, "EAP-TTLS/MSCHAPV2");
347 case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD
:
350 e
->inner_method
= *pos
;
351 wpa_printf(MSG_DEBUG
, "Inner EAP method: %u",
354 case NAI_REALM_EAP_AUTH_CRED_TYPE
:
358 wpa_printf(MSG_DEBUG
, "Credential Type: %u",
361 case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE
:
364 e
->tunneled_cred_type
= *pos
;
365 wpa_printf(MSG_DEBUG
, "Tunneled EAP Method Credential "
366 "Type: %u", e
->tunneled_cred_type
);
369 wpa_printf(MSG_DEBUG
, "Unsupported Authentication "
370 "Parameter: id=%u len=%u", id
, len
);
371 wpa_hexdump(MSG_DEBUG
, "Authentication Parameter "
383 static const u8
* nai_realm_parse_realm(struct nai_realm
*r
, const u8
*pos
,
391 wpa_printf(MSG_DEBUG
, "No room for NAI Realm Data "
396 len
= WPA_GET_LE16(pos
); /* NAI Realm Data field Length */
398 if (pos
+ len
> end
|| len
< 3) {
399 wpa_printf(MSG_DEBUG
, "No room for NAI Realm Data "
401 len
, (unsigned int) (end
- pos
));
406 r
->encoding
= *pos
++;
408 if (pos
+ realm_len
> f_end
) {
409 wpa_printf(MSG_DEBUG
, "No room for NAI Realm "
411 realm_len
, (unsigned int) (f_end
- pos
));
414 wpa_hexdump_ascii(MSG_DEBUG
, "NAI Realm", pos
, realm_len
);
415 r
->realm
= dup_binstr(pos
, realm_len
);
416 if (r
->realm
== NULL
)
420 if (pos
+ 1 > f_end
) {
421 wpa_printf(MSG_DEBUG
, "No room for EAP Method Count");
424 r
->eap_count
= *pos
++;
425 wpa_printf(MSG_DEBUG
, "EAP Count: %u", r
->eap_count
);
426 if (pos
+ r
->eap_count
* 3 > f_end
) {
427 wpa_printf(MSG_DEBUG
, "No room for EAP Methods");
430 r
->eap
= os_calloc(r
->eap_count
, sizeof(struct nai_realm_eap
));
434 for (e
= 0; e
< r
->eap_count
; e
++) {
435 pos
= nai_realm_parse_eap(&r
->eap
[e
], pos
, f_end
);
444 static struct nai_realm
* nai_realm_parse(struct wpabuf
*anqp
, u16
*count
)
446 struct nai_realm
*realm
;
450 if (anqp
== NULL
|| wpabuf_len(anqp
) < 2)
453 pos
= wpabuf_head_u8(anqp
);
454 end
= pos
+ wpabuf_len(anqp
);
455 num
= WPA_GET_LE16(pos
);
456 wpa_printf(MSG_DEBUG
, "NAI Realm Count: %u", num
);
459 if (num
* 5 > end
- pos
) {
460 wpa_printf(MSG_DEBUG
, "Invalid NAI Realm Count %u - not "
461 "enough data (%u octets) for that many realms",
462 num
, (unsigned int) (end
- pos
));
466 realm
= os_calloc(num
, sizeof(struct nai_realm
));
470 for (i
= 0; i
< num
; i
++) {
471 pos
= nai_realm_parse_realm(&realm
[i
], pos
, end
);
473 nai_realm_free(realm
, num
);
483 static int nai_realm_match(struct nai_realm
*realm
, const char *home_realm
)
485 char *tmp
, *pos
, *end
;
488 if (realm
->realm
== NULL
|| home_realm
== NULL
)
491 if (os_strchr(realm
->realm
, ';') == NULL
)
492 return os_strcasecmp(realm
->realm
, home_realm
) == 0;
494 tmp
= os_strdup(realm
->realm
);
500 end
= os_strchr(pos
, ';');
503 if (os_strcasecmp(pos
, home_realm
) == 0) {
518 static int nai_realm_cred_username(struct nai_realm_eap
*eap
)
520 if (eap_get_name(EAP_VENDOR_IETF
, eap
->method
) == NULL
)
521 return 0; /* method not supported */
523 if (eap
->method
!= EAP_TYPE_TTLS
&& eap
->method
!= EAP_TYPE_PEAP
&&
524 eap
->method
!= EAP_TYPE_FAST
) {
525 /* Only tunneled methods with username/password supported */
529 if (eap
->method
== EAP_TYPE_PEAP
|| eap
->method
== EAP_TYPE_FAST
) {
530 if (eap
->inner_method
&&
531 eap_get_name(EAP_VENDOR_IETF
, eap
->inner_method
) == NULL
)
533 if (!eap
->inner_method
&&
534 eap_get_name(EAP_VENDOR_IETF
, EAP_TYPE_MSCHAPV2
) == NULL
)
538 if (eap
->method
== EAP_TYPE_TTLS
) {
539 if (eap
->inner_method
== 0 && eap
->inner_non_eap
== 0)
540 return 1; /* Assume TTLS/MSCHAPv2 is used */
541 if (eap
->inner_method
&&
542 eap_get_name(EAP_VENDOR_IETF
, eap
->inner_method
) == NULL
)
544 if (eap
->inner_non_eap
&&
545 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_PAP
&&
546 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_CHAP
&&
547 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_MSCHAP
&&
548 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_MSCHAPV2
)
552 if (eap
->inner_method
&&
553 eap
->inner_method
!= EAP_TYPE_GTC
&&
554 eap
->inner_method
!= EAP_TYPE_MSCHAPV2
)
561 static int nai_realm_cred_cert(struct nai_realm_eap
*eap
)
563 if (eap_get_name(EAP_VENDOR_IETF
, eap
->method
) == NULL
)
564 return 0; /* method not supported */
566 if (eap
->method
!= EAP_TYPE_TLS
) {
567 /* Only EAP-TLS supported for credential authentication */
575 static struct nai_realm_eap
* nai_realm_find_eap(struct wpa_cred
*cred
,
576 struct nai_realm
*realm
)
581 cred
->username
== NULL
||
582 cred
->username
[0] == '\0' ||
583 ((cred
->password
== NULL
||
584 cred
->password
[0] == '\0') &&
585 (cred
->private_key
== NULL
||
586 cred
->private_key
[0] == '\0')))
589 for (e
= 0; e
< realm
->eap_count
; e
++) {
590 struct nai_realm_eap
*eap
= &realm
->eap
[e
];
591 if (cred
->password
&& cred
->password
[0] &&
592 nai_realm_cred_username(eap
))
594 if (cred
->private_key
&& cred
->private_key
[0] &&
595 nai_realm_cred_cert(eap
))
603 #ifdef INTERWORKING_3GPP
605 static int plmn_id_match(struct wpabuf
*anqp
, const char *imsi
, int mnc_len
)
607 u8 plmn
[3], plmn2
[3];
612 * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
613 * operator is allowed to include only two digits of the MNC, so allow
614 * matches based on both two and three digit MNC assumptions. Since some
615 * SIM/USIM cards may not expose MNC length conveniently, we may be
616 * provided the default MNC length 3 here and as such, checking with MNC
617 * length 2 is justifiable even though 3GPP TS 24.234 does not mention
618 * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
619 * with otherwise matching values would not be good idea in general, so
620 * this should not result in selecting incorrect networks.
622 /* Match with 3 digit MNC */
623 plmn
[0] = (imsi
[0] - '0') | ((imsi
[1] - '0') << 4);
624 plmn
[1] = (imsi
[2] - '0') | ((imsi
[5] - '0') << 4);
625 plmn
[2] = (imsi
[3] - '0') | ((imsi
[4] - '0') << 4);
626 /* Match with 2 digit MNC */
627 plmn2
[0] = (imsi
[0] - '0') | ((imsi
[1] - '0') << 4);
628 plmn2
[1] = (imsi
[2] - '0') | 0xf0;
629 plmn2
[2] = (imsi
[3] - '0') | ((imsi
[4] - '0') << 4);
633 pos
= wpabuf_head_u8(anqp
);
634 end
= pos
+ wpabuf_len(anqp
);
638 wpa_printf(MSG_DEBUG
, "Unsupported GUD version 0x%x", *pos
);
643 if (pos
+ udhl
> end
) {
644 wpa_printf(MSG_DEBUG
, "Invalid UDHL");
649 wpa_printf(MSG_DEBUG
, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
650 plmn
[0], plmn
[1], plmn
[2], plmn2
[0], plmn2
[1], plmn2
[2],
653 while (pos
+ 2 <= end
) {
662 if (iei
== 0 && len
> 0) {
665 wpa_hexdump(MSG_DEBUG
, "Interworking: PLMN List information element",
668 for (i
= 0; i
< num
; i
++) {
671 if (os_memcmp(pos
, plmn
, 3) == 0 ||
672 os_memcmp(pos
, plmn2
, 3) == 0)
673 return 1; /* Found matching PLMN */
677 wpa_hexdump(MSG_DEBUG
, "Interworking: Unrecognized 3GPP information element",
688 static int build_root_nai(char *nai
, size_t nai_len
, const char *imsi
,
689 size_t mnc_len
, char prefix
)
691 const char *sep
, *msin
;
693 size_t msin_len
, plmn_len
;
696 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
698 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
699 * <MNC> is zero-padded to three digits in case two-digit MNC is used
702 if (imsi
== NULL
|| os_strlen(imsi
) > 16) {
703 wpa_printf(MSG_DEBUG
, "No valid IMSI available");
706 sep
= os_strchr(imsi
, '-');
708 plmn_len
= sep
- imsi
;
710 } else if (mnc_len
&& os_strlen(imsi
) >= 3 + mnc_len
) {
711 plmn_len
= 3 + mnc_len
;
712 msin
= imsi
+ plmn_len
;
715 if (plmn_len
!= 5 && plmn_len
!= 6)
717 msin_len
= os_strlen(msin
);
723 os_memcpy(pos
, imsi
, plmn_len
);
725 os_memcpy(pos
, msin
, msin_len
);
727 pos
+= os_snprintf(pos
, end
- pos
, "@wlan.mnc");
737 pos
+= os_snprintf(pos
, end
- pos
, ".mcc%c%c%c.3gppnetwork.org",
738 imsi
[0], imsi
[1], imsi
[2]);
744 static int set_root_nai(struct wpa_ssid
*ssid
, const char *imsi
, char prefix
)
747 if (build_root_nai(nai
, sizeof(nai
), imsi
, 0, prefix
) < 0)
749 return wpa_config_set_quoted(ssid
, "identity", nai
);
752 #endif /* INTERWORKING_3GPP */
755 static int already_connected(struct wpa_supplicant
*wpa_s
,
756 struct wpa_cred
*cred
, struct wpa_bss
*bss
)
758 struct wpa_ssid
*ssid
;
760 if (wpa_s
->wpa_state
< WPA_ASSOCIATED
|| wpa_s
->current_ssid
== NULL
)
763 ssid
= wpa_s
->current_ssid
;
764 if (ssid
->parent_cred
!= cred
)
767 if (ssid
->ssid_len
!= bss
->ssid_len
||
768 os_memcmp(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
) != 0)
775 static void remove_duplicate_network(struct wpa_supplicant
*wpa_s
,
776 struct wpa_cred
*cred
,
779 struct wpa_ssid
*ssid
;
781 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
) {
782 if (ssid
->parent_cred
!= cred
)
784 if (ssid
->ssid_len
!= bss
->ssid_len
||
785 os_memcmp(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
) != 0)
794 wpa_printf(MSG_DEBUG
, "Interworking: Remove duplicate network entry for the same credential");
796 if (ssid
== wpa_s
->current_ssid
) {
797 wpa_sm_set_config(wpa_s
->wpa
, NULL
);
798 eapol_sm_notify_config(wpa_s
->eapol
, NULL
, NULL
);
799 wpa_supplicant_deauthenticate(wpa_s
,
800 WLAN_REASON_DEAUTH_LEAVING
);
803 wpas_notify_network_removed(wpa_s
, ssid
);
804 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
808 static int interworking_set_hs20_params(struct wpa_supplicant
*wpa_s
,
809 struct wpa_ssid
*ssid
)
811 if (wpa_config_set(ssid
, "key_mgmt",
812 wpa_s
->conf
->pmf
!= NO_MGMT_FRAME_PROTECTION
?
813 "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
815 if (wpa_config_set(ssid
, "proto", "RSN", 0) < 0)
817 if (wpa_config_set(ssid
, "pairwise", "CCMP", 0) < 0)
823 static int interworking_connect_3gpp(struct wpa_supplicant
*wpa_s
,
824 struct wpa_cred
*cred
,
827 #ifdef INTERWORKING_3GPP
828 struct wpa_ssid
*ssid
;
833 if (bss
->anqp
== NULL
|| bss
->anqp
->anqp_3gpp
== NULL
)
836 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
" (3GPP)",
837 MAC2STR(bss
->bssid
));
839 if (already_connected(wpa_s
, cred
, bss
)) {
840 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_ALREADY_CONNECTED MACSTR
,
841 MAC2STR(bss
->bssid
));
845 remove_duplicate_network(wpa_s
, cred
, bss
);
847 ssid
= wpa_config_add_network(wpa_s
->conf
);
850 ssid
->parent_cred
= cred
;
852 wpas_notify_network_added(wpa_s
, ssid
);
853 wpa_config_set_network_defaults(ssid
);
854 ssid
->priority
= cred
->priority
;
856 ssid
->ssid
= os_zalloc(bss
->ssid_len
+ 1);
857 if (ssid
->ssid
== NULL
)
859 os_memcpy(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
);
860 ssid
->ssid_len
= bss
->ssid_len
;
862 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
865 eap_type
= EAP_TYPE_SIM
;
866 if (cred
->pcsc
&& wpa_s
->scard
&& scard_supports_umts(wpa_s
->scard
))
867 eap_type
= EAP_TYPE_AKA
;
868 if (cred
->eap_method
&& cred
->eap_method
[0].vendor
== EAP_VENDOR_IETF
) {
869 if (cred
->eap_method
[0].method
== EAP_TYPE_SIM
||
870 cred
->eap_method
[0].method
== EAP_TYPE_AKA
||
871 cred
->eap_method
[0].method
== EAP_TYPE_AKA_PRIME
)
872 eap_type
= cred
->eap_method
[0].method
;
878 res
= wpa_config_set(ssid
, "eap", "SIM", 0);
882 res
= wpa_config_set(ssid
, "eap", "AKA", 0);
884 case EAP_TYPE_AKA_PRIME
:
886 res
= wpa_config_set(ssid
, "eap", "AKA'", 0);
893 wpa_printf(MSG_DEBUG
, "Selected EAP method (%d) not supported",
898 if (!cred
->pcsc
&& set_root_nai(ssid
, cred
->imsi
, prefix
) < 0) {
899 wpa_printf(MSG_DEBUG
, "Failed to set Root NAI");
903 if (cred
->milenage
&& cred
->milenage
[0]) {
904 if (wpa_config_set_quoted(ssid
, "password",
907 } else if (cred
->pcsc
) {
908 if (wpa_config_set_quoted(ssid
, "pcsc", "") < 0)
910 if (wpa_s
->conf
->pcsc_pin
&&
911 wpa_config_set_quoted(ssid
, "pin", wpa_s
->conf
->pcsc_pin
)
916 if (cred
->password
&& cred
->password
[0] &&
917 wpa_config_set_quoted(ssid
, "password", cred
->password
) < 0)
920 wpa_config_update_prio_list(wpa_s
->conf
);
921 interworking_reconnect(wpa_s
);
926 wpas_notify_network_removed(wpa_s
, ssid
);
927 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
928 #endif /* INTERWORKING_3GPP */
933 static int roaming_consortium_element_match(const u8
*ie
, const u8
*rc_id
,
943 end
= ie
+ 2 + ie
[1];
945 /* Roaming Consortium element:
947 * OI #1 and #2 lengths
948 * OI #1, [OI #2], [OI #3]
954 pos
++; /* skip Number of ANQP OIs */
956 if (pos
+ (lens
& 0x0f) + (lens
>> 4) > end
)
959 if ((lens
& 0x0f) == rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
963 if ((lens
>> 4) == rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
967 if (pos
< end
&& (size_t) (end
- pos
) == rc_len
&&
968 os_memcmp(pos
, rc_id
, rc_len
) == 0)
975 static int roaming_consortium_anqp_match(const struct wpabuf
*anqp
,
976 const u8
*rc_id
, size_t rc_len
)
984 pos
= wpabuf_head(anqp
);
985 end
= pos
+ wpabuf_len(anqp
);
987 /* Set of <OI Length, OI> duples */
992 if (len
== rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
1001 static int roaming_consortium_match(const u8
*ie
, const struct wpabuf
*anqp
,
1002 const u8
*rc_id
, size_t rc_len
)
1004 return roaming_consortium_element_match(ie
, rc_id
, rc_len
) ||
1005 roaming_consortium_anqp_match(anqp
, rc_id
, rc_len
);
1009 static int cred_no_required_oi_match(struct wpa_cred
*cred
, struct wpa_bss
*bss
)
1013 if (cred
->required_roaming_consortium_len
== 0)
1016 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
1019 (bss
->anqp
== NULL
|| bss
->anqp
->roaming_consortium
== NULL
))
1022 return !roaming_consortium_match(ie
,
1024 bss
->anqp
->roaming_consortium
: NULL
,
1025 cred
->required_roaming_consortium
,
1026 cred
->required_roaming_consortium_len
);
1030 static int cred_excluded_ssid(struct wpa_cred
*cred
, struct wpa_bss
*bss
)
1034 if (!cred
->excluded_ssid
)
1037 for (i
= 0; i
< cred
->num_excluded_ssid
; i
++) {
1038 struct excluded_ssid
*e
= &cred
->excluded_ssid
[i
];
1039 if (bss
->ssid_len
== e
->ssid_len
&&
1040 os_memcmp(bss
->ssid
, e
->ssid
, e
->ssid_len
) == 0)
1048 static struct wpa_cred
* interworking_credentials_available_roaming_consortium(
1049 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1051 struct wpa_cred
*cred
, *selected
= NULL
;
1054 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
1057 (bss
->anqp
== NULL
|| bss
->anqp
->roaming_consortium
== NULL
))
1060 if (wpa_s
->conf
->cred
== NULL
)
1063 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1064 if (cred
->roaming_consortium_len
== 0)
1067 if (!roaming_consortium_match(ie
,
1069 bss
->anqp
->roaming_consortium
:
1071 cred
->roaming_consortium
,
1072 cred
->roaming_consortium_len
))
1075 if (cred_excluded_ssid(cred
, bss
))
1077 if (cred_no_required_oi_match(cred
, bss
))
1080 if (selected
== NULL
||
1081 selected
->priority
< cred
->priority
)
1089 static int interworking_set_eap_params(struct wpa_ssid
*ssid
,
1090 struct wpa_cred
*cred
, int ttls
)
1092 if (cred
->eap_method
) {
1093 ttls
= cred
->eap_method
->vendor
== EAP_VENDOR_IETF
&&
1094 cred
->eap_method
->method
== EAP_TYPE_TTLS
;
1096 os_free(ssid
->eap
.eap_methods
);
1097 ssid
->eap
.eap_methods
=
1098 os_malloc(sizeof(struct eap_method_type
) * 2);
1099 if (ssid
->eap
.eap_methods
== NULL
)
1101 os_memcpy(ssid
->eap
.eap_methods
, cred
->eap_method
,
1102 sizeof(*cred
->eap_method
));
1103 ssid
->eap
.eap_methods
[1].vendor
= EAP_VENDOR_IETF
;
1104 ssid
->eap
.eap_methods
[1].method
= EAP_TYPE_NONE
;
1107 if (ttls
&& cred
->username
&& cred
->username
[0]) {
1110 /* Use anonymous NAI in Phase 1 */
1111 pos
= os_strchr(cred
->username
, '@');
1113 size_t buflen
= 9 + os_strlen(pos
) + 1;
1114 anon
= os_malloc(buflen
);
1117 os_snprintf(anon
, buflen
, "anonymous%s", pos
);
1118 } else if (cred
->realm
) {
1119 size_t buflen
= 10 + os_strlen(cred
->realm
) + 1;
1120 anon
= os_malloc(buflen
);
1123 os_snprintf(anon
, buflen
, "anonymous@%s", cred
->realm
);
1125 anon
= os_strdup("anonymous");
1129 if (wpa_config_set_quoted(ssid
, "anonymous_identity", anon
) <
1137 if (cred
->username
&& cred
->username
[0] &&
1138 wpa_config_set_quoted(ssid
, "identity", cred
->username
) < 0)
1141 if (cred
->password
&& cred
->password
[0]) {
1142 if (cred
->ext_password
&&
1143 wpa_config_set(ssid
, "password", cred
->password
, 0) < 0)
1145 if (!cred
->ext_password
&&
1146 wpa_config_set_quoted(ssid
, "password", cred
->password
) <
1151 if (cred
->client_cert
&& cred
->client_cert
[0] &&
1152 wpa_config_set_quoted(ssid
, "client_cert", cred
->client_cert
) < 0)
1156 if (cred
->private_key
&&
1157 os_strncmp(cred
->private_key
, "keystore://", 11) == 0) {
1158 /* Use OpenSSL engine configuration for Android keystore */
1159 if (wpa_config_set_quoted(ssid
, "engine_id", "keystore") < 0 ||
1160 wpa_config_set_quoted(ssid
, "key_id",
1161 cred
->private_key
+ 11) < 0 ||
1162 wpa_config_set(ssid
, "engine", "1", 0) < 0)
1165 #endif /* ANDROID */
1166 if (cred
->private_key
&& cred
->private_key
[0] &&
1167 wpa_config_set_quoted(ssid
, "private_key", cred
->private_key
) < 0)
1170 if (cred
->private_key_passwd
&& cred
->private_key_passwd
[0] &&
1171 wpa_config_set_quoted(ssid
, "private_key_passwd",
1172 cred
->private_key_passwd
) < 0)
1176 os_free(ssid
->eap
.phase1
);
1177 ssid
->eap
.phase1
= os_strdup(cred
->phase1
);
1180 os_free(ssid
->eap
.phase2
);
1181 ssid
->eap
.phase2
= os_strdup(cred
->phase2
);
1184 if (cred
->ca_cert
&& cred
->ca_cert
[0] &&
1185 wpa_config_set_quoted(ssid
, "ca_cert", cred
->ca_cert
) < 0)
1188 if (cred
->domain_suffix_match
&& cred
->domain_suffix_match
[0] &&
1189 wpa_config_set_quoted(ssid
, "domain_suffix_match",
1190 cred
->domain_suffix_match
) < 0)
1197 static int interworking_connect_roaming_consortium(
1198 struct wpa_supplicant
*wpa_s
, struct wpa_cred
*cred
,
1199 struct wpa_bss
*bss
)
1201 struct wpa_ssid
*ssid
;
1203 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
" based on "
1204 "roaming consortium match", MAC2STR(bss
->bssid
));
1206 if (already_connected(wpa_s
, cred
, bss
)) {
1207 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_ALREADY_CONNECTED MACSTR
,
1208 MAC2STR(bss
->bssid
));
1212 remove_duplicate_network(wpa_s
, cred
, bss
);
1214 ssid
= wpa_config_add_network(wpa_s
->conf
);
1217 ssid
->parent_cred
= cred
;
1218 wpas_notify_network_added(wpa_s
, ssid
);
1219 wpa_config_set_network_defaults(ssid
);
1220 ssid
->priority
= cred
->priority
;
1221 ssid
->temporary
= 1;
1222 ssid
->ssid
= os_zalloc(bss
->ssid_len
+ 1);
1223 if (ssid
->ssid
== NULL
)
1225 os_memcpy(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
);
1226 ssid
->ssid_len
= bss
->ssid_len
;
1228 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
1231 if (cred
->eap_method
== NULL
) {
1232 wpa_printf(MSG_DEBUG
, "Interworking: No EAP method set for "
1233 "credential using roaming consortium");
1237 if (interworking_set_eap_params(
1239 cred
->eap_method
->vendor
== EAP_VENDOR_IETF
&&
1240 cred
->eap_method
->method
== EAP_TYPE_TTLS
) < 0)
1243 wpa_config_update_prio_list(wpa_s
->conf
);
1244 interworking_reconnect(wpa_s
);
1249 wpas_notify_network_removed(wpa_s
, ssid
);
1250 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
1255 int interworking_connect(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1257 struct wpa_cred
*cred
, *cred_rc
, *cred_3gpp
;
1258 struct wpa_ssid
*ssid
;
1259 struct nai_realm
*realm
;
1260 struct nai_realm_eap
*eap
= NULL
;
1264 if (wpa_s
->conf
->cred
== NULL
|| bss
== NULL
)
1266 if (disallowed_bssid(wpa_s
, bss
->bssid
) ||
1267 disallowed_ssid(wpa_s
, bss
->ssid
, bss
->ssid_len
)) {
1268 wpa_printf(MSG_DEBUG
, "Interworking: Reject connection to disallowed BSS "
1269 MACSTR
, MAC2STR(bss
->bssid
));
1273 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) {
1275 * We currently support only HS 2.0 networks and those are
1276 * required to use WPA2-Enterprise.
1278 wpa_printf(MSG_DEBUG
, "Interworking: Network does not use "
1283 cred_rc
= interworking_credentials_available_roaming_consortium(wpa_s
,
1286 wpa_printf(MSG_DEBUG
, "Interworking: Highest roaming "
1287 "consortium matching credential priority %d",
1291 cred
= interworking_credentials_available_realm(wpa_s
, bss
);
1293 wpa_printf(MSG_DEBUG
, "Interworking: Highest NAI Realm list "
1294 "matching credential priority %d",
1298 cred_3gpp
= interworking_credentials_available_3gpp(wpa_s
, bss
);
1300 wpa_printf(MSG_DEBUG
, "Interworking: Highest 3GPP matching "
1301 "credential priority %d", cred_3gpp
->priority
);
1305 (cred
== NULL
|| cred_rc
->priority
>= cred
->priority
) &&
1306 (cred_3gpp
== NULL
|| cred_rc
->priority
>= cred_3gpp
->priority
))
1307 return interworking_connect_roaming_consortium(wpa_s
, cred_rc
,
1311 (cred
== NULL
|| cred_3gpp
->priority
>= cred
->priority
)) {
1312 return interworking_connect_3gpp(wpa_s
, cred_3gpp
, bss
);
1316 wpa_printf(MSG_DEBUG
, "Interworking: No matching credentials "
1317 "found for " MACSTR
, MAC2STR(bss
->bssid
));
1321 realm
= nai_realm_parse(bss
->anqp
? bss
->anqp
->nai_realm
: NULL
,
1323 if (realm
== NULL
) {
1324 wpa_printf(MSG_DEBUG
, "Interworking: Could not parse NAI "
1325 "Realm list from " MACSTR
, MAC2STR(bss
->bssid
));
1329 for (i
= 0; i
< count
; i
++) {
1330 if (!nai_realm_match(&realm
[i
], cred
->realm
))
1332 eap
= nai_realm_find_eap(cred
, &realm
[i
]);
1338 wpa_printf(MSG_DEBUG
, "Interworking: No matching credentials "
1339 "and EAP method found for " MACSTR
,
1340 MAC2STR(bss
->bssid
));
1341 nai_realm_free(realm
, count
);
1345 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
,
1346 MAC2STR(bss
->bssid
));
1348 if (already_connected(wpa_s
, cred
, bss
)) {
1349 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_ALREADY_CONNECTED MACSTR
,
1350 MAC2STR(bss
->bssid
));
1351 nai_realm_free(realm
, count
);
1355 remove_duplicate_network(wpa_s
, cred
, bss
);
1357 ssid
= wpa_config_add_network(wpa_s
->conf
);
1359 nai_realm_free(realm
, count
);
1362 ssid
->parent_cred
= cred
;
1363 wpas_notify_network_added(wpa_s
, ssid
);
1364 wpa_config_set_network_defaults(ssid
);
1365 ssid
->priority
= cred
->priority
;
1366 ssid
->temporary
= 1;
1367 ssid
->ssid
= os_zalloc(bss
->ssid_len
+ 1);
1368 if (ssid
->ssid
== NULL
)
1370 os_memcpy(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
);
1371 ssid
->ssid_len
= bss
->ssid_len
;
1373 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
1376 if (wpa_config_set(ssid
, "eap", eap_get_name(EAP_VENDOR_IETF
,
1377 eap
->method
), 0) < 0)
1380 switch (eap
->method
) {
1382 if (eap
->inner_method
) {
1383 os_snprintf(buf
, sizeof(buf
), "\"autheap=%s\"",
1384 eap_get_name(EAP_VENDOR_IETF
,
1385 eap
->inner_method
));
1386 if (wpa_config_set(ssid
, "phase2", buf
, 0) < 0)
1390 switch (eap
->inner_non_eap
) {
1391 case NAI_REALM_INNER_NON_EAP_PAP
:
1392 if (wpa_config_set(ssid
, "phase2", "\"auth=PAP\"", 0) <
1396 case NAI_REALM_INNER_NON_EAP_CHAP
:
1397 if (wpa_config_set(ssid
, "phase2", "\"auth=CHAP\"", 0)
1401 case NAI_REALM_INNER_NON_EAP_MSCHAP
:
1402 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAP\"",
1406 case NAI_REALM_INNER_NON_EAP_MSCHAPV2
:
1407 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAPV2\"",
1412 /* EAP params were not set - assume TTLS/MSCHAPv2 */
1413 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAPV2\"",
1421 if (wpa_config_set(ssid
, "phase1", "\"fast_provisioning=2\"",
1424 if (wpa_config_set(ssid
, "pac_file",
1425 "\"blob://pac_interworking\"", 0) < 0)
1427 os_snprintf(buf
, sizeof(buf
), "\"auth=%s\"",
1428 eap_get_name(EAP_VENDOR_IETF
,
1431 EAP_TYPE_MSCHAPV2
));
1432 if (wpa_config_set(ssid
, "phase2", buf
, 0) < 0)
1439 if (interworking_set_eap_params(ssid
, cred
,
1440 eap
->method
== EAP_TYPE_TTLS
) < 0)
1443 nai_realm_free(realm
, count
);
1445 wpa_config_update_prio_list(wpa_s
->conf
);
1446 interworking_reconnect(wpa_s
);
1451 wpas_notify_network_removed(wpa_s
, ssid
);
1452 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
1453 nai_realm_free(realm
, count
);
1458 static struct wpa_cred
* interworking_credentials_available_3gpp(
1459 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1461 struct wpa_cred
*selected
= NULL
;
1462 #ifdef INTERWORKING_3GPP
1463 struct wpa_cred
*cred
;
1466 if (bss
->anqp
== NULL
|| bss
->anqp
->anqp_3gpp
== NULL
)
1469 #ifdef CONFIG_EAP_PROXY
1470 if (!wpa_s
->imsi
[0]) {
1472 wpa_printf(MSG_DEBUG
, "Interworking: IMSI not available - try to read again through eap_proxy");
1473 wpa_s
->mnc_len
= eapol_sm_get_eap_proxy_imsi(wpa_s
->eapol
,
1476 if (wpa_s
->mnc_len
> 0) {
1477 wpa_s
->imsi
[len
] = '\0';
1478 wpa_printf(MSG_DEBUG
, "eap_proxy: IMSI %s (MNC length %d)",
1479 wpa_s
->imsi
, wpa_s
->mnc_len
);
1481 wpa_printf(MSG_DEBUG
, "eap_proxy: IMSI not available");
1484 #endif /* CONFIG_EAP_PROXY */
1486 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1494 if (cred
->pcsc
&& wpa_s
->conf
->pcsc_reader
&& wpa_s
->scard
&&
1497 mnc_len
= wpa_s
->mnc_len
;
1500 #endif /* PCSC_FUNCS */
1501 #ifdef CONFIG_EAP_PROXY
1502 if (cred
->pcsc
&& wpa_s
->mnc_len
> 0 && wpa_s
->imsi
[0]) {
1504 mnc_len
= wpa_s
->mnc_len
;
1507 #endif /* CONFIG_EAP_PROXY */
1509 if (cred
->imsi
== NULL
|| !cred
->imsi
[0] ||
1510 (!wpa_s
->conf
->external_sim
&&
1511 (cred
->milenage
== NULL
|| !cred
->milenage
[0])))
1514 sep
= os_strchr(cred
->imsi
, '-');
1516 (sep
- cred
->imsi
!= 5 && sep
- cred
->imsi
!= 6))
1518 mnc_len
= sep
- cred
->imsi
- 3;
1519 os_memcpy(imsi_buf
, cred
->imsi
, 3 + mnc_len
);
1521 msin_len
= os_strlen(cred
->imsi
);
1522 if (3 + mnc_len
+ msin_len
>= sizeof(imsi_buf
) - 1)
1523 msin_len
= sizeof(imsi_buf
) - 3 - mnc_len
- 1;
1524 os_memcpy(&imsi_buf
[3 + mnc_len
], sep
, msin_len
);
1525 imsi_buf
[3 + mnc_len
+ msin_len
] = '\0';
1528 #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
1530 #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
1531 wpa_printf(MSG_DEBUG
, "Interworking: Parsing 3GPP info from "
1532 MACSTR
, MAC2STR(bss
->bssid
));
1533 ret
= plmn_id_match(bss
->anqp
->anqp_3gpp
, imsi
, mnc_len
);
1534 wpa_printf(MSG_DEBUG
, "PLMN match %sfound", ret
? "" : "not ");
1536 if (cred_excluded_ssid(cred
, bss
))
1538 if (cred_no_required_oi_match(cred
, bss
))
1540 if (selected
== NULL
||
1541 selected
->priority
< cred
->priority
)
1545 #endif /* INTERWORKING_3GPP */
1550 static struct wpa_cred
* interworking_credentials_available_realm(
1551 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1553 struct wpa_cred
*cred
, *selected
= NULL
;
1554 struct nai_realm
*realm
;
1557 if (bss
->anqp
== NULL
|| bss
->anqp
->nai_realm
== NULL
)
1560 if (wpa_s
->conf
->cred
== NULL
)
1563 wpa_printf(MSG_DEBUG
, "Interworking: Parsing NAI Realm list from "
1564 MACSTR
, MAC2STR(bss
->bssid
));
1565 realm
= nai_realm_parse(bss
->anqp
->nai_realm
, &count
);
1566 if (realm
== NULL
) {
1567 wpa_printf(MSG_DEBUG
, "Interworking: Could not parse NAI "
1568 "Realm list from " MACSTR
, MAC2STR(bss
->bssid
));
1572 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1573 if (cred
->realm
== NULL
)
1576 for (i
= 0; i
< count
; i
++) {
1577 if (!nai_realm_match(&realm
[i
], cred
->realm
))
1579 if (nai_realm_find_eap(cred
, &realm
[i
])) {
1580 if (cred_excluded_ssid(cred
, bss
))
1582 if (cred_no_required_oi_match(cred
, bss
))
1584 if (selected
== NULL
||
1585 selected
->priority
< cred
->priority
)
1592 nai_realm_free(realm
, count
);
1598 static struct wpa_cred
* interworking_credentials_available(
1599 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1601 struct wpa_cred
*cred
, *cred2
;
1603 if (disallowed_bssid(wpa_s
, bss
->bssid
) ||
1604 disallowed_ssid(wpa_s
, bss
->ssid
, bss
->ssid_len
)) {
1605 wpa_printf(MSG_DEBUG
, "Interworking: Ignore disallowed BSS "
1606 MACSTR
, MAC2STR(bss
->bssid
));
1610 cred
= interworking_credentials_available_realm(wpa_s
, bss
);
1611 cred2
= interworking_credentials_available_3gpp(wpa_s
, bss
);
1612 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1617 cred2
= interworking_credentials_available_roaming_consortium(wpa_s
,
1619 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1628 static int domain_name_list_contains(struct wpabuf
*domain_names
,
1631 const u8
*pos
, *end
;
1634 len
= os_strlen(domain
);
1635 pos
= wpabuf_head(domain_names
);
1636 end
= pos
+ wpabuf_len(domain_names
);
1638 while (pos
+ 1 < end
) {
1639 if (pos
+ 1 + pos
[0] > end
)
1642 wpa_hexdump_ascii(MSG_DEBUG
, "Interworking: AP domain name",
1644 if (pos
[0] == len
&&
1645 os_strncasecmp(domain
, (const char *) (pos
+ 1), len
) == 0)
1655 int interworking_home_sp_cred(struct wpa_supplicant
*wpa_s
,
1656 struct wpa_cred
*cred
,
1657 struct wpabuf
*domain_names
)
1661 #ifdef INTERWORKING_3GPP
1662 char nai
[100], *realm
;
1669 else if (cred
->pcsc
&& wpa_s
->conf
->pcsc_reader
&&
1670 wpa_s
->scard
&& wpa_s
->imsi
[0]) {
1672 mnc_len
= wpa_s
->mnc_len
;
1674 #endif /* CONFIG_PCSC */
1675 #ifdef CONFIG_EAP_PROXY
1676 else if (cred
->pcsc
&& wpa_s
->mnc_len
> 0 && wpa_s
->imsi
[0]) {
1678 mnc_len
= wpa_s
->mnc_len
;
1680 #endif /* CONFIG_EAP_PROXY */
1682 imsi
&& build_root_nai(nai
, sizeof(nai
), imsi
, mnc_len
, 0) == 0) {
1683 realm
= os_strchr(nai
, '@');
1686 wpa_printf(MSG_DEBUG
, "Interworking: Search for match "
1687 "with SIM/USIM domain %s", realm
);
1689 domain_name_list_contains(domain_names
, realm
))
1694 #endif /* INTERWORKING_3GPP */
1696 if (domain_names
== NULL
|| cred
->domain
== NULL
)
1699 for (i
= 0; i
< cred
->num_domain
; i
++) {
1700 wpa_printf(MSG_DEBUG
, "Interworking: Search for match with "
1701 "home SP FQDN %s", cred
->domain
[i
]);
1702 if (domain_name_list_contains(domain_names
, cred
->domain
[i
]))
1710 static int interworking_home_sp(struct wpa_supplicant
*wpa_s
,
1711 struct wpabuf
*domain_names
)
1713 struct wpa_cred
*cred
;
1715 if (domain_names
== NULL
|| wpa_s
->conf
->cred
== NULL
)
1718 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1719 int res
= interworking_home_sp_cred(wpa_s
, cred
, domain_names
);
1728 static int interworking_find_network_match(struct wpa_supplicant
*wpa_s
)
1730 struct wpa_bss
*bss
;
1731 struct wpa_ssid
*ssid
;
1733 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1734 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
) {
1735 if (wpas_network_disabled(wpa_s
, ssid
) ||
1736 ssid
->mode
!= WPAS_MODE_INFRA
)
1738 if (ssid
->ssid_len
!= bss
->ssid_len
||
1739 os_memcmp(ssid
->ssid
, bss
->ssid
, ssid
->ssid_len
) !=
1743 * TODO: Consider more accurate matching of security
1744 * configuration similarly to what is done in events.c
1754 static void interworking_select_network(struct wpa_supplicant
*wpa_s
)
1756 struct wpa_bss
*bss
, *selected
= NULL
, *selected_home
= NULL
;
1757 int selected_prio
= -999999, selected_home_prio
= -999999;
1758 unsigned int count
= 0;
1761 struct wpa_cred
*cred
;
1763 wpa_s
->network_select
= 0;
1765 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1766 cred
= interworking_credentials_available(wpa_s
, bss
);
1769 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) {
1771 * We currently support only HS 2.0 networks and those
1772 * are required to use WPA2-Enterprise.
1774 wpa_printf(MSG_DEBUG
, "Interworking: Credential match "
1775 "with " MACSTR
" but network does not use "
1776 "RSN", MAC2STR(bss
->bssid
));
1780 res
= interworking_home_sp(wpa_s
, bss
->anqp
?
1781 bss
->anqp
->domain_name
: NULL
);
1788 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_AP MACSTR
" type=%s",
1789 MAC2STR(bss
->bssid
), type
);
1790 if (wpa_s
->auto_select
||
1791 (wpa_s
->conf
->auto_interworking
&&
1792 wpa_s
->auto_network_select
)) {
1793 if (selected
== NULL
||
1794 cred
->priority
> selected_prio
) {
1796 selected_prio
= cred
->priority
;
1799 (selected_home
== NULL
||
1800 cred
->priority
> selected_home_prio
)) {
1801 selected_home
= bss
;
1802 selected_home_prio
= cred
->priority
;
1807 if (selected_home
&& selected_home
!= selected
&&
1808 selected_home_prio
>= selected_prio
) {
1809 /* Prefer network operated by the Home SP */
1810 selected
= selected_home
;
1815 * No matching network was found based on configured
1816 * credentials. Check whether any of the enabled network blocks
1817 * have matching APs.
1819 if (interworking_find_network_match(wpa_s
)) {
1820 wpa_printf(MSG_DEBUG
, "Interworking: Possible BSS "
1821 "match for enabled network configurations");
1822 if (wpa_s
->auto_select
)
1823 interworking_reconnect(wpa_s
);
1827 if (wpa_s
->auto_network_select
) {
1828 wpa_printf(MSG_DEBUG
, "Interworking: Continue "
1829 "scanning after ANQP fetch");
1830 wpa_supplicant_req_scan(wpa_s
, wpa_s
->scan_interval
,
1835 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_NO_MATCH
"No network "
1836 "with matching credentials found");
1840 interworking_connect(wpa_s
, selected
);
1844 static struct wpa_bss_anqp
*
1845 interworking_match_anqp_info(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1847 struct wpa_bss
*other
;
1849 if (is_zero_ether_addr(bss
->hessid
))
1850 return NULL
; /* Cannot be in the same homegenous ESS */
1852 dl_list_for_each(other
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1855 if (other
->anqp
== NULL
)
1857 if (other
->anqp
->roaming_consortium
== NULL
&&
1858 other
->anqp
->nai_realm
== NULL
&&
1859 other
->anqp
->anqp_3gpp
== NULL
&&
1860 other
->anqp
->domain_name
== NULL
)
1862 if (!(other
->flags
& WPA_BSS_ANQP_FETCH_TRIED
))
1864 if (os_memcmp(bss
->hessid
, other
->hessid
, ETH_ALEN
) != 0)
1866 if (bss
->ssid_len
!= other
->ssid_len
||
1867 os_memcmp(bss
->ssid
, other
->ssid
, bss
->ssid_len
) != 0)
1870 wpa_printf(MSG_DEBUG
, "Interworking: Share ANQP data with "
1871 "already fetched BSSID " MACSTR
" and " MACSTR
,
1872 MAC2STR(other
->bssid
), MAC2STR(bss
->bssid
));
1873 other
->anqp
->users
++;
1881 static void interworking_next_anqp_fetch(struct wpa_supplicant
*wpa_s
)
1883 struct wpa_bss
*bss
;
1887 if (eloop_terminated() || !wpa_s
->fetch_anqp_in_progress
)
1890 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1891 if (!(bss
->caps
& IEEE80211_CAP_ESS
))
1893 ie
= wpa_bss_get_ie(bss
, WLAN_EID_EXT_CAPAB
);
1894 if (ie
== NULL
|| ie
[1] < 4 || !(ie
[5] & 0x80))
1895 continue; /* AP does not support Interworking */
1896 if (disallowed_bssid(wpa_s
, bss
->bssid
) ||
1897 disallowed_ssid(wpa_s
, bss
->ssid
, bss
->ssid_len
))
1898 continue; /* Disallowed BSS */
1900 if (!(bss
->flags
& WPA_BSS_ANQP_FETCH_TRIED
)) {
1901 if (bss
->anqp
== NULL
) {
1902 bss
->anqp
= interworking_match_anqp_info(wpa_s
,
1905 /* Shared data already fetched */
1908 bss
->anqp
= wpa_bss_anqp_alloc();
1909 if (bss
->anqp
== NULL
)
1913 bss
->flags
|= WPA_BSS_ANQP_FETCH_TRIED
;
1914 wpa_msg(wpa_s
, MSG_INFO
, "Starting ANQP fetch for "
1915 MACSTR
, MAC2STR(bss
->bssid
));
1916 interworking_anqp_send_req(wpa_s
, bss
);
1922 wpa_msg(wpa_s
, MSG_INFO
, "ANQP fetch completed");
1923 wpa_s
->fetch_anqp_in_progress
= 0;
1924 if (wpa_s
->network_select
)
1925 interworking_select_network(wpa_s
);
1930 void interworking_start_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1932 struct wpa_bss
*bss
;
1934 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
)
1935 bss
->flags
&= ~WPA_BSS_ANQP_FETCH_TRIED
;
1937 wpa_s
->fetch_anqp_in_progress
= 1;
1938 interworking_next_anqp_fetch(wpa_s
);
1942 int interworking_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1944 if (wpa_s
->fetch_anqp_in_progress
|| wpa_s
->network_select
)
1947 wpa_s
->network_select
= 0;
1948 wpa_s
->fetch_all_anqp
= 1;
1950 interworking_start_fetch_anqp(wpa_s
);
1956 void interworking_stop_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1958 if (!wpa_s
->fetch_anqp_in_progress
)
1961 wpa_s
->fetch_anqp_in_progress
= 0;
1965 int anqp_send_req(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
1966 u16 info_ids
[], size_t num_ids
)
1971 struct wpa_bss
*bss
;
1974 freq
= wpa_s
->assoc_freq
;
1975 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
1977 wpa_bss_anqp_unshare_alloc(bss
);
1983 wpa_printf(MSG_DEBUG
, "ANQP: Query Request to " MACSTR
" for %u id(s)",
1984 MAC2STR(dst
), (unsigned int) num_ids
);
1986 buf
= anqp_build_req(info_ids
, num_ids
, NULL
);
1990 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, anqp_resp_cb
, wpa_s
);
1992 wpa_printf(MSG_DEBUG
, "ANQP: Failed to send Query Request");
1996 wpa_printf(MSG_DEBUG
, "ANQP: Query started with dialog token "
2003 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant
*wpa_s
,
2004 struct wpa_bss
*bss
, const u8
*sa
,
2006 const u8
*data
, size_t slen
)
2008 const u8
*pos
= data
;
2009 struct wpa_bss_anqp
*anqp
= NULL
;
2012 #endif /* CONFIG_HS20 */
2018 case ANQP_CAPABILITY_LIST
:
2019 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2020 " ANQP Capability list", MAC2STR(sa
));
2022 case ANQP_VENUE_NAME
:
2023 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2024 " Venue Name", MAC2STR(sa
));
2025 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Venue Name", pos
, slen
);
2027 wpabuf_free(anqp
->venue_name
);
2028 anqp
->venue_name
= wpabuf_alloc_copy(pos
, slen
);
2031 case ANQP_NETWORK_AUTH_TYPE
:
2032 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2033 " Network Authentication Type information",
2035 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Network Authentication "
2038 wpabuf_free(anqp
->network_auth_type
);
2039 anqp
->network_auth_type
= wpabuf_alloc_copy(pos
, slen
);
2042 case ANQP_ROAMING_CONSORTIUM
:
2043 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2044 " Roaming Consortium list", MAC2STR(sa
));
2045 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Roaming Consortium",
2048 wpabuf_free(anqp
->roaming_consortium
);
2049 anqp
->roaming_consortium
= wpabuf_alloc_copy(pos
, slen
);
2052 case ANQP_IP_ADDR_TYPE_AVAILABILITY
:
2053 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2054 " IP Address Type Availability information",
2056 wpa_hexdump(MSG_MSGDUMP
, "ANQP: IP Address Availability",
2059 wpabuf_free(anqp
->ip_addr_type_availability
);
2060 anqp
->ip_addr_type_availability
=
2061 wpabuf_alloc_copy(pos
, slen
);
2064 case ANQP_NAI_REALM
:
2065 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2066 " NAI Realm list", MAC2STR(sa
));
2067 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: NAI Realm", pos
, slen
);
2069 wpabuf_free(anqp
->nai_realm
);
2070 anqp
->nai_realm
= wpabuf_alloc_copy(pos
, slen
);
2073 case ANQP_3GPP_CELLULAR_NETWORK
:
2074 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2075 " 3GPP Cellular Network information", MAC2STR(sa
));
2076 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: 3GPP Cellular Network",
2079 wpabuf_free(anqp
->anqp_3gpp
);
2080 anqp
->anqp_3gpp
= wpabuf_alloc_copy(pos
, slen
);
2083 case ANQP_DOMAIN_NAME
:
2084 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2085 " Domain Name list", MAC2STR(sa
));
2086 wpa_hexdump_ascii(MSG_MSGDUMP
, "ANQP: Domain Name", pos
, slen
);
2088 wpabuf_free(anqp
->domain_name
);
2089 anqp
->domain_name
= wpabuf_alloc_copy(pos
, slen
);
2092 case ANQP_VENDOR_SPECIFIC
:
2096 switch (WPA_GET_BE24(pos
)) {
2108 case HS20_ANQP_OUI_TYPE
:
2109 hs20_parse_rx_hs20_anqp_resp(wpa_s
, sa
, pos
,
2113 wpa_printf(MSG_DEBUG
, "HS20: Unsupported ANQP "
2114 "vendor type %u", type
);
2118 #endif /* CONFIG_HS20 */
2120 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported "
2121 "vendor-specific ANQP OUI %06x",
2127 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported ANQP Info ID "
2134 void anqp_resp_cb(void *ctx
, const u8
*dst
, u8 dialog_token
,
2135 enum gas_query_result result
,
2136 const struct wpabuf
*adv_proto
,
2137 const struct wpabuf
*resp
, u16 status_code
)
2139 struct wpa_supplicant
*wpa_s
= ctx
;
2144 struct wpa_bss
*bss
= NULL
, *tmp
;
2146 if (result
!= GAS_QUERY_SUCCESS
)
2149 pos
= wpabuf_head(adv_proto
);
2150 if (wpabuf_len(adv_proto
) < 4 || pos
[0] != WLAN_EID_ADV_PROTO
||
2151 pos
[1] < 2 || pos
[3] != ACCESS_NETWORK_QUERY_PROTOCOL
) {
2152 wpa_printf(MSG_DEBUG
, "ANQP: Unexpected Advertisement "
2153 "Protocol in response");
2158 * If possible, select the BSS entry based on which BSS entry was used
2159 * for the request. This can help in cases where multiple BSS entries
2160 * may exist for the same AP.
2162 dl_list_for_each_reverse(tmp
, &wpa_s
->bss
, struct wpa_bss
, list
) {
2163 if (tmp
== wpa_s
->interworking_gas_bss
&&
2164 os_memcmp(tmp
->bssid
, dst
, ETH_ALEN
) == 0) {
2170 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2172 pos
= wpabuf_head(resp
);
2173 end
= pos
+ wpabuf_len(resp
);
2176 if (pos
+ 4 > end
) {
2177 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element");
2180 info_id
= WPA_GET_LE16(pos
);
2182 slen
= WPA_GET_LE16(pos
);
2184 if (pos
+ slen
> end
) {
2185 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element length "
2186 "for Info ID %u", info_id
);
2189 interworking_parse_rx_anqp_resp(wpa_s
, bss
, dst
, info_id
, pos
,
2196 static void interworking_scan_res_handler(struct wpa_supplicant
*wpa_s
,
2197 struct wpa_scan_results
*scan_res
)
2199 wpa_printf(MSG_DEBUG
, "Interworking: Scan results available - start "
2201 interworking_start_fetch_anqp(wpa_s
);
2205 int interworking_select(struct wpa_supplicant
*wpa_s
, int auto_select
,
2208 interworking_stop_fetch_anqp(wpa_s
);
2209 wpa_s
->network_select
= 1;
2210 wpa_s
->auto_network_select
= 0;
2211 wpa_s
->auto_select
= !!auto_select
;
2212 wpa_s
->fetch_all_anqp
= 0;
2213 wpa_printf(MSG_DEBUG
, "Interworking: Start scan for network "
2215 wpa_s
->scan_res_handler
= interworking_scan_res_handler
;
2216 wpa_s
->normal_scans
= 0;
2217 wpa_s
->scan_req
= MANUAL_SCAN_REQ
;
2218 os_free(wpa_s
->manual_scan_freqs
);
2219 wpa_s
->manual_scan_freqs
= freqs
;
2220 wpa_s
->after_wps
= 0;
2221 wpa_s
->known_wps_freq
= 0;
2222 wpa_supplicant_req_scan(wpa_s
, 0, 0);
2228 static void gas_resp_cb(void *ctx
, const u8
*addr
, u8 dialog_token
,
2229 enum gas_query_result result
,
2230 const struct wpabuf
*adv_proto
,
2231 const struct wpabuf
*resp
, u16 status_code
)
2233 struct wpa_supplicant
*wpa_s
= ctx
;
2235 wpa_msg(wpa_s
, MSG_INFO
, GAS_RESPONSE_INFO
"addr=" MACSTR
2236 " dialog_token=%d status_code=%d resp_len=%d",
2237 MAC2STR(addr
), dialog_token
, status_code
,
2238 resp
? (int) wpabuf_len(resp
) : -1);
2242 wpabuf_free(wpa_s
->last_gas_resp
);
2243 wpa_s
->last_gas_resp
= wpabuf_dup(resp
);
2244 if (wpa_s
->last_gas_resp
== NULL
)
2246 os_memcpy(wpa_s
->last_gas_addr
, addr
, ETH_ALEN
);
2247 wpa_s
->last_gas_dialog_token
= dialog_token
;
2251 int gas_send_request(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
2252 const struct wpabuf
*adv_proto
,
2253 const struct wpabuf
*query
)
2258 struct wpa_bss
*bss
;
2261 u8 query_resp_len_limit
= 0, pame_bi
= 0;
2263 freq
= wpa_s
->assoc_freq
;
2264 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2270 wpa_printf(MSG_DEBUG
, "GAS request to " MACSTR
" (freq %d MHz)",
2271 MAC2STR(dst
), freq
);
2272 wpa_hexdump_buf(MSG_DEBUG
, "Advertisement Protocol ID", adv_proto
);
2273 wpa_hexdump_buf(MSG_DEBUG
, "GAS Query", query
);
2275 len
= 3 + wpabuf_len(adv_proto
) + 2;
2277 len
+= wpabuf_len(query
);
2278 buf
= gas_build_initial_req(0, len
);
2282 /* Advertisement Protocol IE */
2283 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2284 wpabuf_put_u8(buf
, 1 + wpabuf_len(adv_proto
)); /* Length */
2285 wpabuf_put_u8(buf
, (query_resp_len_limit
& 0x7f) |
2286 (pame_bi
? 0x80 : 0));
2287 wpabuf_put_buf(buf
, adv_proto
);
2291 wpabuf_put_le16(buf
, wpabuf_len(query
));
2292 wpabuf_put_buf(buf
, query
);
2294 wpabuf_put_le16(buf
, 0);
2296 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, gas_resp_cb
, wpa_s
);
2298 wpa_printf(MSG_DEBUG
, "GAS: Failed to send Query Request");
2302 wpa_printf(MSG_DEBUG
, "GAS: Query started with dialog token "