2 * Interworking (IEEE 802.11u)
3 * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
4 * Copyright (c) 2011-2014, Jouni Malinen <j@w1.fi>
6 * This software may be distributed under the terms of the BSD license.
7 * See README for more details.
13 #include "common/ieee802_11_defs.h"
14 #include "common/gas.h"
15 #include "common/wpa_ctrl.h"
16 #include "utils/pcsc_funcs.h"
17 #include "utils/eloop.h"
18 #include "drivers/driver.h"
19 #include "eap_common/eap_defs.h"
20 #include "eap_peer/eap.h"
21 #include "eap_peer/eap_methods.h"
22 #include "eapol_supp/eapol_supp_sm.h"
23 #include "rsn_supp/wpa.h"
24 #include "wpa_supplicant_i.h"
26 #include "config_ssid.h"
30 #include "gas_query.h"
31 #include "hs20_supplicant.h"
32 #include "interworking.h"
35 #if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
36 #define INTERWORKING_3GPP
38 #if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
39 #define INTERWORKING_3GPP
41 #if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
42 #define INTERWORKING_3GPP
47 static void interworking_next_anqp_fetch(struct wpa_supplicant
*wpa_s
);
48 static struct wpa_cred
* interworking_credentials_available_realm(
49 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
);
50 static struct wpa_cred
* interworking_credentials_available_3gpp(
51 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
);
54 static void interworking_reconnect(struct wpa_supplicant
*wpa_s
)
56 if (wpa_s
->wpa_state
>= WPA_AUTHENTICATING
) {
57 wpa_supplicant_cancel_sched_scan(wpa_s
);
58 wpa_supplicant_deauthenticate(wpa_s
,
59 WLAN_REASON_DEAUTH_LEAVING
);
61 wpa_s
->disconnected
= 0;
62 wpa_s
->reassociate
= 1;
64 if (wpa_supplicant_fast_associate(wpa_s
) >= 0)
67 wpa_supplicant_req_scan(wpa_s
, 0, 0);
71 static struct wpabuf
* anqp_build_req(u16 info_ids
[], size_t num_ids
,
78 buf
= gas_anqp_build_initial_req(0, 4 + num_ids
* 2 +
79 (extra
? wpabuf_len(extra
) : 0));
83 len_pos
= gas_anqp_add_element(buf
, ANQP_QUERY_LIST
);
84 for (i
= 0; i
< num_ids
; i
++)
85 wpabuf_put_le16(buf
, info_ids
[i
]);
86 gas_anqp_set_element_len(buf
, len_pos
);
88 wpabuf_put_buf(buf
, extra
);
90 gas_anqp_set_len(buf
);
96 static void interworking_anqp_resp_cb(void *ctx
, const u8
*dst
,
98 enum gas_query_result result
,
99 const struct wpabuf
*adv_proto
,
100 const struct wpabuf
*resp
,
103 struct wpa_supplicant
*wpa_s
= ctx
;
105 anqp_resp_cb(wpa_s
, dst
, dialog_token
, result
, adv_proto
, resp
,
107 interworking_next_anqp_fetch(wpa_s
);
111 static int cred_with_roaming_consortium(struct wpa_supplicant
*wpa_s
)
113 struct wpa_cred
*cred
;
115 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
116 if (cred
->roaming_consortium_len
)
118 if (cred
->required_roaming_consortium_len
)
125 static int cred_with_3gpp(struct wpa_supplicant
*wpa_s
)
127 struct wpa_cred
*cred
;
129 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
130 if (cred
->pcsc
|| cred
->imsi
)
137 static int cred_with_nai_realm(struct wpa_supplicant
*wpa_s
)
139 struct wpa_cred
*cred
;
141 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
142 if (cred
->pcsc
|| cred
->imsi
)
144 if (!cred
->eap_method
)
146 if (cred
->realm
&& cred
->roaming_consortium_len
== 0)
153 static int cred_with_domain(struct wpa_supplicant
*wpa_s
)
155 struct wpa_cred
*cred
;
157 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
158 if (cred
->domain
|| cred
->pcsc
|| cred
->imsi
||
159 cred
->roaming_partner
)
166 static int additional_roaming_consortiums(struct wpa_bss
*bss
)
169 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
170 if (ie
== NULL
|| ie
[1] == 0)
172 return ie
[2]; /* Number of ANQP OIs */
176 static void interworking_continue_anqp(void *eloop_ctx
, void *sock_ctx
)
178 struct wpa_supplicant
*wpa_s
= eloop_ctx
;
179 interworking_next_anqp_fetch(wpa_s
);
183 static int interworking_anqp_send_req(struct wpa_supplicant
*wpa_s
,
190 size_t num_info_ids
= 0;
191 struct wpabuf
*extra
= NULL
;
192 int all
= wpa_s
->fetch_all_anqp
;
194 wpa_printf(MSG_DEBUG
, "Interworking: ANQP Query Request to " MACSTR
,
195 MAC2STR(bss
->bssid
));
196 wpa_s
->interworking_gas_bss
= bss
;
198 info_ids
[num_info_ids
++] = ANQP_CAPABILITY_LIST
;
200 info_ids
[num_info_ids
++] = ANQP_VENUE_NAME
;
201 info_ids
[num_info_ids
++] = ANQP_NETWORK_AUTH_TYPE
;
203 if (all
|| (cred_with_roaming_consortium(wpa_s
) &&
204 additional_roaming_consortiums(bss
)))
205 info_ids
[num_info_ids
++] = ANQP_ROAMING_CONSORTIUM
;
207 info_ids
[num_info_ids
++] = ANQP_IP_ADDR_TYPE_AVAILABILITY
;
208 if (all
|| cred_with_nai_realm(wpa_s
))
209 info_ids
[num_info_ids
++] = ANQP_NAI_REALM
;
210 if (all
|| cred_with_3gpp(wpa_s
))
211 info_ids
[num_info_ids
++] = ANQP_3GPP_CELLULAR_NETWORK
;
212 if (all
|| cred_with_domain(wpa_s
))
213 info_ids
[num_info_ids
++] = ANQP_DOMAIN_NAME
;
214 wpa_hexdump(MSG_DEBUG
, "Interworking: ANQP Query info",
215 (u8
*) info_ids
, num_info_ids
* 2);
218 if (wpa_bss_get_vendor_ie(bss
, HS20_IE_VENDOR_TYPE
)) {
221 extra
= wpabuf_alloc(100);
225 len_pos
= gas_anqp_add_element(extra
, ANQP_VENDOR_SPECIFIC
);
226 wpabuf_put_be24(extra
, OUI_WFA
);
227 wpabuf_put_u8(extra
, HS20_ANQP_OUI_TYPE
);
228 wpabuf_put_u8(extra
, HS20_STYPE_QUERY_LIST
);
229 wpabuf_put_u8(extra
, 0); /* Reserved */
230 wpabuf_put_u8(extra
, HS20_STYPE_CAPABILITY_LIST
);
233 HS20_STYPE_OPERATOR_FRIENDLY_NAME
);
234 wpabuf_put_u8(extra
, HS20_STYPE_WAN_METRICS
);
235 wpabuf_put_u8(extra
, HS20_STYPE_CONNECTION_CAPABILITY
);
236 wpabuf_put_u8(extra
, HS20_STYPE_OPERATING_CLASS
);
238 gas_anqp_set_element_len(extra
, len_pos
);
240 #endif /* CONFIG_HS20 */
242 buf
= anqp_build_req(info_ids
, num_info_ids
, extra
);
247 res
= gas_query_req(wpa_s
->gas
, bss
->bssid
, bss
->freq
, buf
,
248 interworking_anqp_resp_cb
, wpa_s
);
250 wpa_printf(MSG_DEBUG
, "ANQP: Failed to send Query Request");
253 eloop_register_timeout(0, 0, interworking_continue_anqp
, wpa_s
,
256 wpa_printf(MSG_DEBUG
, "ANQP: Query started with dialog token "
263 struct nai_realm_eap
{
266 enum nai_realm_eap_auth_inner_non_eap inner_non_eap
;
268 u8 tunneled_cred_type
;
275 struct nai_realm_eap
*eap
;
279 static void nai_realm_free(struct nai_realm
*realms
, u16 count
)
285 for (i
= 0; i
< count
; i
++) {
286 os_free(realms
[i
].eap
);
287 os_free(realms
[i
].realm
);
293 static const u8
* nai_realm_parse_eap(struct nai_realm_eap
*e
, const u8
*pos
,
296 u8 elen
, auth_count
, a
;
300 wpa_printf(MSG_DEBUG
, "No room for EAP Method fixed fields");
305 if (pos
+ elen
> end
|| elen
< 2) {
306 wpa_printf(MSG_DEBUG
, "No room for EAP Method subfield");
312 wpa_printf(MSG_DEBUG
, "EAP Method: len=%u method=%u auth_count=%u",
313 elen
, e
->method
, auth_count
);
315 for (a
= 0; a
< auth_count
; a
++) {
318 if (pos
+ 2 > end
|| pos
+ 2 + pos
[1] > end
) {
319 wpa_printf(MSG_DEBUG
, "No room for Authentication "
320 "Parameter subfield");
328 case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH
:
331 e
->inner_non_eap
= *pos
;
332 if (e
->method
!= EAP_TYPE_TTLS
)
335 case NAI_REALM_INNER_NON_EAP_PAP
:
336 wpa_printf(MSG_DEBUG
, "EAP-TTLS/PAP");
338 case NAI_REALM_INNER_NON_EAP_CHAP
:
339 wpa_printf(MSG_DEBUG
, "EAP-TTLS/CHAP");
341 case NAI_REALM_INNER_NON_EAP_MSCHAP
:
342 wpa_printf(MSG_DEBUG
, "EAP-TTLS/MSCHAP");
344 case NAI_REALM_INNER_NON_EAP_MSCHAPV2
:
345 wpa_printf(MSG_DEBUG
, "EAP-TTLS/MSCHAPV2");
349 case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD
:
352 e
->inner_method
= *pos
;
353 wpa_printf(MSG_DEBUG
, "Inner EAP method: %u",
356 case NAI_REALM_EAP_AUTH_CRED_TYPE
:
360 wpa_printf(MSG_DEBUG
, "Credential Type: %u",
363 case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE
:
366 e
->tunneled_cred_type
= *pos
;
367 wpa_printf(MSG_DEBUG
, "Tunneled EAP Method Credential "
368 "Type: %u", e
->tunneled_cred_type
);
371 wpa_printf(MSG_DEBUG
, "Unsupported Authentication "
372 "Parameter: id=%u len=%u", id
, len
);
373 wpa_hexdump(MSG_DEBUG
, "Authentication Parameter "
385 static const u8
* nai_realm_parse_realm(struct nai_realm
*r
, const u8
*pos
,
393 wpa_printf(MSG_DEBUG
, "No room for NAI Realm Data "
398 len
= WPA_GET_LE16(pos
); /* NAI Realm Data field Length */
400 if (pos
+ len
> end
|| len
< 3) {
401 wpa_printf(MSG_DEBUG
, "No room for NAI Realm Data "
403 len
, (unsigned int) (end
- pos
));
408 r
->encoding
= *pos
++;
410 if (pos
+ realm_len
> f_end
) {
411 wpa_printf(MSG_DEBUG
, "No room for NAI Realm "
413 realm_len
, (unsigned int) (f_end
- pos
));
416 wpa_hexdump_ascii(MSG_DEBUG
, "NAI Realm", pos
, realm_len
);
417 r
->realm
= dup_binstr(pos
, realm_len
);
418 if (r
->realm
== NULL
)
422 if (pos
+ 1 > f_end
) {
423 wpa_printf(MSG_DEBUG
, "No room for EAP Method Count");
426 r
->eap_count
= *pos
++;
427 wpa_printf(MSG_DEBUG
, "EAP Count: %u", r
->eap_count
);
428 if (pos
+ r
->eap_count
* 3 > f_end
) {
429 wpa_printf(MSG_DEBUG
, "No room for EAP Methods");
432 r
->eap
= os_calloc(r
->eap_count
, sizeof(struct nai_realm_eap
));
436 for (e
= 0; e
< r
->eap_count
; e
++) {
437 pos
= nai_realm_parse_eap(&r
->eap
[e
], pos
, f_end
);
446 static struct nai_realm
* nai_realm_parse(struct wpabuf
*anqp
, u16
*count
)
448 struct nai_realm
*realm
;
452 if (anqp
== NULL
|| wpabuf_len(anqp
) < 2)
455 pos
= wpabuf_head_u8(anqp
);
456 end
= pos
+ wpabuf_len(anqp
);
457 num
= WPA_GET_LE16(pos
);
458 wpa_printf(MSG_DEBUG
, "NAI Realm Count: %u", num
);
461 if (num
* 5 > end
- pos
) {
462 wpa_printf(MSG_DEBUG
, "Invalid NAI Realm Count %u - not "
463 "enough data (%u octets) for that many realms",
464 num
, (unsigned int) (end
- pos
));
468 realm
= os_calloc(num
, sizeof(struct nai_realm
));
472 for (i
= 0; i
< num
; i
++) {
473 pos
= nai_realm_parse_realm(&realm
[i
], pos
, end
);
475 nai_realm_free(realm
, num
);
485 static int nai_realm_match(struct nai_realm
*realm
, const char *home_realm
)
487 char *tmp
, *pos
, *end
;
490 if (realm
->realm
== NULL
|| home_realm
== NULL
)
493 if (os_strchr(realm
->realm
, ';') == NULL
)
494 return os_strcasecmp(realm
->realm
, home_realm
) == 0;
496 tmp
= os_strdup(realm
->realm
);
502 end
= os_strchr(pos
, ';');
505 if (os_strcasecmp(pos
, home_realm
) == 0) {
520 static int nai_realm_cred_username(struct nai_realm_eap
*eap
)
522 if (eap_get_name(EAP_VENDOR_IETF
, eap
->method
) == NULL
)
523 return 0; /* method not supported */
525 if (eap
->method
!= EAP_TYPE_TTLS
&& eap
->method
!= EAP_TYPE_PEAP
&&
526 eap
->method
!= EAP_TYPE_FAST
) {
527 /* Only tunneled methods with username/password supported */
531 if (eap
->method
== EAP_TYPE_PEAP
|| eap
->method
== EAP_TYPE_FAST
) {
532 if (eap
->inner_method
&&
533 eap_get_name(EAP_VENDOR_IETF
, eap
->inner_method
) == NULL
)
535 if (!eap
->inner_method
&&
536 eap_get_name(EAP_VENDOR_IETF
, EAP_TYPE_MSCHAPV2
) == NULL
)
540 if (eap
->method
== EAP_TYPE_TTLS
) {
541 if (eap
->inner_method
== 0 && eap
->inner_non_eap
== 0)
542 return 1; /* Assume TTLS/MSCHAPv2 is used */
543 if (eap
->inner_method
&&
544 eap_get_name(EAP_VENDOR_IETF
, eap
->inner_method
) == NULL
)
546 if (eap
->inner_non_eap
&&
547 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_PAP
&&
548 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_CHAP
&&
549 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_MSCHAP
&&
550 eap
->inner_non_eap
!= NAI_REALM_INNER_NON_EAP_MSCHAPV2
)
554 if (eap
->inner_method
&&
555 eap
->inner_method
!= EAP_TYPE_GTC
&&
556 eap
->inner_method
!= EAP_TYPE_MSCHAPV2
)
563 static int nai_realm_cred_cert(struct nai_realm_eap
*eap
)
565 if (eap_get_name(EAP_VENDOR_IETF
, eap
->method
) == NULL
)
566 return 0; /* method not supported */
568 if (eap
->method
!= EAP_TYPE_TLS
) {
569 /* Only EAP-TLS supported for credential authentication */
577 static struct nai_realm_eap
* nai_realm_find_eap(struct wpa_cred
*cred
,
578 struct nai_realm
*realm
)
583 cred
->username
== NULL
||
584 cred
->username
[0] == '\0' ||
585 ((cred
->password
== NULL
||
586 cred
->password
[0] == '\0') &&
587 (cred
->private_key
== NULL
||
588 cred
->private_key
[0] == '\0')))
591 for (e
= 0; e
< realm
->eap_count
; e
++) {
592 struct nai_realm_eap
*eap
= &realm
->eap
[e
];
593 if (cred
->password
&& cred
->password
[0] &&
594 nai_realm_cred_username(eap
))
596 if (cred
->private_key
&& cred
->private_key
[0] &&
597 nai_realm_cred_cert(eap
))
605 #ifdef INTERWORKING_3GPP
607 static int plmn_id_match(struct wpabuf
*anqp
, const char *imsi
, int mnc_len
)
609 u8 plmn
[3], plmn2
[3];
614 * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
615 * operator is allowed to include only two digits of the MNC, so allow
616 * matches based on both two and three digit MNC assumptions. Since some
617 * SIM/USIM cards may not expose MNC length conveniently, we may be
618 * provided the default MNC length 3 here and as such, checking with MNC
619 * length 2 is justifiable even though 3GPP TS 24.234 does not mention
620 * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
621 * with otherwise matching values would not be good idea in general, so
622 * this should not result in selecting incorrect networks.
624 /* Match with 3 digit MNC */
625 plmn
[0] = (imsi
[0] - '0') | ((imsi
[1] - '0') << 4);
626 plmn
[1] = (imsi
[2] - '0') | ((imsi
[5] - '0') << 4);
627 plmn
[2] = (imsi
[3] - '0') | ((imsi
[4] - '0') << 4);
628 /* Match with 2 digit MNC */
629 plmn2
[0] = (imsi
[0] - '0') | ((imsi
[1] - '0') << 4);
630 plmn2
[1] = (imsi
[2] - '0') | 0xf0;
631 plmn2
[2] = (imsi
[3] - '0') | ((imsi
[4] - '0') << 4);
635 pos
= wpabuf_head_u8(anqp
);
636 end
= pos
+ wpabuf_len(anqp
);
640 wpa_printf(MSG_DEBUG
, "Unsupported GUD version 0x%x", *pos
);
645 if (pos
+ udhl
> end
) {
646 wpa_printf(MSG_DEBUG
, "Invalid UDHL");
651 wpa_printf(MSG_DEBUG
, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
652 plmn
[0], plmn
[1], plmn
[2], plmn2
[0], plmn2
[1], plmn2
[2],
655 while (pos
+ 2 <= end
) {
664 if (iei
== 0 && len
> 0) {
667 wpa_hexdump(MSG_DEBUG
, "Interworking: PLMN List information element",
670 for (i
= 0; i
< num
; i
++) {
673 if (os_memcmp(pos
, plmn
, 3) == 0 ||
674 os_memcmp(pos
, plmn2
, 3) == 0)
675 return 1; /* Found matching PLMN */
679 wpa_hexdump(MSG_DEBUG
, "Interworking: Unrecognized 3GPP information element",
690 static int build_root_nai(char *nai
, size_t nai_len
, const char *imsi
,
691 size_t mnc_len
, char prefix
)
693 const char *sep
, *msin
;
695 size_t msin_len
, plmn_len
;
698 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
700 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
701 * <MNC> is zero-padded to three digits in case two-digit MNC is used
704 if (imsi
== NULL
|| os_strlen(imsi
) > 16) {
705 wpa_printf(MSG_DEBUG
, "No valid IMSI available");
708 sep
= os_strchr(imsi
, '-');
710 plmn_len
= sep
- imsi
;
712 } else if (mnc_len
&& os_strlen(imsi
) >= 3 + mnc_len
) {
713 plmn_len
= 3 + mnc_len
;
714 msin
= imsi
+ plmn_len
;
717 if (plmn_len
!= 5 && plmn_len
!= 6)
719 msin_len
= os_strlen(msin
);
725 os_memcpy(pos
, imsi
, plmn_len
);
727 os_memcpy(pos
, msin
, msin_len
);
729 pos
+= os_snprintf(pos
, end
- pos
, "@wlan.mnc");
739 pos
+= os_snprintf(pos
, end
- pos
, ".mcc%c%c%c.3gppnetwork.org",
740 imsi
[0], imsi
[1], imsi
[2]);
746 static int set_root_nai(struct wpa_ssid
*ssid
, const char *imsi
, char prefix
)
749 if (build_root_nai(nai
, sizeof(nai
), imsi
, 0, prefix
) < 0)
751 return wpa_config_set_quoted(ssid
, "identity", nai
);
754 #endif /* INTERWORKING_3GPP */
757 static int already_connected(struct wpa_supplicant
*wpa_s
,
758 struct wpa_cred
*cred
, struct wpa_bss
*bss
)
760 struct wpa_ssid
*ssid
;
762 if (wpa_s
->wpa_state
< WPA_ASSOCIATED
|| wpa_s
->current_ssid
== NULL
)
765 ssid
= wpa_s
->current_ssid
;
766 if (ssid
->parent_cred
!= cred
)
769 if (ssid
->ssid_len
!= bss
->ssid_len
||
770 os_memcmp(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
) != 0)
777 static void remove_duplicate_network(struct wpa_supplicant
*wpa_s
,
778 struct wpa_cred
*cred
,
781 struct wpa_ssid
*ssid
;
783 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
) {
784 if (ssid
->parent_cred
!= cred
)
786 if (ssid
->ssid_len
!= bss
->ssid_len
||
787 os_memcmp(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
) != 0)
796 wpa_printf(MSG_DEBUG
, "Interworking: Remove duplicate network entry for the same credential");
798 if (ssid
== wpa_s
->current_ssid
) {
799 wpa_sm_set_config(wpa_s
->wpa
, NULL
);
800 eapol_sm_notify_config(wpa_s
->eapol
, NULL
, NULL
);
801 wpa_supplicant_deauthenticate(wpa_s
,
802 WLAN_REASON_DEAUTH_LEAVING
);
805 wpas_notify_network_removed(wpa_s
, ssid
);
806 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
810 static int interworking_set_hs20_params(struct wpa_supplicant
*wpa_s
,
811 struct wpa_ssid
*ssid
)
813 if (wpa_config_set(ssid
, "key_mgmt",
814 wpa_s
->conf
->pmf
!= NO_MGMT_FRAME_PROTECTION
?
815 "WPA-EAP WPA-EAP-SHA256" : "WPA-EAP", 0) < 0)
817 if (wpa_config_set(ssid
, "proto", "RSN", 0) < 0)
819 if (wpa_config_set(ssid
, "pairwise", "CCMP", 0) < 0)
825 static int interworking_connect_3gpp(struct wpa_supplicant
*wpa_s
,
826 struct wpa_cred
*cred
,
829 #ifdef INTERWORKING_3GPP
830 struct wpa_ssid
*ssid
;
835 if (bss
->anqp
== NULL
|| bss
->anqp
->anqp_3gpp
== NULL
)
838 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
" (3GPP)",
839 MAC2STR(bss
->bssid
));
841 if (already_connected(wpa_s
, cred
, bss
)) {
842 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_ALREADY_CONNECTED MACSTR
,
843 MAC2STR(bss
->bssid
));
847 remove_duplicate_network(wpa_s
, cred
, bss
);
849 ssid
= wpa_config_add_network(wpa_s
->conf
);
852 ssid
->parent_cred
= cred
;
854 wpas_notify_network_added(wpa_s
, ssid
);
855 wpa_config_set_network_defaults(ssid
);
856 ssid
->priority
= cred
->priority
;
858 ssid
->ssid
= os_zalloc(bss
->ssid_len
+ 1);
859 if (ssid
->ssid
== NULL
)
861 os_memcpy(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
);
862 ssid
->ssid_len
= bss
->ssid_len
;
864 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
867 eap_type
= EAP_TYPE_SIM
;
868 if (cred
->pcsc
&& wpa_s
->scard
&& scard_supports_umts(wpa_s
->scard
))
869 eap_type
= EAP_TYPE_AKA
;
870 if (cred
->eap_method
&& cred
->eap_method
[0].vendor
== EAP_VENDOR_IETF
) {
871 if (cred
->eap_method
[0].method
== EAP_TYPE_SIM
||
872 cred
->eap_method
[0].method
== EAP_TYPE_AKA
||
873 cred
->eap_method
[0].method
== EAP_TYPE_AKA_PRIME
)
874 eap_type
= cred
->eap_method
[0].method
;
880 res
= wpa_config_set(ssid
, "eap", "SIM", 0);
884 res
= wpa_config_set(ssid
, "eap", "AKA", 0);
886 case EAP_TYPE_AKA_PRIME
:
888 res
= wpa_config_set(ssid
, "eap", "AKA'", 0);
895 wpa_printf(MSG_DEBUG
, "Selected EAP method (%d) not supported",
900 if (!cred
->pcsc
&& set_root_nai(ssid
, cred
->imsi
, prefix
) < 0) {
901 wpa_printf(MSG_DEBUG
, "Failed to set Root NAI");
905 if (cred
->milenage
&& cred
->milenage
[0]) {
906 if (wpa_config_set_quoted(ssid
, "password",
909 } else if (cred
->pcsc
) {
910 if (wpa_config_set_quoted(ssid
, "pcsc", "") < 0)
912 if (wpa_s
->conf
->pcsc_pin
&&
913 wpa_config_set_quoted(ssid
, "pin", wpa_s
->conf
->pcsc_pin
)
918 if (cred
->password
&& cred
->password
[0] &&
919 wpa_config_set_quoted(ssid
, "password", cred
->password
) < 0)
922 wpa_s
->next_ssid
= ssid
;
923 wpa_config_update_prio_list(wpa_s
->conf
);
924 interworking_reconnect(wpa_s
);
929 wpas_notify_network_removed(wpa_s
, ssid
);
930 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
931 #endif /* INTERWORKING_3GPP */
936 static int roaming_consortium_element_match(const u8
*ie
, const u8
*rc_id
,
946 end
= ie
+ 2 + ie
[1];
948 /* Roaming Consortium element:
950 * OI #1 and #2 lengths
951 * OI #1, [OI #2], [OI #3]
957 pos
++; /* skip Number of ANQP OIs */
959 if (pos
+ (lens
& 0x0f) + (lens
>> 4) > end
)
962 if ((lens
& 0x0f) == rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
966 if ((lens
>> 4) == rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
970 if (pos
< end
&& (size_t) (end
- pos
) == rc_len
&&
971 os_memcmp(pos
, rc_id
, rc_len
) == 0)
978 static int roaming_consortium_anqp_match(const struct wpabuf
*anqp
,
979 const u8
*rc_id
, size_t rc_len
)
987 pos
= wpabuf_head(anqp
);
988 end
= pos
+ wpabuf_len(anqp
);
990 /* Set of <OI Length, OI> duples */
995 if (len
== rc_len
&& os_memcmp(pos
, rc_id
, rc_len
) == 0)
1004 static int roaming_consortium_match(const u8
*ie
, const struct wpabuf
*anqp
,
1005 const u8
*rc_id
, size_t rc_len
)
1007 return roaming_consortium_element_match(ie
, rc_id
, rc_len
) ||
1008 roaming_consortium_anqp_match(anqp
, rc_id
, rc_len
);
1012 static int cred_no_required_oi_match(struct wpa_cred
*cred
, struct wpa_bss
*bss
)
1016 if (cred
->required_roaming_consortium_len
== 0)
1019 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
1022 (bss
->anqp
== NULL
|| bss
->anqp
->roaming_consortium
== NULL
))
1025 return !roaming_consortium_match(ie
,
1027 bss
->anqp
->roaming_consortium
: NULL
,
1028 cred
->required_roaming_consortium
,
1029 cred
->required_roaming_consortium_len
);
1033 static int cred_excluded_ssid(struct wpa_cred
*cred
, struct wpa_bss
*bss
)
1037 if (!cred
->excluded_ssid
)
1040 for (i
= 0; i
< cred
->num_excluded_ssid
; i
++) {
1041 struct excluded_ssid
*e
= &cred
->excluded_ssid
[i
];
1042 if (bss
->ssid_len
== e
->ssid_len
&&
1043 os_memcmp(bss
->ssid
, e
->ssid
, e
->ssid_len
) == 0)
1051 static struct wpa_cred
* interworking_credentials_available_roaming_consortium(
1052 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1054 struct wpa_cred
*cred
, *selected
= NULL
;
1057 ie
= wpa_bss_get_ie(bss
, WLAN_EID_ROAMING_CONSORTIUM
);
1060 (bss
->anqp
== NULL
|| bss
->anqp
->roaming_consortium
== NULL
))
1063 if (wpa_s
->conf
->cred
== NULL
)
1066 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1067 if (cred
->roaming_consortium_len
== 0)
1070 if (!roaming_consortium_match(ie
,
1072 bss
->anqp
->roaming_consortium
:
1074 cred
->roaming_consortium
,
1075 cred
->roaming_consortium_len
))
1078 if (cred_excluded_ssid(cred
, bss
))
1080 if (cred_no_required_oi_match(cred
, bss
))
1083 if (selected
== NULL
||
1084 selected
->priority
< cred
->priority
)
1092 static int interworking_set_eap_params(struct wpa_ssid
*ssid
,
1093 struct wpa_cred
*cred
, int ttls
)
1095 if (cred
->eap_method
) {
1096 ttls
= cred
->eap_method
->vendor
== EAP_VENDOR_IETF
&&
1097 cred
->eap_method
->method
== EAP_TYPE_TTLS
;
1099 os_free(ssid
->eap
.eap_methods
);
1100 ssid
->eap
.eap_methods
=
1101 os_malloc(sizeof(struct eap_method_type
) * 2);
1102 if (ssid
->eap
.eap_methods
== NULL
)
1104 os_memcpy(ssid
->eap
.eap_methods
, cred
->eap_method
,
1105 sizeof(*cred
->eap_method
));
1106 ssid
->eap
.eap_methods
[1].vendor
= EAP_VENDOR_IETF
;
1107 ssid
->eap
.eap_methods
[1].method
= EAP_TYPE_NONE
;
1110 if (ttls
&& cred
->username
&& cred
->username
[0]) {
1113 /* Use anonymous NAI in Phase 1 */
1114 pos
= os_strchr(cred
->username
, '@');
1116 size_t buflen
= 9 + os_strlen(pos
) + 1;
1117 anon
= os_malloc(buflen
);
1120 os_snprintf(anon
, buflen
, "anonymous%s", pos
);
1121 } else if (cred
->realm
) {
1122 size_t buflen
= 10 + os_strlen(cred
->realm
) + 1;
1123 anon
= os_malloc(buflen
);
1126 os_snprintf(anon
, buflen
, "anonymous@%s", cred
->realm
);
1128 anon
= os_strdup("anonymous");
1132 if (wpa_config_set_quoted(ssid
, "anonymous_identity", anon
) <
1140 if (cred
->username
&& cred
->username
[0] &&
1141 wpa_config_set_quoted(ssid
, "identity", cred
->username
) < 0)
1144 if (cred
->password
&& cred
->password
[0]) {
1145 if (cred
->ext_password
&&
1146 wpa_config_set(ssid
, "password", cred
->password
, 0) < 0)
1148 if (!cred
->ext_password
&&
1149 wpa_config_set_quoted(ssid
, "password", cred
->password
) <
1154 if (cred
->client_cert
&& cred
->client_cert
[0] &&
1155 wpa_config_set_quoted(ssid
, "client_cert", cred
->client_cert
) < 0)
1159 if (cred
->private_key
&&
1160 os_strncmp(cred
->private_key
, "keystore://", 11) == 0) {
1161 /* Use OpenSSL engine configuration for Android keystore */
1162 if (wpa_config_set_quoted(ssid
, "engine_id", "keystore") < 0 ||
1163 wpa_config_set_quoted(ssid
, "key_id",
1164 cred
->private_key
+ 11) < 0 ||
1165 wpa_config_set(ssid
, "engine", "1", 0) < 0)
1168 #endif /* ANDROID */
1169 if (cred
->private_key
&& cred
->private_key
[0] &&
1170 wpa_config_set_quoted(ssid
, "private_key", cred
->private_key
) < 0)
1173 if (cred
->private_key_passwd
&& cred
->private_key_passwd
[0] &&
1174 wpa_config_set_quoted(ssid
, "private_key_passwd",
1175 cred
->private_key_passwd
) < 0)
1179 os_free(ssid
->eap
.phase1
);
1180 ssid
->eap
.phase1
= os_strdup(cred
->phase1
);
1183 os_free(ssid
->eap
.phase2
);
1184 ssid
->eap
.phase2
= os_strdup(cred
->phase2
);
1187 if (cred
->ca_cert
&& cred
->ca_cert
[0] &&
1188 wpa_config_set_quoted(ssid
, "ca_cert", cred
->ca_cert
) < 0)
1191 if (cred
->domain_suffix_match
&& cred
->domain_suffix_match
[0] &&
1192 wpa_config_set_quoted(ssid
, "domain_suffix_match",
1193 cred
->domain_suffix_match
) < 0)
1200 static int interworking_connect_roaming_consortium(
1201 struct wpa_supplicant
*wpa_s
, struct wpa_cred
*cred
,
1202 struct wpa_bss
*bss
)
1204 struct wpa_ssid
*ssid
;
1206 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
" based on "
1207 "roaming consortium match", MAC2STR(bss
->bssid
));
1209 if (already_connected(wpa_s
, cred
, bss
)) {
1210 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_ALREADY_CONNECTED MACSTR
,
1211 MAC2STR(bss
->bssid
));
1215 remove_duplicate_network(wpa_s
, cred
, bss
);
1217 ssid
= wpa_config_add_network(wpa_s
->conf
);
1220 ssid
->parent_cred
= cred
;
1221 wpas_notify_network_added(wpa_s
, ssid
);
1222 wpa_config_set_network_defaults(ssid
);
1223 ssid
->priority
= cred
->priority
;
1224 ssid
->temporary
= 1;
1225 ssid
->ssid
= os_zalloc(bss
->ssid_len
+ 1);
1226 if (ssid
->ssid
== NULL
)
1228 os_memcpy(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
);
1229 ssid
->ssid_len
= bss
->ssid_len
;
1231 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
1234 if (cred
->eap_method
== NULL
) {
1235 wpa_printf(MSG_DEBUG
, "Interworking: No EAP method set for "
1236 "credential using roaming consortium");
1240 if (interworking_set_eap_params(
1242 cred
->eap_method
->vendor
== EAP_VENDOR_IETF
&&
1243 cred
->eap_method
->method
== EAP_TYPE_TTLS
) < 0)
1246 wpa_s
->next_ssid
= ssid
;
1247 wpa_config_update_prio_list(wpa_s
->conf
);
1248 interworking_reconnect(wpa_s
);
1253 wpas_notify_network_removed(wpa_s
, ssid
);
1254 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
1259 int interworking_connect(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1261 struct wpa_cred
*cred
, *cred_rc
, *cred_3gpp
;
1262 struct wpa_ssid
*ssid
;
1263 struct nai_realm
*realm
;
1264 struct nai_realm_eap
*eap
= NULL
;
1268 if (wpa_s
->conf
->cred
== NULL
|| bss
== NULL
)
1270 if (disallowed_bssid(wpa_s
, bss
->bssid
) ||
1271 disallowed_ssid(wpa_s
, bss
->ssid
, bss
->ssid_len
)) {
1272 wpa_printf(MSG_DEBUG
, "Interworking: Reject connection to disallowed BSS "
1273 MACSTR
, MAC2STR(bss
->bssid
));
1277 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) {
1279 * We currently support only HS 2.0 networks and those are
1280 * required to use WPA2-Enterprise.
1282 wpa_printf(MSG_DEBUG
, "Interworking: Network does not use "
1287 cred_rc
= interworking_credentials_available_roaming_consortium(wpa_s
,
1290 wpa_printf(MSG_DEBUG
, "Interworking: Highest roaming "
1291 "consortium matching credential priority %d",
1295 cred
= interworking_credentials_available_realm(wpa_s
, bss
);
1297 wpa_printf(MSG_DEBUG
, "Interworking: Highest NAI Realm list "
1298 "matching credential priority %d",
1302 cred_3gpp
= interworking_credentials_available_3gpp(wpa_s
, bss
);
1304 wpa_printf(MSG_DEBUG
, "Interworking: Highest 3GPP matching "
1305 "credential priority %d", cred_3gpp
->priority
);
1309 (cred
== NULL
|| cred_rc
->priority
>= cred
->priority
) &&
1310 (cred_3gpp
== NULL
|| cred_rc
->priority
>= cred_3gpp
->priority
))
1311 return interworking_connect_roaming_consortium(wpa_s
, cred_rc
,
1315 (cred
== NULL
|| cred_3gpp
->priority
>= cred
->priority
)) {
1316 return interworking_connect_3gpp(wpa_s
, cred_3gpp
, bss
);
1320 wpa_printf(MSG_DEBUG
, "Interworking: No matching credentials "
1321 "found for " MACSTR
, MAC2STR(bss
->bssid
));
1325 realm
= nai_realm_parse(bss
->anqp
? bss
->anqp
->nai_realm
: NULL
,
1327 if (realm
== NULL
) {
1328 wpa_printf(MSG_DEBUG
, "Interworking: Could not parse NAI "
1329 "Realm list from " MACSTR
, MAC2STR(bss
->bssid
));
1333 for (i
= 0; i
< count
; i
++) {
1334 if (!nai_realm_match(&realm
[i
], cred
->realm
))
1336 eap
= nai_realm_find_eap(cred
, &realm
[i
]);
1342 wpa_printf(MSG_DEBUG
, "Interworking: No matching credentials "
1343 "and EAP method found for " MACSTR
,
1344 MAC2STR(bss
->bssid
));
1345 nai_realm_free(realm
, count
);
1349 wpa_printf(MSG_DEBUG
, "Interworking: Connect with " MACSTR
,
1350 MAC2STR(bss
->bssid
));
1352 if (already_connected(wpa_s
, cred
, bss
)) {
1353 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_ALREADY_CONNECTED MACSTR
,
1354 MAC2STR(bss
->bssid
));
1355 nai_realm_free(realm
, count
);
1359 remove_duplicate_network(wpa_s
, cred
, bss
);
1361 ssid
= wpa_config_add_network(wpa_s
->conf
);
1363 nai_realm_free(realm
, count
);
1366 ssid
->parent_cred
= cred
;
1367 wpas_notify_network_added(wpa_s
, ssid
);
1368 wpa_config_set_network_defaults(ssid
);
1369 ssid
->priority
= cred
->priority
;
1370 ssid
->temporary
= 1;
1371 ssid
->ssid
= os_zalloc(bss
->ssid_len
+ 1);
1372 if (ssid
->ssid
== NULL
)
1374 os_memcpy(ssid
->ssid
, bss
->ssid
, bss
->ssid_len
);
1375 ssid
->ssid_len
= bss
->ssid_len
;
1377 if (interworking_set_hs20_params(wpa_s
, ssid
) < 0)
1380 if (wpa_config_set(ssid
, "eap", eap_get_name(EAP_VENDOR_IETF
,
1381 eap
->method
), 0) < 0)
1384 switch (eap
->method
) {
1386 if (eap
->inner_method
) {
1387 os_snprintf(buf
, sizeof(buf
), "\"autheap=%s\"",
1388 eap_get_name(EAP_VENDOR_IETF
,
1389 eap
->inner_method
));
1390 if (wpa_config_set(ssid
, "phase2", buf
, 0) < 0)
1394 switch (eap
->inner_non_eap
) {
1395 case NAI_REALM_INNER_NON_EAP_PAP
:
1396 if (wpa_config_set(ssid
, "phase2", "\"auth=PAP\"", 0) <
1400 case NAI_REALM_INNER_NON_EAP_CHAP
:
1401 if (wpa_config_set(ssid
, "phase2", "\"auth=CHAP\"", 0)
1405 case NAI_REALM_INNER_NON_EAP_MSCHAP
:
1406 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAP\"",
1410 case NAI_REALM_INNER_NON_EAP_MSCHAPV2
:
1411 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAPV2\"",
1416 /* EAP params were not set - assume TTLS/MSCHAPv2 */
1417 if (wpa_config_set(ssid
, "phase2", "\"auth=MSCHAPV2\"",
1425 if (wpa_config_set(ssid
, "phase1", "\"fast_provisioning=2\"",
1428 if (wpa_config_set(ssid
, "pac_file",
1429 "\"blob://pac_interworking\"", 0) < 0)
1431 os_snprintf(buf
, sizeof(buf
), "\"auth=%s\"",
1432 eap_get_name(EAP_VENDOR_IETF
,
1435 EAP_TYPE_MSCHAPV2
));
1436 if (wpa_config_set(ssid
, "phase2", buf
, 0) < 0)
1443 if (interworking_set_eap_params(ssid
, cred
,
1444 eap
->method
== EAP_TYPE_TTLS
) < 0)
1447 nai_realm_free(realm
, count
);
1449 wpa_s
->next_ssid
= ssid
;
1450 wpa_config_update_prio_list(wpa_s
->conf
);
1451 interworking_reconnect(wpa_s
);
1456 wpas_notify_network_removed(wpa_s
, ssid
);
1457 wpa_config_remove_network(wpa_s
->conf
, ssid
->id
);
1458 nai_realm_free(realm
, count
);
1463 static struct wpa_cred
* interworking_credentials_available_3gpp(
1464 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1466 struct wpa_cred
*selected
= NULL
;
1467 #ifdef INTERWORKING_3GPP
1468 struct wpa_cred
*cred
;
1471 if (bss
->anqp
== NULL
|| bss
->anqp
->anqp_3gpp
== NULL
)
1474 #ifdef CONFIG_EAP_PROXY
1475 if (!wpa_s
->imsi
[0]) {
1477 wpa_printf(MSG_DEBUG
, "Interworking: IMSI not available - try to read again through eap_proxy");
1478 wpa_s
->mnc_len
= eapol_sm_get_eap_proxy_imsi(wpa_s
->eapol
,
1481 if (wpa_s
->mnc_len
> 0) {
1482 wpa_s
->imsi
[len
] = '\0';
1483 wpa_printf(MSG_DEBUG
, "eap_proxy: IMSI %s (MNC length %d)",
1484 wpa_s
->imsi
, wpa_s
->mnc_len
);
1486 wpa_printf(MSG_DEBUG
, "eap_proxy: IMSI not available");
1489 #endif /* CONFIG_EAP_PROXY */
1491 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1499 if (cred
->pcsc
&& wpa_s
->conf
->pcsc_reader
&& wpa_s
->scard
&&
1502 mnc_len
= wpa_s
->mnc_len
;
1505 #endif /* PCSC_FUNCS */
1506 #ifdef CONFIG_EAP_PROXY
1507 if (cred
->pcsc
&& wpa_s
->mnc_len
> 0 && wpa_s
->imsi
[0]) {
1509 mnc_len
= wpa_s
->mnc_len
;
1512 #endif /* CONFIG_EAP_PROXY */
1514 if (cred
->imsi
== NULL
|| !cred
->imsi
[0] ||
1515 (!wpa_s
->conf
->external_sim
&&
1516 (cred
->milenage
== NULL
|| !cred
->milenage
[0])))
1519 sep
= os_strchr(cred
->imsi
, '-');
1521 (sep
- cred
->imsi
!= 5 && sep
- cred
->imsi
!= 6))
1523 mnc_len
= sep
- cred
->imsi
- 3;
1524 os_memcpy(imsi_buf
, cred
->imsi
, 3 + mnc_len
);
1526 msin_len
= os_strlen(cred
->imsi
);
1527 if (3 + mnc_len
+ msin_len
>= sizeof(imsi_buf
) - 1)
1528 msin_len
= sizeof(imsi_buf
) - 3 - mnc_len
- 1;
1529 os_memcpy(&imsi_buf
[3 + mnc_len
], sep
, msin_len
);
1530 imsi_buf
[3 + mnc_len
+ msin_len
] = '\0';
1533 #if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
1535 #endif /* PCSC_FUNCS || CONFIG_EAP_PROXY */
1536 wpa_printf(MSG_DEBUG
, "Interworking: Parsing 3GPP info from "
1537 MACSTR
, MAC2STR(bss
->bssid
));
1538 ret
= plmn_id_match(bss
->anqp
->anqp_3gpp
, imsi
, mnc_len
);
1539 wpa_printf(MSG_DEBUG
, "PLMN match %sfound", ret
? "" : "not ");
1541 if (cred_excluded_ssid(cred
, bss
))
1543 if (cred_no_required_oi_match(cred
, bss
))
1545 if (selected
== NULL
||
1546 selected
->priority
< cred
->priority
)
1550 #endif /* INTERWORKING_3GPP */
1555 static struct wpa_cred
* interworking_credentials_available_realm(
1556 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1558 struct wpa_cred
*cred
, *selected
= NULL
;
1559 struct nai_realm
*realm
;
1562 if (bss
->anqp
== NULL
|| bss
->anqp
->nai_realm
== NULL
)
1565 if (wpa_s
->conf
->cred
== NULL
)
1568 wpa_printf(MSG_DEBUG
, "Interworking: Parsing NAI Realm list from "
1569 MACSTR
, MAC2STR(bss
->bssid
));
1570 realm
= nai_realm_parse(bss
->anqp
->nai_realm
, &count
);
1571 if (realm
== NULL
) {
1572 wpa_printf(MSG_DEBUG
, "Interworking: Could not parse NAI "
1573 "Realm list from " MACSTR
, MAC2STR(bss
->bssid
));
1577 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1578 if (cred
->realm
== NULL
)
1581 for (i
= 0; i
< count
; i
++) {
1582 if (!nai_realm_match(&realm
[i
], cred
->realm
))
1584 if (nai_realm_find_eap(cred
, &realm
[i
])) {
1585 if (cred_excluded_ssid(cred
, bss
))
1587 if (cred_no_required_oi_match(cred
, bss
))
1589 if (selected
== NULL
||
1590 selected
->priority
< cred
->priority
)
1597 nai_realm_free(realm
, count
);
1603 static struct wpa_cred
* interworking_credentials_available(
1604 struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1606 struct wpa_cred
*cred
, *cred2
;
1608 if (disallowed_bssid(wpa_s
, bss
->bssid
) ||
1609 disallowed_ssid(wpa_s
, bss
->ssid
, bss
->ssid_len
)) {
1610 wpa_printf(MSG_DEBUG
, "Interworking: Ignore disallowed BSS "
1611 MACSTR
, MAC2STR(bss
->bssid
));
1615 cred
= interworking_credentials_available_realm(wpa_s
, bss
);
1616 cred2
= interworking_credentials_available_3gpp(wpa_s
, bss
);
1617 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1622 cred2
= interworking_credentials_available_roaming_consortium(wpa_s
,
1624 if (cred
&& cred2
&& cred2
->priority
>= cred
->priority
)
1633 static int domain_name_list_contains(struct wpabuf
*domain_names
,
1634 const char *domain
, int exact_match
)
1636 const u8
*pos
, *end
;
1639 len
= os_strlen(domain
);
1640 pos
= wpabuf_head(domain_names
);
1641 end
= pos
+ wpabuf_len(domain_names
);
1643 while (pos
+ 1 < end
) {
1644 if (pos
+ 1 + pos
[0] > end
)
1647 wpa_hexdump_ascii(MSG_DEBUG
, "Interworking: AP domain name",
1649 if (pos
[0] == len
&&
1650 os_strncasecmp(domain
, (const char *) (pos
+ 1), len
) == 0)
1652 if (!exact_match
&& pos
[0] > len
&& pos
[pos
[0] - len
] == '.') {
1653 const char *ap
= (const char *) (pos
+ 1);
1654 int offset
= pos
[0] - len
;
1655 if (os_strncasecmp(domain
, ap
+ offset
, len
) == 0)
1666 int interworking_home_sp_cred(struct wpa_supplicant
*wpa_s
,
1667 struct wpa_cred
*cred
,
1668 struct wpabuf
*domain_names
)
1672 #ifdef INTERWORKING_3GPP
1673 char nai
[100], *realm
;
1680 else if (cred
->pcsc
&& wpa_s
->conf
->pcsc_reader
&&
1681 wpa_s
->scard
&& wpa_s
->imsi
[0]) {
1683 mnc_len
= wpa_s
->mnc_len
;
1685 #endif /* CONFIG_PCSC */
1686 #ifdef CONFIG_EAP_PROXY
1687 else if (cred
->pcsc
&& wpa_s
->mnc_len
> 0 && wpa_s
->imsi
[0]) {
1689 mnc_len
= wpa_s
->mnc_len
;
1691 #endif /* CONFIG_EAP_PROXY */
1693 imsi
&& build_root_nai(nai
, sizeof(nai
), imsi
, mnc_len
, 0) == 0) {
1694 realm
= os_strchr(nai
, '@');
1697 wpa_printf(MSG_DEBUG
, "Interworking: Search for match "
1698 "with SIM/USIM domain %s", realm
);
1700 domain_name_list_contains(domain_names
, realm
, 1))
1705 #endif /* INTERWORKING_3GPP */
1707 if (domain_names
== NULL
|| cred
->domain
== NULL
)
1710 for (i
= 0; i
< cred
->num_domain
; i
++) {
1711 wpa_printf(MSG_DEBUG
, "Interworking: Search for match with "
1712 "home SP FQDN %s", cred
->domain
[i
]);
1713 if (domain_name_list_contains(domain_names
, cred
->domain
[i
], 1))
1721 static int interworking_home_sp(struct wpa_supplicant
*wpa_s
,
1722 struct wpabuf
*domain_names
)
1724 struct wpa_cred
*cred
;
1726 if (domain_names
== NULL
|| wpa_s
->conf
->cred
== NULL
)
1729 for (cred
= wpa_s
->conf
->cred
; cred
; cred
= cred
->next
) {
1730 int res
= interworking_home_sp_cred(wpa_s
, cred
, domain_names
);
1739 static int interworking_find_network_match(struct wpa_supplicant
*wpa_s
)
1741 struct wpa_bss
*bss
;
1742 struct wpa_ssid
*ssid
;
1744 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1745 for (ssid
= wpa_s
->conf
->ssid
; ssid
; ssid
= ssid
->next
) {
1746 if (wpas_network_disabled(wpa_s
, ssid
) ||
1747 ssid
->mode
!= WPAS_MODE_INFRA
)
1749 if (ssid
->ssid_len
!= bss
->ssid_len
||
1750 os_memcmp(ssid
->ssid
, bss
->ssid
, ssid
->ssid_len
) !=
1754 * TODO: Consider more accurate matching of security
1755 * configuration similarly to what is done in events.c
1765 static int roaming_partner_match(struct wpa_supplicant
*wpa_s
,
1766 struct roaming_partner
*partner
,
1767 struct wpabuf
*domain_names
)
1769 if (!domain_name_list_contains(domain_names
, partner
->fqdn
,
1770 partner
->exact_match
))
1772 /* TODO: match Country */
1777 static u8
roaming_prio(struct wpa_supplicant
*wpa_s
, struct wpa_cred
*cred
,
1778 struct wpa_bss
*bss
)
1782 if (bss
->anqp
== NULL
|| bss
->anqp
->domain_name
== NULL
)
1783 return 128; /* cannot check preference with domain name */
1785 if (interworking_home_sp_cred(wpa_s
, cred
, bss
->anqp
->domain_name
) > 0)
1786 return 0; /* max preference for home SP network */
1788 for (i
= 0; i
< cred
->num_roaming_partner
; i
++) {
1789 if (roaming_partner_match(wpa_s
, &cred
->roaming_partner
[i
],
1790 bss
->anqp
->domain_name
))
1791 return cred
->roaming_partner
[i
].priority
;
1798 static struct wpa_bss
* pick_best_roaming_partner(struct wpa_supplicant
*wpa_s
,
1799 struct wpa_bss
*selected
,
1800 struct wpa_cred
*cred
)
1802 struct wpa_bss
*bss
;
1806 * Check if any other BSS is operated by a more preferred roaming
1810 best_prio
= roaming_prio(wpa_s
, cred
, selected
);
1812 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1813 if (bss
== selected
)
1815 cred
= interworking_credentials_available(wpa_s
, bss
);
1818 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
))
1820 prio
= roaming_prio(wpa_s
, cred
, bss
);
1821 if (prio
< best_prio
) {
1832 static void interworking_select_network(struct wpa_supplicant
*wpa_s
)
1834 struct wpa_bss
*bss
, *selected
= NULL
, *selected_home
= NULL
;
1835 int selected_prio
= -999999, selected_home_prio
= -999999;
1836 unsigned int count
= 0;
1839 struct wpa_cred
*cred
, *selected_cred
= NULL
;
1840 struct wpa_cred
*selected_home_cred
= NULL
;
1842 wpa_s
->network_select
= 0;
1844 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1845 cred
= interworking_credentials_available(wpa_s
, bss
);
1848 if (!wpa_bss_get_ie(bss
, WLAN_EID_RSN
)) {
1850 * We currently support only HS 2.0 networks and those
1851 * are required to use WPA2-Enterprise.
1853 wpa_printf(MSG_DEBUG
, "Interworking: Credential match "
1854 "with " MACSTR
" but network does not use "
1855 "RSN", MAC2STR(bss
->bssid
));
1859 res
= interworking_home_sp(wpa_s
, bss
->anqp
?
1860 bss
->anqp
->domain_name
: NULL
);
1867 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_AP MACSTR
" type=%s",
1868 MAC2STR(bss
->bssid
), type
);
1869 if (wpa_s
->auto_select
||
1870 (wpa_s
->conf
->auto_interworking
&&
1871 wpa_s
->auto_network_select
)) {
1872 if (selected
== NULL
||
1873 cred
->priority
> selected_prio
) {
1875 selected_prio
= cred
->priority
;
1876 selected_cred
= cred
;
1879 (selected_home
== NULL
||
1880 cred
->priority
> selected_home_prio
)) {
1881 selected_home
= bss
;
1882 selected_home_prio
= cred
->priority
;
1883 selected_home_cred
= cred
;
1888 if (selected_home
&& selected_home
!= selected
&&
1889 selected_home_prio
>= selected_prio
) {
1890 /* Prefer network operated by the Home SP */
1891 selected
= selected_home
;
1892 selected_cred
= selected_home_cred
;
1897 * No matching network was found based on configured
1898 * credentials. Check whether any of the enabled network blocks
1899 * have matching APs.
1901 if (interworking_find_network_match(wpa_s
)) {
1902 wpa_printf(MSG_DEBUG
, "Interworking: Possible BSS "
1903 "match for enabled network configurations");
1904 if (wpa_s
->auto_select
)
1905 interworking_reconnect(wpa_s
);
1909 if (wpa_s
->auto_network_select
) {
1910 wpa_printf(MSG_DEBUG
, "Interworking: Continue "
1911 "scanning after ANQP fetch");
1912 wpa_supplicant_req_scan(wpa_s
, wpa_s
->scan_interval
,
1917 wpa_msg(wpa_s
, MSG_INFO
, INTERWORKING_NO_MATCH
"No network "
1918 "with matching credentials found");
1922 selected
= pick_best_roaming_partner(wpa_s
, selected
,
1924 interworking_connect(wpa_s
, selected
);
1929 static struct wpa_bss_anqp
*
1930 interworking_match_anqp_info(struct wpa_supplicant
*wpa_s
, struct wpa_bss
*bss
)
1932 struct wpa_bss
*other
;
1934 if (is_zero_ether_addr(bss
->hessid
))
1935 return NULL
; /* Cannot be in the same homegenous ESS */
1937 dl_list_for_each(other
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1940 if (other
->anqp
== NULL
)
1942 if (other
->anqp
->roaming_consortium
== NULL
&&
1943 other
->anqp
->nai_realm
== NULL
&&
1944 other
->anqp
->anqp_3gpp
== NULL
&&
1945 other
->anqp
->domain_name
== NULL
)
1947 if (!(other
->flags
& WPA_BSS_ANQP_FETCH_TRIED
))
1949 if (os_memcmp(bss
->hessid
, other
->hessid
, ETH_ALEN
) != 0)
1951 if (bss
->ssid_len
!= other
->ssid_len
||
1952 os_memcmp(bss
->ssid
, other
->ssid
, bss
->ssid_len
) != 0)
1955 wpa_printf(MSG_DEBUG
, "Interworking: Share ANQP data with "
1956 "already fetched BSSID " MACSTR
" and " MACSTR
,
1957 MAC2STR(other
->bssid
), MAC2STR(bss
->bssid
));
1958 other
->anqp
->users
++;
1966 static void interworking_next_anqp_fetch(struct wpa_supplicant
*wpa_s
)
1968 struct wpa_bss
*bss
;
1972 if (eloop_terminated() || !wpa_s
->fetch_anqp_in_progress
)
1975 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
) {
1976 if (!(bss
->caps
& IEEE80211_CAP_ESS
))
1978 ie
= wpa_bss_get_ie(bss
, WLAN_EID_EXT_CAPAB
);
1979 if (ie
== NULL
|| ie
[1] < 4 || !(ie
[5] & 0x80))
1980 continue; /* AP does not support Interworking */
1981 if (disallowed_bssid(wpa_s
, bss
->bssid
) ||
1982 disallowed_ssid(wpa_s
, bss
->ssid
, bss
->ssid_len
))
1983 continue; /* Disallowed BSS */
1985 if (!(bss
->flags
& WPA_BSS_ANQP_FETCH_TRIED
)) {
1986 if (bss
->anqp
== NULL
) {
1987 bss
->anqp
= interworking_match_anqp_info(wpa_s
,
1990 /* Shared data already fetched */
1993 bss
->anqp
= wpa_bss_anqp_alloc();
1994 if (bss
->anqp
== NULL
)
1998 bss
->flags
|= WPA_BSS_ANQP_FETCH_TRIED
;
1999 wpa_msg(wpa_s
, MSG_INFO
, "Starting ANQP fetch for "
2000 MACSTR
, MAC2STR(bss
->bssid
));
2001 interworking_anqp_send_req(wpa_s
, bss
);
2007 wpa_msg(wpa_s
, MSG_INFO
, "ANQP fetch completed");
2008 wpa_s
->fetch_anqp_in_progress
= 0;
2009 if (wpa_s
->network_select
)
2010 interworking_select_network(wpa_s
);
2015 void interworking_start_fetch_anqp(struct wpa_supplicant
*wpa_s
)
2017 struct wpa_bss
*bss
;
2019 dl_list_for_each(bss
, &wpa_s
->bss
, struct wpa_bss
, list
)
2020 bss
->flags
&= ~WPA_BSS_ANQP_FETCH_TRIED
;
2022 wpa_s
->fetch_anqp_in_progress
= 1;
2023 interworking_next_anqp_fetch(wpa_s
);
2027 int interworking_fetch_anqp(struct wpa_supplicant
*wpa_s
)
2029 if (wpa_s
->fetch_anqp_in_progress
|| wpa_s
->network_select
)
2032 wpa_s
->network_select
= 0;
2033 wpa_s
->fetch_all_anqp
= 1;
2035 interworking_start_fetch_anqp(wpa_s
);
2041 void interworking_stop_fetch_anqp(struct wpa_supplicant
*wpa_s
)
2043 if (!wpa_s
->fetch_anqp_in_progress
)
2046 wpa_s
->fetch_anqp_in_progress
= 0;
2050 int anqp_send_req(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
2051 u16 info_ids
[], size_t num_ids
)
2056 struct wpa_bss
*bss
;
2059 freq
= wpa_s
->assoc_freq
;
2060 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2062 wpa_bss_anqp_unshare_alloc(bss
);
2068 wpa_printf(MSG_DEBUG
, "ANQP: Query Request to " MACSTR
" for %u id(s)",
2069 MAC2STR(dst
), (unsigned int) num_ids
);
2071 buf
= anqp_build_req(info_ids
, num_ids
, NULL
);
2075 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, anqp_resp_cb
, wpa_s
);
2077 wpa_printf(MSG_DEBUG
, "ANQP: Failed to send Query Request");
2081 wpa_printf(MSG_DEBUG
, "ANQP: Query started with dialog token "
2088 static void interworking_parse_rx_anqp_resp(struct wpa_supplicant
*wpa_s
,
2089 struct wpa_bss
*bss
, const u8
*sa
,
2091 const u8
*data
, size_t slen
)
2093 const u8
*pos
= data
;
2094 struct wpa_bss_anqp
*anqp
= NULL
;
2097 #endif /* CONFIG_HS20 */
2103 case ANQP_CAPABILITY_LIST
:
2104 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2105 " ANQP Capability list", MAC2STR(sa
));
2107 case ANQP_VENUE_NAME
:
2108 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2109 " Venue Name", MAC2STR(sa
));
2110 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Venue Name", pos
, slen
);
2112 wpabuf_free(anqp
->venue_name
);
2113 anqp
->venue_name
= wpabuf_alloc_copy(pos
, slen
);
2116 case ANQP_NETWORK_AUTH_TYPE
:
2117 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2118 " Network Authentication Type information",
2120 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Network Authentication "
2123 wpabuf_free(anqp
->network_auth_type
);
2124 anqp
->network_auth_type
= wpabuf_alloc_copy(pos
, slen
);
2127 case ANQP_ROAMING_CONSORTIUM
:
2128 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2129 " Roaming Consortium list", MAC2STR(sa
));
2130 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: Roaming Consortium",
2133 wpabuf_free(anqp
->roaming_consortium
);
2134 anqp
->roaming_consortium
= wpabuf_alloc_copy(pos
, slen
);
2137 case ANQP_IP_ADDR_TYPE_AVAILABILITY
:
2138 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2139 " IP Address Type Availability information",
2141 wpa_hexdump(MSG_MSGDUMP
, "ANQP: IP Address Availability",
2144 wpabuf_free(anqp
->ip_addr_type_availability
);
2145 anqp
->ip_addr_type_availability
=
2146 wpabuf_alloc_copy(pos
, slen
);
2149 case ANQP_NAI_REALM
:
2150 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2151 " NAI Realm list", MAC2STR(sa
));
2152 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: NAI Realm", pos
, slen
);
2154 wpabuf_free(anqp
->nai_realm
);
2155 anqp
->nai_realm
= wpabuf_alloc_copy(pos
, slen
);
2158 case ANQP_3GPP_CELLULAR_NETWORK
:
2159 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2160 " 3GPP Cellular Network information", MAC2STR(sa
));
2161 wpa_hexdump_ascii(MSG_DEBUG
, "ANQP: 3GPP Cellular Network",
2164 wpabuf_free(anqp
->anqp_3gpp
);
2165 anqp
->anqp_3gpp
= wpabuf_alloc_copy(pos
, slen
);
2168 case ANQP_DOMAIN_NAME
:
2169 wpa_msg(wpa_s
, MSG_INFO
, "RX-ANQP " MACSTR
2170 " Domain Name list", MAC2STR(sa
));
2171 wpa_hexdump_ascii(MSG_MSGDUMP
, "ANQP: Domain Name", pos
, slen
);
2173 wpabuf_free(anqp
->domain_name
);
2174 anqp
->domain_name
= wpabuf_alloc_copy(pos
, slen
);
2177 case ANQP_VENDOR_SPECIFIC
:
2181 switch (WPA_GET_BE24(pos
)) {
2193 case HS20_ANQP_OUI_TYPE
:
2194 hs20_parse_rx_hs20_anqp_resp(wpa_s
, sa
, pos
,
2198 wpa_printf(MSG_DEBUG
, "HS20: Unsupported ANQP "
2199 "vendor type %u", type
);
2203 #endif /* CONFIG_HS20 */
2205 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported "
2206 "vendor-specific ANQP OUI %06x",
2212 wpa_printf(MSG_DEBUG
, "Interworking: Unsupported ANQP Info ID "
2219 void anqp_resp_cb(void *ctx
, const u8
*dst
, u8 dialog_token
,
2220 enum gas_query_result result
,
2221 const struct wpabuf
*adv_proto
,
2222 const struct wpabuf
*resp
, u16 status_code
)
2224 struct wpa_supplicant
*wpa_s
= ctx
;
2229 struct wpa_bss
*bss
= NULL
, *tmp
;
2231 if (result
!= GAS_QUERY_SUCCESS
)
2234 pos
= wpabuf_head(adv_proto
);
2235 if (wpabuf_len(adv_proto
) < 4 || pos
[0] != WLAN_EID_ADV_PROTO
||
2236 pos
[1] < 2 || pos
[3] != ACCESS_NETWORK_QUERY_PROTOCOL
) {
2237 wpa_printf(MSG_DEBUG
, "ANQP: Unexpected Advertisement "
2238 "Protocol in response");
2243 * If possible, select the BSS entry based on which BSS entry was used
2244 * for the request. This can help in cases where multiple BSS entries
2245 * may exist for the same AP.
2247 dl_list_for_each_reverse(tmp
, &wpa_s
->bss
, struct wpa_bss
, list
) {
2248 if (tmp
== wpa_s
->interworking_gas_bss
&&
2249 os_memcmp(tmp
->bssid
, dst
, ETH_ALEN
) == 0) {
2255 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2257 pos
= wpabuf_head(resp
);
2258 end
= pos
+ wpabuf_len(resp
);
2261 if (pos
+ 4 > end
) {
2262 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element");
2265 info_id
= WPA_GET_LE16(pos
);
2267 slen
= WPA_GET_LE16(pos
);
2269 if (pos
+ slen
> end
) {
2270 wpa_printf(MSG_DEBUG
, "ANQP: Invalid element length "
2271 "for Info ID %u", info_id
);
2274 interworking_parse_rx_anqp_resp(wpa_s
, bss
, dst
, info_id
, pos
,
2281 static void interworking_scan_res_handler(struct wpa_supplicant
*wpa_s
,
2282 struct wpa_scan_results
*scan_res
)
2284 wpa_printf(MSG_DEBUG
, "Interworking: Scan results available - start "
2286 interworking_start_fetch_anqp(wpa_s
);
2290 int interworking_select(struct wpa_supplicant
*wpa_s
, int auto_select
,
2293 interworking_stop_fetch_anqp(wpa_s
);
2294 wpa_s
->network_select
= 1;
2295 wpa_s
->auto_network_select
= 0;
2296 wpa_s
->auto_select
= !!auto_select
;
2297 wpa_s
->fetch_all_anqp
= 0;
2298 wpa_printf(MSG_DEBUG
, "Interworking: Start scan for network "
2300 wpa_s
->scan_res_handler
= interworking_scan_res_handler
;
2301 wpa_s
->normal_scans
= 0;
2302 wpa_s
->scan_req
= MANUAL_SCAN_REQ
;
2303 os_free(wpa_s
->manual_scan_freqs
);
2304 wpa_s
->manual_scan_freqs
= freqs
;
2305 wpa_s
->after_wps
= 0;
2306 wpa_s
->known_wps_freq
= 0;
2307 wpa_supplicant_req_scan(wpa_s
, 0, 0);
2313 static void gas_resp_cb(void *ctx
, const u8
*addr
, u8 dialog_token
,
2314 enum gas_query_result result
,
2315 const struct wpabuf
*adv_proto
,
2316 const struct wpabuf
*resp
, u16 status_code
)
2318 struct wpa_supplicant
*wpa_s
= ctx
;
2321 wpa_msg(wpa_s
, MSG_INFO
, GAS_RESPONSE_INFO
"addr=" MACSTR
2322 " dialog_token=%d status_code=%d resp_len=%d",
2323 MAC2STR(addr
), dialog_token
, status_code
,
2324 resp
? (int) wpabuf_len(resp
) : -1);
2328 n
= wpabuf_dup(resp
);
2331 wpabuf_free(wpa_s
->prev_gas_resp
);
2332 wpa_s
->prev_gas_resp
= wpa_s
->last_gas_resp
;
2333 os_memcpy(wpa_s
->prev_gas_addr
, wpa_s
->last_gas_addr
, ETH_ALEN
);
2334 wpa_s
->prev_gas_dialog_token
= wpa_s
->last_gas_dialog_token
;
2335 wpa_s
->last_gas_resp
= n
;
2336 os_memcpy(wpa_s
->last_gas_addr
, addr
, ETH_ALEN
);
2337 wpa_s
->last_gas_dialog_token
= dialog_token
;
2341 int gas_send_request(struct wpa_supplicant
*wpa_s
, const u8
*dst
,
2342 const struct wpabuf
*adv_proto
,
2343 const struct wpabuf
*query
)
2348 struct wpa_bss
*bss
;
2351 u8 query_resp_len_limit
= 0, pame_bi
= 0;
2353 freq
= wpa_s
->assoc_freq
;
2354 bss
= wpa_bss_get_bssid(wpa_s
, dst
);
2360 wpa_printf(MSG_DEBUG
, "GAS request to " MACSTR
" (freq %d MHz)",
2361 MAC2STR(dst
), freq
);
2362 wpa_hexdump_buf(MSG_DEBUG
, "Advertisement Protocol ID", adv_proto
);
2363 wpa_hexdump_buf(MSG_DEBUG
, "GAS Query", query
);
2365 len
= 3 + wpabuf_len(adv_proto
) + 2;
2367 len
+= wpabuf_len(query
);
2368 buf
= gas_build_initial_req(0, len
);
2372 /* Advertisement Protocol IE */
2373 wpabuf_put_u8(buf
, WLAN_EID_ADV_PROTO
);
2374 wpabuf_put_u8(buf
, 1 + wpabuf_len(adv_proto
)); /* Length */
2375 wpabuf_put_u8(buf
, (query_resp_len_limit
& 0x7f) |
2376 (pame_bi
? 0x80 : 0));
2377 wpabuf_put_buf(buf
, adv_proto
);
2381 wpabuf_put_le16(buf
, wpabuf_len(query
));
2382 wpabuf_put_buf(buf
, query
);
2384 wpabuf_put_le16(buf
, 0);
2386 res
= gas_query_req(wpa_s
->gas
, dst
, freq
, buf
, gas_resp_cb
, wpa_s
);
2388 wpa_printf(MSG_DEBUG
, "GAS: Failed to send Query Request");
2392 wpa_printf(MSG_DEBUG
, "GAS: Query started with dialog token "