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");
248 eloop_register_timeout(0, 0, interworking_continue_anqp
, wpa_s
,
251 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 cred
->milenage
== NULL
|| !cred
->milenage
[0])
1413 sep
= os_strchr(cred
->imsi
, '-');
1415 (sep
- cred
->imsi
!= 5 && sep
- cred
->imsi
!= 6))
1417 mnc_len
= sep
- cred
->imsi
- 3;
1418 os_memcpy(imsi_buf
, cred
->imsi
, 3 + mnc_len
);
1420 msin_len
= os_strlen(cred
->imsi
);
1421 if (3 + mnc_len
+ msin_len
>= sizeof(imsi_buf
) - 1)
1422 msin_len
= sizeof(imsi_buf
) - 3 - mnc_len
- 1;
1423 os_memcpy(&imsi_buf
[3 + mnc_len
], sep
, msin_len
);
1424 imsi_buf
[3 + mnc_len
+ msin_len
] = '\0';
1427 #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
1429 #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
1430 wpa_printf(MSG_DEBUG
, "Interworking: Parsing 3GPP info from "
1431 MACSTR
, MAC2STR(bss
->bssid
));
1432 ret
= plmn_id_match(bss
->anqp
->anqp_3gpp
, imsi
, mnc_len
);
1433 wpa_printf(MSG_DEBUG
, "PLMN match %sfound", ret
? "" : "not ");
1435 if (cred_excluded_ssid(cred
, bss
))
1437 if (cred_no_required_oi_match(cred
, bss
))
1439 if (selected
== NULL
||
1440 selected
->priority
< cred
->priority
)
1444 #endif /* INTERWORKING_3GPP */
1449 static struct wpa_cred
* interworking_credentials_available_realm(
1450 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1452 struct wpa_cred
*cred
, *selected
= NULL
;
1453 struct nai_realm
*realm
;
1456 if (bss
->anqp
== NULL
|| bss
->anqp
->nai_realm
== NULL
)
1459 if (wpa_s
->conf
->cred
== NULL
)
1462 wpa_printf(MSG_DEBUG
, "Interworking: Parsing NAI Realm list from "
1463 MACSTR
, MAC2STR(bss
->bssid
));
1464 realm
= nai_realm_parse(bss
->anqp
->nai_realm
, &count
);
1465 if (realm
== NULL
) {
1466 wpa_printf(MSG_DEBUG
, "Interworking: Could not parse NAI "
1467 "Realm list from " MACSTR
, MAC2STR(bss
->bssid
));
1471 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1472 if (cred
->realm
== NULL
)
1475 for (i
= 0; i
< count
; i
++) {
1476 if (!nai_realm_match(&realm
[i
], cred
->realm
))
1478 if (nai_realm_find_eap(cred
, &realm
[i
])) {
1479 if (cred_excluded_ssid(cred
, bss
))
1481 if (cred_no_required_oi_match(cred
, bss
))
1483 if (selected
== NULL
||
1484 selected
->priority
< cred
->priority
)
1491 nai_realm_free(realm
, count
);
1497 static struct wpa_cred
* interworking_credentials_available(
1498 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1500 struct wpa_cred
*cred
, *cred2
;
1502 cred
= interworking_credentials_available_realm(wpa_s
, bss
);
1503 cred2
= interworking_credentials_available_3gpp(wpa_s
, bss
);
1504 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1509 cred2
= interworking_credentials_available_roaming_consortium(wpa_s
,
1511 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1520 static int domain_name_list_contains(struct wpabuf
*domain_names
,
1523 const u8
*pos
, *end
;
1526 len
= os_strlen(domain
);
1527 pos
= wpabuf_head(domain_names
);
1528 end
= pos
+ wpabuf_len(domain_names
);
1530 while (pos
+ 1 < end
) {
1531 if (pos
+ 1 + pos
[0] > end
)
1534 wpa_hexdump_ascii(MSG_DEBUG
, "Interworking: AP domain name",
1536 if (pos
[0] == len
&&
1537 os_strncasecmp(domain
, (const char *) (pos
+ 1), len
) == 0)
1547 int interworking_home_sp_cred(struct wpa_supplicant
*wpa_s
,
1548 struct wpa_cred
*cred
,
1549 struct wpabuf
*domain_names
)
1552 #ifdef INTERWORKING_3GPP
1553 char nai
[100], *realm
;
1560 else if (cred
->pcsc
&& wpa_s
->conf
->pcsc_reader
&&
1561 wpa_s
->scard
&& wpa_s
->imsi
[0]) {
1563 mnc_len
= wpa_s
->mnc_len
;
1565 #endif /* CONFIG_PCSC */
1567 imsi
&& build_root_nai(nai
, sizeof(nai
), imsi
, mnc_len
, 0) == 0) {
1568 realm
= os_strchr(nai
, '@');
1571 wpa_printf(MSG_DEBUG
, "Interworking: Search for match "
1572 "with SIM/USIM domain %s", realm
);
1574 domain_name_list_contains(domain_names
, realm
))
1577 #endif /* INTERWORKING_3GPP */
1579 if (domain_names
== NULL
|| cred
->domain
== NULL
)
1582 for (i
= 0; i
< cred
->num_domain
; i
++) {
1583 wpa_printf(MSG_DEBUG
, "Interworking: Search for match with "
1584 "home SP FQDN %s", cred
->domain
[i
]);
1585 if (domain_name_list_contains(domain_names
, cred
->domain
[i
]))
1593 static int interworking_home_sp(struct wpa_supplicant
*wpa_s
,
1594 struct wpabuf
*domain_names
)
1596 struct wpa_cred
*cred
;
1598 if (domain_names
== NULL
|| wpa_s
->conf
->cred
== NULL
)
1601 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1602 int res
= interworking_home_sp_cred(wpa_s
, cred
, domain_names
);
1611 static int interworking_find_network_match(struct wpa_supplicant
*wpa_s
)
1613 struct wpa_bss
*bss
;
1614 struct wpa_ssid
*ssid
;
1616 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1617 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
) {
1618 if (wpas_network_disabled(wpa_s
, ssid
) ||
1619 ssid
->mode
!= WPAS_MODE_INFRA
)
1621 if (ssid
->ssid_len
!= bss
->ssid_len
||
1622 os_memcmp(ssid
->ssid
, bss
->ssid
, ssid
->ssid_len
) !=
1626 * TODO: Consider more accurate matching of security
1627 * configuration similarly to what is done in events.c
1637 static void interworking_select_network(struct wpa_supplicant
*wpa_s
)
1639 struct wpa_bss
*bss
, *selected
= NULL
, *selected_home
= NULL
;
1640 int selected_prio
= -999999, selected_home_prio
= -999999;
1641 unsigned int count
= 0;
1644 struct wpa_cred
*cred
;
1646 wpa_s
->network_select
= 0;
1648 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1649 cred
= interworking_credentials_available(wpa_s
, bss
);
1652 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) {
1654 * We currently support only HS 2.0 networks and those
1655 * are required to use WPA2-Enterprise.
1657 wpa_printf(MSG_DEBUG
, "Interworking: Credential match "
1658 "with " MACSTR
" but network does not use "
1659 "RSN", MAC2STR(bss
->bssid
));
1663 res
= interworking_home_sp(wpa_s
, bss
->anqp
?
1664 bss
->anqp
->domain_name
: NULL
);
1671 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_AP MACSTR
" type=%s",
1672 MAC2STR(bss
->bssid
), type
);
1673 if (wpa_s
->auto_select
||
1674 (wpa_s
->conf
->auto_interworking
&&
1675 wpa_s
->auto_network_select
)) {
1676 if (selected
== NULL
||
1677 cred
->priority
> selected_prio
) {
1679 selected_prio
= cred
->priority
;
1682 (selected_home
== NULL
||
1683 cred
->priority
> selected_home_prio
)) {
1684 selected_home
= bss
;
1685 selected_home_prio
= cred
->priority
;
1690 if (selected_home
&& selected_home
!= selected
&&
1691 selected_home_prio
>= selected_prio
) {
1692 /* Prefer network operated by the Home SP */
1693 selected
= selected_home
;
1698 * No matching network was found based on configured
1699 * credentials. Check whether any of the enabled network blocks
1700 * have matching APs.
1702 if (interworking_find_network_match(wpa_s
)) {
1703 wpa_printf(MSG_DEBUG
, "Interworking: Possible BSS "
1704 "match for enabled network configurations");
1705 if (wpa_s
->auto_select
)
1706 interworking_reconnect(wpa_s
);
1710 if (wpa_s
->auto_network_select
) {
1711 wpa_printf(MSG_DEBUG
, "Interworking: Continue "
1712 "scanning after ANQP fetch");
1713 wpa_supplicant_req_scan(wpa_s
, wpa_s
->scan_interval
,
1718 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_NO_MATCH
"No network "
1719 "with matching credentials found");
1723 interworking_connect(wpa_s
, selected
);
1727 static struct wpa_bss_anqp
*
1728 interworking_match_anqp_info(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1730 struct wpa_bss
*other
;
1732 if (is_zero_ether_addr(bss
->hessid
))
1733 return NULL
; /* Cannot be in the same homegenous ESS */
1735 dl_list_for_each(other
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1738 if (other
->anqp
== NULL
)
1740 if (other
->anqp
->roaming_consortium
== NULL
&&
1741 other
->anqp
->nai_realm
== NULL
&&
1742 other
->anqp
->anqp_3gpp
== NULL
&&
1743 other
->anqp
->domain_name
== NULL
)
1745 if (!(other
->flags
& WPA_BSS_ANQP_FETCH_TRIED
))
1747 if (os_memcmp(bss
->hessid
, other
->hessid
, ETH_ALEN
) != 0)
1749 if (bss
->ssid_len
!= other
->ssid_len
||
1750 os_memcmp(bss
->ssid
, other
->ssid
, bss
->ssid_len
) != 0)
1753 wpa_printf(MSG_DEBUG
, "Interworking: Share ANQP data with "
1754 "already fetched BSSID " MACSTR
" and " MACSTR
,
1755 MAC2STR(other
->bssid
), MAC2STR(bss
->bssid
));
1756 other
->anqp
->users
++;
1764 static void interworking_next_anqp_fetch(struct wpa_supplicant
*wpa_s
)
1766 struct wpa_bss
*bss
;
1770 if (eloop_terminated() || !wpa_s
->fetch_anqp_in_progress
)
1773 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1774 if (!(bss
->caps
& IEEE80211_CAP_ESS
))
1776 ie
= wpa_bss_get_ie(bss
, WLAN_EID_EXT_CAPAB
);
1777 if (ie
== NULL
|| ie
[1] < 4 || !(ie
[5] & 0x80))
1778 continue; /* AP does not support Interworking */
1780 if (!(bss
->flags
& WPA_BSS_ANQP_FETCH_TRIED
)) {
1781 if (bss
->anqp
== NULL
) {
1782 bss
->anqp
= interworking_match_anqp_info(wpa_s
,
1785 /* Shared data already fetched */
1788 bss
->anqp
= wpa_bss_anqp_alloc();
1789 if (bss
->anqp
== NULL
)
1793 bss
->flags
|= WPA_BSS_ANQP_FETCH_TRIED
;
1794 wpa_msg(wpa_s
, MSG_INFO
, "Starting ANQP fetch for "
1795 MACSTR
, MAC2STR(bss
->bssid
));
1796 interworking_anqp_send_req(wpa_s
, bss
);
1802 wpa_msg(wpa_s
, MSG_INFO
, "ANQP fetch completed");
1803 wpa_s
->fetch_anqp_in_progress
= 0;
1804 if (wpa_s
->network_select
)
1805 interworking_select_network(wpa_s
);
1810 void interworking_start_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1812 struct wpa_bss
*bss
;
1814 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
)
1815 bss
->flags
&= ~WPA_BSS_ANQP_FETCH_TRIED
;
1817 wpa_s
->fetch_anqp_in_progress
= 1;
1818 interworking_next_anqp_fetch(wpa_s
);
1822 int interworking_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1824 if (wpa_s
->fetch_anqp_in_progress
|| wpa_s
->network_select
)
1827 wpa_s
->network_select
= 0;
1828 wpa_s
->fetch_all_anqp
= 1;
1830 interworking_start_fetch_anqp(wpa_s
);
1836 void interworking_stop_fetch_anqp(struct wpa_supplicant
*wpa_s
)
1838 if (!wpa_s
->fetch_anqp_in_progress
)
1841 wpa_s
->fetch_anqp_in_progress
= 0;
1845 int anqp_send_req(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
1846 u16 info_ids
[], size_t num_ids
)
1851 struct wpa_bss
*bss
;
1854 freq
= wpa_s
->assoc_freq
;
1855 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
1857 wpa_bss_anqp_unshare_alloc(bss
);
1863 wpa_printf(MSG_DEBUG
, "ANQP: Query Request to " MACSTR
" for %u id(s)",
1864 MAC2STR(dst
), (unsigned int) num_ids
);
1866 buf
= anqp_build_req(info_ids
, num_ids
, NULL
);
1870 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, anqp_resp_cb
, wpa_s
);
1872 wpa_printf(MSG_DEBUG
, "ANQP: Failed to send Query Request");
1875 wpa_printf(MSG_DEBUG
, "ANQP: Query started with dialog token "
1883 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant
*wpa_s
,
1884 struct wpa_bss
*bss
, const u8
*sa
,
1886 const u8
*data
, size_t slen
)
1888 const u8
*pos
= data
;
1889 struct wpa_bss_anqp
*anqp
= NULL
;
1892 #endif /* CONFIG_HS20 */
1898 case ANQP_CAPABILITY_LIST
:
1899 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1900 " ANQP Capability list", MAC2STR(sa
));
1902 case ANQP_VENUE_NAME
:
1903 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1904 " Venue Name", MAC2STR(sa
));
1905 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Venue Name", pos
, slen
);
1907 wpabuf_free(anqp
->venue_name
);
1908 anqp
->venue_name
= wpabuf_alloc_copy(pos
, slen
);
1911 case ANQP_NETWORK_AUTH_TYPE
:
1912 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1913 " Network Authentication Type information",
1915 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Network Authentication "
1918 wpabuf_free(anqp
->network_auth_type
);
1919 anqp
->network_auth_type
= wpabuf_alloc_copy(pos
, slen
);
1922 case ANQP_ROAMING_CONSORTIUM
:
1923 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1924 " Roaming Consortium list", MAC2STR(sa
));
1925 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Roaming Consortium",
1928 wpabuf_free(anqp
->roaming_consortium
);
1929 anqp
->roaming_consortium
= wpabuf_alloc_copy(pos
, slen
);
1932 case ANQP_IP_ADDR_TYPE_AVAILABILITY
:
1933 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1934 " IP Address Type Availability information",
1936 wpa_hexdump(MSG_MSGDUMP
, "ANQP: IP Address Availability",
1939 wpabuf_free(anqp
->ip_addr_type_availability
);
1940 anqp
->ip_addr_type_availability
=
1941 wpabuf_alloc_copy(pos
, slen
);
1944 case ANQP_NAI_REALM
:
1945 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1946 " NAI Realm list", MAC2STR(sa
));
1947 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: NAI Realm", pos
, slen
);
1949 wpabuf_free(anqp
->nai_realm
);
1950 anqp
->nai_realm
= wpabuf_alloc_copy(pos
, slen
);
1953 case ANQP_3GPP_CELLULAR_NETWORK
:
1954 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1955 " 3GPP Cellular Network information", MAC2STR(sa
));
1956 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: 3GPP Cellular Network",
1959 wpabuf_free(anqp
->anqp_3gpp
);
1960 anqp
->anqp_3gpp
= wpabuf_alloc_copy(pos
, slen
);
1963 case ANQP_DOMAIN_NAME
:
1964 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
1965 " Domain Name list", MAC2STR(sa
));
1966 wpa_hexdump_ascii(MSG_MSGDUMP
, "ANQP: Domain Name", pos
, slen
);
1968 wpabuf_free(anqp
->domain_name
);
1969 anqp
->domain_name
= wpabuf_alloc_copy(pos
, slen
);
1972 case ANQP_VENDOR_SPECIFIC
:
1976 switch (WPA_GET_BE24(pos
)) {
1988 case HS20_ANQP_OUI_TYPE
:
1989 hs20_parse_rx_hs20_anqp_resp(wpa_s
, sa
, pos
,
1993 wpa_printf(MSG_DEBUG
, "HS20: Unsupported ANQP "
1994 "vendor type %u", type
);
1998 #endif /* CONFIG_HS20 */
2000 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported "
2001 "vendor-specific ANQP OUI %06x",
2007 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported ANQP Info ID "
2014 void anqp_resp_cb(void *ctx
, const u8
*dst
, u8 dialog_token
,
2015 enum gas_query_result result
,
2016 const struct wpabuf
*adv_proto
,
2017 const struct wpabuf
*resp
, u16 status_code
)
2019 struct wpa_supplicant
*wpa_s
= ctx
;
2024 struct wpa_bss
*bss
= NULL
, *tmp
;
2026 if (result
!= GAS_QUERY_SUCCESS
)
2029 pos
= wpabuf_head(adv_proto
);
2030 if (wpabuf_len(adv_proto
) < 4 || pos
[0] != WLAN_EID_ADV_PROTO
||
2031 pos
[1] < 2 || pos
[3] != ACCESS_NETWORK_QUERY_PROTOCOL
) {
2032 wpa_printf(MSG_DEBUG
, "ANQP: Unexpected Advertisement "
2033 "Protocol in response");
2038 * If possible, select the BSS entry based on which BSS entry was used
2039 * for the request. This can help in cases where multiple BSS entries
2040 * may exist for the same AP.
2042 dl_list_for_each_reverse(tmp
, &wpa_s
->bss
, struct wpa_bss
, list
) {
2043 if (tmp
== wpa_s
->interworking_gas_bss
&&
2044 os_memcmp(tmp
->bssid
, dst
, ETH_ALEN
) == 0) {
2050 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2052 pos
= wpabuf_head(resp
);
2053 end
= pos
+ wpabuf_len(resp
);
2056 if (pos
+ 4 > end
) {
2057 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element");
2060 info_id
= WPA_GET_LE16(pos
);
2062 slen
= WPA_GET_LE16(pos
);
2064 if (pos
+ slen
> end
) {
2065 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element length "
2066 "for Info ID %u", info_id
);
2069 interworking_parse_rx_anqp_resp(wpa_s
, bss
, dst
, info_id
, pos
,
2076 static void interworking_scan_res_handler(struct wpa_supplicant
*wpa_s
,
2077 struct wpa_scan_results
*scan_res
)
2079 wpa_printf(MSG_DEBUG
, "Interworking: Scan results available - start "
2081 interworking_start_fetch_anqp(wpa_s
);
2085 int interworking_select(struct wpa_supplicant
*wpa_s
, int auto_select
)
2087 interworking_stop_fetch_anqp(wpa_s
);
2088 wpa_s
->network_select
= 1;
2089 wpa_s
->auto_network_select
= 0;
2090 wpa_s
->auto_select
= !!auto_select
;
2091 wpa_s
->fetch_all_anqp
= 0;
2092 wpa_printf(MSG_DEBUG
, "Interworking: Start scan for network "
2094 wpa_s
->scan_res_handler
= interworking_scan_res_handler
;
2095 wpa_s
->scan_req
= MANUAL_SCAN_REQ
;
2096 wpa_supplicant_req_scan(wpa_s
, 0, 0);
2102 static void gas_resp_cb(void *ctx
, const u8
*addr
, u8 dialog_token
,
2103 enum gas_query_result result
,
2104 const struct wpabuf
*adv_proto
,
2105 const struct wpabuf
*resp
, u16 status_code
)
2107 struct wpa_supplicant
*wpa_s
= ctx
;
2109 wpa_msg(wpa_s
, MSG_INFO
, GAS_RESPONSE_INFO
"addr=" MACSTR
2110 " dialog_token=%d status_code=%d resp_len=%d",
2111 MAC2STR(addr
), dialog_token
, status_code
,
2112 resp
? (int) wpabuf_len(resp
) : -1);
2116 wpabuf_free(wpa_s
->last_gas_resp
);
2117 wpa_s
->last_gas_resp
= wpabuf_dup(resp
);
2118 if (wpa_s
->last_gas_resp
== NULL
)
2120 os_memcpy(wpa_s
->last_gas_addr
, addr
, ETH_ALEN
);
2121 wpa_s
->last_gas_dialog_token
= dialog_token
;
2125 int gas_send_request(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
2126 const struct wpabuf
*adv_proto
,
2127 const struct wpabuf
*query
)
2132 struct wpa_bss
*bss
;
2135 u8 query_resp_len_limit
= 0, pame_bi
= 0;
2137 freq
= wpa_s
->assoc_freq
;
2138 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2144 wpa_printf(MSG_DEBUG
, "GAS request to " MACSTR
" (freq %d MHz)",
2145 MAC2STR(dst
), freq
);
2146 wpa_hexdump_buf(MSG_DEBUG
, "Advertisement Protocol ID", adv_proto
);
2147 wpa_hexdump_buf(MSG_DEBUG
, "GAS Query", query
);
2149 len
= 3 + wpabuf_len(adv_proto
) + 2;
2151 len
+= wpabuf_len(query
);
2152 buf
= gas_build_initial_req(0, len
);
2156 /* Advertisement Protocol IE */
2157 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2158 wpabuf_put_u8(buf
, 1 + wpabuf_len(adv_proto
)); /* Length */
2159 wpabuf_put_u8(buf
, (query_resp_len_limit
& 0x7f) |
2160 (pame_bi
? 0x80 : 0));
2161 wpabuf_put_buf(buf
, adv_proto
);
2165 wpabuf_put_le16(buf
, wpabuf_len(query
));
2166 wpabuf_put_buf(buf
, query
);
2168 wpabuf_put_le16(buf
, 0);
2170 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, gas_resp_cb
, wpa_s
);
2172 wpa_printf(MSG_DEBUG
, "GAS: Failed to send Query Request");
2175 wpa_printf(MSG_DEBUG
, "GAS: Query started with dialog token "