diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-07 02:13:27 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2020-04-07 02:13:27 +0000 |
commit | ce4e1673f94ef1f467f4220ce42f92db13fc68e6 (patch) | |
tree | 60ed88972e9c3ba77e3470046ceda53c7702f7e7 | |
parent | 41117d2e6dbc171d0a7bdf6f6b038eb60f1f5695 (diff) | |
parent | 1337a99542601c02f0e0fc3a10cb5aa098a73dc7 (diff) | |
download | wpa_supplicant_8-ce4e1673f94ef1f467f4220ce42f92db13fc68e6.tar.gz |
Snap for 6370344 from 1337a99542601c02f0e0fc3a10cb5aa098a73dc7 to rvc-release
Change-Id: Id1d8525e31e66bf290051249095ae4c7ade76f92
194 files changed, 12393 insertions, 3334 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk index eb01da5c..dff5704d 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -156,6 +156,7 @@ OBJS += src/utils/wpa_debug.c OBJS += src/utils/wpabuf.c OBJS += src/utils/os_$(CONFIG_OS).c OBJS += src/utils/ip_addr.c +OBJS += src/utils/crc32.c OBJS += src/common/ieee802_11_common.c OBJS += src/common/wpa_common.c @@ -295,10 +296,6 @@ L_CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP OBJS += src/ap/wnm_ap.c endif -ifdef CONFIG_IEEE80211N -L_CFLAGS += -DCONFIG_IEEE80211N -endif - ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif @@ -327,6 +324,10 @@ OBJS += src/fst/fst_ctrl_iface.c endif endif +ifdef CONFIG_WEP +L_CFLAGS += -DCONFIG_WEP +endif + include $(LOCAL_PATH)/src/drivers/drivers.mk @@ -558,6 +559,7 @@ NEED_ECC=y NEED_JSON=y NEED_GAS=y NEED_BASE64=y +NEED_ASN1=y ifdef CONFIG_DPP2 L_CFLAGS += -DCONFIG_DPP2 endif @@ -695,12 +697,12 @@ OBJS += src/tls/tlsv1_cred.c OBJS += src/tls/tlsv1_server.c OBJS += src/tls/tlsv1_server_write.c OBJS += src/tls/tlsv1_server_read.c -OBJS += src/tls/asn1.c OBJS += src/tls/rsa.c OBJS += src/tls/x509v3.c OBJS += src/tls/pkcs1.c OBJS += src/tls/pkcs5.c OBJS += src/tls/pkcs8.c +NEED_ASN1=y NEED_BASE64=y NEED_TLS_PRF=y ifdef CONFIG_TLSV12 @@ -950,6 +952,10 @@ L_CFLAGS += -DCONFIG_INTERNAL_SHA512 OBJS += src/crypto/sha512-internal.c endif +ifdef NEED_ASN1 +OBJS += src/tls/asn1.c +endif + ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_groups.c endif @@ -1008,9 +1014,7 @@ OBJS += src/ap/hw_features.c OBJS += src/ap/dfs.c L_CFLAGS += -DNEED_AP_MLME endif -ifdef CONFIG_IEEE80211N OBJS += src/ap/ieee802_11_ht.c -endif ifdef CONFIG_IEEE80211AC OBJS += src/ap/ieee802_11_vht.c diff --git a/hostapd/Makefile b/hostapd/Makefile index f01f5814..4adf9968 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -158,6 +158,7 @@ OBJS_c += ../src/utils/wpa_debug.o OBJS += ../src/utils/wpabuf.o OBJS += ../src/utils/os_$(CONFIG_OS).o OBJS += ../src/utils/ip_addr.o +OBJS += ../src/utils/crc32.o OBJS += ../src/common/ieee802_11_common.o OBJS += ../src/common/wpa_common.o @@ -334,10 +335,6 @@ CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP OBJS += ../src/ap/wnm_ap.o endif -ifdef CONFIG_IEEE80211N -CFLAGS += -DCONFIG_IEEE80211N -endif - ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif @@ -586,6 +583,7 @@ NEED_ECC=y NEED_JSON=y NEED_GAS=y NEED_BASE64=y +NEED_ASN1=y ifdef CONFIG_DPP2 CFLAGS += -DCONFIG_DPP2 endif @@ -759,12 +757,12 @@ OBJS += ../src/tls/tlsv1_cred.o OBJS += ../src/tls/tlsv1_server.o OBJS += ../src/tls/tlsv1_server_write.o OBJS += ../src/tls/tlsv1_server_read.o -OBJS += ../src/tls/asn1.o OBJS += ../src/tls/rsa.o OBJS += ../src/tls/x509v3.o OBJS += ../src/tls/pkcs1.o OBJS += ../src/tls/pkcs5.o OBJS += ../src/tls/pkcs8.o +NEED_ASN1=y NEED_BASE64=y NEED_TLS_PRF=y ifdef CONFIG_TLSV12 @@ -835,12 +833,12 @@ OBJS += ../src/tls/tlsv1_cred.o OBJS += ../src/tls/tlsv1_server.o OBJS += ../src/tls/tlsv1_server_write.o OBJS += ../src/tls/tlsv1_server_read.o -OBJS += ../src/tls/asn1.o OBJS += ../src/tls/rsa.o OBJS += ../src/tls/x509v3.o OBJS += ../src/tls/pkcs1.o OBJS += ../src/tls/pkcs5.o OBJS += ../src/tls/pkcs8.o +NEED_ASN1=y NEED_BASE64=y NEED_TLS_PRF=y ifdef CONFIG_TLSV12 @@ -1088,6 +1086,10 @@ CFLAGS += -DCONFIG_INTERNAL_SHA512 OBJS += ../src/crypto/sha512-internal.o endif +ifdef NEED_ASN1 +OBJS += ../src/tls/asn1.o +endif + ifdef NEED_DH_GROUPS OBJS += ../src/crypto/dh_groups.o endif @@ -1153,9 +1155,7 @@ OBJS += ../src/ap/hw_features.o OBJS += ../src/ap/dfs.o CFLAGS += -DNEED_AP_MLME endif -ifdef CONFIG_IEEE80211N OBJS += ../src/ap/ieee802_11_ht.o -endif ifdef CONFIG_IEEE80211AC OBJS += ../src/ap/ieee802_11_vht.o @@ -1242,6 +1242,10 @@ OBJS += ../src/fst/fst_ctrl_iface.o endif endif +ifdef CONFIG_WEP +CFLAGS += -DCONFIG_WEP +endif + ALL=hostapd hostapd_cli all: verify_config $(ALL) diff --git a/hostapd/android.config b/hostapd/android.config index 68fec325..c53875c5 100644 --- a/hostapd/android.config +++ b/hostapd/android.config @@ -125,12 +125,6 @@ CONFIG_IPV6=y # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211) #CONFIG_DRIVER_RADIUS_ACL=y -# IEEE 802.11n (High Throughput) support -CONFIG_IEEE80211N=y - -# IEEE 802.11ac (Very High Throughput) support -CONFIG_IEEE80211AC=y - # Remove debugging code that is printing out debug messages to stdout. # This can be used to reduce the size of the hostapd considerably if debugging # code is not needed. @@ -225,3 +219,12 @@ CONFIG_DPP=y # WPA3-Personal (SAE) CONFIG_SAE=y + +# Wired equivalent privacy (WEP) +# WEP is an obsolete cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used for anything anymore. The +# functionality needed to use WEP is available in the current hostapd +# release under this optional build parameter. This functionality is subject to +# be completely removed in a future release. +CONFIG_WEP=y + diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 21c9ab28..1d8c0397 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -793,6 +793,7 @@ static int hostapd_config_parse_cipher(int line, const char *value) } +#ifdef CONFIG_WEP static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx, char *val) { @@ -843,6 +844,7 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx, return 0; } +#endif /* CONFIG_WEP */ static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val) @@ -1151,7 +1153,6 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value) #endif /* CONFIG_IEEE80211R_AP */ -#ifdef CONFIG_IEEE80211N static int hostapd_config_ht_capab(struct hostapd_config *conf, const char *capab) { @@ -1171,14 +1172,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf, } if (!os_strstr(capab, "[HT40+]") && !os_strstr(capab, "[HT40-]")) conf->secondary_channel = 0; - if (os_strstr(capab, "[SMPS-STATIC]")) { - conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; - conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC; - } - if (os_strstr(capab, "[SMPS-DYNAMIC]")) { - conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK; - conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC; - } if (os_strstr(capab, "[GF]")) conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD; if (os_strstr(capab, "[SHORT-GI-20]")) @@ -1212,7 +1205,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf, return 0; } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC @@ -2471,6 +2463,13 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "skip_inactivity_poll") == 0) { bss->skip_inactivity_poll = atoi(pos); } else if (os_strcmp(buf, "country_code") == 0) { + if (pos[0] < 'A' || pos[0] > 'Z' || + pos[1] < 'A' || pos[1] > 'Z') { + wpa_printf(MSG_ERROR, + "Line %d: Invalid country_code '%s'", + line, pos); + return 1; + } os_memcpy(conf->country, pos, 2); } else if (os_strcmp(buf, "country3") == 0) { conf->country[2] = strtol(pos, NULL, 16); @@ -2674,6 +2673,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "erp_domain") == 0) { os_free(bss->erp_domain); bss->erp_domain = os_strdup(pos); +#ifdef CONFIG_WEP } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) { int val = atoi(pos); @@ -2701,6 +2701,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, bss->wep_rekeying_period); return 1; } +#endif /* CONFIG_WEP */ } else if (os_strcmp(buf, "eap_reauth_period") == 0) { bss->eap_reauth_period = atoi(pos); if (bss->eap_reauth_period < 0) { @@ -2875,6 +2876,16 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "wpa") == 0) { bss->wpa = atoi(pos); + } else if (os_strcmp(buf, "extended_key_id") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 2) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid extended_key_id=%d; allowed range 0..2", + line, val); + return 1; + } + bss->extended_key_id = val; } else if (os_strcmp(buf, "wpa_group_rekey") == 0) { bss->wpa_group_rekey = atoi(pos); bss->wpa_group_rekey_set = 1; @@ -2884,6 +2895,15 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->wpa_gmk_rekey = atoi(pos); } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) { bss->wpa_ptk_rekey = atoi(pos); + } else if (os_strcmp(buf, "wpa_deny_ptk0_rekey") == 0) { + bss->wpa_deny_ptk0_rekey = atoi(pos); + if (bss->wpa_deny_ptk0_rekey < 0 || + bss->wpa_deny_ptk0_rekey > 2) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid wpa_deny_ptk0_rekey=%d; allowed range 0..2", + line, bss->wpa_deny_ptk0_rekey); + return 1; + } } else if (os_strcmp(buf, "wpa_group_update_count") == 0) { char *endp; unsigned long val = strtoul(pos, &endp, 0); @@ -3312,6 +3332,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->ignore_broadcast_ssid = atoi(pos); } else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) { bss->no_probe_resp_if_max_sta = atoi(pos); +#ifdef CONFIG_WEP } else if (os_strcmp(buf, "wep_default_key") == 0) { bss->ssid.wep.idx = atoi(pos); if (bss->ssid.wep.idx > 3) { @@ -3330,6 +3351,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, buf); return 1; } +#endif /* CONFIG_WEP */ #ifndef CONFIG_NO_VLAN } else if (os_strcmp(buf, "dynamic_vlan") == 0) { bss->ssid.dynamic_vlan = atoi(pos); @@ -3408,6 +3430,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "beacon_prot") == 0) { + bss->beacon_prot = atoi(pos); } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) { bss->assoc_sa_query_max_timeout = atoi(pos); if (bss->assoc_sa_query_max_timeout == 0) { @@ -3428,7 +3452,6 @@ static int hostapd_config_fill(struct hostapd_config *conf, if (bss->ocv && !bss->ieee80211w) bss->ieee80211w = 1; #endif /* CONFIG_OCV */ -#ifdef CONFIG_IEEE80211N } else if (os_strcmp(buf, "ieee80211n") == 0) { conf->ieee80211n = atoi(pos); } else if (os_strcmp(buf, "ht_capab") == 0) { @@ -3441,7 +3464,6 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->require_ht = atoi(pos); } else if (os_strcmp(buf, "obss_interval") == 0) { conf->obss_interval = atoi(pos); -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC } else if (os_strcmp(buf, "ieee80211ac") == 0) { conf->ieee80211ac = atoi(pos); @@ -3474,7 +3496,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "he_mu_beamformer") == 0) { conf->he_phy_capab.he_mu_beamformer = atoi(pos); } else if (os_strcmp(buf, "he_bss_color") == 0) { - conf->he_op.he_bss_color = atoi(pos); + conf->he_op.he_bss_color = atoi(pos) & 0x3f; + conf->he_op.he_bss_color_disabled = 0; + } else if (os_strcmp(buf, "he_bss_color_partial") == 0) { + conf->he_op.he_bss_color_partial = atoi(pos); } else if (os_strcmp(buf, "he_default_pe_duration") == 0) { conf->he_op.he_default_pe_duration = atoi(pos); } else if (os_strcmp(buf, "he_twt_required") == 0) { @@ -3762,6 +3787,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "server_id") == 0) { os_free(bss->server_id); bss->server_id = os_strdup(pos); + } else if (os_strcmp(buf, "wps_application_ext") == 0) { + wpabuf_free(bss->wps_application_ext); + bss->wps_application_ext = wpabuf_parse_bin(pos); #ifdef CONFIG_WPS_NFC } else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) { bss->wps_nfc_dev_pw_id = atoi(pos); @@ -4165,9 +4193,28 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "sae_commit_override") == 0) { wpabuf_free(bss->sae_commit_override); bss->sae_commit_override = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "rsne_override_eapol") == 0) { + wpabuf_free(bss->rsne_override_eapol); + bss->rsne_override_eapol = wpabuf_parse_bin(pos); } else if (os_strcmp(buf, "rsnxe_override_eapol") == 0) { wpabuf_free(bss->rsnxe_override_eapol); bss->rsnxe_override_eapol = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "rsne_override_ft") == 0) { + wpabuf_free(bss->rsne_override_ft); + bss->rsne_override_ft = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "rsnxe_override_ft") == 0) { + wpabuf_free(bss->rsnxe_override_ft); + bss->rsnxe_override_ft = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "gtk_rsc_override") == 0) { + wpabuf_free(bss->gtk_rsc_override); + bss->gtk_rsc_override = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "igtk_rsc_override") == 0) { + wpabuf_free(bss->igtk_rsc_override); + bss->igtk_rsc_override = wpabuf_parse_bin(pos); + } else if (os_strcmp(buf, "no_beacon_rsnxe") == 0) { + bss->no_beacon_rsnxe = atoi(pos); + } else if (os_strcmp(buf, "skip_prune_assoc") == 0) { + bss->skip_prune_assoc = atoi(pos); #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_SAE } else if (os_strcmp(buf, "sae_password") == 0) { @@ -4370,6 +4417,18 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "dpp_controller") == 0) { if (hostapd_dpp_controller_parse(bss, pos)) return 1; + } else if (os_strcmp(buf, "dpp_configurator_connectivity") == 0) { + bss->dpp_configurator_connectivity = atoi(pos); + } else if (os_strcmp(buf, "dpp_pfs") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 2) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid dpp_pfs value '%s'", + line, pos); + return -1; + } + bss->dpp_pfs = val; #endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ #ifdef CONFIG_OWE @@ -4403,9 +4462,11 @@ static int hostapd_config_fill(struct hostapd_config *conf, line, pos); return 1; } + } else if (os_strcmp(buf, "owe_ptk_workaround") == 0) { + bss->owe_ptk_workaround = atoi(pos); +#endif /* CONFIG_OWE */ } else if (os_strcmp(buf, "coloc_intf_reporting") == 0) { bss->coloc_intf_reporting = atoi(pos); -#endif /* CONFIG_OWE */ } else if (os_strcmp(buf, "multi_ap") == 0) { int val = atoi(pos); @@ -4422,6 +4483,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->rssi_reject_assoc_timeout = atoi(pos); } else if (os_strcmp(buf, "pbss") == 0) { bss->pbss = atoi(pos); + } else if (os_strcmp(buf, "transition_disable") == 0) { + bss->transition_disable = strtol(pos, NULL, 16); #ifdef CONFIG_AIRTIME_POLICY } else if (os_strcmp(buf, "airtime_mode") == 0) { int val = atoi(pos); diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 9758881b..d90b5dc8 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -11,7 +11,11 @@ #ifndef CONFIG_NATIVE_WINDOWS #ifdef CONFIG_TESTING_OPTIONS +#ifdef __NetBSD__ +#include <net/if_ether.h> +#else #include <net/ethernet.h> +#endif #include <netinet/ip.h> #endif /* CONFIG_TESTING_OPTIONS */ @@ -55,6 +59,7 @@ #include "ap/neighbor_db.h" #include "ap/rrm.h" #include "ap/dpp_hostapd.h" +#include "ap/dfs.h" #include "wps/wps_defs.h" #include "wps/wps.h" #include "fst/fst_ctrl_iface.h" @@ -65,9 +70,6 @@ #define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256 #ifdef CONFIG_CTRL_IFACE_UDP -#define COOKIE_LEN 8 -static unsigned char cookie[COOKIE_LEN]; -static unsigned char gcookie[COOKIE_LEN]; #define HOSTAPD_CTRL_IFACE_PORT 8877 #define HOSTAPD_CTRL_IFACE_PORT_LIMIT 50 #define HOSTAPD_GLOBAL_CTRL_IFACE_PORT 8878 @@ -1286,6 +1288,22 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, pos += ret; } + if (hapd->conf->wpa && hapd->conf->wpa_deny_ptk0_rekey) { + ret = os_snprintf(pos, end - pos, "wpa_deny_ptk0_rekey=%d\n", + hapd->conf->wpa_deny_ptk0_rekey); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->extended_key_id) { + ret = os_snprintf(pos, end - pos, "extended_key_id=%d\n", + hapd->conf->extended_key_id); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + return pos - buf; } @@ -1658,7 +1676,7 @@ static int hostapd_ctrl_iface_mgmt_tx(struct hostapd_data *hapd, char *cmd) return -1; } - res = hostapd_drv_send_mlme(hapd, buf, len, 0); + res = hostapd_drv_send_mlme(hapd, buf, len, 0, NULL, 0, 0); os_free(buf); return res; } @@ -1857,7 +1875,7 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, { struct hostapd_data *hapd = ctx; const struct ether_header *eth; - struct iphdr ip; + struct ip ip; const u8 *pos; unsigned int i; char extra[30]; @@ -1873,14 +1891,14 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, os_memcpy(&ip, eth + 1, sizeof(ip)); pos = &buf[sizeof(*eth) + sizeof(ip)]; - if (ip.ihl != 5 || ip.version != 4 || - ntohs(ip.tot_len) > HWSIM_IP_LEN) { + if (ip.ip_hl != 5 || ip.ip_v != 4 || + ntohs(ip.ip_len) > HWSIM_IP_LEN) { wpa_printf(MSG_DEBUG, "test data: RX - ignore unexpect IP header"); return; } - for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) { + for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) { if (*pos != (u8) i) { wpa_printf(MSG_DEBUG, "test data: RX - ignore mismatching payload"); @@ -1890,8 +1908,8 @@ static void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, } extra[0] = '\0'; - if (ntohs(ip.tot_len) != HWSIM_IP_LEN) - os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len)); + if (ntohs(ip.ip_len) != HWSIM_IP_LEN) + os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len)); wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s", MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra); } @@ -1944,7 +1962,7 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd) u8 tos; u8 buf[2 + HWSIM_PACKETLEN]; struct ether_header *eth; - struct iphdr *ip; + struct ip *ip; u8 *dpos; unsigned int i; size_t send_len = HWSIM_IP_LEN; @@ -1983,17 +2001,17 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd) os_memcpy(eth->ether_dhost, dst, ETH_ALEN); os_memcpy(eth->ether_shost, src, ETH_ALEN); eth->ether_type = htons(ETHERTYPE_IP); - ip = (struct iphdr *) (eth + 1); + ip = (struct ip *) (eth + 1); os_memset(ip, 0, sizeof(*ip)); - ip->ihl = 5; - ip->version = 4; - ip->ttl = 64; - ip->tos = tos; - ip->tot_len = htons(send_len); - ip->protocol = 1; - ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); - ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2); - ip->check = ipv4_hdr_checksum(ip, sizeof(*ip)); + ip->ip_hl = 5; + ip->ip_v = 4; + ip->ip_ttl = 64; + ip->ip_tos = tos; + ip->ip_len = htons(send_len); + ip->ip_p = 1; + ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); + ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2); + ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip)); dpos = (u8 *) (ip + 1); for (i = 0; i < send_len - sizeof(*ip); i++) *dpos++ = i; @@ -2150,17 +2168,19 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd) if (hostapd_drv_set_key(hapd->conf->iface, hapd, hapd->last_igtk_alg, broadcast_ether_addr, - hapd->last_igtk_key_idx, 1, NULL, 0, - zero, hapd->last_igtk_len) < 0) + hapd->last_igtk_key_idx, 0, 1, NULL, 0, + zero, hapd->last_igtk_len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) return -1; /* Set the previously configured key to reset its TSC */ return hostapd_drv_set_key(hapd->conf->iface, hapd, hapd->last_igtk_alg, broadcast_ether_addr, - hapd->last_igtk_key_idx, 1, NULL, 0, - hapd->last_igtk, - hapd->last_igtk_len); + hapd->last_igtk_key_idx, 0, 1, NULL, + 0, hapd->last_igtk, + hapd->last_igtk_len, + KEY_FLAG_GROUP_TX_DEFAULT); } if (is_broadcast_ether_addr(addr)) { @@ -2174,16 +2194,19 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd) if (hostapd_drv_set_key(hapd->conf->iface, hapd, hapd->last_gtk_alg, broadcast_ether_addr, - hapd->last_gtk_key_idx, 1, NULL, 0, - zero, hapd->last_gtk_len) < 0) + hapd->last_gtk_key_idx, 0, 1, NULL, 0, + zero, hapd->last_gtk_len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) return -1; /* Set the previously configured key to reset its TSC */ return hostapd_drv_set_key(hapd->conf->iface, hapd, hapd->last_gtk_alg, broadcast_ether_addr, - hapd->last_gtk_key_idx, 1, NULL, 0, - hapd->last_gtk, hapd->last_gtk_len); + hapd->last_gtk_key_idx, 0, 1, NULL, + 0, hapd->last_gtk, + hapd->last_gtk_len, + KEY_FLAG_GROUP_TX_DEFAULT); } sta = ap_get_sta(hapd, addr); @@ -2199,14 +2222,16 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd) /* First, use a zero key to avoid any possible duplicate key avoidance * in the driver. */ if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg, - sta->addr, sta->last_tk_key_idx, 1, NULL, 0, - zero, sta->last_tk_len) < 0) + sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0, + zero, sta->last_tk_len, + KEY_FLAG_PAIRWISE_RX_TX) < 0) return -1; /* Set the previously configured key to reset its TSC/RSC */ return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg, - sta->addr, sta->last_tk_key_idx, 1, NULL, 0, - sta->last_tk, sta->last_tk_len); + sta->addr, sta->last_tk_key_idx, 0, 1, NULL, + 0, sta->last_tk, sta->last_tk_len, + KEY_FLAG_PAIRWISE_RX_TX); } @@ -2215,11 +2240,12 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd) u8 addr[ETH_ALEN]; const char *pos = cmd; enum wpa_alg alg; + enum key_flag key_flag; int idx, set_tx; u8 seq[6], key[WPA_TK_MAX_LEN]; size_t key_len; - /* parameters: alg addr idx set_tx seq key */ + /* parameters: alg addr idx set_tx seq key key_flag */ alg = atoi(pos); pos = os_strchr(pos, ' '); @@ -2248,13 +2274,24 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd) if (*pos != ' ') return -1; pos++; - key_len = os_strlen(pos) / 2; + if (!os_strchr(pos, ' ')) + return -1; + key_len = (os_strchr(pos, ' ') - pos) / 2; if (hexstr2bin(pos, key, key_len) < 0) return -1; + pos += 2 * key_len; + if (*pos != ' ') + return -1; + + pos++; + key_flag = atoi(pos); + pos = os_strchr(pos, ' '); + if (pos) + return -1; wpa_printf(MSG_INFO, "TESTING: Set key"); - return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, - set_tx, seq, 6, key, key_len); + return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx, 0, + set_tx, seq, 6, key, key_len, key_flag); } @@ -2269,8 +2306,9 @@ static void restore_tk(void *ctx1, void *ctx2) * in replay protection issues for now since there is no clean way of * preventing encryption of a single EAPOL frame. */ hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg, - sta->addr, sta->last_tk_key_idx, 1, NULL, 0, - sta->last_tk, sta->last_tk_len); + sta->addr, sta->last_tk_key_idx, 0, 1, NULL, 0, + sta->last_tk, sta->last_tk_len, + KEY_FLAG_PAIRWISE_RX_TX); } @@ -2293,8 +2331,8 @@ static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd) wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR, MAC2STR(sta->addr)); hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE, - sta->addr, sta->last_tk_key_idx, 0, NULL, 0, - NULL, 0); + sta->addr, sta->last_tk_key_idx, 0, 0, NULL, + 0, NULL, 0, KEY_FLAG_PAIRWISE); } wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr)); @@ -2323,8 +2361,8 @@ static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd) wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR, MAC2STR(sta->addr)); hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE, - sta->addr, sta->last_tk_key_idx, 0, NULL, 0, - NULL, 0); + sta->addr, sta->last_tk_key_idx, 0, 0, NULL, + 0, NULL, 0, KEY_FLAG_PAIRWISE); } wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr)); @@ -2353,8 +2391,8 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd, wpa_printf(MSG_INFO, "TESTING: Clear TK for " MACSTR, MAC2STR(sta->addr)); hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE, - sta->addr, sta->last_tk_key_idx, 0, NULL, 0, - NULL, 0); + sta->addr, sta->last_tk_key_idx, 0, 0, NULL, + 0, NULL, 0, KEY_FLAG_PAIRWISE); } wpa_printf(MSG_INFO, @@ -2364,21 +2402,204 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd, plain ? restore_tk : NULL, hapd, sta); } + +static int hostapd_ctrl_get_pmk(struct hostapd_data *hapd, const char *cmd, + char *buf, size_t buflen) +{ + struct sta_info *sta; + u8 addr[ETH_ALEN]; + const u8 *pmk; + int pmk_len; + + if (hwaddr_aton(cmd, addr)) + return -1; + + sta = ap_get_sta(hapd, addr); + if (!sta || !sta->wpa_sm) { + wpa_printf(MSG_DEBUG, "No STA WPA state machine for " MACSTR, + MAC2STR(addr)); + return -1; + } + pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); + if (!pmk) { + wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR, + MAC2STR(addr)); + return -1; + } + + return wpa_snprintf_hex(buf, buflen, pmk, pmk_len); +} + #endif /* CONFIG_TESTING_OPTIONS */ +static int hostapd_ctrl_check_freq_params(struct hostapd_freq_params *params) +{ + switch (params->bandwidth) { + case 0: + /* bandwidth not specified: use 20 MHz by default */ + /* fall-through */ + case 20: + if (params->center_freq1 && + params->center_freq1 != params->freq) + return -1; + + if (params->center_freq2 || params->sec_channel_offset) + return -1; + break; + case 40: + if (params->center_freq2 || !params->sec_channel_offset) + return -1; + + if (!params->center_freq1) + break; + switch (params->sec_channel_offset) { + case 1: + if (params->freq + 10 != params->center_freq1) + return -1; + break; + case -1: + if (params->freq - 10 != params->center_freq1) + return -1; + break; + default: + return -1; + } + break; + case 80: + if (!params->center_freq1 || !params->sec_channel_offset) + return 1; + + switch (params->sec_channel_offset) { + case 1: + if (params->freq - 10 != params->center_freq1 && + params->freq + 30 != params->center_freq1) + return 1; + break; + case -1: + if (params->freq + 10 != params->center_freq1 && + params->freq - 30 != params->center_freq1) + return -1; + break; + default: + return -1; + } + + /* Adjacent and overlapped are not allowed for 80+80 */ + if (params->center_freq2 && + params->center_freq1 - params->center_freq2 <= 80 && + params->center_freq2 - params->center_freq1 <= 80) + return 1; + break; + case 160: + if (!params->center_freq1 || params->center_freq2 || + !params->sec_channel_offset) + return -1; + + switch (params->sec_channel_offset) { + case 1: + if (params->freq + 70 != params->center_freq1 && + params->freq + 30 != params->center_freq1 && + params->freq - 10 != params->center_freq1 && + params->freq - 50 != params->center_freq1) + return -1; + break; + case -1: + if (params->freq + 50 != params->center_freq1 && + params->freq + 10 != params->center_freq1 && + params->freq - 30 != params->center_freq1 && + params->freq - 70 != params->center_freq1) + return -1; + break; + default: + return -1; + } + break; + default: + return -1; + } + + return 0; +} + + static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface, char *pos) { #ifdef NEED_AP_MLME struct csa_settings settings; int ret; + int dfs_range = 0; unsigned int i; + int bandwidth; + u8 chan; ret = hostapd_parse_csa_settings(pos, &settings); if (ret) return ret; + ret = hostapd_ctrl_check_freq_params(&settings.freq_params); + if (ret) { + wpa_printf(MSG_INFO, + "chanswitch: invalid frequency settings provided"); + return ret; + } + + switch (settings.freq_params.bandwidth) { + case 40: + bandwidth = CHAN_WIDTH_40; + break; + case 80: + if (settings.freq_params.center_freq2) + bandwidth = CHAN_WIDTH_80P80; + else + bandwidth = CHAN_WIDTH_80; + break; + case 160: + bandwidth = CHAN_WIDTH_160; + break; + default: + bandwidth = CHAN_WIDTH_20; + break; + } + + if (settings.freq_params.center_freq1) + dfs_range += hostapd_is_dfs_overlap( + iface, bandwidth, settings.freq_params.center_freq1); + else + dfs_range += hostapd_is_dfs_overlap( + iface, bandwidth, settings.freq_params.freq); + + if (settings.freq_params.center_freq2) + dfs_range += hostapd_is_dfs_overlap( + iface, bandwidth, settings.freq_params.center_freq2); + + if (dfs_range) { + ret = ieee80211_freq_to_chan(settings.freq_params.freq, &chan); + if (ret == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_ERROR, + "Failed to get channel for (freq=%d, sec_channel_offset=%d, bw=%d)", + settings.freq_params.freq, + settings.freq_params.sec_channel_offset, + settings.freq_params.bandwidth); + return -1; + } + + settings.freq_params.channel = chan; + + wpa_printf(MSG_DEBUG, + "DFS/CAC to (channel=%u, freq=%d, sec_channel_offset=%d, bw=%d, center_freq1=%d)", + settings.freq_params.channel, + settings.freq_params.freq, + settings.freq_params.sec_channel_offset, + settings.freq_params.bandwidth, + settings.freq_params.center_freq1); + + /* Perform CAC and switch channel */ + hostapd_switch_channel_fallback(iface, &settings.freq_params); + return 0; + } + for (i = 0; i < iface->num_bss; i++) { /* Save CHAN_SWITCH VHT config */ @@ -3232,6 +3453,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strcmp(buf, "REKEY_GTK") == 0) { if (wpa_auth_rekey_gtk(hapd->wpa_auth) < 0) reply_len = -1; + } else if (os_strncmp(buf, "GET_PMK ", 8) == 0) { + reply_len = hostapd_ctrl_get_pmk(hapd, buf + 8, reply, + reply_size); #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) @@ -3348,6 +3572,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) { + res = hostapd_dpp_nfc_handover_req(hapd, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) { + res = hostapd_dpp_nfc_handover_sel(hapd, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) { res = dpp_bootstrap_gen(hapd->iface->interfaces->dpp, buf + 18); if (res < 0) { @@ -3377,6 +3619,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, reply_len = dpp_bootstrap_info(hapd->iface->interfaces->dpp, atoi(buf + 19), reply, reply_size); + } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) { + if (dpp_bootstrap_set(hapd->iface->interfaces->dpp, + atoi(buf + 18), + os_strchr(buf + 18, ' ')) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) { if (hostapd_dpp_auth_init(hapd, buf + 13) < 0) reply_len = -1; @@ -3456,7 +3703,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, int reply_len; int level = MSG_DEBUG; #ifdef CONFIG_CTRL_IFACE_UDP - unsigned char lcookie[COOKIE_LEN]; + unsigned char lcookie[CTRL_IFACE_COOKIE_LEN]; #endif /* CONFIG_CTRL_IFACE_UDP */ res = recvfrom(sock, buf, sizeof(buf) - 1, 0, @@ -3481,28 +3728,30 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx, #ifdef CONFIG_CTRL_IFACE_UDP if (os_strcmp(buf, "GET_COOKIE") == 0) { os_memcpy(reply, "COOKIE=", 7); - wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, - cookie, COOKIE_LEN); - reply_len = 7 + 2 * COOKIE_LEN; + wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1, + hapd->ctrl_iface_cookie, + CTRL_IFACE_COOKIE_LEN); + reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN; goto done; } if (os_strncmp(buf, "COOKIE=", 7) != 0 || - hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) { + hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) { wpa_printf(MSG_DEBUG, "CTRL: No cookie in the request - drop request"); os_free(reply); return; } - if (os_memcmp(cookie, lcookie, COOKIE_LEN) != 0) { + if (os_memcmp(hapd->ctrl_iface_cookie, lcookie, + CTRL_IFACE_COOKIE_LEN) != 0) { wpa_printf(MSG_DEBUG, "CTRL: Invalid cookie in the request - drop request"); os_free(reply); return; } - pos = buf + 7 + 2 * COOKIE_LEN; + pos = buf + 7 + 2 * CTRL_IFACE_COOKIE_LEN; while (*pos == ' ') pos++; #endif /* CONFIG_CTRL_IFACE_UDP */ @@ -3591,7 +3840,7 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd) dl_list_init(&hapd->ctrl_dst); hapd->ctrl_sock = -1; - os_get_random(cookie, COOKIE_LEN); + os_get_random(hapd->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN); #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE hints.ai_flags = AI_PASSIVE; @@ -4170,7 +4419,7 @@ static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces, static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, void *sock_ctx) { - void *interfaces = eloop_ctx; + struct hapd_interfaces *interfaces = eloop_ctx; char buffer[256], *buf = buffer; int res; struct sockaddr_storage from; @@ -4179,7 +4428,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, int reply_len; const int reply_size = 4096; #ifdef CONFIG_CTRL_IFACE_UDP - unsigned char lcookie[COOKIE_LEN]; + unsigned char lcookie[CTRL_IFACE_COOKIE_LEN]; #endif /* CONFIG_CTRL_IFACE_UDP */ res = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, @@ -4208,28 +4457,30 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx, #ifdef CONFIG_CTRL_IFACE_UDP if (os_strcmp(buf, "GET_COOKIE") == 0) { os_memcpy(reply, "COOKIE=", 7); - wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, - gcookie, COOKIE_LEN); - reply_len = 7 + 2 * COOKIE_LEN; + wpa_snprintf_hex(reply + 7, 2 * CTRL_IFACE_COOKIE_LEN + 1, + interfaces->ctrl_iface_cookie, + CTRL_IFACE_COOKIE_LEN); + reply_len = 7 + 2 * CTRL_IFACE_COOKIE_LEN; goto send_reply; } if (os_strncmp(buf, "COOKIE=", 7) != 0 || - hexstr2bin(buf + 7, lcookie, COOKIE_LEN) < 0) { + hexstr2bin(buf + 7, lcookie, CTRL_IFACE_COOKIE_LEN) < 0) { wpa_printf(MSG_DEBUG, "CTRL: No cookie in the request - drop request"); os_free(reply); return; } - if (os_memcmp(gcookie, lcookie, COOKIE_LEN) != 0) { + if (os_memcmp(interfaces->ctrl_iface_cookie, lcookie, + CTRL_IFACE_COOKIE_LEN) != 0) { wpa_printf(MSG_DEBUG, "CTRL: Invalid cookie in the request - drop request"); os_free(reply); return; } - buf += 7 + 2 * COOKIE_LEN; + buf += 7 + 2 * CTRL_IFACE_COOKIE_LEN; while (*buf == ' ') buf++; #endif /* CONFIG_CTRL_IFACE_UDP */ @@ -4373,7 +4624,7 @@ int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface) } } - os_get_random(gcookie, COOKIE_LEN); + os_get_random(interface->ctrl_iface_cookie, CTRL_IFACE_COOKIE_LEN); #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE hints.ai_flags = AI_PASSIVE; @@ -4616,13 +4867,8 @@ static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst, return; idx = 0; if (ifname) { -#ifdef CONFIG_CTRL_IFACE_UDP - io[idx].iov_base = "IFACE="; - io[idx].iov_len = 6; -#else /* CONFIG_CTRL_IFACE_UDP */ io[idx].iov_base = "IFNAME="; io[idx].iov_len = 7; -#endif /* CONFIG_CTRL_IFACE_UDP */ idx++; io[idx].iov_base = (char *) ifname; io[idx].iov_len = os_strlen(ifname); diff --git a/hostapd/defconfig b/hostapd/defconfig index 6e2eaa37..f630a223 100644 --- a/hostapd/defconfig +++ b/hostapd/defconfig @@ -148,9 +148,6 @@ CONFIG_IPV6=y # the IEEE 802.11 Management capability (e.g., FreeBSD/net80211) #CONFIG_DRIVER_RADIUS_ACL=y -# IEEE 802.11n (High Throughput) support -#CONFIG_IEEE80211N=y - # Wireless Network Management (IEEE Std 802.11v-2011) # Note: This is experimental and not complete implementation. #CONFIG_WNM=y @@ -388,3 +385,11 @@ CONFIG_IPV6=y # Override default value for the wpa_disable_eapol_key_retries configuration # parameter. See that parameter in hostapd.conf for more details. #CFLAGS += -DDEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES=1 + +# Wired equivalent privacy (WEP) +# WEP is an obsolete cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used for anything anymore. The +# functionality needed to use WEP is available in the current hostapd +# release under this optional build parameter. This functionality is subject to +# be completely removed in a future release. +#CONFIG_WEP=y diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index 263a04e8..812c09a9 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -72,7 +72,7 @@ ctrl_interface=/var/run/hostapd # run as non-root users. However, since the control interface can be used to # change the network configuration, this access needs to be protected in many # cases. By default, hostapd is configured to use gid 0 (root). If you -# want to allow non-root users to use the contron interface, add a new group +# want to allow non-root users to use the control interface, add a new group # and change this value to match with that group. Add users that should have # control interface access to this group. # @@ -598,8 +598,6 @@ wmm_ac_vo_acm=0 # channels if needed or creation of 40 MHz channel maybe rejected based # on overlapping BSSes. These changes are done automatically when hostapd # is setting up the 40 MHz channel. -# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC] -# (SMPS disabled if neither is set) # HT-greenfield: [GF] (disabled if not set) # Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set) # Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set) @@ -806,6 +804,9 @@ wmm_ac_vo_acm=0 # he_bss_color: BSS color (1-63) #he_bss_color=1 +# he_bss_color_partial: BSS color AID equation +#he_bss_color_partial=0 + #he_default_pe_duration: The duration of PE field in an HE PPDU in us # Possible values are 0 us (default), 4 us, 8 us, 12 us, and 16 us #he_default_pe_duration=0 @@ -903,6 +904,8 @@ eapol_key_index_workaround=0 # EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable # reauthentication). +# Note: Reauthentications may enforce a disconnection, check the related +# parameter wpa_deny_ptk0_rekey for details. #eap_reauth_period=3600 # Use PAE group address (01:80:c2:00:00:03) instead of individual target @@ -1507,6 +1510,17 @@ own_ip_addr=127.0.0.1 # wpa_key_mgmt=SAE for WPA3-Personal instead of wpa_key_mgmt=WPA-PSK). #wpa=2 +# Extended Key ID support for Individually Addressed frames +# +# Extended Key ID allows to rekey PTK keys without the impacts the "normal" +# PTK rekeying with only a single Key ID 0 has. It can only be used when the +# driver supports it and RSN/WPA2 is used with a CCMP/GCMP pairwise cipher. +# +# 0 = force off, i.e., use only Key ID 0 (default) +# 1 = enable and use Extended Key ID support when possible +# 2 = identical to 1 but start with Key ID 1 when possible +#extended_key_id=0 + # WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit # secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase # (8..63 characters) that will be converted to PSK. This conversion uses SSID @@ -1607,8 +1621,26 @@ own_ip_addr=127.0.0.1 # Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of # PTK to mitigate some attacks against TKIP deficiencies. +# Warning: PTK rekeying is buggy with many drivers/devices and with such +# devices, the only secure method to rekey the PTK without Extended Key ID +# support requires a disconnection. Check the related parameter +# wpa_deny_ptk0_rekey for details. #wpa_ptk_rekey=600 +# Workaround for PTK rekey issues +# +# PTK0 rekeys (rekeying the PTK without "Extended Key ID for Individually +# Addressed Frames") can degrade the security and stability with some cards. +# To avoid such issues hostapd can replace those PTK rekeys (including EAP +# reauthentications) with disconnects. +# +# Available options: +# 0 = always rekey when configured/instructed (default) +# 1 = only rekey when the local driver is explicitly indicating it can perform +# this operation without issues +# 2 = never allow PTK0 rekeys +#wpa_deny_ptk0_rekey=0 + # The number of times EAPOL-Key Message 1/4 and Message 3/4 in the RSN 4-Way # Handshake are retried per 4-Way Handshake attempt. # (dot11RSNAConfigPairwiseUpdateCount) @@ -1677,6 +1709,12 @@ own_ip_addr=127.0.0.1 # available in deployed devices. #group_mgmt_cipher=AES-128-CMAC +# Beacon Protection (management frame protection for Beacon frames) +# This depends on management frame protection being enabled (ieee80211w != 0). +# 0 = disabled (default) +# 1 = enabled +#beacon_prot=0 + # Association SA Query maximum timeout (in TU = 1.024 ms; for MFP) # (maximum time to wait for a SA Query response) # dot11AssociationSAQueryMaximumTimeout, 1...4294967295 @@ -1784,11 +1822,13 @@ own_ip_addr=127.0.0.1 #sae_confirm_immediate=0 # SAE mechanism for PWE derivation -# 0 = hunting-and-pecking loop only (default) -# 1 = hash-to-element only +# 0 = hunting-and-pecking loop only (default without password identifier) +# 1 = hash-to-element only (default with password identifier) # 2 = both hunting-and-pecking loop and hash-to-element enabled # Note: The default value is likely to change from 0 to 2 once the new # hash-to-element mechanism has received more interoperability testing. +# When using SAE password identifier, the hash-to-element mechanism is used +# regardless of the sae_pwe parameter value. #sae_pwe=0 # FILS Cache Identifier (16-bit value in hexdump format) @@ -1815,6 +1855,19 @@ own_ip_addr=127.0.0.1 # http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10 #owe_groups=19 20 21 +# OWE PTK derivation workaround +# Initial OWE implementation used SHA256 when deriving the PTK for all OWE +# groups. This was supposed to change to SHA384 for group 20 and SHA512 for +# group 21. This parameter can be used to enable workaround for interoperability +# with stations that use SHA256 with groups 20 and 21. By default (0) only the +# appropriate hash function is accepted. When workaround is enabled (1), the +# appropriate hash function is tried first and if that fails, SHA256-based PTK +# derivation is attempted. This workaround can result in reduced security for +# groups 20 and 21, but is required for interoperability with older +# implementations. There is no impact to group 19 behavior. The workaround is +# disabled by default and can be enabled by uncommenting the following line. +#owe_ptk_workaround=1 + # OWE transition mode configuration # Pointer to the matching open/OWE BSS #owe_transition_bssid=<bssid> @@ -1852,6 +1905,23 @@ own_ip_addr=127.0.0.1 # default: 30 TUs (= 30.72 milliseconds) #fils_hlp_wait_time=30 +# Transition Disable indication +# The AP can notify authenticated stations to disable transition mode in their +# network profiles when the network has completed transition steps, i.e., once +# sufficiently large number of APs in the ESS have been updated to support the +# more secure alternative. When this indication is used, the stations are +# expected to automatically disable transition mode and less secure security +# options. This includes use of WEP, TKIP (including use of TKIP as the group +# cipher), and connections without PMF. +# Bitmap bits: +# bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK and only +# allow SAE to be used) +# bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK) +# bit 2 (0x04): WPA3-Enterprise (move to requiring PMF) +# bit 3 (0x08): Enhanced Open (disable use of open network; require OWE) +# (default: 0 = do not include Transition Disable KDE) +#transition_disable=0x01 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) @@ -2205,6 +2275,13 @@ own_ip_addr=127.0.0.1 #wps_nfc_dh_privkey: Hexdump of DH Private Key #wps_nfc_dev_pw: Hexdump of Device Password +# Application Extension attribute for Beacon and Probe Response frames +# This parameter can be used to add application extension into WPS IE. The +# contents of this parameter starts with 16-octet (32 hexdump characters) of +# UUID to identify the specific application and that is followed by the actual +# application specific data. +#wps_application_ext=<hexdump> + ##### Wi-Fi Direct (P2P) ###################################################### # Enable P2P Device management @@ -2227,6 +2304,17 @@ own_ip_addr=127.0.0.1 #dpp_csign #dpp_controller +# Configurator Connectivity indication +# 0: no Configurator is currently connected (default) +# 1: advertise that a Configurator is available +#dpp_configurator_connectivity=0 + +# DPP PFS +# 0: allow PFS to be used or not used (default) +# 1: require PFS to be used (note: not compatible with DPP R1) +# 2: do not allow PFS to be used +#dpp_pfs=0 + #### TDLS (IEEE 802.11z-2010) ################################################# # Prohibit use of TDLS in this BSS @@ -2607,7 +2695,7 @@ own_ip_addr=127.0.0.1 # Default is 0 = OCE disabled #oce=0 -# RSSI-based assocition rejection +# RSSI-based association rejection # # Reject STA association if RSSI is below given threshold (in dBm) # Allowed range: -60 to -90 dBm; default = 0 (rejection disabled) diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk index 166e59e9..2ce5ff23 100644 --- a/hostapd/hostapd.wpa_psk +++ b/hostapd/hostapd.wpa_psk @@ -7,9 +7,15 @@ # keyid=<keyid_string> # An optional VLAN ID can be specified by prefixing the line with # vlanid=<VLAN ID>. +# An optional WPS tag can be added by prefixing the line with +# wps=<0/1> (default: 0). Any matching entry with that tag will be used when +# generating a PSK for a WPS Enrollee instead of generating a new random +# per-Enrollee PSK. 00:00:00:00:00:00 secret passphrase 00:11:22:33:44:55 another passphrase 00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef keyid=example_id 00:11:22:33:44:77 passphrase with keyid vlanid=3 00:00:00:00:00:00 passphrase with vlanid +wps=1 00:00:00:00:00:00 passphrase for WPS +wps=1 11:22:33:44:55:00 dev-specific passphrase for WPS 00:00:00:00:00:00 another passphrase for all STAs diff --git a/hostapd/main.c b/hostapd/main.c index f08d60ef..85c1fd1c 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -220,7 +220,6 @@ static int hostapd_driver_init(struct hostapd_iface *iface) struct wowlan_triggers *triggs; iface->drv_flags = capa.flags; - iface->smps_modes = capa.smps_modes; iface->probe_resp_offloads = capa.probe_resp_offloads; /* * Use default extended capa values from per-radio information @@ -262,7 +261,7 @@ hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name, struct hostapd_iface *iface; int k; - wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); + wpa_printf(MSG_DEBUG, "Configuration file: %s", config_fname); iface = hostapd_init(interfaces, config_fname); if (!iface) return NULL; @@ -453,11 +452,12 @@ static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, static void show_version(void) { fprintf(stderr, - "hostapd v" VERSION_STR "\n" + "hostapd v%s\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" "Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> " - "and contributors\n"); + "and contributors\n", + VERSION_STR); } @@ -772,7 +772,7 @@ int main(int argc, char *argv[]) if (log_file) wpa_debug_open_file(log_file); - else + if (!log_file && !wpa_debug_syslog) wpa_debug_setup_stdout(); #ifdef CONFIG_DEBUG_SYSLOG if (wpa_debug_syslog) diff --git a/hs20/client/Makefile b/hs20/client/Makefile index 67f6f55c..cc2af03f 100644 --- a/hs20/client/Makefile +++ b/hs20/client/Makefile @@ -30,8 +30,17 @@ CFLAGS += -I../../src ifndef CONFIG_NO_BROWSER ifndef CONFIG_BROWSER_SYSTEM +TEST_WK := $(shell pkg-config --silence-errors --cflags webkitgtk-3.0) +ifeq ($(TEST_WK),) +# Try webkit2 +GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkit2gtk-4.0) +GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkit2gtk-4.0) +CFLAGS += -DUSE_WEBKIT2 +else GTKCFLAGS := $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0) GTKLIBS := $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0) +endif + CFLAGS += $(GTKCFLAGS) LIBS += $(GTKLIBS) endif diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c index d75c8456..bcd68b87 100644 --- a/hs20/client/oma_dm_client.c +++ b/hs20/client/oma_dm_client.c @@ -407,7 +407,7 @@ static int oma_dm_exec_browser(struct hs20_osu_client *ctx, xml_node_t *exec) wpa_printf(MSG_INFO, "Data: %s", data); wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data); write_summary(ctx, "Launch browser to URI '%s'", data); - res = hs20_web_browser(data); + res = hs20_web_browser(data, 1); xml_node_get_text_free(ctx->xml, data); if (res > 0) { wpa_printf(MSG_INFO, "User response in browser completed successfully"); diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c index a94f40c5..11bf0db3 100644 --- a/hs20/client/osu_client.c +++ b/hs20/client/osu_client.c @@ -2233,7 +2233,7 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid, wpa_ctrl_close(mon); if (res < 0) { - wpa_printf(MSG_INFO, "Could not connect"); + wpa_printf(MSG_INFO, "Could not connect to OSU network"); write_summary(ctx, "Could not connect to OSU network"); wpa_printf(MSG_INFO, "Remove OSU network connection"); snprintf(buf, sizeof(buf), "REMOVE_NETWORK %d", id); @@ -2406,7 +2406,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir, snprintf(fname, sizeof(fname), "file://%s/osu-providers.html", dir); write_summary(ctx, "Start web browser with OSU provider selection page"); - ret = hs20_web_browser(fname); + ret = hs20_web_browser(fname, 0); selected: if (ret > 0 && (size_t) ret <= osu_count) { @@ -2907,7 +2907,7 @@ static char * get_hostname(const char *url) static int osu_cert_cb(void *_ctx, struct http_cert *cert) { struct hs20_osu_client *ctx = _ctx; - unsigned int i, j; + size_t i, j; int found; char *host = NULL; @@ -3002,7 +3002,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) size_t name_len = os_strlen(name); wpa_printf(MSG_INFO, - "[%i] Looking for icon file name '%s' match", + "[%zu] Looking for icon file name '%s' match", j, name); for (i = 0; i < cert->num_logo; i++) { struct http_logo *logo = &cert->logo[i]; @@ -3010,7 +3010,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) char *pos; wpa_printf(MSG_INFO, - "[%i] Comparing to '%s' uri_len=%d name_len=%d", + "[%zu] Comparing to '%s' uri_len=%d name_len=%d", i, logo->uri, (int) uri_len, (int) name_len); if (uri_len < 1 + name_len) { wpa_printf(MSG_INFO, "URI Length is too short"); @@ -3044,7 +3044,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) if (logo->hash_len != 32) { wpa_printf(MSG_INFO, - "[%i][%i] Icon hash length invalid (should be 32): %d", + "[%zu][%zu] Icon hash length invalid (should be 32): %d", j, i, (int) logo->hash_len); continue; } @@ -3054,7 +3054,7 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert) } wpa_printf(MSG_DEBUG, - "[%u][%u] Icon hash did not match", j, i); + "[%zu][%zu] Icon hash did not match", j, i); wpa_hexdump_ascii(MSG_DEBUG, "logo->hash", logo->hash, 32); wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]", @@ -3152,7 +3152,7 @@ static void check_workarounds(struct hs20_osu_client *ctx) static void usage(void) { - printf("usage: hs20-osu-client [-dddqqKt] [-S<station ifname>] \\\n" + printf("usage: hs20-osu-client [-dddqqKtT] [-S<station ifname>] \\\n" " [-w<wpa_supplicant ctrl_iface dir>] " "[-r<result file>] [-f<debug file>] \\\n" " [-s<summary file>] \\\n" @@ -3198,7 +3198,7 @@ int main(int argc, char *argv[]) return -1; for (;;) { - c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tw:x:"); + c = getopt(argc, argv, "df:hKNo:O:qr:s:S:tTw:x:"); if (c < 0) break; switch (c) { @@ -3236,6 +3236,9 @@ int main(int argc, char *argv[]) case 't': wpa_debug_timestamp++; break; + case 'T': + ctx.ignore_tls = 1; + break; case 'w': wpas_ctrl_path = optarg; break; @@ -3403,7 +3406,7 @@ int main(int argc, char *argv[]) wpa_printf(MSG_INFO, "Launch web browser to URL %s", argv[optind + 1]); - ret = hs20_web_browser(argv[optind + 1]); + ret = hs20_web_browser(argv[optind + 1], ctx.ignore_tls); wpa_printf(MSG_INFO, "Web browser result: %d", ret); } else if (strcmp(argv[optind], "parse_cert") == 0) { if (argc - optind < 2) { diff --git a/hs20/client/osu_client.h b/hs20/client/osu_client.h index 5c8e6d00..9b45b03f 100644 --- a/hs20/client/osu_client.h +++ b/hs20/client/osu_client.h @@ -50,6 +50,8 @@ struct hs20_osu_client { const char *osu_ssid; /* Enforced OSU_SSID for testing purposes */ #define WORKAROUND_OCSP_OPTIONAL 0x00000001 unsigned long int workarounds; + int ignore_tls; /* whether to ignore TLS validation issues with HTTPS + * server certificate */ }; diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c index c619541a..39d10e03 100644 --- a/hs20/client/spp_client.c +++ b/hs20/client/spp_client.c @@ -547,7 +547,7 @@ static int hs20_spp_exec(struct hs20_osu_client *ctx, xml_node_t *exec, } wpa_printf(MSG_INFO, "Launch browser to URI '%s'", uri); write_summary(ctx, "Launch browser to URI '%s'", uri); - res = hs20_web_browser(uri); + res = hs20_web_browser(uri, 1); xml_node_get_text_free(ctx->xml, uri); if (res > 0) { wpa_printf(MSG_INFO, "User response in browser completed successfully - sessionid='%s'", diff --git a/hs20/server/ca/ocsp-responder.sh b/hs20/server/ca/ocsp-responder.sh index 8cebd745..620947d0 100644 --- a/hs20/server/ca/ocsp-responder.sh +++ b/hs20/server/ca/ocsp-responder.sh @@ -1,3 +1,3 @@ #!/bin/sh -openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text +openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner ocsp.pem -rkey ocsp.key -CA demoCA/cacert.pem -text -ignore_err diff --git a/hs20/server/ca/ocsp-update-cache.sh b/hs20/server/ca/ocsp-update-cache.sh index 8ddef9b9..f2b23250 100644 --- a/hs20/server/ca/ocsp-update-cache.sh +++ b/hs20/server/ca/ocsp-update-cache.sh @@ -1,5 +1,6 @@ #!/bin/sh +# NOTE: You may need to replace 'localhost' with your OCSP server hostname. openssl ocsp \ -no_nonce \ -CAfile ca.pem \ diff --git a/hs20/server/hs20_spp_server.c b/hs20/server/hs20_spp_server.c index 6c74f541..347c40a7 100644 --- a/hs20/server/hs20_spp_server.c +++ b/hs20/server/hs20_spp_server.c @@ -176,7 +176,7 @@ int main(int argc, char *argv[]) ctx.root_dir = optarg; break; case 'v': - printf("hs20_spp_server v" VERSION_STR "\n"); + printf("hs20_spp_server v%s\n", VERSION_STR); return 0; default: usage(); diff --git a/src/ap/acs.c b/src/ap/acs.c index 232afa89..5c016107 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -261,13 +261,13 @@ static void acs_clean_chan_surveys(struct hostapd_channel_data *chan) } -void acs_cleanup(struct hostapd_iface *iface) +static void acs_cleanup_mode(struct hostapd_hw_modes *mode) { int i; struct hostapd_channel_data *chan; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (chan->flag & HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED) acs_clean_chan_surveys(chan); @@ -276,6 +276,15 @@ void acs_cleanup(struct hostapd_iface *iface) chan->flag |= HOSTAPD_CHAN_SURVEY_LIST_INITIALIZED; chan->min_nf = 0; } +} + + +void acs_cleanup(struct hostapd_iface *iface) +{ + int i; + + for (i = 0; i < iface->num_hw_features; i++) + acs_cleanup_mode(&iface->hw_features[i]); iface->chans_surveyed = 0; iface->acs_num_completed_scans = 0; @@ -453,21 +462,35 @@ static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan) } -static int acs_surveys_are_sufficient(struct hostapd_iface *iface) +static int acs_surveys_are_sufficient_mode(struct hostapd_hw_modes *mode) { int i; struct hostapd_channel_data *chan; - int valid = 0; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && acs_survey_list_is_sufficient(chan)) - valid++; + return 1; + } + + return 0; +} + + +static int acs_surveys_are_sufficient(struct hostapd_iface *iface) +{ + int i; + struct hostapd_hw_modes *mode; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + if (!hostapd_hw_skip_mode(iface, mode) && + acs_surveys_are_sufficient_mode(mode)) + return 1; } - /* We need at least survey data for one channel */ - return !!valid; + return 0; } @@ -489,14 +512,14 @@ static int is_in_chanlist(struct hostapd_iface *iface, } -static void acs_survey_all_chans_intereference_factor( - struct hostapd_iface *iface) +static void acs_survey_mode_interference_factor( + struct hostapd_iface *iface, struct hostapd_hw_modes *mode) { int i; struct hostapd_channel_data *chan; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (!acs_usable_chan(chan)) continue; @@ -515,14 +538,28 @@ static void acs_survey_all_chans_intereference_factor( } -static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, - int freq) +static void acs_survey_all_chans_interference_factor( + struct hostapd_iface *iface) +{ + int i; + struct hostapd_hw_modes *mode; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + if (!hostapd_hw_skip_mode(iface, mode)) + acs_survey_mode_interference_factor(iface, mode); + } +} + + +static struct hostapd_channel_data * +acs_find_chan_mode(struct hostapd_hw_modes *mode, int freq) { struct hostapd_channel_data *chan; int i; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; if (chan->flag & HOSTAPD_CHAN_DISABLED) continue; @@ -535,6 +572,26 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, } +static struct hostapd_channel_data * +acs_find_chan(struct hostapd_iface *iface, int freq) +{ + int i; + struct hostapd_hw_modes *mode; + struct hostapd_channel_data *chan; + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + if (!hostapd_hw_skip_mode(iface, mode)) { + chan = acs_find_chan_mode(mode, freq); + if (chan) + return chan; + } + } + + return NULL; +} + + static int is_24ghz_mode(enum hostapd_hw_mode mode) { return mode == HOSTAPD_MODE_IEEE80211B || @@ -565,58 +622,24 @@ static int is_common_24ghz_chan(int chan) #define ACS_24GHZ_PREFER_1_6_11 0.8 #endif /* ACS_24GHZ_PREFER_1_6_11 */ -/* - * At this point it's assumed chan->interface_factor has been computed. - * This function should be reusable regardless of interference computation - * option (survey, BSS, spectral, ...). chan->interference factor must be - * summable (i.e., must be always greater than zero). - */ -static struct hostapd_channel_data * -acs_find_ideal_chan(struct hostapd_iface *iface) +static void +acs_find_ideal_chan_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode, + int n_chans, u32 bw, + struct hostapd_channel_data **rand_chan, + struct hostapd_channel_data **ideal_chan, + long double *ideal_factor) { - struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL, - *rand_chan = NULL; - long double factor, ideal_factor = 0; + struct hostapd_channel_data *chan, *adj_chan = NULL; + long double factor; int i, j; - int n_chans = 1; - u32 bw; unsigned int k; - /* TODO: HT40- support */ - - if (iface->conf->ieee80211n && - iface->conf->secondary_channel == -1) { - wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); - return NULL; - } - - if (iface->conf->ieee80211n && - iface->conf->secondary_channel) - n_chans = 2; - - if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { - switch (hostapd_get_oper_chwidth(iface->conf)) { - case CHANWIDTH_80MHZ: - n_chans = 4; - break; - case CHANWIDTH_160MHZ: - n_chans = 8; - break; - } - } - - bw = num_chan_to_bw(n_chans); - - /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */ - - wpa_printf(MSG_DEBUG, - "ACS: Survey analysis for selected bandwidth %d MHz", bw); - - for (i = 0; i < iface->current_mode->num_channels; i++) { + for (i = 0; i < mode->num_channels; i++) { double total_weight; struct acs_bias *bias, tmp_bias; - chan = &iface->current_mode->channels[i]; + chan = &mode->channels[i]; /* Since in the current ACS implementation the first channel is * always a primary channel, skip channels not available as @@ -637,7 +660,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) /* HT40 on 5 GHz has a limited set of primary channels as per * 11n Annex J */ - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && + if (mode->mode == HOSTAPD_MODE_IEEE80211A && iface->conf->ieee80211n && iface->conf->secondary_channel && !acs_usable_ht40_chan(chan)) { @@ -646,7 +669,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) continue; } - if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && + if (mode->mode == HOSTAPD_MODE_IEEE80211A && (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) { if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80MHZ && @@ -698,7 +721,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent * channel interference factor. */ - if (is_24ghz_mode(iface->current_mode->mode)) { + if (is_24ghz_mode(mode->mode)) { for (j = 0; j < n_chans; j++) { adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 5); @@ -744,7 +767,7 @@ acs_find_ideal_chan(struct hostapd_iface *iface) break; bias = NULL; } - } else if (is_24ghz_mode(iface->current_mode->mode) && + } else if (is_24ghz_mode(mode->mode) && is_common_24ghz_chan(chan->chan)) { tmp_bias.channel = chan->chan; tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11; @@ -763,14 +786,71 @@ acs_find_ideal_chan(struct hostapd_iface *iface) } if (acs_usable_chan(chan) && - (!ideal_chan || factor < ideal_factor)) { - ideal_factor = factor; - ideal_chan = chan; + (!*ideal_chan || factor < *ideal_factor)) { + *ideal_factor = factor; + *ideal_chan = chan; } /* This channel would at least be usable */ - if (!rand_chan) - rand_chan = chan; + if (!(*rand_chan)) + *rand_chan = chan; + } +} + + +/* + * At this point it's assumed chan->interference_factor has been computed. + * This function should be reusable regardless of interference computation + * option (survey, BSS, spectral, ...). chan->interference factor must be + * summable (i.e., must be always greater than zero). + */ +static struct hostapd_channel_data * +acs_find_ideal_chan(struct hostapd_iface *iface) +{ + struct hostapd_channel_data *ideal_chan = NULL, + *rand_chan = NULL; + long double ideal_factor = 0; + int i; + int n_chans = 1; + u32 bw; + struct hostapd_hw_modes *mode; + + /* TODO: HT40- support */ + + if (iface->conf->ieee80211n && + iface->conf->secondary_channel == -1) { + wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); + return NULL; + } + + if (iface->conf->ieee80211n && + iface->conf->secondary_channel) + n_chans = 2; + + if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) { + switch (hostapd_get_oper_chwidth(iface->conf)) { + case CHANWIDTH_80MHZ: + n_chans = 4; + break; + case CHANWIDTH_160MHZ: + n_chans = 8; + break; + } + } + + bw = num_chan_to_bw(n_chans); + + /* TODO: VHT/HE80+80. Update acs_adjust_center_freq() too. */ + + wpa_printf(MSG_DEBUG, + "ACS: Survey analysis for selected bandwidth %d MHz", bw); + + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + if (!hostapd_hw_skip_mode(iface, mode)) + acs_find_ideal_chan_mode(iface, mode, n_chans, bw, + &rand_chan, &ideal_chan, + &ideal_factor); } if (ideal_chan) { @@ -826,7 +906,7 @@ static int acs_study_survey_based(struct hostapd_iface *iface) return -1; } - acs_survey_all_chans_intereference_factor(iface); + acs_survey_all_chans_interference_factor(iface); return 0; } @@ -918,29 +998,56 @@ fail: } +static int * acs_request_scan_add_freqs(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode, + int *freq) +{ + struct hostapd_channel_data *chan; + int i; + + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; + if (chan->flag & HOSTAPD_CHAN_DISABLED) + continue; + + if (!is_in_chanlist(iface, chan)) + continue; + + *freq++ = chan->freq; + } + + return freq; +} + + static int acs_request_scan(struct hostapd_iface *iface) { struct wpa_driver_scan_params params; - struct hostapd_channel_data *chan; int i, *freq; + int num_channels; + struct hostapd_hw_modes *mode; os_memset(¶ms, 0, sizeof(params)); - params.freqs = os_calloc(iface->current_mode->num_channels + 1, - sizeof(params.freqs[0])); + + num_channels = 0; + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + if (!hostapd_hw_skip_mode(iface, mode)) + num_channels += mode->num_channels; + } + + params.freqs = os_calloc(num_channels + 1, sizeof(params.freqs[0])); if (params.freqs == NULL) return -1; freq = params.freqs; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if (chan->flag & HOSTAPD_CHAN_DISABLED) - continue; - if (!is_in_chanlist(iface, chan)) - continue; - - *freq++ = chan->freq; + for (i = 0; i < iface->num_hw_features; i++) { + mode = &iface->hw_features[i]; + if (!hostapd_hw_skip_mode(iface, mode)) + freq = acs_request_scan_add_freqs(iface, mode, freq); } + *freq = 0; if (params.freqs == freq) { @@ -978,7 +1085,8 @@ enum hostapd_chan_status acs_init(struct hostapd_iface *iface) return HOSTAPD_CHAN_ACS; } - if (!iface->current_mode) + if (!iface->current_mode && + iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY) return HOSTAPD_CHAN_INVALID; acs_cleanup(iface); diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 68af3c1d..5bf4502b 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -54,16 +54,21 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->logger_syslog = (unsigned int) -1; bss->logger_stdout = (unsigned int) -1; +#ifdef CONFIG_WEP bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED; bss->wep_rekeying_period = 300; /* use key0 in individual key and key1 in broadcast key */ bss->broadcast_key_idx_min = 1; bss->broadcast_key_idx_max = 2; +#else /* CONFIG_WEP */ + bss->auth_algs = WPA_AUTH_ALG_OPEN; +#endif /* CONFIG_WEP */ bss->eap_reauth_period = 3600; bss->wpa_group_rekey = 600; bss->wpa_gmk_rekey = 86400; + bss->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS; bss->wpa_group_update_count = 4; bss->wpa_pairwise_update_count = 4; bss->wpa_disable_eapol_key_retries = @@ -251,6 +256,9 @@ struct hostapd_config * hostapd_config_defaults(void) HE_OPERATION_RTS_THRESHOLD_OFFSET; /* Set default basic MCS/NSS set to single stream MCS 0-7 */ conf->he_op.he_basic_mcs_nss_set = 0xfffc; + conf->he_op.he_bss_color_disabled = 1; + conf->he_op.he_bss_color_partial = 0; + conf->he_op.he_bss_color = 1; #endif /* CONFIG_IEEE80211AX */ /* The third octet of the country string uses an ASCII space character @@ -301,6 +309,7 @@ static int hostapd_config_read_wpa_psk(const char *fname, while (fgets(buf, sizeof(buf), f)) { int vlan_id = 0; + int wps = 0; line++; @@ -331,6 +340,8 @@ static int hostapd_config_read_wpa_psk(const char *fname, value = ""; if (!os_strcmp(name, "keyid")) { keyid = value; + } else if (!os_strcmp(name, "wps")) { + wps = atoi(value); } else if (!os_strcmp(name, "vlanid")) { vlan_id = atoi(value); } else { @@ -348,8 +359,9 @@ static int hostapd_config_read_wpa_psk(const char *fname, if (!token) token = ""; if (hwaddr_aton(token, addr)) { - wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on " - "line %d in '%s'", token, line, fname); + wpa_printf(MSG_ERROR, + "Invalid MAC address '%s' on line %d in '%s'", + token, line, fname); ret = -1; break; } @@ -377,16 +389,17 @@ static int hostapd_config_read_wpa_psk(const char *fname, ok = 0; len = os_strlen(pos); - if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0) + if (len == 2 * PMK_LEN && + hexstr2bin(pos, psk->psk, PMK_LEN) == 0) ok = 1; - else if (len >= 8 && len < 64) { - pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len, - 4096, psk->psk, PMK_LEN); + else if (len >= 8 && len < 64 && + pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len, + 4096, psk->psk, PMK_LEN) == 0) ok = 1; - } if (!ok) { - wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in " - "'%s'", pos, line, fname); + wpa_printf(MSG_ERROR, + "Invalid PSK '%s' on line %d in '%s'", + pos, line, fname); os_free(psk); ret = -1; break; @@ -404,6 +417,8 @@ static int hostapd_config_read_wpa_psk(const char *fname, } } + psk->wps = wps; + psk->next = ssid->wpa_psk; ssid->wpa_psk = psk; } @@ -441,7 +456,9 @@ int hostapd_setup_sae_pt(struct hostapd_bss_config *conf) struct hostapd_ssid *ssid = &conf->ssid; struct sae_password_entry *pw; - if (conf->sae_pwe == 0 || !wpa_key_mgmt_sae(conf->wpa_key_mgmt)) + if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf)) || + conf->sae_pwe == 3 || + !wpa_key_mgmt_sae(conf->wpa_key_mgmt)) return 0; /* PT not needed */ sae_deinit_pt(ssid->pt); @@ -623,6 +640,7 @@ void hostapd_config_free_eap_users(struct hostapd_eap_user *user) } +#ifdef CONFIG_WEP static void hostapd_config_free_wep(struct hostapd_wep_keys *keys) { int i; @@ -631,6 +649,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys) keys->key[i] = NULL; } } +#endif /* CONFIG_WEP */ void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l) @@ -719,7 +738,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) str_clear_free(conf->ssid.wpa_passphrase); os_free(conf->ssid.wpa_psk_file); +#ifdef CONFIG_WEP hostapd_config_free_wep(&conf->ssid.wep); +#endif /* CONFIG_WEP */ #ifdef CONFIG_FULL_DYNAMIC_VLAN os_free(conf->ssid.vlan_tagged_interface); #endif /* CONFIG_FULL_DYNAMIC_VLAN */ @@ -813,6 +834,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) os_free(conf->upc); for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) wpabuf_free(conf->wps_vendor_ext[i]); + wpabuf_free(conf->wps_application_ext); wpabuf_free(conf->wps_nfc_dh_pubkey); wpabuf_free(conf->wps_nfc_dh_privkey); wpabuf_free(conf->wps_nfc_dev_pw); @@ -880,7 +902,12 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) #ifdef CONFIG_TESTING_OPTIONS wpabuf_free(conf->own_ie_override); wpabuf_free(conf->sae_commit_override); + wpabuf_free(conf->rsne_override_eapol); wpabuf_free(conf->rsnxe_override_eapol); + wpabuf_free(conf->rsne_override_ft); + wpabuf_free(conf->rsnxe_override_ft); + wpabuf_free(conf->gtk_rsc_override); + wpabuf_free(conf->igtk_rsc_override); #endif /* CONFIG_TESTING_OPTIONS */ os_free(conf->no_probe_resp_if_seen_on); @@ -1090,6 +1117,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, return -1; } +#ifdef CONFIG_WEP if (bss->wpa) { int wep, i; @@ -1107,6 +1135,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, return -1; } } +#endif /* CONFIG_WEP */ if (full_config && bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED && @@ -1154,7 +1183,6 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, } #endif /* CONFIG_IEEE80211R_AP */ -#ifdef CONFIG_IEEE80211N if (full_config && conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) { bss->disable_11n = 1; @@ -1162,12 +1190,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, "allowed, disabling HT capabilities"); } +#ifdef CONFIG_WEP if (full_config && conf->ieee80211n && bss->ssid.security_policy == SECURITY_STATIC_WEP) { bss->disable_11n = 1; wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not " "allowed, disabling HT capabilities"); } +#endif /* CONFIG_WEP */ if (full_config && conf->ieee80211n && bss->wpa && !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && @@ -1179,15 +1209,16 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, "requires CCMP/GCMP to be enabled, disabling HT " "capabilities"); } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC +#ifdef CONFIG_WEP if (full_config && conf->ieee80211ac && bss->ssid.security_policy == SECURITY_STATIC_WEP) { bss->disable_11ac = 1; wpa_printf(MSG_ERROR, "VHT (IEEE 802.11ac) with WEP is not allowed, disabling VHT capabilities"); } +#endif /* CONFIG_WEP */ if (full_config && conf->ieee80211ac && bss->wpa && !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && @@ -1207,12 +1238,14 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, bss->wps_state = 0; } +#ifdef CONFIG_WEP if (full_config && bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) { wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be " "disabled"); bss->wps_state = 0; } +#endif /* CONFIG_WEP */ if (full_config && bss->wps_state && bss->wpa && (!(bss->wpa & 2) || @@ -1336,11 +1369,13 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config) void hostapd_set_security_params(struct hostapd_bss_config *bss, int full_config) { +#ifdef CONFIG_WEP if (bss->individual_wep_key_len == 0) { /* individual keys are not use; can use key idx0 for * broadcast keys */ bss->broadcast_key_idx_min = 0; } +#endif /* CONFIG_WEP */ if ((bss->wpa & 2) && bss->rsn_pairwise == 0) bss->rsn_pairwise = bss->wpa_pairwise; @@ -1366,6 +1401,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss, } else if (bss->ieee802_1x) { int cipher = WPA_CIPHER_NONE; bss->ssid.security_policy = SECURITY_IEEE_802_1X; +#ifdef CONFIG_WEP bss->ssid.wep.default_len = bss->default_wep_key_len; if (full_config && bss->default_wep_key_len) { cipher = bss->default_wep_key_len >= 13 ? @@ -1376,11 +1412,13 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss, else cipher = WPA_CIPHER_WEP40; } +#endif /* CONFIG_WEP */ bss->wpa_group = cipher; bss->wpa_pairwise = cipher; bss->rsn_pairwise = cipher; if (full_config) bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA; +#ifdef CONFIG_WEP } else if (bss->ssid.wep.keys_set) { int cipher = WPA_CIPHER_WEP40; if (bss->ssid.wep.len[0] >= 13) @@ -1391,6 +1429,7 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss, bss->rsn_pairwise = cipher; if (full_config) bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE; +#endif /* CONFIG_WEP */ } else if (bss->osen) { bss->ssid.security_policy = SECURITY_OSEN; bss->wpa_group = WPA_CIPHER_CCMP; diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 83b8aee6..2a0bf076 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -67,6 +67,7 @@ struct hostapd_radius_servers; struct ft_remote_r0kh; struct ft_remote_r1kh; +#ifdef CONFIG_WEP #define NUM_WEP_KEYS 4 struct hostapd_wep_keys { u8 idx; @@ -75,10 +76,13 @@ struct hostapd_wep_keys { int keys_set; size_t default_len; /* key length used for dynamic key generation */ }; +#endif /* CONFIG_WEP */ typedef enum hostap_security_policy { SECURITY_PLAINTEXT = 0, +#ifdef CONFIG_WEP SECURITY_STATIC_WEP = 1, +#endif /* CONFIG_WEP */ SECURITY_IEEE_802_1X = 2, SECURITY_WPA_PSK = 3, SECURITY_WPA = 4, @@ -88,6 +92,7 @@ typedef enum hostap_security_policy { struct hostapd_ssid { u8 ssid[SSID_MAX_LEN]; size_t ssid_len; + u32 short_ssid; unsigned int ssid_set:1; unsigned int utf8_ssid:1; unsigned int wpa_passphrase_set:1; @@ -101,7 +106,9 @@ struct hostapd_ssid { char *wpa_psk_file; struct sae_pt *pt; +#ifdef CONFIG_WEP struct hostapd_wep_keys wep; +#endif /* CONFIG_WEP */ #define DYNAMIC_VLAN_DISABLED 0 #define DYNAMIC_VLAN_OPTIONAL 1 @@ -151,6 +158,7 @@ struct hostapd_wpa_psk { struct hostapd_wpa_psk *next; int group; char keyid[KEYID_LEN]; + int wps; u8 psk[PMK_LEN]; u8 addr[ETH_ALEN]; u8 p2p_dev_addr[ETH_ALEN]; @@ -319,10 +327,12 @@ struct hostapd_bss_config { size_t eap_req_id_text_len; int eapol_key_index_workaround; +#ifdef CONFIG_WEP size_t default_wep_key_len; int individual_wep_key_len; int wep_rekeying_period; int broadcast_key_idx_min, broadcast_key_idx_max; +#endif /* CONFIG_WEP */ int eap_reauth_period; int erp_send_reauth_start; char *erp_domain; @@ -344,9 +354,11 @@ struct hostapd_bss_config { * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */ int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */ + int extended_key_id; int wpa_key_mgmt; enum mfp_options ieee80211w; int group_mgmt_cipher; + int beacon_prot; /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ unsigned int assoc_sa_query_max_timeout; /* dot11AssociationSAQueryRetryTimeout (in TUs) */ @@ -367,6 +379,7 @@ struct hostapd_bss_config { int wpa_strict_rekey; int wpa_gmk_rekey; int wpa_ptk_rekey; + enum ptk0_rekey_handling wpa_deny_ptk0_rekey; u32 wpa_group_update_count; u32 wpa_pairwise_update_count; int wpa_disable_eapol_key_retries; @@ -497,6 +510,7 @@ struct hostapd_bss_config { char *model_url; char *upc; struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; + struct wpabuf *wps_application_ext; int wps_nfc_pw_from_config; int wps_nfc_dev_pw_id; struct wpabuf *wps_nfc_dh_pubkey; @@ -664,7 +678,14 @@ struct hostapd_bss_config { struct wpabuf *own_ie_override; int sae_reflection_attack; struct wpabuf *sae_commit_override; + struct wpabuf *rsne_override_eapol; struct wpabuf *rsnxe_override_eapol; + struct wpabuf *rsne_override_ft; + struct wpabuf *rsnxe_override_ft; + struct wpabuf *gtk_rsc_override; + struct wpabuf *igtk_rsc_override; + int no_beacon_rsnxe; + int skip_prune_assoc; #endif /* CONFIG_TESTING_OPTIONS */ #define MESH_ENABLED BIT(0) @@ -720,6 +741,8 @@ struct hostapd_bss_config { struct wpabuf *dpp_csign; #ifdef CONFIG_DPP2 struct dpp_controller_conf *dpp_controller; + int dpp_configurator_connectivity; + int dpp_pfs; #endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ @@ -729,12 +752,15 @@ struct hostapd_bss_config { size_t owe_transition_ssid_len; char owe_transition_ifname[IFNAMSIZ + 1]; int *owe_groups; + int owe_ptk_workaround; #endif /* CONFIG_OWE */ int coloc_intf_reporting; u8 send_probe_response; + u8 transition_disable; + #define BACKHAUL_BSS 1 #define FRONTHAUL_BSS 2 int multi_ap; /* bitmap of BACKHAUL_BSS, FRONTHAUL_BSS */ @@ -848,6 +874,8 @@ struct he_phy_capabilities_info { */ struct he_operation { u8 he_bss_color; + u8 he_bss_color_disabled; + u8 he_bss_color_partial; u8 he_default_pe_duration; u8 he_twt_required; u16 he_rts_threshold; diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 75858668..1f284f0f 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -588,7 +588,7 @@ int hostapd_set_frag(struct hostapd_data *hapd, int frag) int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, int total_flags, int flags_or, int flags_and) { - if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL) + if (!hapd->driver || !hapd->drv_priv || !hapd->driver->sta_set_flags) return 0; return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags, flags_or, flags_and); @@ -680,36 +680,41 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, + int key_idx, int vlan_id, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) + const u8 *key, size_t key_len, enum key_flag key_flag) { + struct wpa_driver_set_key_params params; + if (hapd->driver == NULL || hapd->driver->set_key == NULL) return 0; - return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr, - key_idx, set_tx, seq, seq_len, key, - key_len); -} + os_memset(¶ms, 0, sizeof(params)); + params.ifname = ifname; + params.alg = alg; + params.addr = addr; + params.key_idx = key_idx; + params.set_tx = set_tx; + params.seq = seq; + params.seq_len = seq_len; + params.key = key; + params.key_len = key_len; + params.vlan_id = vlan_id; + params.key_flag = key_flag; -int hostapd_drv_send_mlme(struct hostapd_data *hapd, - const void *msg, size_t len, int noack) -{ - if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv) - return 0; - return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, - NULL, 0); + return hapd->driver->set_key(hapd->drv_priv, ¶ms); } -int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd, - const void *msg, size_t len, int noack, - const u16 *csa_offs, size_t csa_offs_len) +int hostapd_drv_send_mlme(struct hostapd_data *hapd, + const void *msg, size_t len, int noack, + const u16 *csa_offs, size_t csa_offs_len, + int no_encrypt) { - if (hapd->driver == NULL || hapd->driver->send_mlme == NULL) + if (!hapd->driver || !hapd->driver->send_mlme || !hapd->drv_priv) return 0; return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0, - csa_offs, csa_offs_len); + csa_offs, csa_offs_len, no_encrypt, 0); } @@ -933,6 +938,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) } params.freq_list = freq_list; + params.edmg_enabled = hapd->iface->conf->enable_edmg; params.ht_enabled = !!(hapd->iface->conf->ieee80211n); params.ht40_enabled = !!(hapd->iface->conf->ht_capab & diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index fa413df0..56d1ad86 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -89,14 +89,13 @@ int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start, int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd, enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, + int key_idx, int vlan_id, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len); + const u8 *key, size_t key_len, enum key_flag key_flag); int hostapd_drv_send_mlme(struct hostapd_data *hapd, - const void *msg, size_t len, int noack); -int hostapd_drv_send_mlme_csa(struct hostapd_data *hapd, - const void *msg, size_t len, int noack, - const u16 *csa_offs, size_t csa_offs_len); + const void *msg, size_t len, int noack, + const u16 *csa_offs, size_t csa_offs_len, + int no_encrypt); int hostapd_drv_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason); int hostapd_drv_sta_disassoc(struct hostapd_data *hapd, diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c index 8bf6ddec..20be7f8f 100644 --- a/src/ap/ap_list.c +++ b/src/ap/ap_list.c @@ -228,7 +228,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface, set_beacon++; } -#ifdef CONFIG_IEEE80211N if (!iface->olbc_ht && !ap->ht_support && (ap->channel == 0 || ap->channel == iface->conf->channel || @@ -241,7 +240,6 @@ void ap_list_process_beacon(struct hostapd_iface *iface, MAC2STR(ap->addr), ap->channel); set_beacon++; } -#endif /* CONFIG_IEEE80211N */ if (set_beacon) ieee802_11_update_beacons(iface); @@ -285,14 +283,12 @@ void ap_list_timer(struct hostapd_iface *iface) iface->olbc = 0; set_beacon++; } -#ifdef CONFIG_IEEE80211N if (!olbc_ht && iface->olbc_ht) { wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore"); iface->olbc_ht = 0; hostapd_ht_operation_update(iface); set_beacon++; } -#endif /* CONFIG_IEEE80211N */ } if (set_beacon) diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 331c09bc..47ced9a1 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -36,27 +36,6 @@ #ifdef NEED_AP_MLME -static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid, - size_t len) -{ - size_t i; - - for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) { - if (hapd->conf->radio_measurements[i]) - break; - } - - if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN) - return eid; - - *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES; - *eid++ = RRM_CAPABILITIES_IE_LEN; - os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN); - - return eid + RRM_CAPABILITIES_IE_LEN; -} - - static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len) { if (len < 2 + 5) @@ -287,17 +266,101 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, } -static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len) +static const u8 * hostapd_wpa_ie(struct hostapd_data *hapd, u8 eid) +{ + const u8 *ies; + size_t ies_len; + + ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len); + if (!ies) + return NULL; + + return get_ie(ies, ies_len, eid); +} + + +static const u8 * hostapd_vendor_wpa_ie(struct hostapd_data *hapd, + u32 vendor_type) +{ + const u8 *ies; + size_t ies_len; + + ies = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ies_len); + if (!ies) + return NULL; + + return get_vendor_ie(ies, ies_len, vendor_type); +} + + +static u8 * hostapd_get_rsne(struct hostapd_data *hapd, u8 *pos, size_t len) { const u8 *ie; - size_t ielen; - ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen); - if (ie == NULL || ielen > len) - return eid; + ie = hostapd_wpa_ie(hapd, WLAN_EID_RSN); + if (!ie || 2U + ie[1] > len) + return pos; + + os_memcpy(pos, ie, 2 + ie[1]); + return pos + 2 + ie[1]; +} + + +static u8 * hostapd_get_mde(struct hostapd_data *hapd, u8 *pos, size_t len) +{ + const u8 *ie; + + ie = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN); + if (!ie || 2U + ie[1] > len) + return pos; + + os_memcpy(pos, ie, 2 + ie[1]); + return pos + 2 + ie[1]; +} + + +static u8 * hostapd_get_rsnxe(struct hostapd_data *hapd, u8 *pos, size_t len) +{ + const u8 *ie; + +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->no_beacon_rsnxe) { + wpa_printf(MSG_INFO, "TESTING: Do not add RSNXE into Beacon"); + return pos; + } +#endif /* CONFIG_TESTING_OPTIONS */ + ie = hostapd_wpa_ie(hapd, WLAN_EID_RSNX); + if (!ie || 2U + ie[1] > len) + return pos; + + os_memcpy(pos, ie, 2 + ie[1]); + return pos + 2 + ie[1]; +} + + +static u8 * hostapd_get_wpa_ie(struct hostapd_data *hapd, u8 *pos, size_t len) +{ + const u8 *ie; - os_memcpy(eid, ie, ielen); - return eid + ielen; + ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE); + if (!ie || 2U + ie[1] > len) + return pos; + + os_memcpy(pos, ie, 2 + ie[1]); + return pos + 2 + ie[1]; +} + + +static u8 * hostapd_get_osen_ie(struct hostapd_data *hapd, u8 *pos, size_t len) +{ + const u8 *ie; + + ie = hostapd_vendor_wpa_ie(hapd, OSEN_IE_VENDOR_TYPE); + if (!ie || 2U + ie[1] > len) + return pos; + + os_memcpy(pos, ie, 2 + ie[1]); + return pos + 2 + ie[1]; } @@ -405,6 +468,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, buflen += hostapd_mbo_ie_len(hapd); buflen += hostapd_eid_owe_trans_len(hapd); + buflen += hostapd_eid_dpp_cc_len(hapd); resp = os_zalloc(buflen); if (resp == NULL) @@ -455,14 +519,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, /* Extended supported rates */ pos = hostapd_eid_ext_supp_rates(hapd, pos); - /* RSN, MDIE */ - if (!(hapd->conf->wpa == WPA_PROTO_WPA || - (hapd->conf->osen && !hapd->conf->wpa))) - pos = hostapd_eid_wpa(hapd, pos, epos - pos); - + pos = hostapd_get_rsne(hapd, pos, epos - pos); pos = hostapd_eid_bss_load(hapd, pos, epos - pos); - pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos); + pos = hostapd_get_mde(hapd, pos, epos - pos); /* eCSA IE */ csa_pos = hostapd_eid_ecsa(hapd, pos); @@ -471,15 +531,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = csa_pos; pos = hostapd_eid_supported_op_classes(hapd, pos); - -#ifdef CONFIG_IEEE80211N - /* Secondary Channel Offset element */ - /* TODO: The standard doesn't specify a position for this element. */ - pos = hostapd_eid_secondary_channel(hapd, pos); - pos = hostapd_eid_ht_capabilities(hapd, pos); pos = hostapd_eid_ht_operation(hapd, pos); -#endif /* CONFIG_IEEE80211N */ pos = hostapd_eid_ext_capab(hapd, pos); @@ -509,13 +562,14 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #endif /* CONFIG_IEEE80211AC */ pos = hostapd_eid_fils_indic(hapd, pos, 0); + pos = hostapd_get_rsnxe(hapd, pos, epos - pos); #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax) { pos = hostapd_eid_he_capab(hapd, pos, IEEE80211_MODE_AP); pos = hostapd_eid_he_operation(hapd, pos); - pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos); pos = hostapd_eid_spatial_reuse(hapd, pos); + pos = hostapd_eid_he_mu_edca_parameter_set(hapd, pos); } #endif /* CONFIG_IEEE80211AX */ @@ -524,10 +578,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_vendor_vht(hapd, pos); #endif /* CONFIG_IEEE80211AC */ - /* WPA */ - if (hapd->conf->wpa == WPA_PROTO_WPA || - (hapd->conf->osen && !hapd->conf->wpa)) - pos = hostapd_eid_wpa(hapd, pos, epos - pos); + /* WPA / OSEN */ + pos = hostapd_get_wpa_ie(hapd, pos, epos - pos); + pos = hostapd_get_osen_ie(hapd, pos, epos - pos); /* Wi-Fi Alliance WMM */ pos = hostapd_eid_wmm(hapd, pos); @@ -560,6 +613,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos); pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos); + pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos); if (hapd->conf->vendor_elements) { os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements), @@ -581,7 +635,9 @@ enum ssid_match_result { static enum ssid_match_result ssid_match(struct hostapd_data *hapd, const u8 *ssid, size_t ssid_len, const u8 *ssid_list, - size_t ssid_list_len) + size_t ssid_list_len, + const u8 *short_ssid_list, + size_t short_ssid_list_len) { const u8 *pos, *end; int wildcard = 0; @@ -592,20 +648,30 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd, os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0) return EXACT_SSID_MATCH; - if (ssid_list == NULL) - return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; + if (ssid_list) { + pos = ssid_list; + end = ssid_list + ssid_list_len; + while (end - pos >= 2) { + if (2 + pos[1] > end - pos) + break; + if (pos[1] == 0) + wildcard = 1; + if (pos[1] == hapd->conf->ssid.ssid_len && + os_memcmp(pos + 2, hapd->conf->ssid.ssid, + pos[1]) == 0) + return EXACT_SSID_MATCH; + pos += 2 + pos[1]; + } + } - pos = ssid_list; - end = ssid_list + ssid_list_len; - while (end - pos >= 2) { - if (2 + pos[1] > end - pos) - break; - if (pos[1] == 0) - wildcard = 1; - if (pos[1] == hapd->conf->ssid.ssid_len && - os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0) - return EXACT_SSID_MATCH; - pos += 2 + pos[1]; + if (short_ssid_list) { + pos = short_ssid_list; + end = short_ssid_list + short_ssid_list_len; + while (end - pos >= 4) { + if (hapd->conf->ssid.short_ssid == WPA_GET_LE32(pos)) + return EXACT_SSID_MATCH; + pos += 4; + } } return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH; @@ -743,11 +809,7 @@ void handle_probe_req(struct hostapd_data *hapd, int ret; u16 csa_offs[2]; size_t csa_offs_len; - u32 session_timeout, acct_interim_interval; - struct vlan_description vlan_id; - struct hostapd_sta_wpa_psk_short *psk = NULL; - char *identity = NULL; - char *radius_cui = NULL; + struct radius_sta rad_info; if (len < IEEE80211_HDRLEN) return; @@ -756,10 +818,8 @@ void handle_probe_req(struct hostapd_data *hapd, sta_track_add(hapd->iface, mgmt->sa, ssi_signal); ie_len = len - IEEE80211_HDRLEN; - ret = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len, - &session_timeout, - &acct_interim_interval, &vlan_id, - &psk, &identity, &radius_cui, 1); + ret = hostapd_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len, + &rad_info, 1); if (ret == HOSTAPD_ACL_REJECT) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Ignore Probe Request frame from " MACSTR @@ -838,7 +898,7 @@ void handle_probe_req(struct hostapd_data *hapd, #endif /* CONFIG_P2P */ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 && - elems.ssid_list_len == 0) { + elems.ssid_list_len == 0 && elems.short_ssid_list_len == 0) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " "broadcast SSID ignored", MAC2STR(mgmt->sa)); return; @@ -870,7 +930,8 @@ void handle_probe_req(struct hostapd_data *hapd, #endif /* CONFIG_TAXONOMY */ res = ssid_match(hapd, elems.ssid, elems.ssid_len, - elems.ssid_list, elems.ssid_list_len); + elems.ssid_list, elems.ssid_list_len, + elems.short_ssid_list, elems.short_ssid_list_len); if (res == NO_SSID_MATCH) { if (!(mgmt->da[0] & 0x01)) { wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR @@ -883,6 +944,12 @@ void handle_probe_req(struct hostapd_data *hapd, return; } + if (hapd->conf->ignore_broadcast_ssid && res == WILDCARD_SSID_MATCH) { + wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for " + "broadcast SSID ignored", MAC2STR(mgmt->sa)); + return; + } + #ifdef CONFIG_INTERWORKING if (hapd->conf->interworking && elems.interworking && elems.interworking_len >= 1) { @@ -987,9 +1054,9 @@ void handle_probe_req(struct hostapd_data *hapd, hapd->cs_c_off_ecsa_proberesp; } - ret = hostapd_drv_send_mlme_csa(hapd, resp, resp_len, noack, - csa_offs_len ? csa_offs : NULL, - csa_offs_len); + ret = hostapd_drv_send_mlme(hapd, resp, resp_len, noack, + csa_offs_len ? csa_offs : NULL, + csa_offs_len, 0); if (ret < 0) wpa_printf(MSG_INFO, "handle_probe_req: send failed"); @@ -1060,7 +1127,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, size_t resp_len = 0; #ifdef NEED_AP_MLME u16 capab_info; - u8 *pos, *tailpos, *csa_pos; + u8 *pos, *tailpos, *tailend, *csa_pos; #define BEACON_HEAD_BUF_SIZE 256 #define BEACON_TAIL_BUF_SIZE 512 @@ -1099,6 +1166,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tail_len += hostapd_mbo_ie_len(hapd); tail_len += hostapd_eid_owe_trans_len(hapd); + tail_len += hostapd_eid_dpp_cc_len(hapd); tailpos = tail = os_malloc(tail_len); if (head == NULL || tail == NULL) { @@ -1107,6 +1175,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, os_free(tail); return -1; } + tailend = tail + tail_len; head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_BEACON); @@ -1147,8 +1216,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, head_len = pos - (u8 *) head; - tailpos = hostapd_eid_country(hapd, tailpos, - tail + BEACON_TAIL_BUF_SIZE - tailpos); + tailpos = hostapd_eid_country(hapd, tailpos, tailend - tailpos); /* Power Constraint element */ tailpos = hostapd_eid_pwr_constraint(hapd, tailpos); @@ -1165,19 +1233,11 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, /* Extended supported rates */ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos); - /* RSN, MDIE */ - if (!(hapd->conf->wpa == WPA_PROTO_WPA || - (hapd->conf->osen && !hapd->conf->wpa))) - tailpos = hostapd_eid_wpa(hapd, tailpos, - tail + BEACON_TAIL_BUF_SIZE - - tailpos); - + tailpos = hostapd_get_rsne(hapd, tailpos, tailend - tailpos); + tailpos = hostapd_eid_bss_load(hapd, tailpos, tailend - tailpos); tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos, - tail + BEACON_TAIL_BUF_SIZE - - tailpos); - - tailpos = hostapd_eid_bss_load(hapd, tailpos, - tail + BEACON_TAIL_BUF_SIZE - tailpos); + tailend - tailpos); + tailpos = hostapd_get_mde(hapd, tailpos, tailend - tailpos); /* eCSA IE */ csa_pos = hostapd_eid_ecsa(hapd, tailpos); @@ -1186,15 +1246,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = csa_pos; tailpos = hostapd_eid_supported_op_classes(hapd, tailpos); - -#ifdef CONFIG_IEEE80211N - /* Secondary Channel Offset element */ - /* TODO: The standard doesn't specify a position for this element. */ - tailpos = hostapd_eid_secondary_channel(hapd, tailpos); - tailpos = hostapd_eid_ht_capabilities(hapd, tailpos); tailpos = hostapd_eid_ht_operation(hapd, tailpos); -#endif /* CONFIG_IEEE80211N */ tailpos = hostapd_eid_ext_capab(hapd, tailpos); @@ -1226,14 +1279,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #endif /* CONFIG_IEEE80211AC */ tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0); + tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos); #ifdef CONFIG_IEEE80211AX if (hapd->iconf->ieee80211ax) { tailpos = hostapd_eid_he_capab(hapd, tailpos, IEEE80211_MODE_AP); tailpos = hostapd_eid_he_operation(hapd, tailpos); - tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos); tailpos = hostapd_eid_spatial_reuse(hapd, tailpos); + tailpos = hostapd_eid_he_mu_edca_parameter_set(hapd, tailpos); } #endif /* CONFIG_IEEE80211AX */ @@ -1242,12 +1296,9 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_vendor_vht(hapd, tailpos); #endif /* CONFIG_IEEE80211AC */ - /* WPA */ - if (hapd->conf->wpa == WPA_PROTO_WPA || - (hapd->conf->osen && !hapd->conf->wpa)) - tailpos = hostapd_eid_wpa(hapd, tailpos, - tail + BEACON_TAIL_BUF_SIZE - - tailpos); + /* WPA / OSEN */ + tailpos = hostapd_get_wpa_ie(hapd, tailpos, tailend - tailpos); + tailpos = hostapd_get_osen_ie(hapd, tailpos, tailend - tailpos); /* Wi-Fi Alliance WMM */ tailpos = hostapd_eid_wmm(hapd, tailpos); @@ -1280,6 +1331,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_mbo(hapd, tailpos, tail + tail_len - tailpos); tailpos = hostapd_eid_owe_trans(hapd, tailpos, tail + tail_len - tailpos); + tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos); if (hapd->conf->vendor_elements) { os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements), @@ -1318,10 +1370,13 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, params->key_mgmt_suites = hapd->conf->wpa_key_mgmt; params->auth_algs = hapd->conf->auth_algs; params->wpa_version = hapd->conf->wpa; - params->privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa || + params->privacy = hapd->conf->wpa; +#ifdef CONFIG_WEP + params->privacy |= hapd->conf->ssid.wep.keys_set || (hapd->conf->ieee802_1x && (hapd->conf->default_wep_key_len || hapd->conf->individual_wep_key_len)); +#endif /* CONFIG_WEP */ switch (hapd->conf->ignore_broadcast_ssid) { case 0: params->hide_ssid = NO_SSID_HIDING; @@ -1334,7 +1389,6 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, break; } params->isolate = hapd->conf->isolate; - params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK; #ifdef NEED_AP_MLME params->cts_protect = !!(ieee802_11_erp_info(hapd) & ERP_INFO_USE_PROTECTION); @@ -1430,6 +1484,13 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) hapd->iface->conf->spr.srg_obss_pd_min_offset; params.he_spr_srg_obss_pd_max_offset = hapd->iface->conf->spr.srg_obss_pd_max_offset; + params.he_bss_color_disabled = + hapd->iface->conf->he_op.he_bss_color_disabled; + params.he_bss_color_partial = + hapd->iface->conf->he_op.he_bss_color_partial; + params.he_bss_color = hapd->iface->conf->he_op.he_bss_color; + params.twt_responder = hostapd_get_he_twt_responder(hapd, + IEEE80211_MODE_AP); #endif /* CONFIG_IEEE80211AX */ hapd->reenable_beacon = 0; diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 9fd1b81a..ef53a825 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -345,7 +345,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, } #endif /* CONFIG_IEEE80211AC */ -#ifdef CONFIG_IEEE80211N if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities) { res = os_snprintf(buf + len, buflen - len, "ht_caps_info=0x%04x\n", @@ -354,7 +353,6 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, if (!os_snprintf_error(buflen - len, res)) len += res; } -#endif /* CONFIG_IEEE80211N */ if (sta->ext_capability && buflen - len > (unsigned) (11 + 2 * sta->ext_capability[0])) { @@ -462,9 +460,6 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, int ret; u8 *pos; - if (!hapd->drv_priv || !hapd->driver->send_frame) - return -1; - mgmt = os_zalloc(sizeof(*mgmt) + 100); if (mgmt == NULL) return -1; @@ -498,8 +493,8 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, pos += 2; *pos++ = minor_reason_code; - ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt, - pos - (u8 *) mgmt, 1); + ret = hostapd_drv_send_mlme(hapd, mgmt, pos - (u8 *) mgmt, 0, NULL, 0, + 0); os_free(mgmt); return ret < 0 ? -1 : 0; @@ -529,8 +524,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, if (pos) { struct ieee80211_mgmt mgmt; int encrypt; - if (!hapd->drv_priv || !hapd->driver->send_frame) - return -1; + pos += 6; encrypt = atoi(pos); os_memset(&mgmt, 0, sizeof(mgmt)); @@ -540,10 +534,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); - if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, - IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), - encrypt) < 0) + if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt, + IEEE80211_HDRLEN + + sizeof(mgmt.u.deauth), + 0, NULL, 0, !encrypt) < 0) return -1; return 0; } @@ -592,8 +586,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, if (pos) { struct ieee80211_mgmt mgmt; int encrypt; - if (!hapd->drv_priv || !hapd->driver->send_frame) - return -1; + pos += 6; encrypt = atoi(pos); os_memset(&mgmt, 0, sizeof(mgmt)); @@ -603,10 +596,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); - if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, - IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), - encrypt) < 0) + if (hostapd_drv_send_mlme(hapd, (u8 *) &mgmt, + IEEE80211_HDRLEN + + sizeof(mgmt.u.deauth), + 0, NULL, 0, !encrypt) < 0) return -1; return 0; } diff --git a/src/ap/dfs.c b/src/ap/dfs.c index f70ecc94..3c078b9c 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -144,30 +144,44 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode, int i; u32 bw = num_chan_to_bw(num_chans); - if (first_chan_idx + num_chans > mode->num_channels) + if (first_chan_idx + num_chans > mode->num_channels) { + wpa_printf(MSG_DEBUG, + "DFS: some channels in range not defined"); return 0; + } first_chan = &mode->channels[first_chan_idx]; /* hostapd DFS implementation assumes the first channel as primary. * If it's not allowed to use the first channel as primary, decline the * whole channel range. */ - if (!chan_pri_allowed(first_chan)) + if (!chan_pri_allowed(first_chan)) { + wpa_printf(MSG_DEBUG, "DFS: primary chanenl not allowed"); return 0; + } for (i = 0; i < num_chans; i++) { chan = dfs_get_chan_data(mode, first_chan->freq + i * 20, first_chan_idx); - if (!chan) + if (!chan) { + wpa_printf(MSG_DEBUG, "DFS: no channel data for %d", + first_chan->freq + i * 20); return 0; + } /* HT 40 MHz secondary channel availability checked only for * primary channel */ - if (!chan_bw_allowed(chan, bw, 1, !i)) + if (!chan_bw_allowed(chan, bw, 1, !i)) { + wpa_printf(MSG_DEBUG, "DFS: bw now allowed for %d", + first_chan->freq + i * 20); return 0; + } - if (!dfs_channel_available(chan, skip_radar)) + if (!dfs_channel_available(chan, skip_radar)) { + wpa_printf(MSG_DEBUG, "DFS: channel not available %d", + first_chan->freq + i * 20); return 0; + } } return 1; @@ -210,22 +224,36 @@ static int dfs_find_channel(struct hostapd_iface *iface, if (iface->conf->ieee80211n && iface->conf->secondary_channel && (!dfs_is_chan_allowed(chan, n_chans) || - !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) + !(chan->allowed_bw & HOSTAPD_CHAN_WIDTH_40P))) { + wpa_printf(MSG_DEBUG, + "DFS: channel %d (%d) is incompatible", + chan->freq, chan->chan); continue; + } /* Skip incompatible chandefs */ - if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) + if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) { + wpa_printf(MSG_DEBUG, + "DFS: range not available for %d (%d)", + chan->freq, chan->chan); continue; + } - if (!is_in_chanlist(iface, chan)) + if (!is_in_chanlist(iface, chan)) { + wpa_printf(MSG_DEBUG, + "DFS: channel %d (%d) not in chanlist", + chan->freq, chan->chan); continue; + } if (ret_chan && idx == channel_idx) { - wpa_printf(MSG_DEBUG, "Selected ch. #%d", chan->chan); + wpa_printf(MSG_DEBUG, "Selected channel %d (%d)", + chan->freq, chan->chan); *ret_chan = chan; return idx; } - wpa_printf(MSG_DEBUG, "Adding channel: %d", chan->chan); + wpa_printf(MSG_DEBUG, "Adding channel %d (%d)", + chan->freq, chan->chan); channel_idx++; } return channel_idx; @@ -235,6 +263,7 @@ static int dfs_find_channel(struct hostapd_iface *iface, static void dfs_adjust_center_freq(struct hostapd_iface *iface, struct hostapd_channel_data *chan, int secondary_channel, + int sec_chan_idx_80p80, u8 *oper_centr_freq_seg0_idx, u8 *oper_centr_freq_seg1_idx) { @@ -261,8 +290,14 @@ static void dfs_adjust_center_freq(struct hostapd_iface *iface, case CHANWIDTH_160MHZ: *oper_centr_freq_seg0_idx = chan->chan + 14; break; + case CHANWIDTH_80P80MHZ: + *oper_centr_freq_seg0_idx = chan->chan + 6; + *oper_centr_freq_seg1_idx = sec_chan_idx_80p80 + 6; + break; + default: - wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now"); + wpa_printf(MSG_INFO, + "DFS: Unsupported channel width configuration"); *oper_centr_freq_seg0_idx = 0; break; } @@ -441,8 +476,11 @@ dfs_get_valid_channel(struct hostapd_iface *iface, { struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan = NULL; + struct hostapd_channel_data *chan2 = NULL; int num_available_chandefs; - int chan_idx; + int chan_idx, chan_idx2; + int sec_chan_idx_80p80 = -1; + int i; u32 _rand; wpa_printf(MSG_DEBUG, "DFS: Selecting random channel"); @@ -459,6 +497,8 @@ dfs_get_valid_channel(struct hostapd_iface *iface, /* Get the count first */ num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar); + wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d", + num_available_chandefs); if (num_available_chandefs == 0) return NULL; @@ -466,6 +506,12 @@ dfs_get_valid_channel(struct hostapd_iface *iface, return NULL; chan_idx = _rand % num_available_chandefs; dfs_find_channel(iface, &chan, chan_idx, skip_radar); + if (!chan) { + wpa_printf(MSG_DEBUG, "DFS: no random channel found"); + return NULL; + } + wpa_printf(MSG_DEBUG, "DFS: got random channel %d (%d)", + chan->freq, chan->chan); /* dfs_find_channel() calculations assume HT40+ */ if (iface->conf->secondary_channel) @@ -473,8 +519,45 @@ dfs_get_valid_channel(struct hostapd_iface *iface, else *secondary_channel = 0; + /* Get secondary channel for HT80P80 */ + if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_80P80MHZ) { + if (num_available_chandefs <= 1) { + wpa_printf(MSG_ERROR, + "only 1 valid chan, can't support 80+80"); + return NULL; + } + + /* + * Loop all channels except channel1 to find a valid channel2 + * that is not adjacent to channel1. + */ + for (i = 0; i < num_available_chandefs - 1; i++) { + /* start from chan_idx + 1, end when chan_idx - 1 */ + chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs; + dfs_find_channel(iface, &chan2, chan_idx2, skip_radar); + if (chan2 && abs(chan2->chan - chan->chan) > 12) { + /* two channels are not adjacent */ + sec_chan_idx_80p80 = chan2->chan; + wpa_printf(MSG_DEBUG, + "DFS: got second chan: %d (%d)", + chan2->freq, chan2->chan); + break; + } + } + + /* Check if we got a valid secondary channel which is not + * adjacent to the first channel. + */ + if (sec_chan_idx_80p80 == -1) { + wpa_printf(MSG_INFO, + "DFS: failed to get chan2 for 80+80"); + return NULL; + } + } + dfs_adjust_center_freq(iface, chan, *secondary_channel, + sec_chan_idx_80p80, oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx); @@ -773,7 +856,7 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) } -static int hostapd_config_dfs_chan_available(struct hostapd_iface *iface) +int hostapd_is_dfs_chan_available(struct hostapd_iface *iface) { int n_chans, n_chans1, start_chan_idx, start_chan_idx1; @@ -821,7 +904,7 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, * another radio. */ if (iface->state != HAPD_IFACE_ENABLED && - hostapd_config_dfs_chan_available(iface)) { + hostapd_is_dfs_chan_available(iface)) { hostapd_setup_interface_complete(iface, 0); iface->cac_started = 0; } @@ -851,6 +934,41 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq, } +static struct hostapd_channel_data * +dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, + u8 *oper_centr_freq_seg0_idx, + u8 *oper_centr_freq_seg1_idx, int *skip_radar) +{ + struct hostapd_channel_data *channel; + + for (;;) { + channel = dfs_get_valid_channel(iface, secondary_channel, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, + *skip_radar); + if (channel) { + wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d", + channel->chan); + return channel; + } + + if (*skip_radar) { + *skip_radar = 0; + } else { + if (iface->conf->vht_oper_chwidth == CHANWIDTH_USE_HT) + break; + *skip_radar = 1; + iface->conf->vht_oper_chwidth--; + } + } + + wpa_printf(MSG_INFO, + "%s: no DFS channels left, waiting for NOP to finish", + __func__); + return NULL; +} + + static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; @@ -868,8 +986,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) skip_radar); if (!channel) { - wpa_printf(MSG_ERROR, "No valid channel available"); - return err; + channel = dfs_downgrade_bandwidth(iface, &secondary_channel, + &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + &skip_radar); + if (!channel) { + wpa_printf(MSG_ERROR, "No valid channel available"); + return err; + } } wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", @@ -898,11 +1022,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) int secondary_channel; u8 oper_centr_freq_seg0_idx; u8 oper_centr_freq_seg1_idx; + u8 new_vht_oper_chwidth; int skip_radar = 1; struct csa_settings csa_settings; unsigned int i; int err = 1; struct hostapd_hw_modes *cmode = iface->current_mode; + u8 current_vht_oper_chwidth = iface->conf->vht_oper_chwidth; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", @@ -936,28 +1062,25 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) * requires to perform a CAC first. */ skip_radar = 0; - channel = dfs_get_valid_channel(iface, &secondary_channel, - &oper_centr_freq_seg0_idx, - &oper_centr_freq_seg1_idx, - skip_radar); - if (!channel) { - wpa_printf(MSG_INFO, - "%s: no DFS channels left, waiting for NOP to finish", - __func__); + channel = dfs_downgrade_bandwidth(iface, &secondary_channel, + &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + &skip_radar); + if (!channel) return err; + if (!skip_radar) { + iface->freq = channel->freq; + iface->conf->channel = channel->chan; + iface->conf->secondary_channel = secondary_channel; + hostapd_set_oper_centr_freq_seg0_idx( + iface->conf, oper_centr_freq_seg0_idx); + hostapd_set_oper_centr_freq_seg1_idx( + iface->conf, oper_centr_freq_seg1_idx); + + hostapd_disable_iface(iface); + hostapd_enable_iface(iface); + return 0; } - - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = secondary_channel; - hostapd_set_oper_centr_freq_seg0_idx(iface->conf, - oper_centr_freq_seg0_idx); - hostapd_set_oper_centr_freq_seg1_idx(iface->conf, - oper_centr_freq_seg1_idx); - - hostapd_disable_iface(iface); - hostapd_enable_iface(iface); - return 0; } wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", @@ -966,6 +1089,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) "freq=%d chan=%d sec_chan=%d", channel->freq, channel->chan, secondary_channel); + new_vht_oper_chwidth = iface->conf->vht_oper_chwidth; + iface->conf->vht_oper_chwidth = current_vht_oper_chwidth; + /* Setup CSA request */ os_memset(&csa_settings, 0, sizeof(csa_settings)); csa_settings.cs_count = 5; @@ -980,7 +1106,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) iface->conf->ieee80211ac, iface->conf->ieee80211ax, secondary_channel, - hostapd_get_oper_chwidth(iface->conf), + new_vht_oper_chwidth, oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx, cmode->vht_capab, @@ -1004,6 +1130,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) iface->freq = channel->freq; iface->conf->channel = channel->chan; iface->conf->secondary_channel = secondary_channel; + iface->conf->vht_oper_chwidth = new_vht_oper_chwidth; hostapd_set_oper_centr_freq_seg0_idx(iface->conf, oper_centr_freq_seg0_idx); hostapd_set_oper_centr_freq_seg1_idx(iface->conf, @@ -1040,8 +1167,10 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, return 0; /* mark radar frequency as invalid */ - set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, - cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); + res = set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, + cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); + if (!res) + return 0; /* Skip if reported radar event not overlapped our channels */ res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); @@ -1161,3 +1290,56 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface) __func__, iface->freq); return 2; } + + +int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width, + int center_freq) +{ + struct hostapd_channel_data *chan; + struct hostapd_hw_modes *mode = iface->current_mode; + int half_width; + int res = 0; + int i; + + if (!iface->conf->ieee80211h || !mode || + mode->mode != HOSTAPD_MODE_IEEE80211A) + return 0; + + switch (width) { + case CHAN_WIDTH_20_NOHT: + case CHAN_WIDTH_20: + half_width = 10; + break; + case CHAN_WIDTH_40: + half_width = 20; + break; + case CHAN_WIDTH_80: + case CHAN_WIDTH_80P80: + half_width = 40; + break; + case CHAN_WIDTH_160: + half_width = 80; + break; + default: + wpa_printf(MSG_WARNING, "DFS chanwidth %d not supported", + width); + return 0; + } + + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; + + if (!(chan->flag & HOSTAPD_CHAN_RADAR)) + continue; + + if (center_freq - chan->freq < half_width && + chan->freq - center_freq < half_width) + res++; + } + + wpa_printf(MSG_DEBUG, "DFS: (%d, %d): in range: %s", + center_freq - half_width, center_freq + half_width, + res ? "yes" : "no"); + + return res; +} diff --git a/src/ap/dfs.h b/src/ap/dfs.h index f0fa6f68..606c1b39 100644 --- a/src/ap/dfs.h +++ b/src/ap/dfs.h @@ -25,9 +25,12 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2); int hostapd_is_dfs_required(struct hostapd_iface *iface); +int hostapd_is_dfs_chan_available(struct hostapd_iface *iface); int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2); int hostapd_handle_dfs_offload(struct hostapd_iface *iface); +int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width, + int center_freq); #endif /* DFS_H */ diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c index ed37fc8f..edc77da2 100644 --- a/src/ap/dhcp_snoop.c +++ b/src/ap/dhcp_snoop.c @@ -39,22 +39,22 @@ static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf, const u8 *end, *pos; int res, msgtype = 0, prefixlen = 32; u32 subnet_mask = 0; - u16 tot_len; + u16 ip_len; exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten)); if (exten_len < 4) return; b = (const struct bootp_pkt *) &buf[ETH_HLEN]; - tot_len = ntohs(b->iph.tot_len); - if (tot_len > (unsigned int) (len - ETH_HLEN)) + ip_len = ntohs(b->iph.ip_len); + if (ip_len > (unsigned int) (len - ETH_HLEN)) return; if (WPA_GET_BE32(b->exten) != DHCP_MAGIC) return; /* Parse DHCP options */ - end = (const u8 *) b + tot_len; + end = (const u8 *) b + ip_len; pos = &b->exten[4]; while (pos < end && *pos != DHCP_OPT_END) { const u8 *opt = pos++; diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 1a3a815c..c86f01ba 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -1,7 +1,7 @@ /* * hostapd / DPP integration * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -81,6 +81,71 @@ int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd) } +int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Request"); + return -1; + } + + if (dpp_nfc_update_bi(own_bi, peer_bi) < 0) + return -1; + + return peer_bi->id; +} + + +int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(hapd->iface->interfaces->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(hapd->iface->interfaces->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Select"); + return -1; + } + + if (peer_bi->curve != own_bi->curve) { + wpa_printf(MSG_INFO, + "DPP: Peer (NFC Handover Selector) used different curve"); + return -1; + } + + return peer_bi->id; +} + + static void hostapd_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx) { @@ -478,15 +543,15 @@ int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd) dpp_auth_deinit(hapd->dpp_auth); } - hapd->dpp_auth = dpp_auth_init(hapd->msg_ctx, peer_bi, own_bi, + hapd->dpp_auth = dpp_auth_init(hapd->iface->interfaces->dpp, + hapd->msg_ctx, peer_bi, own_bi, allowed_roles, neg_freq, hapd->iface->hw_features, hapd->iface->num_hw_features); if (!hapd->dpp_auth) goto fail; hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); - if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, - hapd->dpp_auth, cmd) < 0) { + if (dpp_set_configurator(hapd->dpp_auth, cmd) < 0) { dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; goto fail; @@ -598,7 +663,8 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, } hapd->dpp_auth_ok_on_ack = 0; - hapd->dpp_auth = dpp_auth_req_rx(hapd->msg_ctx, hapd->dpp_allowed_roles, + hapd->dpp_auth = dpp_auth_req_rx(hapd->iface->interfaces->dpp, + hapd->msg_ctx, hapd->dpp_allowed_roles, hapd->dpp_qr_mutual, peer_bi, own_bi, freq, hdr, buf, len); if (!hapd->dpp_auth) { @@ -606,8 +672,7 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src, return; } hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); - if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, - hapd->dpp_auth, + if (dpp_set_configurator(hapd->dpp_auth, hapd->dpp_configurator_params) < 0) { dpp_auth_deinit(hapd->dpp_auth); hapd->dpp_auth = NULL; @@ -643,7 +708,8 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd, * message. */ wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s", conf->connector); - } else if (conf->passphrase[0]) { + } + if (conf->passphrase[0]) { char hex[64 * 2 + 1]; wpa_snprintf_hex(hex, sizeof(hex), @@ -697,6 +763,33 @@ static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd, } +static int hostapd_dpp_handle_key_pkg(struct hostapd_data *hapd, + struct dpp_asymmetric_key *key) +{ +#ifdef CONFIG_DPP2 + int res; + + if (!key) + return 0; + + wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup"); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED); + + while (key) { + res = dpp_configurator_from_backup( + hapd->iface->interfaces->dpp, key); + if (res < 0) + return -1; + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d", + res); + key = key->next; + } +#endif /* CONFIG_DPP2 */ + + return 0; +} + + static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_ap_result result, const struct wpabuf *adv_proto, @@ -741,6 +834,9 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, } hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]); + if (hostapd_dpp_handle_key_pkg(hapd, auth->conf_key_pkg) < 0) + goto fail; + status = DPP_STATUS_OK; #ifdef CONFIG_TESTING_OPTIONS if (dpp_test == DPP_TEST_REJECT_CONFIG) { @@ -1037,6 +1133,70 @@ static void hostapd_dpp_rx_conn_status_result(struct hostapd_data *hapd, } +static void +hostapd_dpp_rx_presence_announcement(struct hostapd_data *hapd, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + const u8 *r_bootstrap; + u16 r_bootstrap_len; + struct dpp_bootstrap_info *peer_bi; + struct dpp_authentication *auth; + + wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR, + MAC2STR(src)); + + r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, + &r_bootstrap_len); + if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL + "Missing or invalid required Responder Bootstrapping Key Hash attribute"); + return; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", + r_bootstrap, r_bootstrap_len); + peer_bi = dpp_bootstrap_find_chirp(hapd->iface->interfaces->dpp, + r_bootstrap); + if (!peer_bi) { + if (dpp_relay_rx_action(hapd->iface->interfaces->dpp, + src, hdr, buf, len, freq, NULL, + r_bootstrap) == 0) + return; + wpa_printf(MSG_DEBUG, + "DPP: No matching bootstrapping information found"); + return; + } + + if (hapd->dpp_auth) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore Presence Announcement during ongoing Authentication"); + return; + } + + auth = dpp_auth_init(hapd->iface->interfaces->dpp, hapd->msg_ctx, + peer_bi, NULL, DPP_CAPAB_CONFIGURATOR, freq, NULL, + 0); + if (!auth) + return; + hostapd_dpp_set_testing_options(hapd, hapd->dpp_auth); + if (dpp_set_configurator(hapd->dpp_auth, + hapd->dpp_configurator_params) < 0) { + dpp_auth_deinit(auth); + return; + } + + auth->neg_freq = freq; + + if (!is_zero_ether_addr(peer_bi->mac_addr)) + os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN); + + hapd->dpp_auth = auth; + if (hostapd_dpp_auth_init_next(hapd) < 0) { + dpp_auth_deinit(hapd->dpp_auth); + hapd->dpp_auth = NULL; + } +} + #endif /* CONFIG_DPP2 */ @@ -1486,6 +1646,10 @@ void hostapd_dpp_rx_action(struct hostapd_data *hapd, const u8 *src, case DPP_PA_CONNECTION_STATUS_RESULT: hostapd_dpp_rx_conn_status_result(hapd, src, hdr, buf, len); break; + case DPP_PA_PRESENCE_ANNOUNCEMENT: + hostapd_dpp_rx_presence_announcement(hapd, src, hdr, buf, len, + freq); + break; #endif /* CONFIG_DPP2 */ default: wpa_printf(MSG_DEBUG, @@ -1580,14 +1744,13 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd) int ret = -1; char *curve = NULL; - auth = os_zalloc(sizeof(*auth)); + auth = dpp_alloc_auth(hapd->iface->interfaces->dpp, hapd->msg_ctx); if (!auth) return -1; curve = get_param(cmd, " curve="); hostapd_dpp_set_testing_options(hapd, auth); - if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx, - auth, cmd) == 0 && + if (dpp_set_configurator(auth, cmd) == 0 && dpp_configurator_own_config(auth, curve, 1) == 0) { hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]); ret = 0; diff --git a/src/ap/dpp_hostapd.h b/src/ap/dpp_hostapd.h index e151c2fc..b1fa99ed 100644 --- a/src/ap/dpp_hostapd.h +++ b/src/ap/dpp_hostapd.h @@ -1,7 +1,7 @@ /* * hostapd / DPP integration * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -12,6 +12,8 @@ int hostapd_dpp_qr_code(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_nfc_uri(struct hostapd_data *hapd, const char *cmd); +int hostapd_dpp_nfc_handover_req(struct hostapd_data *hapd, const char *cmd); +int hostapd_dpp_nfc_handover_sel(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_auth_init(struct hostapd_data *hapd, const char *cmd); int hostapd_dpp_listen(struct hostapd_data *hapd, const char *cmd); void hostapd_dpp_listen_stop(struct hostapd_data *hapd); diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index 8a4b0ef6..559bb87c 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -109,7 +109,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, const u8 *req_ies, size_t req_ies_len, int reassoc) { struct sta_info *sta; - int new_assoc, res; + int new_assoc; + enum wpa_validate_result res; struct ieee802_11_elems elems; const u8 *ie; size_t ielen; @@ -220,7 +221,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } #endif /* CONFIG_P2P */ -#ifdef CONFIG_IEEE80211N #ifdef NEED_AP_MLME if (elems.ht_capabilities && (hapd->iface->conf->ht_capab & @@ -234,7 +234,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, ht40_intolerant_add(hapd->iface, sta); } #endif /* NEED_AP_MLME */ -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_INTERWORKING if (elems.ext_capab && elems.ext_capab_len > 4) { @@ -325,33 +324,67 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, elems.rsnxe ? elems.rsnxe_len + 2 : 0, elems.mdie, elems.mdie_len, elems.owe_dh, elems.owe_dh_len); - if (res != WPA_IE_OK) { + reason = WLAN_REASON_INVALID_IE; + status = WLAN_STATUS_INVALID_IE; + switch (res) { + case WPA_IE_OK: + reason = WLAN_REASON_UNSPECIFIED; + status = WLAN_STATUS_SUCCESS; + break; + case WPA_INVALID_IE: + reason = WLAN_REASON_INVALID_IE; + status = WLAN_STATUS_INVALID_IE; + break; + case WPA_INVALID_GROUP: + reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; + status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; + break; + case WPA_INVALID_PAIRWISE: + reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; + status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; + break; + case WPA_INVALID_AKMP: + reason = WLAN_REASON_AKMP_NOT_VALID; + status = WLAN_STATUS_AKMP_NOT_VALID; + break; + case WPA_NOT_ENABLED: + reason = WLAN_REASON_INVALID_IE; + status = WLAN_STATUS_INVALID_IE; + break; + case WPA_ALLOC_FAIL: + reason = WLAN_REASON_UNSPECIFIED; + status = WLAN_STATUS_UNSPECIFIED_FAILURE; + break; + case WPA_MGMT_FRAME_PROTECTION_VIOLATION: + reason = WLAN_REASON_INVALID_IE; + status = WLAN_STATUS_INVALID_IE; + break; + case WPA_INVALID_MGMT_GROUP_CIPHER: + reason = WLAN_REASON_CIPHER_SUITE_REJECTED; + status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; + break; + case WPA_INVALID_MDIE: + reason = WLAN_REASON_INVALID_MDE; + status = WLAN_STATUS_INVALID_MDIE; + break; + case WPA_INVALID_PROTO: + reason = WLAN_REASON_INVALID_IE; + status = WLAN_STATUS_INVALID_IE; + break; + case WPA_INVALID_PMKID: + reason = WLAN_REASON_INVALID_PMKID; + status = WLAN_STATUS_INVALID_PMKID; + break; + case WPA_DENIED_OTHER_REASON: + reason = WLAN_REASON_UNSPECIFIED; + status = WLAN_STATUS_ASSOC_DENIED_UNSPEC; + break; + } + if (status != WLAN_STATUS_SUCCESS) { wpa_printf(MSG_DEBUG, "WPA/RSN information element rejected? (res %u)", res); wpa_hexdump(MSG_DEBUG, "IE", ie, ielen); - if (res == WPA_INVALID_GROUP) { - reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID; - status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; - } else if (res == WPA_INVALID_PAIRWISE) { - reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID; - status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - } else if (res == WPA_INVALID_AKMP) { - reason = WLAN_REASON_AKMP_NOT_VALID; - status = WLAN_STATUS_AKMP_NOT_VALID; - } else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) { - reason = WLAN_REASON_INVALID_IE; - status = WLAN_STATUS_INVALID_IE; - } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) { - reason = WLAN_REASON_CIPHER_SUITE_REJECTED; - status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; - } else if (res == WPA_INVALID_PMKID) { - reason = WLAN_REASON_INVALID_PMKID; - status = WLAN_STATUS_INVALID_PMKID; - } else { - reason = WLAN_REASON_INVALID_IE; - status = WLAN_STATUS_INVALID_IE; - } goto fail; } @@ -469,6 +502,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, return WLAN_STATUS_INVALID_IE; #endif /* CONFIG_HS20 */ } +#ifdef CONFIG_WPS +skip_wpa_check: +#endif /* CONFIG_WPS */ #ifdef CONFIG_MBO if (hapd->conf->mbo_enabled && (hapd->conf->wpa & 2) && @@ -480,13 +516,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr, } #endif /* CONFIG_MBO */ -#ifdef CONFIG_WPS -skip_wpa_check: -#endif /* CONFIG_WPS */ - #ifdef CONFIG_IEEE80211R_AP p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf), - sta->auth_alg, req_ies, req_ies_len); + sta->auth_alg, req_ies, req_ies_len, + !elems.rsnxe); if (!p) { wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs"); return WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -577,18 +610,18 @@ skip_wpa_check: npos = owe_assoc_req_process(hapd, sta, elems.owe_dh, elems.owe_dh_len, p, sizeof(buf) - (p - buf), - &reason); + &status); if (npos) p = npos; + if (!npos && - reason == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { - status = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED; + status == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) { hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); return 0; } - if (!npos || reason != WLAN_STATUS_SUCCESS) + if (!npos || status != WLAN_STATUS_SUCCESS) goto fail; } #endif /* CONFIG_OWE */ @@ -625,6 +658,11 @@ skip_wpa_check: pfs_fail: #endif /* CONFIG_DPP2 */ + if (elems.rrm_enabled && + elems.rrm_enabled_len >= sizeof(sta->rrm_enabled_capa)) + os_memcpy(sta->rrm_enabled_capa, elems.rrm_enabled, + sizeof(sta->rrm_enabled_capa)); + #if defined(CONFIG_IEEE80211R_AP) || defined(CONFIG_FILS) || defined(CONFIG_OWE) hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); @@ -709,6 +747,7 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr) ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + hostapd_set_sta_flags(hapd, sta); wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); @@ -906,6 +945,12 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) { wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d dfs=%d", freq, is_dfs); + } else if (is_dfs && + hostapd_is_dfs_required(hapd->iface) && + !hostapd_is_dfs_chan_available(hapd->iface) && + !hapd->iface->cac_started) { + hostapd_disable_iface(hapd->iface); + hostapd_enable_iface(hapd->iface); } for (i = 0; i < hapd->iface->num_bss; i++) @@ -1005,32 +1050,35 @@ void hostapd_acs_channel_selected(struct hostapd_data *hapd, goto out; } + hapd->iconf->edmg_channel = acs_res->edmg_channel; + if (hapd->iface->conf->ieee80211ac || hapd->iface->conf->ieee80211ax) { /* set defaults for backwards compatibility */ hostapd_set_oper_centr_freq_seg1_idx(hapd->iconf, 0); hostapd_set_oper_centr_freq_seg0_idx(hapd->iconf, 0); hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_USE_HT); - if (acs_res->ch_width == 80) { - hostapd_set_oper_centr_freq_seg0_idx( - hapd->iconf, acs_res->vht_seg0_center_ch); - hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_80MHZ); - } else if (acs_res->ch_width == 160) { - if (acs_res->vht_seg1_center_ch == 0) { + if (acs_res->ch_width == 40) { + if (is_6ghz_freq(acs_res->pri_freq)) hostapd_set_oper_centr_freq_seg0_idx( hapd->iconf, acs_res->vht_seg0_center_ch); + } else if (acs_res->ch_width == 80) { + hostapd_set_oper_centr_freq_seg0_idx( + hapd->iconf, acs_res->vht_seg0_center_ch); + if (acs_res->vht_seg1_center_ch == 0) { hostapd_set_oper_chwidth(hapd->iconf, - CHANWIDTH_160MHZ); + CHANWIDTH_80MHZ); } else { - hostapd_set_oper_centr_freq_seg0_idx( - hapd->iconf, - acs_res->vht_seg0_center_ch); + hostapd_set_oper_chwidth(hapd->iconf, + CHANWIDTH_80P80MHZ); hostapd_set_oper_centr_freq_seg1_idx( hapd->iconf, acs_res->vht_seg1_center_ch); - hostapd_set_oper_chwidth(hapd->iconf, - CHANWIDTH_80P80MHZ); } + } else if (acs_res->ch_width == 160) { + hostapd_set_oper_chwidth(hapd->iconf, CHANWIDTH_160MHZ); + hostapd_set_oper_centr_freq_seg0_idx( + hapd->iconf, acs_res->vht_seg1_center_ch); } } @@ -1426,15 +1474,33 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src, #endif /* HOSTAPD */ +static struct hostapd_channel_data * +hostapd_get_mode_chan(struct hostapd_hw_modes *mode, unsigned int freq) +{ + int i; + struct hostapd_channel_data *chan; + + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; + if ((unsigned int) chan->freq == freq) + return chan; + } + + return NULL; +} + + static struct hostapd_channel_data * hostapd_get_mode_channel( struct hostapd_iface *iface, unsigned int freq) { int i; struct hostapd_channel_data *chan; - for (i = 0; i < iface->current_mode->num_channels; i++) { - chan = &iface->current_mode->channels[i]; - if ((unsigned int) chan->freq == freq) + for (i = 0; i < iface->num_hw_features; i++) { + if (hostapd_hw_skip_mode(iface, &iface->hw_features[i])) + continue; + chan = hostapd_get_mode_chan(&iface->hw_features[i], freq); + if (chan) return chan; } diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c index 6da514a4..0310aab5 100644 --- a/src/ap/fils_hlp.c +++ b/src/ap/fils_hlp.c @@ -158,7 +158,7 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx) ssize_t res; u8 msgtype = 0; int rapid_commit = 0; - struct iphdr *iph; + struct ip *iph; struct udphdr *udph; struct wpabuf *resp; const u8 *rpos; @@ -259,14 +259,14 @@ static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx) wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6); wpabuf_put_be16(resp, ETH_P_IP); iph = wpabuf_put(resp, sizeof(*iph)); - iph->version = 4; - iph->ihl = sizeof(*iph) / 4; - iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos)); - iph->ttl = 1; - iph->protocol = 17; /* UDP */ - iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr; - iph->daddr = dhcp->client_ip; - iph->check = ip_checksum(iph, sizeof(*iph)); + iph->ip_v = 4; + iph->ip_hl = sizeof(*iph) / 4; + iph->ip_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos)); + iph->ip_ttl = 1; + iph->ip_p = 17; /* UDP */ + iph->ip_src.s_addr = hapd->conf->dhcp_server.u.v4.s_addr; + iph->ip_dst.s_addr = dhcp->client_ip; + iph->ip_sum = ip_checksum(iph, sizeof(*iph)); udph = wpabuf_put(resp, sizeof(*udph)); udph->uh_sport = htons(DHCP_SERVER_PORT); udph->uh_dport = htons(DHCP_CLIENT_PORT); @@ -479,13 +479,13 @@ static int fils_process_hlp_udp(struct hostapd_data *hapd, struct sta_info *sta, const u8 *dst, const u8 *pos, size_t len) { - const struct iphdr *iph; + const struct ip *iph; const struct udphdr *udph; u16 sport, dport, ulen; if (len < sizeof(*iph) + sizeof(*udph)) return 0; - iph = (const struct iphdr *) pos; + iph = (const struct ip *) pos; udph = (const struct udphdr *) (iph + 1); sport = ntohs(udph->uh_sport); dport = ntohs(udph->uh_dport); @@ -510,24 +510,24 @@ static int fils_process_hlp_ip(struct hostapd_data *hapd, struct sta_info *sta, const u8 *dst, const u8 *pos, size_t len) { - const struct iphdr *iph; - u16 tot_len; + const struct ip *iph; + uint16_t ip_len; if (len < sizeof(*iph)) return 0; - iph = (const struct iphdr *) pos; + iph = (const struct ip *) pos; if (ip_checksum(iph, sizeof(*iph)) != 0) { wpa_printf(MSG_DEBUG, "FILS: HLP request IPv4 packet had invalid header checksum - dropped"); return 0; } - tot_len = ntohs(iph->tot_len); - if (tot_len > len) + ip_len = ntohs(iph->ip_len); + if (ip_len > len) return 0; wpa_printf(MSG_DEBUG, "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u", - iph->saddr, iph->daddr, iph->protocol); - switch (iph->protocol) { + iph->ip_src.s_addr, iph->ip_dst.s_addr, iph->ip_p); + switch (iph->ip_p) { case 17: return fils_process_hlp_udp(hapd, sta, dst, pos, len); } diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index e4950e3e..f2e964ac 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -13,6 +13,7 @@ #include "utils/common.h" #include "utils/eloop.h" +#include "utils/crc32.h" #include "common/ieee802_11_defs.h" #include "common/wpa_ctrl.h" #include "common/hw_features_common.h" @@ -57,8 +58,10 @@ static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason); +#ifdef CONFIG_WEP static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd); static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd); +#endif /* CONFIG_WEP */ static int setup_interface2(struct hostapd_iface *iface); static void channel_list_update_timeout(void *eloop_ctx, void *timeout_ctx); static void hostapd_interface_setup_failure_handler(void *eloop_ctx, @@ -88,7 +91,9 @@ void hostapd_reconfig_encryption(struct hostapd_data *hapd) return; hostapd_set_privacy(hapd, 0); +#ifdef CONFIG_WEP hostapd_setup_encryption(hapd->conf->iface, hapd); +#endif /* CONFIG_WEP */ } @@ -141,7 +146,9 @@ static void hostapd_reload_bss(struct hostapd_data *hapd) wpa_deinit(hapd->wpa_auth); hapd->wpa_auth = NULL; hostapd_set_privacy(hapd, 0); +#ifdef CONFIG_WEP hostapd_setup_encryption(hapd->conf->iface, hapd); +#endif /* CONFIG_WEP */ hostapd_set_generic_elem(hapd, (u8 *) "", 0); } @@ -169,7 +176,9 @@ static void hostapd_clear_old(struct hostapd_iface *iface) for (j = 0; j < iface->num_bss; j++) { hostapd_flush_old_stations(iface->bss[j], WLAN_REASON_PREV_AUTH_NOT_VALID); +#ifdef CONFIG_WEP hostapd_broadcast_wep_clear(iface->bss[j]); +#endif /* CONFIG_WEP */ #ifndef CONFIG_NO_RADIUS /* TODO: update dynamic data based on changed configuration @@ -283,6 +292,8 @@ int hostapd_reload_config(struct hostapd_iface *iface) } +#ifdef CONFIG_WEP + static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, const char *ifname) { @@ -291,8 +302,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, if (!ifname || !hapd->drv_priv) return; for (i = 0; i < NUM_WEP_KEYS; i++) { - if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, - 0, NULL, 0, NULL, 0)) { + if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0, + 0, NULL, 0, NULL, 0, KEY_FLAG_GROUP)) { wpa_printf(MSG_DEBUG, "Failed to clear default " "encryption keys (ifname=%s keyidx=%d)", ifname, i); @@ -301,8 +312,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd, if (hapd->conf->ieee80211w) { for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) { if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, - NULL, i, 0, NULL, - 0, NULL, 0)) { + NULL, i, 0, 0, NULL, + 0, NULL, 0, KEY_FLAG_GROUP)) { wpa_printf(MSG_DEBUG, "Failed to clear " "default mgmt encryption keys " "(ifname=%s keyidx=%d)", ifname, i); @@ -325,11 +336,12 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) struct hostapd_ssid *ssid = &hapd->conf->ssid; idx = ssid->wep.idx; - if (ssid->wep.default_len && + if (ssid->wep.default_len && ssid->wep.key[idx] && hostapd_drv_set_key(hapd->conf->iface, - hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, + hapd, WPA_ALG_WEP, broadcast_ether_addr, idx, 0, 1, NULL, 0, ssid->wep.key[idx], - ssid->wep.len[idx])) { + ssid->wep.len[idx], + KEY_FLAG_GROUP_RX_TX_DEFAULT)) { wpa_printf(MSG_WARNING, "Could not set WEP encryption."); errors++; } @@ -337,6 +349,8 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd) return errors; } +#endif /* CONFIG_WEP */ + static void hostapd_free_hapd_data(struct hostapd_data *hapd) { @@ -479,11 +493,9 @@ static void sta_track_deinit(struct hostapd_iface *iface) static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface) { wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface); -#ifdef CONFIG_IEEE80211N #ifdef NEED_AP_MLME hostapd_stop_setup_timers(iface); #endif /* NEED_AP_MLME */ -#endif /* CONFIG_IEEE80211N */ if (iface->current_mode) acs_cleanup(iface); hostapd_free_hw_features(iface->hw_features, iface->num_hw_features); @@ -524,6 +536,8 @@ static void hostapd_cleanup_iface(struct hostapd_iface *iface) } +#ifdef CONFIG_WEP + static void hostapd_clear_wep(struct hostapd_data *hapd) { if (hapd->drv_priv && !hapd->iface->driver_ap_teardown && hapd->conf) { @@ -552,10 +566,13 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) for (i = 0; i < 4; i++) { if (hapd->conf->ssid.wep.key[i] && - hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, + hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i, 0, i == hapd->conf->ssid.wep.idx, NULL, 0, hapd->conf->ssid.wep.key[i], - hapd->conf->ssid.wep.len[i])) { + hapd->conf->ssid.wep.len[i], + i == hapd->conf->ssid.wep.idx ? + KEY_FLAG_GROUP_RX_TX_DEFAULT : + KEY_FLAG_GROUP_RX_TX)) { wpa_printf(MSG_WARNING, "Could not set WEP " "encryption."); return -1; @@ -568,6 +585,8 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd) return 0; } +#endif /* CONFIG_WEP */ + static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason) { @@ -603,7 +622,9 @@ static void hostapd_bss_deinit_no_free(struct hostapd_data *hapd) { hostapd_free_stas(hapd); hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING); +#ifdef CONFIG_WEP hostapd_clear_wep(hapd); +#endif /* CONFIG_WEP */ } @@ -1158,9 +1179,11 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_set_privacy(hapd, 0); +#ifdef CONFIG_WEP hostapd_broadcast_wep_clear(hapd); if (hostapd_setup_encryption(conf->iface, hapd)) return -1; +#endif /* CONFIG_WEP */ /* * Fetch the SSID from the system and use it or, @@ -1190,8 +1213,14 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len); } + /* + * Short SSID calculation is identical to FCS and it is defined in + * IEEE P802.11-REVmd/D3.0, 9.4.2.170.3 (Calculating the Short-SSID). + */ + conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len); + if (!hostapd_drv_none(hapd)) { - wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR + wpa_printf(MSG_DEBUG, "Using interface %s with hwaddr " MACSTR " and ssid \"%s\"", conf->iface, MAC2STR(hapd->own_addr), wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len)); @@ -2338,12 +2367,10 @@ void hostapd_interface_deinit(struct hostapd_iface *iface) hostapd_bss_deinit(iface->bss[j]); } -#ifdef CONFIG_IEEE80211N #ifdef NEED_AP_MLME hostapd_stop_setup_timers(iface); eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL); #endif /* NEED_AP_MLME */ -#endif /* CONFIG_IEEE80211N */ } diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 016fe3b7..439e7274 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -38,6 +38,10 @@ union wps_event_data; struct mesh_conf; #endif /* CONFIG_MESH */ +#ifdef CONFIG_CTRL_IFACE_UDP +#define CTRL_IFACE_COOKIE_LEN 8 +#endif /* CONFIG_CTRL_IFACE_UDP */ + struct hostapd_iface; struct hapd_interfaces { @@ -72,6 +76,11 @@ struct hapd_interfaces { #ifdef CONFIG_DPP struct dpp_global *dpp; #endif /* CONFIG_DPP */ + +#ifdef CONFIG_CTRL_IFACE_UDP + unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN]; +#endif /* CONFIG_CTRL_IFACE_UDP */ + }; enum hostapd_chan_status { @@ -395,6 +404,10 @@ struct hostapd_data { #ifdef CONFIG_SQLITE sqlite3 *rad_attr_db; #endif /* CONFIG_SQLITE */ + +#ifdef CONFIG_CTRL_IFACE_UDP + unsigned char ctrl_iface_cookie[CTRL_IFACE_COOKIE_LEN]; +#endif /* CONFIG_CTRL_IFACE_UDP */ }; @@ -464,9 +477,6 @@ struct hostapd_iface { u64 drv_flags; - /* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */ - unsigned int smps_modes; - /* * A bitmap of supported protocols for probe response offload. See * struct wpa_driver_capa in driver.h diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index ba10752e..f6e69030 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -224,7 +224,6 @@ int hostapd_prepare_rates(struct hostapd_iface *iface, } -#ifdef CONFIG_IEEE80211N static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface) { int pri_freq, sec_freq; @@ -561,26 +560,6 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface) return 0; } - switch (conf & HT_CAP_INFO_SMPS_MASK) { - case HT_CAP_INFO_SMPS_STATIC: - if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) { - wpa_printf(MSG_ERROR, - "Driver does not support configured HT capability [SMPS-STATIC]"); - return 0; - } - break; - case HT_CAP_INFO_SMPS_DYNAMIC: - if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) { - wpa_printf(MSG_ERROR, - "Driver does not support configured HT capability [SMPS-DYNAMIC]"); - return 0; - } - break; - case HT_CAP_INFO_SMPS_DISABLED: - default: - break; - } - if ((conf & HT_CAP_INFO_GREEN_FIELD) && !(hw & HT_CAP_INFO_GREEN_FIELD)) { wpa_printf(MSG_ERROR, "Driver does not support configured " @@ -687,12 +666,9 @@ static int ieee80211ax_supported_he_capab(struct hostapd_iface *iface) } #endif /* CONFIG_IEEE80211AX */ -#endif /* CONFIG_IEEE80211N */ - int hostapd_check_ht_capab(struct hostapd_iface *iface) { -#ifdef CONFIG_IEEE80211N int ret; if (is_6ghz_freq(iface->freq)) @@ -725,7 +701,6 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface) return ret; if (!ieee80211n_allowed_ht40_channel_pair(iface)) return -1; -#endif /* CONFIG_IEEE80211N */ return 0; } @@ -810,7 +785,7 @@ static int hostapd_is_usable_edmg(struct hostapd_iface *iface) /* 60 GHz channels 1..6 */ for (i = 0; i < 6; i++) { - int freq = 56160 + 2160 * i; + int freq = 56160 + 2160 * (i + 1); if (edmg.channels & BIT(i)) { contiguous++; @@ -879,10 +854,11 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface) if (!iface->conf->secondary_channel) return 1; + if (hostapd_is_usable_chan(iface, iface->freq + + iface->conf->secondary_channel * 20, 0)) + return 1; if (!iface->conf->ht40_plus_minus_allowed) - return hostapd_is_usable_chan( - iface, - iface->freq + iface->conf->secondary_channel * 20, 0); + return 0; /* Both HT40+ and HT40- are set, pick a valid secondary channel */ secondary_freq = iface->freq + 20; @@ -903,10 +879,43 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface) } +static void hostapd_determine_mode(struct hostapd_iface *iface) +{ + int i; + enum hostapd_hw_mode target_mode; + + if (iface->current_mode || + iface->conf->hw_mode != HOSTAPD_MODE_IEEE80211ANY) + return; + + if (iface->freq < 4000) + target_mode = HOSTAPD_MODE_IEEE80211G; + else if (iface->freq > 50000) + target_mode = HOSTAPD_MODE_IEEE80211AD; + else + target_mode = HOSTAPD_MODE_IEEE80211A; + + for (i = 0; i < iface->num_hw_features; i++) { + struct hostapd_hw_modes *mode; + + mode = &iface->hw_features[i]; + if (mode->mode == target_mode) { + iface->current_mode = mode; + iface->conf->hw_mode = mode->mode; + break; + } + } + + if (!iface->current_mode) + wpa_printf(MSG_ERROR, "ACS: Cannot decide mode"); +} + + static enum hostapd_chan_status hostapd_check_chans(struct hostapd_iface *iface) { if (iface->freq) { + hostapd_determine_mode(iface); if (hostapd_is_usable_chans(iface)) return HOSTAPD_CHAN_VALID; else @@ -1032,9 +1041,15 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface) } if (iface->current_mode == NULL) { - if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) || - !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) - { + if ((iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) && + (iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY)) { + wpa_printf(MSG_DEBUG, + "Using offloaded hw_mode=any ACS"); + } else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) && + iface->conf->hw_mode == HOSTAPD_MODE_IEEE80211ANY) { + wpa_printf(MSG_DEBUG, + "Using internal ACS for hw_mode=any"); + } else { wpa_printf(MSG_ERROR, "Hardware does not support configured mode"); hostapd_logger(iface->bss[0], NULL, @@ -1109,3 +1124,20 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq) } return 0; } + + +int hostapd_hw_skip_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode) +{ + int i; + + if (iface->current_mode) + return mode != iface->current_mode; + if (mode->mode != HOSTAPD_MODE_IEEE80211B) + return 0; + for (i = 0; i < iface->num_hw_features; i++) { + if (iface->hw_features[i].mode == HOSTAPD_MODE_IEEE80211G) + return 1; + } + return 0; +} diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h index 902a19f9..dd24f95b 100644 --- a/src/ap/hw_features.h +++ b/src/ap/hw_features.h @@ -25,6 +25,8 @@ int hostapd_check_edmg_capab(struct hostapd_iface *iface); int hostapd_prepare_rates(struct hostapd_iface *iface, struct hostapd_hw_modes *mode); void hostapd_stop_setup_timers(struct hostapd_iface *iface); +int hostapd_hw_skip_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode); #else /* NEED_AP_MLME */ static inline void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, @@ -49,7 +51,7 @@ static inline int hostapd_select_hw_mode(struct hostapd_iface *iface) static inline const char * hostapd_hw_mode_txt(int mode) { - return NULL; + return "UNKNOWN"; } static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan) @@ -77,6 +79,12 @@ static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface) { } +static inline int hostapd_hw_skip_mode(struct hostapd_iface *iface, + struct hostapd_hw_modes *mode) +{ + return 0; +} + #endif /* NEED_AP_MLME */ #endif /* HW_FEATURES_H */ diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 5b704255..e54217ce 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -88,6 +88,7 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) { u8 *pos = eid; int i, num, count; + int h2e_required; if (hapd->iface->current_rates == NULL) return eid; @@ -98,8 +99,11 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) num++; if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) num++; - if (hapd->conf->sae_pwe == 1 && - wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) + h2e_required = (hapd->conf->sae_pwe == 1 || + hostapd_sae_pw_id_in_use(hapd->conf) == 2) && + hapd->conf->sae_pwe != 3 && + wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt); + if (h2e_required) num++; if (num > 8) { /* rest of the rates are encoded in Extended supported @@ -127,9 +131,7 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; } - if (hapd->conf->sae_pwe == 1 && - wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && - count < 8) { + if (h2e_required && count < 8) { count++; *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY; } @@ -142,6 +144,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) { u8 *pos = eid; int i, num, count; + int h2e_required; if (hapd->iface->current_rates == NULL) return eid; @@ -151,8 +154,11 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) num++; if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) num++; - if (hapd->conf->sae_pwe == 1 && - wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) + h2e_required = (hapd->conf->sae_pwe == 1 || + hostapd_sae_pw_id_in_use(hapd->conf) == 2) && + hapd->conf->sae_pwe != 3 && + wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt); + if (h2e_required) num++; if (num <= 8) return eid; @@ -183,8 +189,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY; } - if (hapd->conf->sae_pwe == 1 && - wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt)) { + if (h2e_required) { count++; if (count > 8) *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY; @@ -194,10 +199,31 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) } +u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid, + size_t len) +{ + size_t i; + + for (i = 0; i < RRM_CAPABILITIES_IE_LEN; i++) { + if (hapd->conf->radio_measurements[i]) + break; + } + + if (i == RRM_CAPABILITIES_IE_LEN || len < 2 + RRM_CAPABILITIES_IE_LEN) + return eid; + + *eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES; + *eid++ = RRM_CAPABILITIES_IE_LEN; + os_memcpy(eid, hapd->conf->radio_measurements, RRM_CAPABILITIES_IE_LEN); + + return eid + RRM_CAPABILITIES_IE_LEN; +} + + u16 hostapd_own_capab_info(struct hostapd_data *hapd) { int capab = WLAN_CAPABILITY_ESS; - int privacy; + int privacy = 0; int dfs; int i; @@ -213,12 +239,14 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd) hapd->iconf->preamble == SHORT_PREAMBLE) capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; +#ifdef CONFIG_WEP privacy = hapd->conf->ssid.wep.keys_set; if (hapd->conf->ieee802_1x && (hapd->conf->default_wep_key_len || hapd->conf->individual_wep_key_len)) privacy = 1; +#endif /* CONFIG_WEP */ if (hapd->conf->wpa) privacy = 1; @@ -258,6 +286,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd) } +#ifdef CONFIG_WEP #ifndef CONFIG_NO_RC4 static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, u16 auth_transaction, const u8 *challenge, @@ -314,9 +343,10 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, return 0; } #endif /* CONFIG_NO_RC4 */ +#endif /* CONFIG_WEP */ -static int send_auth_reply(struct hostapd_data *hapd, +static int send_auth_reply(struct hostapd_data *hapd, struct sta_info *sta, const u8 *dst, const u8 *bssid, u16 auth_alg, u16 auth_transaction, u16 resp, const u8 *ies, size_t ies_len, const char *dbg) @@ -349,7 +379,37 @@ static int send_auth_reply(struct hostapd_data *hapd, " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu) (dbg=%s)", MAC2STR(dst), auth_alg, auth_transaction, resp, (unsigned long) ies_len, dbg); - if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0) +#ifdef CONFIG_TESTING_OPTIONS +#ifdef CONFIG_SAE + if (hapd->conf->sae_confirm_immediate == 2 && + auth_alg == WLAN_AUTH_SAE) { + if (auth_transaction == 1 && sta && + (resp == WLAN_STATUS_SUCCESS || + resp == WLAN_STATUS_SAE_HASH_TO_ELEMENT)) { + wpa_printf(MSG_DEBUG, + "TESTING: Postpone SAE Commit transmission until Confirm is ready"); + os_free(sta->sae_postponed_commit); + sta->sae_postponed_commit = buf; + sta->sae_postponed_commit_len = rlen; + return WLAN_STATUS_SUCCESS; + } + + if (auth_transaction == 2 && sta && sta->sae_postponed_commit) { + wpa_printf(MSG_DEBUG, + "TESTING: Send postponed SAE Commit first, immediately followed by SAE Confirm"); + if (hostapd_drv_send_mlme(hapd, + sta->sae_postponed_commit, + sta->sae_postponed_commit_len, + 0, NULL, 0, 0) < 0) + wpa_printf(MSG_INFO, "send_auth_reply: send failed"); + os_free(sta->sae_postponed_commit); + sta->sae_postponed_commit = NULL; + sta->sae_postponed_commit_len = 0; + } + } +#endif /* CONFIG_SAE */ +#endif /* CONFIG_TESTING_OPTIONS */ + if (hostapd_drv_send_mlme(hapd, reply, rlen, 0, NULL, 0, 0) < 0) wpa_printf(MSG_INFO, "send_auth_reply: send failed"); else reply_res = WLAN_STATUS_SUCCESS; @@ -369,7 +429,7 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, struct sta_info *sta; int reply_res; - reply_res = send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, + reply_res = send_auth_reply(hapd, NULL, dst, bssid, WLAN_AUTH_FT, auth_transaction, status, ies, ies_len, "auth-ft-finish"); @@ -423,7 +483,9 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, use_pt = sta->sae->tmp->h2e; } - if (status_code == WLAN_STATUS_SUCCESS) + if (rx_id && hapd->conf->sae_pwe != 3) + use_pt = 1; + else if (status_code == WLAN_STATUS_SUCCESS) use_pt = 0; else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) use_pt = 1; @@ -474,10 +536,13 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd, buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN + (rx_id ? 3 + os_strlen(rx_id) : 0)); - if (buf == NULL) - return NULL; - sae_write_commit(sta->sae, buf, sta->sae->tmp ? - sta->sae->tmp->anti_clogging_token : NULL, rx_id); + if (buf && + sae_write_commit(sta->sae, buf, sta->sae->tmp ? + sta->sae->tmp->anti_clogging_token : NULL, + rx_id) < 0) { + wpabuf_free(buf); + buf = NULL; + } return buf; } @@ -514,7 +579,8 @@ static int auth_sae_send_commit(struct hostapd_data *hapd, status = (sta->sae->tmp && sta->sae->tmp->h2e) ? WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS; - reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1, + reply_res = send_auth_reply(hapd, sta, sta->addr, bssid, + WLAN_AUTH_SAE, 1, status, wpabuf_head(data), wpabuf_len(data), "sae-send-commit"); @@ -535,7 +601,8 @@ static int auth_sae_send_confirm(struct hostapd_data *hapd, if (data == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; - reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 2, + reply_res = send_auth_reply(hapd, sta, sta->addr, bssid, + WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS, wpabuf_head(data), wpabuf_len(data), "sae-send-confirm"); @@ -575,13 +642,15 @@ static int use_sae_anti_clogging(struct hostapd_data *hapd) } -static u8 sae_token_hash(struct hostapd_data *hapd, const u8 *addr) +static int sae_token_hash(struct hostapd_data *hapd, const u8 *addr, u8 *idx) { u8 hash[SHA256_MAC_LEN]; - hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), - addr, ETH_ALEN, hash); - return hash[0]; + if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), + addr, ETH_ALEN, hash) < 0) + return -1; + *idx = hash[0]; + return 0; } @@ -594,9 +663,8 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr, u16 token_idx; u8 idx; - if (token_len != SHA256_MAC_LEN) + if (token_len != SHA256_MAC_LEN || sae_token_hash(hapd, addr, &idx) < 0) return -1; - idx = sae_token_hash(hapd, addr); token_idx = hapd->sae_pending_token_idx[idx]; if (token_idx == 0 || token_idx != WPA_GET_BE16(token)) { wpa_printf(MSG_DEBUG, "SAE: Invalid anti-clogging token from " @@ -621,7 +689,7 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr, static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, - int group, const u8 *addr) + int group, const u8 *addr, int h2e) { struct wpabuf *buf; u8 *token; @@ -647,13 +715,23 @@ static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd, sizeof(hapd->sae_pending_token_idx)); } - buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN); + buf = wpabuf_alloc(sizeof(le16) + 3 + SHA256_MAC_LEN); if (buf == NULL) return NULL; wpabuf_put_le16(buf, group); /* Finite Cyclic Group */ - p_idx = sae_token_hash(hapd, addr); + if (h2e) { + /* Encapsulate Anti-clogging Token field in a container IE */ + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + SHA256_MAC_LEN); + wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN); + } + + if (sae_token_hash(hapd, addr, &p_idx) < 0) { + wpabuf_free(buf); + return NULL; + } token_idx = hapd->sae_pending_token_idx[p_idx]; if (!token_idx) { hapd->sae_token_idx++; @@ -795,6 +873,9 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta) mlme_authenticate_indication(hapd, sta); wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); sae_set_state(sta, SAE_ACCEPTED, "Accept Confirm"); + crypto_bignum_deinit(sta->sae->peer_commit_scalar_accepted, 0); + sta->sae->peer_commit_scalar_accepted = sta->sae->peer_commit_scalar; + sta->sae->peer_commit_scalar = NULL; wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr, sta->sae->pmk, sta->sae->pmkid); sae_sme_send_external_auth_status(hapd, sta, WLAN_STATUS_SUCCESS); @@ -1028,11 +1109,20 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta) static int sae_status_success(struct hostapd_data *hapd, u16 status_code) { - return (hapd->conf->sae_pwe == 0 && + int sae_pwe = hapd->conf->sae_pwe; + int id_in_use; + + id_in_use = hostapd_sae_pw_id_in_use(hapd->conf); + if (id_in_use == 2 && sae_pwe != 3) + sae_pwe = 1; + else if (id_in_use == 1 && sae_pwe == 0) + sae_pwe = 2; + + return ((sae_pwe == 0 || sae_pwe == 3) && status_code == WLAN_STATUS_SUCCESS) || - (hapd->conf->sae_pwe == 1 && + (sae_pwe == 1 && status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) || - (hapd->conf->sae_pwe == 2 && + (sae_pwe == 2 && (status_code == WLAN_STATUS_SUCCESS || status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)); } @@ -1103,7 +1193,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "SAE: TESTING - reflection attack"); pos = mgmt->u.auth.variable; end = ((const u8 *) mgmt) + len; - send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, + send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, auth_transaction, resp, pos, end - pos, "auth-sae-reflection-attack"); goto remove_sta; @@ -1111,7 +1201,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, if (hapd->conf->sae_commit_override && auth_transaction == 1) { wpa_printf(MSG_DEBUG, "SAE: TESTING - commit override"); - send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, + send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, auth_transaction, resp, wpabuf_head(hapd->conf->sae_commit_override), wpabuf_len(hapd->conf->sae_commit_override), @@ -1286,11 +1376,17 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta, } if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) { + int h2e = 0; + wpa_printf(MSG_DEBUG, "SAE: Request anti-clogging token from " MACSTR, MAC2STR(sta->addr)); + if (sta->sae->tmp) + h2e = sta->sae->tmp->h2e; + if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) + h2e = 1; data = auth_build_token_req(hapd, sta->sae->group, - sta->addr); + sta->addr, h2e); resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ; if (hapd->conf->mesh & MESH_ENABLED) sae_set_state(sta, SAE_NOTHING, @@ -1365,7 +1461,7 @@ reply: data = wpabuf_alloc_copy(pos, 2); sae_sme_send_external_auth_status(hapd, sta, resp); - send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, + send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE, auth_transaction, resp, data ? wpabuf_head(data) : (u8 *) "", data ? wpabuf_len(data) : 0, "auth-sae"); @@ -1515,27 +1611,37 @@ static int auth_sae_queued_addr(struct hostapd_data *hapd, const u8 *addr) #endif /* CONFIG_SAE */ -static u16 wpa_res_to_status_code(int res) +static u16 wpa_res_to_status_code(enum wpa_validate_result res) { - if (res == WPA_INVALID_GROUP) + switch (res) { + case WPA_IE_OK: + return WLAN_STATUS_SUCCESS; + case WPA_INVALID_IE: + return WLAN_STATUS_INVALID_IE; + case WPA_INVALID_GROUP: return WLAN_STATUS_GROUP_CIPHER_NOT_VALID; - if (res == WPA_INVALID_PAIRWISE) + case WPA_INVALID_PAIRWISE: return WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - if (res == WPA_INVALID_AKMP) + case WPA_INVALID_AKMP: return WLAN_STATUS_AKMP_NOT_VALID; - if (res == WPA_ALLOC_FAIL) + case WPA_NOT_ENABLED: + return WLAN_STATUS_INVALID_IE; + case WPA_ALLOC_FAIL: return WLAN_STATUS_UNSPECIFIED_FAILURE; - if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) + case WPA_MGMT_FRAME_PROTECTION_VIOLATION: return WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; - if (res == WPA_INVALID_MGMT_GROUP_CIPHER) + case WPA_INVALID_MGMT_GROUP_CIPHER: return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; - if (res == WPA_INVALID_MDIE) + case WPA_INVALID_MDIE: return WLAN_STATUS_INVALID_MDIE; - if (res == WPA_INVALID_PMKID) - return WLAN_STATUS_INVALID_PMKID; - if (res != WPA_IE_OK) + case WPA_INVALID_PROTO: return WLAN_STATUS_INVALID_IE; - return WLAN_STATUS_SUCCESS; + case WPA_INVALID_PMKID: + return WLAN_STATUS_INVALID_PMKID; + case WPA_DENIED_OTHER_REASON: + return WLAN_STATUS_ASSOC_DENIED_UNSPEC; + } + return WLAN_STATUS_INVALID_IE; } @@ -1555,7 +1661,7 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, u16 resp = WLAN_STATUS_SUCCESS; const u8 *end; struct ieee802_11_elems elems; - int res; + enum wpa_validate_result res; struct wpa_ie_data rsn; struct rsn_pmksa_cache_entry *pmksa = NULL; @@ -1731,11 +1837,11 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, FILS_SESSION_LEN); os_memcpy(sta->fils_session, elems.fils_session, FILS_SESSION_LEN); - /* FILS Wrapped Data */ - if (elems.fils_wrapped_data) { + /* Wrapped Data */ + if (elems.wrapped_data) { wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data", - elems.fils_wrapped_data, - elems.fils_wrapped_data_len); + elems.wrapped_data, + elems.wrapped_data_len); if (!pmksa) { #ifndef CONFIG_NO_RADIUS if (!sta->eapol_sm) { @@ -1745,8 +1851,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "FILS: Forward EAP-Initiate/Re-auth to authentication server"); ieee802_1x_encapsulate_radius( - hapd, sta, elems.fils_wrapped_data, - elems.fils_wrapped_data_len); + hapd, sta, elems.wrapped_data, + elems.wrapped_data_len); sta->fils_pending_cb = cb; wpa_printf(MSG_DEBUG, "FILS: Will send Authentication frame once the response from authentication server is available"); @@ -1755,8 +1861,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, * to maintain a copy of the EAP-Initiate/Reauth * message. */ if (fils_pmkid_erp(wpa_auth_sta_key_mgmt(sta->wpa_sm), - elems.fils_wrapped_data, - elems.fils_wrapped_data_len, + elems.wrapped_data, + elems.wrapped_data_len, sta->fils_erp_pmkid) == 0) sta->fils_erp_pmkid_set = 1; return; @@ -1899,12 +2005,12 @@ prepare_auth_resp_fils(struct hostapd_data *hapd, wpabuf_put_u8(data, WLAN_EID_EXT_FILS_SESSION); wpabuf_put_data(data, sta->fils_session, FILS_SESSION_LEN); - /* FILS Wrapped Data */ + /* Wrapped Data */ if (!pmksa && erp_resp) { wpabuf_put_u8(data, WLAN_EID_EXTENSION); /* Element ID */ wpabuf_put_u8(data, 1 + wpabuf_len(erp_resp)); /* Length */ /* Element ID Extension */ - wpabuf_put_u8(data, WLAN_EID_EXT_FILS_WRAPPED_DATA); + wpabuf_put_u8(data, WLAN_EID_EXT_WRAPPED_DATA); wpabuf_put_buf(data, erp_resp); if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm), @@ -2006,7 +2112,7 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd, auth_alg = (pub || resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK; - send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp, + send_auth_reply(hapd, sta, sta->addr, hapd->own_addr, auth_alg, 2, resp, data ? wpabuf_head(data) : (u8 *) "", data ? wpabuf_len(data) : 0, "auth-fils-finish"); wpabuf_free(data); @@ -2050,28 +2156,18 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ -int -ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, - const u8 *msg, size_t len, u32 *session_timeout, - u32 *acct_interim_interval, - struct vlan_description *vlan_id, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui, int is_probe_req) +static int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, + const u8 *msg, size_t len, + struct radius_sta *info) { int res; - os_memset(vlan_id, 0, sizeof(*vlan_id)); - res = hostapd_allowed_address(hapd, addr, msg, len, - session_timeout, acct_interim_interval, - vlan_id, psk, identity, radius_cui, - is_probe_req); + res = hostapd_allowed_address(hapd, addr, msg, len, info, 0); if (res == HOSTAPD_ACL_REJECT) { - if (!is_probe_req) - wpa_printf(MSG_DEBUG, - "Station " MACSTR - " not allowed to authenticate", - MAC2STR(addr)); + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not allowed to authenticate", + MAC2STR(addr)); return HOSTAPD_ACL_REJECT; } @@ -2091,12 +2187,15 @@ ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, static int ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, - int res, u32 session_timeout, - u32 acct_interim_interval, - struct vlan_description *vlan_id, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui) + int res, struct radius_sta *info) { + u32 session_timeout = info->session_timeout; + u32 acct_interim_interval = info->acct_interim_interval; + struct vlan_description *vlan_id = &info->vlan_id; + struct hostapd_sta_wpa_psk_short *psk = info->psk; + char *identity = info->identity; + char *radius_cui = info->radius_cui; + if (vlan_id->notempty && !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, @@ -2113,20 +2212,22 @@ ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta, HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); hostapd_free_psk_list(sta->psk); - if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) { - sta->psk = *psk; - *psk = NULL; - } else { + if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) + hostapd_copy_psk_list(&sta->psk, psk); + else sta->psk = NULL; - } os_free(sta->identity); - sta->identity = *identity; - *identity = NULL; + if (identity) + sta->identity = os_strdup(identity); + else + sta->identity = NULL; os_free(sta->radius_cui); - sta->radius_cui = *radius_cui; - *radius_cui = NULL; + if (radius_cui) + sta->radius_cui = os_strdup(radius_cui); + else + sta->radius_cui = NULL; if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval) sta->acct_interim_interval = acct_interim_interval; @@ -2154,14 +2255,10 @@ static void handle_auth(struct hostapd_data *hapd, int res, reply_res; u16 fc; const u8 *challenge = NULL; - u32 session_timeout, acct_interim_interval; - struct vlan_description vlan_id; - struct hostapd_sta_wpa_psk_short *psk = NULL; u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; size_t resp_ies_len = 0; - char *identity = NULL; - char *radius_cui = NULL; u16 seq_ctrl; + struct radius_sta rad_info; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)", @@ -2312,10 +2409,8 @@ static void handle_auth(struct hostapd_data *hapd, } } - res = ieee802_11_allowed_address( - hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout, - &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui, - 0); + res = ieee802_11_allowed_address(hapd, mgmt->sa, (const u8 *) mgmt, len, + &rad_info); if (res == HOSTAPD_ACL_REJECT) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Ignore Authentication frame from " MACSTR @@ -2398,9 +2493,7 @@ static void handle_auth(struct hostapd_data *hapd, sta->auth_rssi = rssi; #endif /* CONFIG_MBO */ - res = ieee802_11_set_radius_info( - hapd, sta, res, session_timeout, acct_interim_interval, - &vlan_id, &psk, &identity, &radius_cui); + res = ieee802_11_set_radius_info(hapd, sta, res, &rad_info); if (res) { wpa_printf(MSG_DEBUG, "ieee802_11_set_radius_info() failed"); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -2471,6 +2564,7 @@ static void handle_auth(struct hostapd_data *hapd, sta->auth_alg = WLAN_AUTH_OPEN; mlme_authenticate_indication(hapd, sta); break; +#ifdef CONFIG_WEP #ifndef CONFIG_NO_RC4 case WLAN_AUTH_SHARED_KEY: resp = auth_shared_key(hapd, sta, auth_transaction, challenge, @@ -2489,6 +2583,7 @@ static void handle_auth(struct hostapd_data *hapd, } break; #endif /* CONFIG_NO_RC4 */ +#endif /* CONFIG_WEP */ #ifdef CONFIG_IEEE80211R_AP case WLAN_AUTH_FT: sta->auth_alg = WLAN_AUTH_FT; @@ -2542,11 +2637,7 @@ static void handle_auth(struct hostapd_data *hapd, } fail: - os_free(identity); - os_free(radius_cui); - hostapd_free_psk_list(psk); - - reply_res = send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, + reply_res = send_auth_reply(hapd, sta, mgmt->sa, mgmt->bssid, auth_alg, auth_transaction + 1, resp, resp_ies, resp_ies_len, "handle-auth"); @@ -2963,7 +3054,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd, u16 status; u8 *owe_buf, ie[256 * 2]; size_t ie_len = 0; - int res; + enum wpa_validate_result res; if (!rsn_ie || rsn_ie_len < 2) { wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq"); @@ -3068,7 +3159,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, if (resp != WLAN_STATUS_SUCCESS) return resp; -#ifdef CONFIG_IEEE80211N resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities); if (resp != WLAN_STATUS_SUCCESS) return resp; @@ -3079,7 +3169,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, "mandatory HT PHY - reject association"); return WLAN_STATUS_ASSOC_DENIED_NO_HT; } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC if (hapd->iconf->ieee80211ac) { @@ -3176,7 +3265,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, } if (hapd->conf->wpa && wpa_ie) { - int res; + enum wpa_validate_result res; + wpa_ie -= 2; wpa_ie_len += 2; if (sta->wpa_sm == NULL) @@ -3324,7 +3414,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, pfs_fail: #endif /* CONFIG_DPP2 */ -#ifdef CONFIG_IEEE80211N if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) && wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { hostapd_logger(hapd, sta->addr, @@ -3334,7 +3423,6 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, "association"); return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_HS20 } else if (hapd->conf->osen) { if (elems.osen == NULL) { @@ -3479,7 +3567,7 @@ static void send_deauth(struct hostapd_data *hapd, const u8 *addr, send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); reply.u.deauth.reason_code = host_to_le16(reason_code); - if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0) + if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0, NULL, 0, 0) < 0) wpa_printf(MSG_INFO, "Failed to send deauth: %s", strerror(errno)); } @@ -3535,10 +3623,8 @@ static int add_associated_sta(struct hostapd_data *hapd, sta->ft_over_ds = 0; } -#ifdef CONFIG_IEEE80211N if (sta->flags & WLAN_STA_HT) hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC if (sta->flags & WLAN_STA_VHT) hostapd_get_vht_capab(hapd, sta->vht_capabilities, &vht_cap); @@ -3586,7 +3672,8 @@ static int add_associated_sta(struct hostapd_data *hapd, static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, const u8 *addr, u16 status_code, int reassoc, - const u8 *ies, size_t ies_len, int rssi) + const u8 *ies, size_t ies_len, int rssi, + int omit_rsnxe) { int send_len; u8 *buf; @@ -3637,6 +3724,9 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, /* Extended supported rates */ p = hostapd_eid_ext_supp_rates(hapd, p); + /* Radio measurement capabilities */ + p = hostapd_eid_rm_enabled_capab(hapd, p, buf + buflen - p); + #ifdef CONFIG_MBO if (status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS && rssi != 0) { @@ -3653,7 +3743,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, * Transition Information, RSN, [RIC Response] */ p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, buf + buflen - p, - sta->auth_alg, ies, ies_len); + sta->auth_alg, ies, ies_len, + omit_rsnxe); if (!p) { wpa_printf(MSG_DEBUG, "FT: Failed to write AssocResp IEs"); @@ -3683,10 +3774,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, if (sta && status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) p = hostapd_eid_assoc_comeback_time(hapd, sta, p); -#ifdef CONFIG_IEEE80211N p = hostapd_eid_ht_capabilities(hapd, p); p = hostapd_eid_ht_operation(hapd, p); -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac && @@ -3734,7 +3823,23 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_FST */ - p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p); +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->conf->rsnxe_override_ft && + buf + buflen - p >= + (long int) wpabuf_len(hapd->conf->rsnxe_override_ft) && + sta && sta->auth_alg == WLAN_AUTH_FT) { + wpa_printf(MSG_DEBUG, "TESTING: RSNXE FT override"); + os_memcpy(p, wpabuf_head(hapd->conf->rsnxe_override_ft), + wpabuf_len(hapd->conf->rsnxe_override_ft)); + p += wpabuf_len(hapd->conf->rsnxe_override_ft); + goto rsnxe_done; + } +#endif /* CONFIG_TESTING_OPTIONS */ + if (!omit_rsnxe) + p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p); +#ifdef CONFIG_TESTING_OPTIONS +rsnxe_done: +#endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_OWE if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && @@ -3865,7 +3970,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_FILS */ - if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) { + if (hostapd_drv_send_mlme(hapd, reply, send_len, 0, NULL, 0, 0) < 0) { wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", strerror(errno)); res = WLAN_STATUS_UNSPECIFIED_FAILURE; @@ -3880,12 +3985,12 @@ done: #ifdef CONFIG_OWE u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, const u8 *owe_dh, u8 owe_dh_len, - u8 *owe_buf, size_t owe_buf_len, u16 *reason) + u8 *owe_buf, size_t owe_buf_len, u16 *status) { #ifdef CONFIG_TESTING_OPTIONS if (hapd->conf->own_ie_override) { wpa_printf(MSG_DEBUG, "OWE: Using IE override"); - *reason = WLAN_STATUS_SUCCESS; + *status = WLAN_STATUS_SUCCESS; return wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, owe_buf_len, NULL, 0); } @@ -3895,18 +4000,18 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "OWE: Using PMKSA caching"); owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, owe_buf_len, NULL, 0); - *reason = WLAN_STATUS_SUCCESS; + *status = WLAN_STATUS_SUCCESS; return owe_buf; } if (sta->owe_pmk && sta->external_dh_updated) { wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK"); - *reason = WLAN_STATUS_SUCCESS; + *status = WLAN_STATUS_SUCCESS; return owe_buf; } - *reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len); - if (*reason != WLAN_STATUS_SUCCESS) + *status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len); + if (*status != WLAN_STATUS_SUCCESS) return NULL; owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, owe_buf, @@ -3917,7 +4022,7 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0); if (!pub) { - *reason = WLAN_STATUS_UNSPECIFIED_FAILURE; + *status = WLAN_STATUS_UNSPECIFIED_FAILURE; return owe_buf; } @@ -3952,7 +4057,7 @@ void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta) reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS, sta->fils_pending_assoc_is_reassoc, sta->fils_pending_assoc_req, - sta->fils_pending_assoc_req_len, 0); + sta->fils_pending_assoc_req_len, 0, 0); os_free(sta->fils_pending_assoc_req); sta->fils_pending_assoc_req = NULL; sta->fils_pending_assoc_req_len = 0; @@ -3997,12 +4102,10 @@ static void handle_assoc(struct hostapd_data *hapd, int left, i; struct sta_info *sta; u8 *tmp = NULL; - struct hostapd_sta_wpa_psk_short *psk = NULL; - char *identity = NULL; - char *radius_cui = NULL; #ifdef CONFIG_FILS int delay_assoc = 0; #endif /* CONFIG_FILS */ + int omit_rsnxe = 0; if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : sizeof(mgmt->u.assoc_req))) { @@ -4079,13 +4182,11 @@ static void handle_assoc(struct hostapd_data *hapd, hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211AD) { int acl_res; - u32 session_timeout, acct_interim_interval; - struct vlan_description vlan_id; + struct radius_sta info; - acl_res = ieee802_11_allowed_address( - hapd, mgmt->sa, (const u8 *) mgmt, len, - &session_timeout, &acct_interim_interval, - &vlan_id, &psk, &identity, &radius_cui, 0); + acl_res = ieee802_11_allowed_address(hapd, mgmt->sa, + (const u8 *) mgmt, + len, &info); if (acl_res == HOSTAPD_ACL_REJECT) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Ignore Association Request frame from " @@ -4110,9 +4211,7 @@ static void handle_assoc(struct hostapd_data *hapd, } acl_res = ieee802_11_set_radius_info( - hapd, sta, acl_res, session_timeout, - acct_interim_interval, &vlan_id, &psk, - &identity, &radius_cui); + hapd, sta, acl_res, &info); if (acl_res) { resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; @@ -4219,6 +4318,7 @@ static void handle_assoc(struct hostapd_data *hapd, resp = check_assoc_ies(hapd, sta, pos, left, reassoc); if (resp != WLAN_STATUS_SUCCESS) goto fail; + omit_rsnxe = !get_ie(pos, left, WLAN_EID_RSNX); if (hostapd_get_aid(hapd, sta) < 0) { hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, @@ -4271,9 +4371,7 @@ static void handle_assoc(struct hostapd_data *hapd, ieee802_11_set_beacons(hapd->iface); } -#ifdef CONFIG_IEEE80211N update_ht_state(hapd, sta); -#endif /* CONFIG_IEEE80211N */ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, @@ -4313,9 +4411,6 @@ static void handle_assoc(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ fail: - os_free(identity); - os_free(radius_cui); - hostapd_free_psk_list(psk); /* * In case of a successful response, add the station to the driver. @@ -4377,7 +4472,7 @@ static void handle_assoc(struct hostapd_data *hapd, #endif /* CONFIG_FILS */ reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos, - left, rssi); + left, rssi, omit_rsnxe); os_free(tmp); /* @@ -4418,6 +4513,7 @@ static void handle_disassoc(struct hostapd_data *hapd, ap_sta_set_authorized(hapd, sta, 0); sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); + hostapd_set_sta_flags(hapd, sta); wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated"); @@ -4484,6 +4580,7 @@ static void handle_deauth(struct hostapd_data *hapd, sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); + hostapd_set_sta_flags(hapd, sta); wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "deauthenticated"); @@ -4615,14 +4712,12 @@ static int handle_action(struct hostapd_data *hapd, #endif /* CONFIG_FST */ case WLAN_ACTION_PUBLIC: case WLAN_ACTION_PROTECTED_DUAL: -#ifdef CONFIG_IEEE80211N if (len >= IEEE80211_HDRLEN + 2 && mgmt->u.action.u.public_action.action == WLAN_PA_20_40_BSS_COEX) { hostapd_2040_coex_action(hapd, mgmt, len); return 1; } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_DPP if (len >= IEEE80211_HDRLEN + 6 && mgmt->u.action.u.vs_public_action.action == @@ -4705,7 +4800,7 @@ static int handle_action(struct hostapd_data *hapd, os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); resp->u.action.category |= 0x80; - if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) { + if (hostapd_drv_send_mlme(hapd, resp, len, 0, NULL, 0, 0) < 0) { wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send " "Action frame"); } @@ -4903,6 +4998,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd, struct sta_info *sta, char *ifname_wds) { +#ifdef CONFIG_WEP int i; struct hostapd_ssid *ssid = &hapd->conf->ssid; @@ -4912,14 +5008,18 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd, for (i = 0; i < 4; i++) { if (ssid->wep.key[i] && hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i, - i == ssid->wep.idx, NULL, 0, - ssid->wep.key[i], ssid->wep.len[i])) { + 0, i == ssid->wep.idx, NULL, 0, + ssid->wep.key[i], ssid->wep.len[i], + i == ssid->wep.idx ? + KEY_FLAG_GROUP_RX_TX_DEFAULT : + KEY_FLAG_GROUP_RX_TX)) { wpa_printf(MSG_WARNING, "Could not set WEP keys for WDS interface; %s", ifname_wds); break; } } +#endif /* CONFIG_WEP */ } diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index f592da54..c7bdb4b2 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -16,8 +16,7 @@ struct hostapd_frame_info; struct ieee80211_ht_capabilities; struct ieee80211_vht_capabilities; struct ieee80211_mgmt; -struct vlan_description; -struct hostapd_sta_wpa_psk_short; +struct radius_sta; enum ieee80211_op_mode; int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, @@ -50,9 +49,10 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid); +u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid, + size_t len); u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid); -u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts); u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid); u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid); @@ -95,6 +95,8 @@ u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta, enum ieee80211_op_mode opmode, const u8 *he_capab, size_t he_capab_len); +int hostapd_get_he_twt_responder(struct hostapd_data *hapd, + enum ieee80211_op_mode mode); void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len, int ack); void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst, @@ -162,7 +164,7 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd, const u8 *msk, size_t msk_len); u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta, const u8 *owe_dh, u8 owe_dh_len, - u8 *owe_buf, size_t owe_buf_len, u16 *reason); + u8 *owe_buf, size_t owe_buf_len, u16 *status); u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta, const u8 *rsn_ie, size_t rsn_ie_len, const u8 *owe_dh, size_t owe_dh_len); @@ -180,13 +182,9 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta, size_t hostapd_eid_owe_trans_len(struct hostapd_data *hapd); u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, size_t len); -int ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr, - const u8 *msg, size_t len, u32 *session_timeout, - u32 *acct_interim_interval, - struct vlan_description *vlan_id, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui, - int is_probe_req); + +size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd); +u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len); int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth, int ap_seg1_idx, int *bandwidth, int *seg1_idx); diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c index 931d4d06..783ee6de 100644 --- a/src/ap/ieee802_11_auth.c +++ b/src/ap/ieee802_11_auth.c @@ -32,12 +32,7 @@ struct hostapd_cached_radius_acl { macaddr addr; int accepted; /* HOSTAPD_ACL_* */ struct hostapd_cached_radius_acl *next; - u32 session_timeout; - u32 acct_interim_interval; - struct vlan_description vlan_id; - struct hostapd_sta_wpa_psk_short *psk; - char *identity; - char *radius_cui; + struct radius_sta info; }; @@ -54,9 +49,9 @@ struct hostapd_acl_query_data { #ifndef CONFIG_NO_RADIUS static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e) { - os_free(e->identity); - os_free(e->radius_cui); - hostapd_free_psk_list(e->psk); + os_free(e->info.identity); + os_free(e->info.radius_cui); + hostapd_free_psk_list(e->info.psk); os_free(e); } @@ -73,25 +68,8 @@ static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache) } -static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, - struct hostapd_sta_wpa_psk_short *src) -{ - if (!psk) - return; - - if (src) - src->ref++; - - *psk = src; -} - - static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, - u32 *session_timeout, - u32 *acct_interim_interval, - struct vlan_description *vlan_id, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui) + struct radius_sta *out) { struct hostapd_cached_radius_acl *entry; struct os_reltime now; @@ -105,27 +83,8 @@ static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, if (os_reltime_expired(&now, &entry->timestamp, RADIUS_ACL_TIMEOUT)) return -1; /* entry has expired */ - if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT) - if (session_timeout) - *session_timeout = entry->session_timeout; - if (acct_interim_interval) - *acct_interim_interval = - entry->acct_interim_interval; - if (vlan_id) - *vlan_id = entry->vlan_id; - copy_psk_list(psk, entry->psk); - if (identity) { - if (entry->identity) - *identity = os_strdup(entry->identity); - else - *identity = NULL; - } - if (radius_cui) { - if (entry->radius_cui) - *radius_cui = os_strdup(entry->radius_cui); - else - *radius_cui = NULL; - } + *out = entry->info; + return entry->accepted; } @@ -238,42 +197,28 @@ int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr, * @addr: MAC address of the STA * @msg: Authentication message * @len: Length of msg in octets - * @session_timeout: Buffer for returning session timeout (from RADIUS) - * @acct_interim_interval: Buffer for returning account interval (from RADIUS) - * @vlan_id: Buffer for returning VLAN ID - * @psk: Linked list buffer for returning WPA PSK - * @identity: Buffer for returning identity (from RADIUS) - * @radius_cui: Buffer for returning CUI (from RADIUS) + * @out.session_timeout: Buffer for returning session timeout (from RADIUS) + * @out.acct_interim_interval: Buffer for returning account interval (from + * RADIUS) + * @out.vlan_id: Buffer for returning VLAN ID + * @out.psk: Linked list buffer for returning WPA PSK + * @out.identity: Buffer for returning identity (from RADIUS) + * @out.radius_cui: Buffer for returning CUI (from RADIUS) * @is_probe_req: Whether this query for a Probe Request frame * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING * - * The caller is responsible for freeing the returned *identity and *radius_cui - * values with os_free(). + * The caller is responsible for properly cloning the returned out->identity and + * out->radius_cui and out->psk values. */ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, - const u8 *msg, size_t len, u32 *session_timeout, - u32 *acct_interim_interval, - struct vlan_description *vlan_id, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui, + const u8 *msg, size_t len, struct radius_sta *out, int is_probe_req) { int res; - if (session_timeout) - *session_timeout = 0; - if (acct_interim_interval) - *acct_interim_interval = 0; - if (vlan_id) - os_memset(vlan_id, 0, sizeof(*vlan_id)); - if (psk) - *psk = NULL; - if (identity) - *identity = NULL; - if (radius_cui) - *radius_cui = NULL; - - res = hostapd_check_acl(hapd, addr, vlan_id); + os_memset(out, 0, sizeof(*out)); + + res = hostapd_check_acl(hapd, addr, &out->vlan_id); if (res != HOSTAPD_ACL_PENDING) return res; @@ -290,12 +235,10 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, }; if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED) - vlan_id = NULL; + os_memset(&out->vlan_id, 0, sizeof(out->vlan_id)); /* Check whether ACL cache has an entry for this station */ - res = hostapd_acl_cache_get(hapd, addr, session_timeout, - acct_interim_interval, vlan_id, psk, - identity, radius_cui); + res = hostapd_acl_cache_get(hapd, addr, out); if (res == HOSTAPD_ACL_ACCEPT || res == HOSTAPD_ACL_ACCEPT_TIMEOUT) return res; @@ -307,14 +250,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) { /* pending query in RADIUS retransmit queue; * do not generate a new one */ - if (identity) { - os_free(*identity); - *identity = NULL; - } - if (radius_cui) { - os_free(*radius_cui); - *radius_cui = NULL; - } return HOSTAPD_ACL_PENDING; } query = query->next; @@ -488,8 +423,8 @@ static void decode_tunnel_passwords(struct hostapd_data *hapd, passphraselen); psk->is_passphrase = 1; } - psk->next = cache->psk; - cache->psk = psk; + psk->next = cache->info.psk; + cache->info.psk = psk; psk = NULL; } skip: @@ -518,6 +453,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, struct hostapd_data *hapd = data; struct hostapd_acl_query_data *query, *prev; struct hostapd_cached_radius_acl *cache; + struct radius_sta *info; struct radius_hdr *hdr = radius_msg_get_hdr(msg); query = hapd->acl_queries; @@ -555,65 +491,66 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, } os_get_reltime(&cache->timestamp); os_memcpy(cache->addr, query->addr, sizeof(cache->addr)); + info = &cache->info; if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) { u8 *buf; size_t len; if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, - &cache->session_timeout) == 0) + &info->session_timeout) == 0) cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT; else cache->accepted = HOSTAPD_ACL_ACCEPT; if (radius_msg_get_attr_int32( msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL, - &cache->acct_interim_interval) == 0 && - cache->acct_interim_interval < 60) { + &info->acct_interim_interval) == 0 && + info->acct_interim_interval < 60) { wpa_printf(MSG_DEBUG, "Ignored too small " "Acct-Interim-Interval %d for STA " MACSTR, - cache->acct_interim_interval, + info->acct_interim_interval, MAC2STR(query->addr)); - cache->acct_interim_interval = 0; + info->acct_interim_interval = 0; } if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED) - cache->vlan_id.notempty = !!radius_msg_get_vlanid( - msg, &cache->vlan_id.untagged, - MAX_NUM_TAGGED_VLAN, cache->vlan_id.tagged); + info->vlan_id.notempty = !!radius_msg_get_vlanid( + msg, &info->vlan_id.untagged, + MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged); decode_tunnel_passwords(hapd, shared_secret, shared_secret_len, msg, req, cache); if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len, NULL) == 0) { - cache->identity = os_zalloc(len + 1); - if (cache->identity) - os_memcpy(cache->identity, buf, len); + info->identity = os_zalloc(len + 1); + if (info->identity) + os_memcpy(info->identity, buf, len); } if (radius_msg_get_attr_ptr( msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, &buf, &len, NULL) == 0) { - cache->radius_cui = os_zalloc(len + 1); - if (cache->radius_cui) - os_memcpy(cache->radius_cui, buf, len); + info->radius_cui = os_zalloc(len + 1); + if (info->radius_cui) + os_memcpy(info->radius_cui, buf, len); } if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED && - !cache->psk) + !info->psk) cache->accepted = HOSTAPD_ACL_REJECT; - if (cache->vlan_id.notempty && - !hostapd_vlan_valid(hapd->conf->vlan, &cache->vlan_id)) { + if (info->vlan_id.notempty && + !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) { hostapd_logger(hapd, query->addr, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, "Invalid VLAN %d%s received from RADIUS server", - cache->vlan_id.untagged, - cache->vlan_id.tagged[0] ? "+" : ""); - os_memset(&cache->vlan_id, 0, sizeof(cache->vlan_id)); + info->vlan_id.untagged, + info->vlan_id.tagged[0] ? "+" : ""); + os_memset(&info->vlan_id, 0, sizeof(info->vlan_id)); } if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED && - !cache->vlan_id.notempty) + !info->vlan_id.notempty) cache->accepted = HOSTAPD_ACL_REJECT; } else cache->accepted = HOSTAPD_ACL_REJECT; @@ -622,7 +559,7 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req, #ifdef CONFIG_DRIVER_RADIUS_ACL hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted, - cache->session_timeout); + info->session_timeout); #else /* CONFIG_DRIVER_RADIUS_ACL */ #ifdef NEED_AP_MLME /* Re-send original authentication frame for 802.11 processing */ @@ -685,6 +622,19 @@ void hostapd_acl_deinit(struct hostapd_data *hapd) } +void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, + struct hostapd_sta_wpa_psk_short *src) +{ + if (!psk) + return; + + if (src) + src->ref++; + + *psk = src; +} + + void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk) { if (psk && psk->ref) { diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h index 5aece518..9410f55c 100644 --- a/src/ap/ieee802_11_auth.h +++ b/src/ap/ieee802_11_auth.h @@ -16,18 +16,25 @@ enum { HOSTAPD_ACL_ACCEPT_TIMEOUT = 3 }; +struct radius_sta { + u32 session_timeout; + u32 acct_interim_interval; + struct vlan_description vlan_id; + struct hostapd_sta_wpa_psk_short *psk; + char *identity; + char *radius_cui; +}; + int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr, struct vlan_description *vlan_id); int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr, - const u8 *msg, size_t len, u32 *session_timeout, - u32 *acct_interim_interval, - struct vlan_description *vlan_id, - struct hostapd_sta_wpa_psk_short **psk, - char **identity, char **radius_cui, + const u8 *msg, size_t len, struct radius_sta *out, int is_probe_req); int hostapd_acl_init(struct hostapd_data *hapd); void hostapd_acl_deinit(struct hostapd_data *hapd); void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk); void hostapd_acl_expire(struct hostapd_data *hapd); +void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk, + struct hostapd_sta_wpa_psk_short *src); #endif /* IEEE802_11_AUTH_H */ diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c index abd39409..57c6b18f 100644 --- a/src/ap/ieee802_11_he.c +++ b/src/ap/ieee802_11_he.c @@ -192,9 +192,12 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) params |= (hapd->iface->conf->he_op.he_rts_threshold << HE_OPERATION_RTS_THRESHOLD_OFFSET); - if (hapd->iface->conf->he_op.he_bss_color) - params |= (hapd->iface->conf->he_op.he_bss_color << - HE_OPERATION_BSS_COLOR_OFFSET); + if (hapd->iface->conf->he_op.he_bss_color_disabled) + params |= HE_OPERATION_BSS_COLOR_DISABLED; + if (hapd->iface->conf->he_op.he_bss_color_partial) + params |= HE_OPERATION_BSS_COLOR_PARTIAL; + params |= hapd->iface->conf->he_op.he_bss_color << + HE_OPERATION_BSS_COLOR_OFFSET; /* HE minimum required basic MCS and NSS for STAs */ oper->he_mcs_nss_set = @@ -206,17 +209,25 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid) if (is_6ghz_op_class(hapd->iconf->op_class)) { u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf); + u8 seg1 = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); if (!seg0) seg0 = hapd->iconf->channel; params |= HE_OPERATION_6GHZ_OPER_INFO; + + /* 6 GHz Operation Information field */ *pos++ = hapd->iconf->channel; /* Primary Channel */ - *pos++ = center_idx_to_bw_6ghz(seg0); /* Control: Channel Width - */ - /* Channel Center Freq Seg0/Seg0 */ + + /* Control: Channel Width */ + if (seg1) + *pos++ = 3; + else + *pos++ = center_idx_to_bw_6ghz(seg0); + + /* Channel Center Freq Seg0/Seg1 */ *pos++ = seg0; - *pos++ = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf); + *pos++ = seg1; /* Minimum Rate */ *pos++ = 6; /* TODO: what should be set here? */ } @@ -402,3 +413,18 @@ u16 copy_sta_he_capab(struct hostapd_data *hapd, struct sta_info *sta, return WLAN_STATUS_SUCCESS; } + + +int hostapd_get_he_twt_responder(struct hostapd_data *hapd, + enum ieee80211_op_mode mode) +{ + u8 *mac_cap; + + if (!hapd->iface->current_mode || + !hapd->iface->current_mode->he_capab[mode].he_supported) + return 0; + + mac_cap = hapd->iface->current_mode->he_capab[mode].mac_cap; + + return !!(mac_cap[HE_MAC_CAPAB_0] & HE_MACCAP_TWT_RESPONDER); +} diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index 6db93658..59ecbdce 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -109,33 +109,9 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) } -u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) -{ - u8 sec_ch; - - if (!hapd->cs_freq_params.channel || - !hapd->cs_freq_params.sec_channel_offset || - is_6ghz_op_class(hapd->iconf->op_class)) - return eid; - - if (hapd->cs_freq_params.sec_channel_offset == -1) - sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; - else if (hapd->cs_freq_params.sec_channel_offset == 1) - sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; - else - return eid; - - *eid++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET; - *eid++ = 1; - *eid++ = sec_ch; - - return eid; -} - - /* op_mode -Set to 0 (HT pure) under the followign conditions +Set to 0 (HT pure) under the following conditions - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or - all STAs in the BSS are 20 MHz HT in 20 MHz BSS Set to 1 (HT non-member protection) if there may be non-HT STAs diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index 1e1cc382..113b4ef0 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -112,7 +112,8 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd, end += oci_ie_len; } #endif /* CONFIG_OCV */ - if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0) < 0) + if (hostapd_drv_send_mlme(hapd, mgmt, end - (u8 *) mgmt, 0, NULL, 0, 0) + < 0) wpa_printf(MSG_INFO, "ieee802_11_send_sa_query_req: send failed"); os_free(mgmt); @@ -193,7 +194,8 @@ static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd, end += oci_ie_len; } #endif /* CONFIG_OCV */ - if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0) < 0) + if (hostapd_drv_send_mlme(hapd, resp, end - (u8 *) resp, 0, NULL, 0, 0) + < 0) wpa_printf(MSG_INFO, "ieee80211_mgmt_sa_query_request: send failed"); os_free(resp); @@ -375,6 +377,11 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) *pos |= 0x01; #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && + hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP)) + *pos |= 0x40; /* Bit 78 - TWT responder */ +#endif /* CONFIG_IEEE80211AX */ break; case 10: /* Bits 80-87 */ #ifdef CONFIG_SAE @@ -390,6 +397,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) * Identifiers Used Exclusively */ } #endif /* CONFIG_SAE */ + if (hapd->conf->beacon_prot) + *pos |= 0x10; /* Bit 84 - Beacon Protection Enabled */ break; } } @@ -438,12 +447,19 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) !wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt)) && len < 10) len = 10; #endif /* CONFIG_FILS */ +#ifdef CONFIG_IEEE80211AX + if (len < 10 && hapd->iconf->ieee80211ax && + hostapd_get_he_twt_responder(hapd, IEEE80211_MODE_AP)) + len = 10; +#endif /* CONFIG_IEEE80211AX */ #ifdef CONFIG_SAE if (len < 11 && hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) && hostapd_sae_pw_id_in_use(hapd->conf)) len = 11; #endif /* CONFIG_SAE */ + if (len < 11 && hapd->conf->beacon_prot) + len = 11; if (len < hapd->iface->extended_capa_len) len = hapd->iface->extended_capa_len; if (len == 0) @@ -858,6 +874,36 @@ u8 * hostapd_eid_owe_trans(struct hostapd_data *hapd, u8 *eid, } +size_t hostapd_eid_dpp_cc_len(struct hostapd_data *hapd) +{ +#ifdef CONFIG_DPP2 + if (hapd->conf->dpp_configurator_connectivity) + return 6; +#endif /* CONFIG_DPP2 */ + return 0; +} + + +u8 * hostapd_eid_dpp_cc(struct hostapd_data *hapd, u8 *eid, size_t len) +{ +#ifdef CONFIG_DPP2 + u8 *pos = eid; + + if (!hapd->conf->dpp_configurator_connectivity || len < 6) + return pos; + + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 4; + WPA_PUT_BE24(pos, OUI_WFA); + pos += 3; + *pos++ = DPP_CC_OUI_TYPE; + + return pos; +#endif /* CONFIG_DPP2 */ + return eid; +} + + void ap_copy_sta_supp_op_classes(struct sta_info *sta, const u8 *supp_op_classes, size_t supp_op_classes_len) @@ -1012,7 +1058,9 @@ u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len) if (!(hapd->conf->wpa & WPA_PROTO_RSN) || !wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) || - (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2) || + (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2 && + !hostapd_sae_pw_id_in_use(hapd->conf)) || + hapd->conf->sae_pwe == 3 || len < 3) return pos; diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index d0810310..6d4d4355 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -137,6 +137,7 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd, } +#ifdef CONFIG_WEP #ifndef CONFIG_FIPS #ifndef CONFIG_NO_RC4 @@ -284,8 +285,9 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) /* TODO: set encryption in TX callback, i.e., only after STA * has ACKed EAPOL-Key frame */ if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, - sta->addr, 0, 1, NULL, 0, ikey, - hapd->conf->individual_wep_key_len)) { + sta->addr, 0, 0, 1, NULL, 0, ikey, + hapd->conf->individual_wep_key_len, + KEY_FLAG_PAIRWISE_RX_TX)) { wpa_printf(MSG_ERROR, "Could not set individual WEP encryption"); } @@ -296,6 +298,7 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta) #endif /* CONFIG_NO_RC4 */ #endif /* CONFIG_FIPS */ +#endif /* CONFIG_WEP */ const char *radius_mode_txt(struct hostapd_data *hapd) @@ -2113,6 +2116,8 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta) } +#ifdef CONFIG_WEP + static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd) { struct eapol_authenticator *eapol = hapd->eapol_auth; @@ -2177,9 +2182,10 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) * after new broadcast key has been sent to all stations. */ if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP, broadcast_ether_addr, - eapol->default_wep_key_idx, 1, NULL, 0, + eapol->default_wep_key_idx, 0, 1, NULL, 0, eapol->default_wep_key, - hapd->conf->default_wep_key_len)) { + hapd->conf->default_wep_key_len, + KEY_FLAG_GROUP_RX_TX_DEFAULT)) { hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_WARNING, "failed to configure a new broadcast key"); @@ -2196,6 +2202,8 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx) } } +#endif /* CONFIG_WEP */ + static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type, const u8 *data, size_t datalen) @@ -2359,6 +2367,7 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx) } +#ifdef CONFIG_WEP static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) { #ifndef CONFIG_FIPS @@ -2370,6 +2379,7 @@ static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx) #endif /* CONFIG_NO_RC4 */ #endif /* CONFIG_FIPS */ } +#endif /* CONFIG_WEP */ static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx, @@ -2420,7 +2430,6 @@ static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp) int ieee802_1x_init(struct hostapd_data *hapd) { - int i; struct eapol_auth_config conf; struct eapol_auth_cb cb; @@ -2431,7 +2440,9 @@ int ieee802_1x_init(struct hostapd_data *hapd) conf.ctx = hapd; conf.eap_reauth_period = hapd->conf->eap_reauth_period; conf.wpa = hapd->conf->wpa; +#ifdef CONFIG_WEP conf.individual_wep_key_len = hapd->conf->individual_wep_key_len; +#endif /* CONFIG_WEP */ conf.eap_req_id_text = hapd->conf->eap_req_id_text; conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len; conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start; @@ -2446,7 +2457,9 @@ int ieee802_1x_init(struct hostapd_data *hapd) cb.logger = ieee802_1x_logger; cb.set_port_authorized = ieee802_1x_set_port_authorized; cb.abort_auth = _ieee802_1x_abort_auth; +#ifdef CONFIG_WEP cb.tx_key = _ieee802_1x_tx_key; +#endif /* CONFIG_WEP */ cb.eapol_event = ieee802_1x_eapol_event; #ifdef CONFIG_ERP cb.erp_get_key = ieee802_1x_erp_get_key; @@ -2467,17 +2480,21 @@ int ieee802_1x_init(struct hostapd_data *hapd) return -1; #endif /* CONFIG_NO_RADIUS */ +#ifdef CONFIG_WEP if (hapd->conf->default_wep_key_len) { + int i; + for (i = 0; i < 4; i++) hostapd_drv_set_key(hapd->conf->iface, hapd, - WPA_ALG_NONE, NULL, i, 0, NULL, 0, - NULL, 0); + WPA_ALG_NONE, NULL, i, 0, 0, NULL, + 0, NULL, 0, KEY_FLAG_GROUP); ieee802_1x_rekey(hapd, NULL); if (!hapd->eapol_auth->default_wep_key) return -1; } +#endif /* CONFIG_WEP */ return 0; } @@ -2497,7 +2514,9 @@ void ieee802_1x_erp_flush(struct hostapd_data *hapd) void ieee802_1x_deinit(struct hostapd_data *hapd) { +#ifdef CONFIG_WEP eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL); +#endif /* CONFIG_WEP */ if (hapd->driver && hapd->drv_priv && (hapd->conf->ieee802_1x || hapd->conf->wpa)) diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c index 4012ae4c..01bf8862 100644 --- a/src/ap/neighbor_db.c +++ b/src/ap/neighbor_db.c @@ -256,6 +256,8 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) /* VHT bit added in IEEE P802.11-REVmc/D4.3 */ if (vht) bssid_info |= NEI_REP_BSSID_INFO_VHT; + if (he) + bssid_info |= NEI_REP_BSSID_INFO_HE; } /* TODO: Set NEI_REP_BSSID_INFO_MOBILITY_DOMAIN if MDE is set */ diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c index 15e2c494..fe5f8171 100644 --- a/src/ap/pmksa_cache_auth.c +++ b/src/ap/pmksa_cache_auth.c @@ -516,6 +516,11 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( for (entry = pmksa->pmksa; entry; entry = entry->next) { if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0) continue; + if (wpa_key_mgmt_sae(entry->akmp)) { + if (os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) + return entry; + continue; + } rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid, entry->akmp); if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index cbb8752e..903be28d 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -164,6 +164,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) /* just in case */ ap_sta_set_authorized(hapd, sta, 0); + hostapd_set_sta_flags(hapd, sta); if (sta->flags & (WLAN_STA_WDS | WLAN_STA_MULTI_AP)) hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0); @@ -233,9 +234,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) sta->assoc_ie_taxonomy = NULL; #endif /* CONFIG_TAXONOMY */ -#ifdef CONFIG_IEEE80211N ht40_intolerant_remove(hapd->iface, sta); -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_P2P if (sta->no_p2p_set) { @@ -246,10 +245,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) } #endif /* CONFIG_P2P */ -#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N) +#ifdef NEED_AP_MLME if (hostapd_ht_operation_update(hapd->iface) > 0) set_beacon++; -#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */ +#endif /* NEED_AP_MLME */ #ifdef CONFIG_MESH if (hapd->mesh_sta_free_cb) @@ -373,6 +372,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) os_free(sta->ifname_wds); +#ifdef CONFIG_TESTING_OPTIONS + os_free(sta->sae_postponed_commit); +#endif /* CONFIG_TESTING_OPTIONS */ + os_free(sta); } @@ -542,6 +545,7 @@ skip_poll: case STA_DISASSOC_FROM_CLI: ap_sta_set_authorized(hapd, sta, 0); sta->flags &= ~WLAN_STA_ASSOC; + hostapd_set_sta_flags(hapd, sta); ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); if (!sta->acct_terminate_cause) sta->acct_terminate_cause = @@ -586,7 +590,8 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); - if (!(sta->flags & WLAN_STA_AUTH)) { + if (!(sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC | + WLAN_STA_AUTHORIZED))) { if (sta->flags & WLAN_STA_GAS) { wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA " "entry " MACSTR, MAC2STR(sta->addr)); @@ -809,6 +814,7 @@ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, sta->timeout_next = STA_DEAUTH; } ap_sta_set_authorized(hapd, sta, 0); + hostapd_set_sta_flags(hapd, sta); wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " "for " MACSTR " (%d seconds - " "AP_MAX_INACTIVITY_AFTER_DISASSOC)", @@ -859,6 +865,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ; sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK); ap_sta_set_authorized(hapd, sta, 0); + hostapd_set_sta_flags(hapd, sta); sta->timeout_next = STA_REMOVE; wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout " "for " MACSTR " (%d seconds - " @@ -1024,6 +1031,13 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) int ret; int old_vlanid = sta->vlan_id_bound; + if ((sta->flags & WLAN_STA_WDS) && sta->vlan_id == 0) { + wpa_printf(MSG_DEBUG, + "Do not override WDS VLAN assignment for STA " + MACSTR, MAC2STR(sta->addr)); + return 0; + } + iface = hapd->conf->iface; if (hapd->conf->ssid.vlan[0]) iface = hapd->conf->ssid.vlan; @@ -1045,7 +1059,8 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta) if (sta->vlan_id == old_vlanid) goto skip_counting; - if (sta->vlan_id > 0 && vlan == NULL) { + if (sta->vlan_id > 0 && !vlan && + !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " "binding station to (vlan_id=%d)", @@ -1129,6 +1144,8 @@ static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx) if (sta->sa_query_count > 0 && ap_check_sa_query_timeout(hapd, sta)) return; + if (sta->sa_query_count >= 1000) + return; nbuf = os_realloc_array(sta->sa_query_trans_id, sta->sa_query_count + 1, @@ -1316,9 +1333,10 @@ void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, if (sta == NULL) return; ap_sta_set_authorized(hapd, sta, 0); + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + hostapd_set_sta_flags(hapd, sta); wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); wpa_printf(MSG_DEBUG, "%s: %s: reschedule ap_handle_timer timeout " "for " MACSTR " (%d seconds - " "AP_MAX_INACTIVITY_AFTER_DEAUTH)", diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index de806b48..8ff6ac62 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -276,6 +276,8 @@ struct sta_info { int last_tk_key_idx; u8 last_tk[WPA_TK_MAX_LEN]; size_t last_tk_len; + u8 *sae_postponed_commit; + size_t sae_postponed_commit_len; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_AIRTIME_POLICY unsigned int airtime_weight; diff --git a/src/ap/utils.c b/src/ap/utils.c index fcb371be..bedad6eb 100644 --- a/src/ap/utils.c +++ b/src/ap/utils.c @@ -56,6 +56,10 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx) ohapd = iface->bss[j]; if (ohapd == data->hapd) continue; +#ifdef CONFIG_TESTING_OPTIONS + if (ohapd->conf->skip_prune_assoc) + continue; +#endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_FST /* Don't prune STAs belong to same FST */ if (ohapd->iface->fst && diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c index e293a003..53eacfb4 100644 --- a/src/ap/vlan_init.c +++ b/src/ap/vlan_init.c @@ -22,7 +22,9 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, int existsok) { - int ret, i; + int ret; +#ifdef CONFIG_WEP + int i; for (i = 0; i < NUM_WEP_KEYS; i++) { if (!hapd->conf->ssid.wep.key[i]) @@ -32,6 +34,7 @@ static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan, vlan->ifname); return -1; } +#endif /* CONFIG_WEP */ if (!iface_exists(vlan->ifname)) ret = hostapd_vlan_if_add(hapd, vlan->ifname); diff --git a/src/ap/wmm.c b/src/ap/wmm.c index 9f52dee3..9ebb01e3 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -111,9 +111,11 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) u8 *pos = eid; struct wmm_parameter_element *wmm = (struct wmm_parameter_element *) (pos + 2); - struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 }; + struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM]; int e; + os_memset(wmmp, 0, sizeof(wmmp)); + if (!hapd->conf->wmm_enabled) return eid; wmm_calc_regulatory_limit(hapd, wmmp); @@ -209,7 +211,7 @@ static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr, os_memcpy(t, tspec, sizeof(struct wmm_tspec_element)); len = ((u8 *) (t + 1)) - buf; - if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0) + if (hostapd_drv_send_mlme(hapd, m, len, 0, NULL, 0, 0) < 0) wpa_printf(MSG_INFO, "wmm_send_action: send failed"); } diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index e4dcfe9e..67281b38 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, size_t len; size_t gtk_elem_len = 0; size_t igtk_elem_len = 0; + size_t bigtk_elem_len = 0; struct wnm_sleep_element wnmsleep_ie; u8 *wnmtfs_ie, *oci_ie; u8 wnmsleep_ie_len, oci_ie_len; @@ -122,8 +123,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, #define MAX_GTK_SUBELEM_LEN 45 #define MAX_IGTK_SUBELEM_LEN 26 +#define MAX_BIGTK_SUBELEM_LEN 26 mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN + + MAX_BIGTK_SUBELEM_LEN + oci_ie_len); if (mgmt == NULL) { wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " @@ -157,10 +160,19 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, pos += igtk_elem_len; wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d", (int) igtk_elem_len); + if (hapd->conf->beacon_prot) { + res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos); + if (res < 0) + goto fail; + bigtk_elem_len = res; + pos += bigtk_elem_len; + wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d", + (int) bigtk_elem_len); + } WPA_PUT_LE16((u8 *) &mgmt->u.action.u.wnm_sleep_resp.keydata_len, - gtk_elem_len + igtk_elem_len); + gtk_elem_len + igtk_elem_len + bigtk_elem_len); } os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len); /* copy TFS IE here */ @@ -176,7 +188,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, #endif /* CONFIG_OCV */ len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len + - igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len; + igtk_elem_len + bigtk_elem_len + + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len; /* In driver, response frame should be forced to sent when STA is in * PS mode */ @@ -189,8 +202,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, /* when entering wnmsleep * 1. pause the node in driver - * 2. mark the node so that AP won't update GTK/IGTK during - * WNM Sleep + * 2. mark the node so that AP won't update GTK/IGTK/BIGTK + * during WNM Sleep */ if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT && wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) { @@ -201,7 +214,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, } /* when exiting wnmsleep * 1. unmark the node - * 2. start GTK/IGTK update if MFP is not used + * 2. start GTK/IGTK/BIGTK update if MFP is not used * 3. unpause the node in driver */ if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT || @@ -221,6 +234,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd, #undef MAX_GTK_SUBELEM_LEN #undef MAX_IGTK_SUBELEM_LEN +#undef MAX_BIGTK_SUBELEM_LEN fail: os_free(wnmtfs_ie); os_free(oci_ie); @@ -508,6 +522,30 @@ static void ieee802_11_rx_bss_trans_mgmt_resp(struct hostapd_data *hapd, } +static void wnm_beacon_protection_failure(struct hostapd_data *hapd, + const u8 *addr) +{ + struct sta_info *sta; + + if (!hapd->conf->beacon_prot) + return; + + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for received WNM-Notification Request", + MAC2STR(addr)); + return; + } + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "Beacon protection failure reported"); + wpa_msg(hapd->msg_ctx, MSG_INFO, WPA_EVENT_UNPROT_BEACON "reporter=" + MACSTR, MAC2STR(addr)); +} + + static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr, const u8 *buf, size_t len) @@ -526,8 +564,14 @@ static void ieee802_11_rx_wnm_notification_req(struct hostapd_data *hapd, MAC2STR(addr), dialog_token, type); wpa_hexdump(MSG_MSGDUMP, "WNM: Notification Request subelements", buf, len); - if (type == WLAN_EID_VENDOR_SPECIFIC) + switch (type) { + case WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE: + wnm_beacon_protection_failure(hapd, addr); + break; + case WNM_NOTIF_TYPE_VENDOR_SPECIFIC: mbo_ap_wnm_notification_req(hapd, addr, buf, len); + break; + } } @@ -641,7 +685,7 @@ int wnm_send_disassoc_imminent(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request frame to indicate imminent disassociation (disassoc_timer=%d) to " MACSTR, disassoc_timer, MAC2STR(sta->addr)); - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " "Management Request frame"); return -1; @@ -714,7 +758,7 @@ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, os_memcpy(pos, url, url_len); pos += url_len; - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { wpa_printf(MSG_DEBUG, "Failed to send BSS Transition " "Management Request frame"); return -1; @@ -790,7 +834,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, mbo_len); } - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { wpa_printf(MSG_DEBUG, "Failed to send BSS Transition Management Request frame"); os_free(buf); @@ -834,7 +878,7 @@ int wnm_send_coloc_intf_req(struct hostapd_data *hapd, struct sta_info *sta, wpa_printf(MSG_DEBUG, "WNM: Sending Collocated Interference Request to " MACSTR " (dialog_token=%u auto_report=%u timeout=%u)", MAC2STR(sta->addr), dialog_token, auto_report, timeout); - if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) { + if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0, NULL, 0, 0) < 0) { wpa_printf(MSG_DEBUG, "WNM: Failed to send Collocated Interference Request frame"); return -1; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 6611b0e5..e0ffb271 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -56,13 +56,14 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, unsigned int pmk_len, - struct wpa_ptk *ptk); + struct wpa_ptk *ptk, int force_sha256); static void wpa_group_free(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_group_get(struct wpa_authenticator *wpa_auth, struct wpa_group *group); static void wpa_group_put(struct wpa_authenticator *wpa_auth, struct wpa_group *group); +static int ieee80211w_kde_len(struct wpa_state_machine *sm); static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos); static const u32 eapol_key_timeout_first = 100; /* ms */ @@ -105,7 +106,7 @@ static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth, static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, wpa_eapol_variable var) { - if (wpa_auth->cb->get_eapol == NULL) + if (!wpa_auth->cb->get_eapol) return -1; return wpa_auth->cb->get_eapol(wpa_auth->cb_ctx, addr, var); } @@ -117,7 +118,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, const u8 *prev_psk, size_t *psk_len, int *vlan_id) { - if (wpa_auth->cb->get_psk == NULL) + if (!wpa_auth->cb->get_psk) return NULL; return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr, prev_psk, psk_len, vlan_id); @@ -127,7 +128,7 @@ static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth, static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, const u8 *addr, u8 *msk, size_t *len) { - if (wpa_auth->cb->get_msk == NULL) + if (!wpa_auth->cb->get_msk) return -1; return wpa_auth->cb->get_msk(wpa_auth->cb_ctx, addr, msk, len); } @@ -136,21 +137,46 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth, static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, - u8 *key, size_t key_len) + u8 *key, size_t key_len, + enum key_flag key_flag) { - if (wpa_auth->cb->set_key == NULL) + if (!wpa_auth->cb->set_key) return -1; return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx, - key, key_len); + key, key_len, key_flag); } static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth, const u8 *addr, int idx, u8 *seq) { - if (wpa_auth->cb->get_seqnum == NULL) + int res; + + if (!wpa_auth->cb->get_seqnum) return -1; - return wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq); + res = wpa_auth->cb->get_seqnum(wpa_auth->cb_ctx, addr, idx, seq); +#ifdef CONFIG_TESTING_OPTIONS + if (!addr && idx < 4 && wpa_auth->conf.gtk_rsc_override_set) { + wpa_printf(MSG_DEBUG, + "TESTING: Override GTK RSC %016llx --> %016llx", + (long long unsigned) WPA_GET_LE64(seq), + (long long unsigned) + WPA_GET_LE64(wpa_auth->conf.gtk_rsc_override)); + os_memcpy(seq, wpa_auth->conf.gtk_rsc_override, + WPA_KEY_RSC_LEN); + } + if (!addr && idx >= 4 && idx <= 5 && + wpa_auth->conf.igtk_rsc_override_set) { + wpa_printf(MSG_DEBUG, + "TESTING: Override IGTK RSC %016llx --> %016llx", + (long long unsigned) WPA_GET_LE64(seq), + (long long unsigned) + WPA_GET_LE64(wpa_auth->conf.igtk_rsc_override)); + os_memcpy(seq, wpa_auth->conf.igtk_rsc_override, + WPA_KEY_RSC_LEN); + } +#endif /* CONFIG_TESTING_OPTIONS */ + return res; } @@ -158,7 +184,7 @@ static inline int wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, const u8 *data, size_t data_len, int encrypt) { - if (wpa_auth->cb->send_eapol == NULL) + if (!wpa_auth->cb->send_eapol) return -1; return wpa_auth->cb->send_eapol(wpa_auth->cb_ctx, addr, data, data_len, encrypt); @@ -169,7 +195,7 @@ wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr, static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth, const u8 *addr) { - if (wpa_auth->cb->start_ampe == NULL) + if (!wpa_auth->cb->start_ampe) return -1; return wpa_auth->cb->start_ampe(wpa_auth->cb_ctx, addr); } @@ -180,7 +206,7 @@ int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth, int (*cb)(struct wpa_state_machine *sm, void *ctx), void *cb_ctx) { - if (wpa_auth->cb->for_each_sta == NULL) + if (!wpa_auth->cb->for_each_sta) return 0; return wpa_auth->cb->for_each_sta(wpa_auth->cb_ctx, cb, cb_ctx); } @@ -190,7 +216,7 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, int (*cb)(struct wpa_authenticator *a, void *ctx), void *cb_ctx) { - if (wpa_auth->cb->for_each_auth == NULL) + if (!wpa_auth->cb->for_each_auth) return 0; return wpa_auth->cb->for_each_auth(wpa_auth->cb_ctx, cb, cb_ctx); } @@ -199,7 +225,7 @@ int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth, void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr, logger_level level, const char *txt) { - if (wpa_auth->cb->logger == NULL) + if (!wpa_auth->cb->logger) return; wpa_auth->cb->logger(wpa_auth->cb_ctx, addr, level, txt); } @@ -212,7 +238,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, int maxlen; va_list ap; - if (wpa_auth->cb->logger == NULL) + if (!wpa_auth->cb->logger) return; maxlen = os_strlen(fmt) + 100; @@ -233,7 +259,7 @@ void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr, static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth, const u8 *addr, u16 reason) { - if (wpa_auth->cb->disconnect == NULL) + if (!wpa_auth->cb->disconnect) return; wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR " (reason %u)", MAC2STR(addr), reason); @@ -266,8 +292,8 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx) struct wpa_authenticator *wpa_auth = eloop_ctx; if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) { - wpa_printf(MSG_ERROR, "Failed to get random data for WPA " - "initialization."); + wpa_printf(MSG_ERROR, + "Failed to get random data for WPA initialization."); } else { wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd"); wpa_hexdump_key(MSG_DEBUG, "GMK", @@ -391,7 +417,7 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, struct wpa_group *group; group = os_zalloc(sizeof(struct wpa_group)); - if (group == NULL) + if (!group) return NULL; group->GTKAuthenticator = TRUE; @@ -399,9 +425,8 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group); if (random_pool_ready() != 1) { - wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " - "for secure operations - update keys later when " - "the first station connects"); + wpa_printf(MSG_INFO, + "WPA: Not enough entropy in random pool for secure operations - update keys later when the first station connects"); } /* @@ -411,16 +436,16 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth, * on embedded devices. */ if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) { - wpa_printf(MSG_ERROR, "Failed to get random data for WPA " - "initialization."); + wpa_printf(MSG_ERROR, + "Failed to get random data for WPA initialization."); os_free(group); return NULL; } group->GInit = TRUE; if (delay_init) { - wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start " - "until Beacon frames have been configured"); + wpa_printf(MSG_DEBUG, + "WPA: Delay group state machine start until Beacon frames have been configured"); /* Initialization is completed in wpa_init_keys(). */ } else { wpa_group_sm_step(wpa_auth, group); @@ -447,7 +472,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, struct wpa_authenticator *wpa_auth; wpa_auth = os_zalloc(sizeof(struct wpa_authenticator)); - if (wpa_auth == NULL) + if (!wpa_auth) return NULL; os_memcpy(wpa_auth->addr, addr, ETH_ALEN); os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); @@ -461,7 +486,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, } wpa_auth->group = wpa_group_init(wpa_auth, 0, 1); - if (wpa_auth->group == NULL) { + if (!wpa_auth->group) { os_free(wpa_auth->wpa_ie); os_free(wpa_auth); return NULL; @@ -469,7 +494,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb, wpa_auth); - if (wpa_auth->pmksa == NULL) { + if (!wpa_auth->pmksa) { wpa_printf(MSG_ERROR, "PMKSA cache initialization failed."); os_free(wpa_auth->group); os_free(wpa_auth->wpa_ie); @@ -479,7 +504,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr, #ifdef CONFIG_IEEE80211R_AP wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init(); - if (wpa_auth->ft_pmk_cache == NULL) { + if (!wpa_auth->ft_pmk_cache) { wpa_printf(MSG_ERROR, "FT PMK cache initialization failed."); os_free(wpa_auth->group); os_free(wpa_auth->wpa_ie); @@ -518,8 +543,8 @@ int wpa_init_keys(struct wpa_authenticator *wpa_auth) { struct wpa_group *group = wpa_auth->group; - wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial " - "keys"); + wpa_printf(MSG_DEBUG, + "WPA: Start group state machine to set initial keys"); wpa_group_sm_step(wpa_auth, group); group->GInit = FALSE; wpa_group_sm_step(wpa_auth, group); @@ -575,7 +600,8 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth, struct wpa_auth_config *conf) { struct wpa_group *group; - if (wpa_auth == NULL) + + if (!wpa_auth) return 0; os_memcpy(&wpa_auth->conf, conf, sizeof(*conf)); @@ -609,7 +635,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, return NULL; sm = os_zalloc(sizeof(struct wpa_state_machine)); - if (sm == NULL) + if (!sm) return NULL; os_memcpy(sm->addr, addr, ETH_ALEN); if (p2p_dev_addr) @@ -626,14 +652,13 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr, int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm) { - if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) + if (!wpa_auth || !wpa_auth->conf.wpa || !sm) return -1; #ifdef CONFIG_IEEE80211R_AP if (sm->ft_completed) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, - "FT authentication already completed - do not " - "start 4-way handshake"); + "FT authentication already completed - do not start 4-way handshake"); /* Go to PTKINITDONE state to allow GTK rekeying */ sm->wpa_ptk_state = WPA_PTK_PTKINITDONE; sm->Pair = TRUE; @@ -676,7 +701,7 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm) /* WPA/RSN was not used - clear WPA state. This is needed if the STA * reassociates back to the same AP while the previous entry for the * STA has not yet been removed. */ - if (sm == NULL) + if (!sm) return; sm->wpa_key_mgmt = 0; @@ -688,8 +713,9 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) #ifdef CONFIG_P2P if (WPA_GET_BE32(sm->ip_addr)) { u32 start; - wpa_printf(MSG_DEBUG, "P2P: Free assigned IP " - "address %u.%u.%u.%u from " MACSTR, + wpa_printf(MSG_DEBUG, + "P2P: Free assigned IP address %u.%u.%u.%u from " + MACSTR, sm->ip_addr[0], sm->ip_addr[1], sm->ip_addr[2], sm->ip_addr[3], MAC2STR(sm->addr)); @@ -719,31 +745,34 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm) void wpa_auth_sta_deinit(struct wpa_state_machine *sm) { - if (sm == NULL) + struct wpa_authenticator *wpa_auth; + + if (!sm) return; - if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "strict rekeying - force GTK rekey since STA " - "is leaving"); + wpa_auth = sm->wpa_auth; + if (wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) { + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, + "strict rekeying - force GTK rekey since STA is leaving"); if (eloop_deplete_timeout(0, 500000, wpa_rekey_gtk, - sm->wpa_auth, NULL) == -1) - eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth, - NULL); + wpa_auth, NULL) == -1) + eloop_register_timeout(0, 500000, wpa_rekey_gtk, + wpa_auth, NULL); } - eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm); + eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); sm->pending_1_of_4_timeout = 0; eloop_cancel_timeout(wpa_sm_call_step, sm, NULL); - eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); + eloop_cancel_timeout(wpa_rekey_ptk, wpa_auth, sm); #ifdef CONFIG_IEEE80211R_AP wpa_ft_sta_deinit(sm); #endif /* CONFIG_IEEE80211R_AP */ if (sm->in_step_loop) { /* Must not free state machine while wpa_sm_step() is running. * Freeing will be completed in the end of wpa_sm_step(). */ - wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state " - "machine deinit for " MACSTR, MAC2STR(sm->addr)); + wpa_printf(MSG_DEBUG, + "WPA: Registering pending STA state machine deinit for " + MACSTR, MAC2STR(sm->addr)); sm->pending_deinit = 1; } else wpa_free_sta_sm(sm); @@ -752,11 +781,23 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm) static void wpa_request_new_ptk(struct wpa_state_machine *sm) { - if (sm == NULL) + if (!sm) return; - sm->PTKRequest = TRUE; - sm->PTK_valid = 0; + if (!sm->use_ext_key_id && sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { + wpa_printf(MSG_INFO, + "WPA: PTK0 rekey not allowed, disconnect " MACSTR, + MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + /* Try to encourage the STA to reconnect */ + sm->disconnect_reason = + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; + } else { + if (sm->use_ext_key_id) + sm->keyidx_active ^= 1; /* flip Key ID */ + sm->PTKRequest = TRUE; + sm->PTK_valid = 0; + } } @@ -781,7 +822,7 @@ static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr, int i; for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { if (ctr[i].valid && - (replay_counter == NULL || + (!replay_counter || os_memcmp(replay_counter, ctr[i].counter, WPA_REPLAY_COUNTER_LEN) == 0)) ctr[i].valid = FALSE; @@ -798,9 +839,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, struct rsn_mdie *mdie; if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 || - ie.num_pmkid != 1 || ie.pmkid == NULL) { - wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in " - "FT 4-way handshake message 2/4"); + ie.num_pmkid != 1 || !ie.pmkid) { + wpa_printf(MSG_DEBUG, + "FT: No PMKR1Name in FT 4-way handshake message 2/4"); return -1; } @@ -809,8 +850,9 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth, sm->sup_pmk_r1_name, PMKID_LEN); if (!kde->mdie || !kde->ftie) { - wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake " - "message 2/4", kde->mdie ? "FTIE" : "MDIE"); + wpa_printf(MSG_DEBUG, + "FT: No %s in FT 4-way handshake message 2/4", + kde->mdie ? "FTIE" : "MDIE"); return -1; } @@ -844,18 +886,15 @@ static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth, { /* Supplicant reported a Michael MIC error */ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key Error Request " - "(STA detected Michael MIC failure (group=%d))", + "received EAPOL-Key Error Request (STA detected Michael MIC failure (group=%d))", group); if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "ignore Michael MIC failure report since " - "group cipher is not TKIP"); + "ignore Michael MIC failure report since group cipher is not TKIP"); } else if (!group && sm->pairwise != WPA_CIPHER_TKIP) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "ignore Michael MIC failure report since " - "pairwise cipher is not TKIP"); + "ignore Michael MIC failure report since pairwise cipher is not TKIP"); } else { if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0) return 1; /* STA entry was removed */ @@ -888,7 +927,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, pmk, &pmk_len, &vlan_id); - if (pmk == NULL) + if (!pmk) break; #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt)) { @@ -901,7 +940,8 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data, pmk_len = sm->pmk_len; } - if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0) + if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK, 0) < + 0) break; if (wpa_verify_key_mic(sm->wpa_key_mgmt, pmk_len, &PTK, @@ -956,7 +996,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, size_t keyhdrlen, mic_len; u8 *mic; - if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL) + if (!wpa_auth || !wpa_auth->conf.wpa || !sm) return; wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL data", data, data_len); @@ -975,20 +1015,19 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, key_data = mic + mic_len + 2; key_data_length = WPA_GET_BE16(mic + mic_len); wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR - " key_info=0x%x type=%u mic_len=%u key_data_length=%u", + " key_info=0x%x type=%u mic_len=%zu key_data_length=%u", MAC2STR(sm->addr), key_info, key->type, - (unsigned int) mic_len, key_data_length); + mic_len, key_data_length); wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key header (ending before Key MIC)", key, sizeof(*key)); wpa_hexdump(MSG_MSGDUMP, "WPA: EAPOL-Key Key MIC", mic, mic_len); if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) { - wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - " - "key_data overflow (%d > %lu)", + wpa_printf(MSG_INFO, + "WPA: Invalid EAPOL-Key frame - key_data overflow (%d > %zu)", key_data_length, - (unsigned long) (data_len - sizeof(*hdr) - - keyhdrlen)); + data_len - sizeof(*hdr) - keyhdrlen); return; } @@ -998,18 +1037,18 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, * Some deployed station implementations seem to send * msg 4/4 with incorrect type value in WPA2 mode. */ - wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key " - "with unexpected WPA type in RSN mode"); + wpa_printf(MSG_DEBUG, + "Workaround: Allow EAPOL-Key with unexpected WPA type in RSN mode"); } else if (key->type != EAPOL_KEY_TYPE_RSN) { - wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " - "unexpected type %d in RSN mode", + wpa_printf(MSG_DEBUG, + "Ignore EAPOL-Key with unexpected type %d in RSN mode", key->type); return; } } else { if (key->type != EAPOL_KEY_TYPE_WPA) { - wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with " - "unexpected type %d in WPA mode", + wpa_printf(MSG_DEBUG, + "Ignore EAPOL-Key with unexpected type %d in WPA mode", key->type); return; } @@ -1054,9 +1093,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, - "advertised support for " - "AES-128-CMAC, but did not " - "use it"); + "advertised support for AES-128-CMAC, but did not use it"); return; } @@ -1065,8 +1102,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, - "did not use HMAC-SHA1-AES " - "with CCMP/GCMP"); + "did not use HMAC-SHA1-AES with CCMP/GCMP"); return; } } @@ -1084,8 +1120,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, os_memcmp(key->replay_counter, sm->req_replay_counter, WPA_REPLAY_COUNTER_LEN) <= 0) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING, - "received EAPOL-Key request with " - "replayed counter"); + "received EAPOL-Key request with replayed counter"); return; } } @@ -1108,9 +1143,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, * even if we have already sent out EAPOL-Key 3/4. */ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "Process SNonce update from STA " - "based on retransmitted EAPOL-Key " - "1/4"); + "Process SNonce update from STA based on retransmitted EAPOL-Key 1/4"); sm->update_snonce = 1; os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN); sm->alt_snonce_valid = TRUE; @@ -1139,12 +1172,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, key->replay_counter) && sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "ignore retransmitted EAPOL-Key %s - " - "SNonce did not change", msgtxt); + "ignore retransmitted EAPOL-Key %s - SNonce did not change", + msgtxt); } else { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, - "received EAPOL-Key %s with " - "unexpected replay counter", msgtxt); + "received EAPOL-Key %s with unexpected replay counter", + msgtxt); } for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) { if (!sm->key_replay[i].valid) @@ -1175,8 +1208,7 @@ continue_processing: (!sm->update_snonce || sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 2/4 in " - "invalid state (%d) - dropped", + "received EAPOL-Key msg 2/4 in invalid state (%d) - dropped", sm->wpa_ptk_state); return; } @@ -1191,9 +1223,8 @@ continue_processing: * Counter update and the station will be allowed to * continue. */ - wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to " - "collect more entropy for random number " - "generation"); + wpa_printf(MSG_DEBUG, + "WPA: Reject 4-way handshake to collect more entropy for random number generation"); random_mark_pool_ready(); wpa_sta_disconnect(wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); @@ -1204,8 +1235,7 @@ continue_processing: if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING || !sm->PTK_valid) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 4/4 in " - "invalid state (%d) - dropped", + "received EAPOL-Key msg 4/4 in invalid state (%d) - dropped", sm->wpa_ptk_state); return; } @@ -1214,8 +1244,7 @@ continue_processing: if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING || !sm->PTK_valid) { wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key msg 2/2 in " - "invalid state (%d) - dropped", + "received EAPOL-Key msg 2/2 in invalid state (%d) - dropped", sm->wpa_ptk_group_state); return; } @@ -1294,8 +1323,7 @@ continue_processing: WPA_REPLAY_COUNTER_LEN); } else { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key request with " - "invalid MIC"); + "received EAPOL-Key request with invalid MIC"); return; } @@ -1311,8 +1339,7 @@ continue_processing: return; /* STA entry was removed */ } else if (key_info & WPA_KEY_INFO_KEY_TYPE) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key Request for new " - "4-Way Handshake"); + "received EAPOL-Key Request for new 4-Way Handshake"); wpa_request_new_ptk(sm); } else if (key_data_length > 0 && wpa_parse_kde_ies(key_data, key_data_length, @@ -1320,8 +1347,7 @@ continue_processing: kde.mac_addr) { } else { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, - "received EAPOL-Key Request for GTK " - "rekeying"); + "received EAPOL-Key Request for GTK rekeying"); eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL); wpa_rekey_gtk(wpa_auth, NULL); } @@ -1354,7 +1380,7 @@ continue_processing: os_free(sm->last_rx_eapol_key); sm->last_rx_eapol_key = os_memdup(data, data_len); - if (sm->last_rx_eapol_key == NULL) + if (!sm->last_rx_eapol_key) return; sm->last_rx_eapol_key_len = data_len; @@ -1433,6 +1459,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *kde, size_t kde_len, int keyidx, int encr, int force_version) { + struct wpa_auth_config *conf = &wpa_auth->conf; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; size_t len, mic_len, keyhdrlen; @@ -1461,15 +1488,14 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, pairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE); - wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d " - "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d " - "encr=%d)", + wpa_printf(MSG_DEBUG, + "WPA: Send EAPOL(version=%d secure=%d mic=%d ack=%d install=%d pairwise=%d kde_len=%zu keyidx=%d encr=%d)", version, (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0, (key_info & WPA_KEY_INFO_MIC) ? 1 : 0, (key_info & WPA_KEY_INFO_ACK) ? 1 : 0, (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0, - pairwise, (unsigned long) kde_len, keyidx, encr); + pairwise, kde_len, keyidx, encr); key_data_len = kde_len; @@ -1487,9 +1513,9 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, len += AES_BLOCK_SIZE; hdr = os_zalloc(len); - if (hdr == NULL) + if (!hdr) return; - hdr->version = wpa_auth->conf.eapol_version; + hdr->version = conf->eapol_version; hdr->type = IEEE802_1X_TYPE_EAPOL_KEY; hdr->length = host_to_be16(len - sizeof(*hdr)); key = (struct wpa_eapol_key *) (hdr + 1); @@ -1505,7 +1531,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT; WPA_PUT_BE16(key->key_info, key_info); - alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group; + alg = pairwise ? sm->pairwise : conf->wpa_group; if (sm->wpa == WPA_VERSION_WPA2 && !pairwise) WPA_PUT_BE16(key->key_length, 0); else @@ -1559,7 +1585,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_FILS */ } else if (encr && kde) { buf = os_zalloc(key_data_len); - if (buf == NULL) { + if (!buf) { os_free(hdr); return; } @@ -1576,8 +1602,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, wpa_use_aes_key_wrap(sm->wpa_key_mgmt) || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { wpa_printf(MSG_DEBUG, - "WPA: Encrypt Key Data using AES-WRAP (KEK length %u)", - (unsigned int) sm->PTK.kek_len); + "WPA: Encrypt Key Data using AES-WRAP (KEK length %zu)", + sm->PTK.kek_len); if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, (key_data_len - 8) / 8, buf, key_data)) { os_free(hdr); @@ -1611,8 +1637,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (key_info & WPA_KEY_INFO_MIC) { if (!sm->PTK_valid || !mic_len) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, - "PTK not valid when sending EAPOL-Key " - "frame"); + "PTK not valid when sending EAPOL-Key frame"); os_free(hdr); return; } @@ -1625,9 +1650,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, } #ifdef CONFIG_TESTING_OPTIONS if (!pairwise && - wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 && - drand48() < - wpa_auth->conf.corrupt_gtk_rekey_mic_probability) { + conf->corrupt_gtk_rekey_mic_probability > 0.0 && + drand48() < conf->corrupt_gtk_rekey_mic_probability) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "Corrupting group EAPOL-Key Key MIC"); key_mic[0]++; @@ -1635,8 +1659,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, #endif /* CONFIG_TESTING_OPTIONS */ } - wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, - 1); + wpa_auth_set_eapol(wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx, 1); wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len, sm->pairwise_set); os_free(hdr); @@ -1653,7 +1676,7 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE; u32 ctr; - if (sm == NULL) + if (!sm) return; __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len, @@ -1673,8 +1696,9 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth, #ifdef TEST_FUZZ timeout_ms = 1; #endif /* TEST_FUZZ */ - wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry " - "counter %u)", timeout_ms, ctr); + wpa_printf(MSG_DEBUG, + "WPA: Use EAPOL-Key timeout of %u ms (retry counter %u)", + timeout_ms, ctr); eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000, wpa_send_eapol_timeout, wpa_auth, sm); } @@ -1714,9 +1738,14 @@ void wpa_remove_ptk(struct wpa_state_machine *sm) sm->PTK_valid = FALSE; os_memset(&sm->PTK, 0, sizeof(sm->PTK)); if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, - 0)) + 0, KEY_FLAG_PAIRWISE)) wpa_printf(MSG_DEBUG, "RSN: PTK removal from the driver failed"); + if (sm->use_ext_key_id && + wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 1, NULL, + 0, KEY_FLAG_PAIRWISE)) + wpa_printf(MSG_DEBUG, + "RSN: PTK Key ID 1 removal from the driver failed"); sm->pairwise_set = FALSE; eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm); } @@ -1726,7 +1755,7 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) { int remove_ptk = 1; - if (sm == NULL) + if (!sm) return -1; wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, @@ -1766,8 +1795,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) * sure that the WPA state machines gets initialized * properly at this point. */ - wpa_printf(MSG_DEBUG, "WPA state machine had not been " - "started - initialize now"); + wpa_printf(MSG_DEBUG, + "WPA state machine had not been started - initialize now"); sm->started = 1; sm->Init = TRUE; if (wpa_sm_step(sm) == 1) @@ -1776,6 +1805,22 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) sm->AuthenticationRequest = TRUE; break; } + + if (!sm->use_ext_key_id && + sm->wpa_auth->conf.wpa_deny_ptk0_rekey) { + wpa_printf(MSG_INFO, + "WPA: PTK0 rekey not allowed, disconnect " + MACSTR, MAC2STR(sm->addr)); + sm->Disconnect = TRUE; + /* Try to encourage the STA to reconnect */ + sm->disconnect_reason = + WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA; + break; + } + + if (sm->use_ext_key_id) + sm->keyidx_active ^= 1; /* flip Key ID */ + if (sm->GUpdateStationKeys) { /* * Reauthentication cancels the pending group key @@ -1789,8 +1834,8 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event) break; case WPA_ASSOC_FT: #ifdef CONFIG_IEEE80211R_AP - wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration " - "after association"); + wpa_printf(MSG_DEBUG, + "FT: Retry PTK configuration after association"); wpa_ft_install_ptk(sm); /* Using FT protocol, not WPA auth state machine */ @@ -1923,11 +1968,11 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth, * GMK and Counter here to improve their strength if there was not * enough entropy available immediately after system startup. */ - wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first " - "station"); + wpa_printf(MSG_DEBUG, + "WPA: Re-initialize GMK/Counter on first station"); if (random_pool_ready() != 1) { - wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool " - "to proceed - reject first 4-way handshake"); + wpa_printf(MSG_INFO, + "WPA: Not enough entropy in random pool to proceed - reject first 4-way handshake"); group->reject_4way_hs_for_entropy = TRUE; } else { group->first_sta_seen = TRUE; @@ -1961,8 +2006,8 @@ SM_STATE(WPA_PTK, AUTHENTICATION2) * stronger protection against potential precomputation attacks. */ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { - wpa_printf(MSG_ERROR, "WPA: Failed to get random data for " - "ANonce."); + wpa_printf(MSG_ERROR, + "WPA: Failed to get random data for ANonce."); sm->Disconnect = TRUE; return; } @@ -2019,13 +2064,13 @@ SM_STATE(WPA_PTK, INITPMK) pmk_len = PMK_LEN_SUITE_B_192; else pmk_len = PMK_LEN; - wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine " - "(MSK len=%lu PMK len=%u)", (unsigned long) len, - pmk_len); + wpa_printf(MSG_DEBUG, + "WPA: PMK from EAPOL state machine (MSK len=%zu PMK len=%u)", + len, pmk_len); if (len < pmk_len) { wpa_printf(MSG_DEBUG, - "WPA: MSK not long enough (%u) to create PMK (%u)", - (unsigned int) len, (unsigned int) pmk_len); + "WPA: MSK not long enough (%zu) to create PMK (%u)", + len, pmk_len); sm->Disconnect = TRUE; return; } @@ -2208,10 +2253,11 @@ SM_STATE(WPA_PTK, PTKSTART) static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, const u8 *pmk, unsigned int pmk_len, - struct wpa_ptk *ptk) + struct wpa_ptk *ptk, int force_sha256) { const u8 *z = NULL; size_t z_len = 0; + int akmp; #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { @@ -2237,9 +2283,12 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce, } #endif /* CONFIG_DPP2 */ + akmp = sm->wpa_key_mgmt; + if (force_sha256) + akmp |= WPA_KEY_MGMT_PSK_SHA256; return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion", sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce, - ptk, sm->wpa_key_mgmt, sm->pairwise, z, z_len); + ptk, akmp, sm->pairwise, z, z_len); } @@ -2453,9 +2502,9 @@ int wpa_fils_validate_key_confirm(struct wpa_state_machine *sm, const u8 *ies, if (elems.fils_key_confirm_len != sm->fils_key_auth_len) { wpa_printf(MSG_DEBUG, - "FILS: Unexpected Key-Auth length %d (expected %d)", + "FILS: Unexpected Key-Auth length %d (expected %zu)", elems.fils_key_confirm_len, - (int) sm->fils_key_auth_len); + sm->fils_key_auth_len); return -1; } @@ -2648,8 +2697,13 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, u8 *gtk, dummy_gtk[32]; size_t gtk_len; struct wpa_group *gsm; + size_t plain_len; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; - plain = wpabuf_alloc(1000); + plain_len = 1000 + ieee80211w_kde_len(sm); + if (conf->transition_disable) + plain_len += 2 + RSN_SELECTOR_LEN + 1; + plain = wpabuf_alloc(plain_len); if (!plain) return NULL; @@ -2678,8 +2732,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, /* GTK KDE */ gtk = gsm->GTK[gsm->GN - 1]; gtk_len = gsm->GTK_len; - if (sm->wpa_auth->conf.disable_gtk || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { + if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random GTK to each STA to prevent use * of GTK in the BSS. @@ -2697,11 +2750,18 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm, gtk, gtk_len); wpabuf_put(plain, tmp2 - tmp); - /* IGTK KDE */ + /* IGTK KDE and BIGTK KDE */ tmp = wpabuf_put(plain, 0); tmp2 = ieee80211w_kde_add(sm, tmp); wpabuf_put(plain, tmp2 - tmp); + if (conf->transition_disable) { + tmp = wpabuf_put(plain, 0); + tmp2 = wpa_add_kde(tmp, WFA_KEY_DATA_TRANSITION_DISABLE, + &conf->transition_disable, 1, NULL, 0); + wpabuf_put(plain, tmp2 - tmp); + } + *len = (u8 *) wpabuf_put(plain, 0) - len - 1; #ifdef CONFIG_OCV @@ -2747,7 +2807,7 @@ int fils_set_tk(struct wpa_state_machine *sm) wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver"); if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk, klen)) { + sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) { wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver"); return -1; } @@ -2779,8 +2839,8 @@ u8 * hostapd_eid_assoc_fils_session(struct wpa_state_machine *sm, u8 *buf, os_memcpy(pos, wpabuf_head(plain), wpabuf_len(plain)); pos += wpabuf_len(plain); - wpa_printf(MSG_DEBUG, "%s: plain buf_len: %u", __func__, - (unsigned int) wpabuf_len(plain)); + wpa_printf(MSG_DEBUG, "%s: plain buf_len: %zu", __func__, + wpabuf_len(plain)); wpabuf_clear_free(plain); sm->fils_completed = 1; return pos; @@ -2819,6 +2879,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) struct wpa_eapol_key *key; struct wpa_eapol_ie_parse kde; int vlan_id = 0; + int owe_ptk_workaround = !!wpa_auth->conf.owe_ptk_workaround; SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk); sm->EAPOLKeyReceived = FALSE; @@ -2836,7 +2897,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, pmk, &pmk_len, &vlan_id); - if (pmk == NULL) + if (!pmk) break; psk_found = 1; #ifdef CONFIG_IEEE80211R_AP @@ -2856,7 +2917,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) pmk_len = sm->pmksa->pmk_len; } - if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0) + if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK, + owe_ptk_workaround == 2) < 0) break; if (mic_len && @@ -2880,6 +2942,16 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) } #endif /* CONFIG_FILS */ +#ifdef CONFIG_OWE + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OWE && pmk_len > 32 && + owe_ptk_workaround == 1) { + wpa_printf(MSG_DEBUG, + "OWE: Try PTK derivation workaround with SHA256"); + owe_ptk_workaround = 2; + continue; + } +#endif /* CONFIG_OWE */ + if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) || wpa_key_mgmt_sae(sm->wpa_key_mgmt)) break; @@ -2922,7 +2994,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) eapol_key_ie_len = kde.wpa_ie_len; } ft = sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt); - if (sm->wpa_ie == NULL || + if (!sm->wpa_ie || wpa_compare_rsn_ie(ft, sm->wpa_ie, sm->wpa_ie_len, eapol_key_ie, eapol_key_ie_len)) { wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, @@ -3016,10 +3088,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "PMKR1Name mismatch in FT 4-way " - "handshake"); - wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from " - "Supplicant", + "PMKR1Name mismatch in FT 4-way handshake"); + wpa_hexdump(MSG_DEBUG, + "FT: PMKR1Name from Supplicant", sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name", sm->pmk_r1_name, WPA_PMK_NAME_LEN); @@ -3063,22 +3134,29 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2) static int ieee80211w_kde_len(struct wpa_state_machine *sm) { + size_t len = 0; + if (sm->mgmt_frame_prot) { - size_t len; - len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); - return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len; + len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN; + len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + } + if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) { + len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN; + len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); } - return 0; + return len; } static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) { struct wpa_igtk_kde igtk; + struct wpa_bigtk_kde bigtk; struct wpa_group *gsm = sm->group; u8 rsc[WPA_KEY_RSC_LEN]; - size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + struct wpa_auth_config *conf = &sm->wpa_auth->conf; + size_t len = wpa_cipher_key_len(conf->group_mgmt_cipher); if (!sm->mgmt_frame_prot) return pos; @@ -3091,8 +3169,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) else os_memcpy(igtk.pn, rsc, sizeof(igtk.pn)); os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len); - if (sm->wpa_auth->conf.disable_gtk || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { + if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random IGTK to each STA to prevent use of * IGTK in the BSS. @@ -3104,6 +3181,21 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len, NULL, 0); + if (!conf->beacon_prot) + return pos; + + bigtk.keyid[0] = gsm->GN_bigtk; + bigtk.keyid[1] = 0; + if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE || + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0) + os_memset(bigtk.pn, 0, sizeof(bigtk.pn)); + else + os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn)); + os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len); + pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK, + (const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len, + NULL, 0); + return pos; } @@ -3138,41 +3230,73 @@ static int ocv_oci_add(struct wpa_state_machine *sm, u8 **argpos) } +#ifdef CONFIG_TESTING_OPTIONS +static u8 * replace_ie(const char *name, const u8 *old_buf, size_t *len, u8 eid, + const u8 *ie, size_t ie_len) +{ + const u8 *elem; + u8 *buf; + + wpa_printf(MSG_DEBUG, "TESTING: %s EAPOL override", name); + wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie before override", + old_buf, *len); + buf = os_malloc(*len + ie_len); + if (!buf) + return NULL; + os_memcpy(buf, old_buf, *len); + elem = get_ie(buf, *len, eid); + if (elem) { + u8 elem_len = 2 + elem[1]; + + os_memmove((void *) elem, elem + elem_len, + *len - (elem - buf) - elem_len); + *len -= elem_len; + } + os_memcpy(buf + *len, ie, ie_len); + *len += ie_len; + wpa_hexdump(MSG_DEBUG, "TESTING: wpa_ie after EAPOL override", + buf, *len); + + return buf; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + SM_STATE(WPA_PTK, PTKINITNEGOTIATING) { u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde = NULL, *pos, dummy_gtk[32]; - size_t gtk_len, kde_len; + size_t gtk_len, kde_len, wpa_ie_len; struct wpa_group *gsm = sm->group; u8 *wpa_ie; - int wpa_ie_len, secure, gtkidx, encr = 0; - u8 *wpa_ie_buf = NULL; + int secure, gtkidx, encr = 0; + u8 *wpa_ie_buf = NULL, *wpa_ie_buf2 = NULL; + u8 hdr[2]; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk); sm->TimeoutEvt = FALSE; sm->TimeoutCtr++; - if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries && - sm->TimeoutCtr > 1) { + if (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1) { /* Do not allow retransmission of EAPOL-Key msg 3/4 */ return; } - if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) { + if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ return; } /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], - GTK[GN], IGTK, [FTIE], [TIE * 2]) + GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2]) */ os_memset(rsc, 0, WPA_KEY_RSC_LEN); wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc); /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */ wpa_ie = sm->wpa_auth->wpa_ie; wpa_ie_len = sm->wpa_auth->wpa_ie_len; - if (sm->wpa == WPA_VERSION_WPA && - (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) && - wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) { + if (sm->wpa == WPA_VERSION_WPA && (conf->wpa & WPA_PROTO_RSN) && + wpa_ie_len > wpa_ie[1] + 2U && wpa_ie[0] == WLAN_EID_RSN) { /* WPA-only STA, remove RSN IE and possible MDIE */ wpa_ie = wpa_ie + wpa_ie[1] + 2; if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN) @@ -3180,42 +3304,45 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) wpa_ie_len = wpa_ie[1] + 2; } #ifdef CONFIG_TESTING_OPTIONS - if (sm->wpa_auth->conf.rsnxe_override_eapol_len) { - u8 *obuf = sm->wpa_auth->conf.rsnxe_override_eapol; - size_t olen = sm->wpa_auth->conf.rsnxe_override_eapol_len; - const u8 *rsnxe; - - wpa_hexdump(MSG_DEBUG, - "TESTING: wpa_ie before RSNXE EAPOL override", - wpa_ie, wpa_ie_len); - wpa_ie_buf = os_malloc(wpa_ie_len + olen); + if (conf->rsne_override_eapol_set) { + wpa_ie_buf2 = replace_ie( + "RSNE", wpa_ie, &wpa_ie_len, WLAN_EID_RSN, + conf->rsne_override_eapol, + conf->rsne_override_eapol_len); + if (!wpa_ie_buf2) + goto done; + wpa_ie = wpa_ie_buf2; + } + if (conf->rsnxe_override_eapol_set) { + wpa_ie_buf = replace_ie( + "RSNXE", wpa_ie, &wpa_ie_len, WLAN_EID_RSNX, + conf->rsnxe_override_eapol, + conf->rsnxe_override_eapol_len); if (!wpa_ie_buf) - return; - os_memcpy(wpa_ie_buf, wpa_ie, wpa_ie_len); + goto done; wpa_ie = wpa_ie_buf; - rsnxe = get_ie(wpa_ie, wpa_ie_len, WLAN_EID_RSNX); - if (rsnxe) { - u8 rsnxe_len = 2 + rsnxe[1]; - - os_memmove((void *) rsnxe, rsnxe + rsnxe_len, - wpa_ie_len - (rsnxe - wpa_ie) - rsnxe_len); - wpa_ie_len -= rsnxe_len; - } - os_memcpy(wpa_ie + wpa_ie_len, obuf, olen); - wpa_ie_len += olen; - wpa_hexdump(MSG_DEBUG, - "TESTING: wpa_ie after RSNXE EAPOL override", - wpa_ie, wpa_ie_len); } #endif /* CONFIG_TESTING_OPTIONS */ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "sending 3/4 msg of 4-Way Handshake"); if (sm->wpa == WPA_VERSION_WPA2) { + if (sm->use_ext_key_id && sm->TimeoutCtr == 1 && + wpa_auth_set_key(sm->wpa_auth, 0, + wpa_cipher_to_alg(sm->pairwise), + sm->addr, + sm->keyidx_active, sm->PTK.tk, + wpa_cipher_key_len(sm->pairwise), + KEY_FLAG_PAIRWISE_RX)) { + wpa_sta_disconnect(sm->wpa_auth, sm->addr, + WLAN_REASON_PREV_AUTH_NOT_VALID); + return; + } + /* WPA2 send GTK in the 4-way handshake */ secure = 1; gtk = gsm->GTK[gsm->GN - 1]; gtk_len = gsm->GTK_len; - if (sm->wpa_auth->conf.disable_gtk || + if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random GTK to each STA to prevent use @@ -3244,13 +3371,16 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) * WPA if the supplicant used it first. */ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "STA used Secure bit in WPA msg 2/4 - " - "set Secure for 3/4 as workaround"); + "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround"); secure = 1; } } kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); + + if (sm->use_ext_key_id) + kde_len += 2 + RSN_SELECTOR_LEN + 2; + if (gtk) kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; #ifdef CONFIG_IEEE80211R_AP @@ -3263,8 +3393,12 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) if (WPA_GET_BE32(sm->ip_addr) > 0) kde_len += 2 + RSN_SELECTOR_LEN + 3 * 4; #endif /* CONFIG_P2P */ + + if (conf->transition_disable) + kde_len += 2 + RSN_SELECTOR_LEN + 1; + kde = os_malloc(kde_len); - if (kde == NULL) + if (!kde) goto done; pos = kde; @@ -3278,18 +3412,23 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) elen = pos - kde; res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name); if (res < 0) { - wpa_printf(MSG_ERROR, "FT: Failed to insert " - "PMKR1Name into RSN IE in EAPOL-Key data"); + wpa_printf(MSG_ERROR, + "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data"); goto done; } pos -= wpa_ie_len; pos += elen; } #endif /* CONFIG_IEEE80211R_AP */ + hdr[1] = 0; + + if (sm->use_ext_key_id) { + hdr[0] = sm->keyidx_active & 0x01; + pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0); + } + if (gtk) { - u8 hdr[2]; hdr[0] = gtkidx & 0x03; - hdr[1] = 0; pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); } @@ -3300,9 +3439,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) #ifdef CONFIG_IEEE80211R_AP if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { int res; - struct wpa_auth_config *conf; - conf = &sm->wpa_auth->conf; if (sm->assoc_resp_ftie && kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) { os_memcpy(pos, sm->assoc_resp_ftie, @@ -3316,11 +3453,11 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) conf->r0_key_holder_len, NULL, NULL, pos, kde + kde_len - pos, - NULL, 0); + NULL, 0, 0); } if (res < 0) { - wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " - "into EAPOL-Key Key Data"); + wpa_printf(MSG_ERROR, + "FT: Failed to insert FTIE into EAPOL-Key Key Data"); goto done; } pos += res; @@ -3344,13 +3481,17 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) if (WPA_GET_BE32(sm->ip_addr) > 0) { u8 addr[3 * 4]; os_memcpy(addr, sm->ip_addr, 4); - os_memcpy(addr + 4, sm->wpa_auth->conf.ip_addr_mask, 4); - os_memcpy(addr + 8, sm->wpa_auth->conf.ip_addr_go, 4); + os_memcpy(addr + 4, conf->ip_addr_mask, 4); + os_memcpy(addr + 8, conf->ip_addr_go, 4); pos = wpa_add_kde(pos, WFA_KEY_DATA_IP_ADDR_ALLOC, addr, sizeof(addr), NULL, 0); } #endif /* CONFIG_P2P */ + if (conf->transition_disable) + pos = wpa_add_kde(pos, WFA_KEY_DATA_TRANSITION_DISABLE, + &conf->transition_disable, 1, NULL, 0); + wpa_send_eapol(sm->wpa_auth, sm, (secure ? WPA_KEY_INFO_SECURE : 0) | (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ? @@ -3361,6 +3502,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) done: os_free(kde); os_free(wpa_ie_buf); + os_free(wpa_ie_buf2); } @@ -3371,8 +3513,17 @@ SM_STATE(WPA_PTK, PTKINITDONE) if (sm->Pair) { enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise); int klen = wpa_cipher_key_len(sm->pairwise); - if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk, klen)) { + int res; + + if (sm->use_ext_key_id) + res = wpa_auth_set_key(sm->wpa_auth, 0, 0, sm->addr, + sm->keyidx_active, NULL, 0, + KEY_FLAG_PAIRWISE_RX_TX_MODIFY); + else + res = wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, + 0, sm->PTK.tk, klen, + KEY_FLAG_PAIRWISE_RX_TX); + if (res) { wpa_sta_disconnect(sm->wpa_auth, sm->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); return; @@ -3419,6 +3570,7 @@ SM_STATE(WPA_PTK, PTKINITDONE) SM_STEP(WPA_PTK) { struct wpa_authenticator *wpa_auth = sm->wpa_auth; + struct wpa_auth_config *conf = &wpa_auth->conf; if (sm->Init) SM_ENTER(WPA_PTK, INITIALIZE); @@ -3453,7 +3605,7 @@ SM_STEP(WPA_PTK) break; case WPA_PTK_AUTHENTICATION2: if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) && - wpa_auth_get_eapol(sm->wpa_auth, sm->addr, + wpa_auth_get_eapol(wpa_auth, sm->addr, WPA_EAPOL_keyRun) > 0) SM_ENTER(WPA_PTK, INITPMK); else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt) || @@ -3464,7 +3616,7 @@ SM_STEP(WPA_PTK) SM_ENTER(WPA_PTK, INITPMK); break; case WPA_PTK_INITPMK: - if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr, + if (wpa_auth_get_eapol(wpa_auth, sm->addr, WPA_EAPOL_keyAvailable) > 0) { SM_ENTER(WPA_PTK, PTKSTART); #ifdef CONFIG_DPP @@ -3473,13 +3625,13 @@ SM_STEP(WPA_PTK) #endif /* CONFIG_DPP */ } else { wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "INITPMK - keyAvailable = false"); SM_ENTER(WPA_PTK, DISCONNECT); } break; case WPA_PTK_INITPSK: - if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, + if (wpa_auth_get_psk(wpa_auth, sm->addr, sm->p2p_dev_addr, NULL, NULL, NULL)) { SM_ENTER(WPA_PTK, PTKSTART); #ifdef CONFIG_SAE @@ -3487,7 +3639,7 @@ SM_STEP(WPA_PTK) SM_ENTER(WPA_PTK, PTKSTART); #endif /* CONFIG_SAE */ } else { - wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "no PSK configured for the STA"); wpa_auth->dot11RSNA4WayHandshakeFailures++; SM_ENTER(WPA_PTK, DISCONNECT); @@ -3497,13 +3649,11 @@ SM_STEP(WPA_PTK) if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest && sm->EAPOLKeyPairwise) SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING); - else if (sm->TimeoutCtr > - sm->wpa_auth->conf.wpa_pairwise_update_count) { + else if (sm->TimeoutCtr > conf->wpa_pairwise_update_count) { wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_vlogger( - sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "PTKSTART: Retry limit %u reached", - sm->wpa_auth->conf.wpa_pairwise_update_count); + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, + "PTKSTART: Retry limit %u reached", + conf->wpa_pairwise_update_count); SM_ENTER(WPA_PTK, DISCONNECT); } else if (sm->TimeoutEvt) SM_ENTER(WPA_PTK, PTKSTART); @@ -3527,14 +3677,13 @@ SM_STEP(WPA_PTK) sm->EAPOLKeyPairwise && sm->MICVerified) SM_ENTER(WPA_PTK, PTKINITDONE); else if (sm->TimeoutCtr > - sm->wpa_auth->conf.wpa_pairwise_update_count || - (sm->wpa_auth->conf.wpa_disable_eapol_key_retries && + conf->wpa_pairwise_update_count || + (conf->wpa_disable_eapol_key_retries && sm->TimeoutCtr > 1)) { wpa_auth->dot11RSNA4WayHandshakeFailures++; - wpa_auth_vlogger( - sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "PTKINITNEGOTIATING: Retry limit %u reached", - sm->wpa_auth->conf.wpa_pairwise_update_count); + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG, + "PTKINITNEGOTIATING: Retry limit %u reached", + conf->wpa_pairwise_update_count); SM_ENTER(WPA_PTK, DISCONNECT); } else if (sm->TimeoutEvt) SM_ENTER(WPA_PTK, PTKINITNEGOTIATING); @@ -3565,16 +3714,16 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) u8 *kde_buf = NULL, *pos, hdr[2]; size_t kde_len; u8 *gtk, dummy_gtk[32]; + struct wpa_auth_config *conf = &sm->wpa_auth->conf; SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group); sm->GTimeoutCtr++; - if (sm->wpa_auth->conf.wpa_disable_eapol_key_retries && - sm->GTimeoutCtr > 1) { + if (conf->wpa_disable_eapol_key_retries && sm->GTimeoutCtr > 1) { /* Do not allow retransmission of EAPOL-Key group msg 1/2 */ return; } - if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) { + if (sm->GTimeoutCtr > conf->wpa_group_update_count) { /* No point in sending the EAPOL-Key - we will disconnect * immediately following this. */ return; @@ -3591,8 +3740,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) "sending 1/2 msg of Group Key Handshake"); gtk = gsm->GTK[gsm->GN - 1]; - if (sm->wpa_auth->conf.disable_gtk || - sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { + if (conf->disable_gtk || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN) { /* * Provide unique random GTK to each STA to prevent use * of GTK in the BSS. @@ -3605,7 +3753,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); kde_buf = os_malloc(kde_len); - if (kde_buf == NULL) + if (!kde_buf) return; kde = pos = kde_buf; @@ -3638,8 +3786,8 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING) SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) { -#ifdef CONFIG_OCV struct wpa_authenticator *wpa_auth = sm->wpa_auth; +#ifdef CONFIG_OCV const u8 *key_data, *mic; struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; @@ -3704,7 +3852,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED) sm->GUpdateStationKeys = FALSE; sm->GTimeoutCtr = 0; /* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */ - wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO, + wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, "group key handshake completed (%s)", sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN"); sm->has_GTK = TRUE; @@ -3761,7 +3909,9 @@ SM_STEP(WPA_PTK_GROUP) static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { + struct wpa_auth_config *conf = &wpa_auth->conf; int ret = 0; + size_t len; os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); inc_byte_array(group->Counter, WPA_NONCE_LEN); @@ -3772,9 +3922,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, wpa_hexdump_key(MSG_DEBUG, "GTK", group->GTK[group->GN - 1], group->GTK_len); - if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { - size_t len; - len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + len = wpa_cipher_key_len(conf->group_mgmt_cipher); os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); inc_byte_array(group->Counter, WPA_NONCE_LEN); if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion", @@ -3785,6 +3934,19 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, group->IGTK[group->GN_igtk - 4], len); } + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION && + conf->beacon_prot) { + len = wpa_cipher_key_len(conf->group_mgmt_cipher); + os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); + inc_byte_array(group->Counter, WPA_NONCE_LEN); + if (wpa_gmk_to_gtk(group->GMK, "BIGTK key expansion", + wpa_auth->addr, group->GNonce, + group->BIGTK[group->GN_bigtk - 6], len) < 0) + ret = -1; + wpa_hexdump_key(MSG_DEBUG, "BIGTK", + group->BIGTK[group->GN_bigtk - 6], len); + } + return ret; } @@ -3792,8 +3954,9 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " - "GTK_INIT (VLAN-ID %d)", group->vlan_id); + wpa_printf(MSG_DEBUG, + "WPA: group state machine entering state GTK_INIT (VLAN-ID %d)", + group->vlan_id); group->changed = FALSE; /* GInit is not cleared here; avoid loop */ group->wpa_group_state = WPA_GROUP_GTK_INIT; @@ -3803,6 +3966,8 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth, group->GM = 2; group->GN_igtk = 4; group->GM_igtk = 5; + group->GN_bigtk = 6; + group->GM_bigtk = 7; /* GTK[GN] = CalcGTK() */ wpa_gtk_update(wpa_auth, group); } @@ -3826,8 +3991,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) * station needs to be counted here anyway. */ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "GUpdateStationKeys was already set when " - "marking station for GTK rekeying"); + "GUpdateStationKeys was already set when marking station for GTK rekeying"); } /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */ @@ -3846,7 +4010,7 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx) /* update GTK when exiting WNM-Sleep Mode */ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm) { - if (sm == NULL || sm->is_wnmsleep) + if (!sm || sm->is_wnmsleep) return; wpa_group_update_sta(sm, NULL); @@ -3920,6 +4084,36 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) return pos - start; } + +int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos) +{ + struct wpa_group *gsm = sm->group; + u8 *start = pos; + size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + + /* + * BIGTK subelement: + * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16] + */ + *pos++ = WNM_SLEEP_SUBELEM_BIGTK; + *pos++ = 2 + 6 + len; + WPA_PUT_LE16(pos, gsm->GN_bigtk); + pos += 2; + if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0) + return 0; + pos += 6; + + os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len); + pos += len; + + wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit", + gsm->GN_bigtk); + wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit", + gsm->IGTK[gsm->GN_bigtk - 6], len); + + return pos - start; +} + #endif /* CONFIG_WNM_AP */ @@ -3928,8 +4122,9 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, { int tmp; - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " - "SETKEYS (VLAN-ID %d)", group->vlan_id); + wpa_printf(MSG_DEBUG, + "WPA: group state machine entering state SETKEYS (VLAN-ID %d)", + group->vlan_id); group->changed = TRUE; group->wpa_group_state = WPA_GROUP_SETKEYS; group->GTKReKey = FALSE; @@ -3939,14 +4134,17 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, tmp = group->GM_igtk; group->GM_igtk = group->GN_igtk; group->GN_igtk = tmp; + tmp = group->GM_bigtk; + group->GM_bigtk = group->GN_bigtk; + group->GN_bigtk = tmp; /* "GKeyDoneStations = GNoStations" is done in more robust way by * counting the STAs that are marked with GUpdateStationKeys instead of * including all STAs that could be in not-yet-completed state. */ wpa_gtk_update(wpa_auth, group); if (group->GKeyDoneStations) { - wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected " - "GKeyDoneStations=%d when starting new GTK rekey", + wpa_printf(MSG_DEBUG, + "wpa_group_setkeys: Unexpected GKeyDoneStations=%d when starting new GTK rekey", group->GKeyDoneStations); group->GKeyDoneStations = 0; } @@ -3959,25 +4157,35 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth, static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { + struct wpa_auth_config *conf = &wpa_auth->conf; int ret = 0; if (wpa_auth_set_key(wpa_auth, group->vlan_id, - wpa_cipher_to_alg(wpa_auth->conf.wpa_group), + wpa_cipher_to_alg(conf->wpa_group), broadcast_ether_addr, group->GN, - group->GTK[group->GN - 1], group->GTK_len) < 0) + group->GTK[group->GN - 1], group->GTK_len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) ret = -1; - if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { + if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { enum wpa_alg alg; size_t len; - alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher); - len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); + alg = wpa_cipher_to_alg(conf->group_mgmt_cipher); + len = wpa_cipher_key_len(conf->group_mgmt_cipher); if (ret == 0 && wpa_auth_set_key(wpa_auth, group->vlan_id, alg, broadcast_ether_addr, group->GN_igtk, - group->IGTK[group->GN_igtk - 4], len) < 0) + group->IGTK[group->GN_igtk - 4], len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) + ret = -1; + + if (ret == 0 && conf->beacon_prot && + wpa_auth_set_key(wpa_auth, group->vlan_id, alg, + broadcast_ether_addr, group->GN_bigtk, + group->BIGTK[group->GN_bigtk - 6], len, + KEY_FLAG_GROUP_TX_DEFAULT) < 0) ret = -1; } @@ -3989,7 +4197,7 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx) { if (sm->group == ctx) { wpa_printf(MSG_DEBUG, "WPA: Mark STA " MACSTR - " for discconnection due to fatal failure", + " for disconnection due to fatal failure", MAC2STR(sm->addr)); sm->Disconnect = TRUE; } @@ -4001,7 +4209,8 @@ static int wpa_group_disconnect_cb(struct wpa_state_machine *sm, void *ctx) static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state FATAL_FAILURE"); + wpa_printf(MSG_DEBUG, + "WPA: group state machine entering state FATAL_FAILURE"); group->changed = TRUE; group->wpa_group_state = WPA_GROUP_FATAL_FAILURE; wpa_auth_for_each_sta(wpa_auth, wpa_group_disconnect_cb, group); @@ -4011,8 +4220,9 @@ static void wpa_group_fatal_failure(struct wpa_authenticator *wpa_auth, static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth, struct wpa_group *group) { - wpa_printf(MSG_DEBUG, "WPA: group state machine entering state " - "SETKEYSDONE (VLAN-ID %d)", group->vlan_id); + wpa_printf(MSG_DEBUG, + "WPA: group state machine entering state SETKEYSDONE (VLAN-ID %d)", + group->vlan_id); group->changed = TRUE; group->wpa_group_state = WPA_GROUP_SETKEYSDONE; @@ -4049,7 +4259,7 @@ static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth, static int wpa_sm_step(struct wpa_state_machine *sm) { - if (sm == NULL) + if (!sm) return 0; if (sm->in_step_loop) { @@ -4079,8 +4289,9 @@ static int wpa_sm_step(struct wpa_state_machine *sm) sm->in_step_loop = 0; if (sm->pending_deinit) { - wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state " - "machine deinit for " MACSTR, MAC2STR(sm->addr)); + wpa_printf(MSG_DEBUG, + "WPA: Completing pending STA state machine deinit for " + MACSTR, MAC2STR(sm->addr)); wpa_free_sta_sm(sm); return 1; } @@ -4097,7 +4308,7 @@ static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx) void wpa_auth_sm_notify(struct wpa_state_machine *sm) { - if (sm == NULL) + if (!sm) return; eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL); } @@ -4108,7 +4319,7 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) int tmp, i; struct wpa_group *group; - if (wpa_auth == NULL) + if (!wpa_auth) return; group = wpa_auth->group; @@ -4120,6 +4331,9 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth) tmp = group->GM_igtk; group->GM_igtk = group->GN_igtk; group->GN_igtk = tmp; + tmp = group->GM_bigtk; + group->GM_bigtk = group->GN_bigtk; + group->GN_bigtk = tmp; wpa_gtk_update(wpa_auth, group); wpa_group_config_group_keys(wpa_auth, group); } @@ -4138,6 +4352,7 @@ static const char * wpa_bool_txt(int val) int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen) { + struct wpa_auth_config *conf; int len = 0, ret; char pmkid_txt[PMKID_LEN * 2 + 1]; #ifdef CONFIG_RSN_PREAUTH @@ -4146,8 +4361,9 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen) const int preauth = 0; #endif /* CONFIG_RSN_PREAUTH */ - if (wpa_auth == NULL) + if (!wpa_auth) return len; + conf = &wpa_auth->conf; ret = os_snprintf(buf + len, buflen - len, "dot11RSNAOptionImplemented=TRUE\n" @@ -4155,8 +4371,8 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen) "dot11RSNAEnabled=%s\n" "dot11RSNAPreauthenticationEnabled=%s\n", wpa_bool_txt(preauth), - wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN), - wpa_bool_txt(wpa_auth->conf.rsn_preauth)); + wpa_bool_txt(conf->wpa & WPA_PROTO_RSN), + wpa_bool_txt(conf->rsn_preauth)); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; @@ -4191,10 +4407,10 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen) "dot11RSNA4WayHandshakeFailures=%u\n" "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n", RSN_VERSION, - !!wpa_auth->conf.wpa_strict_rekey, - wpa_auth->conf.wpa_group_update_count, - wpa_auth->conf.wpa_pairwise_update_count, - wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8, + !!conf->wpa_strict_rekey, + conf->wpa_group_update_count, + conf->wpa_pairwise_update_count, + wpa_cipher_key_len(conf->wpa_group) * 8, dot11RSNAConfigPMKLifetime, dot11RSNAConfigPMKReauthThreshold, dot11RSNAConfigSATimeout, @@ -4230,7 +4446,7 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen) int len = 0, ret; u32 pairwise = 0; - if (sm == NULL) + if (!sm) return 0; /* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */ @@ -4311,7 +4527,7 @@ const u8 * wpa_auth_get_pmk(struct wpa_state_machine *sm, int *len) int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm) { - if (sm == NULL) + if (!sm) return -1; return sm->wpa_key_mgmt; } @@ -4319,7 +4535,7 @@ int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm) int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm) { - if (sm == NULL) + if (!sm) return 0; return sm->wpa; } @@ -4344,7 +4560,7 @@ int wpa_auth_sta_fils_tk_already_set(struct wpa_state_machine *sm) int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm, struct rsn_pmksa_cache_entry *entry) { - if (sm == NULL || sm->pmksa != entry) + if (!sm || sm->pmksa != entry) return -1; sm->pmksa = NULL; return 0; @@ -4367,7 +4583,7 @@ void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm) const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len) { - if (wpa_auth == NULL) + if (!wpa_auth) return NULL; *len = wpa_auth->wpa_ie_len; return wpa_auth->wpa_ie; @@ -4378,7 +4594,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, unsigned int pmk_len, int session_timeout, struct eapol_state_machine *eapol) { - if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 || + if (!sm || sm->wpa != WPA_VERSION_WPA2 || sm->wpa_auth->conf.disable_pmksa_caching) return -1; @@ -4414,7 +4630,7 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth, int session_timeout, struct eapol_state_machine *eapol) { - if (wpa_auth == NULL) + if (!wpa_auth) return -1; wpa_hexdump_key(MSG_DEBUG, "RSN: Cache PMK from preauth", pmk, len); @@ -4475,7 +4691,7 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth, { struct rsn_pmksa_cache_entry *pmksa; - if (wpa_auth == NULL || wpa_auth->pmksa == NULL) + if (!wpa_auth || !wpa_auth->pmksa) return; pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL); if (pmksa) { @@ -4641,13 +4857,13 @@ wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id) { struct wpa_group *group; - if (wpa_auth == NULL || wpa_auth->group == NULL) + if (!wpa_auth || !wpa_auth->group) return NULL; wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d", vlan_id); group = wpa_group_init(wpa_auth, vlan_id, 0); - if (group == NULL) + if (!group) return NULL; group->next = wpa_auth->group->next; @@ -4667,7 +4883,7 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id) { struct wpa_group *group; - if (wpa_auth == NULL) + if (!wpa_auth) return 0; group = wpa_auth->group; @@ -4677,9 +4893,9 @@ int wpa_auth_ensure_group(struct wpa_authenticator *wpa_auth, int vlan_id) group = group->next; } - if (group == NULL) { + if (!group) { group = wpa_auth_add_group(wpa_auth, vlan_id); - if (group == NULL) + if (!group) return -1; } @@ -4708,7 +4924,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id) struct wpa_group *group; int ret = 0; - if (wpa_auth == NULL) + if (!wpa_auth) return 0; group = wpa_auth->group; @@ -4718,7 +4934,7 @@ int wpa_auth_release_group(struct wpa_authenticator *wpa_auth, int vlan_id) group = group->next; } - if (group == NULL) + if (!group) return -1; wpa_printf(MSG_DEBUG, @@ -4753,7 +4969,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) { struct wpa_group *group; - if (sm == NULL || sm->wpa_auth == NULL) + if (!sm || !sm->wpa_auth) return 0; group = sm->wpa_auth->group; @@ -4763,9 +4979,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) group = group->next; } - if (group == NULL) { + if (!group) { group = wpa_auth_add_group(sm->wpa_auth, vlan_id); - if (group == NULL) + if (!group) return -1; } @@ -4775,8 +4991,9 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) if (group->wpa_group_state == WPA_GROUP_FATAL_FAILURE) return -1; - wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state " - "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id); + wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR + " to use group state machine for VLAN ID %d", + MAC2STR(sm->addr), vlan_id); wpa_group_get(sm->wpa_auth, group); wpa_group_put(sm->wpa_auth, sm->group); @@ -4789,7 +5006,7 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id) void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, int ack) { - if (wpa_auth == NULL || sm == NULL) + if (!wpa_auth || !sm) return; wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR " ack=%d", MAC2STR(sm->addr), ack); @@ -4805,8 +5022,8 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, * the station has received the frame. */ int timeout_ms = eapol_key_timeout_subseq; - wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 " - "timeout by %u ms because of acknowledged frame", + wpa_printf(MSG_DEBUG, + "WPA: Increase initial EAPOL-Key 1/4 timeout by %u ms because of acknowledged frame", timeout_ms); eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm); eloop_register_timeout(timeout_ms / 1000, @@ -4826,7 +5043,7 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, int wpa_auth_uses_sae(struct wpa_state_machine *sm) { - if (sm == NULL) + if (!sm) return 0; return wpa_key_mgmt_sae(sm->wpa_key_mgmt); } @@ -4834,7 +5051,7 @@ int wpa_auth_uses_sae(struct wpa_state_machine *sm) int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm) { - if (sm == NULL) + if (!sm) return 0; return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_SAE; } @@ -4843,7 +5060,7 @@ int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm) #ifdef CONFIG_P2P int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr) { - if (sm == NULL || WPA_GET_BE32(sm->ip_addr) == 0) + if (!sm || WPA_GET_BE32(sm->ip_addr) == 0) return -1; os_memcpy(addr, sm->ip_addr, 4); return 0; @@ -4919,7 +5136,7 @@ int wpa_auth_write_fte(struct wpa_authenticator *wpa_auth, int use_sha384, return wpa_write_ftie(conf, use_sha384, conf->r0_key_holder, conf->r0_key_holder_len, - NULL, NULL, buf, len, NULL, 0); + NULL, NULL, buf, len, NULL, 0, 0); } #endif /* CONFIG_IEEE80211R_AP */ @@ -4999,9 +5216,10 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, struct wpa_group *gsm = sm->group; u8 *wpa_ie; int wpa_ie_len, secure, gtkidx, encr = 0; + u8 hdr[2]; /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE], - GTK[GN], IGTK, [FTIE], [TIE * 2]) + GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2]) */ /* Use 0 RSC */ @@ -5044,13 +5262,16 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, * WPA if the supplicant used it first. */ wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, - "STA used Secure bit in WPA msg 2/4 - " - "set Secure for 3/4 as workaround"); + "STA used Secure bit in WPA msg 2/4 - set Secure for 3/4 as workaround"); secure = 1; } } kde_len = wpa_ie_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); + + if (sm->use_ext_key_id) + kde_len += 2 + RSN_SELECTOR_LEN + 2; + if (gtk) kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len; #ifdef CONFIG_IEEE80211R_AP @@ -5060,7 +5281,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, } #endif /* CONFIG_IEEE80211R_AP */ kde = os_malloc(kde_len); - if (kde == NULL) + if (!kde) return -1; pos = kde; @@ -5074,8 +5295,8 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, elen = pos - kde; res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name); if (res < 0) { - wpa_printf(MSG_ERROR, "FT: Failed to insert " - "PMKR1Name into RSN IE in EAPOL-Key data"); + wpa_printf(MSG_ERROR, + "FT: Failed to insert PMKR1Name into RSN IE in EAPOL-Key data"); os_free(kde); return -1; } @@ -5083,10 +5304,15 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, pos += elen; } #endif /* CONFIG_IEEE80211R_AP */ + hdr[1] = 0; + + if (sm->use_ext_key_id) { + hdr[0] = sm->keyidx_active & 0x01; + pos = wpa_add_kde(pos, RSN_KEY_DATA_KEYID, hdr, 2, NULL, 0); + } + if (gtk) { - u8 hdr[2]; hdr[0] = gtkidx & 0x03; - hdr[1] = 0; pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2, gtk, gtk_len); } @@ -5121,11 +5347,11 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm, conf->r0_key_holder_len, NULL, NULL, pos, kde + kde_len - pos, - NULL, 0); + NULL, 0, 0); } if (res < 0) { - wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE " - "into EAPOL-Key Key Data"); + wpa_printf(MSG_ERROR, + "FT: Failed to insert FTIE into EAPOL-Key Key Data"); os_free(kde); return -1; } @@ -5182,7 +5408,7 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm, kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len + ieee80211w_kde_len(sm) + ocv_oci_len(sm); kde_buf = os_malloc(kde_len); - if (kde_buf == NULL) + if (!kde_buf) return -1; kde = pos = kde_buf; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 933a4b8e..868aaa1f 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -169,6 +169,7 @@ struct ft_remote_r1kh { struct wpa_auth_config { int wpa; + int extended_key_id; int wpa_key_mgmt; int wpa_pairwise; int wpa_group; @@ -176,6 +177,7 @@ struct wpa_auth_config { int wpa_strict_rekey; int wpa_gmk_rekey; int wpa_ptk_rekey; + int wpa_deny_ptk0_rekey; u32 wpa_group_update_count; u32 wpa_pairwise_update_count; int wpa_disable_eapol_key_retries; @@ -188,6 +190,7 @@ struct wpa_auth_config { int okc; int tx_status; enum mfp_options ieee80211w; + int beacon_prot; int group_mgmt_cipher; int sae_require_mfp; #ifdef CONFIG_OCV @@ -219,8 +222,22 @@ struct wpa_auth_config { double corrupt_gtk_rekey_mic_probability; u8 own_ie_override[MAX_OWN_IE_OVERRIDE]; size_t own_ie_override_len; + u8 rsne_override_eapol[MAX_OWN_IE_OVERRIDE]; + size_t rsne_override_eapol_len; u8 rsnxe_override_eapol[MAX_OWN_IE_OVERRIDE]; size_t rsnxe_override_eapol_len; + u8 rsne_override_ft[MAX_OWN_IE_OVERRIDE]; + size_t rsne_override_ft_len; + u8 rsnxe_override_ft[MAX_OWN_IE_OVERRIDE]; + size_t rsnxe_override_ft_len; + u8 gtk_rsc_override[WPA_KEY_RSC_LEN]; + u8 igtk_rsc_override[WPA_KEY_RSC_LEN]; + unsigned int rsne_override_eapol_set:1; + unsigned int rsnxe_override_eapol_set:1; + unsigned int rsne_override_ft_set:1; + unsigned int rsnxe_override_ft_set:1; + unsigned int gtk_rsc_override_set:1; + unsigned int igtk_rsc_override_set:1; #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_P2P u8 ip_addr_go[4]; @@ -233,6 +250,11 @@ struct wpa_auth_config { u8 fils_cache_id[FILS_CACHE_ID_LEN]; #endif /* CONFIG_FILS */ int sae_pwe; + int owe_ptk_workaround; + u8 transition_disable; +#ifdef CONFIG_DPP2 + int dpp_pfs; +#endif /* CONFIG_DPP2 */ }; typedef enum { @@ -259,7 +281,8 @@ struct wpa_auth_callbacks { int *vlan_id); int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len); int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg, - const u8 *addr, int idx, u8 *key, size_t key_len); + const u8 *addr, int idx, u8 *key, size_t key_len, + enum key_flag key_flag); int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq); int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data, size_t data_len, int encrypt); @@ -311,19 +334,21 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth); int wpa_reconfig(struct wpa_authenticator *wpa_auth, struct wpa_auth_config *conf); -enum { +enum wpa_validate_result { WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE, WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL, WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER, - WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID + WPA_INVALID_MDIE, WPA_INVALID_PROTO, WPA_INVALID_PMKID, + WPA_DENIED_OTHER_REASON }; -int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, int freq, - const u8 *wpa_ie, size_t wpa_ie_len, - const u8 *rsnxe, size_t rsnxe_len, - const u8 *mdie, size_t mdie_len, - const u8 *owe_dh, size_t owe_dh_len); +enum wpa_validate_result +wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int freq, + const u8 *wpa_ie, size_t wpa_ie_len, + const u8 *rsnxe, size_t rsnxe_len, + const u8 *mdie, size_t mdie_len, + const u8 *owe_dh, size_t owe_dh_len); int wpa_validate_osen(struct wpa_authenticator *wpa_auth, struct wpa_state_machine *sm, const u8 *osen_ie, size_t osen_ie_len); @@ -407,7 +432,8 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_IEEE80211R_AP u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, size_t max_len, int auth_alg, - const u8 *req_ies, size_t req_ies_len); + const u8 *req_ies, size_t req_ies_len, + int omit_rsnxe); void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, u16 auth_transaction, const u8 *ies, size_t ies_len, void (*cb)(void *ctx, const u8 *dst, const u8 *bssid, @@ -431,6 +457,7 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm); void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag); int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos); int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos); +int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos); int wpa_auth_uses_sae(struct wpa_state_machine *sm); int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index a599be22..476a2be6 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -808,7 +808,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *anonce, const u8 *snonce, u8 *buf, size_t len, const u8 *subelem, - size_t subelem_len) + size_t subelem_len, int rsnxe_used) { u8 *pos = buf, *ielen; size_t hdrlen = use_sha384 ? sizeof(struct rsn_ftie_sha384) : @@ -826,7 +826,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, 0); + WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) @@ -836,7 +836,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, os_memset(hdr, 0, sizeof(*hdr)); pos += sizeof(*hdr); - WPA_PUT_LE16(hdr->mic_control, 0); + WPA_PUT_LE16(hdr->mic_control, !!rsnxe_used); if (anonce) os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN); if (snonce) @@ -951,8 +951,9 @@ wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth, goto err; } - wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR, - MAC2STR(src_addr)); + wpa_printf(MSG_DEBUG, "FT: Send sequence number request from " MACSTR + " to " MACSTR, + MAC2STR(wpa_auth->addr), MAC2STR(src_addr)); item = os_zalloc(sizeof(*item)); if (!item) goto err; @@ -1997,9 +1998,6 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, key = r0kh->key; key_len = sizeof(r0kh->key); - wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH " - "address " MACSTR, MAC2STR(r0kh->addr)); - if (r0kh->seq->rx.num_last == 0) { /* A sequence request will be sent out anyway when pull * response is received. Send it out now to avoid one RTT. */ @@ -2008,6 +2006,10 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, key_len, NULL, 0, NULL, 0, NULL); } + wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request from " MACSTR + " to remote R0KH address " MACSTR, + MAC2STR(sm->wpa_auth->addr), MAC2STR(r0kh->addr)); + if (first && random_get_bytes(sm->ft_pending_pull_nonce, FT_RRB_NONCE_LEN) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " @@ -2280,6 +2282,54 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) } +static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len) +{ + u8 *subelem, *pos; + struct wpa_group *gsm = sm->group; + size_t subelem_len; + const u8 *kek; + size_t kek_len; + size_t bigtk_len; + + if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) { + kek = sm->PTK.kek2; + kek_len = sm->PTK.kek2_len; + } else { + kek = sm->PTK.kek; + kek_len = sm->PTK.kek_len; + } + + bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + + /* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] | + * Key[16+8] */ + subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8; + subelem = os_zalloc(subelem_len); + if (subelem == NULL) + return NULL; + + pos = subelem; + *pos++ = FTIE_SUBELEM_BIGTK; + *pos++ = subelem_len - 2; + WPA_PUT_LE16(pos, gsm->GN_bigtk); + pos += 2; + wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos); + pos += 6; + *pos++ = bigtk_len; + if (aes_wrap(kek, kek_len, bigtk_len / 8, + gsm->IGTK[gsm->GN_bigtk - 6], pos)) { + wpa_printf(MSG_DEBUG, + "FT: BIGTK subelem encryption failed: kek_len=%d", + (int) kek_len); + os_free(subelem); + return NULL; + } + + *len = subelem_len; + return subelem; +} + + static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm, u8 *pos, u8 *end, u8 id, u8 descr_count, const u8 *ies, size_t ies_len) @@ -2413,13 +2463,15 @@ static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end, u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, size_t max_len, int auth_alg, - const u8 *req_ies, size_t req_ies_len) + const u8 *req_ies, size_t req_ies_len, + int omit_rsnxe) { u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL; u8 *fte_mic, *elem_count; size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0; - u8 rsnxe[10]; + u8 rsnxe_buf[10], *rsnxe = rsnxe_buf; size_t rsnxe_len; + int rsnxe_used; int res; struct wpa_auth_config *conf; struct wpa_ft_ies parse; @@ -2440,6 +2492,32 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, end = pos + max_len; +#ifdef CONFIG_TESTING_OPTIONS + if (auth_alg == WLAN_AUTH_FT && + sm->wpa_auth->conf.rsne_override_ft_set) { + wpa_printf(MSG_DEBUG, + "TESTING: RSNE FT override for MIC calculation"); + rsnie = sm->wpa_auth->conf.rsne_override_ft; + rsnie_len = sm->wpa_auth->conf.rsne_override_ft_len; + if (end - pos < (long int) rsnie_len) + return pos; + os_memcpy(pos, rsnie, rsnie_len); + rsnie = pos; + pos += rsnie_len; + if (rsnie_len > PMKID_LEN && sm->pmk_r1_name_valid) { + int idx; + + /* Replace all 0xff PMKID with the valid PMKR1Name */ + for (idx = 0; idx < PMKID_LEN; idx++) { + if (rsnie[rsnie_len - 1 - idx] != 0xff) + break; + } + if (idx == PMKID_LEN) + os_memcpy(&rsnie[rsnie_len - PMKID_LEN], + sm->pmk_r1_name, WPA_PMK_NAME_LEN); + } + } else +#endif /* CONFIG_TESTING_OPTIONS */ if (auth_alg == WLAN_AUTH_FT || ((auth_alg == WLAN_AUTH_FILS_SK || auth_alg == WLAN_AUTH_FILS_SK_PFS || @@ -2509,6 +2587,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, subelem_len += igtk_len; os_free(igtk); } + if (sm->mgmt_frame_prot && conf->beacon_prot) { + u8 *bigtk; + size_t bigtk_len; + u8 *nbuf; + + bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len); + if (!bigtk) { + wpa_printf(MSG_DEBUG, + "FT: Failed to add BIGTK subelement"); + os_free(subelem); + return NULL; + } + nbuf = os_realloc(subelem, subelem_len + bigtk_len); + if (!nbuf) { + os_free(subelem); + os_free(bigtk); + return NULL; + } + subelem = nbuf; + os_memcpy(subelem + subelem_len, bigtk, bigtk_len); + subelem_len += bigtk_len; + os_free(bigtk); + } #ifdef CONFIG_OCV if (wpa_auth_uses_ocv(sm)) { struct wpa_channel_info ci; @@ -2544,9 +2645,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, anonce = NULL; snonce = NULL; } + rsnxe_used = (auth_alg == WLAN_AUTH_FT) && + (conf->sae_pwe == 1 || conf->sae_pwe == 2); res = wpa_write_ftie(conf, use_sha384, r0kh_id, r0kh_id_len, anonce, snonce, pos, end - pos, - subelem, subelem_len); + subelem, subelem_len, rsnxe_used); os_free(subelem); if (res < 0) return NULL; @@ -2582,10 +2685,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, if (ric_start == pos) ric_start = NULL; - res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe)); - if (res < 0) - return NULL; - rsnxe_len = res; + if (omit_rsnxe) { + rsnxe_len = 0; + } else { + res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, + sizeof(rsnxe_buf)); + if (res < 0) + return NULL; + rsnxe_len = res; + } +#ifdef CONFIG_TESTING_OPTIONS + if (auth_alg == WLAN_AUTH_FT && + sm->wpa_auth->conf.rsnxe_override_ft_set) { + wpa_printf(MSG_DEBUG, + "TESTING: RSNXE FT override for MIC calculation"); + rsnxe = sm->wpa_auth->conf.rsnxe_override_ft; + rsnxe_len = sm->wpa_auth->conf.rsnxe_override_ft_len; + } +#endif /* CONFIG_TESTING_OPTIONS */ if (auth_alg == WLAN_AUTH_FT && rsnxe_len) *elem_count += 1; @@ -2620,12 +2737,13 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, - u8 *key, size_t key_len) + u8 *key, size_t key_len, + enum key_flag key_flag) { if (wpa_auth->cb->set_key == NULL) return -1; return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx, - key, key_len); + key, key_len, key_flag); } @@ -2657,8 +2775,8 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) * again after association to get the PTK configured, but that could be * optimized by adding the STA entry earlier. */ - if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0, - sm->PTK.tk, klen)) + if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, sm->keyidx_active, + sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) return; /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */ @@ -3057,7 +3175,8 @@ pmk_r1_derived: pos += ret; ret = wpa_write_ftie(conf, use_sha384, parse.r0kh_id, parse.r0kh_id_len, - sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0); + sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0, + 0); if (ret < 0) goto fail; pos += ret; @@ -3129,10 +3248,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, int use_sha384; const u8 *anonce, *snonce, *fte_mic; u8 fte_elem_count; + int rsnxe_used; + struct wpa_auth_config *conf; if (sm == NULL) return WLAN_STATUS_UNSPECIFIED_FAILURE; + conf = &sm->wpa_auth->conf; use_sha384 = wpa_key_mgmt_sha384(sm->wpa_key_mgmt); wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len); @@ -3161,8 +3283,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, mdie = (struct rsn_mdie *) parse.mdie; if (mdie == NULL || parse.mdie_len < sizeof(*mdie) || - os_memcmp(mdie->mobility_domain, - sm->wpa_auth->conf.mobility_domain, + os_memcmp(mdie->mobility_domain, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MDIE"); return WLAN_STATUS_INVALID_MDIE; @@ -3179,6 +3300,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, anonce = ftie->anonce; snonce = ftie->snonce; + rsnxe_used = ftie->mic_control[0] & 0x01; fte_elem_count = ftie->mic_control[1]; fte_mic = ftie->mic; } else { @@ -3192,6 +3314,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, anonce = ftie->anonce; snonce = ftie->snonce; + rsnxe_used = ftie->mic_control[0] & 0x01; fte_elem_count = ftie->mic_control[1]; fte_mic = ftie->mic; } @@ -3237,14 +3360,14 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return WLAN_STATUS_INVALID_FTIE; } - if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder, + if (os_memcmp_const(parse.r1kh_id, conf->r1_key_holder, FT_R1KH_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " "ReassocReq"); wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE", parse.r1kh_id, FT_R1KH_ID_LEN); wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID", - sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN); + conf->r1_key_holder, FT_R1KH_ID_LEN); return WLAN_STATUS_INVALID_FTIE; } @@ -3306,6 +3429,13 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return WLAN_STATUS_INVALID_FTIE; } + if (rsnxe_used && (conf->sae_pwe == 1 || conf->sae_pwe == 2) && + !parse.rsnxe) { + wpa_printf(MSG_INFO, + "FT: FTE indicated that STA uses RSNXE, but RSNXE was not included"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + #ifdef CONFIG_OCV if (wpa_auth_uses_ocv(sm)) { struct wpa_channel_info ci; @@ -3687,6 +3817,10 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, goto out; } + wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull response from " MACSTR + " to " MACSTR, + MAC2STR(wpa_auth->addr), MAC2STR(src_addr)); + resp[0].type = FT_RRB_S1KH_ID; resp[0].len = f_s1kh_id_len; resp[0].data = f_s1kh_id; @@ -4193,6 +4327,10 @@ static int wpa_ft_rrb_rx_seq_req(struct wpa_authenticator *wpa_auth, goto out; } + wpa_printf(MSG_DEBUG, "FT: Send sequence number response from " MACSTR + " to " MACSTR, + MAC2STR(wpa_auth->addr), MAC2STR(src_addr)); + seq_resp_auth[0].type = FT_RRB_NONCE; seq_resp_auth[0].len = f_nonce_len; seq_resp_auth[0].data = f_nonce; @@ -4452,9 +4590,11 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, size_t alen, elen; int no_defer = 0; - wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP " - MACSTR, MAC2STR(src_addr)); - wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix); + wpa_printf(MSG_DEBUG, "FT: RRB-OUI(" MACSTR + ") received frame from remote AP " + MACSTR " oui_suffix=%u dst=" MACSTR, + MAC2STR(wpa_auth->addr), MAC2STR(src_addr), oui_suffix, + MAC2STR(dst_addr)); wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len); if (is_multicast_ether_addr(src_addr)) { @@ -4464,13 +4604,8 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, return; } - if (is_multicast_ether_addr(dst_addr)) { - wpa_printf(MSG_DEBUG, - "FT: RRB-OUI received frame from remote AP " MACSTR - " to multicast address " MACSTR, - MAC2STR(src_addr), MAC2STR(dst_addr)); + if (is_multicast_ether_addr(dst_addr)) no_defer = 1; - } if (data_len < sizeof(u16)) { wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame too short"); @@ -4545,6 +4680,10 @@ static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth, return -1; } + wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 push from " MACSTR + " to remote R0KH address " MACSTR, + MAC2STR(wpa_auth->addr), MAC2STR(r1kh->addr)); + if (wpa_ft_rrb_build_r0(r1kh->key, sizeof(r1kh->key), push, pmk_r0, r1kh->id, s1kh_id, push_auth, wpa_auth->addr, FT_PACKET_R0KH_R1KH_PUSH, diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index 7fb0923e..7a1ed24e 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -37,8 +37,11 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, struct hostapd_config *iconf, struct wpa_auth_config *wconf) { + int sae_pw_id; + os_memset(wconf, 0, sizeof(*wconf)); wconf->wpa = conf->wpa; + wconf->extended_key_id = conf->extended_key_id; wconf->wpa_key_mgmt = conf->wpa_key_mgmt; wconf->wpa_pairwise = conf->wpa_pairwise; wconf->wpa_group = conf->wpa_group; @@ -65,6 +68,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, #endif /* CONFIG_OCV */ wconf->okc = conf->okc; wconf->ieee80211w = conf->ieee80211w; + wconf->beacon_prot = conf->beacon_prot; wconf->group_mgmt_cipher = conf->group_mgmt_cipher; wconf->sae_require_mfp = conf->sae_require_mfp; #ifdef CONFIG_IEEE80211R_AP @@ -118,14 +122,58 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wpabuf_head(conf->own_ie_override), wconf->own_ie_override_len); } + if (conf->rsne_override_eapol && + wpabuf_len(conf->rsne_override_eapol) <= MAX_OWN_IE_OVERRIDE) { + wconf->rsne_override_eapol_set = 1; + wconf->rsne_override_eapol_len = + wpabuf_len(conf->rsne_override_eapol); + os_memcpy(wconf->rsne_override_eapol, + wpabuf_head(conf->rsne_override_eapol), + wconf->rsne_override_eapol_len); + } if (conf->rsnxe_override_eapol && wpabuf_len(conf->rsnxe_override_eapol) <= MAX_OWN_IE_OVERRIDE) { + wconf->rsnxe_override_eapol_set = 1; wconf->rsnxe_override_eapol_len = wpabuf_len(conf->rsnxe_override_eapol); os_memcpy(wconf->rsnxe_override_eapol, wpabuf_head(conf->rsnxe_override_eapol), wconf->rsnxe_override_eapol_len); } + if (conf->rsne_override_ft && + wpabuf_len(conf->rsne_override_ft) <= MAX_OWN_IE_OVERRIDE) { + wconf->rsne_override_ft_set = 1; + wconf->rsne_override_ft_len = + wpabuf_len(conf->rsne_override_ft); + os_memcpy(wconf->rsne_override_ft, + wpabuf_head(conf->rsne_override_ft), + wconf->rsne_override_ft_len); + } + if (conf->rsnxe_override_ft && + wpabuf_len(conf->rsnxe_override_ft) <= MAX_OWN_IE_OVERRIDE) { + wconf->rsnxe_override_ft_set = 1; + wconf->rsnxe_override_ft_len = + wpabuf_len(conf->rsnxe_override_ft); + os_memcpy(wconf->rsnxe_override_ft, + wpabuf_head(conf->rsnxe_override_ft), + wconf->rsnxe_override_ft_len); + } + if (conf->gtk_rsc_override && + wpabuf_len(conf->gtk_rsc_override) > 0 && + wpabuf_len(conf->gtk_rsc_override) <= WPA_KEY_RSC_LEN) { + os_memcpy(wconf->gtk_rsc_override, + wpabuf_head(conf->gtk_rsc_override), + wpabuf_len(conf->gtk_rsc_override)); + wconf->gtk_rsc_override_set = 1; + } + if (conf->igtk_rsc_override && + wpabuf_len(conf->igtk_rsc_override) > 0 && + wpabuf_len(conf->igtk_rsc_override) <= WPA_KEY_RSC_LEN) { + os_memcpy(wconf->igtk_rsc_override, + wpabuf_head(conf->igtk_rsc_override), + wpabuf_len(conf->igtk_rsc_override)); + wconf->igtk_rsc_override_set = 1; + } #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_P2P os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); @@ -139,6 +187,18 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, FILS_CACHE_ID_LEN); #endif /* CONFIG_FILS */ wconf->sae_pwe = conf->sae_pwe; + sae_pw_id = hostapd_sae_pw_id_in_use(conf); + if (sae_pw_id == 2 && wconf->sae_pwe != 3) + wconf->sae_pwe = 1; + else if (sae_pw_id == 1 && wconf->sae_pwe == 0) + wconf->sae_pwe = 2; +#ifdef CONFIG_OWE + wconf->owe_ptk_workaround = conf->owe_ptk_workaround; +#endif /* CONFIG_OWE */ + wconf->transition_disable = conf->transition_disable; +#ifdef CONFIG_DPP2 + wconf->dpp_pfs = conf->dpp_pfs; +#endif /* CONFIG_DPP2 */ } @@ -362,19 +422,27 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, const u8 *addr, int idx, u8 *key, - size_t key_len) + size_t key_len, enum key_flag key_flag) { struct hostapd_data *hapd = ctx; const char *ifname = hapd->conf->iface; if (vlan_id > 0) { ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); - if (ifname == NULL) - return -1; + if (!ifname) { + if (!(hapd->iface->drv_flags & + WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) + return -1; + ifname = hapd->conf->iface; + } } #ifdef CONFIG_TESTING_OPTIONS - if (addr && !is_broadcast_ether_addr(addr)) { + if (key_flag & KEY_FLAG_MODIFY) { + /* We are updating an already installed key. Don't overwrite + * the already stored key information with zeros. + */ + } else if (addr && !is_broadcast_ether_addr(addr)) { struct sta_info *sta; sta = ap_get_sta(hapd, addr); @@ -402,8 +470,8 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, hapd->last_gtk_len = key_len; } #endif /* CONFIG_TESTING_OPTIONS */ - return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, - key, key_len); + return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, vlan_id, 1, + NULL, 0, key, key_len, key_flag); } @@ -623,10 +691,6 @@ static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, } #endif /* CONFIG_IEEE80211R_AP */ - if (hapd->driver && hapd->driver->send_ether) - return hapd->driver->send_ether(hapd->drv_priv, dst, - hapd->own_addr, proto, - data, data_len); if (hapd->l2 == NULL) return -1; @@ -688,6 +752,12 @@ static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx) dl_list_for_each_safe(data, n, &hapd->l2_oui_queue, struct oui_deliver_later_data, list) { oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix); + wpa_printf(MSG_DEBUG, "RRB(%s): %s src=" MACSTR " dst=" MACSTR + " oui_suffix=%u data_len=%u data=%p", + hapd->conf->iface, __func__, + MAC2STR(data->src_addr), MAC2STR(data->dst_addr), + data->oui_suffix, (unsigned int) data->data_len, + data); if (hapd->wpa_auth && oui_ctx) { eth_p_oui_deliver(oui_ctx, data->src_addr, data->dst_addr, @@ -712,16 +782,26 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx) { struct wpa_auth_oui_iface_iter_data *idata = ctx; struct oui_deliver_later_data *data; - struct hostapd_data *hapd; + struct hostapd_data *hapd, *src_hapd = idata->src_hapd; size_t j; for (j = 0; j < iface->num_bss; j++) { hapd = iface->bss[j]; - if (hapd == idata->src_hapd) - continue; + if (hapd == src_hapd) + continue; /* don't deliver back to same interface */ + if (!wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) || + hapd->conf->ssid.ssid_len != + src_hapd->conf->ssid.ssid_len || + os_memcmp(hapd->conf->ssid.ssid, + src_hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len) != 0 || + os_memcmp(hapd->conf->mobility_domain, + src_hapd->conf->mobility_domain, + MOBILITY_DOMAIN_ID_LEN) != 0) + continue; /* no matching FT SSID/mobility domain */ if (!is_multicast_ether_addr(idata->dst_addr) && os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0) - continue; + continue; /* destination address does not match */ /* defer eth_p_oui_deliver until next eloop step as this is * when it would be triggerd from reading from sock @@ -733,14 +813,20 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx) data = os_zalloc(sizeof(*data) + idata->data_len); if (!data) return 1; + wpa_printf(MSG_DEBUG, + "RRB(%s): local delivery to %s dst=" MACSTR + " oui_suffix=%u data_len=%u data=%p", + src_hapd->conf->iface, hapd->conf->iface, + MAC2STR(idata->dst_addr), idata->oui_suffix, + (unsigned int) idata->data_len, data); - os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN); + os_memcpy(data->src_addr, src_hapd->own_addr, ETH_ALEN); os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN); os_memcpy(data + 1, idata->data, idata->data_len); data->data_len = idata->data_len; data->oui_suffix = idata->oui_suffix; - dl_list_add(&hapd->l2_oui_queue, &data->list); + dl_list_add_tail(&hapd->l2_oui_queue, &data->list); if (!eloop_is_timeout_registered(hostapd_oui_deliver_later, hapd, NULL)) @@ -748,7 +834,11 @@ static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx) hostapd_oui_deliver_later, hapd, NULL); - return 1; + /* If dst_addr is a multicast address, do not return any + * non-zero value here. Otherwise, the iteration of + * for_each_interface() will be stopped. */ + if (!is_multicast_ether_addr(idata->dst_addr)) + return 1; } return 0; @@ -764,6 +854,10 @@ static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix, struct hostapd_data *hapd = ctx; struct eth_p_oui_ctx *oui_ctx; + wpa_printf(MSG_DEBUG, "RRB(%s): send to dst=" MACSTR + " oui_suffix=%u data_len=%u", + hapd->conf->iface, MAC2STR(dst), oui_suffix, + (unsigned int) data_len); #ifdef CONFIG_IEEE80211R_AP if (hapd->iface->interfaces && hapd->iface->interfaces->for_each_interface) { @@ -807,26 +901,32 @@ static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id) #ifndef CONFIG_NO_VLAN struct hostapd_data *hapd = ctx; struct sta_info *sta; - struct vlan_description vlan_desc; sta = ap_get_sta(hapd, addr); if (!sta) return -1; - os_memset(&vlan_desc, 0, sizeof(vlan_desc)); - vlan_desc.notempty = 1; - vlan_desc.untagged = vlan_id; - if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { - wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file", - vlan_id); - return -1; - } + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { + struct vlan_description vlan_desc; - if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) { - wpa_printf(MSG_INFO, - "Failed to assign VLAN ID %d from wpa_psk_file to " - MACSTR, vlan_id, MAC2STR(sta->addr)); - return -1; + os_memset(&vlan_desc, 0, sizeof(vlan_desc)); + vlan_desc.notempty = 1; + vlan_desc.untagged = vlan_id; + if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { + wpa_printf(MSG_INFO, + "Invalid VLAN ID %d in wpa_psk_file", + vlan_id); + return -1; + } + + if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) { + wpa_printf(MSG_INFO, + "Failed to assign VLAN ID %d from wpa_psk_file to " + MACSTR, vlan_id, MAC2STR(sta->addr)); + return -1; + } + } else { + sta->vlan_id = vlan_id; } wpa_printf(MSG_INFO, @@ -888,7 +988,7 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); os_memcpy(&m->u, data, data_len); - res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0); + res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0, NULL, 0, 0); os_free(m); return res; } @@ -1318,6 +1418,22 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) _conf.tx_status = 1; if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) _conf.ap_mlme = 1; + + if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED) && + (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER || + (hapd->conf->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK && + !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) { + wpa_msg(hapd->msg_ctx, MSG_INFO, + "Disable PTK0 rekey support - replaced with disconnect"); + _conf.wpa_deny_ptk0_rekey = 1; + } + + if (_conf.extended_key_id && + (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) + wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Extended Key ID supported"); + else + _conf.extended_key_id = 0; + hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd); if (hapd->wpa_auth == NULL) { wpa_printf(MSG_ERROR, "WPA initialization failed."); @@ -1352,9 +1468,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) hapd->conf->iface; hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB, hostapd_rrb_receive, hapd, 1); - if (hapd->l2 == NULL && - (hapd->driver == NULL || - hapd->driver->send_ether == NULL)) { + if (!hapd->l2) { wpa_printf(MSG_ERROR, "Failed to open l2_packet " "interface"); return -1; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index a993f500..bc59d6a4 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -61,6 +61,8 @@ struct wpa_state_machine { unsigned int pmk_len; u8 pmkid[PMKID_LEN]; /* valid if pmkid_set == 1 */ struct wpa_ptk PTK; + u8 keyidx_active; + Boolean use_ext_key_id; Boolean PTK_valid; Boolean pairwise_set; Boolean tk_already_set; @@ -193,7 +195,9 @@ struct wpa_group { Boolean first_sta_seen; Boolean reject_4way_hs_for_entropy; u8 IGTK[2][WPA_IGTK_MAX_LEN]; + u8 BIGTK[2][WPA_IGTK_MAX_LEN]; int GN_igtk, GM_igtk; + int GN_bigtk, GM_bigtk; /* Number of references except those in struct wpa_group->next */ unsigned int references; unsigned int num_setup_iface; @@ -292,7 +296,7 @@ int wpa_write_ftie(struct wpa_auth_config *conf, int use_sha384, const u8 *r0kh_id, size_t r0kh_id_len, const u8 *anonce, const u8 *snonce, u8 *buf, size_t len, const u8 *subelem, - size_t subelem_len); + size_t subelem_len, int rsnxe_used); int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk); struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 2e6d0591..2ac1df47 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -297,6 +297,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, if (rsn_testing) capab |= BIT(8) | BIT(15); #endif /* CONFIG_RSN_TESTING */ + if (conf->extended_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; WPA_PUT_LE16(pos, capab); pos += 2; @@ -546,13 +548,15 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx) } -int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, - struct wpa_state_machine *sm, int freq, - const u8 *wpa_ie, size_t wpa_ie_len, - const u8 *rsnxe, size_t rsnxe_len, - const u8 *mdie, size_t mdie_len, - const u8 *owe_dh, size_t owe_dh_len) +enum wpa_validate_result +wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, + struct wpa_state_machine *sm, int freq, + const u8 *wpa_ie, size_t wpa_ie_len, + const u8 *rsnxe, size_t rsnxe_len, + const u8 *mdie, size_t mdie_len, + const u8 *owe_dh, size_t owe_dh_len) { + struct wpa_auth_config *conf = &wpa_auth->conf; struct wpa_ie_data data; int ciphers, key_mgmt, res, version; u32 selector; @@ -860,6 +864,16 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #endif /* CONFIG_OWE */ +#ifdef CONFIG_DPP2 + if (sm->wpa_key_mgmt == WPA_KEY_MGMT_DPP && + ((conf->dpp_pfs == 1 && !owe_dh) || + (conf->dpp_pfs == 2 && owe_dh))) { + wpa_printf(MSG_DEBUG, "DPP: PFS %s", + conf->dpp_pfs == 1 ? "required" : "not allowed"); + return WPA_DENIED_OTHER_REASON; + } +#endif /* CONFIG_DPP2 */ + sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0); if (sm->pairwise < 0) return WPA_INVALID_PAIRWISE; @@ -944,6 +958,23 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } #endif /* CONFIG_DPP */ + if (conf->extended_key_id && sm->wpa == WPA_VERSION_WPA2 && + sm->pairwise != WPA_CIPHER_TKIP && + (data.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) { + sm->use_ext_key_id = TRUE; + if (conf->extended_key_id == 2 && + !wpa_key_mgmt_ft(sm->wpa_key_mgmt) && + !wpa_key_mgmt_fils(sm->wpa_key_mgmt)) + sm->keyidx_active = 1; + else + sm->keyidx_active = 0; + wpa_printf(MSG_DEBUG, + "RSN: Extended Key ID supported (start with %d)", + sm->keyidx_active); + } else { + sm->use_ext_key_id = FALSE; + } + if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) { os_free(sm->wpa_ie); sm->wpa_ie = os_malloc(wpa_ie_len); diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c index 175b9fc0..1d77b946 100644 --- a/src/ap/wps_hostapd.c +++ b/src/ap/wps_hostapd.c @@ -125,6 +125,7 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, os_memcpy(p->addr, mac_addr, ETH_ALEN); os_memcpy(p->p2p_dev_addr, p2p_dev_addr, ETH_ALEN); os_memcpy(p->psk, psk, PMK_LEN); + p->wps = 1; if (hapd->new_psk_cb) { hapd->new_psk_cb(hapd->new_psk_cb_ctx, mac_addr, p2p_dev_addr, @@ -137,16 +138,17 @@ static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, if (ssid->wpa_psk_file) { FILE *f; char hex[PMK_LEN * 2 + 1]; + /* Add the new PSK to PSK list file */ f = fopen(ssid->wpa_psk_file, "a"); - if (f == NULL) { - wpa_printf(MSG_DEBUG, "Failed to add the PSK to " - "'%s'", ssid->wpa_psk_file); + if (!f) { + wpa_printf(MSG_DEBUG, "Failed to add the PSK to '%s'", + ssid->wpa_psk_file); return -1; } wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len); - fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex); + fprintf(f, "wps=1 " MACSTR " %s\n", MAC2STR(mac_addr), hex); fclose(f); } @@ -269,6 +271,44 @@ static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr, } +static int hostapd_wps_lookup_pskfile_cb(void *ctx, const u8 *mac_addr, + const u8 **psk) +{ + const struct hostapd_data *hapd = ctx; + const struct hostapd_wpa_psk *wpa_psk; + const u8 *any_psk = NULL; + const u8 *dev_psk = NULL; + + for (wpa_psk = hapd->conf->ssid.wpa_psk; wpa_psk; + wpa_psk = wpa_psk->next) { + if (!wpa_psk->wps) + continue; + + if (!any_psk && is_zero_ether_addr(wpa_psk->addr)) + any_psk = wpa_psk->psk; + + if (mac_addr && !dev_psk && + os_memcmp(mac_addr, wpa_psk->addr, ETH_ALEN) == 0) { + dev_psk = wpa_psk->psk; + break; + } + } + + if (dev_psk) { + *psk = dev_psk; + } else if (any_psk) { + *psk = any_psk; + } else { + *psk = NULL; + wpa_printf(MSG_DEBUG, + "WPS: No appropriate PSK in wpa_psk_file"); + return 0; + } + + return 1; +} + + static void wps_reload_config(void *eloop_data, void *user_ctx) { struct hostapd_iface *iface = eloop_data; @@ -611,8 +651,10 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx) (str_starts(buf, "ssid=") || str_starts(buf, "ssid2=") || str_starts(buf, "auth_algs=") || +#ifdef CONFIG_WEP str_starts(buf, "wep_default_key=") || str_starts(buf, "wep_key") || +#endif /* CONFIG_WEP */ str_starts(buf, "wps_state=") || (pmf_changed && str_starts(buf, "ieee80211w=")) || str_starts(buf, "wpa=") || @@ -985,6 +1027,21 @@ static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd, } +static int hostapd_wps_set_application_ext(struct hostapd_data *hapd, + struct wps_context *wps) +{ + wpabuf_free(wps->dev.application_ext); + + if (!hapd->conf->wps_application_ext) { + wps->dev.application_ext = NULL; + return 0; + } + + wps->dev.application_ext = wpabuf_dup(hapd->conf->wps_application_ext); + return wps->dev.application_ext ? 0 : -1; +} + + static void hostapd_free_wps(struct wps_context *wps) { int i; @@ -1074,7 +1131,8 @@ int hostapd_init_wps(struct hostapd_data *hapd, os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type, WPS_DEV_TYPE_LEN); - if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) + if (hostapd_wps_set_vendor_ext(hapd, wps) < 0 || + hostapd_wps_set_application_ext(hapd, wps) < 0) goto fail; wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version); @@ -1140,6 +1198,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1, conf->ssid.wpa_psk->psk, PMK_LEN); wps->network_key_len = 2 * PMK_LEN; +#ifdef CONFIG_WEP } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) { wps->network_key = os_malloc(conf->ssid.wep.len[0]); if (wps->network_key == NULL) @@ -1147,6 +1206,7 @@ int hostapd_init_wps(struct hostapd_data *hapd, os_memcpy(wps->network_key, conf->ssid.wep.key[0], conf->ssid.wep.len[0]); wps->network_key_len = conf->ssid.wep.len[0]; +#endif /* CONFIG_WEP */ } if (conf->ssid.wpa_psk) { @@ -1197,14 +1257,13 @@ int hostapd_init_wps(struct hostapd_data *hapd, cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; cfg.reg_success_cb = hostapd_wps_reg_success_cb; cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb; + cfg.lookup_pskfile_cb = hostapd_wps_lookup_pskfile_cb; cfg.cb_ctx = hapd; cfg.skip_cred_build = conf->skip_cred_build; cfg.extra_cred = conf->extra_cred; cfg.extra_cred_len = conf->extra_cred_len; cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) && conf->skip_cred_build; - if (conf->ssid.security_policy == SECURITY_STATIC_WEP) - cfg.static_wep_only = 1; cfg.dualband = interface_count(hapd->iface) > 1; if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) == (WPS_RF_50GHZ | WPS_RF_24GHZ)) @@ -1311,6 +1370,7 @@ void hostapd_update_wps(struct hostapd_data *hapd) #endif /* CONFIG_WPS_UPNP */ hostapd_wps_set_vendor_ext(hapd, hapd->wps); + hostapd_wps_set_application_ext(hapd, hapd->wps); if (hapd->conf->wps_state) wps_registrar_update_ie(hapd->wps->registrar); diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c index 7694c96b..a58bf666 100644 --- a/src/common/common_module_tests.c +++ b/src/common/common_module_tests.c @@ -434,7 +434,8 @@ static int sae_tests(void) goto fail; /* Check that output matches the test vector */ - sae_write_commit(&sae, buf, NULL, pwid); + if (sae_write_commit(&sae, buf, NULL, pwid) < 0) + goto fail; wpa_hexdump_buf(MSG_DEBUG, "SAE: Commit message", buf); if (wpabuf_len(buf) != sizeof(local_commit) || diff --git a/src/common/defs.h b/src/common/defs.h index e2fa4b29..f62c3cee 100644 --- a/src/common/defs.h +++ b/src/common/defs.h @@ -82,6 +82,13 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) WPA_KEY_MGMT_FT_FILS_SHA384)); } +static inline int wpa_key_mgmt_wpa_psk_no_sae(int akm) +{ + return !!(akm & (WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256)); +} + static inline int wpa_key_mgmt_wpa_psk(int akm) { return !!(akm & (WPA_KEY_MGMT_PSK | @@ -193,7 +200,6 @@ enum wpa_alg { WPA_ALG_TKIP, WPA_ALG_CCMP, WPA_ALG_IGTK, - WPA_ALG_PMK, WPA_ALG_GCMP, WPA_ALG_SMS4, WPA_ALG_KRK, @@ -423,4 +429,47 @@ enum chan_width { CHAN_WIDTH_UNKNOWN }; +enum key_flag { + KEY_FLAG_MODIFY = BIT(0), + KEY_FLAG_DEFAULT = BIT(1), + KEY_FLAG_RX = BIT(2), + KEY_FLAG_TX = BIT(3), + KEY_FLAG_GROUP = BIT(4), + KEY_FLAG_PAIRWISE = BIT(5), + KEY_FLAG_PMK = BIT(6), + /* Used flag combinations */ + KEY_FLAG_RX_TX = KEY_FLAG_RX | KEY_FLAG_TX, + KEY_FLAG_GROUP_RX_TX = KEY_FLAG_GROUP | KEY_FLAG_RX_TX, + KEY_FLAG_GROUP_RX_TX_DEFAULT = KEY_FLAG_GROUP_RX_TX | + KEY_FLAG_DEFAULT, + KEY_FLAG_GROUP_RX = KEY_FLAG_GROUP | KEY_FLAG_RX, + KEY_FLAG_GROUP_TX_DEFAULT = KEY_FLAG_GROUP | KEY_FLAG_TX | + KEY_FLAG_DEFAULT, + KEY_FLAG_PAIRWISE_RX_TX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX_TX, + KEY_FLAG_PAIRWISE_RX = KEY_FLAG_PAIRWISE | KEY_FLAG_RX, + KEY_FLAG_PAIRWISE_RX_TX_MODIFY = KEY_FLAG_PAIRWISE_RX_TX | + KEY_FLAG_MODIFY, + /* Max allowed flags for each key type */ + KEY_FLAG_PAIRWISE_MASK = KEY_FLAG_PAIRWISE_RX_TX_MODIFY, + KEY_FLAG_GROUP_MASK = KEY_FLAG_GROUP_RX_TX_DEFAULT, + KEY_FLAG_PMK_MASK = KEY_FLAG_PMK, +}; + +static inline int check_key_flag(enum key_flag key_flag) +{ + return !!(!key_flag || + ((key_flag & (KEY_FLAG_PAIRWISE | KEY_FLAG_MODIFY)) && + (key_flag & ~KEY_FLAG_PAIRWISE_MASK)) || + ((key_flag & KEY_FLAG_GROUP) && + (key_flag & ~KEY_FLAG_GROUP_MASK)) || + ((key_flag & KEY_FLAG_PMK) && + (key_flag & ~KEY_FLAG_PMK_MASK))); +} + +enum ptk0_rekey_handling { + PTK0_REKEY_ALLOW_ALWAYS, + PTK0_REKEY_ALLOW_LOCAL_OK, + PTK0_REKEY_ALLOW_NEVER +}; + #endif /* DEFS_H */ diff --git a/src/common/dhcp.h b/src/common/dhcp.h index e38512c2..7dc67d5b 100644 --- a/src/common/dhcp.h +++ b/src/common/dhcp.h @@ -39,7 +39,7 @@ struct dhcp_data { } STRUCT_PACKED; struct bootp_pkt { - struct iphdr iph; + struct ip iph; struct udphdr udph; u8 op; u8 htype; diff --git a/src/common/dpp.c b/src/common/dpp.c index 7542c666..d8690ad5 100644 --- a/src/common/dpp.c +++ b/src/common/dpp.c @@ -1,7 +1,7 @@ /* * DPP functionality shared between hostapd and wpa_supplicant * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -29,6 +29,7 @@ #include "crypto/aes_siv.h" #include "crypto/sha384.h" #include "crypto/sha512.h" +#include "tls/asn1.h" #include "drivers/driver.h" #include "dpp.h" @@ -72,6 +73,14 @@ static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, *ps = sig->s; } + +static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) +{ + if (pkey->type != EVP_PKEY_EC) + return NULL; + return pkey->pkey.ec; +} + #endif @@ -130,6 +139,7 @@ struct dpp_global { struct dl_list tcp_init; /* struct dpp_connection */ void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi); #endif /* CONFIG_DPP2 */ }; @@ -453,6 +463,76 @@ static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len, } +#ifdef CONFIG_DPP2 + +static int dpp_pbkdf2_f(size_t hash_len, + const u8 *password, size_t password_len, + const u8 *salt, size_t salt_len, + unsigned int iterations, unsigned int count, u8 *digest) +{ + unsigned char tmp[DPP_MAX_HASH_LEN], tmp2[DPP_MAX_HASH_LEN]; + unsigned int i; + size_t j; + u8 count_buf[4]; + const u8 *addr[2]; + size_t len[2]; + + addr[0] = salt; + len[0] = salt_len; + addr[1] = count_buf; + len[1] = 4; + + /* F(P, S, c, i) = U1 xor U2 xor ... Uc + * U1 = PRF(P, S || i) + * U2 = PRF(P, U1) + * Uc = PRF(P, Uc-1) + */ + + WPA_PUT_BE32(count_buf, count); + if (dpp_hmac_vector(hash_len, password, password_len, 2, addr, len, + tmp)) + return -1; + os_memcpy(digest, tmp, hash_len); + + for (i = 1; i < iterations; i++) { + if (dpp_hmac(hash_len, password, password_len, tmp, hash_len, + tmp2)) + return -1; + os_memcpy(tmp, tmp2, hash_len); + for (j = 0; j < hash_len; j++) + digest[j] ^= tmp2[j]; + } + + return 0; +} + + +static int dpp_pbkdf2(size_t hash_len, const u8 *password, size_t password_len, + const u8 *salt, size_t salt_len, unsigned int iterations, + u8 *buf, size_t buflen) +{ + unsigned int count = 0; + unsigned char *pos = buf; + size_t left = buflen, plen; + unsigned char digest[DPP_MAX_HASH_LEN]; + + while (left > 0) { + count++; + if (dpp_pbkdf2_f(hash_len, password, password_len, + salt, salt_len, iterations, count, digest)) + return -1; + plen = left > hash_len ? hash_len : left; + os_memcpy(pos, digest, plen); + pos += plen; + left -= plen; + } + + return 0; +} + +#endif /* CONFIG_DPP2 */ + + static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len) { int num_bytes, offset; @@ -820,7 +900,10 @@ void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info) return; os_free(info->uri); os_free(info->info); + os_free(info->chan); + os_free(info->pk); EVP_PKEY_free(info->pubkey); + str_clear_free(info->configurator_params); os_free(info); } @@ -982,6 +1065,32 @@ static const struct dpp_curve_params * dpp_get_curve_nid(int nid) } +static int dpp_bi_pubkey_hash(struct dpp_bootstrap_info *bi, + const u8 *data, size_t data_len) +{ + const u8 *addr[2]; + size_t len[2]; + + addr[0] = data; + len[0] = data_len; + if (sha256_vector(1, addr, len, bi->pubkey_hash) < 0) + return -1; + wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", + bi->pubkey_hash, SHA256_MAC_LEN); + + addr[0] = (const u8 *) "chirp"; + len[0] = 5; + addr[1] = data; + len[1] = data_len; + if (sha256_vector(2, addr, len, bi->pubkey_hash_chirp) < 0) + return -1; + wpa_hexdump(MSG_DEBUG, "DPP: Public key hash (chirp)", + bi->pubkey_hash_chirp, SHA256_MAC_LEN); + + return 0; +} + + static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) { const char *end; @@ -1020,14 +1129,11 @@ static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key", data, data_len); - if (sha256_vector(1, (const u8 **) &data, &data_len, - bi->pubkey_hash) < 0) { + if (dpp_bi_pubkey_hash(bi, data, data_len) < 0) { wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); os_free(data); return -1; } - wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", - bi->pubkey_hash, SHA256_MAC_LEN); /* DER encoded ASN.1 SubjectPublicKeyInfo * @@ -1445,41 +1551,31 @@ fail: } -int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi) +static int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi) { struct wpabuf *der; int res; - const u8 *addr[1]; - size_t len[1]; der = dpp_bootstrap_key_der(bi->pubkey); if (!der) return -1; wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", der); - - addr[0] = wpabuf_head(der); - len[0] = wpabuf_len(der); - res = sha256_vector(1, addr, len, bi->pubkey_hash); + res = dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)); if (res < 0) wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); - else - wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, - SHA256_MAC_LEN); wpabuf_free(der); return res; } -char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, - const u8 *privkey, size_t privkey_len) +static int dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, + const u8 *privkey, size_t privkey_len) { char *base64 = NULL; char *pos, *end; size_t len; struct wpabuf *der = NULL; - const u8 *addr[1]; - int res; if (!curve) { bi->curve = &dpp_curves[0]; @@ -1488,7 +1584,7 @@ char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, if (!bi->curve) { wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", curve); - return NULL; + return -1; } } if (privkey) @@ -1505,15 +1601,10 @@ char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, wpa_hexdump_buf(MSG_DEBUG, "DPP: Compressed public key (DER)", der); - addr[0] = wpabuf_head(der); - len = wpabuf_len(der); - res = sha256_vector(1, addr, &len, bi->pubkey_hash); - if (res < 0) { + if (dpp_bi_pubkey_hash(bi, wpabuf_head(der), wpabuf_len(der)) < 0) { wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); goto fail; } - wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", bi->pubkey_hash, - SHA256_MAC_LEN); base64 = base64_encode(wpabuf_head(der), wpabuf_len(der), &len); wpabuf_free(der); @@ -1528,11 +1619,13 @@ char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, break; os_memmove(pos, pos + 1, end - pos); } - return base64; + os_free(bi->pk); + bi->pk = base64; + return 0; fail: os_free(base64); wpabuf_free(der); - return NULL; + return -1; } @@ -1916,9 +2009,11 @@ static struct wpabuf * dpp_auth_build_resp(struct dpp_authentication *auth, #ifdef CONFIG_DPP2 /* Protocol Version */ - wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); - wpabuf_put_le16(msg, 1); - wpabuf_put_u8(msg, 2); + if (auth->peer_version >= 2) { + wpabuf_put_le16(msg, DPP_ATTR_PROTOCOL_VERSION); + wpabuf_put_le16(msg, 1); + wpabuf_put_u8(msg, 2); + } #endif /* CONFIG_DPP2 */ attr_end = wpabuf_put(msg, 0); @@ -2159,6 +2254,7 @@ static int dpp_channel_local_list(struct dpp_authentication *auth, static int dpp_prepare_channel_list(struct dpp_authentication *auth, + unsigned int neg_freq, struct hostapd_hw_modes *own_modes, u16 num_modes) { @@ -2166,6 +2262,14 @@ static int dpp_prepare_channel_list(struct dpp_authentication *auth, char freqs[DPP_BOOTSTRAP_MAX_FREQ * 6 + 10], *pos, *end; unsigned int i; + if (!own_modes) { + if (!neg_freq) + return -1; + auth->num_freq = 1; + auth->freq[0] = neg_freq; + return 0; + } + if (auth->peer_bi->num_freq > 0) res = dpp_channel_intersect(auth, own_modes, num_modes); else @@ -2198,11 +2302,42 @@ static int dpp_prepare_channel_list(struct dpp_authentication *auth, } +static int dpp_gen_uri(struct dpp_bootstrap_info *bi) +{ + char macstr[ETH_ALEN * 2 + 10]; + size_t len; + + len = 4; /* "DPP:" */ + if (bi->chan) + len += 3 + os_strlen(bi->chan); /* C:...; */ + if (is_zero_ether_addr(bi->mac_addr)) + macstr[0] = '\0'; + else + os_snprintf(macstr, sizeof(macstr), "M:" COMPACT_MACSTR ";", + MAC2STR(bi->mac_addr)); + len += os_strlen(macstr); /* M:...; */ + if (bi->info) + len += 3 + os_strlen(bi->info); /* I:...; */ + len += 4 + os_strlen(bi->pk); /* K:...;; */ + + os_free(bi->uri); + bi->uri = os_malloc(len + 1); + if (!bi->uri) + return -1; + os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%sK:%s;;", + bi->chan ? "C:" : "", bi->chan ? bi->chan : "", + bi->chan ? ";" : "", + macstr, + bi->info ? "I:" : "", bi->info ? bi->info : "", + bi->info ? ";" : "", + bi->pk); + return 0; +} + + static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth) { struct dpp_bootstrap_info *bi; - char *pk = NULL; - size_t len; if (auth->own_bi) return 0; /* already generated */ @@ -2211,33 +2346,38 @@ static int dpp_autogen_bootstrap_key(struct dpp_authentication *auth) if (!bi) return -1; bi->type = DPP_BOOTSTRAP_QR_CODE; - pk = dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0); - if (!pk) - goto fail; - - len = 4; /* "DPP:" */ - len += 4 + os_strlen(pk); - bi->uri = os_malloc(len + 1); - if (!bi->uri) + if (dpp_keygen(bi, auth->peer_bi->curve->name, NULL, 0) < 0 || + dpp_gen_uri(bi) < 0) goto fail; - os_snprintf(bi->uri, len + 1, "DPP:K:%s;;", pk); wpa_printf(MSG_DEBUG, "DPP: Auto-generated own bootstrapping key info: URI %s", bi->uri); auth->tmp_own_bi = auth->own_bi = bi; - os_free(pk); - return 0; fail: - os_free(pk); dpp_bootstrap_info_free(bi); return -1; } -struct dpp_authentication * dpp_auth_init(void *msg_ctx, +struct dpp_authentication * +dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx) +{ + struct dpp_authentication *auth; + + auth = os_zalloc(sizeof(*auth)); + if (!auth) + return NULL; + auth->global = dpp; + auth->msg_ctx = msg_ctx; + auth->conf_resp_status = 255; + return auth; +} + + +struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, u8 dpp_allowed_roles, @@ -2254,10 +2394,12 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, u8 test_hash[SHA256_MAC_LEN]; #endif /* CONFIG_TESTING_OPTIONS */ - auth = os_zalloc(sizeof(*auth)); + auth = dpp_alloc_auth(dpp, msg_ctx); if (!auth) return NULL; - auth->msg_ctx = msg_ctx; + if (peer_bi->configurator_params && + dpp_set_configurator(auth, peer_bi->configurator_params) < 0) + goto fail; auth->initiator = 1; auth->waiting_auth_resp = 1; auth->allowed_roles = dpp_allowed_roles; @@ -2267,7 +2409,7 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, auth->curve = peer_bi->curve; if (dpp_autogen_bootstrap_key(auth) < 0 || - dpp_prepare_channel_list(auth, own_modes, num_modes) < 0) + dpp_prepare_channel_list(auth, neg_freq, own_modes, num_modes) < 0) goto fail; #ifdef CONFIG_TESTING_OPTIONS @@ -2363,6 +2505,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, } #endif /* CONFIG_TESTING_OPTIONS */ + if (neg_freq && auth->num_freq == 1 && auth->freq[0] == neg_freq) + neg_freq = 0; auth->req_msg = dpp_auth_build_req(auth, pi, nonce_len, r_pubkey_hash, i_pubkey_hash, neg_freq); if (!auth->req_msg) @@ -3149,8 +3293,8 @@ static int dpp_auth_build_resp_status(struct dpp_authentication *auth, struct dpp_authentication * -dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, - struct dpp_bootstrap_info *peer_bi, +dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles, + int qr_mutual, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, unsigned int freq, const u8 *hdr, const u8 *attr_start, size_t attr_len) @@ -3191,10 +3335,12 @@ dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, wrapped_data, wrapped_data_len); attr_len = wrapped_data - 4 - attr_start; - auth = os_zalloc(sizeof(*auth)); + auth = dpp_alloc_auth(dpp, msg_ctx); if (!auth) goto fail; - auth->msg_ctx = msg_ctx; + if (peer_bi && peer_bi->configurator_params && + dpp_set_configurator(auth, peer_bi->configurator_params) < 0) + goto fail; auth->peer_bi = peer_bi; auth->own_bi = own_bi; auth->curve = own_bi->curve; @@ -4137,7 +4283,11 @@ int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, } #endif /* CONFIG_TESTING_OPTIONS */ - if (auth->initiator || !auth->own_bi) { + if (auth->initiator || !auth->own_bi || !auth->waiting_auth_conf) { + wpa_printf(MSG_DEBUG, + "DPP: initiator=%d own_bi=%d waiting_auth_conf=%d", + auth->initiator, !!auth->own_bi, + auth->waiting_auth_conf); dpp_auth_fail(auth, "Unexpected Authentication Confirm"); return -1; } @@ -4404,6 +4554,10 @@ static int dpp_configuration_parse_helper(struct dpp_authentication *auth, conf = conf_ap; } + pos = os_strstr(cmd, " conf=configurator"); + if (pos) + auth->provision_configurator = 1; + if (!conf) return 0; @@ -4558,25 +4712,38 @@ dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id) } -int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx, - struct dpp_authentication *auth, - const char *cmd) +int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd) { const char *pos; + char *tmp = NULL; + int ret = -1; - if (!cmd) + if (!cmd || auth->configurator_set) return 0; + auth->configurator_set = 1; + + if (cmd[0] != ' ') { + size_t len; + + len = os_strlen(cmd); + tmp = os_malloc(len + 2); + if (!tmp) + goto fail; + tmp[0] = ' '; + os_memcpy(tmp + 1, cmd, len + 1); + cmd = tmp; + } wpa_printf(MSG_DEBUG, "DPP: Set configurator parameters: %s", cmd); pos = os_strstr(cmd, " configurator="); if (pos) { pos += 14; - auth->conf = dpp_configurator_get_id(dpp, atoi(pos)); + auth->conf = dpp_configurator_get_id(auth->global, atoi(pos)); if (!auth->conf) { wpa_printf(MSG_INFO, "DPP: Could not find the specified configurator"); - return -1; + goto fail; } } @@ -4593,11 +4760,28 @@ int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx, } if (dpp_configuration_parse(auth, cmd) < 0) { - wpa_msg(msg_ctx, MSG_INFO, + wpa_msg(auth->msg_ctx, MSG_INFO, "DPP: Failed to set configurator parameters"); - return -1; + goto fail; + } + ret = 0; +fail: + os_free(tmp); + return ret; +} + + +static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key) +{ + while (key) { + struct dpp_asymmetric_key *next = key->next; + + EVP_PKEY_free(key->csign); + str_clear_free(key->config_template); + str_clear_free(key->connector_template); + os_free(key); + key = next; } - return 0; } @@ -4622,6 +4806,7 @@ void dpp_auth_deinit(struct dpp_authentication *auth) os_free(conf->connector); wpabuf_free(conf->c_sign_key); } + dpp_free_asymmetric_key(auth->conf_key_pkg); wpabuf_free(auth->net_access_key); dpp_bootstrap_info_free(auth->tmp_own_bi); #ifdef CONFIG_TESTING_OPTIONS @@ -5051,17 +5236,499 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole, return NULL; } - if (dpp_akm_dpp(conf->akm)) + if (dpp_akm_dpp(conf->akm) || (auth->peer_version >= 2 && auth->conf)) return dpp_build_conf_obj_dpp(auth, conf); return dpp_build_conf_obj_legacy(auth, conf); } +#ifdef CONFIG_DPP2 + +static struct wpabuf * dpp_build_conf_params(void) +{ + struct wpabuf *buf; + size_t len; + /* TODO: proper template values */ + const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}"; + const char *connector_template = NULL; + + len = 100 + os_strlen(conf_template); + if (connector_template) + len += os_strlen(connector_template); + buf = wpabuf_alloc(len); + if (!buf) + return NULL; + + /* + * DPPConfigurationParameters ::= SEQUENCE { + * configurationTemplate UTF8String, + * connectorTemplate UTF8String OPTIONAL} + */ + + asn1_put_utf8string(buf, conf_template); + if (connector_template) + asn1_put_utf8string(buf, connector_template); + return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); +} + + +static struct wpabuf * dpp_build_attribute(void) +{ + struct wpabuf *conf_params, *attr; + + /* + * aa-DPPConfigurationParameters ATTRIBUTE ::= + * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams } + * + * Attribute ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * values SET SIZE(1..MAX) OF Type + */ + conf_params = dpp_build_conf_params(); + conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL, + ASN1_TAG_SET); + if (!conf_params) + return NULL; + + attr = wpabuf_alloc(100 + wpabuf_len(conf_params)); + if (!attr) { + wpabuf_clear_free(conf_params); + return NULL; + } + + asn1_put_oid(attr, &asn1_dpp_config_params_oid); + wpabuf_put_buf(attr, conf_params); + wpabuf_clear_free(conf_params); + + return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); +} + + +static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve) +{ + const struct asn1_oid *oid; + struct wpabuf *params, *res; + + switch (curve->ike_group) { + case 19: + oid = &asn1_prime256v1_oid; + break; + case 20: + oid = &asn1_secp384r1_oid; + break; + case 21: + oid = &asn1_secp521r1_oid; + break; + case 28: + oid = &asn1_brainpoolP256r1_oid; + break; + case 29: + oid = &asn1_brainpoolP384r1_oid; + break; + case 30: + oid = &asn1_brainpoolP512r1_oid; + break; + default: + return NULL; + } + + params = wpabuf_alloc(20); + if (!params) + return NULL; + asn1_put_oid(params, oid); /* namedCurve */ + + res = asn1_build_alg_id(&asn1_ec_public_key_oid, params); + wpabuf_free(params); + return res; +} + + +static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth) +{ + struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL; + EC_KEY *eckey; + unsigned char *der = NULL; + int der_len; + + eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign); + if (!eckey) + return NULL; + + EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY); + der_len = i2d_ECPrivateKey(eckey, &der); + if (der_len > 0) + priv_key = wpabuf_alloc_copy(der, der_len); + OPENSSL_free(der); + + alg = dpp_build_key_alg(auth->conf->curve); + + /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */ + attr = dpp_build_attribute(); + attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET); + if (!priv_key || !attr || !alg) + goto fail; + + /* + * OneAsymmetricKey ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL, + * ..., + * [[2: publicKey [1] BIT STRING OPTIONAL ]], + * ... + * } + */ + + key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) + + wpabuf_len(attr)); + if (!key) + goto fail; + + asn1_put_integer(key, 1); /* version = v2(1) */ + + /* PrivateKeyAlgorithmIdentifier */ + wpabuf_put_buf(key, alg); + + /* PrivateKey ::= OCTET STRING */ + asn1_put_octet_string(key, priv_key); + + /* [0] Attributes OPTIONAL */ + asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr)); + wpabuf_put_buf(key, attr); + +fail: + wpabuf_clear_free(attr); + wpabuf_clear_free(priv_key); + wpabuf_free(alg); + + /* + * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage + * + * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey + * + * OneAsymmetricKey ::= SEQUENCE + */ + return asn1_encaps(asn1_encaps(key, + ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE), + ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); +} + + +static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt, + size_t hash_len) +{ + struct wpabuf *params = NULL, *buf = NULL, *prf = NULL; + const struct asn1_oid *oid; + + /* + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier} + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX), + * prf AlgorithmIdentifier} + * + * salt is an 64 octet value, iterationCount is 1000, keyLength is based + * on Configurator signing key length, prf is + * id-hmacWithSHA{256,384,512} based on Configurator signing key. + */ + + if (hash_len == 32) + oid = &asn1_pbkdf2_hmac_sha256_oid; + else if (hash_len == 48) + oid = &asn1_pbkdf2_hmac_sha384_oid; + else if (hash_len == 64) + oid = &asn1_pbkdf2_hmac_sha512_oid; + else + goto fail; + prf = asn1_build_alg_id(oid, NULL); + if (!prf) + goto fail; + params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf)); + if (!params) + goto fail; + asn1_put_octet_string(params, salt); /* salt.specified */ + asn1_put_integer(params, 1000); /* iterationCount */ + asn1_put_integer(params, hash_len); /* keyLength */ + wpabuf_put_buf(params, prf); + params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); + if (!params) + goto fail; + buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params); +fail: + wpabuf_free(params); + wpabuf_free(prf); + return buf; +} + + +static struct wpabuf * +dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len, + const struct wpabuf *cont_enc_key) +{ + struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL, + *key_enc_alg = NULL, *salt; + u8 kek[DPP_MAX_HASH_LEN]; + const u8 *key; + size_t key_len; + + salt = wpabuf_alloc(64); + if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0) + goto fail; + wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt); + + /* TODO: For initial testing, use ke as the key. Replace this with a + * new key once that has been defined. */ + key = auth->ke; + key_len = auth->curve->hash_len; + wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len); + + if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000, + kek, hash_len)) { + wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed"); + goto fail; + } + wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2", + kek, hash_len); + + enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE); + if (!enc_key || + aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key), + wpabuf_len(cont_enc_key), 0, NULL, NULL, + wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0) + goto fail; + wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key); + + /* + * PasswordRecipientInfo ::= SEQUENCE { + * version CMSVersion, + * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey} + * + * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the + * parameters contains PBKDF2-params SEQUENCE. + */ + + key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len); + key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL); + if (!key_der_alg || !key_enc_alg) + goto fail; + pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) + + wpabuf_len(key_enc_alg) + wpabuf_len(enc_key)); + if (!pwri) + goto fail; + + /* version = 0 */ + asn1_put_integer(pwri, 0); + + /* [0] KeyDerivationAlgorithmIdentifier */ + asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, + wpabuf_len(key_der_alg)); + wpabuf_put_buf(pwri, key_der_alg); + + /* KeyEncryptionAlgorithmIdentifier */ + wpabuf_put_buf(pwri, key_enc_alg); + + /* EncryptedKey ::= OCTET STRING */ + asn1_put_octet_string(pwri, enc_key); + +fail: + wpabuf_clear_free(key_der_alg); + wpabuf_free(key_enc_alg); + wpabuf_free(enc_key); + wpabuf_free(salt); + forced_memzero(kek, sizeof(kek)); + return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); +} + + +static struct wpabuf * +dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len, + const struct wpabuf *cont_enc_key) +{ + struct wpabuf *pwri; + + /* + * RecipientInfo ::= CHOICE { + * ktri KeyTransRecipientInfo, + * kari [1] KeyAgreeRecipientInfo, + * kekri [2] KEKRecipientInfo, + * pwri [3] PasswordRecipientInfo, + * ori [4] OtherRecipientInfo} + * + * Shall always use the pwri CHOICE. + */ + + pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key); + return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3); +} + + +static struct wpabuf * +dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len, + const struct wpabuf *cont_enc_key) +{ + struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL, + *enc_alg; + const struct asn1_oid *oid; + size_t enc_cont_len; + + /* + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL} + */ + + if (hash_len == 32) + oid = &asn1_aes_siv_cmac_aead_256_oid; + else if (hash_len == 48) + oid = &asn1_aes_siv_cmac_aead_384_oid; + else if (hash_len == 64) + oid = &asn1_aes_siv_cmac_aead_512_oid; + else + return NULL; + + key_pkg = dpp_build_key_pkg(auth); + enc_alg = asn1_build_alg_id(oid, NULL); + if (!key_pkg || !enc_alg) + goto fail; + + wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage", + key_pkg); + + enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE; + enc_cont = wpabuf_alloc(enc_cont_len); + if (!enc_cont || + aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key), + wpabuf_head(key_pkg), wpabuf_len(key_pkg), + 0, NULL, NULL, + wpabuf_put(enc_cont, enc_cont_len)) < 0) + goto fail; + + enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) + + wpabuf_len(enc_cont)); + if (!enc_cont_info) + goto fail; + + /* ContentType ::= OBJECT IDENTIFIER */ + asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid); + + /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */ + wpabuf_put_buf(enc_cont_info, enc_alg); + + /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * EncryptedContent ::= OCTET STRING */ + asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0, + wpabuf_len(enc_cont)); + wpabuf_put_buf(enc_cont_info, enc_cont); + +fail: + wpabuf_clear_free(key_pkg); + wpabuf_free(enc_cont); + wpabuf_free(enc_alg); + return enc_cont_info; +} + + +static struct wpabuf * dpp_gen_random(size_t len) +{ + struct wpabuf *key; + + key = wpabuf_alloc(len); + if (!key || os_get_random(wpabuf_put(key, len), len) < 0) { + wpabuf_free(key); + key = NULL; + } + wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key); + return key; +} + + +static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth) +{ + struct wpabuf *env = NULL; + struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL; + struct wpabuf *cont_enc_key = NULL; + size_t hash_len; + + if (!auth->conf) { + wpa_printf(MSG_DEBUG, + "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData"); + return NULL; + } + + if (!auth->provision_configurator) { + wpa_printf(MSG_DEBUG, + "DPP: Configurator provisioning not allowed"); + return NULL; + } + + wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData"); + + hash_len = auth->conf->curve->hash_len; + cont_enc_key = dpp_gen_random(hash_len); + if (!cont_enc_key) + goto fail; + recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key); + enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key); + if (!recipient_info || !enc_cont_info) + goto fail; + + env = wpabuf_alloc(wpabuf_len(recipient_info) + + wpabuf_len(enc_cont_info) + + 100); + if (!env) + goto fail; + + /* + * DPPEnvelopedData ::= EnvelopedData + * + * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL} + * + * For DPP, version is 3, both originatorInfo and + * unprotectedAttrs are omitted, and recipientInfos contains a single + * RecipientInfo. + */ + + /* EnvelopedData.version = 3 */ + asn1_put_integer(env, 3); + + /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */ + asn1_put_set(env, recipient_info); + + /* EncryptedContentInfo ::= SEQUENCE */ + asn1_put_sequence(env, enc_cont_info); + + env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); + wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env); +out: + wpabuf_clear_free(cont_enc_key); + wpabuf_clear_free(recipient_info); + wpabuf_free(enc_cont_info); + return env; +fail: + wpabuf_free(env); + env = NULL; + goto out; +} + +#endif /* CONFIG_DPP2 */ + + static struct wpabuf * dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, u16 e_nonce_len, enum dpp_netrole netrole) { - struct wpabuf *conf, *conf2 = NULL; + struct wpabuf *conf = NULL, *conf2 = NULL, *env_data = NULL; size_t clear_len, attr_len; struct wpabuf *clear = NULL, *msg = NULL; u8 *wrapped; @@ -5069,13 +5736,21 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, size_t len[1]; enum dpp_status_error status; - conf = dpp_build_conf_obj(auth, netrole, 0); - if (conf) { - wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON", - wpabuf_head(conf), wpabuf_len(conf)); - conf2 = dpp_build_conf_obj(auth, netrole, 1); + if (netrole == DPP_NETROLE_CONFIGURATOR) { +#ifdef CONFIG_DPP2 + env_data = dpp_build_enveloped_data(auth); +#endif /* CONFIG_DPP2 */ + } else { + conf = dpp_build_conf_obj(auth, netrole, 0); + if (conf) { + wpa_hexdump_ascii(MSG_DEBUG, + "DPP: configurationObject JSON", + wpabuf_head(conf), wpabuf_len(conf)); + conf2 = dpp_build_conf_obj(auth, netrole, 1); + } } - status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE; + status = (conf || env_data) ? DPP_STATUS_OK : + DPP_STATUS_CONFIGURE_FAILURE; auth->conf_resp_status = status; /* { E-nonce, configurationObject[, sendConnStatus]}ke */ @@ -5084,6 +5759,8 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, clear_len += 4 + wpabuf_len(conf); if (conf2) clear_len += 4 + wpabuf_len(conf2); + if (env_data) + clear_len += 4 + wpabuf_len(env_data); if (auth->peer_version >= 2 && auth->send_conn_status && netrole == DPP_NETROLE_STA) clear_len += 4; @@ -5142,6 +5819,11 @@ skip_e_nonce: wpa_printf(MSG_DEBUG, "DPP: Second Config Object available, but peer does not support more than one"); } + if (env_data) { + wpabuf_put_le16(clear, DPP_ATTR_ENVELOPED_DATA); + wpabuf_put_le16(clear, wpabuf_len(env_data)); + wpabuf_put_buf(clear, env_data); + } if (auth->peer_version >= 2 && auth->send_conn_status && netrole == DPP_NETROLE_STA) { @@ -5196,9 +5878,10 @@ skip_wrapped_data: wpa_hexdump_buf(MSG_DEBUG, "DPP: Configuration Response attributes", msg); out: - wpabuf_free(conf); - wpabuf_free(conf2); - wpabuf_free(clear); + wpabuf_clear_free(conf); + wpabuf_clear_free(conf2); + wpabuf_clear_free(env_data); + wpabuf_clear_free(clear); return msg; fail: @@ -6047,7 +6730,8 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth, conf->connector = os_strdup(signed_connector); dpp_copy_csign(conf, csign_pub); - dpp_copy_netaccesskey(auth, conf); + if (dpp_akm_dpp(conf->akm)) + dpp_copy_netaccesskey(auth, conf); ret = 0; fail: @@ -6159,6 +6843,7 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth, struct json_token *root, *token, *discovery, *cred; struct dpp_config_obj *conf; struct wpabuf *ssid64 = NULL; + int legacy; root = json_parse((const char *) conf_obj, conf_obj_len); if (!root) @@ -6246,10 +6931,21 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth, } conf->akm = dpp_akm_from_str(token->string); - if (dpp_akm_legacy(conf->akm)) { + legacy = dpp_akm_legacy(conf->akm); + if (legacy && auth->peer_version >= 2) { + struct json_token *csign, *s_conn; + + csign = json_get_member(cred, "csign"); + s_conn = json_get_member(cred, "signedConnector"); + if (csign && csign->type == JSON_OBJECT && + s_conn && s_conn->type == JSON_STRING) + legacy = 0; + } + if (legacy) { if (dpp_parse_cred_legacy(conf, cred) < 0) goto fail; - } else if (dpp_akm_dpp(conf->akm)) { + } else if (dpp_akm_dpp(conf->akm) || + (auth->peer_version >= 2 && dpp_akm_legacy(conf->akm))) { if (dpp_parse_cred_dpp(auth, conf, cred) < 0) goto fail; } else { @@ -6268,11 +6964,716 @@ fail: } +#ifdef CONFIG_DPP2 + +struct dpp_enveloped_data { + const u8 *enc_cont; + size_t enc_cont_len; + const u8 *enc_key; + size_t enc_key_len; + const u8 *salt; + size_t pbkdf2_key_len; + size_t prf_hash_len; +}; + + +static int dpp_parse_recipient_infos(const u8 *pos, size_t len, + struct dpp_enveloped_data *data) +{ + struct asn1_hdr hdr; + const u8 *end = pos + len; + const u8 *next, *e_end; + struct asn1_oid oid; + int val; + const u8 *params; + size_t params_len; + + wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len); + + /* + * RecipientInfo ::= CHOICE { + * ktri KeyTransRecipientInfo, + * kari [1] KeyAgreeRecipientInfo, + * kekri [2] KEKRecipientInfo, + * pwri [3] PasswordRecipientInfo, + * ori [4] OtherRecipientInfo} + * + * Shall always use the pwri CHOICE. + */ + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) { + wpa_printf(MSG_DEBUG, + "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo", + hdr.payload, hdr.length); + pos = hdr.payload; + end = pos + hdr.length; + + /* + * PasswordRecipientInfo ::= SEQUENCE { + * version CMSVersion, + * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL, + * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, + * encryptedKey EncryptedKey} + * + * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the + * parameters contains PBKDF2-params SEQUENCE. + */ + + if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0) + return -1; + pos = hdr.payload; + + if (asn1_get_integer(pos, end - pos, &val, &pos) < 0) + return -1; + if (val != 0) { + wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0"); + return -1; + } + + wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version", + pos, end - pos); + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) { + wpa_printf(MSG_DEBUG, + "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + pos = hdr.payload; + e_end = pos + hdr.length; + + /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */ + if (asn1_get_alg_id(pos, e_end - pos, &oid, ¶ms, ¶ms_len, + &next) < 0) + return -1; + if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) { + char buf[80]; + + asn1_oid_to_str(&oid, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, + "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s", + buf); + return -1; + } + + /* + * PBKDF2-params ::= SEQUENCE { + * salt CHOICE { + * specified OCTET STRING, + * otherSource AlgorithmIdentifier} + * iterationCount INTEGER (1..MAX), + * keyLength INTEGER (1..MAX), + * prf AlgorithmIdentifier} + * + * salt is an 64 octet value, iterationCount is 1000, keyLength is based + * on Configurator signing key length, prf is + * id-hmacWithSHA{256,384,512} based on Configurator signing key. + */ + if (!params || + asn1_get_sequence(params, params_len, &hdr, &e_end) < 0) + return -1; + pos = hdr.payload; + + if (asn1_get_next(pos, e_end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified", + hdr.payload, hdr.length); + if (hdr.length != 64) { + wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u", + hdr.length); + return -1; + } + data->salt = hdr.payload; + pos = hdr.payload + hdr.length; + + if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0) + return -1; + if (val != 1000) { + wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val); + return -1; + } + + if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0) + return -1; + if (val != 32 && val != 48 && val != 64) { + wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val); + return -1; + } + data->pbkdf2_key_len = val; + + if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 || + asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Could not parse prf"); + return -1; + } + if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) { + data->prf_hash_len = 32; + } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) { + data->prf_hash_len = 48; + } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) { + data->prf_hash_len = 64; + } else { + char buf[80]; + + asn1_oid_to_str(&oid, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s", + buf); + return -1; + } + + pos = next; + + /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier + * + * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or + * id-alg-AES-SIV-CMAC-aed-512. */ + if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0) + return -1; + if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) && + !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) && + !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) { + char buf[80]; + + asn1_oid_to_str(&oid, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, + "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s", + buf); + return -1; + } + + /* + * encryptedKey EncryptedKey + * + * EncryptedKey ::= OCTET STRING + */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey", + hdr.payload, hdr.length); + data->enc_key = hdr.payload; + data->enc_key_len = hdr.length; + + return 0; +} + + +static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end, + struct dpp_enveloped_data *data) +{ + struct asn1_hdr hdr; + struct asn1_oid oid; + + /* + * EncryptedContentInfo ::= SEQUENCE { + * contentType ContentType, + * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL} + */ + if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0) + return -1; + wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo", + hdr.payload, hdr.length); + if (pos < end) { + wpa_hexdump(MSG_DEBUG, + "DPP: Unexpected extra data after EncryptedContentInfo", + pos, end - pos); + return -1; + } + + end = pos; + pos = hdr.payload; + + /* ContentType ::= OBJECT IDENTIFIER */ + if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) { + wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType"); + return -1; + } + if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) { + char buf[80]; + + asn1_oid_to_str(&oid, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf); + return -1; + } + + /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */ + if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0) + return -1; + if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) && + !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) && + !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) { + char buf[80]; + + asn1_oid_to_str(&oid, buf, sizeof(buf)); + wpa_printf(MSG_DEBUG, + "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s", + buf); + return -1; + } + /* ignore optional parameters */ + + /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * EncryptedContent ::= OCTET STRING */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) { + wpa_printf(MSG_DEBUG, + "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent", + hdr.payload, hdr.length); + data->enc_cont = hdr.payload; + data->enc_cont_len = hdr.length; + return 0; +} + + +static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len, + struct dpp_enveloped_data *data) +{ + struct asn1_hdr hdr; + const u8 *pos, *end; + int val; + + os_memset(data, 0, sizeof(*data)); + + /* + * DPPEnvelopedData ::= EnvelopedData + * + * EnvelopedData ::= SEQUENCE { + * version CMSVersion, + * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, + * recipientInfos RecipientInfos, + * encryptedContentInfo EncryptedContentInfo, + * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL} + * + * CMSVersion ::= INTEGER + * + * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo + * + * For DPP, version is 3, both originatorInfo and + * unprotectedAttrs are omitted, and recipientInfos contains a single + * RecipientInfo. + */ + if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0) + return -1; + pos = hdr.payload; + if (end < env_data + env_data_len) { + wpa_hexdump(MSG_DEBUG, + "DPP: Unexpected extra data after DPPEnvelopedData", + end, env_data + env_data_len - end); + return -1; + } + + if (asn1_get_integer(pos, end - pos, &val, &pos) < 0) + return -1; + if (val != 3) { + wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3"); + return -1; + } + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) { + wpa_printf(MSG_DEBUG, + "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + + if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0) + return -1; + return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end, + data); +} + + +static struct dpp_asymmetric_key * +dpp_parse_one_asymmetric_key(const u8 *buf, size_t len) +{ + struct asn1_hdr hdr; + const u8 *pos = buf, *end = buf + len, *next; + int val; + const u8 *params; + size_t params_len; + struct asn1_oid oid; + char txt[80]; + struct dpp_asymmetric_key *key; + EC_KEY *eckey; + + wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len); + + key = os_zalloc(sizeof(*key)); + if (!key) + return NULL; + + /* + * OneAsymmetricKey ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL, + * ..., + * [[2: publicKey [1] BIT STRING OPTIONAL ]], + * ... + * } + */ + if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0) + goto fail; + pos = hdr.payload; + + /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */ + if (asn1_get_integer(pos, end - pos, &val, &pos) < 0) + goto fail; + if (val != 1) { + wpa_printf(MSG_DEBUG, + "DPP: Unsupported DPPAsymmetricKeyPackage version %d", + val); + goto fail; + } + + /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */ + if (asn1_get_alg_id(pos, end - pos, &oid, ¶ms, ¶ms_len, + &pos) < 0) + goto fail; + if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) { + asn1_oid_to_str(&oid, txt, sizeof(txt)); + wpa_printf(MSG_DEBUG, + "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s", + txt); + goto fail; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params", + params, params_len); + /* + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * -- implicitCurve NULL + * -- specifiedCurve SpecifiedECDomain} + */ + if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Could not parse ECParameters.namedCurve"); + goto fail; + } + asn1_oid_to_str(&oid, txt, sizeof(txt)); + wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt); + /* Assume the curve is identified within ECPrivateKey, so that this + * separate indication is not really needed. */ + + /* + * PrivateKey ::= OCTET STRING + * (Contains DER encoding of ECPrivateKey) + */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey", + hdr.payload, hdr.length); + pos = hdr.payload + hdr.length; + eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length); + if (!eckey) { + wpa_printf(MSG_INFO, + "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + goto fail; + } + key->csign = EVP_PKEY_new(); + if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) { + EC_KEY_free(eckey); + goto fail; + } + if (wpa_debug_show_keys) + dpp_debug_print_key("DPP: Received c-sign-key", key->csign); + + /* + * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } + * + * Exactly one instance of type Attribute in OneAsymmetricKey. + */ + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) { + wpa_printf(MSG_DEBUG, + "DPP: Expected [0] Attributes - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes", + hdr.payload, hdr.length); + if (hdr.payload + hdr.length < end) { + wpa_hexdump_key(MSG_MSGDUMP, + "DPP: Ignore additional data at the end of OneAsymmetricKey", + hdr.payload + hdr.length, + end - (hdr.payload + hdr.length)); + } + pos = hdr.payload; + end = hdr.payload + hdr.length; + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) { + wpa_printf(MSG_DEBUG, + "DPP: Expected SET (Attributes) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + if (hdr.payload + hdr.length < end) { + wpa_hexdump_key(MSG_MSGDUMP, + "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)", + hdr.payload + hdr.length, + end - (hdr.payload + hdr.length)); + } + pos = hdr.payload; + end = hdr.payload + hdr.length; + + /* + * OneAsymmetricKeyAttributes ATTRIBUTE ::= { + * aa-DPPConfigurationParameters, + * ... -- For local profiles + * } + * + * aa-DPPConfigurationParameters ATTRIBUTE ::= + * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams } + * + * Attribute ::= SEQUENCE { + * type OBJECT IDENTIFIER, + * values SET SIZE(1..MAX) OF Type + * + * Exactly one instance of ATTRIBUTE in attrValues. + */ + if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0) + goto fail; + if (pos < end) { + wpa_hexdump_key(MSG_MSGDUMP, + "DPP: Ignore additional data at the end of ATTRIBUTE", + pos, end - pos); + } + end = pos; + pos = hdr.payload; + + if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) + goto fail; + if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) { + asn1_oid_to_str(&oid, txt, sizeof(txt)); + wpa_printf(MSG_DEBUG, + "DPP: Unexpected Attribute identifier %s", txt); + goto fail; + } + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) { + wpa_printf(MSG_DEBUG, + "DPP: Expected SET (Attribute) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + pos = hdr.payload; + end = hdr.payload + hdr.length; + + /* + * DPPConfigurationParameters ::= SEQUENCE { + * configurationTemplate UTF8String, + * connectorTemplate UTF8String OPTIONAL} + */ + + wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters", + pos, end - pos); + if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0) + goto fail; + if (pos < end) { + wpa_hexdump_key(MSG_MSGDUMP, + "DPP: Ignore additional data after DPPConfigurationParameters", + pos, end - pos); + } + end = pos; + pos = hdr.payload; + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_UTF8STRING) { + wpa_printf(MSG_DEBUG, + "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate", + hdr.payload, hdr.length); + key->config_template = os_zalloc(hdr.length + 1); + if (!key->config_template) + goto fail; + os_memcpy(key->config_template, hdr.payload, hdr.length); + + pos = hdr.payload + hdr.length; + + if (pos < end) { + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_UTF8STRING) { + wpa_printf(MSG_DEBUG, + "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x", + hdr.class, hdr.tag); + goto fail; + } + wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate", + hdr.payload, hdr.length); + key->connector_template = os_zalloc(hdr.length + 1); + if (!key->connector_template) + goto fail; + os_memcpy(key->connector_template, hdr.payload, hdr.length); + } + + return key; +fail: + wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey"); + dpp_free_asymmetric_key(key); + return NULL; +} + + +static struct dpp_asymmetric_key * +dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len) +{ + struct asn1_hdr hdr; + const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len; + struct dpp_asymmetric_key *first = NULL, *last = NULL, *key; + + wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage", + key_pkg, key_pkg_len); + + /* + * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage + * + * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey + */ + while (pos < end) { + if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 || + !(key = dpp_parse_one_asymmetric_key(hdr.payload, + hdr.length))) { + dpp_free_asymmetric_key(first); + return NULL; + } + if (!last) { + first = last = key; + } else { + last->next = key; + last = key; + } + } + + return first; +} + + +static int dpp_conf_resp_env_data(struct dpp_authentication *auth, + const u8 *env_data, size_t env_data_len) +{ + const u8 *key; + size_t key_len; + u8 kek[DPP_MAX_HASH_LEN]; + u8 cont_encr_key[DPP_MAX_HASH_LEN]; + size_t cont_encr_key_len; + int res; + u8 *key_pkg; + size_t key_pkg_len; + struct dpp_enveloped_data data; + struct dpp_asymmetric_key *keys; + + wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len); + + if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0) + return -1; + + /* TODO: For initial testing, use ke as the key. Replace this with a + * new key once that has been defined. */ + key = auth->ke; + key_len = auth->curve->hash_len; + wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len); + + if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000, + kek, data.pbkdf2_key_len)) { + wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed"); + return -1; + } + wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2", + kek, data.pbkdf2_key_len); + + if (data.enc_key_len < AES_BLOCK_SIZE || + data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) { + wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length"); + return -1; + } + res = aes_siv_decrypt(kek, data.pbkdf2_key_len, + data.enc_key, data.enc_key_len, + 0, NULL, NULL, cont_encr_key); + forced_memzero(kek, data.pbkdf2_key_len); + if (res < 0) { + wpa_printf(MSG_DEBUG, + "DPP: AES-SIV decryption of encryptedKey failed"); + return -1; + } + cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE; + wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key", + cont_encr_key, cont_encr_key_len); + + if (data.enc_cont_len < AES_BLOCK_SIZE) + return -1; + key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE; + key_pkg = os_malloc(key_pkg_len); + if (!key_pkg) + return -1; + res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len, + data.enc_cont, data.enc_cont_len, + 0, NULL, NULL, key_pkg); + forced_memzero(cont_encr_key, cont_encr_key_len); + if (res < 0) { + bin_clear_free(key_pkg, key_pkg_len); + wpa_printf(MSG_DEBUG, + "DPP: AES-SIV decryption of encryptedContent failed"); + return -1; + } + + keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len); + bin_clear_free(key_pkg, key_pkg_len); + dpp_free_asymmetric_key(auth->conf_key_pkg); + auth->conf_key_pkg = keys; + + return keys != NULL;; +} + +#endif /* CONFIG_DPP2 */ + + int dpp_conf_resp_rx(struct dpp_authentication *auth, const struct wpabuf *resp) { const u8 *wrapped_data, *e_nonce, *status, *conf_obj; u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len; + const u8 *env_data; + u16 env_data_len; const u8 *addr[1]; size_t len[1]; u8 *unwrapped = NULL; @@ -6348,9 +7749,17 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth, goto fail; } + env_data = dpp_get_attr(unwrapped, unwrapped_len, + DPP_ATTR_ENVELOPED_DATA, &env_data_len); +#ifdef CONFIG_DPP2 + if (env_data && + dpp_conf_resp_env_data(auth, env_data, env_data_len) < 0) + goto fail; +#endif /* CONFIG_DPP2 */ + conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ, &conf_obj_len); - if (!conf_obj) { + if (!conf_obj && !env_data) { dpp_auth_fail(auth, "Missing required Configuration Object attribute"); goto fail; @@ -6770,15 +8179,41 @@ int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf, } -struct dpp_configurator * -dpp_keygen_configurator(const char *curve, const u8 *privkey, - size_t privkey_len) +static int dpp_configurator_gen_kid(struct dpp_configurator *conf) { - struct dpp_configurator *conf; struct wpabuf *csign_pub = NULL; u8 kid_hash[SHA256_MAC_LEN]; const u8 *addr[1]; size_t len[1]; + int res; + + csign_pub = dpp_get_pubkey_point(conf->csign, 1); + if (!csign_pub) { + wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key"); + return -1; + } + + /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */ + addr[0] = wpabuf_head(csign_pub); + len[0] = wpabuf_len(csign_pub); + res = sha256_vector(1, addr, len, kid_hash); + wpabuf_free(csign_pub); + if (res < 0) { + wpa_printf(MSG_DEBUG, + "DPP: Failed to derive kid for C-sign-key"); + return -1; + } + + conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL); + return conf->kid ? 0 : -1; +} + + +struct dpp_configurator * +dpp_keygen_configurator(const char *curve, const u8 *privkey, + size_t privkey_len) +{ + struct dpp_configurator *conf; conf = os_zalloc(sizeof(*conf)); if (!conf) @@ -6804,31 +8239,12 @@ dpp_keygen_configurator(const char *curve, const u8 *privkey, goto fail; conf->own = 1; - csign_pub = dpp_get_pubkey_point(conf->csign, 1); - if (!csign_pub) { - wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key"); - goto fail; - } - - /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */ - addr[0] = wpabuf_head(csign_pub); - len[0] = wpabuf_len(csign_pub); - if (sha256_vector(1, addr, len, kid_hash) < 0) { - wpa_printf(MSG_DEBUG, - "DPP: Failed to derive kid for C-sign-key"); + if (dpp_configurator_gen_kid(conf) < 0) goto fail; - } - - conf->kid = base64_url_encode(kid_hash, sizeof(kid_hash), NULL); - if (!conf->kid) - goto fail; -out: - wpabuf_free(csign_pub); return conf; fail: dpp_configurator_free(conf); - conf = NULL; - goto out; + return NULL; } @@ -8956,6 +10372,10 @@ static int dpp_bootstrap_del(struct dpp_global *dpp, unsigned int id) if (id && bi->id != id) continue; found = 1; +#ifdef CONFIG_DPP2 + if (dpp->remove_bi) + dpp->remove_bi(dpp->cb_ctx, bi); +#endif /* CONFIG_DPP2 */ dl_list_del(&bi->list); dpp_bootstrap_info_free(bi); } @@ -9006,11 +10426,10 @@ struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp, int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) { - char *chan = NULL, *mac = NULL, *info = NULL, *pk = NULL, *curve = NULL; + char *mac = NULL, *info = NULL, *curve = NULL; char *key = NULL; u8 *privkey = NULL; size_t privkey_len = 0; - size_t len; int ret = -1; struct dpp_bootstrap_info *bi; @@ -9030,7 +10449,7 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) else goto fail; - chan = get_param(cmd, " chan="); + bi->chan = get_param(cmd, " chan="); mac = get_param(cmd, " mac="); info = get_param(cmd, " info="); curve = get_param(cmd, " curve="); @@ -9044,43 +10463,19 @@ int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd) goto fail; } - pk = dpp_keygen(bi, curve, privkey, privkey_len); - if (!pk) + if (dpp_keygen(bi, curve, privkey, privkey_len) < 0 || + dpp_parse_uri_chan_list(bi, bi->chan) < 0 || + dpp_parse_uri_mac(bi, mac) < 0 || + dpp_parse_uri_info(bi, info) < 0 || + dpp_gen_uri(bi) < 0) goto fail; - len = 4; /* "DPP:" */ - if (chan) { - if (dpp_parse_uri_chan_list(bi, chan) < 0) - goto fail; - len += 3 + os_strlen(chan); /* C:...; */ - } - if (mac) { - if (dpp_parse_uri_mac(bi, mac) < 0) - goto fail; - len += 3 + os_strlen(mac); /* M:...; */ - } - if (info) { - if (dpp_parse_uri_info(bi, info) < 0) - goto fail; - len += 3 + os_strlen(info); /* I:...; */ - } - len += 4 + os_strlen(pk); - bi->uri = os_malloc(len + 1); - if (!bi->uri) - goto fail; - os_snprintf(bi->uri, len + 1, "DPP:%s%s%s%s%s%s%s%s%sK:%s;;", - chan ? "C:" : "", chan ? chan : "", chan ? ";" : "", - mac ? "M:" : "", mac ? mac : "", mac ? ";" : "", - info ? "I:" : "", info ? info : "", info ? ";" : "", - pk); bi->id = dpp_next_id(dpp); dl_list_add(&dpp->bootstrap, &bi->list); ret = bi->id; bi = NULL; fail: os_free(curve); - os_free(pk); - os_free(chan); os_free(mac); os_free(info); str_clear_free(key); @@ -9175,17 +10570,39 @@ int dpp_bootstrap_info(struct dpp_global *dpp, int id, "mac_addr=" MACSTR "\n" "info=%s\n" "num_freq=%u\n" + "use_freq=%u\n" "curve=%s\n" "pkhash=%s\n", dpp_bootstrap_type_txt(bi->type), MAC2STR(bi->mac_addr), bi->info ? bi->info : "", bi->num_freq, + bi->num_freq == 1 ? bi->freq[0] : 0, bi->curve->name, pkhash); } +int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params) +{ + struct dpp_bootstrap_info *bi; + + bi = dpp_bootstrap_get_id(dpp, id); + if (!bi) + return -1; + + str_clear_free(bi->configurator_params); + + if (params) { + bi->configurator_params = os_strdup(params); + return bi->configurator_params ? 0 : -1; + } + + bi->configurator_params = NULL; + return 0; +} + + void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, const u8 *r_bootstrap, struct dpp_bootstrap_info **own_bi, @@ -9218,7 +10635,108 @@ void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, if (*own_bi && *peer_bi) break; } +} + + +#ifdef CONFIG_DPP2 +struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp, + const u8 *hash) +{ + struct dpp_bootstrap_info *bi; + + if (!dpp) + return NULL; + + dl_list_for_each(bi, &dpp->bootstrap, struct dpp_bootstrap_info, list) { + if (!bi->own && os_memcmp(bi->pubkey_hash_chirp, hash, + SHA256_MAC_LEN) == 0) + return bi; + } + + return NULL; +} +#endif /* CONFIG_DPP2 */ + + +static int dpp_nfc_update_bi_channel(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi) +{ + unsigned int i, freq = 0; + enum hostapd_hw_mode mode; + u8 op_class, channel; + char chan[20]; + + if (peer_bi->num_freq == 0) + return 0; /* no channel preference/constraint */ + + for (i = 0; i < peer_bi->num_freq; i++) { + if (own_bi->num_freq == 0 || + freq_included(own_bi->freq, own_bi->num_freq, + peer_bi->freq[i])) { + freq = peer_bi->freq[i]; + break; + } + } + if (!freq) { + wpa_printf(MSG_DEBUG, "DPP: No common channel found"); + return -1; + } + + mode = ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, &channel); + if (mode == NUM_HOSTAPD_MODES) { + wpa_printf(MSG_DEBUG, + "DPP: Could not determine operating class or channel number for %u MHz", + freq); + } + + wpa_printf(MSG_DEBUG, + "DPP: Selected %u MHz (op_class %u channel %u) as the negotiation channel based on information from NFC negotiated handover", + freq, op_class, channel); + os_snprintf(chan, sizeof(chan), "%u/%u", op_class, channel); + os_free(own_bi->chan); + own_bi->chan = os_strdup(chan); + own_bi->freq[0] = freq; + own_bi->num_freq = 1; + os_free(peer_bi->chan); + peer_bi->chan = os_strdup(chan); + peer_bi->freq[0] = freq; + peer_bi->num_freq = 1; + return dpp_gen_uri(own_bi); +} + + +static int dpp_nfc_update_bi_key(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi) +{ + if (peer_bi->curve == own_bi->curve) + return 0; + + wpa_printf(MSG_DEBUG, + "DPP: Update own bootstrapping key to match peer curve from NFC handover"); + + EVP_PKEY_free(own_bi->pubkey); + own_bi->pubkey = NULL; + + if (dpp_keygen(own_bi, peer_bi->curve->name, NULL, 0) < 0 || + dpp_gen_uri(own_bi) < 0) + goto fail; + + return 0; +fail: + dl_list_del(&own_bi->list); + dpp_bootstrap_info_free(own_bi); + return -1; +} + + +int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi) +{ + if (dpp_nfc_update_bi_channel(own_bi, peer_bi) < 0 || + dpp_nfc_update_bi_key(own_bi, peer_bi) < 0) + return -1; + return 0; } @@ -9327,6 +10845,48 @@ int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, #ifdef CONFIG_DPP2 +int dpp_configurator_from_backup(struct dpp_global *dpp, + struct dpp_asymmetric_key *key) +{ + struct dpp_configurator *conf; + const EC_KEY *eckey; + const EC_GROUP *group; + int nid; + const struct dpp_curve_params *curve; + + if (!key->csign) + return -1; + eckey = EVP_PKEY_get0_EC_KEY(key->csign); + if (!eckey) + return -1; + group = EC_KEY_get0_group(eckey); + if (!group) + return -1; + nid = EC_GROUP_get_curve_name(group); + curve = dpp_get_curve_nid(nid); + if (!curve) { + wpa_printf(MSG_INFO, "DPP: Unsupported group in c-sign-key"); + return -1; + } + + conf = os_zalloc(sizeof(*conf)); + if (!conf) + return -1; + conf->curve = curve; + conf->csign = key->csign; + key->csign = NULL; + conf->own = 1; + if (dpp_configurator_gen_kid(conf) < 0) { + dpp_configurator_free(conf); + return -1; + } + + conf->id = dpp_next_configurator_id(dpp); + dl_list_add(&dpp->configurator, &conf->list); + return conf->id; +} + + static void dpp_controller_conn_status_result_wait_timeout(void *eloop_ctx, void *timeout_ctx); @@ -9405,6 +10965,7 @@ struct dpp_global * dpp_global_init(struct dpp_global_config *config) #ifdef CONFIG_DPP2 dpp->cb_ctx = config->cb_ctx; dpp->process_conf_obj = config->process_conf_obj; + dpp->remove_bi = config->remove_bi; #endif /* CONFIG_DPP2 */ dl_list_init(&dpp->bootstrap); @@ -9561,6 +11122,32 @@ static int dpp_tcp_send(struct dpp_connection *conn) } +static int dpp_tcp_send_msg(struct dpp_connection *conn, + const struct wpabuf *msg) +{ + wpabuf_free(conn->msg_out); + conn->msg_out_pos = 0; + conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1); + if (!conn->msg_out) + return -1; + wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1); + wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1, + wpabuf_len(msg) - 1); + + if (dpp_tcp_send(conn) == 1) { + if (!conn->write_eloop) { + if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, + dpp_conn_tx_ready, + conn, NULL) < 0) + return -1; + conn->write_eloop = 1; + } + } + + return 0; +} + + static void dpp_controller_start_gas_client(struct dpp_connection *conn) { struct dpp_authentication *auth = conn->auth; @@ -9574,27 +11161,8 @@ static void dpp_controller_start_gas_client(struct dpp_connection *conn) return; } - wpabuf_free(conn->msg_out); - conn->msg_out_pos = 0; - conn->msg_out = wpabuf_alloc(4 + wpabuf_len(buf) - 1); - if (!conn->msg_out) { - wpabuf_free(buf); - return; - } - wpabuf_put_be32(conn->msg_out, wpabuf_len(buf) - 1); - wpabuf_put_data(conn->msg_out, wpabuf_head_u8(buf) + 1, - wpabuf_len(buf) - 1); + dpp_tcp_send_msg(conn, buf); wpabuf_free(buf); - - if (dpp_tcp_send(conn) == 1) { - if (!conn->write_eloop) { - if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, - dpp_conn_tx_ready, - conn, NULL) < 0) - return; - conn->write_eloop = 1; - } - } } @@ -9793,7 +11361,8 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, * continue that session (send this over TCP) and return 0. */ if (type != DPP_PA_PEER_DISCOVERY_REQ && - type != DPP_PA_PEER_DISCOVERY_RESP) { + type != DPP_PA_PEER_DISCOVERY_RESP && + type != DPP_PA_PRESENCE_ANNOUNCEMENT) { dl_list_for_each(ctrl, &dpp->controllers, struct dpp_relay_controller, list) { dl_list_for_each(conn, &ctrl->conn, @@ -9808,7 +11377,14 @@ int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, if (!r_bootstrap) return -1; - ctrl = dpp_relay_controller_get(dpp, r_bootstrap); + if (type == DPP_PA_PRESENCE_ANNOUNCEMENT) { + /* TODO: Could send this to all configured Controllers. For now, + * only the first Controller is supported. */ + ctrl = dl_list_first(&dpp->controllers, + struct dpp_relay_controller, list); + } else { + ctrl = dpp_relay_controller_get(dpp, r_bootstrap); + } if (!ctrl) return -1; @@ -9940,7 +11516,8 @@ static int dpp_controller_rx_auth_req(struct dpp_connection *conn, return 0; } - conn->auth = dpp_auth_req_rx(conn->ctrl->global->msg_ctx, + conn->auth = dpp_auth_req_rx(conn->ctrl->global, + conn->ctrl->global->msg_ctx, conn->ctrl->allowed_roles, conn->ctrl->qr_mutual, peer_bi, own_bi, -1, hdr, buf, len); @@ -9949,33 +11526,13 @@ static int dpp_controller_rx_auth_req(struct dpp_connection *conn, return -1; } - if (dpp_set_configurator(conn->ctrl->global, conn->ctrl->global->msg_ctx, - conn->auth, + if (dpp_set_configurator(conn->auth, conn->ctrl->configurator_params) < 0) { dpp_connection_remove(conn); return -1; } - wpabuf_free(conn->msg_out); - conn->msg_out_pos = 0; - conn->msg_out = wpabuf_alloc(4 + wpabuf_len(conn->auth->resp_msg) - 1); - if (!conn->msg_out) - return -1; - wpabuf_put_be32(conn->msg_out, wpabuf_len(conn->auth->resp_msg) - 1); - wpabuf_put_data(conn->msg_out, wpabuf_head_u8(conn->auth->resp_msg) + 1, - wpabuf_len(conn->auth->resp_msg) - 1); - - if (dpp_tcp_send(conn) == 1) { - if (!conn->write_eloop) { - if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, - dpp_conn_tx_ready, - conn, NULL) < 0) - return -1; - conn->write_eloop = 1; - } - } - - return 0; + return dpp_tcp_send_msg(conn, conn->auth->resp_msg); } @@ -9984,6 +11541,7 @@ static int dpp_controller_rx_auth_resp(struct dpp_connection *conn, { struct dpp_authentication *auth = conn->auth; struct wpabuf *msg; + int res; if (!auth) return -1; @@ -10002,30 +11560,10 @@ static int dpp_controller_rx_auth_resp(struct dpp_connection *conn, return -1; } - wpabuf_free(conn->msg_out); - conn->msg_out_pos = 0; - conn->msg_out = wpabuf_alloc(4 + wpabuf_len(msg) - 1); - if (!conn->msg_out) { - wpabuf_free(msg); - return -1; - } - wpabuf_put_be32(conn->msg_out, wpabuf_len(msg) - 1); - wpabuf_put_data(conn->msg_out, wpabuf_head_u8(msg) + 1, - wpabuf_len(msg) - 1); - wpabuf_free(msg); - conn->on_tcp_tx_complete_auth_ok = 1; - if (dpp_tcp_send(conn) == 1) { - if (!conn->write_eloop) { - if (eloop_register_sock(conn->sock, EVENT_TYPE_WRITE, - dpp_conn_tx_ready, - conn, NULL) < 0) - return -1; - conn->write_eloop = 1; - } - } - - return 0; + res = dpp_tcp_send_msg(conn, msg); + wpabuf_free(msg); + return res; } @@ -10142,6 +11680,56 @@ static int dpp_controller_rx_conn_status_result(struct dpp_connection *conn, } +static int dpp_controller_rx_presence_announcement(struct dpp_connection *conn, + const u8 *hdr, const u8 *buf, + size_t len) +{ + const u8 *r_bootstrap; + u16 r_bootstrap_len; + struct dpp_bootstrap_info *peer_bi; + struct dpp_authentication *auth; + struct dpp_global *dpp = conn->ctrl->global; + + if (conn->auth) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore Presence Announcement during ongoing Authentication"); + return -1; + } + + wpa_printf(MSG_DEBUG, "DPP: Presence Announcement"); + + r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, + &r_bootstrap_len); + if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { + wpa_msg(dpp->msg_ctx, MSG_INFO, DPP_EVENT_FAIL + "Missing or invalid required Responder Bootstrapping Key Hash attribute"); + return -1; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", + r_bootstrap, r_bootstrap_len); + peer_bi = dpp_bootstrap_find_chirp(dpp, r_bootstrap); + if (!peer_bi) { + wpa_printf(MSG_DEBUG, + "DPP: No matching bootstrapping information found"); + return -1; + } + + auth = dpp_auth_init(dpp, dpp->msg_ctx, peer_bi, NULL, + DPP_CAPAB_CONFIGURATOR, -1, NULL, 0); + if (!auth) + return -1; + if (dpp_set_configurator(conn->auth, + conn->ctrl->configurator_params) < 0) { + dpp_auth_deinit(auth); + dpp_connection_remove(conn); + return -1; + } + + conn->auth = auth; + return dpp_tcp_send_msg(conn, conn->auth->req_msg); +} + + static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg, size_t len) { @@ -10192,6 +11780,9 @@ static int dpp_controller_rx_action(struct dpp_connection *conn, const u8 *msg, case DPP_PA_CONNECTION_STATUS_RESULT: return dpp_controller_rx_conn_status_result(conn, msg, pos, end - pos); + case DPP_PA_PRESENCE_ANNOUNCEMENT: + return dpp_controller_rx_presence_announcement(conn, msg, pos, + end - pos); default: /* TODO: missing messages types */ wpa_printf(MSG_DEBUG, @@ -10286,7 +11877,7 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) { struct dpp_authentication *auth = conn->auth; int res; - struct wpabuf *msg, *encaps; + struct wpabuf *msg; enum dpp_status_error status; wpa_printf(MSG_DEBUG, @@ -10308,35 +11899,19 @@ static int dpp_tcp_rx_gas_resp(struct dpp_connection *conn, struct wpabuf *resp) if (auth->peer_version < 2 || auth->conf_resp_status != DPP_STATUS_OK) return -1; -#ifdef CONFIG_DPP2 wpa_printf(MSG_DEBUG, "DPP: Send DPP Configuration Result"); status = res < 0 ? DPP_STATUS_CONFIG_REJECTED : DPP_STATUS_OK; msg = dpp_build_conf_result(auth, status); if (!msg) return -1; - encaps = wpabuf_alloc(4 + wpabuf_len(msg) - 1); - if (!encaps) { - wpabuf_free(msg); - return -1; - } - wpabuf_put_be32(encaps, wpabuf_len(msg) - 1); - wpabuf_put_data(encaps, wpabuf_head_u8(msg) + 1, wpabuf_len(msg) - 1); - wpabuf_free(msg); - wpa_hexdump_buf(MSG_MSGDUMP, "DPP: Outgoing TCP message", encaps); - - wpabuf_free(conn->msg_out); - conn->msg_out_pos = 0; - conn->msg_out = encaps; conn->on_tcp_tx_complete_remove = 1; - dpp_tcp_send(conn); + res = dpp_tcp_send_msg(conn, msg); + wpabuf_free(msg); /* This exchange will be terminated in the TX status handler */ - return 0; -#else /* CONFIG_DPP2 */ - return -1; -#endif /* CONFIG_DPP2 */ + return res; } @@ -10721,4 +12296,22 @@ void dpp_controller_stop(struct dpp_global *dpp) } } + +struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi) +{ + struct wpabuf *msg; + + wpa_printf(MSG_DEBUG, "DPP: Build Presence Announcement frame"); + + msg = dpp_alloc_msg(DPP_PA_PRESENCE_ANNOUNCEMENT, 4 + SHA256_MAC_LEN); + if (!msg) + return NULL; + + /* Responder Bootstrapping Key Hash */ + dpp_build_attr_r_bootstrap_key_hash(msg, bi->pubkey_hash_chirp); + wpa_hexdump_buf(MSG_DEBUG, + "DPP: Presence Announcement frame attributes", msg); + return msg; +} + #endif /* CONFIG_DPP2 */ diff --git a/src/common/dpp.h b/src/common/dpp.h index cb788ae4..ab3f9271 100644 --- a/src/common/dpp.h +++ b/src/common/dpp.h @@ -1,7 +1,7 @@ /* * DPP functionality shared between hostapd and wpa_supplicant * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -36,6 +36,11 @@ enum dpp_public_action_frame_type { DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10, DPP_PA_CONFIGURATION_RESULT = 11, DPP_PA_CONNECTION_STATUS_RESULT = 12, + DPP_PA_PRESENCE_ANNOUNCEMENT = 13, + DPP_PA_RECONFIG_ANNOUNCEMENT = 14, + DPP_PA_RECONFIG_AUTH_REQ = 15, + DPP_PA_RECONFIG_AUTH_RESP = 16, + DPP_PA_RECONFIG_AUTH_CONF = 17, }; enum dpp_attribute_id { @@ -67,6 +72,9 @@ enum dpp_attribute_id { DPP_ATTR_ENVELOPED_DATA = 0x101A, DPP_ATTR_SEND_CONN_STATUS = 0x101B, DPP_ATTR_CONN_STATUS = 0x101C, + DPP_ATTR_RECONFIG_FLAGS = 0x101D, + DPP_ATTR_C_SIGN_KEY_HASH = 0x101E, + DPP_ATTR_CSR_ATTR_REQ = 0x101F, }; enum dpp_status_error { @@ -81,6 +89,9 @@ enum dpp_status_error { DPP_STATUS_NO_MATCH = 8, DPP_STATUS_CONFIG_REJECTED = 9, DPP_STATUS_NO_AP = 10, + DPP_STATUS_CONFIGURE_PENDING = 11, + DPP_STATUS_CSR_NEEDED = 12, + DPP_STATUS_CSR_BAD = 13, }; #define DPP_CAPAB_ENROLLEE BIT(0) @@ -115,15 +126,19 @@ struct dpp_bootstrap_info { enum dpp_bootstrap_type type; char *uri; u8 mac_addr[ETH_ALEN]; + char *chan; char *info; + char *pk; unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ]; unsigned int num_freq; int own; EVP_PKEY *pubkey; u8 pubkey_hash[SHA256_MAC_LEN]; + u8 pubkey_hash_chirp[SHA256_MAC_LEN]; const struct dpp_curve_params *curve; unsigned int pkex_t; /* number of failures before dpp_pkex * instantiation */ + char *configurator_params; }; #define PKEX_COUNTER_T_LIMIT 5 @@ -187,10 +202,18 @@ struct dpp_configuration { int psk_set; }; +struct dpp_asymmetric_key { + struct dpp_asymmetric_key *next; + EVP_PKEY *csign; + char *config_template; + char *connector_template; +}; + #define DPP_MAX_CONF_OBJ 10 #define DPP_MAX_CHANNELS 32 struct dpp_authentication { + struct dpp_global *global; void *msg_ctx; u8 peer_version; const struct dpp_curve_params *curve; @@ -246,6 +269,7 @@ struct dpp_authentication { struct dpp_configuration *conf2_ap; struct dpp_configuration *conf_sta; struct dpp_configuration *conf2_sta; + int provision_configurator; struct dpp_configurator *conf; struct dpp_config_obj { char *connector; /* received signedConnector */ @@ -259,11 +283,13 @@ struct dpp_authentication { struct wpabuf *c_sign_key; } conf_obj[DPP_MAX_CONF_OBJ]; unsigned int num_conf_obj; + struct dpp_asymmetric_key *conf_key_pkg; struct wpabuf *net_access_key; os_time_t net_access_key_expiry; int send_conn_status; int conn_status_requested; int akm_use_selector; + int configurator_set; #ifdef CONFIG_TESTING_OPTIONS char *config_obj_override; char *discovery_override; @@ -414,15 +440,16 @@ extern size_t dpp_nonce_override_len; void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info); const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type); -int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi); int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi, const char *chan_list); int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac); int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info); -char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, - const u8 *privkey, size_t privkey_len); +int dpp_nfc_update_bi(struct dpp_bootstrap_info *own_bi, + struct dpp_bootstrap_info *peer_bi); +struct dpp_authentication * +dpp_alloc_auth(struct dpp_global *dpp, void *msg_ctx); struct hostapd_hw_modes; -struct dpp_authentication * dpp_auth_init(void *msg_ctx, +struct dpp_authentication * dpp_auth_init(struct dpp_global *dpp, void *msg_ctx, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, u8 dpp_allowed_roles, @@ -430,8 +457,8 @@ struct dpp_authentication * dpp_auth_init(void *msg_ctx, struct hostapd_hw_modes *own_modes, u16 num_modes); struct dpp_authentication * -dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, - struct dpp_bootstrap_info *peer_bi, +dpp_auth_req_rx(struct dpp_global *dpp, void *msg_ctx, u8 dpp_allowed_roles, + int qr_mutual, struct dpp_bootstrap_info *peer_bi, struct dpp_bootstrap_info *own_bi, unsigned int freq, const u8 *hdr, const u8 *attr_start, size_t attr_len); @@ -456,9 +483,7 @@ int dpp_akm_dpp(enum dpp_akm akm); int dpp_akm_ver2(enum dpp_akm akm); int dpp_configuration_valid(const struct dpp_configuration *conf); void dpp_configuration_free(struct dpp_configuration *conf); -int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx, - struct dpp_authentication *auth, - const char *cmd); +int dpp_set_configurator(struct dpp_authentication *auth, const char *cmd); void dpp_auth_deinit(struct dpp_authentication *auth); struct wpabuf * dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, @@ -551,14 +576,19 @@ dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer, const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id); int dpp_bootstrap_info(struct dpp_global *dpp, int id, char *reply, int reply_size); +int dpp_bootstrap_set(struct dpp_global *dpp, int id, const char *params); void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap, const u8 *r_bootstrap, struct dpp_bootstrap_info **own_bi, struct dpp_bootstrap_info **peer_bi); +struct dpp_bootstrap_info * dpp_bootstrap_find_chirp(struct dpp_global *dpp, + const u8 *hash); int dpp_configurator_add(struct dpp_global *dpp, const char *cmd); int dpp_configurator_remove(struct dpp_global *dpp, const char *id); int dpp_configurator_get_key_id(struct dpp_global *dpp, unsigned int id, char *buf, size_t buflen); +int dpp_configurator_from_backup(struct dpp_global *dpp, + struct dpp_asymmetric_key *key); int dpp_relay_add_controller(struct dpp_global *dpp, struct dpp_relay_config *config); int dpp_relay_rx_action(struct dpp_global *dpp, const u8 *src, const u8 *hdr, @@ -571,11 +601,13 @@ int dpp_controller_start(struct dpp_global *dpp, void dpp_controller_stop(struct dpp_global *dpp); int dpp_tcp_init(struct dpp_global *dpp, struct dpp_authentication *auth, const struct hostapd_ip_addr *addr, int port); +struct wpabuf * dpp_build_presence_announcement(struct dpp_bootstrap_info *bi); struct dpp_global_config { void *msg_ctx; void *cb_ctx; int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth); + void (*remove_bi)(void *ctx, struct dpp_bootstrap_info *bi); }; struct dpp_global * dpp_global_init(struct dpp_global_config *config); diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c index 19593a52..f6c67a37 100644 --- a/src/common/hw_features_common.c +++ b/src/common/hw_features_common.c @@ -468,20 +468,53 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, data->bandwidth = (1 << (u8) bw) * 20; data->center_freq1 = freq1; data->center_freq2 = freq2; - data->ht_enabled = 0; - data->vht_enabled = 0; } + data->ht_enabled = 0; + data->vht_enabled = 0; return 0; } - if (data->vht_enabled) switch (oper_chwidth) { + if (data->he_enabled) switch (oper_chwidth) { case CHANWIDTH_USE_HT: - if (center_segment1 || - (center_segment0 != 0 && - 5000 + center_segment0 * 5 != data->center_freq1 && - 2407 + center_segment0 * 5 != data->center_freq1)) + if (mode == HOSTAPD_MODE_IEEE80211G && sec_channel_offset) { + if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_IN_2G)) { + wpa_printf(MSG_ERROR, + "40 MHz channel width is not supported in 2.4 GHz"); + return -1; + } + break; + } + /* fall through */ + case CHANWIDTH_80MHZ: + if (mode == HOSTAPD_MODE_IEEE80211A) { + if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + HE_PHYCAP_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G)) { + wpa_printf(MSG_ERROR, + "40/80 MHz channel width is not supported in 5/6 GHz"); + return -1; + } + } + break; + case CHANWIDTH_80P80MHZ: + if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + HE_PHYCAP_CHANNEL_WIDTH_SET_80PLUS80MHZ_IN_5G)) { + wpa_printf(MSG_ERROR, + "80+80 MHz channel width is not supported in 5/6 GHz"); return -1; + } + break; + case CHANWIDTH_160MHZ: + if (!(he_cap->phy_cap[HE_PHYCAP_CHANNEL_WIDTH_SET_IDX] & + HE_PHYCAP_CHANNEL_WIDTH_SET_160MHZ_IN_5G)) { + wpa_printf(MSG_ERROR, + "160 MHz channel width is not supported in 5 / 6GHz"); + return -1; + } + break; + } else if (data->vht_enabled) switch (oper_chwidth) { + case CHANWIDTH_USE_HT: break; case CHANWIDTH_80P80MHZ: if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) { @@ -489,6 +522,28 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, "80+80 channel width is not supported!"); return -1; } + /* fall through */ + case CHANWIDTH_80MHZ: + break; + case CHANWIDTH_160MHZ: + if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | + VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { + wpa_printf(MSG_ERROR, + "160 MHz channel width is not supported!"); + return -1; + } + break; + } + + if (data->he_enabled || data->vht_enabled) switch (oper_chwidth) { + case CHANWIDTH_USE_HT: + if (center_segment1 || + (center_segment0 != 0 && + 5000 + center_segment0 * 5 != data->center_freq1 && + 2407 + center_segment0 * 5 != data->center_freq1)) + return -1; + break; + case CHANWIDTH_80P80MHZ: if (center_segment1 == center_segment0 + 4 || center_segment1 == center_segment0 - 4) return -1; @@ -533,12 +588,6 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, break; case CHANWIDTH_160MHZ: data->bandwidth = 160; - if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | - VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) { - wpa_printf(MSG_ERROR, - "160MHZ channel width is not supported!"); - return -1; - } if (center_segment1) return -1; if (!sec_channel_offset) diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index b3304548..42c916b5 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -130,6 +130,12 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen, elems->multi_ap = pos; elems->multi_ap_len = elen; break; + case OWE_OUI_TYPE: + /* OWE Transition Mode element */ + break; + case DPP_CC_OUI_TYPE: + /* DPP Configurator Connectivity element */ + break; default: wpa_printf(MSG_MSGDUMP, "Unknown WFA " "information element ignored " @@ -206,6 +212,8 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, ext_id = *pos++; elen--; + elems->frag_ies.last_eid_ext = 0; + switch (ext_id) { case WLAN_EID_EXT_ASSOC_DELAY_INFO: if (elen != 1) @@ -245,9 +253,9 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, elems->key_delivery = pos; elems->key_delivery_len = elen; break; - case WLAN_EID_EXT_FILS_WRAPPED_DATA: - elems->fils_wrapped_data = pos; - elems->fils_wrapped_data_len = elen; + case WLAN_EID_EXT_WRAPPED_DATA: + elems->wrapped_data = pos; + elems->wrapped_data_len = elen; break; case WLAN_EID_EXT_FILS_PUBLIC_KEY: if (elen < 1) @@ -286,6 +294,10 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, elems->oci = pos; elems->oci_len = elen; break; + case WLAN_EID_EXT_SHORT_SSID_LIST: + elems->short_ssid_list = pos; + elems->short_ssid_list_len = elen; + break; default: if (show_errors) { wpa_printf(MSG_MSGDUMP, @@ -295,10 +307,39 @@ static int ieee802_11_parse_extension(const u8 *pos, size_t elen, return -1; } + if (elen == 254) + elems->frag_ies.last_eid_ext = ext_id; + return 0; } +static void ieee802_11_parse_fragment(struct frag_ies_info *frag_ies, + const u8 *pos, u8 elen) +{ + if (frag_ies->n_frags >= MAX_NUM_FRAG_IES_SUPPORTED) { + wpa_printf(MSG_MSGDUMP, "Too many element fragments - skip"); + return; + } + + /* + * Note: while EID == 0 is a valid ID (SSID IE), it should not be + * fragmented. + */ + if (!frag_ies->last_eid) { + wpa_printf(MSG_MSGDUMP, + "Fragment without a valid last element - skip"); + return; + } + + frag_ies->frags[frag_ies->n_frags].ie = pos; + frag_ies->frags[frag_ies->n_frags].ie_len = elen; + frag_ies->frags[frag_ies->n_frags].eid = frag_ies->last_eid; + frag_ies->frags[frag_ies->n_frags].eid_ext = frag_ies->last_eid_ext; + frag_ies->n_frags++; +} + + /** * ieee802_11_parse_elems - Parse information elements in management frames * @start: Pointer to the start of IEs @@ -331,6 +372,11 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elen); break; } + if (elems->ssid) { + wpa_printf(MSG_MSGDUMP, + "Ignored duplicated SSID element"); + break; + } elems->ssid = pos; elems->ssid_len = elen; break; @@ -516,7 +562,7 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, elems->dils_len = elen; break; case WLAN_EID_FRAGMENT: - /* TODO */ + ieee802_11_parse_fragment(&elems->frag_ies, pos, elen); break; case WLAN_EID_EXTENSION: if (ieee802_11_parse_extension(pos, elen, elems, @@ -532,6 +578,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len, id, elen); break; } + + if (id != WLAN_EID_FRAGMENT && elen == 255) + elems->frag_ies.last_eid = id; + + if (id == WLAN_EID_EXTENSION && !elems->frag_ies.last_eid_ext) + elems->frag_ies.last_eid = 0; } if (!for_each_element_completed(elem, start, len)) { @@ -2394,6 +2446,79 @@ int op_class_to_ch_width(u8 op_class) return CHANWIDTH_USE_HT; } +struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems, + u8 eid, u8 eid_ext, + const u8 *data, u8 len) +{ + struct frag_ies_info *frag_ies = &elems->frag_ies; + struct wpabuf *buf; + unsigned int i; + + if (!elems || !data || !len) + return NULL; + + buf = wpabuf_alloc_copy(data, len); + if (!buf) + return NULL; + + for (i = 0; i < frag_ies->n_frags; i++) { + int ret; + + if (frag_ies->frags[i].eid != eid || + frag_ies->frags[i].eid_ext != eid_ext) + continue; + + ret = wpabuf_resize(&buf, frag_ies->frags[i].ie_len); + if (ret < 0) { + wpabuf_free(buf); + return NULL; + } + + /* Copy only the fragment data (without the EID and length) */ + wpabuf_put_data(buf, frag_ies->frags[i].ie, + frag_ies->frags[i].ie_len); + } + + return buf; +} + + +struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems, + u8 eid, u8 eid_ext) +{ + const u8 *data; + u8 len; + + /* + * TODO: Defragmentation mechanism can be supported for all IEs. For now + * handle only those that are used (or use ieee802_11_defrag_data()). + */ + switch (eid) { + case WLAN_EID_EXTENSION: + switch (eid_ext) { + case WLAN_EID_EXT_FILS_HLP_CONTAINER: + data = elems->fils_hlp; + len = elems->fils_hlp_len; + break; + case WLAN_EID_EXT_WRAPPED_DATA: + data = elems->wrapped_data; + len = elems->wrapped_data_len; + break; + default: + wpa_printf(MSG_DEBUG, + "Defragmentation not supported. eid_ext=%u", + eid_ext); + return NULL; + } + break; + default: + wpa_printf(MSG_DEBUG, + "Defragmentation not supported. eid=%u", eid); + return NULL; + } + + return ieee802_11_defrag_data(elems, eid, eid_ext, data, len); +} /* Parse HT capabilities to get maximum number of supported spatial streams */ static int parse_ht_mcs_set_for_max_nss( diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 2c66507e..e3957697 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -21,6 +21,7 @@ struct element { struct hostapd_hw_modes; #define MAX_NOF_MB_IES_SUPPORTED 5 +#define MAX_NUM_FRAG_IES_SUPPORTED 3 struct mb_ies_info { struct { @@ -30,6 +31,21 @@ struct mb_ies_info { u8 nof_ies; }; +struct frag_ies_info { + struct { + u8 eid; + u8 eid_ext; + const u8 *ie; + u8 ie_len; + } frags[MAX_NUM_FRAG_IES_SUPPORTED]; + + u8 n_frags; + + /* the last parsed element ID and element extension ID */ + u8 last_eid; + u8 last_eid_ext; +}; + /* Parsed Information Elements */ struct ieee802_11_elems { const u8 *ssid; @@ -85,7 +101,7 @@ struct ieee802_11_elems { const u8 *fils_hlp; const u8 *fils_ip_addr_assign; const u8 *key_delivery; - const u8 *fils_wrapped_data; + const u8 *wrapped_data; const u8 *fils_pk; const u8 *fils_nonce; const u8 *owe_dh; @@ -96,6 +112,7 @@ struct ieee802_11_elems { const u8 *multi_ap; const u8 *he_capabilities; const u8 *he_operation; + const u8 *short_ssid_list; u8 ssid_len; u8 supp_rates_len; @@ -137,7 +154,7 @@ struct ieee802_11_elems { u8 fils_hlp_len; u8 fils_ip_addr_assign_len; u8 key_delivery_len; - u8 fils_wrapped_data_len; + u8 wrapped_data_len; u8 fils_pk_len; u8 owe_dh_len; u8 power_capab_len; @@ -147,8 +164,10 @@ struct ieee802_11_elems { u8 multi_ap_len; u8 he_capabilities_len; u8 he_operation_len; + u8 short_ssid_list_len; struct mb_ies_info mb_ies; + struct frag_ies_info frag_ies; }; typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes; @@ -291,6 +310,12 @@ void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel, int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed, struct ieee80211_edmg_config requested); +struct wpabuf * ieee802_11_defrag_data(struct ieee802_11_elems *elems, + u8 eid, u8 eid_ext, + const u8 *data, u8 len); +struct wpabuf * ieee802_11_defrag(struct ieee802_11_elems *elems, + u8 eid, u8 eid_ext); + int get_max_nss_capability(struct ieee802_11_elems *elems, int parse_for_rx); struct supported_chan_width { diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index fdc51dcc..4a5eb16c 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -458,7 +458,7 @@ #define WLAN_EID_EXT_FILS_HLP_CONTAINER 5 #define WLAN_EID_EXT_FILS_IP_ADDR_ASSIGN 6 #define WLAN_EID_EXT_KEY_DELIVERY 7 -#define WLAN_EID_EXT_FILS_WRAPPED_DATA 8 +#define WLAN_EID_EXT_WRAPPED_DATA 8 #define WLAN_EID_EXT_FTM_SYNC_INFO 9 #define WLAN_EID_EXT_EXTENDED_REQUEST 10 #define WLAN_EID_EXT_ESTIMATED_SERVICE_PARAMS 11 @@ -472,9 +472,11 @@ #define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38 #define WLAN_EID_EXT_SPATIAL_REUSE 39 #define WLAN_EID_EXT_OCV_OCI 54 +#define WLAN_EID_EXT_SHORT_SSID_LIST 58 #define WLAN_EID_EXT_EDMG_CAPABILITIES 61 #define WLAN_EID_EXT_EDMG_OPERATION 62 #define WLAN_EID_EXT_REJECTED_GROUPS 92 +#define WLAN_EID_EXT_ANTI_CLOGGING_TOKEN 93 /* Extended Capabilities field */ #define WLAN_EXT_CAPAB_20_40_COEX 0 @@ -556,6 +558,7 @@ #define WLAN_EXT_CAPAB_COMPLETE_NON_TX_BSSID_PROFILE 80 #define WLAN_EXT_CAPAB_SAE_PW_ID 81 #define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82 +#define WLAN_EXT_CAPAB_BEACON_PROTECTION 84 /* Extended RSN Capabilities */ /* bits 0-3: Field length (n-1) */ @@ -1319,6 +1322,8 @@ struct ieee80211_ampe_ie { #define OWE_IE_VENDOR_TYPE 0x506f9a1c #define OWE_OUI_TYPE 28 #define MULTI_AP_OUI_TYPE 0x1B +#define DPP_CC_IE_VENDOR_TYPE 0x506f9a1e +#define DPP_CC_OUI_TYPE 0x1e #define MULTI_AP_SUB_ELEM_TYPE 0x06 #define MULTI_AP_TEAR_DOWN BIT(4) @@ -1878,7 +1883,15 @@ enum wnm_sleep_mode_response_status { /* WNM-Sleep Mode subelement IDs */ enum wnm_sleep_mode_subelement_id { WNM_SLEEP_SUBELEM_GTK = 0, - WNM_SLEEP_SUBELEM_IGTK = 1 + WNM_SLEEP_SUBELEM_IGTK = 1, + WNM_SLEEP_SUBELEM_BIGTK = 2, +}; + +/* WNM notification type (IEEE P802.11-REVmd/D3.0, Table 9-430) */ +enum wnm_notification_Type { + WNM_NOTIF_TYPE_FIRMWARE_UPDATE = 0, + WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE = 2, + WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221, }; /* Channel Switch modes (802.11h) */ @@ -2094,7 +2107,7 @@ enum phy_type { PHY_TYPE_VHT = 9, }; -/* IEEE P802.11-REVmc/D5.0, 9.4.2.37 - Neighbor Report element */ +/* IEEE P802.11-REVmd/D3.0, 9.4.2.36 - Neighbor Report element */ /* BSSID Information Field */ #define NEI_REP_BSSID_INFO_AP_NOT_REACH BIT(0) #define NEI_REP_BSSID_INFO_AP_UNKNOWN_REACH BIT(1) @@ -2111,6 +2124,7 @@ enum phy_type { #define NEI_REP_BSSID_INFO_HT BIT(11) #define NEI_REP_BSSID_INFO_VHT BIT(12) #define NEI_REP_BSSID_INFO_FTM BIT(13) +#define NEI_REP_BSSID_INFO_HE BIT(14) /* * IEEE P802.11-REVmc/D5.0 Table 9-152 - HT/VHT Operation Information @@ -2173,6 +2187,7 @@ struct ieee80211_6ghz_operation_info { #define HE_CAPABILITIES_IE_MIN_LEN 21 /* HE Capabilities Information defines */ +#define HE_MACCAP_TWT_RESPONDER ((u8) BIT(2)) #define HE_PHYCAP_CHANNEL_WIDTH_SET_IDX 0 #define HE_PHYCAP_CHANNEL_WIDTH_MASK ((u8) (BIT(1) | BIT(2) | \ BIT(3) | BIT(4))) @@ -2215,7 +2230,7 @@ struct ieee80211_6ghz_operation_info { #define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \ BIT(26) | BIT(27) | \ BIT(28) | BIT(29))) -#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(30)) +#define HE_OPERATION_BSS_COLOR_PARTIAL ((u32) BIT(30)) #define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(31)) #define HE_OPERATION_BSS_COLOR_OFFSET 24 diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h index b85c6c34..d2c4bbd5 100644 --- a/src/common/privsep_commands.h +++ b/src/common/privsep_commands.h @@ -82,6 +82,7 @@ struct privsep_cmd_set_key { size_t seq_len; u8 key[32]; size_t key_len; + enum key_flag key_flag; }; enum privsep_event { diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index ade7aa62..8ef666db 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -21,6 +21,10 @@ #define OUI_QCA 0x001374 +#ifndef BIT +#define BIT(x) (1U << (x)) +#endif + /** * enum qca_radiotap_vendor_ids - QCA radiotap vendor namespace IDs */ @@ -619,6 +623,31 @@ enum qca_radiotap_vendor_ids { * association when in disconnected state. For AP mode, only information * of the currently connected stations is available. This command uses * attributes defined in enum qca_wlan_vendor_attr_get_sta_info. + * + * @QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_EVENT: This acts as an event. + * Host drivers can request the user space entity to set the SAR power + * limits with this event. Accordingly, the user space entity is expected + * to set the SAR power limits. Host drivers can retry this event to the + * user space for the SAR power limits configuration from user space. If + * the driver does not get the SAR power limits from user space for all + * the retried attempts, it can configure a default SAR power limit. + * + * @QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO: This acts as a vendor event and + * is used to update the information about the station from the driver to + * userspace. Uses attributes from enum + * qca_wlan_vendor_attr_update_sta_info. + * + * @QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON: This acts as an event. + * The host driver initiates the disconnection for scenarios such as beacon + * miss, NUD failure, peer kick out, etc. The disconnection indication + * through cfg80211_disconnected() expects the reason codes from enum + * ieee80211_reasoncode which does not signify these various reasons why + * the driver has triggered the disconnection. This event will be used to + * send the driver specific reason codes by the host driver to userspace. + * Host drivers should trigger this event and pass the respective reason + * code immediately prior to triggering cfg80211_disconnected(). The + * attributes used with this event are defined in enum + * qca_wlan_vendor_attr_driver_disconnect_reason. */ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, @@ -795,6 +824,9 @@ enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184, QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185, QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO = 186, + QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT = 187, + QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO = 188, + QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON = 189, }; enum qca_wlan_vendor_attr { @@ -1191,7 +1223,9 @@ enum qca_wlan_vendor_attr_p2p_listen_offload { * * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL: Required (u8). * Used with event to notify the VHT segment 0 center channel number selected in - * ACS operation. + * ACS operation. The value is the index of the channel center frequency for + * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center frequency index + * of the primary 80 MHz segment for 160 MHz and 80+80 MHz channels. * Note: If both the driver and user-space application supports the 6 GHz band, * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL is deprecated; use * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY instead. @@ -1201,7 +1235,10 @@ enum qca_wlan_vendor_attr_p2p_listen_offload { * * @QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL: Required (u8). * Used with event to notify the VHT segment 1 center channel number selected in - * ACS operation. + * ACS operation. The value is zero for 20 MHz, 40 MHz, and 80 MHz channels. + * The value is the index of the channel center frequency for 160 MHz channels + * and the center frequency index of the secondary 80 MHz segment for 80+80 MHz + * channels. * Note: If both the driver and user-space application supports the 6 GHz band, * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL is deprecated; use * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY instead. @@ -1244,6 +1281,15 @@ enum qca_wlan_vendor_attr_p2p_listen_offload { * Note: If the driver supports the 6 GHz band, the event sent from the driver * includes this attribute along with * QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL. + * + * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED: Flag attribute. + * Used with command to notify the driver of EDMG request for ACS + * operation. + * + * @QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL: Optional (u8). + * Used with event to notify the EDMG channel number selected in ACS + * operation. + * EDMG primary channel is indicated by QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL */ enum qca_wlan_vendor_attr_acs_offload { QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0, @@ -1262,6 +1308,8 @@ enum qca_wlan_vendor_attr_acs_offload { QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY = 13, QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY = 14, QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY = 15, + QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED = 16, + QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL = 17, /* keep last */ QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST, @@ -1320,6 +1368,11 @@ enum qca_wlan_vendor_acs_hw_mode { * @QCA_WLAN_VENDOR_FEATURE_TWT: Device supports TWT (Target Wake Time). * @QCA_WLAN_VENDOR_FEATURE_11AX: Device supports 802.11ax (HE) * @QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT: Device supports 6 GHz band operation + * @QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG: Device is capable of receiving + * and applying thermal configuration through + * %QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL and + * %QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW attributes from + * userspace. * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits */ enum qca_wlan_vendor_features { @@ -1334,6 +1387,7 @@ enum qca_wlan_vendor_features { QCA_WLAN_VENDOR_FEATURE_TWT = 8, QCA_WLAN_VENDOR_FEATURE_11AX = 9, QCA_WLAN_VENDOR_FEATURE_6GHZ_SUPPORT = 10, + QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG = 11, NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */ }; @@ -1675,6 +1729,9 @@ enum qca_vendor_element_id { * randomisation * @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: 6-byte MAC address representing the * specific BSSID to scan for. + * @QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME: Unsigned 64-bit dwell time in + * microseconds. This is a common value which applies across all + * frequencies specified by QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES. */ enum qca_wlan_vendor_attr_scan { QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0, @@ -1689,6 +1746,7 @@ enum qca_wlan_vendor_attr_scan { QCA_WLAN_VENDOR_ATTR_SCAN_MAC = 9, QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK = 10, QCA_WLAN_VENDOR_ATTR_SCAN_BSSID = 11, + QCA_WLAN_VENDOR_ATTR_SCAN_DWELL_TIME = 12, QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_SCAN_MAX = QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1 @@ -2043,19 +2101,41 @@ enum qca_wlan_vendor_attr_config { * take the union of IEs from both of these interfaces and send in * further disassoc/deauth frames. */ - QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES = 58, + QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES = 58, /* 8-bit unsigned value for ELNA bypass. * 1-Enable, 0-Disable */ QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS = 59, + /* 8-bit unsigned value. This attribute enables/disables the host driver + * to send the Beacon Report Response with failure reason for the + * scenarios where STA cannot honor the Beacon Report Request from AP. + * 1-Enable, 0-Disable. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL = 60, + + /* 8-bit unsigned value. This attribute enables/disables the host driver + * to send roam reason information in the Reassociation Request frame to + * the target AP when roaming within the same ESS. + * 1-Enable, 0-Disable. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON = 61, + /* keep last */ QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX = QCA_WLAN_VENDOR_ATTR_CONFIG_AFTER_LAST - 1, }; +/* Compatibility defines for previously used incorrect enum + * qca_wlan_vendor_attr_config names. These values should not be used in any + * new implementation. */ +#define QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES \ + QCA_WLAN_VENDOR_ATTR_CONFIG_DISCONNECT_IES +#define QCA_WLAN_VENDOR_ATTR_BEACON_REPORT_FAIL \ + QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL + /** * enum qca_wlan_vendor_attr_sap_config - Parameters for AP configuration * @@ -5656,6 +5736,39 @@ enum qca_wlan_vendor_hang_reason { QCA_WLAN_HANG_DXE_FAILURE = 12, /* WMI pending commands exceed the maximum count */ QCA_WLAN_HANG_WMI_EXCEED_MAX_PENDING_CMDS = 13, + /* Timeout for peer STA connection accept command's response from the + * FW in AP mode. This command is triggered when a STA (peer) connects + * to AP (DUT). + */ + QCA_WLAN_HANG_AP_STA_CONNECT_REQ_TIMEOUT = 14, + /* Timeout for the AP connection accept command's response from the FW + * in STA mode. This command is triggered when the STA (DUT) connects + * to an AP (peer). + */ + QCA_WLAN_HANG_STA_AP_CONNECT_REQ_TIMEOUT = 15, + /* Timeout waiting for the response to the MAC HW mode change command + * sent to FW as a part of MAC mode switch among DBS (Dual Band + * Simultaneous), SCC (Single Channel Concurrency), and MCC (Multi + * Channel Concurrency) mode. + */ + QCA_WLAN_HANG_MAC_HW_MODE_CHANGE_TIMEOUT = 16, + /* Timeout waiting for the response from FW to configure the MAC HW's + * mode. This operation is to configure the single/two MACs in either + * SCC/MCC/DBS mode. + */ + QCA_WLAN_HANG_MAC_HW_MODE_CONFIG_TIMEOUT = 17, + /* Timeout waiting for response of VDEV start command from the FW */ + QCA_WLAN_HANG_VDEV_START_RESPONSE_TIMED_OUT = 18, + /* Timeout waiting for response of VDEV restart command from the FW */ + QCA_WLAN_HANG_VDEV_RESTART_RESPONSE_TIMED_OUT = 19, + /* Timeout waiting for response of VDEV stop command from the FW */ + QCA_WLAN_HANG_VDEV_STOP_RESPONSE_TIMED_OUT = 20, + /* Timeout waiting for response of VDEV delete command from the FW */ + QCA_WLAN_HANG_VDEV_DELETE_RESPONSE_TIMED_OUT = 21, + /* Timeout waiting for response of peer all delete request command to + * the FW on a specific VDEV. + */ + QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT = 22, }; /** @@ -5668,6 +5781,12 @@ enum qca_wlan_vendor_attr_hang { * qca_wlan_vendor_hang_reason. */ QCA_WLAN_VENDOR_ATTR_HANG_REASON = 1, + /* The binary blob data associated with the hang reason specified by + * QCA_WLAN_VENDOR_ATTR_HANG_REASON. This binary data is expected to + * contain the required dump to analyze the reason for the hang. + * NLA_BINARY attribute, the max size is 1024 bytes. + */ + QCA_WLAN_VENDOR_ATTR_HANG_REASON_DATA = 2, QCA_WLAN_VENDOR_ATTR_HANG_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_HANG_MAX = @@ -5768,12 +5887,22 @@ enum qca_wlan_vendor_attr_rrop_info { enum qca_wlan_vendor_attr_rtplinst { QCA_WLAN_VENDOR_ATTR_RTPLINST_INVALID = 0, - /* Primary channel number (u8) */ + /* Primary channel number (u8). + * Note: If both the driver and user space application support the + * 6 GHz band, this attribute is deprecated and + * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY should be used. To + * maintain backward compatibility, + * QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY is still used if either the + * driver or user space application or both do not support the 6 GHz + * band. + */ QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY = 1, /* Representative Tx power in dBm (s32) with emphasis on throughput. */ QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_THROUGHPUT = 2, /* Representative Tx power in dBm (s32) with emphasis on range. */ QCA_WLAN_VENDOR_ATTR_RTPLINST_TXPOWER_RANGE = 3, + /* Primary channel center frequency (u32) in MHz */ + QCA_WLAN_VENDOR_ATTR_RTPLINST_PRIMARY_FREQUENCY = 4, QCA_WLAN_VENDOR_ATTR_RTPLINST_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_RTPLINST_MAX = @@ -6305,6 +6434,29 @@ enum qca_wlan_vendor_attr_wake_stats { }; /** + * enum qca_wlan_vendor_thermal_level - Defines various thermal levels + * configured by userspace to the driver/firmware. The values will be + * encapsulated in QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL attribute. + * The driver/firmware takes actions requested by userspace such as throttling + * wifi TX etc. in order to mitigate high temperature. + * + * @QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE: Stop/clear all throttling actions. + * @QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT: Throttle TX lightly. + * @QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE: Throttle TX moderately. + * @QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE: Throttle TX severely. + * @QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL: Critical thermal level reached. + * @QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY: Emergency thermal level reached. + */ +enum qca_wlan_vendor_thermal_level { + QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE = 0, + QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT = 1, + QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE = 2, + QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE = 3, + QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL = 4, + QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY = 5, +}; + +/** * enum qca_wlan_vendor_attr_thermal_cmd - Vendor subcmd attributes to set * cmd value. Used for NL attributes for data used by * QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD sub command. @@ -6317,6 +6469,21 @@ enum qca_wlan_vendor_attr_thermal_cmd { * u32 attribute. */ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE = 1, + /* Userspace uses this attribute to configure thermal level to the + * driver/firmware. Used in request, u32 attribute, possible values + * are defined in enum qca_wlan_vendor_thermal_level. + */ + QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL = 2, + /* Userspace uses this attribute to configure the time in which the + * driver/firmware should complete applying settings it received from + * userspace with QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL + * command type. Used in request, u32 attribute, value is in + * milliseconds. A value of zero indicates to apply the settings + * immediately. The driver/firmware can delay applying the configured + * thermal settings within the time specified in this attribute if + * there is any critical ongoing operation. + */ + QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW = 3, /* keep last */ QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_AFTER_LAST, @@ -6340,12 +6507,15 @@ enum qca_wlan_vendor_attr_thermal_cmd { * suspend action. * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME: Request to execute thermal * resume action. + * @QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: Configure thermal level to + * the driver/firmware. */ enum qca_wlan_vendor_attr_thermal_cmd_type { QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_PARAMS, QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE, QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SUSPEND, QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_RESUME, + QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL, }; /** @@ -7254,10 +7424,42 @@ enum qca_wlan_vendor_attr_roam_scan { * enum qca_wlan_vendor_cfr_method - QCA vendor CFR methods used by * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD as part of vendor * command QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG. + * @QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL: CFR method using QoS Null frame + * @QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE: CFR method using QoS Null frame + * with phase + * @QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE: CFR method using Probe Response frame */ enum qca_wlan_vendor_cfr_method { - /* CFR method using QOS Null frame */ QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL = 0, + QCA_WLAN_VENDOR_CFR_QOS_NULL_WITH_PHASE = 1, + QCA_WLAN_VENDOR_CFR_PROBE_RESPONSE = 2, +}; + +/** + * enum qca_wlan_vendor_cfr_capture_type - QCA vendor CFR capture type used by + * attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE. + * @QCA_WLAN_VENDOR_CFR_DIRECT_FTM: Filter directed FTM ACK frames. + * @QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK: Filter all FTM ACK frames. + * @QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP: Filter NDPA NDP directed frames. + * @QCA_WLAN_VENDOR_CFR_TA_RA: Filter frames based on TA/RA/Subtype which + * is provided by one or more of below attributes: + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER + * @QCA_WLAN_CFR_ALL_PACKET: Filter all packets. + * @QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL: Filter all NDPA NDP frames. + */ +enum qca_wlan_vendor_cfr_capture_type { + QCA_WLAN_VENDOR_CFR_DIRECT_FTM = 0, + QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK = 1, + QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP = 2, + QCA_WLAN_VENDOR_CFR_TA_RA = 3, + QCA_WLAN_VENDOR_CFR_ALL_PACKET = 4, + QCA_WLAN_VENDOR_CFR_NDPA_NDP_ALL = 5, }; /** @@ -7265,44 +7467,177 @@ enum qca_wlan_vendor_cfr_method { * QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG to configure peer * Channel Frequency Response capture parameters and enable periodic CFR * capture. + * + * @QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR: Optional (6-byte MAC address) + * MAC address of peer. This is for CFR version 1 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE: Required (flag) + * Enable peer CFR capture. This attribute is mandatory to enable peer CFR + * capture. If this attribute is not present, peer CFR capture is disabled. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH: Optional (u8) + * BW of measurement, attribute uses the values in enum nl80211_chan_width + * Supported values: 20, 40, 80, 80+80, 160. + * Note that all targets may not support all bandwidths. + * This attribute is mandatory for version 1 if attribute + * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY: Optional (u32) + * Periodicity of CFR measurement in milliseconds. + * Periodicity should be a multiple of Base timer. + * Current Base timer value supported is 10 milliseconds (default). + * 0 for one shot capture. + * This attribute is mandatory for version 1 if attribute + * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD: Optional (u8) + * Method used to capture Channel Frequency Response. + * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method. + * This attribute is mandatory for version 1 if attribute + * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. + * + * @QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE: Optional (flag) + * Enable periodic CFR capture. + * This attribute is mandatory for version 1 to enable Periodic CFR capture. + * If this attribute is not present, periodic CFR capture is disabled. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION: Optional (u8) + * Value is 1 or 2 since there are two versions of CFR capture. Two versions + * can't be enabled at same time. This attribute is mandatory if target + * support both versions and use one of them. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP: Optional (u32) + * This attribute is mandatory for version 2 if + * QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY is used. + * Bits 15:0 bitfield indicates which group is to be enabled. + * Bits 31:16 Reserved for future use. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION: Optional (u32) + * CFR capture duration in microsecond. This attribute is mandatory for + * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL is used. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL: Optional (u32) + * CFR capture interval in microsecond. This attribute is mandatory for + * version 2 if attribute QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION is used. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE: Optional (u32) + * CFR capture type is defined in enum qca_wlan_vendor_cfr_capture_type. + * This attribute is mandatory for version 2. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK: Optional (u64) + * Bitfield indicating which user in the current UL MU transmissions are + * enabled for CFR capture. Bits 36 to 0 indicate user indexes for 37 users in + * a UL MU transmission. If bit 0 is set, the CFR capture will happen for user + * index 0 in the current UL MU transmission. If bits 0 and 2 are set, CFR + * capture for UL MU TX corresponds to user indices 0 and 2. Bits 63:37 are + * reserved for future use. This is for CFR version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT: Optional (u32) + * Indicates the number of consecutive RX frames to be skipped before CFR + * capture is enabled again. This is for CFR version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE: Nested attribute containing + * one or more %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY attributes. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY: Nested attribute containing + * the following group attributes: + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER, + * %QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER: Optional (u32) + * Target supports multiple groups for some configurations. The group number + * can be any value between 0 and 15. This is for CFR version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA: Optional (6-byte MAC address) + * Transmitter address which is used to filter frames. This MAC address takes + * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK. This is for CFR + * version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA: Optional (6-byte MAC address) + * Receiver address which is used to filter frames. This MAC address takes + * effect with QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK. This is for CFR + * version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK: Optional (6-byte MAC address) + * Mask of transmitter address which is used to filter frames. This is for CFR + * version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK: Optional (6-byte MAC address) + * Mask of receiver address which is used to filter frames. This is for CFR + * version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS: Optional (u32) + * Indicates frames with a specific NSS will be filtered for CFR capture. + * This is for CFR version 2 only. This is a bitmask. Bits 7:0 request CFR + * capture to be done for frames matching the NSS specified within this bitmask. + * Bits 31:8 are reserved for future use. Bits 7:0 map to NSS: + * bit 0 : NSS 1 + * bit 1 : NSS 2 + * ... + * bit 7 : NSS 8 + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW: Optional (u32) + * Indicates frames with a specific bandwidth will be filtered for CFR capture. + * This is for CFR version 2 only. This is a bitmask. Bits 4:0 request CFR + * capture to be done for frames matching the bandwidths specified within this + * bitmask. Bits 31:5 are reserved for future use. Bits 4:0 map to bandwidth + * numerated in enum nl80211_band (although not all bands may be supported + * by a given device). + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER: Optional (u32) + * Management frames matching the subtype filter categories will be filtered in + * by MAC for CFR capture. This is a bitmask in which each bit represents the + * corresponding Management frame subtype value per IEEE Std 802.11-2016, + * 9.2.4.1.3 Type and Subtype subfields. For example, Beacon frame control type + * is 8 and its value is 1 << 8 = 0x100. This is for CFR version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER: Optional (u32) + * Control frames matching the subtype filter categories will be filtered in by + * MAC for CFR capture. This is a bitmask in which each bit represents the + * corresponding Control frame subtype value per IEEE Std 802.11-2016, + * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only. + * + * @QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER: Optional (u32) + * Data frames matching the subtype filter categories will be filtered in by + * MAC for CFR capture. This is a bitmask in which each bit represents the + * corresponding Data frame subtype value per IEEE Std 802.11-2016, + * 9.2.4.1.3 Type and Subtype subfields. This is for CFR version 2 only. */ enum qca_wlan_vendor_peer_cfr_capture_attr { QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_INVALID = 0, - /* 6-byte MAC address of the peer. - * This attribute is mandatory. - */ QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR = 1, - /* Enable peer CFR Capture, flag attribute. - * This attribute is mandatory to enable peer CFR capture. - * If this attribute is not present, peer CFR capture is disabled. - */ QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE = 2, - /* BW of measurement, attribute uses the values in enum nl80211_chan_width - * Supported values: 20, 40, 80, 80+80, 160. - * Note that all targets may not support all bandwidths. - * u8 attribute. This attribute is mandatory if attribute - * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. - */ QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH = 3, - /* Periodicity of CFR measurement in msec. - * Periodicity should be a multiple of Base timer. - * Current Base timer value supported is 10 msecs (default). - * 0 for one shot capture. u32 attribute. - * This attribute is mandatory if attribute - * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. - */ QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY = 4, - /* Method used to capture Channel Frequency Response. - * Attribute uses the values defined in enum qca_wlan_vendor_cfr_method. - * u8 attribute. This attribute is mandatory if attribute - * QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE is used. - */ QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD = 5, - /* Enable periodic CFR capture, flag attribute. - * This attribute is mandatory to enable Periodic CFR capture. - * If this attribute is not present, periodic CFR capture is disabled. - */ QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE = 6, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION = 7, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP = 8, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION = 9, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL = 10, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE = 11, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK = 12, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT = 13, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE = 14, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY = 15, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER = 16, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA = 17, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA = 18, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK = 19, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK = 20, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS = 21, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW = 22, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER = 23, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER = 24, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER = 25, /* Keep last */ QCA_WLAN_VENDOR_ATTR_PEER_CFR_AFTER_LAST, @@ -8091,10 +8426,10 @@ enum qca_vendor_wlan_sta_guard_interval { * used by QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO vendor command. * * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC: - * Required attribute in request, 6-byte MAC address, - * used in both STA and AP modes. - * MAC address of the station for which information is requested (BSSID of the - * AP in STA mode). + * Required attribute in request for AP mode only, 6-byte MAC address, + * corresponding to the station's MAC address for which information is + * requested. For STA mode this is not required as the info always correspond + * to the self STA and the current/last association. * * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS: * Optionally used in response, u32 attribute, contains a bitmap of different @@ -8122,7 +8457,7 @@ enum qca_vendor_wlan_sta_guard_interval { * back to host from target. * * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED: - * Optionally used in response, u32 attribute, used in AP mode only. + * Optionally used in response, u32 attribute, used in both STA and AP mode. * Value indicates the number of data frames not transmitted successfully even * after retrying the packets for the number of times equal to the total number * of retries allowed for that packet and for which the TX status has been @@ -8139,10 +8474,167 @@ enum qca_vendor_wlan_sta_guard_interval { * after retrying the packets. * * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED: - * Optionally used in response, u32 attribute, used in AP mode only. + * Optionally used in response, u32 attribute, used in both STA & AP mode. * Value indicates the number of data frames not transmitted successfully even * after retrying the packets for the number of times equal to the total number * of retries allowed for that packet. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT: u32, used in + * the STA mode only. Represent the number of probe requests sent by the STA + * while attempting to roam on missing certain number of beacons from the + * connected AP. If queried in the disconnected state, this represents the + * count for the last connected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT: u32, used in + * the STA mode. Represent the number of probe responses received by the station + * while attempting to roam on missing certain number of beacons from the + * connected AP. When queried in the disconnected state, this represents the + * count when in last connected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT: u32, used in the + * STA mode only. Represents the total number of frames sent out by STA + * including Data, ACK, RTS, CTS, Control Management. This data is maintained + * only for the connect session. Represents the count of last connected session, + * when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT: u32, used in the STA mode. + * Total number of RTS sent out by the STA. This data is maintained per connect + * session. Represents the count of last connected session, when queried in the + * disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT: u32, used in the + * STA mode.Represent the number of RTS transmission failure that reach retry + * limit. This data is maintained per connect session. Represents the count of + * last connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT: u32, used in + * the STA mode. Represent the total number of non aggregated frames transmitted + * by the STA. This data is maintained per connect session. Represents the count + * of last connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT: u32, used in the + * STA mode. Represent the total number of aggregated frames transmitted by the + * STA. This data is maintained per connect session. Represents the count of + * last connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT: u32, used in + * the STA mode. Represents the number of received frames with a good PLCP. This + * data is maintained per connect session. Represents the count of last + * connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT: u32, + * used in the STA mode. Represents the number of occasions that no valid + * delimiter is detected by A-MPDU parser. This data is maintained per connect + * session. Represents the count of last connected session, when queried in the + * disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT: u32, used in the + * STA mode. Represents the number of frames for which CRC check failed in the + * MAC. This data is maintained per connect session. Represents the count of + * last connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT: u32, used in the + * STA mode. Represents the number of unicast ACKs received with good FCS. This + * data is maintained per connect session. Represents the count of last + * connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT: u32, used in the STA + * mode. Represents the number of received Block Acks. This data is maintained + * per connect session. Represents the count of last connected session, when + * queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT: u32, used in the STA + * mode. Represents the number of beacons received from the connected BSS. This + * data is maintained per connect session. Represents the count of last + * connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT: u32, used in the + * STA mode. Represents the number of beacons received by the other BSS when in + * connected state (through the probes done by the STA). This data is maintained + * per connect session. Represents the count of last connected session, when + * queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT: u64, used in + * the STA mode. Represents the number of received DATA frames with good FCS and + * matching Receiver Address when in connected state. This data is maintained + * per connect session. Represents the count of last connected session, when + * queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT: u32, used in the + * STA mode. Represents the number of RX Data multicast frames dropped by the HW + * when in the connected state. This data is maintained per connect session. + * Represents the count of last connected session, when queried in the + * disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS: u32, used in the + * STA mode. This represents the target power in dBm for the transmissions done + * to the AP in 2.4 GHz at 1 Mbps (DSSS) rate. This data is maintained per + * connect session. Represents the count of last connected session, when + * queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS: u32, used in the + * STA mode. This represents the Target power in dBm for transmissions done to + * the AP in 2.4 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect + * session. Represents the count of last connected session, when queried in the + * disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0: u32, used in the + * STA mode. This represents the Target power in dBm for transmissions done to + * the AP in 2.4 GHz at MCS0 rate. This data is maintained per connect session. + * Represents the count of last connected session, when queried in the + * disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS: u32, used in the + * STA mode. This represents the Target power in dBm for transmissions done to + * the AP in 5 GHz at 6 Mbps (OFDM) rate. This data is maintained per connect + * session. Represents the count of last connected session, when queried in + * the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0: u32, used in the + * STA mode. This represents the Target power in dBm for for transmissions done + * to the AP in 5 GHz at MCS0 rate. This data is maintained per connect session. + * Represents the count of last connected session, when queried in the + * disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT: u32, used + * in the STA mode. This represents the Nested attribute representing the + * overflow counts of each receive buffer allocated to the hardware during the + * STA's connection. The number of hw buffers might vary for each WLAN + * solution and hence this attribute represents the nested array of all such + * HW buffer count. This data is maintained per connect session. Represents + * the count of last connected session, when queried in the disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER: u32, Max TX power (dBm) + * allowed as per the regulatory requirements for the current or last connected + * session. Used in the STA mode. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER: u32, Latest TX power + * (dBm) used by the station in its latest unicast frame while communicating + * to the AP in the connected state. When queried in the disconnected state, + * this represents the TX power used by the STA with last AP communication + * when in connected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL: u32, Adaptive noise immunity + * level used to adjust the RX sensitivity. Represents the current ANI level + * when queried in the connected state. When queried in the disconnected + * state, this corresponds to the latest ANI level at the instance of + * disconnection. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES: Binary attribute containing + * the raw information elements from Beacon frames. Represents the Beacon frames + * of the current BSS in the connected state. When queried in the disconnected + * state, these IEs correspond to the last connected BSSID. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES: Binary attribute + * containing the raw information elements from Probe Response frames. + * Represents the Probe Response frames of the current BSS in the connected + * state. When queried in the disconnected state, these IEs correspond to the + * last connected BSSID. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON: u32, Driver + * disconnect reason for the last disconnection if the disconnection is + * triggered from the host driver. The values are referred from + * enum qca_disconnect_reason_codes. */ enum qca_wlan_vendor_attr_get_sta_info { QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID = 0, @@ -8156,6 +8648,34 @@ enum qca_wlan_vendor_attr_get_sta_info { QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL = 8, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY = 9, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED = 10, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_PROBE_REQ_BMISS_COUNT = 11, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_PROBE_RESP_BMISS_COUNT = 12, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_ALL_COUNT = 13, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_COUNT = 14, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RTS_RETRY_FAIL_COUNT = 15, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_NON_AGGREGATED_COUNT = 16, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_DATA_AGGREGATED_COUNT = 17, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_GOOD_PLCP_COUNT = 18, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_INVALID_DELIMITER_COUNT = 19, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT = 20, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_ACKS_GOOD_FCS_COUNT = 21, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BLOCKACK_COUNT = 22, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BEACON_COUNT = 23, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_OTHER_BEACON_COUNT = 24, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_UCAST_DATA_GOOD_FCS_COUNT = 25, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_DATA_BC_MC_DROP_COUNT = 26, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS = 27, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS = 28, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_MCS0 = 29, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS = 30, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_MCS0 = 31, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_HW_BUFFERS_OVERFLOW_COUNT = 32, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX_TX_POWER = 33, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER = 34, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL = 35, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_IES = 36, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PROBE_RESP_IES = 37, + QCA_WLAN_VENDOR_ATTR_GET_STA_DRIVER_DISCONNECT_REASON = 38, /* keep last */ QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST, @@ -8163,4 +8683,126 @@ enum qca_wlan_vendor_attr_get_sta_info { QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_AFTER_LAST - 1, }; +/** + * enum qca_wlan_vendor_attr_update_sta_info - Defines attributes + * used by QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS: Type is NLA_UNSPEC. + * Used in STA mode. This attribute represents the list of channel center + * frequencies in MHz (u32) the station has learnt during the last connection + * or roaming attempt. This information shall not signify the channels for + * an explicit scan request from the user space. Host drivers can update this + * information to the user space in both connected and disconnected state. + * In the disconnected state this information shall signify the channels + * scanned in the last connection/roam attempt that lead to the disconnection. + */ +enum qca_wlan_vendor_attr_update_sta_info { + QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_disconnect_reason_codes - Specifies driver disconnect reason codes. + * Used when the driver triggers the STA to disconnect from the AP. + * + * @QCA_DISCONNECT_REASON_UNSPECIFIED: The host driver triggered the + * disconnection with the AP due to unspecified reasons. + * + * @QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE: The host driver triggered the + * disconnection with the AP due to a roaming failure. This roaming is triggered + * internally (host driver/firmware). + * + * @QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE: The driver disconnected from + * the AP when the user/external triggered roaming fails. + * + * @QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE: This reason code is used + * by the host driver whenever gateway reachability failure is detected and the + * driver disconnects with AP. + * + * @QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA: The driver disconnected from + * the AP on a channel switch announcement from it with an unsupported channel. + * + * @QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR: On a concurrent AP start + * with indoor channels disabled and if the STA is connected on one of these + * disabled channels, the host driver disconnected the STA with this reason + * code. + * + * @QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED: Disconnection due to an + * explicit request from the user to disable the current operating channel. + * + * @QCA_DISCONNECT_REASON_DEVICE_RECOVERY: STA disconnected from the AP due to + * the internal host driver/firmware recovery. + * + * @QCA_DISCONNECT_REASON_KEY_TIMEOUT: The driver triggered the disconnection on + * a timeout for the key installations from the user space. + * + * @QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE: The dDriver disconnected the + * STA on a band change request from the user space to a different band from the + * current operation channel/band. + * + * @QCA_DISCONNECT_REASON_IFACE_DOWN: The STA disconnected from the AP on an + * interface down trigger from the user space. + * + * @QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL: The host driver disconnected the + * STA on getting continuous transmission failures for multiple Data frames. + * + * @QCA_DISCONNECT_REASON_PEER_INACTIVITY: The STA does a keep alive + * notification to the AP by transmitting NULL/G-ARP frames. This disconnection + * represents inactivity from AP on such transmissions. + + * @QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT: This reason code is used on + * disconnection when SA Query times out (AP does not respond to SA Query). + * + * @QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE: The host driver disconnected the + * STA on missing the beacons continuously from the AP. + * + * @QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE: Disconnection due to STA not + * able to move to the channel mentioned by the AP in CSA. + * + * @QCA_DISCONNECT_REASON_USER_TRIGGERED: User triggered disconnection. + */ +enum qca_disconnect_reason_codes { + QCA_DISCONNECT_REASON_UNSPECIFIED = 0, + QCA_DISCONNECT_REASON_INTERNAL_ROAM_FAILURE = 1, + QCA_DISCONNECT_REASON_EXTERNAL_ROAM_FAILURE = 2, + QCA_DISCONNECT_REASON_GATEWAY_REACHABILITY_FAILURE = 3, + QCA_DISCONNECT_REASON_UNSUPPORTED_CHANNEL_CSA = 4, + QCA_DISCONNECT_REASON_OPER_CHANNEL_DISABLED_INDOOR = 5, + QCA_DISCONNECT_REASON_OPER_CHANNEL_USER_DISABLED = 6, + QCA_DISCONNECT_REASON_DEVICE_RECOVERY = 7, + QCA_DISCONNECT_REASON_KEY_TIMEOUT = 8, + QCA_DISCONNECT_REASON_OPER_CHANNEL_BAND_CHANGE = 9, + QCA_DISCONNECT_REASON_IFACE_DOWN = 10, + QCA_DISCONNECT_REASON_PEER_XRETRY_FAIL = 11, + QCA_DISCONNECT_REASON_PEER_INACTIVITY = 12, + QCA_DISCONNECT_REASON_SA_QUERY_TIMEOUT = 13, + QCA_DISCONNECT_REASON_BEACON_MISS_FAILURE = 14, + QCA_DISCONNECT_REASON_CHANNEL_SWITCH_FAILURE = 15, + QCA_DISCONNECT_REASON_USER_TRIGGERED = 16, +}; + +/** + * enum qca_wlan_vendor_attr_driver_disconnect_reason - Defines attributes + * used by %QCA_NL80211_VENDOR_SUBCMD_DRIVER_DISCONNECT_REASON vendor command. + * + * @QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE: u32 attribute. + * This attribute represents the driver specific reason codes (local + * driver/firmware initiated reasons for disconnection) defined + * in enum qca_disconnect_reason_codes. + */ +enum qca_wlan_vendor_attr_driver_disconnect_reason { + QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASCON_CODE = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_MAX = + QCA_WLAN_VENDOR_ATTR_DRIVER_DISCONNECT_REASON_AFTER_LAST - 1, +}; + #endif /* QCA_VENDOR_H */ diff --git a/src/common/sae.c b/src/common/sae.c index bf8cc9de..543640de 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -123,6 +123,7 @@ void sae_clear_data(struct sae_data *sae) return; sae_clear_temp_data(sae); crypto_bignum_deinit(sae->peer_commit_scalar, 0); + crypto_bignum_deinit(sae->peer_commit_scalar_accepted, 0); os_memset(sae, 0, sizeof(*sae)); } @@ -864,7 +865,7 @@ size_t sae_ecc_prime_len_2_hash_len(size_t prime_len) } -struct crypto_ec_point * +static struct crypto_ec_point * sae_derive_pt_ecc(struct crypto_ec *ec, int group, const u8 *ssid, size_t ssid_len, const u8 *password, size_t password_len, @@ -1622,38 +1623,42 @@ int sae_process_commit(struct sae_data *sae) } -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token, const char *identifier) +int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, + const struct wpabuf *token, const char *identifier) { u8 *pos; if (sae->tmp == NULL) - return; + return -1; wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */ - if (token) { + if (!sae->tmp->h2e && token) { wpabuf_put_buf(buf, token); wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token", wpabuf_head(token), wpabuf_len(token)); } pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, - sae->tmp->prime_len, sae->tmp->prime_len); + if (crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos, + sae->tmp->prime_len, sae->tmp->prime_len) < 0) + return -1; wpa_hexdump(MSG_DEBUG, "SAE: own commit-scalar", pos, sae->tmp->prime_len); if (sae->tmp->ec) { pos = wpabuf_put(buf, 2 * sae->tmp->prime_len); - crypto_ec_point_to_bin(sae->tmp->ec, - sae->tmp->own_commit_element_ecc, - pos, pos + sae->tmp->prime_len); + if (crypto_ec_point_to_bin(sae->tmp->ec, + sae->tmp->own_commit_element_ecc, + pos, pos + sae->tmp->prime_len) < 0) + return -1; wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(x)", pos, sae->tmp->prime_len); wpa_hexdump(MSG_DEBUG, "SAE: own commit-element(y)", pos + sae->tmp->prime_len, sae->tmp->prime_len); } else { pos = wpabuf_put(buf, sae->tmp->prime_len); - crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, - sae->tmp->prime_len, sae->tmp->prime_len); + if (crypto_bignum_to_bin(sae->tmp->own_commit_element_ffc, pos, + sae->tmp->prime_len, + sae->tmp->prime_len) < 0) + return -1; wpa_hexdump(MSG_DEBUG, "SAE: own commit-element", pos, sae->tmp->prime_len); } @@ -1677,6 +1682,18 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS); wpabuf_put_buf(buf, sae->tmp->own_rejected_groups); } + + if (sae->tmp->h2e && token) { + wpabuf_put_u8(buf, WLAN_EID_EXTENSION); + wpabuf_put_u8(buf, 1 + wpabuf_len(token)); + wpabuf_put_u8(buf, WLAN_EID_EXT_ANTI_CLOGGING_TOKEN); + wpabuf_put_buf(buf, token); + wpa_hexdump_buf(MSG_DEBUG, + "SAE: Anti-clogging token (in container)", + token); + } + + return 0; } @@ -1742,32 +1759,34 @@ static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end) } +static int sae_is_token_container_elem(const u8 *pos, const u8 *end) +{ + return end - pos >= 3 && + pos[0] == WLAN_EID_EXTENSION && + pos[1] >= 1 && + end - pos - 2 >= pos[1] && + pos[2] == WLAN_EID_EXT_ANTI_CLOGGING_TOKEN; +} + + static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, const u8 *end, const u8 **token, size_t *token_len, int h2e) { size_t scalar_elem_len, tlen; - const u8 *elem; if (token) *token = NULL; if (token_len) *token_len = 0; + if (h2e) + return; /* No Anti-Clogging Token field outside container IE */ + scalar_elem_len = (sae->tmp->ec ? 3 : 2) * sae->tmp->prime_len; if (scalar_elem_len >= (size_t) (end - *pos)) return; /* No extra data beyond peer scalar and element */ - /* It is a bit difficult to parse this now that there is an - * optional variable length Anti-Clogging Token field and - * optional variable length Password Identifier element in the - * frame. We are sending out fixed length Anti-Clogging Token - * fields, so use that length as a requirement for the received - * token and check for the presence of possible Password - * Identifier element based on the element header information. - * When parsing H2E case, also consider the Rejected Groupd element - * similarly. - */ tlen = end - (*pos + scalar_elem_len); if (tlen < SHA256_MAC_LEN) { @@ -1777,36 +1796,6 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, return; } - elem = *pos + scalar_elem_len; - if (sae_is_password_id_elem(elem, end)) { - /* Password Identifier element takes out all available - * extra octets, so there can be no Anti-Clogging token in - * this frame. */ - return; - } - if (h2e && sae_is_rejected_groups_elem(elem, end)) { - /* Rejected Groups takes out all available extra octets, so - * there can be no Anti-Clogging token in this frame. */ - return; - } - - elem += SHA256_MAC_LEN; - if (sae_is_password_id_elem(elem, end)) { - /* Password Identifier element is included in the end, so - * remove its length from the Anti-Clogging token field. */ - tlen -= 2 + elem[1]; - elem += 2 + elem[1]; - if (h2e && sae_is_rejected_groups_elem(elem, end)) { - /* Also remove Rejected Groups element from the - * Anti-Clogging token field length */ - tlen -= 2 + elem[1]; - } - } else if (h2e && sae_is_rejected_groups_elem(elem, end)) { - /* Rejected Groups element is included in the end, so - * remove its length from the Anti-Clogging token field. */ - tlen -= 2 + elem[1]; - } - wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen); if (token) *token = *pos; @@ -1816,6 +1805,21 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos, } +static void sae_parse_token_container(struct sae_data *sae, + const u8 *pos, const u8 *end, + const u8 **token, size_t *token_len) +{ + wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame", + pos, end - pos); + if (!sae_is_token_container_elem(pos, end)) + return; + *token = pos + 3; + *token_len = pos[1] - 1; + wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)", + *token, *token_len); +} + + static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, const u8 *end) { @@ -1836,8 +1840,9 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos, * shall be dropped if the peer-scalar is identical to the one used in * the existing protocol instance. */ - if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar && - crypto_bignum_cmp(sae->peer_commit_scalar, peer_scalar) == 0) { + if (sae->state == SAE_ACCEPTED && sae->peer_commit_scalar_accepted && + crypto_bignum_cmp(sae->peer_commit_scalar_accepted, + peer_scalar) == 0) { wpa_printf(MSG_DEBUG, "SAE: Do not accept re-use of previous " "peer-commit-scalar"); crypto_bignum_deinit(peer_scalar, 0); @@ -2010,19 +2015,21 @@ static int sae_parse_password_identifier(struct sae_data *sae, static int sae_parse_rejected_groups(struct sae_data *sae, - const u8 *pos, const u8 *end) + const u8 **pos, const u8 *end) { wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame", - pos, end - pos); - if (!sae_is_rejected_groups_elem(pos, end)) + *pos, end - *pos); + if (!sae_is_rejected_groups_elem(*pos, end)) return WLAN_STATUS_SUCCESS; wpabuf_free(sae->tmp->peer_rejected_groups); - sae->tmp->peer_rejected_groups = wpabuf_alloc(pos[1] - 1); + sae->tmp->peer_rejected_groups = wpabuf_alloc((*pos)[1] - 1); if (!sae->tmp->peer_rejected_groups) return WLAN_STATUS_UNSPECIFIED_FAILURE; - wpabuf_put_data(sae->tmp->peer_rejected_groups, pos + 3, pos[1] - 1); + wpabuf_put_data(sae->tmp->peer_rejected_groups, (*pos) + 3, + (*pos)[1] - 1); wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list", sae->tmp->peer_rejected_groups); + *pos = *pos + 2 + (*pos)[1]; return WLAN_STATUS_SUCCESS; } @@ -2062,11 +2069,15 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, /* Conditional Rejected Groups element */ if (h2e) { - res = sae_parse_rejected_groups(sae, pos, end); + res = sae_parse_rejected_groups(sae, &pos, end); if (res != WLAN_STATUS_SUCCESS) return res; } + /* Optional Anti-Clogging Token Container element */ + if (h2e) + sae_parse_token_container(sae, pos, end, token, token_len); + /* * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as * the values we sent which would be evidence of a reflection attack. diff --git a/src/common/sae.h b/src/common/sae.h index b3787e4f..7966d70e 100644 --- a/src/common/sae.h +++ b/src/common/sae.h @@ -70,6 +70,7 @@ struct sae_data { u8 pmk[SAE_PMK_LEN]; u8 pmkid[SAE_PMKID_LEN]; struct crypto_bignum *peer_commit_scalar; + struct crypto_bignum *peer_commit_scalar_accepted; int group; unsigned int sync; /* protocol instance variable: Sync */ u16 rc; /* protocol instance variable: Rc (received send-confirm) */ @@ -87,8 +88,8 @@ int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt, const u8 *addr1, const u8 *addr2, int *rejected_groups); int sae_process_commit(struct sae_data *sae); -void sae_write_commit(struct sae_data *sae, struct wpabuf *buf, - const struct wpabuf *token, const char *identifier); +int sae_write_commit(struct sae_data *sae, struct wpabuf *buf, + const struct wpabuf *token, const char *identifier); u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len, const u8 **token, size_t *token_len, int *allowed_groups, int h2e); diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index de4b6ecd..12847430 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -355,6 +355,14 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, size_t data_len = 2 * ETH_ALEN + 2 * WPA_NONCE_LEN; u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN]; size_t ptk_len; +#ifdef CONFIG_OWE + int owe_ptk_workaround = 0; + + if (akmp == (WPA_KEY_MGMT_OWE | WPA_KEY_MGMT_PSK_SHA256)) { + owe_ptk_workaround = 1; + akmp = WPA_KEY_MGMT_OWE; + } +#endif /* CONFIG_OWE */ if (pmk_len == 0) { wpa_printf(MSG_ERROR, "WPA: No PMK set for PTK derivation"); @@ -407,11 +415,33 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, #else /* CONFIG_SUITEB192 || CONFIG_FILS */ return -1; #endif /* CONFIG_SUITEB192 || CONFIG_FILS */ - } else if (wpa_key_mgmt_sha256(akmp) || akmp == WPA_KEY_MGMT_OWE) { + } else if (wpa_key_mgmt_sha256(akmp)) { + wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); + if (sha256_prf(pmk, pmk_len, label, data, data_len, + tmp, ptk_len) < 0) + return -1; +#ifdef CONFIG_OWE + } else if (akmp == WPA_KEY_MGMT_OWE && (pmk_len == 32 || + owe_ptk_workaround)) { wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); if (sha256_prf(pmk, pmk_len, label, data, data_len, tmp, ptk_len) < 0) return -1; + } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 48) { + wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA384)"); + if (sha384_prf(pmk, pmk_len, label, data, data_len, + tmp, ptk_len) < 0) + return -1; + } else if (akmp == WPA_KEY_MGMT_OWE && pmk_len == 64) { + wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA512)"); + if (sha512_prf(pmk, pmk_len, label, data, data_len, + tmp, ptk_len) < 0) + return -1; + } else if (akmp == WPA_KEY_MGMT_OWE) { + wpa_printf(MSG_INFO, "OWE: Unknown PMK length %u", + (unsigned int) pmk_len); + return -1; +#endif /* CONFIG_OWE */ #ifdef CONFIG_DPP } else if (akmp == WPA_KEY_MGMT_DPP && pmk_len == 32) { wpa_printf(MSG_DEBUG, "WPA: PTK derivation using PRF(SHA256)"); @@ -904,6 +934,10 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, parse->oci_len = len; break; #endif /* CONFIG_OCV */ + case FTIE_SUBELEM_BIGTK: + parse->bigtk = pos; + parse->bigtk_len = len; + break; default: wpa_printf(MSG_DEBUG, "FT: Unknown subelem id %u", id); break; @@ -1940,10 +1974,12 @@ const char * wpa_cipher_txt(int cipher) switch (cipher) { case WPA_CIPHER_NONE: return "NONE"; +#ifdef CONFIG_WEP case WPA_CIPHER_WEP40: return "WEP-40"; case WPA_CIPHER_WEP104: return "WEP-104"; +#endif /* CONFIG_WEP */ case WPA_CIPHER_TKIP: return "TKIP"; case WPA_CIPHER_CCMP: @@ -2079,8 +2115,6 @@ u32 wpa_akm_to_suite(int akm) return RSN_AUTH_KEY_MGMT_OWE; if (akm & WPA_KEY_MGMT_DPP) return RSN_AUTH_KEY_MGMT_DPP; - if (akm & WPA_KEY_MGMT_OSEN) - return RSN_AUTH_KEY_MGMT_OSEN; return 0; } @@ -2444,10 +2478,12 @@ int wpa_parse_cipher(const char *value) val |= WPA_CIPHER_GCMP; else if (os_strcmp(start, "TKIP") == 0) val |= WPA_CIPHER_TKIP; +#ifdef CONFIG_WEP else if (os_strcmp(start, "WEP104") == 0) val |= WPA_CIPHER_WEP104; else if (os_strcmp(start, "WEP40") == 0) val |= WPA_CIPHER_WEP40; +#endif /* CONFIG_WEP */ else if (os_strcmp(start, "NONE") == 0) val |= WPA_CIPHER_NONE; else if (os_strcmp(start, "GTK_NOT_USED") == 0) @@ -2645,12 +2681,10 @@ static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end, /** * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header - * @end: Pointer to the end of the Key Data buffer * @ie: Pointer to parsed IE data * Returns: 0 on success, 1 if end mark is found, -1 on failure */ -static int wpa_parse_generic(const u8 *pos, const u8 *end, - struct wpa_eapol_ie_parse *ie) +static int wpa_parse_generic(const u8 *pos, struct wpa_eapol_ie_parse *ie) { if (pos[1] == 0) return 1; @@ -2672,8 +2706,7 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, return 0; } - if (1 + RSN_SELECTOR_LEN < end - pos && - pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && + if (pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) { ie->pmkid = pos + 2 + RSN_SELECTOR_LEN; wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key", @@ -2681,6 +2714,14 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, return 0; } + if (pos[1] >= RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_KEYID) { + ie->key_id = pos + 2 + RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, "WPA: KeyID in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + if (pos[1] > RSN_SELECTOR_LEN + 2 && RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) { ie->gtk = pos + 2 + RSN_SELECTOR_LEN; @@ -2708,6 +2749,15 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, return 0; } + if (pos[1] > RSN_SELECTOR_LEN + 2 && + RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_BIGTK) { + ie->bigtk = pos + 2 + RSN_SELECTOR_LEN; + ie->bigtk_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + if (pos[1] >= RSN_SELECTOR_LEN + 1 && RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) { ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN; @@ -2734,6 +2784,16 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end, return 0; } + if (pos[1] >= RSN_SELECTOR_LEN + 1 && + RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_TRANSITION_DISABLE) { + ie->transition_disable = pos + 2 + RSN_SELECTOR_LEN; + ie->transition_disable_len = pos[1] - RSN_SELECTOR_LEN; + wpa_hexdump(MSG_DEBUG, + "WPA: Transition Disable KDE in EAPOL-Key", + pos, pos[1] + 2); + return 0; + } + return 0; } @@ -2842,7 +2902,7 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie) ie->supp_oper_classes_len = pos[1]; } } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) { - ret = wpa_parse_generic(pos, end, ie); + ret = wpa_parse_generic(pos, ie); if (ret < 0) break; if (ret > 0) { diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index beb1ecd5..da58159e 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -109,9 +109,11 @@ WPA_CIPHER_BIP_CMAC_256) #define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11) #define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12) #define RSN_KEY_DATA_OCI RSN_SELECTOR(0x00, 0x0f, 0xac, 13) +#define RSN_KEY_DATA_BIGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 14) #define WFA_KEY_DATA_IP_ADDR_REQ RSN_SELECTOR(0x50, 0x6f, 0x9a, 4) #define WFA_KEY_DATA_IP_ADDR_ALLOC RSN_SELECTOR(0x50, 0x6f, 0x9a, 5) +#define WFA_KEY_DATA_TRANSITION_DISABLE RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x20) #define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1) @@ -130,6 +132,8 @@ WPA_CIPHER_BIP_CMAC_256) #define WPA_IGTK_LEN 16 #define WPA_IGTK_MAX_LEN 32 +#define WPA_BIGTK_LEN 16 +#define WPA_BIGTK_MAX_LEN 32 /* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */ @@ -227,6 +231,11 @@ struct wpa_igtk { size_t igtk_len; }; +struct wpa_bigtk { + u8 bigtk[WPA_BIGTK_MAX_LEN]; + size_t bigtk_len; +}; + /* WPA IE version 1 * 00-50-f2:1 (OUI:OUI type) * 0x01 0x00 (version; little endian) @@ -292,6 +301,13 @@ struct wpa_igtk_kde { u8 igtk[WPA_IGTK_MAX_LEN]; } STRUCT_PACKED; +#define WPA_BIGTK_KDE_PREFIX_LEN (2 + 6) +struct wpa_bigtk_kde { + u8 keyid[2]; + u8 pn[6]; + u8 bigtk[WPA_BIGTK_MAX_LEN]; +} STRUCT_PACKED; + struct rsn_mdie { u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN]; u8 ft_capab; @@ -321,6 +337,7 @@ struct rsn_ftie_sha384 { #define FTIE_SUBELEM_R0KH_ID 3 #define FTIE_SUBELEM_IGTK 4 #define FTIE_SUBELEM_OCI 5 +#define FTIE_SUBELEM_BIGTK 6 struct rsn_rdie { u8 id; @@ -328,6 +345,12 @@ struct rsn_rdie { le16 status_code; } STRUCT_PACKED; +/* WFA Transition Disable KDE (using OUI_WFA) */ +/* Transition Disable Bitmap bits */ +#define TRANSITION_DISABLE_WPA3_PERSONAL BIT(0) +#define TRANSITION_DISABLE_SAE_PK BIT(1) +#define TRANSITION_DISABLE_WPA3_ENTERPRISE BIT(2) +#define TRANSITION_DISABLE_ENHANCED_OPEN BIT(3) #ifdef _MSC_VER #pragma pack(pop) @@ -455,6 +478,8 @@ struct wpa_ft_ies { size_t tie_len; const u8 *igtk; size_t igtk_len; + const u8 *bigtk; + size_t bigtk_len; #ifdef CONFIG_OCV const u8 *oci; size_t oci_len; @@ -476,18 +501,23 @@ struct wpa_eapol_ie_parse { const u8 *rsn_ie; size_t rsn_ie_len; const u8 *pmkid; + const u8 *key_id; const u8 *gtk; size_t gtk_len; const u8 *mac_addr; size_t mac_addr_len; const u8 *igtk; size_t igtk_len; + const u8 *bigtk; + size_t bigtk_len; const u8 *mdie; size_t mdie_len; const u8 *ftie; size_t ftie_len; const u8 *ip_addr_req; const u8 *ip_addr_alloc; + const u8 *transition_disable; + size_t transition_disable_len; const u8 *oci; size_t oci_len; const u8 *osen; diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index 944b6e35..c1ce68c1 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -270,7 +270,6 @@ void wpa_ctrl_close(struct wpa_ctrl *ctrl) void wpa_ctrl_cleanup(void) { DIR *dir; - struct dirent entry; struct dirent *result; size_t dirnamelen; size_t maxcopy; @@ -288,8 +287,8 @@ void wpa_ctrl_cleanup(void) } namep = pathname + dirnamelen; maxcopy = PATH_MAX - dirnamelen; - while (readdir_r(dir, &entry, &result) == 0 && result != NULL) { - if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy) + while ((result = readdir(dir)) != NULL) { + if (os_strlcpy(namep, result->d_name, maxcopy) < maxcopy) unlink(pathname); } closedir(dir); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index f03c698f..ca1c35f8 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -95,6 +95,8 @@ extern "C" { /** SAE authentication failed due to unknown password identifier */ #define WPA_EVENT_SAE_UNKNOWN_PASSWORD_IDENTIFIER \ "CTRL-EVENT-SAE-UNKNOWN-PASSWORD-IDENTIFIER " +/** Unprotected Beacon frame dropped */ +#define WPA_EVENT_UNPROT_BEACON "CTRL-EVENT-UNPROT-BEACON " /** IP subnet status change notification * @@ -179,6 +181,7 @@ extern "C" { #define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY " #define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR " #define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID " +#define DPP_EVENT_CONFIGURATOR_ID "DPP-CONFIGURATOR-ID " #define DPP_EVENT_RX "DPP-RX " #define DPP_EVENT_TX "DPP-TX " #define DPP_EVENT_TX_STATUS "DPP-TX-STATUS " @@ -186,6 +189,7 @@ extern "C" { #define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT " #define DPP_EVENT_INTRO "DPP-INTRO " #define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX " +#define DPP_EVENT_CHIRP_STOPPED "DPP-CHIRP-STOPPED " /* MESH events */ #define MESH_GROUP_STARTED "MESH-GROUP-STARTED " @@ -379,6 +383,13 @@ extern "C" { #define WDS_STA_INTERFACE_ADDED "WDS-STA-INTERFACE-ADDED " #define WDS_STA_INTERFACE_REMOVED "WDS-STA-INTERFACE-REMOVED " +/* Transition mode disabled indication - followed by bitmap */ +#define TRANSITION_DISABLE "TRANSITION-DISABLE " + +#ifndef BIT +#define BIT(x) (1U << (x)) +#endif + /* BSS command information masks */ #define WPA_BSS_MASK_ALL 0xFFFDFFFF diff --git a/src/crypto/Makefile b/src/crypto/Makefile index ab108daa..c40e9556 100644 --- a/src/crypto/Makefile +++ b/src/crypto/Makefile @@ -54,6 +54,8 @@ LIB_OBJS= \ sha384.o \ sha384-prf.o \ sha384-internal.o \ + sha512.o \ + sha512-prf.o \ sha512-internal.o LIB_OBJS += crypto_internal.o diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 440da030..7c7515f6 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -916,5 +916,6 @@ struct wpabuf * crypto_ecdh_get_pubkey(struct crypto_ecdh *ecdh, int inc_y); struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y, const u8 *key, size_t len); void crypto_ecdh_deinit(struct crypto_ecdh *ecdh); +size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh); #endif /* CRYPTO_H */ diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index 783b293e..47b6ebbd 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -2168,4 +2168,10 @@ void crypto_ecdh_deinit(struct crypto_ecdh *ecdh) } } + +size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh) +{ + return crypto_ec_prime_len(ecdh->ec); +} + #endif /* CONFIG_ECC */ diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c index 85ce565b..dc68bd65 100644 --- a/src/crypto/crypto_wolfssl.c +++ b/src/crypto/crypto_wolfssl.c @@ -1834,4 +1834,10 @@ fail: goto done; } + +size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh) +{ + return crypto_ec_prime_len(ecdh->ec); +} + #endif /* CONFIG_ECC */ diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c index b55e976f..17af964a 100644 --- a/src/crypto/sha256.c +++ b/src/crypto/sha256.c @@ -28,10 +28,10 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, { unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */ unsigned char tk[32]; - const u8 *_addr[6]; - size_t _len[6], i; + const u8 *_addr[11]; + size_t _len[11], i; - if (num_elem > 5) { + if (num_elem > 10) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c index ee136ce9..fd84b82b 100644 --- a/src/crypto/sha384.c +++ b/src/crypto/sha384.c @@ -28,10 +28,10 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem, { unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */ unsigned char tk[48]; - const u8 *_addr[6]; - size_t _len[6], i; + const u8 *_addr[11]; + size_t _len[11], i; - if (num_elem > 5) { + if (num_elem > 10) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). diff --git a/src/crypto/sha512.c b/src/crypto/sha512.c index 66311c37..f60a5767 100644 --- a/src/crypto/sha512.c +++ b/src/crypto/sha512.c @@ -28,10 +28,10 @@ int hmac_sha512_vector(const u8 *key, size_t key_len, size_t num_elem, { unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */ unsigned char tk[64]; - const u8 *_addr[6]; - size_t _len[6], i; + const u8 *_addr[11]; + size_t _len[11], i; - if (num_elem > 5) { + if (num_elem > 10) { /* * Fixed limit on the number of fragments to avoid having to * allocate memory (which could fail). diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 84ec9854..7ee371ab 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -2208,6 +2208,7 @@ static int openssl_cert_tod(X509 *cert) else if (os_strcmp(buf, "1.3.6.1.4.1.40808.1.3.2") == 0 && !tod) tod = 2; /* TOD-TOFU */ } + sk_POLICYINFO_pop_free(ext, POLICYINFO_free); return tod; } @@ -4926,6 +4927,76 @@ static int ocsp_status_cb(SSL *s, void *arg) #endif /* HAVE_OCSP */ +static size_t max_str_len(const char **lines) +{ + const char **p; + size_t max_len = 0; + + for (p = lines; *p; p++) { + size_t len = os_strlen(*p); + + if (len > max_len) + max_len = len; + } + + return max_len; +} + + +static int match_lines_in_file(const char *path, const char **lines) +{ + FILE *f; + char *buf; + size_t bufsize; + int found = 0, is_linestart = 1; + + bufsize = max_str_len(lines) + sizeof("\r\n"); + buf = os_malloc(bufsize); + if (!buf) + return 0; + + f = fopen(path, "r"); + if (!f) { + os_free(buf); + return 0; + } + + while (!found && fgets(buf, bufsize, f)) { + int is_lineend; + size_t len; + const char **p; + + len = strcspn(buf, "\r\n"); + is_lineend = buf[len] != '\0'; + buf[len] = '\0'; + + if (is_linestart && is_lineend) { + for (p = lines; !found && *p; p++) + found = os_strcmp(buf, *p) == 0; + } + is_linestart = is_lineend; + } + + fclose(f); + bin_clear_free(buf, bufsize); + + return found; +} + + +static int is_tpm2_key(const char *path) +{ + /* Check both new and old format of TPM2 PEM guard tag */ + static const char *tpm2_tags[] = { + "-----BEGIN TSS2 PRIVATE KEY-----", + "-----BEGIN TSS2 KEY BLOB-----", + NULL + }; + + return match_lines_in_file(path, tpm2_tags); +} + + int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, const struct tls_connection_params *params) { @@ -4978,6 +5049,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, if (can_pkcs11 == 2 && !engine_id) engine_id = "pkcs11"; + /* If private_key points to a TPM2-wrapped key, automatically enable + * tpm2 engine and use it to unwrap the key. */ + if (params->private_key && + (!engine_id || os_strcmp(engine_id, "tpm2") == 0) && + is_tpm2_key(params->private_key)) { + wpa_printf(MSG_DEBUG, "OpenSSL: Found TPM2 wrapped key %s", + params->private_key); + key_id = key_id ? key_id : params->private_key; + engine_id = engine_id ? engine_id : "tpm2"; + } + #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) if (params->flags & TLS_CONN_EAP_FAST) { @@ -5009,7 +5091,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, } if (engine_id) { - wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); + wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine %s", + engine_id); ret = tls_engine_init(conn, engine_id, params->pin, key_id, cert_id, ca_cert_id); if (ret) diff --git a/src/drivers/driver.h b/src/drivers/driver.h index f0e2a6f2..032bbd89 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -182,6 +182,7 @@ struct hostapd_channel_data { struct hostapd_wmm_rule wmm_rules[WMM_AC_NUM]; }; +#define HE_MAC_CAPAB_0 0 #define HE_MAX_MAC_CAPAB_SIZE 6 #define HE_MAX_PHY_CAPAB_SIZE 11 #define HE_MAX_MCS_CAPAB_SIZE 12 @@ -1095,6 +1096,13 @@ struct wpa_driver_associate_params { const struct ieee80211_vht_capabilities *vhtcaps_mask; #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + /** + * disable_he - Disable HE for this connection + */ + int disable_he; +#endif /* CONFIG_HE_OVERRIDES */ + /** * req_key_mgmt_offload - Request key management offload for connection * @@ -1402,14 +1410,6 @@ struct wpa_driver_ap_params { u8 p2p_go_ctwindow; /** - * smps_mode - SMPS mode - * - * SMPS mode to be used by the AP, specified as the relevant bits of - * ht_capab (i.e. HT_CAP_INFO_SMPS_*). - */ - unsigned int smps_mode; - - /** * disable_dgaf - Whether group-addressed frames are disabled */ int disable_dgaf; @@ -1487,6 +1487,26 @@ struct wpa_driver_ap_params { * he_spr_srg_obss_pd_max_offset - Maximum TX power offset */ int he_spr_srg_obss_pd_max_offset; + + /** + * he_bss_color - Whether the BSS Color is disabled + */ + int he_bss_color_disabled; + + /** + * he_bss_color_partial - The BSS Color AID equation + */ + int he_bss_color_partial; + + /** + * he_bss_color - The BSS Color of the AP + */ + int he_bss_color; + + /** + * twt_responder - Whether Target Wait Time responder is enabled + */ + int twt_responder; }; struct wpa_driver_mesh_bss_params { @@ -1524,6 +1544,120 @@ struct wpa_driver_mesh_join_params { unsigned int flags; }; +struct wpa_driver_set_key_params { + /** + * ifname - Interface name (for multi-SSID/VLAN support) */ + const char *ifname; + + /** + * alg - Encryption algorithm + * + * (%WPA_ALG_NONE, %WPA_ALG_WEP, %WPA_ALG_TKIP, %WPA_ALG_CCMP, + * %WPA_ALG_IGTK, %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256, + * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, %WPA_ALG_BIP_CMAC_256); + * %WPA_ALG_NONE clears the key. */ + enum wpa_alg alg; + + /** + * addr - Address of the peer STA + * + * (BSSID of the current AP when setting pairwise key in station mode), + * ff:ff:ff:ff:ff:ff for broadcast keys, %NULL for default keys that + * are used both for broadcast and unicast; when clearing keys, %NULL + * is used to indicate that both the broadcast-only and default key of + * the specified key index is to be cleared */ + const u8 *addr; + + /** + * key_idx - Key index + * + * (0..3), usually 0 for unicast keys; 4..5 for IGTK; 6..7 for BIGTK */ + int key_idx; + + /** + * set_tx - Configure this key as the default Tx key + * + * Only used when driver does not support separate unicast/individual + * key */ + int set_tx; + + /** + * seq - Sequence number/packet number + * + * seq_len octets, the next packet number to be used for in replay + * protection; configured for Rx keys (in most cases, this is only used + * with broadcast keys and set to zero for unicast keys); %NULL if not + * set */ + const u8 *seq; + + /** + * seq_len - Length of the seq, depends on the algorithm + * + * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets */ + size_t seq_len; + + /** + * key - Key buffer + * + * TKIP: 16-byte temporal key, 8-byte Tx Mic key, 8-byte Rx Mic Key */ + const u8 *key; + + /** + * key_len - Length of the key buffer in octets + * + * WEP: 5 or 13, TKIP: 32, CCMP/GCMP: 16, IGTK: 16 */ + size_t key_len; + + /** + * vlan_id - VLAN index (0..4095) for VLAN offload cases */ + int vlan_id; + + /** + * key_flag - Additional key flags + * + * %KEY_FLAG_MODIFY + * Set when an already installed key must be updated. + * So far the only use-case is changing RX/TX status for + * pairwise keys. Must not be set when deleting a key. + * %KEY_FLAG_DEFAULT + * Set when the key is also a default key. Must not be set when + * deleting a key. + * %KEY_FLAG_RX + * The key is valid for RX. Must not be set when deleting a key. + * %KEY_FLAG_TX + * The key is valid for TX. Must not be set when deleting a key. + * %KEY_FLAG_GROUP + * The key is a broadcast or group key. + * %KEY_FLAG_PAIRWISE + * The key is a pairwise key. + * %KEY_FLAG_PMK + * The key is a Pairwise Master Key (PMK). + * + * Valid and pre-defined combinations are: + * %KEY_FLAG_GROUP_RX_TX + * WEP key not to be installed as default key. + * %KEY_FLAG_GROUP_RX_TX_DEFAULT + * Default WEP or WPA-NONE key. + * %KEY_FLAG_GROUP_RX + * GTK key valid for RX only. + * %KEY_FLAG_GROUP_TX_DEFAULT + * GTK key valid for TX only, immediately taking over TX. + * %KEY_FLAG_PAIRWISE_RX_TX + * Pairwise key immediately becoming the active pairwise key. + * %KEY_FLAG_PAIRWISE_RX + * Pairwise key not yet valid for TX. (Only usable when Extended + * Key ID is supported by the driver.) + * %KEY_FLAG_PAIRWISE_RX_TX_MODIFY + * Enable TX for a pairwise key installed with + * KEY_FLAG_PAIRWISE_RX. + * + * Not a valid standalone key type but pre-defined to be combined + * with other key_flags: + * %KEY_FLAG_RX_TX + * RX/TX key. */ + enum key_flag key_flag; +}; + /** * struct wpa_driver_capa - Driver capability information */ @@ -1577,7 +1711,7 @@ struct wpa_driver_capa { /** Driver takes care of all DFS operations */ #define WPA_DRIVER_FLAGS_DFS_OFFLOAD 0x00000004 /** Driver takes care of RSN 4-way handshake internally; PMK is configured with - * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */ + * struct wpa_driver_ops::set_key using key_flag = KEY_FLAG_PMK */ #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X 0x00000008 /** Driver is for a wired Ethernet interface */ #define WPA_DRIVER_FLAGS_WIRED 0x00000010 @@ -1704,15 +1838,23 @@ struct wpa_driver_capa { #define WPA_DRIVER_FLAGS_FTM_RESPONDER 0x0100000000000000ULL /** Driver support 4-way handshake offload for WPA-Personal */ #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK 0x0200000000000000ULL +/** Driver supports a separate control port for EAPOL frames */ +#define WPA_DRIVER_FLAGS_CONTROL_PORT 0x0400000000000000ULL +/** Driver supports VLAN offload */ +#define WPA_DRIVER_FLAGS_VLAN_OFFLOAD 0x0800000000000000ULL +/** Driver supports UPDATE_FT_IES command */ +#define WPA_DRIVER_FLAGS_UPDATE_FT_IES 0x1000000000000000ULL +/** Driver can correctly rekey PTKs without Extended Key ID */ +#define WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS 0x2000000000000000ULL +/** Driver supports Beacon protection */ +#define WPA_DRIVER_FLAGS_BEACON_PROTECTION 0x4000000000000000ULL +/** Driver supports Extended Key ID */ +#define WPA_DRIVER_FLAGS_EXTENDED_KEY_ID 0x8000000000000000ULL u64 flags; #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \ (drv_flags & WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE) -#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001 -#define WPA_DRIVER_SMPS_MODE_DYNAMIC 0x00000002 - unsigned int smps_modes; - unsigned int wmm_ac_supported:1; unsigned int mac_addr_rand_scan_supported:1; @@ -2194,6 +2336,9 @@ struct drv_acs_params { /* ACS frequency list info */ const int *freq_list; + + /* Indicates whether EDMG is enabled */ + int edmg_enabled; }; struct wpa_bss_trans_info { @@ -2219,6 +2364,8 @@ struct wpa_pmkid_params { const u8 *pmkid; const u8 *pmk; size_t pmk_len; + u32 pmk_lifetime; + u8 pmk_reauth_threshold; }; /* Mask used to specify which connection parameters have to be updated */ @@ -2305,35 +2452,8 @@ struct wpa_driver_ops { /** * set_key - Configure encryption key - * @ifname: Interface name (for multi-SSID/VLAN support) * @priv: private driver interface data - * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, - * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK, - * %WPA_ALG_GCMP, %WPA_ALG_GCMP_256, %WPA_ALG_CCMP_256, - * %WPA_ALG_BIP_GMAC_128, %WPA_ALG_BIP_GMAC_256, - * %WPA_ALG_BIP_CMAC_256); - * %WPA_ALG_NONE clears the key. - * @addr: Address of the peer STA (BSSID of the current AP when setting - * pairwise key in station mode), ff:ff:ff:ff:ff:ff for - * broadcast keys, %NULL for default keys that are used both for - * broadcast and unicast; when clearing keys, %NULL is used to - * indicate that both the broadcast-only and default key of the - * specified key index is to be cleared - * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for - * IGTK - * @set_tx: configure this key as the default Tx key (only used when - * driver does not support separate unicast/individual key - * @seq: sequence number/packet number, seq_len octets, the next - * packet number to be used for in replay protection; configured - * for Rx keys (in most cases, this is only used with broadcast - * keys and set to zero for unicast keys); %NULL if not set - * @seq_len: length of the seq, depends on the algorithm: - * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets - * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, - * 8-byte Rx Mic Key - * @key_len: length of the key buffer in octets (WEP: 5 or 13, - * TKIP: 32, CCMP/GCMP: 16, IGTK: 16) - * + * @params: Key parameters * Returns: 0 on success, -1 on failure * * Configure the given key for the kernel driver. If the driver @@ -2354,10 +2474,7 @@ struct wpa_driver_ops { * in driver_*.c set_key() implementation, see driver_ndis.c for an * example on how this can be done. */ - int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg, - const u8 *addr, int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len); + int (*set_key)(void *priv, struct wpa_driver_set_key_params *params); /** * init - Initialize driver interface @@ -2609,11 +2726,15 @@ struct wpa_driver_ops { * driver decide * @csa_offs: Array of CSA offsets or %NULL * @csa_offs_len: Number of elements in csa_offs + * @no_encrypt: Do not encrypt frame even if appropriate key exists + * (used only for testing purposes) + * @wait: Time to wait off-channel for a response (in ms), or zero * Returns: 0 on success, -1 on failure */ int (*send_mlme)(void *priv, const u8 *data, size_t data_len, int noack, unsigned int freq, const u16 *csa_offs, - size_t csa_offs_len); + size_t csa_offs_len, int no_encrypt, + unsigned int wait); /** * update_ft_ies - Update FT (IEEE 802.11r) IEs @@ -2868,6 +2989,33 @@ struct wpa_driver_ops { const u8 *addr); /** + * tx_control_port - Send a frame over the 802.1X controlled port + * @priv: Private driver interface data + * @dest: Destination MAC address + * @proto: Ethertype in host byte order + * @buf: Frame payload starting from IEEE 802.1X header + * @len: Frame payload length + * @no_encrypt: Do not encrypt frame + * + * Returns 0 on success, else an error + * + * This is like a normal Ethernet send except that the driver is aware + * (by other means than the Ethertype) that this frame is special, + * and more importantly it gains an ordering between the transmission of + * the frame and other driver management operations such as key + * installations. This can be used to work around known limitations in + * IEEE 802.11 protocols such as race conditions between rekeying 4-way + * handshake message 4/4 and a PTK being overwritten. + * + * This function is only used for a given interface if the driver + * instance reports WPA_DRIVER_FLAGS_CONTROL_PORT capability. Otherwise, + * API users will fall back to sending the frame via a normal socket. + */ + int (*tx_control_port)(void *priv, const u8 *dest, + u16 proto, const u8 *buf, size_t len, + int no_encrypt); + + /** * hapd_send_eapol - Send an EAPOL packet (AP only) * @priv: private driver interface data * @addr: Destination MAC address @@ -3113,19 +3261,6 @@ struct wpa_driver_ops { int (*commit)(void *priv); /** - * send_ether - Send an ethernet packet (AP only) - * @priv: private driver interface data - * @dst: Destination MAC address - * @src: Source MAC address - * @proto: Ethertype - * @data: EAPOL packet starting with IEEE 802.1X header - * @data_len: Length of the EAPOL packet in octets - * Returns: 0 on success, -1 on failure - */ - int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto, - const u8 *data, size_t data_len); - - /** * set_radius_acl_auth - Notification of RADIUS ACL change * @priv: Private driver interface data * @mac: MAC address of the station @@ -3348,20 +3483,6 @@ struct wpa_driver_ops { int (*signal_monitor)(void *priv, int threshold, int hysteresis); /** - * send_frame - Send IEEE 802.11 frame (testing use only) - * @priv: Private driver interface data - * @data: IEEE 802.11 frame with IEEE 802.11 header - * @data_len: Size of the frame - * @encrypt: Whether to encrypt the frame (if keys are set) - * Returns: 0 on success, -1 on failure - * - * This function is only used for debugging purposes and is not - * required to be implemented for normal operations. - */ - int (*send_frame)(void *priv, const u8 *data, size_t data_len, - int encrypt); - - /** * get_noa - Get current Notice of Absence attribute payload * @priv: Private driver interface data * @buf: Buffer for returning NoA @@ -3513,6 +3634,12 @@ struct wpa_driver_ops { unsigned int val); /** + * get_wowlan - Get wake-on-wireless status + * @priv: Private driver interface data + */ + int (*get_wowlan)(void *priv); + + /** * set_wowlan - Set wake-on-wireless triggers * @priv: Private driver interface data * @triggers: wowlan triggers @@ -4843,6 +4970,15 @@ enum wpa_event_type { * EVENT_UPDATE_DH - Notification of updated DH information */ EVENT_UPDATE_DH, + + /** + * EVENT_UNPROT_BEACON - Unprotected Beacon frame received + * + * This event should be called when a Beacon frame is dropped due to it + * not being protected correctly. union wpa_event_data::unprot_beacon + * is required to provide more details of the frame. + */ + EVENT_UNPROT_BEACON, }; @@ -5609,8 +5745,17 @@ union wpa_event_data { * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED * @pri_freq: Selected primary frequency * @sec_freq: Selected secondary frequency + * @edmg_channel: Selected EDMG channel * @vht_seg0_center_ch: VHT mode Segment0 center channel + * The value is the index of the channel center frequency for + * 20 MHz, 40 MHz, and 80 MHz channels. The value is the center + * frequency index of the primary 80 MHz segment for 160 MHz and + * 80+80 MHz channels. * @vht_seg1_center_ch: VHT mode Segment1 center channel + * The value is zero for 20 MHz, 40 MHz, and 80 MHz channels. The + * value is the index of the channel center frequency for 160 MHz + * channels and the center frequency index of the secondary 80 MHz + * segment for 80+80 MHz channels. * @ch_width: Selected Channel width by driver. Driver may choose to * change hostapd configured ACS channel width due driver internal * channel restrictions. @@ -5619,6 +5764,7 @@ union wpa_event_data { struct acs_selected_channels { unsigned int pri_freq; unsigned int sec_freq; + u8 edmg_channel; u8 vht_seg0_center_ch; u8 vht_seg1_center_ch; u16 ch_width; @@ -5685,6 +5831,13 @@ union wpa_event_data { const u8 *ie; size_t ie_len; } update_dh; + + /** + * struct unprot_beacon - Data for EVENT_UNPROT_BEACON + */ + struct unprot_beacon { + const u8 *sa; + } unprot_beacon; }; /** diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index eac3ae8a..d630c3dc 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -492,14 +492,18 @@ atheros_del_key(void *priv, const u8 *addr, int key_idx) } static int -atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const u8 *addr, int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, size_t key_len) +atheros_set_key(void *priv, struct wpa_driver_set_key_params *params) { struct atheros_driver_data *drv = priv; struct ieee80211req_key wk; u_int8_t cipher; int ret; + enum wpa_alg alg = params->alg; + const u8 *addr = params->addr; + int key_idx = params->key_idx; + int set_tx = params->set_tx; + const u8 *key = params->key; + size_t key_len = params->key_len; if (alg == WPA_ALG_NONE) return atheros_del_key(drv, addr, key_idx); @@ -1960,7 +1964,8 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params) static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len, int noack, unsigned int freq, - const u16 *csa_offs, size_t csa_offs_len) + const u16 *csa_offs, size_t csa_offs_len, + int no_encrypt, unsigned int wait) { struct atheros_driver_data *drv = priv; u8 buf[1510]; diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c index 8667ee51..b4400d7b 100644 --- a/src/drivers/driver_bsd.c +++ b/src/drivers/driver_bsd.c @@ -9,7 +9,6 @@ #include "includes.h" #include <sys/ioctl.h> -#include <sys/sysctl.h> #include "common.h" #include "driver.h" @@ -51,22 +50,19 @@ struct bsd_driver_global { void *ctx; int sock; /* socket for 802.11 ioctls */ int route; /* routing socket for events */ - char *event_buf; - size_t event_buf_len; struct dl_list ifaces; /* list of interfaces */ }; struct bsd_driver_data { struct dl_list list; struct bsd_driver_global *global; - struct hostapd_data *hapd; /* back pointer */ + void *ctx; struct l2_packet_data *sock_xmit;/* raw packet xmit socket */ char ifname[IFNAMSIZ+1]; /* interface name */ int flags; unsigned int ifindex; /* interface index */ int if_removed; /* has the interface been removed? */ - void *ctx; struct wpa_driver_capa capa; /* driver capability */ int is_ap; /* Access point mode */ int prev_roaming; /* roaming state to restore on deinit */ @@ -90,7 +86,6 @@ bsd_get_drvindex(void *priv, unsigned int ifindex) return NULL; } -#ifndef HOSTAPD static struct bsd_driver_data * bsd_get_drvname(void *priv, const char *ifname) { @@ -103,7 +98,6 @@ bsd_get_drvname(void *priv, const char *ifname) } return NULL; } -#endif /* HOSTAPD */ static int bsd_set80211(void *priv, int op, int val, const void *arg, int arg_len) @@ -295,9 +289,8 @@ bsd_send_mlme_param(void *priv, const u8 op, const u16 reason, const u8 *addr) } static int -bsd_ctrl_iface(void *priv, int enable) +bsd_get_iface_flags(struct bsd_driver_data *drv) { - struct bsd_driver_data *drv = priv; struct ifreq ifr; os_memset(&ifr, 0, sizeof(ifr)); @@ -309,36 +302,24 @@ bsd_ctrl_iface(void *priv, int enable) return -1; } drv->flags = ifr.ifr_flags; - - if (enable) { - if (ifr.ifr_flags & IFF_UP) - return 0; - ifr.ifr_flags |= IFF_UP; - } else { - if (!(ifr.ifr_flags & IFF_UP)) - return 0; - ifr.ifr_flags &= ~IFF_UP; - } - - if (ioctl(drv->global->sock, SIOCSIFFLAGS, &ifr) < 0) { - wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s", - strerror(errno)); - return -1; - } - - drv->flags = ifr.ifr_flags; return 0; } static int -bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, size_t key_len) +bsd_set_key(void *priv, struct wpa_driver_set_key_params *params) { struct ieee80211req_key wk; #ifdef IEEE80211_KEY_NOREPLAY struct bsd_driver_data *drv = priv; #endif /* IEEE80211_KEY_NOREPLAY */ + enum wpa_alg alg = params->alg; + const u8 *addr = params->addr; + int key_idx = params->key_idx; + int set_tx = params->set_tx; + const u8 *seq = params->seq; + size_t seq_len = params->seq_len; + const u8 *key = params->key; + size_t key_len = params->key_len; wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d " "seq_len=%zu key_len=%zu", __func__, alg, addr, key_idx, @@ -540,7 +521,7 @@ bsd_set_ieee8021x(void *priv, struct wpa_bss_params *params) __func__); return -1; } - return bsd_ctrl_iface(priv, 1); + return 0; } static void @@ -595,17 +576,13 @@ bsd_set_freq(void *priv, struct hostapd_freq_params *freq) if (channel < 14) { mode = -#ifdef CONFIG_IEEE80211N freq->ht_enabled ? IFM_IEEE80211_11NG : -#endif /* CONFIG_IEEE80211N */ - IFM_IEEE80211_11G; + IFM_IEEE80211_11G; } else if (channel == 14) { mode = IFM_IEEE80211_11B; } else { mode = -#ifdef CONFIG_IEEE80211N freq->ht_enabled ? IFM_IEEE80211_11NA : -#endif /* CONFIG_IEEE80211N */ IFM_IEEE80211_11A; } if (bsd_set_mediaopt(drv, IFM_MMASK, mode) < 0) { @@ -636,20 +613,152 @@ bsd_set_opt_ie(void *priv, const u8 *ie, size_t ie_len) return 0; } -static size_t -rtbuf_len(void) +static void +bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) { - size_t len; - - int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0}; + char event_buf[2048]; /* max size of a single route(4) msg */ + struct bsd_driver_global *global = sock_ctx; + struct bsd_driver_data *drv; + struct if_announcemsghdr *ifan; + struct if_msghdr *ifm; + struct rt_msghdr *rtm; + union wpa_event_data event; + struct ieee80211_michael_event *mic; + struct ieee80211_leave_event *leave; + struct ieee80211_join_event *join; + int n; - if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { - wpa_printf(MSG_WARNING, "%s failed: %s", __func__, - strerror(errno)); - len = 2048; + n = read(sock, event_buf, sizeof(event_buf)); + if (n < 0) { + if (errno != EINTR && errno != EAGAIN) + wpa_printf(MSG_ERROR, "%s read() failed: %s", + __func__, strerror(errno)); + return; } - return len; + rtm = (struct rt_msghdr *) event_buf; + if (rtm->rtm_version != RTM_VERSION) { + wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", + rtm->rtm_version); + return; + } + os_memset(&event, 0, sizeof(event)); + switch (rtm->rtm_type) { + case RTM_IEEE80211: + ifan = (struct if_announcemsghdr *) rtm; + drv = bsd_get_drvindex(global, ifan->ifan_index); + if (drv == NULL) + return; + switch (ifan->ifan_what) { + case RTM_IEEE80211_ASSOC: + case RTM_IEEE80211_REASSOC: + if (drv->is_ap) + break; + wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); + break; + case RTM_IEEE80211_DISASSOC: + if (drv->is_ap) + break; + wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); + break; + case RTM_IEEE80211_SCAN: + if (drv->is_ap) + break; + wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, + NULL); + break; + case RTM_IEEE80211_LEAVE: + leave = (struct ieee80211_leave_event *) &ifan[1]; + drv_event_disassoc(drv->ctx, leave->iev_addr); + break; + case RTM_IEEE80211_JOIN: +#ifdef RTM_IEEE80211_REJOIN + case RTM_IEEE80211_REJOIN: +#endif + join = (struct ieee80211_join_event *) &ifan[1]; + bsd_new_sta(drv, drv->ctx, join->iev_addr); + break; + case RTM_IEEE80211_REPLAY: + /* ignore */ + break; + case RTM_IEEE80211_MICHAEL: + mic = (struct ieee80211_michael_event *) &ifan[1]; + wpa_printf(MSG_DEBUG, + "Michael MIC failure wireless event: " + "keyix=%u src_addr=" MACSTR, mic->iev_keyix, + MAC2STR(mic->iev_src)); + os_memset(&event, 0, sizeof(event)); + event.michael_mic_failure.unicast = + !IEEE80211_IS_MULTICAST(mic->iev_dst); + event.michael_mic_failure.src = mic->iev_src; + wpa_supplicant_event(drv->ctx, + EVENT_MICHAEL_MIC_FAILURE, &event); + break; + } + break; + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *) rtm; + switch (ifan->ifan_what) { + case IFAN_DEPARTURE: + drv = bsd_get_drvindex(global, ifan->ifan_index); + if (drv) + drv->if_removed = 1; + event.interface_status.ievent = EVENT_INTERFACE_REMOVED; + break; + case IFAN_ARRIVAL: + drv = bsd_get_drvname(global, ifan->ifan_name); + if (drv) { + drv->ifindex = ifan->ifan_index; + drv->if_removed = 0; + } + event.interface_status.ievent = EVENT_INTERFACE_ADDED; + break; + default: + wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action"); + return; + } + wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", + ifan->ifan_name, + ifan->ifan_what == IFAN_DEPARTURE ? + "removed" : "added"); + os_strlcpy(event.interface_status.ifname, ifan->ifan_name, + sizeof(event.interface_status.ifname)); + if (drv) { + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, + &event); + /* + * Set ifindex to zero after sending the event as the + * event might query the driver to ensure a match. + */ + if (ifan->ifan_what == IFAN_DEPARTURE) + drv->ifindex = 0; + } else { + wpa_supplicant_event_global(global->ctx, + EVENT_INTERFACE_STATUS, + &event); + } + break; + case RTM_IFINFO: + ifm = (struct if_msghdr *) rtm; + drv = bsd_get_drvindex(global, ifm->ifm_index); + if (drv == NULL) + return; + if ((ifm->ifm_flags & IFF_UP) == 0 && + (drv->flags & IFF_UP) != 0) { + wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, + NULL); + } else if ((ifm->ifm_flags & IFF_UP) != 0 && + (drv->flags & IFF_UP) == 0) { + wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", + drv->ifname); + wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, + NULL); + } + drv->flags = ifm->ifm_flags; + break; + } } #ifdef HOSTAPD @@ -770,80 +879,10 @@ bsd_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, } static void -bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx) -{ - struct bsd_driver_global *global = sock_ctx; - struct bsd_driver_data *drv; - struct if_announcemsghdr *ifan; - struct rt_msghdr *rtm; - struct ieee80211_michael_event *mic; - struct ieee80211_join_event *join; - struct ieee80211_leave_event *leave; - int n; - union wpa_event_data data; - - n = read(sock, global->event_buf, global->event_buf_len); - if (n < 0) { - if (errno != EINTR && errno != EAGAIN) - wpa_printf(MSG_ERROR, "%s read() failed: %s", - __func__, strerror(errno)); - return; - } - - rtm = (struct rt_msghdr *) global->event_buf; - if (rtm->rtm_version != RTM_VERSION) { - wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", - rtm->rtm_version); - return; - } - switch (rtm->rtm_type) { - case RTM_IEEE80211: - ifan = (struct if_announcemsghdr *) rtm; - drv = bsd_get_drvindex(global, ifan->ifan_index); - if (drv == NULL) - return; - switch (ifan->ifan_what) { - case RTM_IEEE80211_ASSOC: - case RTM_IEEE80211_REASSOC: - case RTM_IEEE80211_DISASSOC: - case RTM_IEEE80211_SCAN: - break; - case RTM_IEEE80211_LEAVE: - leave = (struct ieee80211_leave_event *) &ifan[1]; - drv_event_disassoc(drv->hapd, leave->iev_addr); - break; - case RTM_IEEE80211_JOIN: -#ifdef RTM_IEEE80211_REJOIN - case RTM_IEEE80211_REJOIN: -#endif - join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, drv->hapd, join->iev_addr); - break; - case RTM_IEEE80211_REPLAY: - /* ignore */ - break; - case RTM_IEEE80211_MICHAEL: - mic = (struct ieee80211_michael_event *) &ifan[1]; - wpa_printf(MSG_DEBUG, - "Michael MIC failure wireless event: " - "keyix=%u src_addr=" MACSTR, mic->iev_keyix, - MAC2STR(mic->iev_src)); - os_memset(&data, 0, sizeof(data)); - data.michael_mic_failure.unicast = 1; - data.michael_mic_failure.src = mic->iev_src; - wpa_supplicant_event(drv->hapd, - EVENT_MICHAEL_MIC_FAILURE, &data); - break; - } - break; - } -} - -static void handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { struct bsd_driver_data *drv = ctx; - drv_event_eapol_rx(drv->hapd, src_addr, buf, len); + drv_event_eapol_rx(drv->ctx, src_addr, buf, len); } static void * @@ -864,7 +903,8 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) goto bad; } - drv->hapd = hapd; + drv->ctx = hapd; + drv->is_ap = 1; drv->global = params->global_priv; os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname)); @@ -875,8 +915,7 @@ bsd_init(struct hostapd_data *hapd, struct wpa_init_params *params) if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr)) goto bad; - /* mark down during setup */ - if (bsd_ctrl_iface(drv, 0) < 0) + if (bsd_get_iface_flags(drv) < 0) goto bad; if (bsd_set_mediaopt(drv, IFM_OMASK, IFM_IEEE80211_HOSTAP) < 0) { @@ -901,8 +940,6 @@ bsd_deinit(void *priv) { struct bsd_driver_data *drv = priv; - if (drv->ifindex != 0) - bsd_ctrl_iface(drv, 0); if (drv->sock_xmit != NULL) l2_packet_deinit(drv->sock_xmit); os_free(drv); @@ -910,13 +947,6 @@ bsd_deinit(void *priv) static int -bsd_commit(void *priv) -{ - return bsd_ctrl_iface(priv, 1); -} - - -static int bsd_set_sta_authorized(void *priv, const u8 *addr, unsigned int total_flags, unsigned int flags_or, unsigned int flags_and) @@ -1169,8 +1199,11 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) } /* NB: interface must be marked UP to do a scan */ - if (bsd_ctrl_iface(drv, 1) < 0) + if (!(drv->flags & IFF_UP)) { + wpa_printf(MSG_DEBUG, "%s: interface is not up, cannot scan", + __func__); return -1; + } #ifdef IEEE80211_IOC_SCAN_MAX_SSID os_memset(&sr, 0, sizeof(sr)); @@ -1208,153 +1241,6 @@ wpa_driver_bsd_scan(void *priv, struct wpa_driver_scan_params *params) } static void -wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx) -{ - struct bsd_driver_global *global = sock_ctx; - struct bsd_driver_data *drv; - struct if_announcemsghdr *ifan; - struct if_msghdr *ifm; - struct rt_msghdr *rtm; - union wpa_event_data event; - struct ieee80211_michael_event *mic; - struct ieee80211_leave_event *leave; - struct ieee80211_join_event *join; - int n; - - n = read(sock, global->event_buf, global->event_buf_len); - if (n < 0) { - if (errno != EINTR && errno != EAGAIN) - wpa_printf(MSG_ERROR, "%s read() failed: %s", - __func__, strerror(errno)); - return; - } - - rtm = (struct rt_msghdr *) global->event_buf; - if (rtm->rtm_version != RTM_VERSION) { - wpa_printf(MSG_DEBUG, "Invalid routing message version=%d", - rtm->rtm_version); - return; - } - os_memset(&event, 0, sizeof(event)); - switch (rtm->rtm_type) { - case RTM_IFANNOUNCE: - ifan = (struct if_announcemsghdr *) rtm; - switch (ifan->ifan_what) { - case IFAN_DEPARTURE: - drv = bsd_get_drvindex(global, ifan->ifan_index); - if (drv) - drv->if_removed = 1; - event.interface_status.ievent = EVENT_INTERFACE_REMOVED; - break; - case IFAN_ARRIVAL: - drv = bsd_get_drvname(global, ifan->ifan_name); - if (drv) { - drv->ifindex = ifan->ifan_index; - drv->if_removed = 0; - } - event.interface_status.ievent = EVENT_INTERFACE_ADDED; - break; - default: - wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: unknown action"); - return; - } - wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s", - ifan->ifan_name, - ifan->ifan_what == IFAN_DEPARTURE ? - "removed" : "added"); - os_strlcpy(event.interface_status.ifname, ifan->ifan_name, - sizeof(event.interface_status.ifname)); - if (drv) { - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, - &event); - /* - * Set ifindex to zero after sending the event as the - * event might query the driver to ensure a match. - */ - if (ifan->ifan_what == IFAN_DEPARTURE) - drv->ifindex = 0; - } else { - wpa_supplicant_event_global(global->ctx, - EVENT_INTERFACE_STATUS, - &event); - } - break; - case RTM_IEEE80211: - ifan = (struct if_announcemsghdr *) rtm; - drv = bsd_get_drvindex(global, ifan->ifan_index); - if (drv == NULL) - return; - switch (ifan->ifan_what) { - case RTM_IEEE80211_ASSOC: - case RTM_IEEE80211_REASSOC: - if (drv->is_ap) - break; - wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); - break; - case RTM_IEEE80211_DISASSOC: - if (drv->is_ap) - break; - wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); - break; - case RTM_IEEE80211_SCAN: - if (drv->is_ap) - break; - wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, - NULL); - break; - case RTM_IEEE80211_LEAVE: - leave = (struct ieee80211_leave_event *) &ifan[1]; - drv_event_disassoc(drv->ctx, leave->iev_addr); - break; - case RTM_IEEE80211_JOIN: -#ifdef RTM_IEEE80211_REJOIN - case RTM_IEEE80211_REJOIN: -#endif - join = (struct ieee80211_join_event *) &ifan[1]; - bsd_new_sta(drv, drv->ctx, join->iev_addr); - break; - case RTM_IEEE80211_REPLAY: - /* ignore */ - break; - case RTM_IEEE80211_MICHAEL: - mic = (struct ieee80211_michael_event *) &ifan[1]; - wpa_printf(MSG_DEBUG, - "Michael MIC failure wireless event: " - "keyix=%u src_addr=" MACSTR, mic->iev_keyix, - MAC2STR(mic->iev_src)); - - os_memset(&event, 0, sizeof(event)); - event.michael_mic_failure.unicast = - !IEEE80211_IS_MULTICAST(mic->iev_dst); - wpa_supplicant_event(drv->ctx, - EVENT_MICHAEL_MIC_FAILURE, &event); - break; - } - break; - case RTM_IFINFO: - ifm = (struct if_msghdr *) rtm; - drv = bsd_get_drvindex(global, ifm->ifm_index); - if (drv == NULL) - return; - if ((ifm->ifm_flags & IFF_UP) == 0 && - (drv->flags & IFF_UP) != 0) { - wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN", - drv->ifname); - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, - NULL); - } else if ((ifm->ifm_flags & IFF_UP) != 0 && - (drv->flags & IFF_UP) == 0) { - wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP", - drv->ifname); - wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, - NULL); - } - drv->flags = ifm->ifm_flags; - break; - } -} - -static void wpa_driver_bsd_add_scan_entry(struct wpa_scan_results *res, struct ieee80211req_scan_result *sr) { @@ -1570,12 +1456,6 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) if (drv == NULL) return NULL; - /* - * NB: We require the interface name be mappable to an index. - * This implies we do not support having wpa_supplicant - * wait for an interface to appear. This seems ok; that - * doesn't belong here; it's really the job of devd. - */ drv->ifindex = if_nametoindex(ifname); if (drv->ifindex == 0) { wpa_printf(MSG_DEBUG, "%s: interface %s does not exist", @@ -1607,7 +1487,7 @@ wpa_driver_bsd_init(void *ctx, const char *ifname, void *priv) goto fail; /* Down interface during setup. */ - if (bsd_ctrl_iface(drv, 0) < 0) + if (bsd_get_iface_flags(drv) < 0) goto fail; drv->opmode = get80211opmode(drv); @@ -1628,9 +1508,6 @@ wpa_driver_bsd_deinit(void *priv) if (drv->ifindex != 0 && !drv->if_removed) { wpa_driver_bsd_set_wpa(drv, 0); - /* NB: mark interface down */ - bsd_ctrl_iface(drv, 0); - wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy); @@ -1664,9 +1541,7 @@ bsd_global_init(void *ctx) #if defined(RO_MSGFILTER) || defined(ROUTE_MSGFILTER) unsigned char msgfilter[] = { RTM_IEEE80211, -#ifndef HOSTAPD RTM_IFINFO, RTM_IFANNOUNCE, -#endif }; #endif #ifdef ROUTE_MSGFILTER @@ -1709,22 +1584,9 @@ bsd_global_init(void *ctx) strerror(errno)); #endif - global->event_buf_len = rtbuf_len(); - global->event_buf = os_malloc(global->event_buf_len); - if (global->event_buf == NULL) { - wpa_printf(MSG_ERROR, "%s: os_malloc() failed", __func__); - goto fail; - } - -#ifdef HOSTAPD eloop_register_read_sock(global->route, bsd_wireless_event_receive, NULL, global); -#else /* HOSTAPD */ - eloop_register_read_sock(global->route, wpa_driver_bsd_event_receive, - NULL, global); -#endif /* HOSTAPD */ - return global; fail: @@ -1761,7 +1623,6 @@ const struct wpa_driver_ops wpa_driver_bsd_ops = { .sta_disassoc = bsd_sta_disassoc, .sta_deauth = bsd_sta_deauth, .sta_set_flags = bsd_set_sta_authorized, - .commit = bsd_commit, #else /* HOSTAPD */ .init2 = wpa_driver_bsd_init, .deinit = wpa_driver_bsd_deinit, diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 731c6a3b..63846db2 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -89,6 +89,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(INTERFACE_MAC_CHANGED); E2S(WDS_STA_INTERFACE_STATUS); E2S(UPDATE_DH); + E2S(UNPROT_BEACON); } return "UNKNOWN"; @@ -308,6 +309,14 @@ const char * driver_flag_to_string(u64 flag) DF2S(OCE_AP); DF2S(OCE_STA_CFON); DF2S(MFP_OPTIONAL); + DF2S(SELF_MANAGED_REGULATORY); + DF2S(FTM_RESPONDER); + DF2S(CONTROL_PORT); + DF2S(VLAN_OFFLOAD); + DF2S(UPDATE_FT_IES); + DF2S(SAFE_PTK0_REKEYS); + DF2S(BEACON_PROTECTION); + DF2S(EXTENDED_KEY_ID); } return "UNKNOWN"; #undef DF2S diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c index 186eccbf..b9c42e4d 100644 --- a/src/drivers/driver_hostap.c +++ b/src/drivers/driver_hostap.c @@ -263,7 +263,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr) static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack, unsigned int freq, - const u16 *csa_offs, size_t csa_offs_len) + const u16 *csa_offs, size_t csa_offs_len, + int no_encrypt, unsigned int wait) { struct hostap_driver_data *drv = priv; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg; @@ -312,7 +313,7 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data, pos += 2; memcpy(pos, data, data_len); - res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0); + res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0, NULL, 0, 0, 0); if (res < 0) { wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - " "failed: %d (%s)", @@ -395,17 +396,20 @@ static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param, } -static int wpa_driver_hostap_set_key(const char *ifname, void *priv, - enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) +static int wpa_driver_hostap_set_key(void *priv, + struct wpa_driver_set_key_params *params) { struct hostap_driver_data *drv = priv; struct prism2_hostapd_param *param; u8 *buf; size_t blen; int ret = 0; + enum wpa_alg alg = params->alg; + const u8 *addr = params->addr; + int key_idx = params->key_idx; + int set_tx = params->set_tx; + const u8 *key = params->key; + size_t key_len = params->key_len; blen = sizeof(*param) + key_len; buf = os_zalloc(blen); @@ -1051,7 +1055,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.deauth.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.deauth), 0, 0, NULL, 0); + sizeof(mgmt.u.deauth), 0, 0, NULL, 0, 0, 0); } @@ -1089,7 +1093,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, memcpy(mgmt.bssid, own_addr, ETH_ALEN); mgmt.u.disassoc.reason_code = host_to_le16(reason); return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN + - sizeof(mgmt.u.disassoc), 0, 0, NULL, 0); + sizeof(mgmt.u.disassoc), 0, 0, NULL, 0, 0, 0); } @@ -1169,7 +1173,7 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr, os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN); os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); - hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0); + hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0, NULL, 0, 0, 0); } diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c index e922503f..5319ba2d 100644 --- a/src/drivers/driver_macsec_linux.c +++ b/src/drivers/driver_macsec_linux.c @@ -54,8 +54,6 @@ struct macsec_drv_data { struct nl_sock *sk; struct macsec_genl_ctx ctx; - struct netlink_data *netlink; - struct nl_handle *nl; char ifname[IFNAMSIZ + 1]; int ifi; int parent_ifi; @@ -321,14 +319,14 @@ static int macsec_drv_macsec_init(void *priv, struct macsec_init_params *params) if (err < 0) { wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to connect NETLINK_ROUTE socket: %s", - strerror(errno)); + nl_geterror(err)); goto sock; } err = rtnl_link_alloc_cache(drv->sk, AF_UNSPEC, &drv->link_cache); if (err < 0) { wpa_printf(MSG_ERROR, DRV_PREFIX "Unable to get link cache: %s", - strerror(errno)); + nl_geterror(err)); goto sock; } diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c index 5b4b9247..529fc3bc 100644 --- a/src/drivers/driver_ndis.c +++ b/src/drivers/driver_ndis.c @@ -1034,6 +1034,18 @@ static int wpa_driver_ndis_set_key(const char *ifname, void *priv, static int +wpa_driver_ndis_set_key_wrapper(void *priv, + struct wpa_driver_set_key_params *params) +{ + return wpa_driver_ndis_set_key(params->ifname, priv, + params->alg, params->addr, + params->key_idx, params->set_tx, + params->seq, params->seq_len, + params->key, params->key_len); +} + + +static int wpa_driver_ndis_associate(void *priv, struct wpa_driver_associate_params *params) { @@ -3195,7 +3207,7 @@ void driver_ndis_init_ops(void) wpa_driver_ndis_ops.desc = ndis_drv_desc; wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid; wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid; - wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key; + wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key_wrapper; wpa_driver_ndis_ops.init = wpa_driver_ndis_init; wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit; wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index b7efb6a3..3b7c31c8 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -66,48 +66,6 @@ enum nlmsgerr_attrs { #define SOL_NETLINK 270 #endif -#ifndef CONFIG_LIBNL20 -/* - * libnl 1.1 has a bug, it tries to allocate socket numbers densely - * but when you free a socket again it will mess up its bitmap and - * and use the wrong number the next time it needs a socket ID. - * Therefore, we wrap the handle alloc/destroy and add our own pid - * accounting. - */ -static uint32_t port_bitmap[32] = { 0 }; - -static struct nl_handle *nl80211_handle_alloc(void *cb) -{ - struct nl_handle *handle; - uint32_t pid = getpid() & 0x3FFFFF; - int i; - - handle = nl_handle_alloc_cb(cb); - - for (i = 0; i < 1024; i++) { - if (port_bitmap[i / 32] & (1 << (i % 32))) - continue; - port_bitmap[i / 32] |= 1 << (i % 32); - pid += i << 22; - break; - } - - nl_socket_set_local_port(handle, pid); - - return handle; -} - -static void nl80211_handle_destroy(struct nl_handle *handle) -{ - uint32_t port = nl_socket_get_local_port(handle); - - port >>= 22; - port_bitmap[port / 32] &= ~(1 << (port % 32)); - - nl_handle_destroy(handle); -} -#endif /* CONFIG_LIBNL20 */ - #ifdef ANDROID /* system/core/libnl_2 does not include nl_socket_set_nonblocking() */ @@ -117,11 +75,11 @@ static void nl80211_handle_destroy(struct nl_handle *handle) #endif /* ANDROID */ -static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg) +static struct nl_sock * nl_create_handle(struct nl_cb *cb, const char *dbg) { - struct nl_handle *handle; + struct nl_sock *handle; - handle = nl80211_handle_alloc(cb); + handle = nl_socket_alloc_cb(cb); if (handle == NULL) { wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink " "callbacks (%s)", dbg); @@ -131,7 +89,7 @@ static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg) if (genl_connect(handle)) { wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic " "netlink (%s)", dbg); - nl80211_handle_destroy(handle); + nl_socket_free(handle); return NULL; } @@ -139,11 +97,11 @@ static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg) } -static void nl_destroy_handles(struct nl_handle **handle) +static void nl_destroy_handles(struct nl_sock **handle) { if (*handle == NULL) return; - nl80211_handle_destroy(*handle); + nl_socket_free(*handle); *handle = NULL; } @@ -154,11 +112,10 @@ static void nl_destroy_handles(struct nl_handle **handle) #define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL #endif -static void nl80211_register_eloop_read(struct nl_handle **handle, +static void nl80211_register_eloop_read(struct nl_sock **handle, eloop_sock_handler handler, void *eloop_data, int persist) { -#ifdef CONFIG_LIBNL20 /* * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB) * by default. It is possible to hit that limit in some cases where @@ -166,13 +123,15 @@ static void nl80211_register_eloop_read(struct nl_handle **handle, * to hostapd and STA entry deletion. Try to increase the buffer to make * this less likely to occur. */ - if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) { + int err; + + err = nl_socket_set_buffer_size(*handle, 262144, 0); + if (err < 0) { wpa_printf(MSG_DEBUG, "nl80211: Could not set nl_socket RX buffer size: %s", - strerror(errno)); + nl_geterror(err)); /* continue anyway with the default (smaller) buffer */ } -#endif /* CONFIG_LIBNL20 */ nl_socket_set_nonblocking(*handle); eloop_register_read_sock(nl_socket_get_fd(*handle), handler, @@ -183,7 +142,7 @@ static void nl80211_register_eloop_read(struct nl_handle **handle, } -static void nl80211_destroy_eloop_handle(struct nl_handle **handle, int persist) +static void nl80211_destroy_eloop_handle(struct nl_sock **handle, int persist) { if (!persist) *handle = (void *) (((intptr_t) *handle) ^ @@ -206,7 +165,8 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, const char *driver_params); static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, - const u8 *buf, size_t buf_len, u64 *cookie, + const u8 *buf, size_t buf_len, + int save_cookie, int no_cck, int no_ack, int offchanok, const u16 *csa_offs, size_t csa_offs_len); static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, @@ -391,7 +351,7 @@ static void nl80211_nlmsg_clear(struct nl_msg *msg) static int send_and_recv(struct nl80211_global *global, - struct nl_handle *nl_handle, struct nl_msg *msg, + struct nl_sock *nl_handle, struct nl_msg *msg, int (*valid_handler)(struct nl_msg *, void *), void *valid_data) { @@ -416,8 +376,16 @@ static int send_and_recv(struct nl80211_global *global, NETLINK_CAP_ACK, &opt, sizeof(opt)); err = nl_send_auto_complete(nl_handle, msg); - if (err < 0) + if (err < 0) { + wpa_printf(MSG_INFO, + "nl80211: nl_send_auto_complete() failed: %s", + nl_geterror(err)); + /* Need to convert libnl error code to an errno value. For now, + * just hardcode this to EBADF; the real error reason is shown + * in that error print above. */ + err = -EBADF; goto out; + } err = 1; @@ -431,10 +399,24 @@ static int send_and_recv(struct nl80211_global *global, while (err > 0) { int res = nl_recvmsgs(nl_handle, cb); - if (res < 0) { + + if (res == -NLE_DUMP_INTR) { + /* Most likely one of the nl80211 dump routines hit a + * case where internal results changed while the dump + * was being sent. The most common known case for this + * is scan results fetching while associated were every + * received Beacon frame from the AP may end up + * incrementing bss_generation. This + * NL80211_CMD_GET_SCAN case tries again in the caller; + * other cases (of which there are no known common ones) + * will stop and return an error. */ + wpa_printf(MSG_DEBUG, "nl80211: %s; convert to -EAGAIN", + nl_geterror(res)); + err = -EAGAIN; + } else if (res < 0) { wpa_printf(MSG_INFO, - "nl80211: %s->nl_recvmsgs failed: %d", - __func__, res); + "nl80211: %s->nl_recvmsgs failed: %d (%s)", + __func__, res, nl_geterror(res)); } } out: @@ -1065,7 +1047,7 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, while (RTA_OK(attr, attrlen)) { switch (attr->rta_type) { case IFLA_IFNAME: - if (RTA_PAYLOAD(attr) >= IFNAMSIZ) + if (RTA_PAYLOAD(attr) > IFNAMSIZ) break; os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); ifname[RTA_PAYLOAD(attr)] = '\0'; @@ -1240,7 +1222,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, while (RTA_OK(attr, attrlen)) { switch (attr->rta_type) { case IFLA_IFNAME: - if (RTA_PAYLOAD(attr) >= IFNAMSIZ) + if (RTA_PAYLOAD(attr) > IFNAMSIZ) break; os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr)); ifname[RTA_PAYLOAD(attr)] = '\0'; @@ -1369,12 +1351,25 @@ int nl80211_get_assoc_ssid(struct wpa_driver_nl80211_data *drv, u8 *ssid) struct nl_msg *msg; int ret; struct nl80211_get_assoc_freq_arg arg; + int count = 0; +try_again: msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); os_memset(&arg, 0, sizeof(arg)); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler, &arg); + if (ret == -EAGAIN) { + count++; + if (count >= 10) { + wpa_printf(MSG_INFO, + "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid"); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to receive consistent scan result dump for get_assoc_ssid - try again"); + goto try_again; + } + } if (ret == 0) { os_memcpy(ssid, arg.assoc_ssid, arg.assoc_ssid_len); return arg.assoc_ssid_len; @@ -1390,12 +1385,25 @@ unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv) struct nl_msg *msg; int ret; struct nl80211_get_assoc_freq_arg arg; + int count = 0; +try_again: msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN); os_memset(&arg, 0, sizeof(arg)); arg.drv = drv; ret = send_and_recv_msgs(drv, msg, nl80211_get_assoc_freq_handler, &arg); + if (ret == -EAGAIN) { + count++; + if (count >= 10) { + wpa_printf(MSG_INFO, + "nl80211: Failed to receive consistent scan result dump for get_assoc_freq"); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to receive consistent scan result dump for get_assoc_freq - try again"); + goto try_again; + } + } if (ret == 0) { unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ? arg.ibss_freq : arg.assoc_freq; @@ -1733,7 +1741,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for scan events: %d (%s)", - ret, strerror(-ret)); + ret, nl_geterror(ret)); goto err; } @@ -1743,7 +1751,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) if (ret < 0) { wpa_printf(MSG_ERROR, "nl80211: Could not add multicast " "membership for mlme events: %d (%s)", - ret, strerror(-ret)); + ret, nl_geterror(ret)); goto err; } @@ -1753,7 +1761,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " "membership for regulatory events: %d (%s)", - ret, strerror(-ret)); + ret, nl_geterror(ret)); /* Continue without regulatory events */ } @@ -1763,7 +1771,7 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global) if (ret < 0) { wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast " "membership for vendor events: %d (%s)", - ret, strerror(-ret)); + ret, nl_geterror(ret)); /* Continue without vendor events */ } @@ -1789,7 +1797,7 @@ err: static void nl80211_check_global(struct nl80211_global *global) { - struct nl_handle *handle; + struct nl_sock *handle; const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL }; int ret; unsigned int i; @@ -1808,7 +1816,7 @@ static void nl80211_check_global(struct nl80211_global *global) if (ret < 0) { wpa_printf(MSG_INFO, "nl80211: Could not re-add multicast membership for %s events: %d (%s)", - groups[i], ret, strerror(-ret)); + groups[i], ret, nl_geterror(ret)); } } } @@ -2087,7 +2095,7 @@ static void * wpa_driver_nl80211_init(void *ctx, const char *ifname, static int nl80211_register_frame(struct i802_bss *bss, - struct nl_handle *nl_handle, + struct nl_sock *nl_handle, u16 type, const u8 *match, size_t match_len) { struct wpa_driver_nl80211_data *drv = bss->drv; @@ -2100,7 +2108,7 @@ static int nl80211_register_frame(struct i802_bss *bss, wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s", type, fc2str(type), nl_handle, buf); - if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) || + if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_FRAME)) || nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) || nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) { nlmsg_free(msg); @@ -2174,6 +2182,7 @@ static int nl80211_init_connect_handle(struct i802_bss *bss) static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) { struct wpa_driver_nl80211_data *drv = bss->drv; + u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4); int ret = 0; if (nl80211_alloc_mgmt_handle(bss)) @@ -2181,13 +2190,14 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP " "handle %p", bss->nl_mgmt); - if (drv->nlmode == NL80211_IFTYPE_ADHOC || - ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) && - !(drv->capa.flags & WPA_DRIVER_FLAGS_SME))) { - u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4); - + if (drv->nlmode == NL80211_IFTYPE_ADHOC) { /* register for any AUTH message */ nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0); + } else if ((drv->capa.flags & WPA_DRIVER_FLAGS_SAE) && + !(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { + /* register for SAE Authentication frames */ + nl80211_register_frame(bss, bss->nl_mgmt, type, + (u8 *) "\x03\x00", 2); } #ifdef CONFIG_INTERWORKING @@ -2757,7 +2767,7 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) } if (drv->rtnl_sk) - nl80211_handle_destroy(drv->rtnl_sk); + nl_socket_free(drv->rtnl_sk); if (bss->added_bridge) { if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname, @@ -2873,7 +2883,6 @@ static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len) case WPA_ALG_KRK: return RSN_CIPHER_SUITE_KRK; case WPA_ALG_NONE: - case WPA_ALG_PMK: wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d", alg); return 0; @@ -2934,6 +2943,40 @@ static int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[], } +static int wpa_key_mgmt_to_suites(unsigned int key_mgmt_suites, u32 suites[], + int max_suites) +{ + int num_suites = 0; + +#define __AKM(a, b) \ + if (num_suites < max_suites && \ + (key_mgmt_suites & (WPA_KEY_MGMT_ ## a))) \ + suites[num_suites++] = (RSN_AUTH_KEY_MGMT_ ## b) + __AKM(IEEE8021X, UNSPEC_802_1X); + __AKM(PSK, PSK_OVER_802_1X); + __AKM(FT_IEEE8021X, FT_802_1X); + __AKM(FT_PSK, FT_PSK); + __AKM(IEEE8021X_SHA256, 802_1X_SHA256); + __AKM(PSK_SHA256, PSK_SHA256); + __AKM(SAE, SAE); + __AKM(FT_SAE, FT_SAE); + __AKM(CCKM, CCKM); + __AKM(OSEN, OSEN); + __AKM(IEEE8021X_SUITE_B, 802_1X_SUITE_B); + __AKM(IEEE8021X_SUITE_B_192, 802_1X_SUITE_B_192); + __AKM(FILS_SHA256, FILS_SHA256); + __AKM(FILS_SHA384, FILS_SHA384); + __AKM(FT_FILS_SHA256, FT_FILS_SHA256); + __AKM(FT_FILS_SHA384, FT_FILS_SHA384); + __AKM(OWE, OWE); + __AKM(DPP, DPP); + __AKM(FT_IEEE8021X_SHA384, FT_802_1X_SHA384); +#undef __AKM + + return num_suites; +} + + #ifdef CONFIG_DRIVER_NL80211_QCA static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv, const u8 *key, size_t key_len) @@ -3003,18 +3046,26 @@ static int nl80211_set_pmk(struct wpa_driver_nl80211_data *drv, } -static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, - enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) +static int wpa_driver_nl80211_set_key(struct i802_bss *bss, + struct wpa_driver_set_key_params *params) { struct wpa_driver_nl80211_data *drv = bss->drv; int ifindex; struct nl_msg *msg; struct nl_msg *key_msg; int ret; - int tdls = 0; + int skip_set_key = 1; + const char *ifname = params->ifname; + enum wpa_alg alg = params->alg; + const u8 *addr = params->addr; + int key_idx = params->key_idx; + int set_tx = params->set_tx; + const u8 *seq = params->seq; + size_t seq_len = params->seq_len; + const u8 *key = params->key; + size_t key_len = params->key_len; + int vlan_id = params->vlan_id; + enum key_flag key_flag = params->key_flag; /* Ignore for P2P Device */ if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) @@ -3022,18 +3073,17 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, ifindex = if_nametoindex(ifname); wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d " - "set_tx=%d seq_len=%lu key_len=%lu", + "set_tx=%d seq_len=%lu key_len=%lu key_flag=0x%x", __func__, ifindex, ifname, alg, addr, key_idx, set_tx, - (unsigned long) seq_len, (unsigned long) key_len); -#ifdef CONFIG_TDLS - if (key_idx == -1) { - key_idx = 0; - tdls = 1; + (unsigned long) seq_len, (unsigned long) key_len, key_flag); + + if (check_key_flag(key_flag)) { + wpa_printf(MSG_DEBUG, "%s: invalid key_flag", __func__); + return -EINVAL; } -#endif /* CONFIG_TDLS */ #ifdef CONFIG_DRIVER_NL80211_QCA - if (alg == WPA_ALG_PMK && + if ((key_flag & KEY_FLAG_PMK) && (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) { wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key", __func__); @@ -3042,15 +3092,33 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, } #endif /* CONFIG_DRIVER_NL80211_QCA */ - if (alg == WPA_ALG_PMK && - (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X)) - return nl80211_set_pmk(drv, key, key_len, addr); + if (key_flag & KEY_FLAG_PMK) { + if (drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_8021X) + return nl80211_set_pmk(drv, key, key_len, addr); + /* The driver does not have any offload mechanism for PMK, so + * there is no need to configure this key. */ + return 0; + } + ret = -ENOBUFS; key_msg = nlmsg_alloc(); if (!key_msg) - return -ENOBUFS; + return ret; - if (alg == WPA_ALG_NONE) { + if ((key_flag & KEY_FLAG_PAIRWISE_MASK) == + KEY_FLAG_PAIRWISE_RX_TX_MODIFY) { + wpa_printf(MSG_DEBUG, + "nl80211: SET_KEY (pairwise RX/TX modify)"); + msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY); + if (!msg) + goto fail2; + } else if (alg == WPA_ALG_NONE && (key_flag & KEY_FLAG_RX_TX)) { + wpa_printf(MSG_DEBUG, "%s: invalid key_flag to delete key", + __func__); + ret = -EINVAL; + goto fail2; + } else if (alg == WPA_ALG_NONE) { + wpa_printf(MSG_DEBUG, "nl80211: DEL_KEY"); msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY); if (!msg) goto fail2; @@ -3058,8 +3126,11 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, u32 suite; suite = wpa_alg_to_cipher_suite(alg, key_len); - if (!suite) + if (!suite) { + ret = -EINVAL; goto fail2; + } + wpa_printf(MSG_DEBUG, "nl80211: NEW_KEY"); msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY); if (!msg) goto fail2; @@ -3067,12 +3138,13 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, nla_put_u32(key_msg, NL80211_KEY_CIPHER, suite)) goto fail; wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len); - } - if (seq && seq_len) { - if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq)) - goto fail; - wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len); + if (seq && seq_len) { + if (nla_put(key_msg, NL80211_KEY_SEQ, seq_len, seq)) + goto fail; + wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", + seq, seq_len); + } } if (addr && !is_broadcast_ether_addr(addr)) { @@ -3080,22 +3152,42 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) goto fail; - if (alg != WPA_ALG_WEP && key_idx && !set_tx) { + if ((key_flag & KEY_FLAG_PAIRWISE_MASK) == + KEY_FLAG_PAIRWISE_RX || + (key_flag & KEY_FLAG_PAIRWISE_MASK) == + KEY_FLAG_PAIRWISE_RX_TX_MODIFY) { + if (nla_put_u8(key_msg, NL80211_KEY_MODE, + key_flag == KEY_FLAG_PAIRWISE_RX ? + NL80211_KEY_NO_TX : NL80211_KEY_SET_TX)) + goto fail; + } else if ((key_flag & KEY_FLAG_GROUP_MASK) == + KEY_FLAG_GROUP_RX) { wpa_printf(MSG_DEBUG, " RSN IBSS RX GTK"); if (nla_put_u32(key_msg, NL80211_KEY_TYPE, NL80211_KEYTYPE_GROUP)) goto fail; + } else if (!(key_flag & KEY_FLAG_PAIRWISE)) { + wpa_printf(MSG_DEBUG, + " key_flag missing PAIRWISE when setting a pairwise key"); + ret = -EINVAL; + goto fail; + } else if (alg == WPA_ALG_WEP && + (key_flag & KEY_FLAG_RX_TX) == KEY_FLAG_RX_TX) { + wpa_printf(MSG_DEBUG, " unicast WEP key"); + skip_set_key = 0; + } else { + wpa_printf(MSG_DEBUG, " pairwise key"); } - } else if (addr && is_broadcast_ether_addr(addr)) { - struct nlattr *types; - + } else if ((key_flag & KEY_FLAG_PAIRWISE) || + !(key_flag & KEY_FLAG_GROUP)) { + wpa_printf(MSG_DEBUG, + " invalid key_flag for a broadcast key"); + ret = -EINVAL; + goto fail; + } else { wpa_printf(MSG_DEBUG, " broadcast key"); - - types = nla_nest_start(key_msg, NL80211_KEY_DEFAULT_TYPES); - if (!types || - nla_put_flag(key_msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST)) - goto fail; - nla_nest_end(key_msg, types); + if (key_flag & KEY_FLAG_DEFAULT) + skip_set_key = 0; } if (nla_put_u8(key_msg, NL80211_KEY_IDX, key_idx) || nla_put_nested(msg, NL80211_ATTR_KEY, key_msg)) @@ -3104,26 +3196,31 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, nlmsg_free(key_msg); key_msg = NULL; + if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { + wpa_printf(MSG_DEBUG, "nl80211: VLAN ID %d", vlan_id); + if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) + goto fail; + } + ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL); if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE) ret = 0; if (ret) - wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)", + wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s", ret, strerror(-ret)); /* - * If we failed or don't need to set the default TX key (below), + * If we failed or don't need to set the key as default (below), * we're done here. */ - if (ret || !set_tx || alg == WPA_ALG_NONE || tdls) - return ret; - if (is_ap_interface(drv->nlmode) && addr && - !is_broadcast_ether_addr(addr)) + if (ret || skip_set_key) return ret; + wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_SET_KEY - default key"); + ret = -ENOBUFS; key_msg = nlmsg_alloc(); if (!key_msg) - return -ENOBUFS; + return ret; msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY); if (!msg) @@ -3134,8 +3231,10 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, alg == WPA_ALG_BIP_GMAC_128 || alg == WPA_ALG_BIP_GMAC_256 || alg == WPA_ALG_BIP_CMAC_256) ? - NL80211_KEY_DEFAULT_MGMT : - NL80211_KEY_DEFAULT)) + (key_idx == 6 || key_idx == 7 ? + NL80211_KEY_DEFAULT_BEACON : + NL80211_KEY_DEFAULT_MGMT) : + NL80211_KEY_DEFAULT)) goto fail; if (addr && is_broadcast_ether_addr(addr)) { struct nlattr *types; @@ -3161,12 +3260,18 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, nlmsg_free(key_msg); key_msg = NULL; + if (vlan_id && (drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD)) { + wpa_printf(MSG_DEBUG, "nl80211: set_key default - VLAN ID %d", + vlan_id); + if (nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) + goto fail; + } + ret = send_and_recv_msgs(drv, msg, NULL, NULL); - if (ret == -ENOENT) - ret = 0; if (ret) - wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; " - "err=%d %s)", ret, strerror(-ret)); + wpa_printf(MSG_DEBUG, + "nl80211: set_key default failed; err=%d %s", + ret, strerror(-ret)); return ret; fail: @@ -3175,7 +3280,7 @@ fail: fail2: nl80211_nlmsg_clear(key_msg); nlmsg_free(key_msg); - return -ENOBUFS; + return ret; } @@ -3271,7 +3376,7 @@ static int nl80211_set_conn_keys(struct wpa_driver_associate_params *params, int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change, - struct nl_handle *nl_connect) + struct nl_sock *nl_connect) { int ret; struct nl_msg *msg; @@ -3300,7 +3405,7 @@ int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, static int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv, u16 reason_code, - struct nl_handle *nl_connect) + struct nl_sock *nl_connect) { int ret; int drv_associated = drv->associated; @@ -3332,7 +3437,7 @@ static int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss, return nl80211_leave_ibss(drv, 1); } if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { - struct nl_handle *nl_connect = NULL; + struct nl_sock *nl_connect = NULL; if (bss->use_nl_connect) nl_connect = bss->nl_connect; @@ -3450,6 +3555,7 @@ static int wpa_driver_nl80211_authenticate( enum nl80211_iftype nlmode; int count = 0; int is_retry; + struct wpa_driver_set_key_params p; nl80211_unmask_11b_rates(bss); @@ -3478,14 +3584,20 @@ retry: if (!msg) goto fail; + os_memset(&p, 0, sizeof(p)); + p.ifname = bss->ifname; + p.alg = WPA_ALG_WEP; for (i = 0; i < 4; i++) { if (!params->wep_key[i]) continue; - wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP, - NULL, i, - i == params->wep_tx_keyidx, NULL, 0, - params->wep_key[i], - params->wep_key_len[i]); + p.key_idx = i; + p.set_tx = i == params->wep_tx_keyidx; + p.key = params->wep_key[i]; + p.key_len = params->wep_key_len[i]; + p.key_flag = i == params->wep_tx_keyidx ? + KEY_FLAG_GROUP_RX_TX_DEFAULT : + KEY_FLAG_GROUP_RX_TX; + wpa_driver_nl80211_set_key(bss, &p); if (params->wep_tx_keyidx != i) continue; if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0, @@ -3647,80 +3759,27 @@ int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv) } -static int wpa_driver_nl80211_send_frame(struct i802_bss *bss, - const void *data, size_t len, - int encrypt, int noack, - unsigned int freq, int no_cck, - int offchanok, unsigned int wait_time, - const u16 *csa_offs, - size_t csa_offs_len) -{ - struct wpa_driver_nl80211_data *drv = bss->drv; - u64 cookie; - int res; - - if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) { - freq = nl80211_get_assoc_freq(drv); - wpa_printf(MSG_DEBUG, - "nl80211: send_frame - Use assoc_freq=%u for IBSS", - freq); - } - if (freq == 0) { - wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u", - bss->freq); - freq = bss->freq; - } - - if (drv->use_monitor) { - wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor", - freq, bss->freq); - return nl80211_send_monitor(drv, data, len, encrypt, noack); - } - - wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd"); - res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len, - &cookie, no_cck, noack, offchanok, - csa_offs, csa_offs_len); - if (res == 0 && !noack) { - const struct ieee80211_mgmt *mgmt; - u16 fc; - - mgmt = (const struct ieee80211_mgmt *) data; - fc = le_to_host16(mgmt->frame_control); - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && - WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { - wpa_printf(MSG_MSGDUMP, - "nl80211: Update send_action_cookie from 0x%llx to 0x%llx", - (long long unsigned int) - drv->send_action_cookie, - (long long unsigned int) cookie); - drv->send_action_cookie = cookie; - } - } - - return res; -} - - static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, size_t data_len, int noack, unsigned int freq, int no_cck, int offchanok, unsigned int wait_time, const u16 *csa_offs, - size_t csa_offs_len) + size_t csa_offs_len, int no_encrypt) { struct wpa_driver_nl80211_data *drv = bss->drv; struct ieee80211_mgmt *mgmt; - int encrypt = 1; + int encrypt = !no_encrypt; u16 fc; + int use_cookie = 1; + int res; mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); - wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR - " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x (%s) nlmode=%d", + wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da=" MACSTR + " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u no_encrypt=%d fc=0x%x (%s) nlmode=%d", MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time, - fc, fc2str(fc), drv->nlmode); + no_encrypt, fc, fc2str(fc), drv->nlmode); if ((is_sta_interface(drv->nlmode) || drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) && @@ -3736,9 +3795,11 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, drv->last_mgmt_freq); freq = drv->last_mgmt_freq; } - return nl80211_send_frame_cmd(bss, freq, 0, - data, data_len, NULL, 1, noack, - 1, csa_offs, csa_offs_len); + wait_time = 0; + use_cookie = 0; + no_cck = 1; + offchanok = 1; + goto send_frame_cmd; } if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) { @@ -3747,13 +3808,9 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, bss->freq); freq = bss->freq; } - return nl80211_send_frame_cmd(bss, freq, - (int) freq == bss->freq ? 0 : - wait_time, - data, data_len, - &drv->send_action_cookie, - no_cck, noack, offchanok, - csa_offs, csa_offs_len); + if ((int) freq == bss->freq) + wait_time = 0; + goto send_frame_cmd; } if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && @@ -3770,11 +3827,60 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, encrypt = 0; } - wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame"); - return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, - noack, freq, no_cck, offchanok, - wait_time, csa_offs, - csa_offs_len); + if (freq == 0 && drv->nlmode == NL80211_IFTYPE_STATION && + (drv->capa.flags & WPA_DRIVER_FLAGS_SAE) && + !(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && + WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { + freq = nl80211_get_assoc_freq(drv); + wpa_printf(MSG_DEBUG, + "nl80211: send_mlme - Use assoc_freq=%u for external auth", + freq); + } + + if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) { + freq = nl80211_get_assoc_freq(drv); + wpa_printf(MSG_DEBUG, + "nl80211: send_mlme - Use assoc_freq=%u for IBSS", + freq); + } + if (freq == 0) { + wpa_printf(MSG_DEBUG, "nl80211: send_mlme - Use bss->freq=%u", + bss->freq); + freq = bss->freq; + } + + if (drv->use_monitor) { + wpa_printf(MSG_DEBUG, + "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor", + freq, bss->freq); + return nl80211_send_monitor(drv, data, data_len, encrypt, + noack); + } + + if (noack || WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || + WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION) + use_cookie = 0; +send_frame_cmd: +#ifdef CONFIG_TESTING_OPTIONS + if (no_encrypt && !encrypt && !drv->use_monitor) { + wpa_printf(MSG_DEBUG, + "nl80211: Request to send an unencrypted frame - use a monitor interface for this"); + if (nl80211_create_monitor_interface(drv) < 0) + return -1; + res = nl80211_send_monitor(drv, data, data_len, encrypt, + noack); + nl80211_remove_monitor_interface(drv); + return res; + } +#endif /* CONFIG_TESTING_OPTIONS */ + + wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame_cmd"); + res = nl80211_send_frame_cmd(bss, freq, wait_time, data, data_len, + use_cookie, no_cck, noack, offchanok, + csa_offs, csa_offs_len); + + return res; } @@ -4076,8 +4182,7 @@ static int wpa_driver_nl80211_set_ap(void *priv, int ret = -ENOBUFS; int beacon_set; int num_suites; - int smps_mode; - u32 suites[10], suite; + u32 suites[20], suite; u32 ver; #ifdef CONFIG_MESH struct wpa_driver_mesh_bss_params mesh_params; @@ -4171,14 +4276,15 @@ static int wpa_driver_nl80211_set_ap(void *priv, wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x", params->key_mgmt_suites); - num_suites = 0; - if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X) - suites[num_suites++] = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X; - if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK) - suites[num_suites++] = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X; - if (num_suites && - nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32), - suites)) + num_suites = wpa_key_mgmt_to_suites(params->key_mgmt_suites, + suites, ARRAY_SIZE(suites)); + if (num_suites > NL80211_MAX_NR_AKM_SUITES) + wpa_printf(MSG_WARNING, + "nl80211: Not enough room for all AKM suites (num_suites=%d > NL80211_MAX_NR_AKM_SUITES)", + num_suites); + else if (num_suites && + nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32), + suites)) goto fail; if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA && @@ -4209,27 +4315,6 @@ static int wpa_driver_nl80211_set_ap(void *priv, nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite)) goto fail; - if (params->ht_opmode != -1) { - switch (params->smps_mode) { - case HT_CAP_INFO_SMPS_DYNAMIC: - wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic"); - smps_mode = NL80211_SMPS_DYNAMIC; - break; - case HT_CAP_INFO_SMPS_STATIC: - wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static"); - smps_mode = NL80211_SMPS_STATIC; - break; - default: - /* invalid - fallback to smps off */ - case HT_CAP_INFO_SMPS_DISABLED: - wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off"); - smps_mode = NL80211_SMPS_OFF; - break; - } - if (nla_put_u8(msg, NL80211_ATTR_SMPS_MODE, smps_mode)) - goto fail; - } - if (params->beacon_ies) { wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies", params->beacon_ies); @@ -4314,7 +4399,8 @@ static int wpa_driver_nl80211_set_ap(void *priv, spr = nla_nest_start(msg, NL80211_ATTR_HE_OBSS_PD); wpa_printf(MSG_DEBUG, "nl80211: he_spr=%d", params->he_spr); - if (nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET, + if (!spr || + nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET, params->he_spr_srg_obss_pd_min_offset) || nla_put_u8(msg, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET, params->he_spr_srg_obss_pd_max_offset)) @@ -4322,6 +4408,28 @@ static int wpa_driver_nl80211_set_ap(void *priv, nla_nest_end(msg, spr); } + + if (params->freq && params->freq->he_enabled) { + struct nlattr *bss_color; + + bss_color = nla_nest_start(msg, NL80211_ATTR_HE_BSS_COLOR); + if (!bss_color || + (params->he_bss_color_disabled && + nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_DISABLED)) || + (params->he_bss_color_partial && + nla_put_flag(msg, NL80211_HE_BSS_COLOR_ATTR_PARTIAL)) || + nla_put_u8(msg, NL80211_HE_BSS_COLOR_ATTR_COLOR, + params->he_bss_color)) + goto fail; + nla_nest_end(msg, bss_color); + } + + if (params->twt_responder) { + wpa_printf(MSG_DEBUG, "nl80211: twt_responder=%d", + params->twt_responder); + if (nla_put_flag(msg, NL80211_ATTR_TWT_RESPONDER)) + goto fail; + } #endif /* CONFIG_IEEE80211AX */ ret = send_and_recv_msgs(drv, msg, NULL, NULL); @@ -5101,6 +5209,40 @@ static void nl80211_teardown_ap(struct i802_bss *bss) } +static int nl80211_tx_control_port(void *priv, const u8 *dest, + u16 proto, const u8 *buf, size_t len, + int no_encrypt) +{ + struct i802_bss *bss = priv; + struct nl_msg *msg; + int ret; + + wpa_printf(MSG_DEBUG, + "nl80211: Send over control port dest=" MACSTR + " proto=0x%04x len=%u no_encrypt=%d", + MAC2STR(dest), proto, (unsigned int) len, no_encrypt); + + msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CONTROL_PORT_FRAME); + if (!msg || + nla_put_u16(msg, NL80211_ATTR_CONTROL_PORT_ETHERTYPE, proto) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dest) || + nla_put(msg, NL80211_ATTR_FRAME, len, buf) || + (no_encrypt && + nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))) { + nlmsg_free(msg); + return -ENOBUFS; + } + + ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL); + if (ret) + wpa_printf(MSG_DEBUG, + "nl80211: tx_control_port failed: ret=%d (%s)", + ret, strerror(-ret)); + + return ret; +} + + static int nl80211_send_eapol_data(struct i802_bss *bss, const u8 *addr, const u8 *data, size_t data_len) @@ -5143,6 +5285,10 @@ static int wpa_driver_nl80211_hapd_send_eapol( int res; int qos = flags & WPA_STA_WMM; + if (drv->capa.flags & WPA_DRIVER_FLAGS_CONTROL_PORT) + return nl80211_tx_control_port(bss, addr, ETH_P_EAPOL, + data, data_len, !encrypt); + if (drv->device_ap_sme || !drv->use_monitor) return nl80211_send_eapol_data(bss, addr, data, data_len); @@ -5183,12 +5329,11 @@ static int wpa_driver_nl80211_hapd_send_eapol( pos += 2; memcpy(pos, data, data_len); - res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0, - 0, 0, 0, 0, NULL, 0); + res = nl80211_send_monitor(drv, hdr, len, encrypt, 0); if (res < 0) { - wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - " - "failed: %d (%s)", - (unsigned long) len, errno, strerror(errno)); + wpa_printf(MSG_ERROR, + "hapd_send_eapol - packet len: %lu - failed", + (unsigned long) len); } os_free(hdr); @@ -5775,7 +5920,7 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, static int wpa_driver_nl80211_try_connect( struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params, - struct nl_handle *nl_connect) + struct nl_sock *nl_connect) { struct nl_msg *msg; enum nl80211_auth_type type; @@ -5866,7 +6011,7 @@ fail: static int wpa_driver_nl80211_connect( struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params, - struct nl_handle *nl_connect) + struct nl_sock *nl_connect) { int ret; @@ -5914,7 +6059,7 @@ static int wpa_driver_nl80211_associate( if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) { enum nl80211_iftype nlmode = params->p2p ? NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION; - struct nl_handle *nl_connect = NULL; + struct nl_sock *nl_connect = NULL; if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0) return -1; @@ -6646,6 +6791,8 @@ static int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr, MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id); if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) || + ((drv->capa.flags & WPA_DRIVER_FLAGS_VLAN_OFFLOAD) && + nla_put_u16(msg, NL80211_ATTR_VLAN_ID, vlan_id)) || nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) { nlmsg_free(msg); return -ENOBUFS; @@ -6718,7 +6865,7 @@ static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr, return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.deauth), 0, 0, 0, 0, - 0, NULL, 0); + 0, NULL, 0, 0); } @@ -6745,7 +6892,7 @@ static int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr, return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.disassoc), 0, 0, 0, 0, - 0, NULL, 0); + 0, NULL, 0, 0); } @@ -7078,15 +7225,18 @@ static void *i802_init(struct hostapd_data *hapd, #ifdef CONFIG_LIBNL3_ROUTE if (bss->added_if_into_bridge || bss->already_in_bridge) { + int err; + drv->rtnl_sk = nl_socket_alloc(); if (drv->rtnl_sk == NULL) { wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock"); goto failed; } - if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) { + err = nl_connect(drv->rtnl_sk, NETLINK_ROUTE); + if (err) { wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s", - strerror(errno)); + nl_geterror(err)); goto failed; } } @@ -7460,7 +7610,7 @@ static int cookie_handler(struct nl_msg *msg, void *arg) static int nl80211_send_frame_cmd(struct i802_bss *bss, unsigned int freq, unsigned int wait, const u8 *buf, size_t buf_len, - u64 *cookie_out, int no_cck, int no_ack, + int save_cookie, int no_cck, int no_ack, int offchanok, const u16 *csa_offs, size_t csa_offs_len) { @@ -7499,22 +7649,22 @@ static int nl80211_send_frame_cmd(struct i802_bss *bss, "cookie 0x%llx", no_ack ? " (no ACK)" : "", (long long unsigned int) cookie); - if (cookie_out) - *cookie_out = no_ack ? (u64) -1 : cookie; + if (save_cookie) + drv->send_frame_cookie = no_ack ? (u64) -1 : cookie; - if (drv->num_send_action_cookies == MAX_SEND_ACTION_COOKIES) { + if (drv->num_send_frame_cookies == MAX_SEND_FRAME_COOKIES) { wpa_printf(MSG_DEBUG, - "nl80211: Drop oldest pending send action cookie 0x%llx", + "nl80211: Drop oldest pending send frame cookie 0x%llx", (long long unsigned int) - drv->send_action_cookies[0]); - os_memmove(&drv->send_action_cookies[0], - &drv->send_action_cookies[1], - (MAX_SEND_ACTION_COOKIES - 1) * + drv->send_frame_cookies[0]); + os_memmove(&drv->send_frame_cookies[0], + &drv->send_frame_cookies[1], + (MAX_SEND_FRAME_COOKIES - 1) * sizeof(u64)); - drv->num_send_action_cookies--; + drv->num_send_frame_cookies--; } - drv->send_action_cookies[drv->num_send_action_cookies] = cookie; - drv->num_send_action_cookies++; + drv->send_frame_cookies[drv->num_send_frame_cookies] = cookie; + drv->num_send_frame_cookies++; } fail: @@ -7535,10 +7685,14 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss, int ret = -1; u8 *buf; struct ieee80211_hdr *hdr; + int offchanok = 1; + + if (is_ap_interface(drv->nlmode) && (int) freq == bss->freq) + offchanok = 0; wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, " - "freq=%u MHz wait=%d ms no_cck=%d)", - drv->ifindex, freq, wait_time, no_cck); + "freq=%u MHz wait=%d ms no_cck=%d offchanok=%d)", + drv->ifindex, freq, wait_time, no_cck, offchanok); buf = os_zalloc(24 + data_len); if (buf == NULL) @@ -7564,13 +7718,12 @@ static int wpa_driver_nl80211_send_action(struct i802_bss *bss, (int) freq == bss->freq || drv->device_ap_sme || !drv->use_monitor)) ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len, - 0, freq, no_cck, 1, - wait_time, NULL, 0); + 0, freq, no_cck, offchanok, + wait_time, NULL, 0, 0); else ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf, 24 + data_len, - &drv->send_action_cookie, - no_cck, 0, 1, NULL, 0); + 1, no_cck, 0, offchanok, NULL, 0); os_free(buf); return ret; @@ -7606,19 +7759,19 @@ static void wpa_driver_nl80211_send_action_cancel_wait(void *priv) u64 cookie; /* Cancel the last pending TX cookie */ - nl80211_frame_wait_cancel(bss, drv->send_action_cookie); + nl80211_frame_wait_cancel(bss, drv->send_frame_cookie); /* * Cancel the other pending TX cookies, if any. This is needed since * the driver may keep a list of all pending offchannel TX operations * and free up the radio only once they have expired or cancelled. */ - for (i = drv->num_send_action_cookies; i > 0; i--) { - cookie = drv->send_action_cookies[i - 1]; - if (cookie != drv->send_action_cookie) + for (i = drv->num_send_frame_cookies; i > 0; i--) { + cookie = drv->send_frame_cookies[i - 1]; + if (cookie != drv->send_frame_cookie) nl80211_frame_wait_cancel(bss, cookie); } - drv->num_send_action_cookies = 0; + drv->num_send_frame_cookies = 0; } @@ -7938,15 +8091,6 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si) } -static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len, - int encrypt) -{ - struct i802_bss *bss = priv; - return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0, - 0, 0, 0, 0, NULL, 0); -} - - static int nl80211_set_param(void *priv, const char *param) { struct i802_bss *bss = priv; @@ -7981,6 +8125,12 @@ static int nl80211_set_param(void *priv, const char *param) drv->test_use_roc_tx = 1; } + if (os_strstr(param, "control_port=0")) + drv->capa.flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT; + + if (os_strstr(param, "full_ap_client_state=0")) + drv->capa.flags &= ~WPA_DRIVER_FLAGS_FULL_AP_CLIENT_STATE; + return 0; } @@ -8081,6 +8231,12 @@ static int nl80211_pmkid(struct i802_bss *bss, int cmd, (params->fils_cache_id && nla_put(msg, NL80211_ATTR_FILS_CACHE_ID, 2, params->fils_cache_id)) || + (params->pmk_lifetime && + nla_put_u32(msg, NL80211_ATTR_PMK_LIFETIME, + params->pmk_lifetime)) || + (params->pmk_reauth_threshold && + nla_put_u8(msg, NL80211_ATTR_PMK_REAUTH_THRESHOLD, + params->pmk_reauth_threshold)) || (cmd != NL80211_CMD_DEL_PMKSA && params->pmk_len && params->pmk_len <= PMK_MAX_LEN && nla_put(msg, NL80211_ATTR_PMK, params->pmk_len, params->pmk))) { @@ -8401,7 +8557,7 @@ static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr, os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN); if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0, - 0, 0, NULL, 0) < 0) + 0, 0, NULL, 0, 0) < 0) wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to " "send poll frame"); } @@ -8675,15 +8831,12 @@ nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr) #endif /* CONFIG TDLS */ -static int driver_nl80211_set_key(const char *ifname, void *priv, - enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) +static int driver_nl80211_set_key(void *priv, + struct wpa_driver_set_key_params *params) { struct i802_bss *bss = priv; - return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx, - set_tx, seq, seq_len, key, key_len); + + return wpa_driver_nl80211_set_key(bss, params); } @@ -8742,12 +8895,13 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type, static int driver_nl80211_send_mlme(void *priv, const u8 *data, size_t data_len, int noack, unsigned int freq, - const u16 *csa_offs, size_t csa_offs_len) + const u16 *csa_offs, size_t csa_offs_len, + int no_encrypt, unsigned int wait) { struct i802_bss *bss = priv; return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack, - freq, 0, 0, 0, csa_offs, - csa_offs_len); + freq, 0, 0, wait, csa_offs, + csa_offs_len, no_encrypt); } @@ -9398,6 +9552,46 @@ static int nl80211_set_qos_map(void *priv, const u8 *qos_map_set, } +static int get_wowlan_handler(struct nl_msg *msg, void *arg) +{ + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); + int *wowlan_enabled = arg; + + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + + *wowlan_enabled = !!tb[NL80211_ATTR_WOWLAN_TRIGGERS]; + + return NL_SKIP; +} + + +static int nl80211_get_wowlan(void *priv) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + int wowlan_enabled; + int ret; + + wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status"); + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_WOWLAN); + + ret = send_and_recv_msgs(drv, msg, get_wowlan_handler, &wowlan_enabled); + if (ret) { + wpa_printf(MSG_DEBUG, "nl80211: Getting wowlan status failed"); + return 0; + } + + wpa_printf(MSG_DEBUG, "nl80211: wowlan is %s", + wowlan_enabled ? "enabled" : "disabled"); + + return wowlan_enabled; +} + + static int nl80211_set_wowlan(void *priv, const struct wowlan_triggers *triggers) { @@ -9941,7 +10135,7 @@ static int wpa_driver_br_add_ip_neigh(void *priv, u8 version, if (res) { wpa_printf(MSG_DEBUG, "nl80211: Adding bridge ip neigh failed: %s", - strerror(errno)); + nl_geterror(res)); } errout: if (nl_lladdr) @@ -10017,7 +10211,7 @@ static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version, if (res) { wpa_printf(MSG_DEBUG, "nl80211: Deleting bridge ip neigh failed: %s", - strerror(errno)); + nl_geterror(res)); } errout: if (nl_ipaddr) @@ -10251,22 +10445,24 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params) nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) || add_acs_ch_list(msg, params->freq_list) || - add_acs_freq_list(msg, params->freq_list)) { + add_acs_freq_list(msg, params->freq_list) || + (params->edmg_enabled && + nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED))) { nlmsg_free(msg); return -ENOBUFS; } nla_nest_end(msg, data); wpa_printf(MSG_DEBUG, - "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d", + "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d EDMG: %d", params->hw_mode, params->ht_enabled, params->ht40_enabled, - params->vht_enabled, params->ch_width); + params->vht_enabled, params->ch_width, params->edmg_enabled); ret = send_and_recv_msgs(drv, msg, NULL, NULL); if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Failed to invoke driver ACS function: %s", - strerror(errno)); + strerror(-ret)); } return ret; } @@ -10313,7 +10509,7 @@ static int nl80211_set_band(void *priv, enum set_band band) if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Driver setband function failed: %s", - strerror(errno)); + strerror(-ret)); } return ret; } @@ -11204,6 +11400,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .get_hw_feature_data = nl80211_get_hw_feature_data, .sta_add = wpa_driver_nl80211_sta_add, .sta_remove = driver_nl80211_sta_remove, + .tx_control_port = nl80211_tx_control_port, .hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol, .sta_set_flags = wpa_driver_nl80211_sta_set_flags, .sta_set_airtime_weight = driver_nl80211_sta_set_airtime_weight, @@ -11234,7 +11431,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .signal_monitor = nl80211_signal_monitor, .signal_poll = nl80211_signal_poll, .channel_info = nl80211_channel_info, - .send_frame = nl80211_send_frame, .set_param = nl80211_set_param, .get_radio_name = nl80211_get_radio_name, .add_pmkid = nl80211_add_pmkid, @@ -11269,6 +11465,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #endif /* ANDROID */ .vendor_cmd = nl80211_vendor_cmd, .set_qos_map = nl80211_set_qos_map, + .get_wowlan = nl80211_get_wowlan, .set_wowlan = nl80211_set_wowlan, .set_mac_addr = nl80211_set_mac_addr, #ifdef CONFIG_MESH diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 716504c1..6e6c8724 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -17,12 +17,10 @@ #include "utils/list.h" #include "driver.h" -#ifdef CONFIG_LIBNL20 -/* libnl 2.0 compatibility code */ -#define nl_handle nl_sock -#define nl80211_handle_alloc nl_socket_alloc_cb -#define nl80211_handle_destroy nl_socket_free -#endif /* CONFIG_LIBNL20 */ +#ifndef NL_CAPABILITY_VERSION_3_5_0 +#define nla_nest_start(msg, attrtype) \ + nla_nest_start(msg, NLA_F_NESTED | (attrtype)) +#endif struct nl80211_global { void *ctx; @@ -32,11 +30,11 @@ struct nl80211_global { int if_add_wdevid_set; struct netlink_data *netlink; struct nl_cb *nl_cb; - struct nl_handle *nl; + struct nl_sock *nl; int nl80211_id; int ioctl_sock; /* socket for ioctl() use */ - struct nl_handle *nl_event; + struct nl_sock *nl_event; }; struct nl80211_wiphy_data { @@ -44,7 +42,7 @@ struct nl80211_wiphy_data { struct dl_list bsss; struct dl_list drvs; - struct nl_handle *nl_beacons; + struct nl_sock *nl_beacons; struct nl_cb *nl_cb; int wiphy_idx; @@ -75,7 +73,7 @@ struct i802_bss { int if_dynamic; void *ctx; - struct nl_handle *nl_preq, *nl_mgmt, *nl_connect; + struct nl_sock *nl_preq, *nl_mgmt, *nl_connect; struct nl_cb *nl_cb; struct nl80211_wiphy_data *wiphy_data; @@ -176,10 +174,10 @@ struct wpa_driver_nl80211_data { u64 vendor_scan_cookie; u64 remain_on_chan_cookie; - u64 send_action_cookie; -#define MAX_SEND_ACTION_COOKIES 20 - u64 send_action_cookies[MAX_SEND_ACTION_COOKIES]; - unsigned int num_send_action_cookies; + u64 send_frame_cookie; +#define MAX_SEND_FRAME_COOKIES 20 + u64 send_frame_cookies[MAX_SEND_FRAME_COOKIES]; + unsigned int num_send_frame_cookies; unsigned int last_mgmt_freq; @@ -192,7 +190,7 @@ struct wpa_driver_nl80211_data { int eapol_sock; /* socket for EAPOL frames */ - struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */ + struct nl_sock *rtnl_sk; /* nl_sock for NETLINK_ROUTE */ struct drv_nl80211_if_info default_if_indices[16]; struct drv_nl80211_if_info *if_indices; @@ -256,7 +254,7 @@ int wpa_driver_nl80211_set_mode(struct i802_bss *bss, int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv, const u8 *addr, int cmd, u16 reason_code, int local_state_change, - struct nl_handle *nl_connect); + struct nl_sock *nl_connect); int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv); void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv); @@ -275,7 +273,7 @@ int process_bss_event(struct nl_msg *msg, void *arg); const char * nl80211_iftype_str(enum nl80211_iftype mode); #ifdef ANDROID -int android_nl_socket_set_nonblocking(struct nl_handle *handle); +int android_nl_socket_set_nonblocking(struct nl_sock *handle); int android_pno_start(struct i802_bss *bss, struct wpa_driver_scan_params *params); int android_pno_stop(struct i802_bss *bss); diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c index ba478888..9431a12d 100644 --- a/src/drivers/driver_nl80211_android.c +++ b/src/drivers/driver_nl80211_android.c @@ -182,9 +182,7 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon, #endif /* ANDROID_P2P */ -int android_nl_socket_set_nonblocking(struct nl_handle *handle) +int android_nl_socket_set_nonblocking(struct nl_sock *handle) { return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK); } - - diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 9a82cd1e..b4fed9ea 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -78,6 +78,7 @@ struct wiphy_info_data { unsigned int wmm_ac_supported:1; unsigned int mac_addr_rand_scan_supported:1; unsigned int mac_addr_rand_sched_scan_supported:1; + unsigned int update_ft_ies_supported:1; }; @@ -243,6 +244,9 @@ static void wiphy_info_supp_cmds(struct wiphy_info_data *info, case NL80211_CMD_SET_QOS_MAP: info->set_qos_map_supported = 1; break; + case NL80211_CMD_UPDATE_FT_IES: + info->update_ft_ies_supported = 1; + break; } } } @@ -433,6 +437,26 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info, if (ext_feature_isset(ext_features, len, NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER)) capa->flags |= WPA_DRIVER_FLAGS_FTM_RESPONDER; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211)) + capa->flags |= WPA_DRIVER_FLAGS_CONTROL_PORT; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_VLAN_OFFLOAD)) + capa->flags |= WPA_DRIVER_FLAGS_VLAN_OFFLOAD; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_CAN_REPLACE_PTK0)) + capa->flags |= WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_BEACON_PROTECTION)) + capa->flags |= WPA_DRIVER_FLAGS_BEACON_PROTECTION; + + if (ext_feature_isset(ext_features, len, + NL80211_EXT_FEATURE_EXT_KEY_ID)) + capa->flags |= WPA_DRIVER_FLAGS_EXTENDED_KEY_ID; } @@ -479,12 +503,6 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info, if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR) info->mac_addr_rand_sched_scan_supported = 1; - if (flags & NL80211_FEATURE_STATIC_SMPS) - capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC; - - if (flags & NL80211_FEATURE_DYNAMIC_SMPS) - capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC; - if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION) info->wmm_ac_supported = 1; @@ -904,6 +922,9 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv, drv->capa.max_sched_scan_plan_iterations = 0; } + if (info->update_ft_ies_supported) + drv->capa.flags |= WPA_DRIVER_FLAGS_UPDATE_FT_IES; + return 0; } @@ -1294,6 +1315,12 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_SIMULTANEOUS; #endif /* CONFIG_DRIVER_NL80211_QCA */ + wpa_printf(MSG_DEBUG, + "nl80211: key_mgmt=0x%x enc=0x%x auth=0x%x flags=0x%llx rrm_flags=0x%x probe_resp_offloads=0x%x max_stations=%u max_remain_on_chan=%u max_scan_ssids=%d", + drv->capa.key_mgmt, drv->capa.enc, drv->capa.auth, + (unsigned long long) drv->capa.flags, drv->capa.rrm_flags, + drv->capa.probe_resp_offloads, drv->capa.max_stations, + drv->capa.max_remain_on_chan, drv->capa.max_scan_ssids); return 0; } @@ -1360,6 +1387,20 @@ static int phy_info_edmg_capa(struct hostapd_hw_modes *mode, } +static int cw2ecw(unsigned int cw) +{ + int bit; + + if (cw == 0) + return 0; + + for (bit = 1; cw != 1; bit++) + cw >>= 1; + + return bit; +} + + static void phy_info_freq(struct hostapd_hw_modes *mode, struct hostapd_channel_data *chan, struct nlattr *tb_freq[]) @@ -1432,6 +1473,12 @@ static void phy_info_freq(struct hostapd_hw_modes *mode, [NL80211_WMMR_AIFSN] = { .type = NLA_U8 }, [NL80211_WMMR_TXOP] = { .type = NLA_U16 }, }; + static const u8 wmm_map[4] = { + [NL80211_AC_BE] = WMM_AC_BE, + [NL80211_AC_BK] = WMM_AC_BK, + [NL80211_AC_VI] = WMM_AC_VI, + [NL80211_AC_VO] = WMM_AC_VO, + }; struct nlattr *nl_wmm; struct nlattr *tb_wmm[NL80211_WMMR_MAX + 1]; int rem_wmm, ac, count = 0; @@ -1453,16 +1500,19 @@ static void phy_info_freq(struct hostapd_hw_modes *mode, return; } ac = nl_wmm->nla_type; - if (ac < 0 || ac >= WMM_AC_NUM) { + if ((unsigned int) ac >= ARRAY_SIZE(wmm_map)) { wpa_printf(MSG_DEBUG, "nl80211: Invalid AC value %d", ac); return; } + ac = wmm_map[ac]; chan->wmm_rules[ac].min_cwmin = - nla_get_u16(tb_wmm[NL80211_WMMR_CW_MIN]); + cw2ecw(nla_get_u16( + tb_wmm[NL80211_WMMR_CW_MIN])); chan->wmm_rules[ac].min_cwmax = - nla_get_u16(tb_wmm[NL80211_WMMR_CW_MAX]); + cw2ecw(nla_get_u16( + tb_wmm[NL80211_WMMR_CW_MAX])); chan->wmm_rules[ac].min_aifs = nla_get_u8(tb_wmm[NL80211_WMMR_AIFSN]); chan->wmm_rules[ac].max_txop = diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 2aecc749..d4ca2eb2 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -683,29 +683,42 @@ static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv, size_t len, struct nlattr *ack) { union wpa_event_data event; - const struct ieee80211_hdr *hdr; - u16 fc; + const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame; + u16 fc = le_to_host16(hdr->frame_control); + u64 cookie_val = 0; - wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event"); - if (!is_ap_interface(drv->nlmode)) { - u64 cookie_val; + if (cookie) + cookie_val = nla_get_u64(cookie); + wpa_printf(MSG_DEBUG, + "nl80211: Frame TX status event A1=" MACSTR + " %sstype=%d cookie=0x%llx%s ack=%d", + MAC2STR(hdr->addr1), + WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ? "not-mgmt " : "", + WLAN_FC_GET_STYPE(fc), (long long unsigned int) cookie_val, + cookie ? "" : "(N/A)", ack != NULL); + + if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) + return; + if (!is_ap_interface(drv->nlmode) && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) { if (!cookie) return; - cookie_val = nla_get_u64(cookie); - wpa_printf(MSG_DEBUG, "nl80211: Action TX status:" - " cookie=0x%llx%s (ack=%d)", + wpa_printf(MSG_DEBUG, + "nl80211: Frame TX status: cookie=0x%llx%s (ack=%d)", (long long unsigned int) cookie_val, - cookie_val == drv->send_action_cookie ? + cookie_val == drv->send_frame_cookie ? " (match)" : " (unknown)", ack != NULL); - if (cookie_val != drv->send_action_cookie) + if (cookie_val != drv->send_frame_cookie) return; + } else if (!is_ap_interface(drv->nlmode) && + WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) { + wpa_printf(MSG_DEBUG, + "nl80211: Authentication frame TX status: ack=%d", + !!ack); } - hdr = (const struct ieee80211_hdr *) frame; - fc = le_to_host16(hdr->frame_control); - os_memset(&event, 0, sizeof(event)); event.tx_status.type = WLAN_FC_GET_TYPE(fc); event.tx_status.stype = WLAN_FC_GET_STYPE(fc); @@ -1740,8 +1753,41 @@ static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode) } -static unsigned int chan_2ghz_or_5ghz_to_freq(u8 chan) +static unsigned int chan_to_freq(struct wpa_driver_nl80211_data *drv, + u8 chan, enum hostapd_hw_mode hw_mode) { + if (hw_mode == NUM_HOSTAPD_MODES) { + /* For drivers that do not report ACS_HW_MODE */ + u16 num_modes, flags; + struct hostapd_hw_modes *modes; + u8 dfs_domain; + int i; + + modes = nl80211_get_hw_feature_data(drv->first_bss, &num_modes, + &flags, &dfs_domain); + if (!modes) { + wpa_printf(MSG_DEBUG, + "nl80211: Fetching hardware mode failed"); + goto try_2_4_or_5; + } + if (num_modes == 1) + hw_mode = modes[0].mode; + + for (i = 0; i < num_modes; i++) { + os_free(modes[i].channels); + os_free(modes[i].rates); + } + + os_free(modes); + } + + if (hw_mode == HOSTAPD_MODE_IEEE80211AD) { + if (chan >= 1 && chan <= 6) + return 56160 + (2160 * chan); + return 0; + } + +try_2_4_or_5: if (chan >= 1 && chan <= 13) return 2407 + 5 * chan; if (chan == 14) @@ -1772,13 +1818,30 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, return; os_memset(&event, 0, sizeof(event)); + event.acs_selected_channels.hw_mode = NUM_HOSTAPD_MODES; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { + u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); + + event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode); + if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES || + event.acs_selected_channels.hw_mode == + HOSTAPD_MODE_IEEE80211ANY) { + wpa_printf(MSG_DEBUG, + "nl80211: Invalid hw_mode %d in ACS selection event", + hw_mode); + return; + } + } + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]) { event.acs_selected_channels.pri_freq = nla_get_u32( tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY]); } else { chan = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]); event.acs_selected_channels.pri_freq = - chan_2ghz_or_5ghz_to_freq(chan); + chan_to_freq(drv, chan, + event.acs_selected_channels.hw_mode); } if (tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY]) { @@ -1788,40 +1851,31 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, chan = nla_get_u8( tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]); event.acs_selected_channels.sec_freq = - chan_2ghz_or_5ghz_to_freq(chan); + chan_to_freq(drv, chan, + event.acs_selected_channels.hw_mode); } + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL]) + event.acs_selected_channels.edmg_channel = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL]); if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) event.acs_selected_channels.vht_seg0_center_ch = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]); - if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]) event.acs_selected_channels.vht_seg1_center_ch = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]); if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) event.acs_selected_channels.ch_width = nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); - if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { - u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); - - event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode); - if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES || - event.acs_selected_channels.hw_mode == - HOSTAPD_MODE_IEEE80211ANY) { - wpa_printf(MSG_DEBUG, - "nl80211: Invalid hw_mode %d in ACS selection event", - hw_mode); - return; - } - } - wpa_printf(MSG_INFO, - "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d", + "nl80211: ACS Results: PFreq: %d SFreq: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d EDMGCH: %d", event.acs_selected_channels.pri_freq, event.acs_selected_channels.sec_freq, event.acs_selected_channels.ch_width, event.acs_selected_channels.vht_seg0_center_ch, event.acs_selected_channels.vht_seg1_center_ch, - event.acs_selected_channels.hw_mode); + event.acs_selected_channels.hw_mode, + event.acs_selected_channels.edmg_channel); /* Ignore ACS channel list check for backwards compatibility */ @@ -2448,6 +2502,18 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv, } +static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, + struct nlattr **tb) +{ + if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_FRAME]) + return; + + drv_event_eapol_rx(drv->ctx, nla_data(tb[NL80211_ATTR_MAC]), + nla_data(tb[NL80211_ATTR_FRAME]), + nla_len(tb[NL80211_ATTR_FRAME])); +} + + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -2663,6 +2729,9 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_UPDATE_OWE_INFO: mlme_event_dh_event(drv, bss, tb); break; + case NL80211_CMD_CONTROL_PORT_FRAME: + nl80211_control_port_frame(drv, tb); + break; default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c index f25cd792..7ff55f14 100644 --- a/src/drivers/driver_nl80211_monitor.c +++ b/src/drivers/driver_nl80211_monitor.c @@ -71,6 +71,9 @@ static void handle_frame(struct wpa_driver_nl80211_data *drv, u16 fc; union wpa_event_data event; + if (!drv->use_monitor) + return; + hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 9afa5b30..04f6bb87 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -236,6 +236,11 @@ nl80211_scan_common(struct i802_bss *bss, u8 cmd, params->filter_ssids = NULL; drv->num_filter_ssids = params->num_filter_ssids; + if (!drv->hostapd && is_ap_interface(drv->nlmode)) { + wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_AP"); + scan_flags |= NL80211_SCAN_FLAG_AP; + } + if (params->only_new_results) { wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH"); scan_flags |= NL80211_SCAN_FLAG_FLUSH; @@ -928,7 +933,9 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) struct wpa_scan_results *res; int ret; struct nl80211_bss_info_arg arg; + int count = 0; +try_again: res = os_zalloc(sizeof(*res)); if (res == NULL) return NULL; @@ -941,6 +948,18 @@ nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv) arg.drv = drv; arg.res = res; ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg); + if (ret == -EAGAIN) { + count++; + if (count >= 10) { + wpa_printf(MSG_INFO, + "nl80211: Failed to receive consistent scan result dump"); + } else { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to receive consistent scan result dump - try again"); + wpa_scan_results_free(res); + goto try_again; + } + } if (ret == 0) { struct nl80211_noise_info info; diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c index 6ff3eae6..ccd2d9da 100644 --- a/src/drivers/driver_none.c +++ b/src/drivers/driver_none.c @@ -43,13 +43,6 @@ static void none_driver_hapd_deinit(void *priv) } -static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src, - u16 proto, const u8 *data, size_t data_len) -{ - return 0; -} - - static void * none_driver_init(void *ctx, const char *ifname) { struct none_driver_data *drv; @@ -79,7 +72,6 @@ const struct wpa_driver_ops wpa_driver_none_ops = { .desc = "no driver (RADIUS server/WPS ER)", .hapd_init = none_driver_hapd_init, .hapd_deinit = none_driver_hapd_deinit, - .send_ether = none_driver_send_ether, .init = none_driver_init, .deinit = none_driver_deinit, }; diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c index c06e75c0..bfc23117 100644 --- a/src/drivers/driver_openbsd.c +++ b/src/drivers/driver_openbsd.c @@ -69,14 +69,16 @@ wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa) static int -wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const unsigned char *addr, int key_idx, int set_tx, const u8 *seq, - size_t seq_len, const u8 *key, size_t key_len) +wpa_driver_openbsd_set_key(void *priv, struct wpa_driver_set_key_params *params) { struct openbsd_driver_data *drv = priv; struct ieee80211_keyavail keyavail; + enum key_flag key_flag = params->key_flag; + const u8 *key = params->key; + size_t key_len = params->key_len; - if (alg != WPA_ALG_PMK || key_len > IEEE80211_PMK_LEN) + if (key_len > IEEE80211_PMK_LEN || + (key_flag & KEY_FLAG_PMK_MASK) != KEY_FLAG_PMK) { return -1; memset(&keyavail, 0, sizeof(keyavail)); diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c index 55cf6188..d6735b49 100644 --- a/src/drivers/driver_privsep.c +++ b/src/drivers/driver_privsep.c @@ -205,14 +205,19 @@ wpa_driver_privsep_get_scan_results2(void *priv) } -static int wpa_driver_privsep_set_key(const char *ifname, void *priv, - enum wpa_alg alg, const u8 *addr, - int key_idx, int set_tx, - const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) +static int wpa_driver_privsep_set_key(void *priv, + struct wpa_driver_set_key_params *params) { struct wpa_driver_privsep_data *drv = priv; struct privsep_cmd_set_key cmd; + enum wpa_alg alg = params->alg; + const u8 *addr = params->addr; + int key_idx = params->key_idx; + int set_tx = params->set_tx; + const u8 *seq = params->seq; + size_t seq_len = params->seq_len; + const u8 *key = params->key; + size_t key_len = params->key_len; wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d", __func__, priv, alg, key_idx, set_tx); @@ -225,6 +230,7 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv, os_memset(cmd.addr, 0xff, ETH_ALEN); cmd.key_idx = key_idx; cmd.set_tx = set_tx; + cmd.key_flag = params->key_flag; if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) { os_memcpy(cmd.seq, seq, seq_len); cmd.seq_len = seq_len; @@ -791,6 +797,8 @@ static int wpa_driver_privsep_get_capa(void *priv, capa->extended_capa = NULL; capa->extended_capa_mask = NULL; capa->extended_capa_len = 0; + /* Control port is not yet supported */ + capa->flags &= ~WPA_DRIVER_FLAGS_CONTROL_PORT; return 0; } diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index 32c29713..978e1cf4 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -1712,7 +1712,8 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) + const u8 *key, size_t key_len, + enum key_flag key_flag) { struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; @@ -1751,30 +1752,31 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, os_memcpy(ext + 1, key, key_len); ext->key_len = key_len; } - switch (alg) { - case WPA_ALG_NONE: - ext->alg = IW_ENCODE_ALG_NONE; - break; - case WPA_ALG_WEP: - ext->alg = IW_ENCODE_ALG_WEP; - break; - case WPA_ALG_TKIP: - ext->alg = IW_ENCODE_ALG_TKIP; - break; - case WPA_ALG_CCMP: - ext->alg = IW_ENCODE_ALG_CCMP; - break; - case WPA_ALG_PMK: + if (key_flag & KEY_FLAG_PMK) { ext->alg = IW_ENCODE_ALG_PMK; - break; - case WPA_ALG_IGTK: - ext->alg = IW_ENCODE_ALG_AES_CMAC; - break; - default: - wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", - __FUNCTION__, alg); - os_free(ext); - return -1; + } else { + switch (alg) { + case WPA_ALG_NONE: + ext->alg = IW_ENCODE_ALG_NONE; + break; + case WPA_ALG_WEP: + ext->alg = IW_ENCODE_ALG_WEP; + break; + case WPA_ALG_TKIP: + ext->alg = IW_ENCODE_ALG_TKIP; + break; + case WPA_ALG_CCMP: + ext->alg = IW_ENCODE_ALG_CCMP; + break; + case WPA_ALG_IGTK: + ext->alg = IW_ENCODE_ALG_AES_CMAC; + break; + default: + wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d", + __FUNCTION__, alg); + os_free(ext); + return -1; + } } if (seq && seq_len) { @@ -1803,37 +1805,27 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg, /** * wpa_driver_wext_set_key - Configure encryption key * @priv: Pointer to private wext data from wpa_driver_wext_init() - * @priv: Private driver interface data - * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP, - * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key. - * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for - * broadcast/default keys - * @key_idx: key index (0..3), usually 0 for unicast keys - * @set_tx: Configure this key as the default Tx key (only used when - * driver does not support separate unicast/individual key - * @seq: Sequence number/packet number, seq_len octets, the next - * packet number to be used for in replay protection; configured - * for Rx keys (in most cases, this is only used with broadcast - * keys and set to zero for unicast keys) - * @seq_len: Length of the seq, depends on the algorithm: - * TKIP: 6 octets, CCMP: 6 octets - * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key, - * 8-byte Rx Mic Key - * @key_len: Length of the key buffer in octets (WEP: 5 or 13, - * TKIP: 32, CCMP: 16) + * @params: Key parameters * Returns: 0 on success, -1 on failure * * This function uses SIOCSIWENCODEEXT by default, but tries to use * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key. */ -int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const u8 *addr, int key_idx, - int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) +static int wpa_driver_wext_set_key(void *priv, + struct wpa_driver_set_key_params *params) { struct wpa_driver_wext_data *drv = priv; struct iwreq iwr; int ret = 0; + enum wpa_alg alg = params->alg; + enum key_flag key_flag = params->key_flag; + const u8 *addr = params->addr; + int key_idx = params->key_idx; + int set_tx = params->set_tx; + const u8 *seq = params->seq; + size_t seq_len = params->seq_len; + const u8 *key = params->key; + size_t key_len = params->key_len; wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu " "key_len=%lu", @@ -1841,7 +1833,7 @@ int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, (unsigned long) seq_len, (unsigned long) key_len); ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx, - seq, seq_len, key, key_len); + seq, seq_len, key, key_len, key_flag); if (ret == 0) return 0; diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h index b4b5960a..6214cdf4 100644 --- a/src/drivers/driver_wext.h +++ b/src/drivers/driver_wext.h @@ -52,10 +52,6 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid); int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len); int wpa_driver_wext_set_freq(void *priv, int freq); int wpa_driver_wext_set_mode(void *priv, int mode); -int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg, - const u8 *addr, int key_idx, - int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len); int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params); struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv); diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index bc2e87e0..55a98ef8 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -176,7 +176,6 @@ endif ifdef CONFIG_LIBNL32 DRV_LIBS += -lnl-3 DRV_LIBS += -lnl-genl-3 - DRV_CFLAGS += -DCONFIG_LIBNL20 ifdef LIBNL_INC DRV_CFLAGS += -I$(LIBNL_INC) else @@ -193,14 +192,8 @@ else else ifndef CONFIG_OSX DRV_LIBS += -lnl - endif - endif - - ifdef CONFIG_LIBNL20 - ifndef CONFIG_LIBNL_TINY DRV_LIBS += -lnl-genl endif - DRV_CFLAGS += -DCONFIG_LIBNL20 endif endif endif diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk index c3c2c0fe..5a32a242 100644 --- a/src/drivers/drivers.mk +++ b/src/drivers/drivers.mk @@ -160,7 +160,7 @@ ifdef NEED_LIBNL ifdef CONFIG_LIBNL32 DRV_LIBS += -lnl-3 DRV_LIBS += -lnl-genl-3 - DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 + DRV_CFLAGS += -I/usr/include/libnl3 ifdef CONFIG_LIBNL3_ROUTE DRV_LIBS += -lnl-route-3 DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE @@ -170,13 +170,7 @@ else DRV_LIBS += -lnl-tiny else DRV_LIBS += -lnl - endif - - ifdef CONFIG_LIBNL20 - ifndef CONFIG_LIBNL_TINY - DRV_LIBS += -lnl-genl - endif - DRV_CFLAGS += -DCONFIG_LIBNL20 + DRV_LIBS += -lnl-genl endif endif endif diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 341e0e8c..38835b58 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -11,7 +11,7 @@ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com> * Copyright 2008 Colin McCabe <colin@cozybit.com> * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2019 Intel Corporation + * Copyright (C) 2018-2020 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -265,6 +265,29 @@ */ /** + * DOC: TID configuration + * + * TID config support can be checked in the %NL80211_ATTR_TID_CONFIG + * attribute given in wiphy capabilities. + * + * The necessary configuration parameters are mentioned in + * &enum nl80211_tid_config_attr and it will be passed to the + * %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG. + * + * If the configuration needs to be applied for specific peer then the MAC + * address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the + * configuration will be applied for all the connected peers in the vif except + * any peers that have peer specific configuration for the TID by default; if + * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values + * will be overwritten. + * + * All this configuration is valid only for STA's current connection + * i.e. the configuration will be reset to default when the STA connects back + * after disconnection/roaming, and this configuration will be cleared when + * the interface goes down. + */ + +/** * enum nl80211_commands - supported nl80211 commands * * @NL80211_CMD_UNSPEC: unspecified command to catch errors @@ -1125,6 +1148,9 @@ * peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame * content. The frame is ethernet data. * + * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration + * is passed using %NL80211_ATTR_TID_CONFIG attribute. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1349,6 +1375,8 @@ enum nl80211_commands { NL80211_CMD_PROBE_MESH_LINK, + NL80211_CMD_SET_TID_CONFIG, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1604,7 +1632,8 @@ enum nl80211_commands { * flag is included, then control port frames are sent over NL80211 instead * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER - * flag. + * flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth + * frames are not forwared over the control port. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -2400,6 +2429,47 @@ enum nl80211_commands { * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key * (u16). * + * @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings. + * + * @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry + * using attributes from &enum nl80211_iftype_akm_attributes. This + * attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating + * supported AKM suites capability per interface. AKMs advertised in + * %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not + * advertised for a specific interface type. + * + * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a + * nested attribute with &enum nl80211_tid_config_attr sub-attributes; + * on output (in wiphy attributes) it contains only the feature sub- + * attributes. + * + * @NL80211_ATTR_CONTROL_PORT_NO_PREAUTH: disable preauth frame rx on control + * port in order to forward/receive them as ordinary data frames. + * + * @NL80211_ATTR_PMK_LIFETIME: Maximum lifetime for PMKSA in seconds (u32, + * dot11RSNAConfigPMKReauthThreshold; 0 is not a valid value). + * An optional parameter configured through %NL80211_CMD_SET_PMKSA. + * Drivers that trigger roaming need to know the lifetime of the + * configured PMKSA for triggering the full vs. PMKSA caching based + * authentication. This timeout helps authentication methods like SAE, + * where PMK gets updated only by going through a full (new SAE) + * authentication instead of getting updated during an association for EAP + * authentication. No new full authentication within the PMK expiry shall + * result in a disassociation at the end of the lifetime. + * + * @NL80211_ATTR_PMK_REAUTH_THRESHOLD: Reauthentication threshold time, in + * terms of percentage of %NL80211_ATTR_PMK_LIFETIME + * (u8, dot11RSNAConfigPMKReauthThreshold, 1..100). This is an optional + * parameter configured through %NL80211_CMD_SET_PMKSA. Requests the + * driver to trigger a full authentication roam (without PMKSA caching) + * after the reauthentication threshold time, but before the PMK lifetime + * has expired. + * + * Authentication methods like SAE need to be able to generate a new PMKSA + * entry without having to force a disconnection after the PMK timeout. If + * no roaming occurs between the reauth threshold and PMK expiration, + * disassociation is still forced. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2864,6 +2934,17 @@ enum nl80211_attrs { NL80211_ATTR_VLAN_ID, + NL80211_ATTR_HE_BSS_COLOR, + + NL80211_ATTR_IFTYPE_AKM_SUITES, + + NL80211_ATTR_TID_CONFIG, + + NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, + + NL80211_ATTR_PMK_LIFETIME, + NL80211_ATTR_PMK_REAUTH_THRESHOLD, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -3583,6 +3664,8 @@ enum nl80211_wmm_rule { * @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations. * This is a nested attribute that contains the wmm limitation per AC. * (see &enum nl80211_wmm_rule) + * @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel + * in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -3612,6 +3695,7 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_20MHZ, NL80211_FREQUENCY_ATTR_NO_10MHZ, NL80211_FREQUENCY_ATTR_WMM, + NL80211_FREQUENCY_ATTR_NO_HE, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -3809,6 +3893,7 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed + * @NL80211_RRF_NO_HE: HE operation not allowed */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -3826,6 +3911,7 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_HT40PLUS = 1<<14, NL80211_RRF_NO_80MHZ = 1<<15, NL80211_RRF_NO_160MHZ = 1<<16, + NL80211_RRF_NO_HE = 1<<17, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR @@ -4532,6 +4618,7 @@ enum nl80211_key_default_types { * See &enum nl80211_key_default_types. * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode. * Defaults to @NL80211_KEY_RX_TX. + * @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key * * @__NL80211_KEY_AFTER_LAST: internal * @NL80211_KEY_MAX: highest key attribute @@ -4547,6 +4634,7 @@ enum nl80211_key_attributes { NL80211_KEY_TYPE, NL80211_KEY_DEFAULT_TYPES, NL80211_KEY_MODE, + NL80211_KEY_DEFAULT_BEACON, /* keep last */ __NL80211_KEY_AFTER_LAST, @@ -4703,6 +4791,69 @@ enum nl80211_tx_power_setting { }; /** + * enum nl80211_tid_config - TID config state + * @NL80211_TID_CONFIG_ENABLE: Enable config for the TID + * @NL80211_TID_CONFIG_DISABLE: Disable config for the TID + */ +enum nl80211_tid_config { + NL80211_TID_CONFIG_ENABLE, + NL80211_TID_CONFIG_DISABLE, +}; + +/* enum nl80211_tid_config_attr - TID specific configuration. + * @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values + * @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported + * for per-vif configuration; doesn't list the ones that are generic + * (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE). + * @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but + * per peer instead. + * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribute, if no peer + * is selected, if set indicates that the new configuration overrides + * all previous peer configurations, otherwise previous peer specific + * configurations should be left untouched. If peer is selected then + * it will reset particular TID configuration of that peer and it will + * not accept other TID config attributes along with peer. + * @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7) + * Its type is u16. + * @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID. + * specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config. + * Its type is u8. + * @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame + * transmission, user-space sets this configuration in + * &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and + * the max value is advertised by the driver in this attribute on + * output in wiphy capabilities. + * @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame + * transmission, user-space sets this configuration in + * &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and + * the max value is advertised by the driver in this attribute on + * output in wiphy capabilities. + * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable aggregation for the TIDs + * specified in %NL80211_TID_CONFIG_ATTR_TIDS. Its type is u8, using + * the values from &nl80211_tid_config. + * @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs + * specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using + * the values from &nl80211_tid_config. + */ +enum nl80211_tid_config_attr { + __NL80211_TID_CONFIG_ATTR_INVALID, + NL80211_TID_CONFIG_ATTR_PAD, + NL80211_TID_CONFIG_ATTR_VIF_SUPP, + NL80211_TID_CONFIG_ATTR_PEER_SUPP, + NL80211_TID_CONFIG_ATTR_OVERRIDE, + NL80211_TID_CONFIG_ATTR_TIDS, + NL80211_TID_CONFIG_ATTR_NOACK, + NL80211_TID_CONFIG_ATTR_RETRY_SHORT, + NL80211_TID_CONFIG_ATTR_RETRY_LONG, + NL80211_TID_CONFIG_ATTR_AMPDU_CTRL, + NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL, + + /* keep last */ + __NL80211_TID_CONFIG_ATTR_AFTER_LAST, + NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1 +}; + +/** * enum nl80211_packet_pattern_attr - packet pattern attribute * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute * @NL80211_PKTPAT_PATTERN: the pattern, values where the mask has @@ -5517,6 +5668,22 @@ enum nl80211_feature_flags { * with VLAN tagged frames and separate VLAN-specific netdevs added using * vconfig similarly to the Ethernet case. * + * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL) + * feature, which prevents bufferbloat by using the expected transmission + * time to limit the amount of data buffered in the hardware. + * + * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection + * and can receive key configuration for BIGTK using key indexes 6 and 7. + * + * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the + * forwarding of preauth frames over the control port. They are then + * handled as ordinary data frames. + * + * @NL80211_EXT_FEATURE_PROTECTED_TWT: Driver supports protected TWT frames + * + * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations + * in IBSS mode, essentially by dropping their state. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -5563,6 +5730,11 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_STA_TX_PWR, NL80211_EXT_FEATURE_SAE_OFFLOAD, NL80211_EXT_FEATURE_VLAN_OFFLOAD, + NL80211_EXT_FEATURE_AQL, + NL80211_EXT_FEATURE_BEACON_PROTECTION, + NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH, + NL80211_EXT_FEATURE_PROTECTED_TWT, + NL80211_EXT_FEATURE_DEL_IBSS_STA, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -6185,12 +6357,14 @@ enum nl80211_ftm_responder_stats { * @NL80211_PREAMBLE_HT: HT preamble * @NL80211_PREAMBLE_VHT: VHT preamble * @NL80211_PREAMBLE_DMG: DMG preamble + * @NL80211_PREAMBLE_HE: HE preamble */ enum nl80211_preamble { NL80211_PREAMBLE_LEGACY, NL80211_PREAMBLE_HT, NL80211_PREAMBLE_VHT, NL80211_PREAMBLE_DMG, + NL80211_PREAMBLE_HE, }; /** @@ -6383,6 +6557,10 @@ enum nl80211_peer_measurement_attrs { * is valid) * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating * the maximum FTMs per burst (if not present anything is valid) + * @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if + * trigger based ranging measurement is supported + * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating + * if non trigger based ranging measurement is supported * * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number @@ -6398,6 +6576,8 @@ enum nl80211_peer_measurement_ftm_capa { NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST, + NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED, /* keep last */ NUM_NL80211_PMSR_FTM_CAPA_ATTR, @@ -6427,6 +6607,20 @@ enum nl80211_peer_measurement_ftm_capa { * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag) * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data * (flag) + * @NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED: request trigger based ranging + * measurement (flag). + * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED are + * mutually exclusive. + * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based + * ranging will be used. + * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based + * ranging measurement (flag) + * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are + * mutually exclusive. + * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based + * ranging will be used. * * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number @@ -6443,6 +6637,8 @@ enum nl80211_peer_measurement_ftm_req { NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, + NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, /* keep last */ NUM_NL80211_PMSR_FTM_REQ_ATTR, @@ -6582,5 +6778,51 @@ enum nl80211_obss_pd_attributes { NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1, }; +/** + * enum nl80211_bss_color_attributes - BSS Color attributes + * @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid + * + * @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color. + * @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled. + * @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used.. + * + * @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal + * @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute. + */ +enum nl80211_bss_color_attributes { + __NL80211_HE_BSS_COLOR_ATTR_INVALID, + + NL80211_HE_BSS_COLOR_ATTR_COLOR, + NL80211_HE_BSS_COLOR_ATTR_DISABLED, + NL80211_HE_BSS_COLOR_ATTR_PARTIAL, + + /* keep last */ + __NL80211_HE_BSS_COLOR_ATTR_LAST, + NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1, +}; + +/** + * enum nl80211_iftype_akm_attributes - interface type AKM attributes + * @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid + * + * @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag + * attribute for each interface type that supports AKM suites specified in + * %NL80211_IFTYPE_AKM_ATTR_SUITES + * @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported + * AKM suites for the specified interface types. + * + * @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal + * @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute. + */ +enum nl80211_iftype_akm_attributes { + __NL80211_IFTYPE_AKM_ATTR_INVALID, + + NL80211_IFTYPE_AKM_ATTR_IFTYPES, + NL80211_IFTYPE_AKM_ATTR_SUITES, + + /* keep last */ + __NL80211_IFTYPE_AKM_ATTR_LAST, + NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1, +}; #endif /* __LINUX_NL80211_H */ diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c index 5a2ba261..2e79614f 100644 --- a/src/eapol_auth/eapol_auth_sm.c +++ b/src/eapol_auth/eapol_auth_sm.c @@ -648,6 +648,8 @@ SM_STEP(REAUTH_TIMER) +#ifdef CONFIG_WEP + /* Authenticator Key Transmit state machine */ SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT) @@ -726,6 +728,8 @@ SM_STEP(KEY_RX) } } +#endif /* CONFIG_WEP */ + /* Controlled Directions state machine */ @@ -813,10 +817,12 @@ eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr, sm->portControl = Auto; +#ifdef CONFIG_WEP if (!eapol->conf.wpa && (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0)) sm->keyTxEnabled = TRUE; else +#endif /* CONFIG_WEP */ sm->keyTxEnabled = FALSE; if (eapol->conf.wpa) sm->portValid = FALSE; @@ -910,10 +916,12 @@ restart: SM_STEP_RUN(BE_AUTH); if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(REAUTH_TIMER); +#ifdef CONFIG_WEP if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(AUTH_KEY_TX); if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(KEY_RX); +#endif /* CONFIG_WEP */ if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(CTRL_DIR); @@ -1167,7 +1175,9 @@ static int eapol_auth_conf_clone(struct eapol_auth_config *dst, dst->ctx = src->ctx; dst->eap_reauth_period = src->eap_reauth_period; dst->wpa = src->wpa; +#ifdef CONFIG_WEP dst->individual_wep_key_len = src->individual_wep_key_len; +#endif /* CONFIG_WEP */ os_free(dst->eap_req_id_text); if (src->eap_req_id_text) { dst->eap_req_id_text = os_memdup(src->eap_req_id_text, @@ -1221,10 +1231,12 @@ struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf, return NULL; } +#ifdef CONFIG_WEP if (conf->individual_wep_key_len > 0) { /* use key0 in individual key and key1 in broadcast key */ eapol->default_wep_key_idx = 1; } +#endif /* CONFIG_WEP */ eapol->cb.eapol_send = cb->eapol_send; eapol->cb.aaa_send = cb->aaa_send; @@ -1249,6 +1261,8 @@ void eapol_auth_deinit(struct eapol_authenticator *eapol) return; eapol_auth_conf_free(&eapol->conf); +#ifdef CONFIG_WEP os_free(eapol->default_wep_key); +#endif /* CONFIG_WEP */ os_free(eapol); } diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index f1ca0a85..7f04b010 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -200,6 +200,15 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx) } +static int eapol_sm_confirm_auth(struct eapol_sm *sm) +{ + if (!sm->ctx->confirm_auth_cb) + return 0; + + return sm->ctx->confirm_auth_cb(sm->ctx->ctx); +} + + static void eapol_enable_timer_tick(struct eapol_sm *sm) { if (sm->timer_tick_enabled) @@ -316,6 +325,11 @@ SM_STATE(SUPP_PAE, AUTHENTICATED) SM_STATE(SUPP_PAE, RESTART) { + if (eapol_sm_confirm_auth(sm)) { + /* Don't process restart, we are already reconnecting */ + return; + } + SM_ENTRY(SUPP_PAE, RESTART); sm->eapRestart = TRUE; if (sm->altAccept) { @@ -678,6 +692,7 @@ struct eap_key_data { static void eapol_sm_processKey(struct eapol_sm *sm) { +#ifdef CONFIG_WEP #ifndef CONFIG_FIPS struct ieee802_1x_hdr *hdr; struct ieee802_1x_eapol_key *key; @@ -828,7 +843,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm) if (sm->ctx->set_wep_key && sm->ctx->set_wep_key(sm->ctx->ctx, - key->key_index & IEEE8021X_KEY_INDEX_FLAG, + !!(key->key_index & IEEE8021X_KEY_INDEX_FLAG), key->key_index & IEEE8021X_KEY_INDEX_MASK, datakey, key_len) < 0) { wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " @@ -852,6 +867,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm) } } #endif /* CONFIG_FIPS */ +#endif /* CONFIG_WEP */ } diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index c9d7522d..67f82c60 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -298,6 +298,15 @@ struct eapol_ctx { * @len: Length of anonymous identity in octets */ void (*set_anon_id)(void *ctx, const u8 *id, size_t len); + + /** + * confirm_auth_cb - Callback confirming if we can install a new PTK + * @ctx: eapol_ctx from eap_peer_sm_init() call + * Returns: 0 when authentication can continue, -1 when reconnecting + * + * Automatically triggers a reconnect when not. + */ + int (*confirm_auth_cb)(void *ctx); }; diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 79de09ce..2dae6c6e 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -36,7 +36,7 @@ /** * P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class */ -#define P2P_MAX_REG_CLASS_CHANNELS 20 +#define P2P_MAX_REG_CLASS_CHANNELS 60 /** * struct p2p_channels - List of supported channels diff --git a/src/radius/radius.c b/src/radius/radius.c index 07240ea2..be16e27b 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -609,7 +609,7 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg, { if (msg->attr_used >= msg->attr_size) { size_t *nattr_pos; - int nlen = msg->attr_size * 2; + size_t nlen = msg->attr_size * 2; nattr_pos = os_realloc_array(msg->attr_pos, nlen, sizeof(*msg->attr_pos)); diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index a3db4048..2b7a604e 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -457,7 +457,7 @@ static int radius_client_retransmit(struct radius_client_data *radius, } /* retransmit; remove entry if too many attempts */ - if (entry->accu_attempts > RADIUS_CLIENT_MAX_FAILOVER * + if (entry->accu_attempts >= RADIUS_CLIENT_MAX_FAILOVER * RADIUS_CLIENT_NUM_FAILOVER * num_servers) { wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts"); @@ -507,7 +507,7 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) if (now.sec >= entry->next_try) { s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock : radius->acct_sock; - if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER || + if (entry->attempts >= RADIUS_CLIENT_NUM_FAILOVER || (s < 0 && entry->attempts > 0)) { if (entry->msg_type == RADIUS_ACCT || entry->msg_type == RADIUS_ACCT_INTERIM) @@ -1116,7 +1116,7 @@ radius_change_server(struct radius_client_data *radius, (!auth && entry->msg_type != RADIUS_ACCT)) continue; entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; - entry->attempts = 1; + entry->attempts = 0; entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; } diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index fa5215ca..e46c89a6 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -270,7 +270,9 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa, wpas_notify_pmk_cache_added((struct wpa_supplicant *)pmksa->sm->ctx->ctx, entry); wpa_sm_add_pmkid(pmksa->sm, entry->network_ctx, entry->aa, entry->pmkid, entry->fils_cache_id_set ? entry->fils_cache_id : NULL, - entry->pmk, entry->pmk_len); + entry->pmk, entry->pmk_len, + pmksa->sm->dot11RSNAConfigPMKLifetime, + pmksa->sm->dot11RSNAConfigPMKReauthThreshold); return entry; } @@ -374,9 +376,12 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, { struct rsn_pmksa_cache_entry *new_entry; os_time_t old_expiration = old_entry->expiration; + const u8 *pmkid = NULL; + if (wpa_key_mgmt_sae(old_entry->akmp)) + pmkid = old_entry->pmkid; new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len, - NULL, NULL, 0, + pmkid, NULL, 0, aa, pmksa->sm->own_addr, old_entry->network_ctx, old_entry->akmp, old_entry->fils_cache_id_set ? @@ -416,6 +421,20 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, while (entry) { if (entry->network_ctx == network_ctx && (!akmp || entry->akmp == akmp)) { + struct os_reltime now; + + if (wpa_key_mgmt_sae(entry->akmp) && + os_get_reltime(&now) == 0 && + entry->reauth_time < now.sec) { + wpa_printf(MSG_DEBUG, + "RSN: Do not clone PMKSA cache entry for " + MACSTR + " since its reauth threshold has passed", + MAC2STR(entry->aa)); + entry = entry->next; + continue; + } + entry = pmksa_cache_clone_entry(pmksa, entry, aa); if (entry) { wpa_printf(MSG_DEBUG, "RSN: added " @@ -519,6 +538,20 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, network_ctx, fils_cache_id); if (sm->cur_pmksa) { + struct os_reltime now; + + if (wpa_key_mgmt_sae(sm->cur_pmksa->akmp) && + os_get_reltime(&now) == 0 && + sm->cur_pmksa->reauth_time < now.sec) { + wpa_printf(MSG_DEBUG, + "RSN: Do not allow PMKSA cache entry for " + MACSTR + " to be used for SAE since its reauth threshold has passed", + MAC2STR(sm->cur_pmksa->aa)); + sm->cur_pmksa = NULL; + return -1; + } + wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", sm->cur_pmksa->pmkid, PMKID_LEN); return 0; diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c index d0c43f46..a1019217 100644 --- a/src/rsn_supp/preauth.c +++ b/src/rsn_supp/preauth.c @@ -49,6 +49,15 @@ void pmksa_candidate_free(struct wpa_sm *sm) } +static int rsn_preauth_key_mgmt(int akmp) +{ + return !!(akmp & (WPA_KEY_MGMT_IEEE8021X | + WPA_KEY_MGMT_IEEE8021X_SHA256 | + WPA_KEY_MGMT_IEEE8021X_SUITE_B | + WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)); +} + + static void rsn_preauth_receive(void *ctx, const u8 *src_addr, const u8 *buf, size_t len) { @@ -311,10 +320,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm) if (sm->preauth_eapol || sm->proto != WPA_PROTO_RSN || wpa_sm_get_state(sm) != WPA_COMPLETED || - (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X && - sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 && - sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B && - sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) { + !rsn_preauth_key_mgmt(sm->key_mgmt)) { wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable " "state for new pre-authentication"); return; /* invalid state for new pre-auth */ @@ -343,7 +349,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm) * PMKIDs again, so report the existing data now. */ if (p) { wpa_sm_add_pmkid(sm, NULL, candidate->bssid, p->pmkid, - NULL, p->pmk, p->pmk_len); + NULL, p->pmk, p->pmk_len, 0, 0); } dl_list_del(&candidate->list); @@ -488,6 +494,9 @@ void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid, !(ie.capabilities & WPA_CAPABILITY_PREAUTH))) return; + if (!rsn_preauth_key_mgmt(ie.key_mgmt)) + return; + /* Give less priority to candidates found from normal scan results. */ pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN, ie.capabilities & WPA_CAPABILITY_PREAUTH); diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 704c95e6..7b47e3ac 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -178,7 +178,7 @@ static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) { if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, - 0, 0, NULL, 0, NULL, 0) < 0) { + 0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) { wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " "the driver"); return -1; @@ -227,8 +227,9 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR, MAC2STR(peer->addr)); - if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, - rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { + if (wpa_sm_set_key(sm, alg, peer->addr, 0, 1, rsc, sizeof(rsc), + peer->tpk.tk, key_len, + KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " "driver"); return -1; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 892eece7..166d6eeb 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -183,6 +183,14 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) int key_info, ver; u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic; + if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id && + wpa_sm_get_state(sm) == WPA_COMPLETED) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: PTK0 rekey not allowed, reconnecting"); + wpa_sm_reconnect(sm); + return; + } + if (wpa_use_akm_defined(sm->key_mgmt)) ver = WPA_KEY_INFO_TYPE_AKM_DEFINED; else if (wpa_key_mgmt_ft(sm->key_mgmt) || @@ -570,6 +578,7 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, { const u8 *z = NULL; size_t z_len = 0; + int akmp; #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->key_mgmt)) @@ -583,13 +592,67 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, } #endif /* CONFIG_DPP2 */ + akmp = sm->key_mgmt; +#ifdef CONFIG_OWE + if (sm->owe_ptk_workaround && akmp == WPA_KEY_MGMT_OWE && + sm->pmk_len > 32) { + wpa_printf(MSG_DEBUG, + "OWE: Force SHA256 for PTK derivation"); + akmp |= WPA_KEY_MGMT_PSK_SHA256; + } +#endif /* CONFIG_OWE */ return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", sm->own_addr, sm->bssid, sm->snonce, - key->key_nonce, ptk, sm->key_mgmt, + key->key_nonce, ptk, akmp, sm->pairwise_cipher, z, z_len); } +static int wpa_handle_ext_key_id(struct wpa_sm *sm, + struct wpa_eapol_ie_parse *kde) +{ + if (sm->ext_key_id) { + u16 key_id; + + if (!kde->key_id) { + wpa_msg(sm->ctx->msg_ctx, + sm->use_ext_key_id ? MSG_INFO : MSG_DEBUG, + "RSN: No Key ID in Extended Key ID handshake"); + sm->keyidx_active = 0; + return sm->use_ext_key_id ? -1 : 0; + } + + key_id = kde->key_id[0] & 0x03; + if (key_id > 1) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: Invalid Extended Key ID: %d", key_id); + return -1; + } + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Using Extended Key ID %d", key_id); + sm->keyidx_active = key_id; + sm->use_ext_key_id = 1; + } else { + if (kde->key_id && (kde->key_id[0] & 0x03)) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "RSN: Non-zero Extended Key ID Key ID in PTK0 handshake"); + return -1; + } + + if (kde->key_id) { + /* This is not supposed to be included here, but ignore + * the case of matching Key ID 0 just in case. */ + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, + "RSN: Extended Key ID Key ID 0 in PTK0 handshake"); + } + sm->keyidx_active = 0; + sm->use_ext_key_id = 0; + } + + return 0; +} + + static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, @@ -608,6 +671,14 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, return; } + if (sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id && + wpa_sm_get_state(sm) == WPA_COMPLETED) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "WPA: PTK0 rekey not allowed, reconnecting"); + wpa_sm_reconnect(sm); + return; + } + wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); wpa_dbg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RX message 1 of 4-Way " "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); @@ -789,7 +860,8 @@ static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx) static int wpa_supplicant_install_ptk(struct wpa_sm *sm, - const struct wpa_eapol_key *key) + const struct wpa_eapol_key *key, + enum key_flag key_flag) { int keylen, rsclen; enum wpa_alg alg; @@ -833,12 +905,14 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen); } - if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen, - sm->ptk.tk, keylen) < 0) { + if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc, + rsclen, sm->ptk.tk, keylen, + KEY_FLAG_PAIRWISE | key_flag) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Failed to set PTK to the " - "driver (alg=%d keylen=%d bssid=" MACSTR ")", - alg, keylen, MAC2STR(sm->bssid)); + "WPA: Failed to set PTK to the driver (alg=%d keylen=%d bssid=" + MACSTR " idx=%d key_flag=0x%x)", + alg, keylen, MAC2STR(sm->bssid), + sm->keyidx_active, key_flag); return -1; } @@ -852,7 +926,23 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk, sm, NULL); } + return 0; +} + +static int wpa_supplicant_activate_ptk(struct wpa_sm *sm) +{ + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Activate PTK (idx=%d bssid=" MACSTR ")", + sm->keyidx_active, MAC2STR(sm->bssid)); + + if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, 0, NULL, 0, + NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Failed to activate PTK for TX (idx=%d bssid=" + MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid)); + return -1; + } return 0; } @@ -927,7 +1017,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, if (sm->pairwise_cipher == WPA_CIPHER_NONE) { if (wpa_sm_set_key(sm, gd->alg, NULL, gd->keyidx, 1, key_rsc, gd->key_rsc_len, - _gtk, gd->gtk_len) < 0) { + _gtk, gd->gtk_len, + KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to set GTK to the driver " "(Group only)"); @@ -936,7 +1027,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm, } } else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr, gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len, - _gtk, gd->gtk_len) < 0) { + _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to set GTK to " "the driver (alg=%d keylen=%d keyidx=%d)", @@ -1090,7 +1181,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm, if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), broadcast_ether_addr, keyidx, 0, igtk->pn, sizeof(igtk->pn), - igtk->igtk, len) < 0) { + igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) { if (keyidx == 0x0400 || keyidx == 0x0500) { /* Assume the AP has broken PMF implementation since it * seems to have swapped the KeyID bytes. The AP cannot @@ -1127,14 +1218,66 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm, } +static int wpa_supplicant_install_bigtk(struct wpa_sm *sm, + const struct wpa_bigtk_kde *bigtk, + int wnm_sleep) +{ + size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher); + u16 keyidx = WPA_GET_LE16(bigtk->keyid); + + /* Detect possible key reinstallation */ + if ((sm->bigtk.bigtk_len == len && + os_memcmp(sm->bigtk.bigtk, bigtk->bigtk, + sm->bigtk.bigtk_len) == 0) || + (sm->bigtk_wnm_sleep.bigtk_len == len && + os_memcmp(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk, + sm->bigtk_wnm_sleep.bigtk_len) == 0)) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)", + keyidx); + return 0; + } + + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: BIGTK keyid %d pn " COMPACT_MACSTR, + keyidx, MAC2STR(bigtk->pn)); + wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len); + if (keyidx < 6 || keyidx > 7) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Invalid BIGTK KeyID %d", keyidx); + return -1; + } + if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), + broadcast_ether_addr, + keyidx, 0, bigtk->pn, sizeof(bigtk->pn), + bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "WPA: Failed to configure BIGTK to the driver"); + return -1; + } + + if (wnm_sleep) { + sm->bigtk_wnm_sleep.bigtk_len = len; + os_memcpy(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk, + sm->bigtk_wnm_sleep.bigtk_len); + } else { + sm->bigtk.bigtk_len = len; + os_memcpy(sm->bigtk.bigtk, bigtk->bigtk, sm->bigtk.bigtk_len); + } + + return 0; +} + + static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie) { + size_t len; + if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher)) return 0; if (ie->igtk) { - size_t len; const struct wpa_igtk_kde *igtk; len = wpa_cipher_key_len(sm->mgmt_group_cipher); @@ -1146,6 +1289,18 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, return -1; } + if (ie->bigtk && sm->beacon_prot) { + const struct wpa_bigtk_kde *bigtk; + + len = wpa_cipher_key_len(sm->mgmt_group_cipher); + if (ie->bigtk_len != WPA_BIGTK_KDE_PREFIX_LEN + len) + return -1; + + bigtk = (const struct wpa_bigtk_kde *) ie->bigtk; + if (wpa_supplicant_install_bigtk(sm, bigtk, 0) < 0) + return -1; + } + return 0; } @@ -1332,11 +1487,10 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Could not find AP from " "the scan results"); - } else { - wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: Found the current AP from " - "updated scan results"); + return -1; } + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: Found the current AP from updated scan results"); } if (ie->wpa_ie == NULL && ie->rsn_ie == NULL && @@ -1380,6 +1534,11 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm, os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4"); + wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp", + sm->ap_rsnxe, sm->ap_rsnxe_len); + wpa_hexdump(MSG_INFO, "RSNXE in EAPOL-Key msg 3/4", + ie->rsnxe, ie->rsnxe_len); + wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS); return -1; } @@ -1486,6 +1645,9 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0) goto failed; + if (wpa_handle_ext_key_id(sm, &ie)) + goto failed; + if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: ANonce from message 1 of 4-Way Handshake " @@ -1531,6 +1693,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, } #endif /* CONFIG_OCV */ + if (sm->use_ext_key_id && + wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX)) + goto failed; + if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info, &sm->ptk) < 0) { goto failed; @@ -1542,7 +1708,14 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, sm->renew_snonce = 1; if (key_info & WPA_KEY_INFO_INSTALL) { - if (wpa_supplicant_install_ptk(sm, key)) + int res; + + if (sm->use_ext_key_id) + res = wpa_supplicant_activate_ptk(sm); + else + res = wpa_supplicant_install_ptk(sm, key, + KEY_FLAG_RX_TX); + if (res) goto failed; } @@ -1598,6 +1771,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, sm->cur_pmksa = sa; } + if (ie.transition_disable) + wpa_sm_transition_disable(sm, ie.transition_disable[0]); sm->msg_3_of_4_ok = 1; return; @@ -2784,6 +2959,8 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid) #ifdef CONFIG_P2P os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr)); #endif /* CONFIG_P2P */ + + sm->keyidx_active = 0; } @@ -2815,6 +2992,7 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm) /* Keys are not needed in the WPA state machine anymore */ wpa_sm_drop_sa(sm); + sm->keyidx_active = 0; sm->msg_3_of_4_ok = 0; os_memset(sm->bssid, 0, ETH_ALEN); @@ -2910,7 +3088,7 @@ void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx) /** - * wpa_sm_set_config - Notification of current configration change + * wpa_sm_set_config - Notification of current configuration change * @sm: Pointer to WPA state machine data from wpa_sm_init() * @config: Pointer to current network configuration * @@ -2937,6 +3115,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->wpa_ptk_rekey = config->wpa_ptk_rekey; sm->p2p = config->p2p; sm->wpa_rsc_relaxation = config->wpa_rsc_relaxation; + sm->owe_ptk_workaround = config->owe_ptk_workaround; #ifdef CONFIG_FILS if (config->fils_cache_id) { sm->fils_cache_id_set = 1; @@ -2946,6 +3125,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->fils_cache_id_set = 0; } #endif /* CONFIG_FILS */ + sm->beacon_prot = config->beacon_prot; } else { sm->network_ctx = NULL; sm->allowed_pairwise_cipher = 0; @@ -2956,6 +3136,8 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config) sm->wpa_ptk_rekey = 0; sm->p2p = 0; sm->wpa_rsc_relaxation = 0; + sm->owe_ptk_workaround = 0; + sm->beacon_prot = 0; } } @@ -3061,6 +3243,15 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, case WPA_PARAM_SAE_PWE: sm->sae_pwe = value; break; + case WPA_PARAM_DENY_PTK0_REKEY: + sm->wpa_deny_ptk0_rekey = value; + break; + case WPA_PARAM_EXT_KEY_ID: + sm->ext_key_id = value; + break; + case WPA_PARAM_USE_EXT_KEY_ID: + sm->use_ext_key_id = value; + break; default: break; } @@ -3135,6 +3326,18 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm) } +int wpa_sm_ext_key_id(struct wpa_sm *sm) +{ + return sm ? sm->ext_key_id : 0; +} + + +int wpa_sm_ext_key_id_active(struct wpa_sm *sm) +{ + return sm ? sm->use_ext_key_id : 0; +} + + int wpa_sm_ocv_enabled(struct wpa_sm *sm) { struct wpa_ie_data rsn; @@ -3510,6 +3713,14 @@ int wpa_sm_has_ptk(struct wpa_sm *sm) } +int wpa_sm_has_ptk_installed(struct wpa_sm *sm) +{ + if (!sm) + return 0; + return sm->ptk.installed; +} + + void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr) { os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN); @@ -3570,6 +3781,13 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) igtk = (const struct wpa_igtk_kde *) (buf + 2); if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0) return -1; + } else if (subelem_id == WNM_SLEEP_SUBELEM_BIGTK) { + const struct wpa_bigtk_kde *bigtk; + + bigtk = (const struct wpa_bigtk_kde *) (buf + 2); + if (sm->beacon_prot && + wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0) + return -1; } else { wpa_printf(MSG_DEBUG, "Unknown element id"); return -1; @@ -3753,13 +3971,13 @@ struct wpabuf * fils_build_auth(struct wpa_sm *sm, int dh_group, const u8 *md) wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_SESSION); wpabuf_put_data(buf, sm->fils_session, FILS_SESSION_LEN); - /* FILS Wrapped Data */ + /* Wrapped Data */ sm->fils_erp_pmkid_set = 0; if (erp_msg) { wpabuf_put_u8(buf, WLAN_EID_EXTENSION); /* Element ID */ wpabuf_put_u8(buf, 1 + wpabuf_len(erp_msg)); /* Length */ /* Element ID Extension */ - wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_WRAPPED_DATA); + wpabuf_put_u8(buf, WLAN_EID_EXT_WRAPPED_DATA); wpabuf_put_buf(buf, erp_msg); /* Calculate pending PMKID here so that we do not need to * maintain a copy of the EAP-Initiate/Reauth message. */ @@ -3964,16 +4182,16 @@ int fils_process_auth(struct wpa_sm *sm, const u8 *bssid, const u8 *data, goto fail; } - /* FILS Wrapped Data */ - if (!sm->cur_pmksa && elems.fils_wrapped_data) { + /* Wrapped Data */ + if (!sm->cur_pmksa && elems.wrapped_data) { u8 rmsk[ERP_MAX_KEY_LEN]; size_t rmsk_len; wpa_hexdump(MSG_DEBUG, "FILS: Wrapped Data", - elems.fils_wrapped_data, - elems.fils_wrapped_data_len); - eapol_sm_process_erp_finish(sm->eapol, elems.fils_wrapped_data, - elems.fils_wrapped_data_len); + elems.wrapped_data, + elems.wrapped_data_len); + eapol_sm_process_erp_finish(sm->eapol, elems.wrapped_data, + elems.wrapped_data_len); if (eapol_sm_failed(sm->eapol)) goto fail; @@ -4135,6 +4353,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf) capab |= WPA_CAPABILITY_MFPR; if (sm->ocv) capab |= WPA_CAPABILITY_OCVC; + if (sm->ext_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; wpabuf_put_le16(buf, capab); /* PMKID Count */ @@ -4562,11 +4782,12 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len) keylen, (long unsigned int) sm->ptk.tk_len); goto fail; } + rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher); wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver", sm->ptk.tk, keylen); if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen, - sm->ptk.tk, keylen) < 0) { + sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid=" MACSTR ")", @@ -4590,6 +4811,9 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len) sm->fils_completed = 1; forced_memzero(&gd, sizeof(gd)); + if (kde.transition_disable) + wpa_sm_transition_disable(sm, kde.transition_disable[0]); + return 0; fail: forced_memzero(&gd, sizeof(gd)); diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index f1fbb1bb..796f3920 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -27,10 +27,11 @@ struct wpa_sm_ctx { void (*set_state)(void *ctx, enum wpa_states state); enum wpa_states (*get_state)(void *ctx); void (*deauthenticate)(void * ctx, u16 reason_code); + void (*reconnect)(void *ctx); int (*set_key)(void *ctx, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len); + const u8 *key, size_t key_len, enum key_flag key_flag); void * (*get_network_ctx)(void *ctx); int (*get_bssid)(void *ctx, u8 *bssid); int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf, @@ -41,7 +42,8 @@ struct wpa_sm_ctx { size_t *msg_len, void **data_pos); int (*add_pmkid)(void *ctx, void *network_ctx, const u8 *bssid, const u8 *pmkid, const u8 *fils_cache_id, - const u8 *pmk, size_t pmk_len); + const u8 *pmk, size_t pmk_len, u32 pmk_lifetime, + u8 pmk_reauth_threshold); int (*remove_pmkid)(void *ctx, void *network_ctx, const u8 *bssid, const u8 *pmkid, const u8 *fils_cache_id); void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); @@ -84,6 +86,7 @@ struct wpa_sm_ctx { void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src, const u8 *pkt, size_t pkt_len); int (*channel_info)(void *ctx, struct wpa_channel_info *ci); + void (*transition_disable)(void *ctx, u8 bitmap); }; @@ -100,6 +103,9 @@ enum wpa_sm_conf_params { WPA_PARAM_MFP, WPA_PARAM_OCV, WPA_PARAM_SAE_PWE, + WPA_PARAM_DENY_PTK0_REKEY, + WPA_PARAM_EXT_KEY_ID, + WPA_PARAM_USE_EXT_KEY_ID, }; struct rsn_supp_config { @@ -111,9 +117,12 @@ struct rsn_supp_config { const u8 *ssid; size_t ssid_len; int wpa_ptk_rekey; + int wpa_deny_ptk0_rekey; int p2p; int wpa_rsc_relaxation; + int owe_ptk_workaround; const u8 *fils_cache_id; + int beacon_prot; }; #ifndef CONFIG_NO_WPA @@ -149,6 +158,8 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param, int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen, int verbose); int wpa_sm_pmf_enabled(struct wpa_sm *sm); +int wpa_sm_ext_key_id(struct wpa_sm *sm); +int wpa_sm_ext_key_id_active(struct wpa_sm *sm); int wpa_sm_ocv_enabled(struct wpa_sm *sm); void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise); @@ -172,6 +183,7 @@ int wpa_sm_pmksa_exists(struct wpa_sm *sm, const u8 *bssid, const void *network_ctx); void wpa_sm_drop_sa(struct wpa_sm *sm); int wpa_sm_has_ptk(struct wpa_sm *sm); +int wpa_sm_has_ptk_installed(struct wpa_sm *sm); void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr); @@ -294,6 +306,16 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm) return 0; } +static inline int wpa_sm_ext_key_id(struct wpa_sm *sm) +{ + return 0; +} + +static inline int wpa_sm_ext_key_id_active(struct wpa_sm *sm) +{ + return 0; +} + static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm) { return 0; diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index 2b8b41fa..203a61c7 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -82,23 +82,30 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) if (sm == NULL) return 0; + if (!get_ie(ies, ies_len, WLAN_EID_MOBILITY_DOMAIN)) { + os_free(sm->assoc_resp_ies); + sm->assoc_resp_ies = NULL; + sm->assoc_resp_ies_len = 0; + os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); + os_memset(sm->r0kh_id, 0, FT_R0KH_ID_MAX_LEN); + sm->r0kh_id_len = 0; + os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN); + return 0; + } + use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); if (wpa_ft_parse_ies(ies, ies_len, &ft, use_sha384) < 0) return -1; - if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) + if (ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) return -1; - if (ft.mdie) { - wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", - ft.mdie, MOBILITY_DOMAIN_ID_LEN); - os_memcpy(sm->mobility_domain, ft.mdie, - MOBILITY_DOMAIN_ID_LEN); - sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; - wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", - sm->mdie_ft_capab); - } else - os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN); + wpa_hexdump(MSG_DEBUG, "FT: Mobility domain", + ft.mdie, MOBILITY_DOMAIN_ID_LEN); + os_memcpy(sm->mobility_domain, ft.mdie, MOBILITY_DOMAIN_ID_LEN); + sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN]; + wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x", + sm->mdie_ft_capab); if (ft.r0kh_id) { wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID", @@ -125,10 +132,10 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2); if (sm->assoc_resp_ies) { u8 *pos = sm->assoc_resp_ies; - if (ft.mdie) { - os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); - pos += ft.mdie_len + 2; - } + + os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2); + pos += ft.mdie_len + 2; + if (ft.ftie) { os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2); pos += ft.ftie_len + 2; @@ -155,6 +162,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL * @ric_ies_len: Length of ric_ies buffer in octets * @ap_mdie: Mobility Domain IE from the target AP + * @omit_rsnxe: Whether RSNXE is omitted from Reassociation Request frame * Returns: Pointer to buffer with IEs or %NULL on failure * * Caller is responsible for freeing the returned buffer with os_free(); @@ -164,16 +172,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, const u8 *kck, size_t kck_len, const u8 *target_ap, const u8 *ric_ies, size_t ric_ies_len, - const u8 *ap_mdie) + const u8 *ap_mdie, int omit_rsnxe) { size_t buf_len; u8 *buf, *pos, *ftie_len, *ftie_pos, *fte_mic, *elem_count; struct rsn_mdie *mdie; struct rsn_ie_hdr *rsnie; - u16 capab; int mdie_len; u8 rsnxe[10]; size_t rsnxe_len; + int rsnxe_used; int res; sm->ft_completed = 0; @@ -249,14 +257,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, pos += RSN_SELECTOR_LEN; /* RSN Capabilities */ - capab = 0; - if (sm->mfp) - capab |= WPA_CAPABILITY_MFPC; - if (sm->mfp == 2) - capab |= WPA_CAPABILITY_MFPR; - if (sm->ocv) - capab |= WPA_CAPABILITY_OCVC; - WPA_PUT_LE16(pos, capab); + WPA_PUT_LE16(pos, rsn_supp_capab(sm)); pos += 2; /* PMKID Count */ @@ -302,10 +303,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, ftie_pos = pos; *pos++ = WLAN_EID_FAST_BSS_TRANSITION; ftie_len = pos++; + rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && anonce && + (sm->sae_pwe == 1 || sm->sae_pwe == 2); if (wpa_key_mgmt_sha384(sm->key_mgmt)) { struct rsn_ftie_sha384 *ftie; ftie = (struct rsn_ftie_sha384 *) pos; + ftie->mic_control[0] = !!rsnxe_used; fte_mic = ftie->mic; elem_count = &ftie->mic_control[1]; pos += sizeof(*ftie); @@ -316,6 +320,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, struct rsn_ftie *ftie; ftie = (struct rsn_ftie *) pos; + ftie->mic_control[0] = !!rsnxe_used; fte_mic = ftie->mic; elem_count = &ftie->mic_control[1]; pos += sizeof(*ftie); @@ -363,12 +368,16 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, pos += ric_ies_len; } - res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe)); - if (res < 0) { - os_free(buf); - return NULL; + if (omit_rsnxe) { + rsnxe_len = 0; + } else { + res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe)); + if (res < 0) { + os_free(buf); + return NULL; + } + rsnxe_len = res; } - rsnxe_len = res; if (kck) { /* @@ -422,8 +431,9 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) alg = wpa_cipher_to_alg(sm->pairwise_cipher); keylen = wpa_cipher_key_len(sm->pairwise_cipher); - if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, - sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) { + if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc), + (u8 *) sm->ptk.tk, keylen, + KEY_FLAG_PAIRWISE_RX_TX) < 0) { wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver"); return -1; } @@ -450,7 +460,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) } ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, - NULL, 0, sm->bssid, NULL, 0, mdie); + NULL, 0, sm->bssid, NULL, 0, mdie, 0); if (ft_ies) { wpa_sm_update_ft_ies(sm, sm->mobility_domain, ft_ies, ft_ies_len); @@ -646,7 +656,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, sm->pmk_r1_name, kck, kck_len, bssid, ric_ies, ric_ies_len, - parse.mdie ? parse.mdie - 2 : NULL); + parse.mdie ? parse.mdie - 2 : NULL, + !sm->ap_rsnxe); if (ft_ies) { wpa_sm_update_ft_ies(sm, sm->mobility_domain, ft_ies, ft_ies_len); @@ -773,7 +784,8 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, os_memcpy(gtk + 24, tmp, 8); } if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0, - gtk_elem + 3, rsc_len, gtk, keylen) < 0) { + gtk_elem + 3, rsc_len, gtk, keylen, + KEY_FLAG_GROUP_RX) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " "driver."); return -1; @@ -840,7 +852,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, igtk_len); if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), broadcast_ether_addr, keyidx, 0, - igtk_elem + 2, 6, igtk, igtk_len) < 0) { + igtk_elem + 2, 6, igtk, igtk_len, + KEY_FLAG_GROUP_RX) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the " "driver."); forced_memzero(igtk, sizeof(igtk)); @@ -852,6 +865,74 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, } +static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem, + size_t bigtk_elem_len) +{ + u8 bigtk[WPA_BIGTK_MAX_LEN]; + size_t bigtk_len; + u16 keyidx; + const u8 *kek; + size_t kek_len; + + if (!sm->beacon_prot || !bigtk_elem || + (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC && + sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_128 && + sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256 && + sm->mgmt_group_cipher != WPA_CIPHER_BIP_CMAC_256)) + return 0; + + if (wpa_key_mgmt_fils(sm->key_mgmt)) { + kek = sm->ptk.kek2; + kek_len = sm->ptk.kek2_len; + } else { + kek = sm->ptk.kek; + kek_len = sm->ptk.kek_len; + } + + wpa_hexdump_key(MSG_DEBUG, "FT: Received BIGTK in Reassoc Resp", + bigtk_elem, bigtk_elem_len); + + bigtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher); + if (bigtk_elem_len != 2 + 6 + 1 + bigtk_len + 8) { + wpa_printf(MSG_DEBUG, + "FT: Invalid BIGTK sub-elem length %lu", + (unsigned long) bigtk_elem_len); + return -1; + } + if (bigtk_elem[8] != bigtk_len) { + wpa_printf(MSG_DEBUG, + "FT: Invalid BIGTK sub-elem Key Length %d", + bigtk_elem[8]); + return -1; + } + + if (aes_unwrap(kek, kek_len, bigtk_len / 8, bigtk_elem + 9, bigtk)) { + wpa_printf(MSG_WARNING, + "FT: AES unwrap failed - could not decrypt BIGTK"); + return -1; + } + + /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */ + + keyidx = WPA_GET_LE16(bigtk_elem); + + wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk, + bigtk_len); + if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), + broadcast_ether_addr, keyidx, 0, + bigtk_elem + 2, 6, bigtk, bigtk_len, + KEY_FLAG_GROUP_RX) < 0) { + wpa_printf(MSG_WARNING, + "WPA: Failed to set BIGTK to the driver"); + forced_memzero(bigtk, sizeof(bigtk)); + return -1; + } + forced_memzero(bigtk, sizeof(bigtk)); + + return 0; +} + + int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len, const u8 *src_addr) { @@ -864,6 +945,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, int use_sha384 = wpa_key_mgmt_sha384(sm->key_mgmt); const u8 *anonce, *snonce, *fte_mic; u8 fte_elem_count; + int own_rsnxe_used, rsnxe_used; wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len); @@ -902,6 +984,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, anonce = ftie->anonce; snonce = ftie->snonce; + rsnxe_used = ftie->mic_control[0] & 0x01; fte_elem_count = ftie->mic_control[1]; fte_mic = ftie->mic; } else { @@ -915,6 +998,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, anonce = ftie->anonce; snonce = ftie->snonce; + rsnxe_used = ftie->mic_control[0] & 0x01; fte_elem_count = ftie->mic_control[1]; fte_mic = ftie->mic; } @@ -1012,6 +1096,58 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return -1; } + if (rsnxe_used && !sm->ap_rsnxe) { + wpa_printf(MSG_INFO, + "FT: FTE indicated that AP uses RSNXE, but RSNXE was not included in Beacon/Probe Response frames"); + return -1; + } + + if (!sm->ap_rsn_ie) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "FT: No RSNE for this AP known - trying to get from scan results"); + if (wpa_sm_get_beacon_ie(sm) < 0) { + wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, + "FT: Could not find AP from the scan results"); + return -1; + } + wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, + "FT: Found the current AP from updated scan results"); + } + + if (sm->ap_rsn_ie && + wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt), + sm->ap_rsn_ie, sm->ap_rsn_ie_len, + parse.rsn - 2, parse.rsn_len + 2)) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "FT: RSNE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame"); + wpa_hexdump(MSG_INFO, "RSNE in Beacon/ProbeResp", + sm->ap_rsn_ie, sm->ap_rsn_ie_len); + wpa_hexdump(MSG_INFO, + "RSNE in FT protocol Reassociation Response frame", + parse.rsn ? parse.rsn - 2 : NULL, + parse.rsn ? parse.rsn_len + 2 : 0); + return -1; + } + + own_rsnxe_used = wpa_key_mgmt_sae(sm->key_mgmt) && + (sm->sae_pwe == 1 || sm->sae_pwe == 2); + if ((sm->ap_rsnxe && !parse.rsnxe && own_rsnxe_used) || + (!sm->ap_rsnxe && parse.rsnxe) || + (sm->ap_rsnxe && parse.rsnxe && + (sm->ap_rsnxe_len != 2 + parse.rsnxe_len || + os_memcmp(sm->ap_rsnxe, parse.rsnxe - 2, + sm->ap_rsnxe_len) != 0))) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, + "FT: RSNXE mismatch between Beacon/ProbeResp and FT protocol Reassociation Response frame"); + wpa_hexdump(MSG_INFO, "RSNXE in Beacon/ProbeResp", + sm->ap_rsnxe, sm->ap_rsnxe_len); + wpa_hexdump(MSG_INFO, + "RSNXE in FT protocol Reassociation Response frame", + parse.rsnxe ? parse.rsnxe - 2 : NULL, + parse.rsnxe ? parse.rsnxe_len + 2 : 0); + return -1; + } + #ifdef CONFIG_OCV if (wpa_sm_ocv_enabled(sm)) { struct wpa_channel_info ci; @@ -1033,10 +1169,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, sm->ft_reassoc_completed = 1; - if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0) - return -1; - - if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0) + if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 || + wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 || + wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0) return -1; if (sm->set_ptk_after_assoc) { @@ -1083,7 +1218,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, } ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name, - NULL, 0, target_ap, NULL, 0, mdie); + NULL, 0, target_ap, NULL, 0, mdie, 0); if (ft_ies) { sm->over_the_ds_in_progress = 1; os_memcpy(sm->target_ap, target_ap, ETH_ALEN); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index 2a433425..1ad75dcf 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -33,6 +33,8 @@ struct wpa_sm { struct wpa_gtk gtk_wnm_sleep; struct wpa_igtk igtk; struct wpa_igtk igtk_wnm_sleep; + struct wpa_bigtk bigtk; + struct wpa_bigtk bigtk_wnm_sleep; struct eapol_sm *eapol; /* EAPOL state machine from upper level code */ @@ -61,8 +63,15 @@ struct wpa_sm { u8 ssid[32]; size_t ssid_len; int wpa_ptk_rekey; + int wpa_deny_ptk0_rekey:1; int p2p; int wpa_rsc_relaxation; + int owe_ptk_workaround; + int beacon_prot; + int ext_key_id; /* whether Extended Key ID is enabled */ + int use_ext_key_id; /* whether Extended Key ID has been detected + * to be used */ + int keyidx_active; /* Key ID for the active TK */ u8 own_addr[ETH_ALEN]; const char *ifname; @@ -198,11 +207,18 @@ static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, u16 reason_code) static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) + const u8 *key, size_t key_len, + enum key_flag key_flag) { WPA_ASSERT(sm->ctx->set_key); return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx, - seq, seq_len, key, key_len); + seq, seq_len, key, key_len, key_flag); +} + +static inline void wpa_sm_reconnect(struct wpa_sm *sm) +{ + WPA_ASSERT(sm->ctx->reconnect); + sm->ctx->reconnect(sm->ctx->ctx); } static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm) @@ -248,11 +264,13 @@ static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type, static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, void *network_ctx, const u8 *bssid, const u8 *pmkid, const u8 *cache_id, const u8 *pmk, - size_t pmk_len) + size_t pmk_len, u32 pmk_lifetime, + u8 pmk_reauth_threshold) { WPA_ASSERT(sm->ctx->add_pmkid); return sm->ctx->add_pmkid(sm->ctx->ctx, network_ctx, bssid, pmkid, - cache_id, pmk, pmk_len); + cache_id, pmk, pmk_len, pmk_lifetime, + pmk_reauth_threshold); } static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, void *network_ctx, @@ -410,6 +428,12 @@ static inline int wpa_sm_channel_info(struct wpa_sm *sm, return sm->ctx->channel_info(sm->ctx->ctx, ci); } +static inline void wpa_sm_transition_disable(struct wpa_sm *sm, u8 bitmap) +{ + if (sm->ctx->transition_disable) + sm->ctx->transition_disable(sm->ctx->ctx, bitmap); +} + int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk, int ver, const u8 *dest, u16 proto, diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 03c0d7e8..9068781b 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -105,6 +105,23 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len, } +u16 rsn_supp_capab(struct wpa_sm *sm) +{ + u16 capab = 0; + + if (sm->mfp) + capab |= WPA_CAPABILITY_MFPC; + if (sm->mfp == 2) + capab |= WPA_CAPABILITY_MFPR; + if (sm->ocv) + capab |= WPA_CAPABILITY_OCVC; + if (sm->ext_key_id) + capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST; + + return capab; +} + + static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, int pairwise_cipher, int group_cipher, int key_mgmt, int mgmt_group_cipher, @@ -112,7 +129,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, { u8 *pos; struct rsn_ie_hdr *hdr; - u16 capab; u32 suite; if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN + @@ -214,14 +230,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, pos += RSN_SELECTOR_LEN; /* RSN Capabilities */ - capab = 0; - if (sm->mfp) - capab |= WPA_CAPABILITY_MFPC; - if (sm->mfp == 2) - capab |= WPA_CAPABILITY_MFPR; - if (sm->ocv) - capab |= WPA_CAPABILITY_OCVC; - WPA_PUT_LE16(pos, capab); + WPA_PUT_LE16(pos, rsn_supp_capab(sm)); pos += 2; if (sm->cur_pmksa) { diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h index 6dc6cf56..83a6727f 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -13,5 +13,6 @@ struct wpa_sm; int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len); int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len); +u16 rsn_supp_capab(struct wpa_sm *sm); #endif /* WPA_IE_H */ diff --git a/src/tls/asn1.c b/src/tls/asn1.c index a08c2e1e..2da7b4a3 100644 --- a/src/tls/asn1.c +++ b/src/tls/asn1.c @@ -9,18 +9,99 @@ #include "includes.h" #include "common.h" +#include "utils/wpabuf.h" #include "asn1.h" -struct asn1_oid asn1_sha1_oid = { +const struct asn1_oid asn1_sha1_oid = { .oid = { 1, 3, 14, 3, 2, 26 }, .len = 6 }; -struct asn1_oid asn1_sha256_oid = { +const struct asn1_oid asn1_sha256_oid = { .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }, .len = 9 }; +const struct asn1_oid asn1_ec_public_key_oid = { + .oid = { 1, 2, 840, 10045, 2, 1 }, + .len = 6 +}; + +const struct asn1_oid asn1_prime256v1_oid = { + .oid = { 1, 2, 840, 10045, 3, 1, 7 }, + .len = 7 +}; + +const struct asn1_oid asn1_secp384r1_oid = { + .oid = { 1, 3, 132, 0, 34 }, + .len = 5 +}; + +const struct asn1_oid asn1_secp521r1_oid = { + .oid = { 1, 3, 132, 0, 35 }, + .len = 5 +}; + +const struct asn1_oid asn1_brainpoolP256r1_oid = { + .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 7 }, + .len = 10 +}; + +const struct asn1_oid asn1_brainpoolP384r1_oid = { + .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 11 }, + .len = 10 +}; + +const struct asn1_oid asn1_brainpoolP512r1_oid = { + .oid = { 1, 3, 36, 3, 3, 2, 8, 1, 1, 13 }, + .len = 10 +}; + +const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid = { + .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 22 }, + .len = 9 +}; + +const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid = { + .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 23 }, + .len = 9 +}; + +const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid = { + .oid = { 1, 2, 840, 113549, 1, 9, 16, 3, 24 }, + .len = 9 +}; + +const struct asn1_oid asn1_pbkdf2_oid = { + .oid = { 1, 2, 840, 113549, 1, 5, 12 }, + .len = 7 +}; + +const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid = { + .oid = { 1, 2, 840, 113549, 2, 9 }, + .len = 6 +}; + +const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid = { + .oid = { 1, 2, 840, 113549, 2, 10 }, + .len = 6 +}; + +const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid = { + .oid = { 1, 2, 840, 113549, 2, 11 }, + .len = 6 +}; + +const struct asn1_oid asn1_dpp_config_params_oid = { + .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 1 }, + .len = 10 +}; + +const struct asn1_oid asn1_dpp_asymmetric_key_package_oid = { + .oid = { 1, 3, 6, 1, 4, 1, 40808, 1, 2, 2 }, + .len = 10 +}; + static int asn1_valid_der_boolean(struct asn1_hdr *hdr) { @@ -270,3 +351,231 @@ int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b) return 1; } + + +int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next) +{ + struct asn1_hdr hdr; + size_t left; + const u8 *pos; + int value; + + if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0) + return -1; + + if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) { + wpa_printf(MSG_DEBUG, + "ASN.1: Expected INTEGER - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + + *next = hdr.payload + hdr.length; + pos = hdr.payload; + left = hdr.length; + if (left > sizeof(value)) { + wpa_printf(MSG_DEBUG, "ASN.1: Too large INTEGER (len %u)", + hdr.length); + return -1; + } + value = 0; + while (left) { + value <<= 8; + value |= *pos++; + left--; + } + + *integer = value; + return 0; +} + + +int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr, + const u8 **next) +{ + if (asn1_get_next(buf, len, hdr) < 0 || + hdr->class != ASN1_CLASS_UNIVERSAL || + hdr->tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "ASN.1: Expected SEQUENCE - found class %d tag 0x%x", + hdr->class, hdr->tag); + return -1; + } + + if (next) + *next = hdr->payload + hdr->length; + return 0; +} + + +int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **params, size_t *params_len, const u8 **next) +{ + const u8 *pos = buf, *end = buf + len; + struct asn1_hdr hdr; + + /* + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL} + */ + if (asn1_get_sequence(pos, end - pos, &hdr, next) < 0 || + asn1_get_oid(hdr.payload, hdr.length, oid, &pos) < 0) + return -1; + + if (params && params_len) { + *params = pos; + *params_len = hdr.payload + hdr.length - pos; + } + + return 0; +} + + +void asn1_put_integer(struct wpabuf *buf, int val) +{ + u8 bin[4]; + int zeros; + + WPA_PUT_BE32(bin, val); + zeros = 0; + while (zeros < 3 && bin[zeros] == 0) + zeros++; + wpabuf_put_u8(buf, ASN1_TAG_INTEGER); + wpabuf_put_u8(buf, 4 - zeros); + wpabuf_put_data(buf, &bin[zeros], 4 - zeros); +} + + +static void asn1_put_len(struct wpabuf *buf, size_t len) +{ + if (len <= 0x7f) { + wpabuf_put_u8(buf, len); + } else if (len <= 0xff) { + wpabuf_put_u8(buf, 0x80 | 1); + wpabuf_put_u8(buf, len); + } else if (len <= 0xffff) { + wpabuf_put_u8(buf, 0x80 | 2); + wpabuf_put_be16(buf, len); + } else if (len <= 0xffffff) { + wpabuf_put_u8(buf, 0x80 | 3); + wpabuf_put_be24(buf, len); + } else { + wpabuf_put_u8(buf, 0x80 | 4); + wpabuf_put_be32(buf, len); + } +} + + +void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val) +{ + wpabuf_put_u8(buf, ASN1_TAG_OCTETSTRING); + asn1_put_len(buf, wpabuf_len(val)); + wpabuf_put_buf(buf, val); +} + + +void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid) +{ + u8 *len; + size_t i; + + if (oid->len < 2) + return; + wpabuf_put_u8(buf, ASN1_TAG_OID); + len = wpabuf_put(buf, 1); + wpabuf_put_u8(buf, 40 * oid->oid[0] + oid->oid[1]); + for (i = 2; i < oid->len; i++) { + unsigned long val = oid->oid[i]; + u8 bytes[8]; + int idx = 0; + + while (val) { + bytes[idx] = (idx ? 0x80 : 0x00) | (val & 0x7f); + idx++; + val >>= 7; + } + if (idx == 0) { + bytes[idx] = 0; + idx = 1; + } + while (idx > 0) { + idx--; + wpabuf_put_u8(buf, bytes[idx]); + } + } + *len = (u8 *) wpabuf_put(buf, 0) - len - 1; +} + + +void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag, + size_t len) +{ + wpabuf_put_u8(buf, class << 6 | (constructed ? 0x20 : 0x00) | tag); + asn1_put_len(buf, len); +} + + +void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload) +{ + asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SEQUENCE, + wpabuf_len(payload)); + wpabuf_put_buf(buf, payload); +} + + +void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload) +{ + asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 1, ASN1_TAG_SET, + wpabuf_len(payload)); + wpabuf_put_buf(buf, payload); +} + + +void asn1_put_utf8string(struct wpabuf *buf, const char *val) +{ + asn1_put_hdr(buf, ASN1_CLASS_UNIVERSAL, 0, ASN1_TAG_UTF8STRING, + os_strlen(val)); + wpabuf_put_str(buf, val); +} + + +struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid, + const struct wpabuf *params) +{ + struct wpabuf *buf; + size_t len; + + /* + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL} + */ + + len = 100; + if (params) + len += wpabuf_len(params); + buf = wpabuf_alloc(len); + if (!buf) + return NULL; + asn1_put_oid(buf, oid); + if (params) + wpabuf_put_buf(buf, params); + return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); +} + + +struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag) +{ + struct wpabuf *res; + + if (!buf) + return NULL; + res = wpabuf_alloc(10 + wpabuf_len(buf)); + if (res) { + asn1_put_hdr(res, class, 1, tag, wpabuf_len(buf)); + wpabuf_put_buf(res, buf); + } + wpabuf_clear_free(buf); + return res; +} diff --git a/src/tls/asn1.h b/src/tls/asn1.h index 6bd7df56..6878a4f2 100644 --- a/src/tls/asn1.h +++ b/src/tls/asn1.h @@ -65,8 +65,43 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len); unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b); +int asn1_get_integer(const u8 *buf, size_t len, int *integer, const u8 **next); +int asn1_get_sequence(const u8 *buf, size_t len, struct asn1_hdr *hdr, + const u8 **next); +int asn1_get_alg_id(const u8 *buf, size_t len, struct asn1_oid *oid, + const u8 **params, size_t *params_len, const u8 **next); +void asn1_put_integer(struct wpabuf *buf, int val); +void asn1_put_octet_string(struct wpabuf *buf, const struct wpabuf *val); +void asn1_put_oid(struct wpabuf *buf, const struct asn1_oid *oid); +void asn1_put_hdr(struct wpabuf *buf, u8 class, int constructed, u8 tag, + size_t len); +void asn1_put_sequence(struct wpabuf *buf, const struct wpabuf *payload); +void asn1_put_set(struct wpabuf *buf, const struct wpabuf *payload); +void asn1_put_utf8string(struct wpabuf *buf, const char *val); +struct wpabuf * asn1_build_alg_id(const struct asn1_oid *oid, + const struct wpabuf *params); +struct wpabuf * asn1_encaps(struct wpabuf *buf, u8 class, u8 tag); -extern struct asn1_oid asn1_sha1_oid; -extern struct asn1_oid asn1_sha256_oid; +extern const struct asn1_oid asn1_sha1_oid; +extern const struct asn1_oid asn1_sha256_oid; +extern const struct asn1_oid asn1_ec_public_key_oid; +extern const struct asn1_oid asn1_prime256v1_oid; +extern const struct asn1_oid asn1_secp384r1_oid; +extern const struct asn1_oid asn1_secp521r1_oid; +extern const struct asn1_oid asn1_brainpoolP256r1_oid; +extern const struct asn1_oid asn1_brainpoolP384r1_oid; +extern const struct asn1_oid asn1_brainpoolP512r1_oid; +extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid; +extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid; +extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid; +extern const struct asn1_oid asn1_aes_siv_cmac_aead_256_oid; +extern const struct asn1_oid asn1_aes_siv_cmac_aead_384_oid; +extern const struct asn1_oid asn1_aes_siv_cmac_aead_512_oid; +extern const struct asn1_oid asn1_pbkdf2_oid; +extern const struct asn1_oid asn1_pbkdf2_hmac_sha256_oid; +extern const struct asn1_oid asn1_pbkdf2_hmac_sha384_oid; +extern const struct asn1_oid asn1_pbkdf2_hmac_sha512_oid; +extern const struct asn1_oid asn1_dpp_config_params_oid; +extern const struct asn1_oid asn1_dpp_asymmetric_key_package_oid; #endif /* ASN1_H */ diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index 80874e59..3825a738 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -312,6 +312,14 @@ static void tls_peer_cert_event(struct tlsv1_client *conn, int depth, x509_name_string(&cert->subject, subject, sizeof(subject)); ev.peer_cert.subject = subject; + if (cert->extensions_present & X509_EXT_CERTIFICATE_POLICY) { + if (cert->certificate_policy & X509_EXT_CERT_POLICY_TOD_STRICT) + ev.peer_cert.tod = 1; + else if (cert->certificate_policy & + X509_EXT_CERT_POLICY_TOD_TOFU) + ev.peer_cert.tod = 2; + } + conn->event_cb(conn->cb_ctx, TLS_PEER_CERTIFICATE, &ev); wpabuf_free(cert_buf); } @@ -532,7 +540,7 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct, } } else if (conn->cred && conn->cred->cert_probe) { wpa_printf(MSG_DEBUG, - "TLSv1: Reject server certificate on probe-only rune"); + "TLSv1: Reject server certificate on probe-only run"); if (conn->event_cb) { union tls_event_data ev; char buf[128]; diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index 1bd5aa00..5c8ac567 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -1120,6 +1120,133 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert, } +static int x509_id_cert_policy_any_oid(struct asn1_oid *oid) +{ + return oid->len == 5 && + oid->oid[0] == 2 /* iso/itu-t */ && + oid->oid[1] == 5 /* X.500 Directory Services */ && + oid->oid[2] == 29 /* id-ce */ && + oid->oid[3] == 32 /* id-ce-certificate-policies */ && + oid->oid[4] == 0 /* anyPolicy */; +} + + +static int x509_id_wfa_oid(struct asn1_oid *oid) +{ + return oid->len >= 7 && + oid->oid[0] == 1 /* iso */ && + oid->oid[1] == 3 /* identified-organization */ && + oid->oid[2] == 6 /* dod */ && + oid->oid[3] == 1 /* internet */ && + oid->oid[4] == 4 /* private */ && + oid->oid[5] == 1 /* enterprise */ && + oid->oid[6] == 40808 /* WFA */; +} + + +static int x509_id_wfa_tod_oid(struct asn1_oid *oid) +{ + return oid->len >= 9 && + x509_id_wfa_oid(oid) && + oid->oid[7] == 1 && + oid->oid[8] == 3; +} + + +static int x509_id_wfa_tod_strict_oid(struct asn1_oid *oid) +{ + return oid->len == 10 && + x509_id_wfa_tod_oid(oid) && + oid->oid[9] == 1; +} + + +static int x509_id_wfa_tod_tofu_oid(struct asn1_oid *oid) +{ + return oid->len == 10 && + x509_id_wfa_tod_oid(oid) && + oid->oid[9] == 2; +} + + +static int x509_parse_ext_certificate_policies(struct x509_certificate *cert, + const u8 *pos, size_t len) +{ + struct asn1_hdr hdr; + const u8 *end; + + /* + * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation + * + * PolicyInformation ::= SEQUENCE { + * policyIdentifier CertPolicyId, + * policyQualifiers SEQUENCE SIZE (1..MAX) OF + * PolicyQualifierInfo OPTIONAL } + * + * CertPolicyId ::= OBJECT IDENTIFIER + */ + + if (asn1_get_next(pos, len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (certificatePolicies) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + if (hdr.length > pos + len - hdr.payload) + return -1; + pos = hdr.payload; + end = pos + hdr.length; + + wpa_hexdump(MSG_MSGDUMP, "X509: certificatePolicies", pos, end - pos); + + while (pos < end) { + const u8 *pol_end; + struct asn1_oid oid; + char buf[80]; + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE (PolicyInformation) - found class %d tag 0x%x", + hdr.class, hdr.tag); + return -1; + } + if (hdr.length > end - hdr.payload) + return -1; + pos = hdr.payload; + pol_end = pos + hdr.length; + wpa_hexdump(MSG_MSGDUMP, "X509: PolicyInformation", + pos, pol_end - pos); + + if (asn1_get_oid(pos, pol_end - pos, &oid, &pos)) + return -1; + if (x509_id_cert_policy_any_oid(&oid)) { + os_strlcpy(buf, "anyPolicy-STRICT", sizeof(buf)); + cert->certificate_policy |= + X509_EXT_CERT_POLICY_ANY; + } else if (x509_id_wfa_tod_strict_oid(&oid)) { + os_strlcpy(buf, "TOD-STRICT", sizeof(buf)); + cert->certificate_policy |= + X509_EXT_CERT_POLICY_TOD_STRICT; + } else if (x509_id_wfa_tod_tofu_oid(&oid)) { + os_strlcpy(buf, "TOD-TOFU", sizeof(buf)); + cert->certificate_policy |= + X509_EXT_CERT_POLICY_TOD_TOFU; + } else { + asn1_oid_to_str(&oid, buf, sizeof(buf)); + } + wpa_printf(MSG_DEBUG, "policyIdentifier: %s", buf); + + pos = pol_end; + } + + cert->extensions_present |= X509_EXT_CERTIFICATE_POLICY; + + return 0; +} + + static int x509_id_pkix_oid(struct asn1_oid *oid) { return oid->len >= 7 && @@ -1234,7 +1361,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert, return 1; /* TODO: add other extensions required by RFC 3280, Ch 4.2: - * certificate policies (section 4.2.1.5) * name constraints (section 4.2.1.11) * policy constraints (section 4.2.1.12) * inhibit any-policy (section 4.2.1.15) @@ -1248,6 +1374,8 @@ static int x509_parse_extension_data(struct x509_certificate *cert, return x509_parse_ext_issuer_alt_name(cert, pos, len); case 19: /* id-ce-basicConstraints */ return x509_parse_ext_basic_constraints(cert, pos, len); + case 32: /* id-ce-certificatePolicies */ + return x509_parse_ext_certificate_policies(cert, pos, len); case 37: /* id-ce-extKeyUsage */ return x509_parse_ext_ext_key_usage(cert, pos, len); default: diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h index 7df8e2ab..e3b108ff 100644 --- a/src/tls/x509v3.h +++ b/src/tls/x509v3.h @@ -74,6 +74,7 @@ struct x509_certificate { #define X509_EXT_SUBJECT_ALT_NAME (1 << 3) #define X509_EXT_ISSUER_ALT_NAME (1 << 4) #define X509_EXT_EXT_KEY_USAGE (1 << 5) +#define X509_EXT_CERTIFICATE_POLICY (1 << 6) /* BasicConstraints */ int ca; /* cA */ @@ -98,6 +99,12 @@ struct x509_certificate { #define X509_EXT_KEY_USAGE_CLIENT_AUTH (1 << 2) #define X509_EXT_KEY_USAGE_OCSP (1 << 3) + /* CertificatePolicy */ + unsigned long certificate_policy; +#define X509_EXT_CERT_POLICY_ANY (1 << 0) +#define X509_EXT_CERT_POLICY_TOD_STRICT (1 << 1) +#define X509_EXT_CERT_POLICY_TOD_TOFU (1 << 2) + /* * The DER format certificate follows struct x509_certificate. These * pointers point to that buffer. diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c index 71a16526..26c83d63 100644 --- a/src/utils/browser-android.c +++ b/src/utils/browser-android.c @@ -62,7 +62,7 @@ static void http_req(void *ctx, struct http_request *req) } -int hs20_web_browser(const char *url) +int hs20_web_browser(const char *url, int ignore_tls) { struct http_server *http; struct in_addr addr; diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c index aed39706..d87d97b5 100644 --- a/src/utils/browser-system.c +++ b/src/utils/browser-system.c @@ -62,7 +62,7 @@ static void http_req(void *ctx, struct http_request *req) } -int hs20_web_browser(const char *url) +int hs20_web_browser(const char *url, int ignore_tls) { struct http_server *http; struct in_addr addr; diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c index dfb4b679..d32a85bd 100644 --- a/src/utils/browser-wpadebug.c +++ b/src/utils/browser-wpadebug.c @@ -63,7 +63,7 @@ static void http_req(void *ctx, struct http_request *req) } -int hs20_web_browser(const char *url) +int hs20_web_browser(const char *url, int ignore_tls) { struct http_server *http; struct in_addr addr; diff --git a/src/utils/browser.c b/src/utils/browser.c index ad0b382f..c0f4380c 100644 --- a/src/utils/browser.c +++ b/src/utils/browser.c @@ -7,7 +7,11 @@ */ #include "includes.h" +#ifdef USE_WEBKIT2 +#include <webkit2/webkit2.h> +#else /* USE_WEBKIT2 */ #include <webkit/webkit.h> +#endif /* USE_WEBKIT2 */ #include "common.h" #include "browser.h" @@ -15,16 +19,20 @@ struct browser_context { GtkWidget *win; + WebKitWebView *view; int success; int progress; char *hover_link; char *title; + int gtk_main_started; + int quit_gtk_main; }; static void win_cb_destroy(GtkWidget *win, struct browser_context *ctx) { wpa_printf(MSG_DEBUG, "BROWSER:%s", __func__); - gtk_main_quit(); + if (ctx->gtk_main_started) + gtk_main_quit(); } @@ -50,6 +58,142 @@ static void browser_update_title(struct browser_context *ctx) } +static void process_request_starting_uri(struct browser_context *ctx, + const char *uri) +{ + int quit = 0; + + if (g_str_has_prefix(uri, "osu://")) { + ctx->success = atoi(uri + 6); + quit = 1; + } else if (g_str_has_prefix(uri, "http://localhost:12345")) { + /* + * This is used as a special trigger to indicate that the + * user exchange has been completed. + */ + ctx->success = 1; + quit = 1; + } + + if (quit) { + if (ctx->gtk_main_started) { + gtk_main_quit(); + ctx->gtk_main_started = 0; + } else { + ctx->quit_gtk_main = 1; + } + } +} + + +#ifdef USE_WEBKIT2 + +static void view_cb_notify_estimated_load_progress(WebKitWebView *view, + GParamSpec *pspec, + struct browser_context *ctx) +{ + ctx->progress = 100 * webkit_web_view_get_estimated_load_progress(view); + wpa_printf(MSG_DEBUG, "BROWSER:%s progress=%d", __func__, + ctx->progress); + browser_update_title(ctx); +} + + +static void view_cb_resource_load_starting(WebKitWebView *view, + WebKitWebResource *res, + WebKitURIRequest *req, + struct browser_context *ctx) +{ + const gchar *uri = webkit_uri_request_get_uri(req); + + wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri); + process_request_starting_uri(ctx, uri); +} + + +static gboolean view_cb_decide_policy(WebKitWebView *view, + WebKitPolicyDecision *policy, + WebKitPolicyDecisionType type, + struct browser_context *ctx) +{ + wpa_printf(MSG_DEBUG, "BROWSER:%s type=%d", __func__, type); + switch (type) { + case WEBKIT_POLICY_DECISION_TYPE_RESPONSE: { + /* This function makes webkit send a download signal for all + * unknown mime types. */ + WebKitResponsePolicyDecision *response; + + response = WEBKIT_RESPONSE_POLICY_DECISION(policy); + if (!webkit_response_policy_decision_is_mime_type_supported( + response)) { + webkit_policy_decision_download(policy); + return TRUE; + } + break; + } + case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION: { + WebKitNavigationPolicyDecision *d; + WebKitNavigationAction *a; + WebKitURIRequest *req; + const gchar *uri; + + d = WEBKIT_NAVIGATION_POLICY_DECISION(policy); + a = webkit_navigation_policy_decision_get_navigation_action(d); + req = webkit_navigation_action_get_request(a); + uri = webkit_uri_request_get_uri(req); + wpa_printf(MSG_DEBUG, "BROWSER:%s navigation action: uri=%s", + __func__, uri); + process_request_starting_uri(ctx, uri); + break; + } + default: + break; + } + + return FALSE; +} + + +static void view_cb_mouse_target_changed(WebKitWebView *view, + WebKitHitTestResult *h, + guint modifiers, + struct browser_context *ctx) +{ + WebKitHitTestResultContext hc = webkit_hit_test_result_get_context(h); + const char *uri = NULL; + + if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) + uri = webkit_hit_test_result_get_link_uri(h); + else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE) + uri = webkit_hit_test_result_get_image_uri(h); + else if (hc & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA) + uri = webkit_hit_test_result_get_media_uri(h); + + wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri ? uri : "N/A"); + os_free(ctx->hover_link); + if (uri) + ctx->hover_link = os_strdup(uri); + else + ctx->hover_link = NULL; + + browser_update_title(ctx); +} + + +static void view_cb_notify_title(WebKitWebView *view, GParamSpec *ps, + struct browser_context *ctx) +{ + const char *title; + + title = webkit_web_view_get_title(ctx->view); + wpa_printf(MSG_DEBUG, "BROWSER:%s title=%s", __func__, title); + os_free(ctx->title); + ctx->title = os_strdup(title); + browser_update_title(ctx); +} + +#else /* USE_WEBKIT2 */ + static void view_cb_notify_progress(WebKitWebView *view, GParamSpec *pspec, struct browser_context *ctx) { @@ -66,6 +210,10 @@ static void view_cb_notify_load_status(WebKitWebView *view, GParamSpec *pspec, int status = webkit_web_view_get_load_status(view); wpa_printf(MSG_DEBUG, "BROWSER:%s load-status=%d uri=%s", __func__, status, webkit_web_view_get_uri(view)); + if (ctx->quit_gtk_main) { + gtk_main_quit(); + ctx->gtk_main_started = 0; + } } @@ -77,21 +225,12 @@ static void view_cb_resource_request_starting(WebKitWebView *view, struct browser_context *ctx) { const gchar *uri = webkit_network_request_get_uri(req); + wpa_printf(MSG_DEBUG, "BROWSER:%s uri=%s", __func__, uri); if (g_str_has_suffix(uri, "/favicon.ico")) webkit_network_request_set_uri(req, "about:blank"); - if (g_str_has_prefix(uri, "osu://")) { - ctx->success = atoi(uri + 6); - gtk_main_quit(); - } - if (g_str_has_prefix(uri, "http://localhost:12345")) { - /* - * This is used as a special trigger to indicate that the - * user exchange has been completed. - */ - ctx->success = 1; - gtk_main_quit(); - } + + process_request_starting_uri(ctx, uri); } @@ -147,23 +286,32 @@ static void view_cb_title_changed(WebKitWebView *view, WebKitWebFrame *frame, browser_update_title(ctx); } +#endif /* USE_WEBKIT2 */ + -int hs20_web_browser(const char *url) +int hs20_web_browser(const char *url, int ignore_tls) { GtkWidget *scroll; - SoupSession *s; WebKitWebView *view; +#ifdef USE_WEBKIT2 + WebKitSettings *settings; +#else /* USE_WEBKIT2 */ WebKitWebSettings *settings; + SoupSession *s; +#endif /* USE_WEBKIT2 */ struct browser_context ctx; memset(&ctx, 0, sizeof(ctx)); if (!gtk_init_check(NULL, NULL)) return -1; +#ifndef USE_WEBKIT2 s = webkit_get_default_session(); g_object_set(G_OBJECT(s), "ssl-ca-file", "/etc/ssl/certs/ca-certificates.crt", NULL); - g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL); + if (ignore_tls) + g_object_set(G_OBJECT(s), "ssl-strict", FALSE, NULL); +#endif /* USE_WEBKIT2 */ ctx.win = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_role(GTK_WINDOW(ctx.win), "Hotspot 2.0 client"); @@ -177,10 +325,24 @@ int hs20_web_browser(const char *url) G_CALLBACK(win_cb_destroy), &ctx); view = WEBKIT_WEB_VIEW(webkit_web_view_new()); - g_signal_connect(G_OBJECT(view), "notify::progress", - G_CALLBACK(view_cb_notify_progress), &ctx); + ctx.view = view; +#ifdef USE_WEBKIT2 + g_signal_connect(G_OBJECT(view), "notify::estimated-load-progress", + G_CALLBACK(view_cb_notify_estimated_load_progress), + &ctx); + g_signal_connect(G_OBJECT(view), "resource-load-started", + G_CALLBACK(view_cb_resource_load_starting), &ctx); + g_signal_connect(G_OBJECT(view), "decide-policy", + G_CALLBACK(view_cb_decide_policy), &ctx); + g_signal_connect(G_OBJECT(view), "mouse-target-changed", + G_CALLBACK(view_cb_mouse_target_changed), &ctx); + g_signal_connect(G_OBJECT(view), "notify::title", + G_CALLBACK(view_cb_notify_title), &ctx); +#else /* USE_WEBKIT2 */ g_signal_connect(G_OBJECT(view), "notify::load-status", G_CALLBACK(view_cb_notify_load_status), &ctx); + g_signal_connect(G_OBJECT(view), "notify::progress", + G_CALLBACK(view_cb_notify_progress), &ctx); g_signal_connect(G_OBJECT(view), "resource-request-starting", G_CALLBACK(view_cb_resource_request_starting), &ctx); g_signal_connect(G_OBJECT(view), "mime-type-policy-decision-requested", @@ -191,6 +353,7 @@ int hs20_web_browser(const char *url) G_CALLBACK(view_cb_hovering_over_link), &ctx); g_signal_connect(G_OBJECT(view), "title-changed", G_CALLBACK(view_cb_title_changed), &ctx); +#endif /* USE_WEBKIT2 */ gtk_container_add(GTK_CONTAINER(scroll), GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(ctx.win), GTK_WIDGET(scroll)); @@ -205,8 +368,19 @@ int hs20_web_browser(const char *url) "hs20-client/1.0", NULL); g_object_set(G_OBJECT(settings), "auto-load-images", TRUE, NULL); +#ifdef USE_WEBKIT2 + if (ignore_tls) { + WebKitWebContext *wkctx; + + wkctx = webkit_web_context_get_default(); + webkit_web_context_set_tls_errors_policy( + wkctx, WEBKIT_TLS_ERRORS_POLICY_IGNORE); + } +#endif /* USE_WEBKIT2 */ + webkit_web_view_load_uri(view, url); + ctx.gtk_main_started = 1; gtk_main(); gtk_widget_destroy(ctx.win); while (gtk_events_pending()) diff --git a/src/utils/browser.h b/src/utils/browser.h index aaa0eed2..3af13b9a 100644 --- a/src/utils/browser.h +++ b/src/utils/browser.h @@ -10,12 +10,12 @@ #define BROWSER_H #ifdef CONFIG_NO_BROWSER -static inline int hs20_web_browser(const char *url) +static inline int hs20_web_browser(const char *url, int ignore_tls) { return -1; } #else /* CONFIG_NO_BROWSER */ -int hs20_web_browser(const char *url); +int hs20_web_browser(const char *url, int ignore_tls); #endif /* CONFIG_NO_BROWSER */ #endif /* BROWSER_H */ diff --git a/src/utils/common.c b/src/utils/common.c index 27bf435d..2c127519 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -7,6 +7,7 @@ */ #include "includes.h" +#include <limits.h> #include "common/ieee802_11_defs.h" #include "common.h" @@ -790,6 +791,10 @@ int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value) */ pos = value; while (pos && pos[0]) { + if (count == UINT_MAX) { + os_free(freq); + return -1; + } n = os_realloc_array(freq, count + 1, sizeof(struct wpa_freq_range)); if (n == NULL) { @@ -874,9 +879,10 @@ char * freq_range_list_str(const struct wpa_freq_range_list *list) } -int int_array_len(const int *a) +size_t int_array_len(const int *a) { - int i; + size_t i; + for (i = 0; a && a[i]; i++) ; return i; @@ -885,12 +891,21 @@ int int_array_len(const int *a) void int_array_concat(int **res, const int *a) { - int reslen, alen, i; + size_t reslen, alen, i, max_size; int *n; reslen = int_array_len(*res); alen = int_array_len(a); - + max_size = (size_t) -1; + if (alen >= max_size - reslen) { + /* This should not really happen, but if it did, something + * would overflow. Do not try to merge the arrays; instead, make + * this behave like memory allocation failure to avoid messing + * up memory. */ + os_free(*res); + *res = NULL; + return; + } n = os_realloc_array(*res, reslen + alen + 1, sizeof(int)); if (n == NULL) { os_free(*res); @@ -918,8 +933,7 @@ static int freq_cmp(const void *a, const void *b) void int_array_sort_unique(int *a) { - int alen; - int i, j; + size_t alen, i, j; if (a == NULL) return; @@ -944,7 +958,7 @@ void int_array_sort_unique(int *a) void int_array_add_unique(int **res, int a) { - int reslen; + size_t reslen, max_size; int *n; for (reslen = 0; *res && (*res)[reslen]; reslen++) { @@ -952,6 +966,16 @@ void int_array_add_unique(int **res, int a) return; /* already in the list */ } + max_size = (size_t) -1; + if (reslen > max_size - 2) { + /* This should not really happen in practice, but if it did, + * something would overflow. Do not try to add the new value; + * instead, make this behave like memory allocation failure to + * avoid messing up memory. */ + os_free(*res); + *res = NULL; + return; + } n = os_realloc_array(*res, reslen + 2, sizeof(int)); if (n == NULL) { os_free(*res); diff --git a/src/utils/common.h b/src/utils/common.h index 833469a5..8e5cfe16 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -547,7 +547,7 @@ int freq_range_list_includes(const struct wpa_freq_range_list *list, unsigned int freq); char * freq_range_list_str(const struct wpa_freq_range_list *list); -int int_array_len(const int *a); +size_t int_array_len(const int *a); void int_array_concat(int **res, const int *a); void int_array_sort_unique(int *a); void int_array_add_unique(int **res, int a); diff --git a/src/utils/crc32.c b/src/utils/crc32.c new file mode 100644 index 00000000..12d9e2a7 --- /dev/null +++ b/src/utils/crc32.c @@ -0,0 +1,85 @@ +/* + * 32-bit CRC for FCS calculation + * Copyright (c) 2010, Jouni Malinen <j@w1.fi> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "utils/includes.h" + +#include "utils/common.h" +#include "utils/crc32.h" + +/* + * IEEE 802.11 FCS CRC32 + * G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + + * x^5 + x^4 + x^2 + x + 1 + */ +static const u32 crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + + +u32 crc32(const u8 *frame, size_t frame_len) +{ + size_t i; + u32 crc; + + crc = 0xFFFFFFFF; + for (i = 0; i < frame_len; i++) + crc = crc32_table[(crc ^ frame[i]) & 0xff] ^ (crc >> 8); + + return ~crc; +} diff --git a/src/utils/eloop.c b/src/utils/eloop.c index bb375be1..b353ab0e 100644 --- a/src/utils/eloop.c +++ b/src/utils/eloop.c @@ -68,7 +68,7 @@ struct eloop_signal { }; struct eloop_sock_table { - int count; + size_t count; struct eloop_sock *table; eloop_event_type type; int changed; @@ -77,10 +77,10 @@ struct eloop_sock_table { struct eloop_data { int max_sock; - int count; /* sum of all table counts */ + size_t count; /* sum of all table counts */ #ifdef CONFIG_ELOOP_POLL - int max_pollfd_map; /* number of pollfds_map currently allocated */ - int max_poll_fds; /* number of pollfds currently allocated */ + size_t max_pollfd_map; /* number of pollfds_map currently allocated */ + size_t max_poll_fds; /* number of pollfds currently allocated */ struct pollfd *pollfds; struct pollfd **pollfds_map; #endif /* CONFIG_ELOOP_POLL */ @@ -90,12 +90,12 @@ struct eloop_data { #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ #ifdef CONFIG_ELOOP_EPOLL int epollfd; - int epoll_max_event_num; + size_t epoll_max_event_num; struct epoll_event *epoll_events; #endif /* CONFIG_ELOOP_EPOLL */ #ifdef CONFIG_ELOOP_KQUEUE int kqueuefd; - int kqueue_nevents; + size_t kqueue_nevents; struct kevent *kqueue_events; #endif /* CONFIG_ELOOP_KQUEUE */ struct eloop_sock_table readers; @@ -104,7 +104,7 @@ struct eloop_data { struct dl_list timeout; - int signal_count; + size_t signal_count; struct eloop_signal *signals; int signaled; int pending_terminate; @@ -125,7 +125,8 @@ static void eloop_sigsegv_handler(int sig) static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) { - int i; + size_t i; + if (table == NULL || table->table == NULL) return; for (i = 0; i < table->count; i++) { @@ -139,7 +140,8 @@ static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) { - int i; + size_t i; + if (table == NULL || table->table == NULL) return; for (i = 0; i < table->count; i++) { @@ -266,7 +268,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, #endif /* CONFIG_ELOOP_EPOLL */ #if defined(CONFIG_ELOOP_EPOLL) || defined(CONFIG_ELOOP_KQUEUE) struct eloop_sock *temp_table; - int next; + size_t next; #endif /* CONFIG_ELOOP_EPOLL || CONFIG_ELOOP_KQUEUE */ struct eloop_sock *tmp; int new_max_sock; @@ -280,7 +282,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, return -1; #ifdef CONFIG_ELOOP_POLL - if (new_max_sock >= eloop.max_pollfd_map) { + if ((size_t) new_max_sock >= eloop.max_pollfd_map) { struct pollfd **nmap; nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50, sizeof(struct pollfd *)); @@ -293,7 +295,8 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, if (eloop.count + 1 > eloop.max_poll_fds) { struct pollfd *n; - int nmax = eloop.count + 1 + 50; + size_t nmax = eloop.count + 1 + 50; + n = os_realloc_array(eloop.pollfds, nmax, sizeof(struct pollfd)); if (n == NULL) @@ -385,7 +388,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, #ifdef CONFIG_ELOOP_KQUEUE struct kevent ke; #endif /* CONFIG_ELOOP_KQUEUE */ - int i; + size_t i; if (table == NULL || table->table == NULL || table->count == 0) return; @@ -444,7 +447,7 @@ static int eloop_sock_table_set_fds(struct eloop_sock_table *readers, struct pollfd **pollfds_map, int max_pollfd_map) { - int i; + size_t i; int nxt = 0; int fd; struct pollfd *pfd; @@ -519,7 +522,7 @@ static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table, int max_pollfd_map, short int revents) { - int i; + size_t i; struct pollfd *pfd; if (!table || !table->table) @@ -572,7 +575,7 @@ static void eloop_sock_table_dispatch(struct eloop_sock_table *readers, static void eloop_sock_table_set_fds(struct eloop_sock_table *table, fd_set *fds) { - int i; + size_t i; FD_ZERO(fds); @@ -589,7 +592,7 @@ static void eloop_sock_table_set_fds(struct eloop_sock_table *table, static void eloop_sock_table_dispatch(struct eloop_sock_table *table, fd_set *fds) { - int i; + size_t i; if (table == NULL || table->table == NULL) return; @@ -653,7 +656,8 @@ static void eloop_sock_table_dispatch(struct kevent *events, int nfds) static int eloop_sock_table_requeue(struct eloop_sock_table *table) { - int i, r; + size_t i; + int r; r = 0; for (i = 0; i < table->count && table->table; i++) { @@ -694,7 +698,8 @@ int eloop_sock_requeue(void) static void eloop_sock_table_destroy(struct eloop_sock_table *table) { if (table) { - int i; + size_t i; + for (i = 0; i < table->count && table->table; i++) { wpa_printf(MSG_INFO, "ELOOP: remaining socket: " "sock=%d eloop_data=%p user_data=%p " @@ -968,7 +973,7 @@ static void eloop_handle_alarm(int sig) static void eloop_handle_signal(int sig) { - int i; + size_t i; #ifndef CONFIG_NATIVE_WINDOWS if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) { @@ -992,7 +997,7 @@ static void eloop_handle_signal(int sig) static void eloop_process_pending_signals(void) { - int i; + size_t i; if (eloop.signaled == 0) return; diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c index 9c8b12be..74eaa33e 100644 --- a/src/utils/eloop_win.c +++ b/src/utils/eloop_win.c @@ -54,7 +54,7 @@ struct eloop_data { struct dl_list timeout; - int signal_count; + size_t signal_count; struct eloop_signal *signals; int signaled; int pending_terminate; @@ -422,7 +422,7 @@ int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs, #if 0 static void eloop_handle_signal(int sig) { - int i; + size_t i; eloop.signaled++; for (i = 0; i < eloop.signal_count; i++) { @@ -437,7 +437,7 @@ static void eloop_handle_signal(int sig) static void eloop_process_pending_signals(void) { - int i; + size_t i; if (eloop.signaled == 0) return; @@ -517,7 +517,7 @@ int eloop_register_signal_terminate(eloop_signal_handler handler, eloop.term_signal.handler = handler; eloop.term_signal.user_data = user_data; - + return 0; } diff --git a/src/utils/http-utils.h b/src/utils/http-utils.h index 8d4399a3..d9fc925a 100644 --- a/src/utils/http-utils.h +++ b/src/utils/http-utils.h @@ -28,11 +28,11 @@ struct http_logo { struct http_cert { char **dnsname; - unsigned int num_dnsname; + size_t num_dnsname; struct http_othername *othername; - unsigned int num_othername; + size_t num_othername; struct http_logo *logo; - unsigned int num_logo; + size_t num_logo; }; int soap_init_client(struct http_ctx *ctx, const char *address, diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 494bf4cc..ae2f8029 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -339,6 +339,8 @@ char * os_rel2abs_path(const char *rel_path) int os_program_init(void) { + unsigned int seed; + #ifdef ANDROID struct __user_cap_header_struct header; struct __user_cap_data_struct cap; @@ -391,6 +393,9 @@ int os_program_init(void) capset(&header, &cap); #endif /* ANDROID */ + if (os_get_random((unsigned char *) &seed, sizeof(seed)) == 0) + srandom(seed); + return 0; } diff --git a/src/utils/trace.c b/src/utils/trace.c index 40843432..8f12da87 100644 --- a/src/utils/trace.c +++ b/src/utils/trace.c @@ -146,6 +146,17 @@ struct bfd_data { unsigned int line; }; +/* + * binutils removed the bfd parameter and renamed things but + * those were macros so we can detect their absence. + * Cf. https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=commitdiff;h=fd3619828e94a24a92cddec42cbc0ab33352eeb4;hp=5dfda3562a69686c43aad4fb0269cc9d5ec010d5 + */ +#ifndef bfd_get_section_vma +#define bfd_get_section_vma(bfd, section) bfd_section_vma(section) +#endif +#ifndef bfd_get_section_size +#define bfd_get_section_size bfd_section_size +#endif static void find_addr_sect(bfd *abfd, asection *section, void *obj) { diff --git a/src/utils/utils_module_tests.c b/src/utils/utils_module_tests.c index b09225de..365f21fb 100644 --- a/src/utils/utils_module_tests.c +++ b/src/utils/utils_module_tests.c @@ -226,7 +226,7 @@ static int int_array_tests(void) int test3[] = { 1, 1, 1, -1, 2, 3, 4, 1, 2, 0 }; int test3_res[] = { -1, 1, 2, 3, 4, 0 }; int errors = 0; - int len; + size_t len; wpa_printf(MSG_INFO, "int_array tests"); @@ -930,7 +930,7 @@ static int const_time_tests(void) { 0, 0 }, { 1, 0 }, { 2, 0 }, - { 1 << (sizeof(unsigned int) * 8 - 1), ~0 }, + { 1U << (sizeof(unsigned int) * 8 - 1), ~0 }, { ~0 - 1, ~0 }, { ~0, ~0 } }; @@ -941,7 +941,7 @@ static int const_time_tests(void) { 0, ~0 }, { 1, 0 }, { 2, 0 }, - { 1 << (sizeof(unsigned int) * 8 - 1), 0 }, + { 1U << (sizeof(unsigned int) * 8 - 1), 0 }, { ~0 - 1, 0 }, { ~0, 0 } }; diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index c336e538..a338a203 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -12,8 +12,6 @@ #ifdef CONFIG_DEBUG_SYSLOG #include <syslog.h> - -int wpa_debug_syslog = 0; #endif /* CONFIG_DEBUG_SYSLOG */ #ifdef CONFIG_DEBUG_LINUX_TRACING @@ -32,6 +30,10 @@ static FILE *wpa_debug_tracing_file = NULL; int wpa_debug_level = MSG_INFO; int wpa_debug_show_keys = 0; int wpa_debug_timestamp = 0; +int wpa_debug_syslog = 0; +#ifndef CONFIG_NO_STDOUT_DEBUG +static FILE *out_file = NULL; +#endif /* CONFIG_NO_STDOUT_DEBUG */ #ifdef CONFIG_ANDROID_LOG @@ -61,8 +63,6 @@ static int wpa_to_android_level(int level) #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> - -static FILE *out_file = NULL; #endif /* CONFIG_DEBUG_FILE */ @@ -76,12 +76,12 @@ void wpa_debug_print_timestamp(void) os_get_time(&tv); #ifdef CONFIG_DEBUG_FILE - if (out_file) { + if (out_file) fprintf(out_file, "%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); - } else #endif /* CONFIG_DEBUG_FILE */ - printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); + if (!out_file && !wpa_debug_syslog) + printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec); #endif /* CONFIG_ANDROID_LOG */ } @@ -210,35 +210,37 @@ void wpa_printf(int level, const char *fmt, ...) { va_list ap; - va_start(ap, fmt); if (level >= wpa_debug_level) { #ifdef CONFIG_ANDROID_LOG + va_start(ap, fmt); __android_log_vprint(wpa_to_android_level(level), ANDROID_LOG_NAME, fmt, ap); + va_end(ap); #else /* CONFIG_ANDROID_LOG */ #ifdef CONFIG_DEBUG_SYSLOG if (wpa_debug_syslog) { + va_start(ap, fmt); vsyslog(syslog_priority(level), fmt, ap); - } else { + va_end(ap); + } #endif /* CONFIG_DEBUG_SYSLOG */ wpa_debug_print_timestamp(); #ifdef CONFIG_DEBUG_FILE if (out_file) { + va_start(ap, fmt); vfprintf(out_file, fmt, ap); fprintf(out_file, "\n"); - } else { -#endif /* CONFIG_DEBUG_FILE */ - vprintf(fmt, ap); - printf("\n"); -#ifdef CONFIG_DEBUG_FILE + va_end(ap); } #endif /* CONFIG_DEBUG_FILE */ -#ifdef CONFIG_DEBUG_SYSLOG + if (!wpa_debug_syslog && !out_file) { + va_start(ap, fmt); + vprintf(fmt, ap); + printf("\n"); + va_end(ap); } -#endif /* CONFIG_DEBUG_SYSLOG */ #endif /* CONFIG_ANDROID_LOG */ } - va_end(ap); #ifdef CONFIG_DEBUG_LINUX_TRACING if (wpa_debug_tracing_file != NULL) { @@ -254,7 +256,7 @@ void wpa_printf(int level, const char *fmt, ...) static void _wpa_hexdump(int level, const char *title, const u8 *buf, - size_t len, int show) + size_t len, int show, int only_syslog) { size_t i; @@ -345,7 +347,8 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s", title, (unsigned long) len, display); bin_clear_free(strbuf, 1 + 3 * len); - return; + if (only_syslog) + return; } #endif /* CONFIG_DEBUG_SYSLOG */ wpa_debug_print_timestamp(); @@ -362,33 +365,32 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf, fprintf(out_file, " [REMOVED]"); } fprintf(out_file, "\n"); - } else { -#endif /* CONFIG_DEBUG_FILE */ - printf("%s - hexdump(len=%lu):", title, (unsigned long) len); - if (buf == NULL) { - printf(" [NULL]"); - } else if (show) { - for (i = 0; i < len; i++) - printf(" %02x", buf[i]); - } else { - printf(" [REMOVED]"); - } - printf("\n"); -#ifdef CONFIG_DEBUG_FILE } #endif /* CONFIG_DEBUG_FILE */ + if (!wpa_debug_syslog && !out_file) { + printf("%s - hexdump(len=%lu):", title, (unsigned long) len); + if (buf == NULL) { + printf(" [NULL]"); + } else if (show) { + for (i = 0; i < len; i++) + printf(" %02x", buf[i]); + } else { + printf(" [REMOVED]"); + } + printf("\n"); + } #endif /* CONFIG_ANDROID_LOG */ } void wpa_hexdump(int level, const char *title, const void *buf, size_t len) { - _wpa_hexdump(level, title, buf, len, 1); + _wpa_hexdump(level, title, buf, len, 1, 0); } void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len) { - _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys); + _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys, 0); } @@ -421,13 +423,11 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, if (level < wpa_debug_level) return; #ifdef CONFIG_ANDROID_LOG - _wpa_hexdump(level, title, buf, len, show); + _wpa_hexdump(level, title, buf, len, show, 0); #else /* CONFIG_ANDROID_LOG */ #ifdef CONFIG_DEBUG_SYSLOG - if (wpa_debug_syslog) { - _wpa_hexdump(level, title, buf, len, show); - return; - } + if (wpa_debug_syslog) + _wpa_hexdump(level, title, buf, len, show, 1); #endif /* CONFIG_DEBUG_SYSLOG */ wpa_debug_print_timestamp(); #ifdef CONFIG_DEBUG_FILE @@ -436,13 +436,13 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, fprintf(out_file, "%s - hexdump_ascii(len=%lu): [REMOVED]\n", title, (unsigned long) len); - return; + goto file_done; } if (buf == NULL) { fprintf(out_file, "%s - hexdump_ascii(len=%lu): [NULL]\n", title, (unsigned long) len); - return; + goto file_done; } fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); @@ -466,42 +466,43 @@ static void _wpa_hexdump_ascii(int level, const char *title, const void *buf, pos += llen; len -= llen; } - } else { -#endif /* CONFIG_DEBUG_FILE */ - if (!show) { - printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", - title, (unsigned long) len); - return; } - if (buf == NULL) { - printf("%s - hexdump_ascii(len=%lu): [NULL]\n", - title, (unsigned long) len); - return; - } - printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len); - while (len) { - llen = len > line_len ? line_len : len; - printf(" "); - for (i = 0; i < llen; i++) - printf(" %02x", pos[i]); - for (i = llen; i < line_len; i++) +file_done: +#endif /* CONFIG_DEBUG_FILE */ + if (!wpa_debug_syslog && !out_file) { + if (!show) { + printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n", + title, (unsigned long) len); + return; + } + if (buf == NULL) { + printf("%s - hexdump_ascii(len=%lu): [NULL]\n", + title, (unsigned long) len); + return; + } + printf("%s - hexdump_ascii(len=%lu):\n", title, + (unsigned long) len); + while (len) { + llen = len > line_len ? line_len : len; + printf(" "); + for (i = 0; i < llen; i++) + printf(" %02x", pos[i]); + for (i = llen; i < line_len; i++) + printf(" "); printf(" "); - printf(" "); - for (i = 0; i < llen; i++) { - if (isprint(pos[i])) - printf("%c", pos[i]); - else - printf("_"); + for (i = 0; i < llen; i++) { + if (isprint(pos[i])) + printf("%c", pos[i]); + else + printf("_"); + } + for (i = llen; i < line_len; i++) + printf(" "); + printf("\n"); + pos += llen; + len -= llen; } - for (i = llen; i < line_len; i++) - printf(" "); - printf("\n"); - pos += llen; - len -= llen; - } -#ifdef CONFIG_DEBUG_FILE } -#endif /* CONFIG_DEBUG_FILE */ #endif /* CONFIG_ANDROID_LOG */ } diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h index c94c4391..c6d5cc64 100644 --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h @@ -14,9 +14,7 @@ extern int wpa_debug_level; extern int wpa_debug_show_keys; extern int wpa_debug_timestamp; -#ifdef CONFIG_DEBUG_SYSLOG extern int wpa_debug_syslog; -#endif /* CONFIG_DEBUG_SYSLOG */ /* Debugging function - conditional printf and hex dump. Driver wrappers can * use these for debugging purposes. */ diff --git a/src/wps/wps.h b/src/wps/wps.h index 9963c468..93888b01 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -98,6 +98,7 @@ struct wps_device_data { u16 config_methods; struct wpabuf *vendor_ext_m1; struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; + struct wpabuf *application_ext; int p2p; u8 multi_ap_ext; @@ -344,6 +345,14 @@ struct wps_registrar_config { const char *dev_name); /** + * lookup_pskfile_cb - Callback for searching for PSK in wpa_psk_file + * @ctx: Higher layer context data (cb_ctx) + * @addr: Enrollee's MAC address + * @psk: Pointer to found PSK (output arg) + */ + int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk); + + /** * cb_ctx: Higher layer context data for Registrar callbacks */ void *cb_ctx; @@ -386,11 +395,6 @@ struct wps_registrar_config { int disable_auto_conf; /** - * static_wep_only - Whether the BSS supports only static WEP - */ - int static_wep_only; - - /** * dualband - Whether this is a concurrent dualband AP */ int dualband; diff --git a/src/wps/wps_dev_attr.c b/src/wps/wps_dev_attr.c index b209fea8..c2e949cb 100644 --- a/src/wps/wps_dev_attr.c +++ b/src/wps/wps_dev_attr.c @@ -242,6 +242,21 @@ int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg) } +int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg) +{ + if (!dev->application_ext) + return 0; + + wpa_hexdump_buf(MSG_DEBUG, "WPS: * Application Extension", + dev->application_ext); + wpabuf_put_be16(msg, ATTR_APPLICATION_EXT); + wpabuf_put_be16(msg, wpabuf_len(dev->application_ext)); + wpabuf_put_buf(msg, dev->application_ext); + + return 0; +} + + static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str, size_t str_len) { @@ -424,4 +439,6 @@ void wps_device_data_free(struct wps_device_data *dev) dev->model_number = NULL; os_free(dev->serial_number); dev->serial_number = NULL; + wpabuf_free(dev->application_ext); + dev->application_ext = NULL; } diff --git a/src/wps/wps_dev_attr.h b/src/wps/wps_dev_attr.h index a4b4173c..81fdd5f4 100644 --- a/src/wps/wps_dev_attr.h +++ b/src/wps/wps_dev_attr.h @@ -33,6 +33,7 @@ void wps_process_vendor_ext_m1(struct wps_device_data *dev, const u8 ext); int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands); void wps_device_data_free(struct wps_device_data *dev); int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg); +int wps_build_application_ext(struct wps_device_data *dev, struct wpabuf *msg); int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg, unsigned int num_req_dev_types, const u8 *req_dev_types); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 671f5fed..9ee89ae3 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -17,6 +17,7 @@ #include "crypto/sha256.h" #include "crypto/random.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_common.h" #include "wps_i.h" #include "wps_dev_attr.h" #include "wps_upnp.h" @@ -159,6 +160,7 @@ struct wps_registrar { const u8 *pri_dev_type, u16 config_methods, u16 dev_password_id, u8 request_type, const char *dev_name); + int (*lookup_pskfile_cb)(void *ctx, const u8 *mac_addr, const u8 **psk); void *cb_ctx; struct dl_list pins; @@ -171,7 +173,6 @@ struct wps_registrar { int sel_reg_union; int sel_reg_dev_password_id_override; int sel_reg_config_methods_override; - int static_wep_only; int dualband; int force_per_enrollee_psk; @@ -681,6 +682,7 @@ wps_registrar_init(struct wps_context *wps, reg->reg_success_cb = cfg->reg_success_cb; reg->set_sel_reg_cb = cfg->set_sel_reg_cb; reg->enrollee_seen_cb = cfg->enrollee_seen_cb; + reg->lookup_pskfile_cb = cfg->lookup_pskfile_cb; reg->cb_ctx = cfg->cb_ctx; reg->skip_cred_build = cfg->skip_cred_build; if (cfg->extra_cred) { @@ -694,7 +696,6 @@ wps_registrar_init(struct wps_context *wps, reg->disable_auto_conf = cfg->disable_auto_conf; reg->sel_reg_dev_password_id_override = -1; reg->sel_reg_config_methods_override = -1; - reg->static_wep_only = cfg->static_wep_only; reg->dualband = cfg->dualband; reg->force_per_enrollee_psk = cfg->force_per_enrollee_psk; @@ -1290,6 +1291,15 @@ static void wps_cb_set_sel_reg(struct wps_registrar *reg) } +static int wps_cp_lookup_pskfile(struct wps_registrar *reg, const u8 *mac_addr, + const u8 **psk) +{ + if (!reg->lookup_pskfile_cb) + return 0; + return reg->lookup_pskfile_cb(reg->cb_ctx, mac_addr, psk); +} + + static int wps_set_ie(struct wps_registrar *reg) { struct wpabuf *beacon; @@ -1331,7 +1341,8 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_sel_pbc_reg_uuid_e(reg, beacon) || (reg->dualband && wps_build_rf_bands(®->wps->dev, beacon, 0)) || wps_build_wfa_ext(beacon, 0, auth_macs, count, 0) || - wps_build_vendor_ext(®->wps->dev, beacon)) { + wps_build_vendor_ext(®->wps->dev, beacon) || + wps_build_application_ext(®->wps->dev, beacon)) { wpabuf_free(beacon); wpabuf_free(probe); return -1; @@ -1361,7 +1372,8 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_probe_config_methods(reg, probe) || (reg->dualband && wps_build_rf_bands(®->wps->dev, probe, 0)) || wps_build_wfa_ext(probe, 0, auth_macs, count, 0) || - wps_build_vendor_ext(®->wps->dev, probe)) { + wps_build_vendor_ext(®->wps->dev, probe) || + wps_build_application_ext(®->wps->dev, probe)) { wpabuf_free(beacon); wpabuf_free(probe); return -1; @@ -1376,28 +1388,6 @@ static int wps_set_ie(struct wps_registrar *reg) return -1; } - if (reg->static_wep_only) { - /* - * Windows XP and Vista clients can get confused about - * EAP-Identity/Request when they probe the network with - * EAPOL-Start. In such a case, they may assume the network is - * using IEEE 802.1X and prompt user for a certificate while - * the correct (non-WPS) behavior would be to ask for the - * static WEP key. As a workaround, use Microsoft Provisioning - * IE to advertise that legacy 802.1X is not supported. - */ - const u8 ms_wps[7] = { - WLAN_EID_VENDOR_SPECIFIC, 5, - /* Microsoft Provisioning IE (00:50:f2:5) */ - 0x00, 0x50, 0xf2, 5, - 0x00 /* no legacy 802.1X or MS WPS */ - }; - wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE " - "into Beacon/Probe Response frames"); - wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps)); - wpabuf_put_data(probe, ms_wps, sizeof(ms_wps)); - } - return wps_cb_set_ie(reg, beacon, probe); } @@ -1642,6 +1632,8 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) { struct wpabuf *cred; struct wps_registrar *reg = wps->wps->registrar; + const u8 *pskfile_psk; + char hex[65]; if (wps->wps->registrar->skip_cred_build) goto skip_cred_build; @@ -1757,23 +1749,27 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wps->new_psk, wps->new_psk_len); os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len); wps->cred.key_len = wps->new_psk_len; + } else if (wps_cp_lookup_pskfile(reg, wps->mac_addr_e, &pskfile_psk)) { + wpa_hexdump_key(MSG_DEBUG, "WPS: Use PSK from wpa_psk_file", + pskfile_psk, PMK_LEN); + wpa_snprintf_hex(hex, sizeof(hex), pskfile_psk, PMK_LEN); + os_memcpy(wps->cred.key, hex, PMK_LEN * 2); + wps->cred.key_len = PMK_LEN * 2; } else if (!wps->wps->registrar->force_per_enrollee_psk && wps->use_psk_key && wps->wps->psk_set) { - char hex[65]; wpa_printf(MSG_DEBUG, "WPS: Use PSK format for Network Key"); - wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, 32); - os_memcpy(wps->cred.key, hex, 32 * 2); - wps->cred.key_len = 32 * 2; + wpa_snprintf_hex(hex, sizeof(hex), wps->wps->psk, PMK_LEN); + os_memcpy(wps->cred.key, hex, PMK_LEN * 2); + wps->cred.key_len = PMK_LEN * 2; } else if (!wps->wps->registrar->force_per_enrollee_psk && wps->wps->network_key) { os_memcpy(wps->cred.key, wps->wps->network_key, wps->wps->network_key_len); wps->cred.key_len = wps->wps->network_key_len; } else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) { - char hex[65]; /* Generate a random per-device PSK */ os_free(wps->new_psk); - wps->new_psk_len = 32; + wps->new_psk_len = PMK_LEN; wps->new_psk = os_malloc(wps->new_psk_len); if (wps->new_psk == NULL) return -1; @@ -3482,6 +3478,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx, "unselect internal Registrar"); reg->selected_registrar = 0; reg->pbc = 0; + wps_registrar_expire_pins(reg); wps_registrar_selected_registrar_changed(reg, 0); } diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 309127ec..65c639b6 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -124,6 +124,7 @@ OBJS += src/utils/wpa_debug.c OBJS += src/utils/wpabuf.c OBJS += src/utils/bitfield.c OBJS += src/utils/ip_addr.c +OBJS += src/utils/crc32.c OBJS += wmm_ac.c OBJS += op_classes.c OBJS += rrm.c @@ -195,6 +196,10 @@ ifdef CONFIG_VHT_OVERRIDES L_CFLAGS += -DCONFIG_VHT_OVERRIDES endif +ifdef CONFIG_HE_OVERRIDES +L_CFLAGS += -DCONFIG_HE_OVERRIDES +endif + ifndef CONFIG_BACKEND CONFIG_BACKEND=file endif @@ -282,6 +287,7 @@ NEED_ECC=y NEED_JSON=y NEED_GAS_SERVER=y NEED_BASE64=y +NEED_ASN1=y ifdef CONFIG_DPP2 L_CFLAGS += -DCONFIG_DPP2 endif @@ -410,6 +416,10 @@ OBJS += src/fst/fst_ctrl_iface.c endif endif +ifdef CONFIG_WEP +L_CFLAGS += -DCONFIG_WEP +endif + include $(LOCAL_PATH)/src/drivers/drivers.mk @@ -890,7 +900,6 @@ OBJS += src/ap/bss_load.c OBJS += src/ap/eap_user_db.c OBJS += src/ap/neighbor_db.c OBJS += src/ap/rrm.c -ifdef CONFIG_IEEE80211N OBJS += src/ap/ieee802_11_ht.c ifdef CONFIG_IEEE80211AC OBJS += src/ap/ieee802_11_vht.c @@ -898,7 +907,6 @@ endif ifdef CONFIG_IEEE80211AX OBJS += src/ap/ieee802_11_he.c endif -endif ifdef CONFIG_WNM_AP L_CFLAGS += -DCONFIG_WNM_AP OBJS += src/ap/wnm_ap.c @@ -918,15 +926,12 @@ OBJS += src/eap_server/eap_server.c OBJS += src/eap_server/eap_server_identity.c OBJS += src/eap_server/eap_server_methods.c -ifdef CONFIG_IEEE80211N -L_CFLAGS += -DCONFIG_IEEE80211N ifdef CONFIG_IEEE80211AC L_CFLAGS += -DCONFIG_IEEE80211AC endif ifdef CONFIG_IEEE80211AX L_CFLAGS += -DCONFIG_IEEE80211AX endif -endif ifdef NEED_AP_MLME OBJS += src/ap/wmm.c @@ -1123,7 +1128,7 @@ OBJS += src/tls/tlsv1_client.c OBJS += src/tls/tlsv1_client_write.c OBJS += src/tls/tlsv1_client_read.c OBJS += src/tls/tlsv1_client_ocsp.c -OBJS += src/tls/asn1.c +NEED_ASN1=y OBJS += src/tls/rsa.c OBJS += src/tls/x509v3.c OBJS += src/tls/pkcs1.c @@ -1413,6 +1418,10 @@ endif OBJS += src/crypto/sha512-prf.c endif +ifdef NEED_ASN1 +OBJS += src/tls/asn1.c +endif + ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_groups.c endif diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 68ef5a2f..45f673ee 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -104,6 +104,7 @@ OBJS += ../src/utils/wpa_debug.o OBJS += ../src/utils/wpabuf.o OBJS += ../src/utils/bitfield.o OBJS += ../src/utils/ip_addr.o +OBJS += ../src/utils/crc32.o OBJS += op_classes.o OBJS += rrm.o OBJS_p = wpa_passphrase.o @@ -197,6 +198,10 @@ ifdef CONFIG_VHT_OVERRIDES CFLAGS += -DCONFIG_VHT_OVERRIDES endif +ifdef CONFIG_HE_OVERRIDES +CFLAGS += -DCONFIG_HE_OVERRIDES +endif + ifndef CONFIG_BACKEND CONFIG_BACKEND=file endif @@ -284,6 +289,7 @@ NEED_ECC=y NEED_JSON=y NEED_GAS_SERVER=y NEED_BASE64=y +NEED_ASN1=y ifdef CONFIG_DPP2 CFLAGS += -DCONFIG_DPP2 endif @@ -906,7 +912,6 @@ OBJS += ../src/ap/bss_load.o OBJS += ../src/ap/eap_user_db.o OBJS += ../src/ap/neighbor_db.o OBJS += ../src/ap/rrm.o -ifdef CONFIG_IEEE80211N OBJS += ../src/ap/ieee802_11_ht.o ifdef CONFIG_IEEE80211AC OBJS += ../src/ap/ieee802_11_vht.o @@ -914,7 +919,6 @@ endif ifdef CONFIG_IEEE80211AX OBJS += ../src/ap/ieee802_11_he.o endif -endif ifdef CONFIG_WNM_AP CFLAGS += -DCONFIG_WNM_AP OBJS += ../src/ap/wnm_ap.o @@ -934,15 +938,12 @@ OBJS += ../src/eap_server/eap_server.o OBJS += ../src/eap_server/eap_server_identity.o OBJS += ../src/eap_server/eap_server_methods.o -ifdef CONFIG_IEEE80211N -CFLAGS += -DCONFIG_IEEE80211N ifdef CONFIG_IEEE80211AC CFLAGS += -DCONFIG_IEEE80211AC endif ifdef CONFIG_IEEE80211AX CFLAGS += -DCONFIG_IEEE80211AX endif -endif ifdef NEED_AP_MLME OBJS += ../src/ap/wmm.o @@ -1156,12 +1157,12 @@ OBJS += ../src/tls/tlsv1_client.o OBJS += ../src/tls/tlsv1_client_write.o OBJS += ../src/tls/tlsv1_client_read.o OBJS += ../src/tls/tlsv1_client_ocsp.o -OBJS += ../src/tls/asn1.o OBJS += ../src/tls/rsa.o OBJS += ../src/tls/x509v3.o OBJS += ../src/tls/pkcs1.o OBJS += ../src/tls/pkcs5.o OBJS += ../src/tls/pkcs8.o +NEED_ASN1=y NEED_BASE64=y NEED_TLS_PRF=y ifdef CONFIG_TLSV12 @@ -1235,12 +1236,12 @@ OBJS += ../src/tls/tlsv1_client.o OBJS += ../src/tls/tlsv1_client_write.o OBJS += ../src/tls/tlsv1_client_read.o OBJS += ../src/tls/tlsv1_client_ocsp.o -OBJS += ../src/tls/asn1.o OBJS += ../src/tls/rsa.o OBJS += ../src/tls/x509v3.o OBJS += ../src/tls/pkcs1.o OBJS += ../src/tls/pkcs5.o OBJS += ../src/tls/pkcs8.o +NEED_ASN1=y NEED_BASE64=y NEED_TLS_PRF=y ifdef CONFIG_TLSV12 @@ -1523,6 +1524,10 @@ CFLAGS += -DCONFIG_SHA512 OBJS += ../src/crypto/sha512-prf.o endif +ifdef NEED_ASN1 +OBJS += ../src/tls/asn1.o +endif + ifdef NEED_DH_GROUPS OBJS += ../src/crypto/dh_groups.o endif @@ -1846,6 +1851,10 @@ OBJS_t2 += $(FST_OBJS) OBJS_nfc += $(FST_OBJS) endif +ifdef CONFIG_WEP +CFLAGS += -DCONFIG_WEP +endif + ifndef LDO LDO=$(CC) endif diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP index 457e32ee..d378245c 100644 --- a/wpa_supplicant/README-DPP +++ b/wpa_supplicant/README-DPP @@ -9,40 +9,44 @@ Connector mechanism. Introduction to DPP ------------------- -Device provisioning Protocol allows enrolling of interface-less devices -in a secure Wi-Fi network using many methods like QR code based -authentication( detailed below ), PKEX based authentication etc. In DPP -a Configurator is used to provide network credentials to the devices. -The three phases of DPP connection are authentication, configuration and +Device Provisioning Protocol (also known as Wi-Fi Easy Connect) allows +enrolling of interface-less devices in a secure Wi-Fi network using many +methods like QR code based authentication (detailed below), PKEX based +authentication (password with in-band provisioning), etc. In DPP a +Configurator is used to provide network credentials to the devices. The +three phases of DPP connection are authentication, configuration and network introduction. +More information about Wi-Fi Easy Connect is available from this Wi-Fi +Alliance web page: +https://www.wi-fi.org/discover-wi-fi/wi-fi-easy-connect + Build config setup ------------------ -The following changes must go in the config file used to compile hostapd -and wpa_supplicant. +The following parameters must be included in the config file used to +compile hostapd and wpa_supplicant. wpa_supplicant build config --------------------------- -Enable DPP and protected management frame in wpa_supplicant build config -file +Enable DPP in wpa_supplicant build config file CONFIG_DPP=y hostapd build config -------------------- -Enable DPP and protected management frame in hostapd build config file +Enable DPP in hostapd build config file CONFIG_DPP=y Configurator build config ------------------------- -Any STA or AP device can act as a Configurator. Enable DPP and protected -managment frames in build config. For an AP to act as Configurator, -Interworking needs to be enabled. For wpa_supplicant it is not required. +Any STA or AP device can act as a Configurator. Enable DPP in build +config. For an AP to act as a Configurator, Interworking needs to be +enabled for GAS. For wpa_supplicant it is not required. CONFIG_INTERWORKING=y @@ -90,41 +94,46 @@ To get key of Configurator > dpp_configurator_get_key <id> -How to configure an enrollee using Configurator +How to configure an Enrollee using Configurator ----------------------------------------------- -On enrollee side: +On Enrollee side: -Generate QR code for the device. Store the qr code id returned by the +Generate QR code for the device. Store the QR code id returned by the command. -> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/operating-channel> key=<key of the device> -(returns bootstrapping info id) +> dpp_bootstrap_gen type=qrcode mac=<mac-address-of-device> chan=<operating-class/channel> key=<key of the device> +(Returns bootstrapping info id. If the key parameter is not included, a new key +is generated automatically. The MAC address is specified without octet +separating colons. The channel list includes the possible channels on which the +device is waiting. This uses global operating classes; e.g., 81/1 is the 2.4 +GHz channel 1 on 2412 MHz.) -Get QR Code of device using the bootstrap info id. +Get URI for the QR Code of device using the bootstrap info id. > dpp_bootstrap_get_uri <bootstrap-id> -Make device listen to DPP request (The central frequency of channel 1 is -2412) in case if enrollee is a client device. +Make device listen to DPP request. The central frequency of the 2.4 GHz +band channel 1 is 2412 MHz) in case the Enrollee is a client device. An +AP as an Enrollee is listening on its operating channel. > dpp_listen <frequency> On Configurator side: Enter the QR Code in the Configurator. -> dpp_qr_code "<QR-Code-read-from-enrollee>" +> dpp_qr_code "<URI-from-QR-Code-read-from-enrollee>" On successfully adding QR Code, a bootstrapping info id is returned. -Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an -AP. conf is sta-dpp if enrollee is a client) +Send provisioning request to Enrollee. (conf is ap-dpp if Enrollee is an +AP. conf is sta-dpp if Enrollee is a client) > dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> ssid=<SSID hexdump> configurator=<configurator-id> or for legacy (PSK/SAE) provisioning for a station Enrollee: > dpp_auth_init peer=<qr-code-id> conf=sta-psk ssid=<SSID hexdump> pass=<passphrase hexdump> -The DPP values will be printed in the console. Save this values into the -config file. If the enrollee is an AP, we need to manually write these -values to the hostapd config file. If the enrollee is a client device, +The DPP values will be printed in the console. Save these values into the +config file. If the Enrollee is an AP, we need to manually write these +values to the hostapd config file. If the Enrollee is a client device, these details can be automatically saved to config file using the following command. @@ -156,7 +165,7 @@ command to get DPP credentials. > dpp_configurator_add (returns configurator id) -> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> +> dpp_configurator_sign conf=<ap-dpp|sta-dpp> configurator=<configurator-id> ssid=<SSID hexdump> Sample AP configuration files after provisioning diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config index acefc926..5f8c8f6c 100644 --- a/wpa_supplicant/android.config +++ b/wpa_supplicant/android.config @@ -435,11 +435,7 @@ CONFIG_ANDROID_LOG=y # either wpa_supplicant or hostapd are run. CONFIG_NO_RANDOM_POOL=y -# IEEE 802.11n (High Throughput) support (mainly for AP mode) -CONFIG_IEEE80211N=y - # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) -# (depends on CONFIG_IEEE80211N) #CONFIG_IEEE80211AC=y # Wireless Network Management (IEEE Std 802.11v-2011) @@ -552,4 +548,12 @@ CONFIG_SUITEB192=y # Note: does not configure WAPI implementation itself. #CONFIG_WAPI_INTERFACE=y +# Wired equivalent privacy (WEP) +# WEP is an obsolete cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used for anything anymore. The +# functionality needed to use WEP is available in the current wpa_supplicant +# release under this optional build parameter. This functionality is subject to +# be completely removed in a future release. +CONFIG_WEP=y + include $(wildcard $(LOCAL_PATH)/android_config_*.inc) diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index e552306d..62416820 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -44,7 +44,6 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx); #endif /* CONFIG_WPS */ -#ifdef CONFIG_IEEE80211N static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct hostapd_config *conf, @@ -130,7 +129,6 @@ no_vht: conf->channel + conf->secondary_channel * 2; conf->vht_oper_chwidth = CHANWIDTH_USE_HT; } -#endif /* CONFIG_IEEE80211N */ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, @@ -149,7 +147,6 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, /* TODO: enable HT40 if driver supports it; * drop to 11b if driver does not support 11g */ -#ifdef CONFIG_IEEE80211N /* * Enable HT20 if the driver supports it, by setting conf->ieee80211n * and a mask of allowed capabilities within conf->ht_capab. @@ -269,7 +266,6 @@ int wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s, conf->no_pri_sec_switch = 1; } } -#endif /* CONFIG_IEEE80211N */ return 0; } @@ -348,7 +344,9 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, #endif /* CONFIG_IEEE80211AX */ bss->isolate = !wpa_s->conf->p2p_intra_bss; + bss->extended_key_id = wpa_s->conf->extended_key_id; bss->force_per_enrollee_psk = wpa_s->global->p2p_per_sta_psk; + bss->wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey; if (ssid->p2p_group) { os_memcpy(bss->ip_addr_go, wpa_s->p2pdev->conf->ip_addr_go, 4); @@ -393,6 +391,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->ssid.wpa_psk_set = 1; } else if (ssid->passphrase) { bss->ssid.wpa_passphrase = os_strdup(ssid->passphrase); +#ifdef CONFIG_WEP } else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] || ssid->wep_key_len[2] || ssid->wep_key_len[3]) { struct hostapd_wep_keys *wep = &bss->ssid.wep; @@ -408,6 +407,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, } wep->idx = ssid->wep_tx_keyidx; wep->keys_set = 1; +#endif /* CONFIG_WEP */ } #ifdef CONFIG_SAE if (ssid->sae_password) { @@ -489,11 +489,12 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->wpa_group = wpa_select_ap_group_cipher(bss->wpa, bss->wpa_pairwise, bss->rsn_pairwise); - if (bss->wpa && bss->ieee802_1x) + if (bss->wpa && bss->ieee802_1x) { bss->ssid.security_policy = SECURITY_WPA; - else if (bss->wpa) + } else if (bss->wpa) { bss->ssid.security_policy = SECURITY_WPA_PSK; - else if (bss->ieee802_1x) { +#ifdef CONFIG_WEP + } else if (bss->ieee802_1x) { int cipher = WPA_CIPHER_NONE; bss->ssid.security_policy = SECURITY_IEEE_802_1X; bss->ssid.wep.default_len = bss->default_wep_key_len; @@ -511,6 +512,7 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s, bss->wpa_group = cipher; bss->wpa_pairwise = cipher; bss->rsn_pairwise = cipher; +#endif /* CONFIG_WEP */ } else { bss->ssid.security_policy = SECURITY_PLAINTEXT; bss->wpa_group = WPA_CIPHER_NONE; @@ -605,6 +607,8 @@ no_wps: bss->ftm_responder = wpa_s->conf->ftm_responder; bss->ftm_initiator = wpa_s->conf->ftm_initiator; + bss->transition_disable = ssid->transition_disable; + return 0; } @@ -839,7 +843,6 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, return -1; hapd_iface->owner = wpa_s; hapd_iface->drv_flags = wpa_s->drv_flags; - hapd_iface->smps_modes = wpa_s->drv_smps_modes; hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads; hapd_iface->extended_capa = wpa_s->extended_capa; hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 943a3408..127f43e5 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -906,7 +906,7 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, } } - wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u", + wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu", wpa_s->last_scan_res_used, wpa_s->last_scan_res_size); } diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h index 3ce8cd3f..07167617 100644 --- a/wpa_supplicant/bss.h +++ b/wpa_supplicant/bss.h @@ -18,6 +18,7 @@ struct wpa_scan_res; #define WPA_BSS_AUTHENTICATED BIT(4) #define WPA_BSS_ASSOCIATED BIT(5) #define WPA_BSS_ANQP_FETCH_TRIED BIT(6) +#define WPA_BSS_OWE_TRANSITION BIT(7) struct wpa_bss_anqp_elem { struct dl_list list; diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 2d1c126e..e1d98249 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1856,6 +1856,8 @@ static char * wpa_config_write_machine_password(const struct parse_data *data, #endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_WEP + static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line, const char *value, int idx) { @@ -1966,6 +1968,8 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data, } #endif /* NO_CONFIG_WRITE */ +#endif /* CONFIG_WEP */ + #ifdef CONFIG_P2P @@ -2451,11 +2455,13 @@ static const struct parse_data ssid_fields[] = { { STRe(openssl_ciphers, openssl_ciphers) }, { INTe(erp, erp) }, #endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_WEP { FUNC_KEY(wep_key0) }, { FUNC_KEY(wep_key1) }, { FUNC_KEY(wep_key2) }, { FUNC_KEY(wep_key3) }, { INT(wep_tx_keyidx) }, +#endif /* CONFIG_WEP */ { INT(priority) }, #ifdef IEEE8021X_EAPOL { INT(eap_workaround) }, @@ -2495,6 +2501,7 @@ static const struct parse_data ssid_fields[] = { { INT(dot11MeshHoldingTimeout) }, #endif /* CONFIG_MESH */ { INT(wpa_ptk_rekey) }, + { INT_RANGE(wpa_deny_ptk0_rekey, 0, 2) }, { INT(group_rekey) }, { STR(bgscan) }, { INT_RANGE(ignore_broadcast_ssid, 0, 2) }, @@ -2537,6 +2544,9 @@ static const struct parse_data ssid_fields[] = { { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) }, { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) }, #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + { INT_RANGE(disable_he, 0, 1)}, +#endif /* CONFIG_HE_OVERRIDES */ { INT(ap_max_inactivity) }, { INT(dtim_period) }, { INT(beacon_int) }, @@ -2563,11 +2573,15 @@ static const struct parse_data ssid_fields[] = { { STR_LEN(dpp_netaccesskey) }, { INT(dpp_netaccesskey_expiry) }, { STR_LEN(dpp_csign) }, + { INT_RANGE(dpp_pfs, 0, 2) }, #endif /* CONFIG_DPP */ { INT_RANGE(owe_group, 0, 65535) }, { INT_RANGE(owe_only, 0, 1) }, + { INT_RANGE(owe_ptk_workaround, 0, 1) }, { INT_RANGE(multi_ap_backhaul_sta, 0, 1) }, { INT_RANGE(ft_eap_pmksa_caching, 0, 1) }, + { INT_RANGE(beacon_prot, 0, 1) }, + { INT_RANGE(transition_disable, 0, 255) }, }; #undef OFFSET @@ -2603,7 +2617,7 @@ static const struct parse_data ssid_fields[] = { int wpa_config_add_prio_network(struct wpa_config *config, struct wpa_ssid *ssid) { - int prio; + size_t prio; struct wpa_ssid *prev, **nlist; /* @@ -3018,6 +3032,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid) ssid->pairwise_cipher = DEFAULT_PAIRWISE; ssid->group_cipher = DEFAULT_GROUP; ssid->key_mgmt = DEFAULT_KEY_MGMT; + ssid->wpa_deny_ptk0_rekey = PTK0_REKEY_ALLOW_ALWAYS; ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD; ssid->ht = 1; #ifdef IEEE8021X_EAPOL @@ -4283,6 +4298,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD; config->cert_in_cb = DEFAULT_CERT_IN_CB; config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION; + config->extended_key_id = DEFAULT_EXTENDED_KEY_ID; #ifdef CONFIG_MBO config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA; @@ -4308,7 +4324,7 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, */ void wpa_config_debug_dump_networks(struct wpa_config *config) { - int prio; + size_t prio; struct wpa_ssid *ssid; for (prio = 0; prio < config->num_prio; prio++) { @@ -4639,7 +4655,7 @@ static int wpa_config_process_p2p_pref_chan( struct wpa_config *config, int line, const char *pos) { struct p2p_channel *pref = NULL, *n; - unsigned int num = 0; + size_t num = 0; const char *pos2; u8 op_class, chan; @@ -4997,7 +5013,7 @@ static const struct global_parse_data global_fields[] = { { INT(okc), 0 }, { INT(pmf), 0 }, { FUNC(sae_groups), 0 }, - { INT_RANGE(sae_pwe, 0, 2), 0 }, + { INT_RANGE(sae_pwe, 0, 3), 0 }, { INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 }, { INT(dtim_period), 0 }, { INT(beacon_int), 0 }, @@ -5047,6 +5063,7 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(bss_no_flush_when_down, 0, 1), 0 }, #ifdef CONFIG_WNM { INT_RANGE(disable_btm, 0, 1), CFG_CHANGED_DISABLE_BTM }, + { INT_RANGE(extended_key_id, 0, 1), 0 }, #endif /* CONFIG_WNM */ }; diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index d00c4ec0..0ca27cb3 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -44,6 +44,7 @@ #define DEFAULT_MBO_CELL_CAPA MBO_CELL_CAPA_NOT_SUPPORTED #define DEFAULT_DISASSOC_IMMINENT_RSSI_THRESHOLD -75 #define DEFAULT_OCE_SUPPORT OCE_STA +#define DEFAULT_EXTENDED_KEY_ID 0 #include "config_ssid.h" #include "wps/wps.h" @@ -332,7 +333,7 @@ struct wpa_cred { */ unsigned int max_bss_load; - unsigned int num_req_conn_capab; + size_t num_req_conn_capab; u8 *req_conn_capab_proto; int **req_conn_capab_port; @@ -403,7 +404,7 @@ struct wpa_config { * This indicates how many per-priority network lists are included in * pssid. */ - int num_prio; + size_t num_prio; /** * cred - Head of the credential list @@ -1578,6 +1579,17 @@ struct wpa_config { * By default BSS transition management is enabled */ int disable_btm; + + /** + * extended_key_id - Extended Key ID support + * + * IEEE Std 802.11-2016 optionally allows to use Key ID 0 and 1 for PTK + * keys with Extended Key ID. + * + * 0 = don't use Extended Key ID + * 1 = use Extended Key ID when possible + */ + int extended_key_id; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 305291eb..52e1372e 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -213,8 +213,22 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id) } } - if (wpa_config_set(ssid, pos, pos2, *line) < 0) + if (wpa_config_set(ssid, pos, pos2, *line) < 0) { +#ifndef CONFIG_WEP + if (os_strcmp(pos, "wep_key0") == 0 || + os_strcmp(pos, "wep_key1") == 0 || + os_strcmp(pos, "wep_key2") == 0 || + os_strcmp(pos, "wep_key3") == 0 || + os_strcmp(pos, "wep_tx_keyidx") == 0) { + wpa_printf(MSG_ERROR, + "Line %d: unsupported WEP parameter", + *line); + ssid->disabled = 1; + continue; + } +#endif /* CONFIG_WEP */ errors++; + } } if (!end) { @@ -653,6 +667,7 @@ static void write_eap(FILE *f, struct wpa_ssid *ssid) #endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_WEP static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid) { char field[20], *value; @@ -667,6 +682,7 @@ static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid) os_free(value); } } +#endif /* CONFIG_WEP */ #ifdef CONFIG_P2P @@ -741,8 +757,6 @@ static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid) static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) { - int i; - #define STR(t) write_str(f, #t, ssid) #define INT(t) write_int(f, #t, ssid->t, 0) #define INTe(t, m) write_int(f, #t, ssid->eap.m, 0) @@ -831,9 +845,15 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(openssl_ciphers); INTe(erp, erp); #endif /* IEEE8021X_EAPOL */ - for (i = 0; i < 4; i++) - write_wep_key(f, i, ssid); - INT(wep_tx_keyidx); +#ifdef CONFIG_WEP + { + int i; + + for (i = 0; i < 4; i++) + write_wep_key(f, i, ssid); + INT(wep_tx_keyidx); + } +#endif /* CONFIG_WEP */ INT(priority); #ifdef IEEE8021X_EAPOL INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); @@ -900,6 +920,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(mesh_rssi_threshold, DEFAULT_MESH_RSSI_THRESHOLD); #endif /* CONFIG_MESH */ INT(wpa_ptk_rekey); + INT(wpa_deny_ptk0_rekey); INT(group_rekey); INT(ignore_broadcast_ssid); #ifdef CONFIG_DPP @@ -907,11 +928,15 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) STR(dpp_netaccesskey); INT(dpp_netaccesskey_expiry); STR(dpp_csign); + INT(dpp_pfs); #endif /* CONFIG_DPP */ INT(owe_group); INT(owe_only); + INT(owe_ptk_workaround); INT(multi_ap_backhaul_sta); INT(ft_eap_pmksa_caching); + INT(beacon_prot); + INT(transition_disable); #ifdef CONFIG_HT_OVERRIDES INT_DEF(disable_ht, DEFAULT_DISABLE_HT); INT_DEF(disable_ht40, DEFAULT_DISABLE_HT40); @@ -946,6 +971,9 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid) INT_DEF(vht_tx_mcs_nss_7, -1); INT_DEF(vht_tx_mcs_nss_8, -1); #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + INT(disable_he); +#endif /* CONFIG_HE_OVERRIDES */ #undef STR #undef INT @@ -1576,6 +1604,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) config->bss_no_flush_when_down); if (config->disable_btm) fprintf(f, "disable_btm=1\n"); + if (config->extended_key_id != DEFAULT_EXTENDED_KEY_ID) + fprintf(f, "extended_key_id=%d\n", + config->extended_key_id); } #endif /* CONFIG_NO_CONFIG_WRITE */ @@ -1592,9 +1623,16 @@ int wpa_config_write(const char *name, struct wpa_config *config) #endif /* CONFIG_NO_CONFIG_BLOBS */ int ret = 0; const char *orig_name = name; - int tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */ - char *tmp_name = os_malloc(tmp_len); + int tmp_len; + char *tmp_name; + + if (!name) { + wpa_printf(MSG_ERROR, "No configuration file for writing"); + return -1; + } + tmp_len = os_strlen(name) + 5; /* allow space for .tmp suffix */ + tmp_name = os_malloc(tmp_len); if (tmp_name) { os_snprintf(tmp_name, tmp_len, "%s.tmp", name); name = tmp_name; @@ -1622,8 +1660,11 @@ int wpa_config_write(const char *name, struct wpa_config *config) for (ssid = config->ssid; ssid; ssid = ssid->next) { if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary) continue; /* do not save temporary networks */ - if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set && - !ssid->passphrase) + if (wpa_key_mgmt_wpa_psk_no_sae(ssid->key_mgmt) && + !ssid->psk_set && !ssid->passphrase) + continue; /* do not save invalid network */ + if (wpa_key_mgmt_sae(ssid->key_mgmt) && + !ssid->passphrase && !ssid->sae_password) continue; /* do not save invalid network */ fprintf(f, "\nnetwork={\n"); wpa_config_write_network(f, ssid); diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h index af8317bd..a186ab9f 100644 --- a/wpa_supplicant/config_ssid.h +++ b/wpa_supplicant/config_ssid.h @@ -299,6 +299,7 @@ struct wpa_ssid { struct eap_peer_config eap; #endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_WEP #define NUM_WEP_KEYS 4 #define MAX_WEP_KEY_LEN 16 /** @@ -315,6 +316,7 @@ struct wpa_ssid { * wep_tx_keyidx - Default key index for TX frames using WEP */ int wep_tx_keyidx; +#endif /* CONFIG_WEP */ /** * proactive_key_caching - Enable proactive key caching @@ -552,6 +554,19 @@ struct wpa_ssid { */ int wpa_ptk_rekey; + /** wpa_deny_ptk0_rekey - Control PTK0 rekeying + * + * Rekeying a pairwise key using only keyid 0 (PTK0 rekey) has many + * broken implementations and should be avoided when using or + * interacting with one. + * + * 0 = always rekey when configured/instructed + * 1 = only rekey when the local driver is explicitly indicating it can + * perform this operation without issues + * 2 = never allow PTK0 rekeys + */ + enum ptk0_rekey_handling wpa_deny_ptk0_rekey; + /** * group_rekey - Group rekeying time in seconds * @@ -763,6 +778,16 @@ struct wpa_ssid { vht_tx_mcs_nss_7, vht_tx_mcs_nss_8; #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + /** + * disable_he - Disable HE (IEEE 802.11ax) for this network + * + * By default, use it if it is available, but this can be configured + * to 1 to have it disabled. + */ + int disable_he; +#endif /* CONFIG_HE_OVERRIDES */ + /** * ap_max_inactivity - Timeout in seconds to detect STA's inactivity * @@ -987,6 +1012,22 @@ struct wpa_ssid { size_t dpp_csign_len; /** + * dpp_pfs - DPP PFS + * 0: allow PFS to be used or not used + * 1: require PFS to be used (note: not compatible with DPP R1) + * 2: do not allow PFS to be used + */ + int dpp_pfs; + + /** + * dpp_pfs_fallback - DPP PFS fallback selection + * + * This is an internally used variable (i.e., not used in external + * configuration) to track state of the DPP PFS fallback mechanism. + */ + int dpp_pfs_fallback; + + /** * owe_group - OWE DH Group * * 0 = use default (19) first and then try all supported groups one by @@ -1008,6 +1049,19 @@ struct wpa_ssid { int owe_only; /** + * owe_ptk_workaround - OWE PTK derivation workaround + * + * Initial OWE implementation used SHA256 when deriving the PTK for all + * OWE groups. This was supposed to change to SHA384 for group 20 and + * SHA512 for group 21. This parameter can be used to enable older + * behavior mainly for testing purposes. There is no impact to group 19 + * behavior, but if enabled, this will make group 20 and 21 cases use + * SHA256-based PTK derivation which will not work with the updated + * OWE implementation on the AP side. + */ + int owe_ptk_workaround; + + /** * owe_transition_bss_select_count - OWE transition BSS select count * * This is an internally used variable (i.e., not used in external @@ -1033,6 +1087,34 @@ struct wpa_ssid { * FT initial mobility domain association. */ int ft_eap_pmksa_caching; + + /** + * beacon_prot - Whether Beacon protection is enabled + * + * This depends on management frame protection (ieee80211w) being + * enabled. + */ + int beacon_prot; + + /** + * transition_disable - Transition Disable indication + * The AP can notify authenticated stations to disable transition mode + * in their network profiles when the network has completed transition + * steps, i.e., once sufficiently large number of APs in the ESS have + * been updated to support the more secure alternative. When this + * indication is used, the stations are expected to automatically + * disable transition mode and less secure security options. This + * includes use of WEP, TKIP (including use of TKIP as the group + * cipher), and connections without PMF. + * Bitmap bits: + * bit 0 (0x01): WPA3-Personal (i.e., disable WPA2-Personal = WPA-PSK + * and only allow SAE to be used) + * bit 1 (0x02): SAE-PK (disable SAE without use of SAE-PK) + * bit 2 (0x04): WPA3-Enterprise (move to requiring PMF) + * bit 3 (0x08): Enhanced Open (disable use of open network; require + * OWE) + */ + u8 transition_disable; }; #endif /* CONFIG_SSID_H */ diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c index 0f2a30a4..1b7f96ed 100644 --- a/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant/config_winreg.c @@ -277,6 +277,15 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk) wpa_config_read_reg_dword(hk, TEXT("okc"), &config->okc); wpa_config_read_reg_dword(hk, TEXT("pmf"), &val); config->pmf = val; + if (wpa_config_read_reg_dword(hk, TEXT("extended_key_id"), + &val) == 0) { + if (val < 0 || val > 1) { + wpa_printf(MSG_ERROR, + "Invalid Extended Key ID setting (%d)", val); + errors++; + } + config->extended_key_id = val; + } return errors ? -1 : 0; } @@ -823,6 +832,7 @@ static void write_eap(HKEY hk, struct wpa_ssid *ssid) #endif /* IEEE8021X_EAPOL */ +#ifdef CONFIG_WEP static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid) { char field[20], *value; @@ -834,11 +844,12 @@ static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid) os_free(value); } } +#endif /* CONFIG_WEP */ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) { - int i, errors = 0; + int errors = 0; HKEY nhk, netw; LONG ret; TCHAR name[5]; @@ -924,9 +935,15 @@ static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id) INTe(engine2, phase2_cert.engine); INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS); #endif /* IEEE8021X_EAPOL */ - for (i = 0; i < 4; i++) - write_wep_key(netw, i, ssid); - INT(wep_tx_keyidx); +#ifdef CONFIG_WEP + { + int i; + + for (i = 0; i < 4; i++) + write_wep_key(netw, i, ssid); + INT(wep_tx_keyidx); + } +#endif /* CONFIG_WEP */ INT(priority); #ifdef IEEE8021X_EAPOL INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index be5ea17b..7301d50f 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -419,6 +419,64 @@ static int wpas_ctrl_iface_set_ric_ies(struct wpa_supplicant *wpa_s, } +#ifdef CONFIG_TESTING_OPTIONS +static int wpas_ctrl_iface_set_dso(struct wpa_supplicant *wpa_s, + const char *val) +{ + u8 bssid[ETH_ALEN]; + const char *pos = val; + struct driver_signal_override *dso = NULL, *tmp, parsed; + + if (hwaddr_aton(pos, bssid)) + return -1; + pos = os_strchr(pos, ' '); + + dl_list_for_each(tmp, &wpa_s->drv_signal_override, + struct driver_signal_override, list) { + if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) { + dso = tmp; + break; + } + } + + if (!pos) { + /* Remove existing entry */ + if (dso) { + dl_list_del(&dso->list); + os_free(dso); + } + return 0; + } + pos++; + + /* Update an existing entry or add a new one */ + os_memset(&parsed, 0, sizeof(parsed)); + if (sscanf(pos, "%d %d %d %d %d", + &parsed.si_current_signal, + &parsed.si_avg_signal, + &parsed.si_avg_beacon_signal, + &parsed.si_current_noise, + &parsed.scan_level) != 5) + return -1; + + if (!dso) { + dso = os_zalloc(sizeof(*dso)); + if (!dso) + return -1; + os_memcpy(dso->bssid, bssid, ETH_ALEN); + dl_list_add(&wpa_s->drv_signal_override, &dso->list); + } + dso->si_current_signal = parsed.si_current_signal; + dso->si_avg_signal = parsed.si_avg_signal; + dso->si_avg_beacon_signal = parsed.si_avg_beacon_signal; + dso->si_current_noise = parsed.si_current_noise; + dso->scan_level = parsed.scan_level; + + return 0; +} +#endif /* CONFIG_TESTING_OPTIONS */ + + static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, char *cmd) { @@ -663,6 +721,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->ignore_assoc_disallow = !!atoi(value); wpa_drv_ignore_assoc_disallow(wpa_s, wpa_s->ignore_assoc_disallow); + } else if (os_strcasecmp(cmd, "disable_sa_query") == 0) { + wpa_s->disable_sa_query = !!atoi(value); } else if (os_strcasecmp(cmd, "ignore_sae_h2e_only") == 0) { wpa_s->ignore_sae_h2e_only = !!atoi(value); } else if (os_strcasecmp(cmd, "extra_sae_rejected_groups") == 0) { @@ -687,6 +747,12 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, break; pos++; } + } else if (os_strcasecmp(cmd, "rsne_override_eapol") == 0) { + wpabuf_free(wpa_s->rsne_override_eapol); + if (os_strcmp(value, "NULL") == 0) + wpa_s->rsne_override_eapol = NULL; + else + wpa_s->rsne_override_eapol = wpabuf_parse_bin(value); } else if (os_strcasecmp(cmd, "rsnxe_override_assoc") == 0) { wpabuf_free(wpa_s->rsnxe_override_assoc); if (os_strcmp(value, "NULL") == 0) @@ -713,6 +779,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, wpa_s->sae_commit_override = NULL; else wpa_s->sae_commit_override = wpabuf_parse_bin(value); + } else if (os_strcasecmp(cmd, "driver_signal_override") == 0) { + ret = wpas_ctrl_iface_set_dso(wpa_s, value); #ifdef CONFIG_DPP } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) { os_free(wpa_s->dpp_config_obj_override); @@ -851,6 +919,8 @@ static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s, return wpa_snprintf_hex(buf, buflen, wpa_sm_get_anonce(wpa_s->wpa), WPA_NONCE_LEN); + } else if (os_strcasecmp(cmd, "last_tk_key_idx") == 0) { + res = os_snprintf(buf, buflen, "%d", wpa_s->last_tk_key_idx); #endif /* CONFIG_TESTING_OPTIONS */ } else { res = wpa_config_get_value(cmd, wpa_s->conf, buf, buflen); @@ -3889,8 +3959,10 @@ static const struct cipher_info ciphers[] = { { WPA_DRIVER_CAPA_ENC_GCMP, "GCMP", 0 }, { WPA_DRIVER_CAPA_ENC_TKIP, "TKIP", 0 }, { WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE, "NONE", 0 }, +#ifdef CONFIG_WEP { WPA_DRIVER_CAPA_ENC_WEP104, "WEP104", 1 }, { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 } +#endif /* CONFIG_WEP */ }; static const struct cipher_info ciphers_group_mgmt[] = { @@ -3952,7 +4024,11 @@ static int ctrl_iface_get_capability_group(int res, char *strict, if (res < 0) { if (strict) return 0; +#ifdef CONFIG_WEP len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen); +#else /* CONFIG_WEP */ + len = os_strlcpy(buf, "CCMP TKIP", buflen); +#endif /* CONFIG_WEP */ if (len >= buflen) return -1; return len; @@ -5285,15 +5361,24 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s) { wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication"); /* MLME-DELETEKEYS.request */ - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0); - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, + 0, KEY_FLAG_GROUP); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, + 0, KEY_FLAG_GROUP); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, + 0, KEY_FLAG_GROUP); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, + 0, KEY_FLAG_GROUP); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, + 0, KEY_FLAG_GROUP); + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, + 0, KEY_FLAG_GROUP); wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL, - 0); + 0, KEY_FLAG_PAIRWISE); + if (wpa_sm_ext_key_id(wpa_s->wpa)) + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 1, 0, + NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid, MLME_SETPROTECTION_PROTECT_TYPE_NONE, @@ -7130,7 +7215,7 @@ static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst, return -1; } - bss = wpa_bss_get_bssid(wpa_s, bssid); + bss = wpa_bss_get_bssid_latest(wpa_s, bssid); if (bss == NULL) { wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR, MAC2STR(bssid)); @@ -8019,6 +8104,10 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->dpp_resp_wait_time = 0; wpa_s->dpp_resp_max_tries = 0; wpa_s->dpp_resp_retry_time = 0; +#ifdef CONFIG_DPP2 + wpas_dpp_chirp_stop(wpa_s); + wpa_s->dpp_pfs_fallback = 0; +#endif /* CONFIG_DPP2 */ #ifdef CONFIG_TESTING_OPTIONS os_memset(dpp_pkex_own_mac_override, 0, ETH_ALEN); os_memset(dpp_pkex_peer_mac_override, 0, ETH_ALEN); @@ -8038,9 +8127,12 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL); wpa_supplicant_stop_countermeasures(wpa_s, NULL); + wpa_s->last_michael_mic_error.sec = 0; wpa_s->no_keep_alive = 0; wpa_s->own_disconnect_req = 0; + wpa_s->own_reconnect_req = 0; + wpa_s->deny_ptk0_rekey = 0; os_free(wpa_s->disallow_aps_bssid); wpa_s->disallow_aps_bssid = NULL; @@ -8089,6 +8181,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->p2p_go_csa_on_inv = 0; wpa_s->ignore_auth_resp = 0; wpa_s->ignore_assoc_disallow = 0; + wpa_s->disable_sa_query = 0; wpa_s->testing_resend_assoc = 0; wpa_s->ignore_sae_h2e_only = 0; wpa_s->reject_btm_req_reason = 0; @@ -8099,10 +8192,13 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->sae_commit_override = NULL; os_free(wpa_s->extra_sae_rejected_groups); wpa_s->extra_sae_rejected_groups = NULL; + wpabuf_free(wpa_s->rsne_override_eapol); + wpa_s->rsne_override_eapol = NULL; wpabuf_free(wpa_s->rsnxe_override_assoc); wpa_s->rsnxe_override_assoc = NULL; wpabuf_free(wpa_s->rsnxe_override_eapol); wpa_s->rsnxe_override_eapol = NULL; + wpas_clear_driver_signal_override(wpa_s); #ifdef CONFIG_DPP os_free(wpa_s->dpp_config_obj_override); wpa_s->dpp_config_obj_override = NULL; @@ -8117,6 +8213,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) wpa_s->disconnected = 0; os_free(wpa_s->next_scan_freqs); wpa_s->next_scan_freqs = NULL; + os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); + wpa_s->next_scan_bssid_wildcard_ssid = 0; os_free(wpa_s->select_network_scan_freqs); wpa_s->select_network_scan_freqs = NULL; @@ -8135,6 +8233,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s) #ifdef CONFIG_SME wpa_s->sme.last_unprot_disconnect.sec = 0; + wpa_s->sme.auth_alg = 0; #endif /* CONFIG_SME */ wpabuf_free(wpa_s->ric_ies); @@ -8451,6 +8550,9 @@ static void wpas_ctrl_scan(struct wpa_supplicant *wpa_s, char *params, goto done; } os_memcpy(wpa_s->next_scan_bssid, bssid, ETH_ALEN); + + wpa_s->next_scan_bssid_wildcard_ssid = + os_strstr(params, "wildcard_ssid=1") != NULL; } pos = params; @@ -8962,7 +9064,7 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, { struct wpa_supplicant *wpa_s = ctx; const struct ether_header *eth; - struct iphdr ip; + struct ip ip; const u8 *pos; unsigned int i; char extra[30]; @@ -8978,14 +9080,13 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, os_memcpy(&ip, eth + 1, sizeof(ip)); pos = &buf[sizeof(*eth) + sizeof(ip)]; - if (ip.ihl != 5 || ip.version != 4 || - ntohs(ip.tot_len) > HWSIM_IP_LEN) { + if (ip.ip_hl != 5 || ip.ip_v != 4 || ntohs(ip.ip_len) > HWSIM_IP_LEN) { wpa_printf(MSG_DEBUG, "test data: RX - ignore unexpect IP header"); return; } - for (i = 0; i < ntohs(ip.tot_len) - sizeof(ip); i++) { + for (i = 0; i < ntohs(ip.ip_len) - sizeof(ip); i++) { if (*pos != (u8) i) { wpa_printf(MSG_DEBUG, "test data: RX - ignore mismatching payload"); @@ -8994,8 +9095,8 @@ static void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, pos++; } extra[0] = '\0'; - if (ntohs(ip.tot_len) != HWSIM_IP_LEN) - os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.tot_len)); + if (ntohs(ip.ip_len) != HWSIM_IP_LEN) + os_snprintf(extra, sizeof(extra), " len=%d", ntohs(ip.ip_len)); wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR "%s", MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost), extra); } @@ -9047,7 +9148,7 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) u8 tos; u8 buf[2 + HWSIM_PACKETLEN]; struct ether_header *eth; - struct iphdr *ip; + struct ip *ip; u8 *dpos; unsigned int i; size_t send_len = HWSIM_IP_LEN; @@ -9086,17 +9187,17 @@ static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd) os_memcpy(eth->ether_dhost, dst, ETH_ALEN); os_memcpy(eth->ether_shost, src, ETH_ALEN); eth->ether_type = htons(ETHERTYPE_IP); - ip = (struct iphdr *) (eth + 1); + ip = (struct ip *) (eth + 1); os_memset(ip, 0, sizeof(*ip)); - ip->ihl = 5; - ip->version = 4; - ip->ttl = 64; - ip->tos = tos; - ip->tot_len = htons(send_len); - ip->protocol = 1; - ip->saddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); - ip->daddr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2); - ip->check = ipv4_hdr_checksum(ip, sizeof(*ip)); + ip->ip_hl = 5; + ip->ip_v = 4; + ip->ip_ttl = 64; + ip->ip_tos = tos; + ip->ip_len = htons(send_len); + ip->ip_p = 1; + ip->ip_src.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 1); + ip->ip_dst.s_addr = htonl(192U << 24 | 168 << 16 | 1 << 8 | 2); + ip->ip_sum = ipv4_hdr_checksum(ip, sizeof(*ip)); dpos = (u8 *) (ip + 1); for (i = 0; i < send_len - sizeof(*ip); i++) *dpos++ = i; @@ -9289,13 +9390,15 @@ static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s) * in the driver. */ if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr, wpa_s->last_tk_key_idx, 1, zero, 6, - zero, wpa_s->last_tk_len) < 0) + zero, wpa_s->last_tk_len, + KEY_FLAG_PAIRWISE_RX_TX) < 0) return -1; /* Set the previously configured key to reset its TSC/RSC */ return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr, wpa_s->last_tk_key_idx, 1, zero, 6, - wpa_s->last_tk, wpa_s->last_tk_len); + wpa_s->last_tk, wpa_s->last_tk_len, + KEY_FLAG_PAIRWISE_RX_TX); } @@ -10741,6 +10844,28 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, if (os_snprintf_error(reply_size, reply_len)) reply_len = -1; } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_REQ ", 21) == 0) { + int res; + + res = wpas_dpp_nfc_handover_req(wpa_s, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } + } else if (os_strncmp(buf, "DPP_NFC_HANDOVER_SEL ", 21) == 0) { + int res; + + res = wpas_dpp_nfc_handover_sel(wpa_s, buf + 20); + if (res < 0) { + reply_len = -1; + } else { + reply_len = os_snprintf(reply, reply_size, "%d", res); + if (os_snprintf_error(reply_size, reply_len)) + reply_len = -1; + } } else if (os_strncmp(buf, "DPP_BOOTSTRAP_GEN ", 18) == 0) { int res; @@ -10769,6 +10894,10 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, } else if (os_strncmp(buf, "DPP_BOOTSTRAP_INFO ", 19) == 0) { reply_len = dpp_bootstrap_info(wpa_s->dpp, atoi(buf + 19), reply, reply_size); + } else if (os_strncmp(buf, "DPP_BOOTSTRAP_SET ", 18) == 0) { + if (dpp_bootstrap_set(wpa_s->dpp, atoi(buf + 18), + os_strchr(buf + 18, ' ')) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DPP_AUTH_INIT ", 14) == 0) { if (wpas_dpp_auth_init(wpa_s, buf + 13) < 0) reply_len = -1; @@ -10822,6 +10951,11 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s, reply_len = -1; } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) { dpp_controller_stop(wpa_s->dpp); + } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) { + if (wpas_dpp_chirp(wpa_s, buf + 9) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) { + wpas_dpp_chirp_stop(wpa_s); #endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ } else { diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index 8a6057a8..1e92b975 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -516,7 +516,7 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, return; if (ifname) - os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>", + os_snprintf(levelstr, sizeof(levelstr), "IFNAME=%s <%d>", ifname, level); else os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 4b6dabcc..4e17e31a 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -991,20 +991,25 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( const struct wpa_dbus_property_desc *property_desc, DBusMessageIter *iter, DBusError *error, void *user_data) { - const char *capabilities[11]; + const char *capabilities[12]; size_t num_items = 0; -#ifdef CONFIG_FILS struct wpa_global *global = user_data; struct wpa_supplicant *wpa_s; +#ifdef CONFIG_FILS int fils_supported = 0, fils_sk_pfs_supported = 0; +#endif /* CONFIG_FILS */ + int ext_key_id_supported = 0; for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) { +#ifdef CONFIG_FILS if (wpa_is_fils_supported(wpa_s)) fils_supported = 1; if (wpa_is_fils_sk_pfs_supported(wpa_s)) fils_sk_pfs_supported = 1; - } #endif /* CONFIG_FILS */ + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID) + ext_key_id_supported = 1; + } #ifdef CONFIG_AP capabilities[num_items++] = "ap"; @@ -1037,6 +1042,8 @@ dbus_bool_t wpas_dbus_getter_global_capabilities( #ifdef CONFIG_OWE capabilities[num_items++] = "owe"; #endif /* CONFIG_OWE */ + if (ext_key_id_supported) + capabilities[num_items++] = "extended_key_id"; return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_STRING, @@ -1146,7 +1153,7 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, DBusMessage **reply) { u8 *ies = NULL, *nies; - int ies_len = 0; + size_t ies_len = 0; DBusMessageIter array_iter, sub_array_iter; char *val; int len; @@ -1177,7 +1184,7 @@ static int wpas_dbus_get_scan_ies(DBusMessage *message, DBusMessageIter *var, dbus_message_iter_recurse(&array_iter, &sub_array_iter); dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len); - if (len == 0) { + if (len <= 0) { dbus_message_iter_next(&array_iter); continue; } @@ -1208,7 +1215,7 @@ static int wpas_dbus_get_scan_channels(DBusMessage *message, { DBusMessageIter array_iter, sub_array_iter; int *freqs = NULL, *nfreqs; - int freqs_num = 0; + size_t freqs_num = 0; if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) { wpa_printf(MSG_DEBUG, @@ -2664,7 +2671,10 @@ dbus_bool_t wpas_dbus_getter_capabilities( /***** group cipher */ if (res < 0) { const char *args[] = { - "ccmp", "tkip", "wep104", "wep40" + "ccmp", "tkip", +#ifdef CONFIG_WEP + "wep104", "wep40" +#endif /* CONFIG_WEP */ }; if (!wpa_dbus_dict_append_string_array( @@ -2691,12 +2701,14 @@ dbus_bool_t wpas_dbus_getter_capabilities( ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) && !wpa_dbus_dict_string_array_add_element( &iter_array, "tkip")) || +#ifdef CONFIG_WEP ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) && !wpa_dbus_dict_string_array_add_element( &iter_array, "wep104")) || ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) && !wpa_dbus_dict_string_array_add_element( &iter_array, "wep40")) || +#endif /* CONFIG_WEP */ !wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, @@ -2793,6 +2805,12 @@ dbus_bool_t wpas_dbus_getter_capabilities( goto nomem; #endif /* CONFIG_WPS */ +#ifdef CONFIG_SAE + if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE) && + !wpa_dbus_dict_string_array_add_element(&iter_array, "sae")) + goto nomem; +#endif /* CONFIG_SAE */ + if (!wpa_dbus_dict_end_string_array(&iter_dict, &iter_dict_entry, &iter_dict_val, @@ -4733,9 +4751,14 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( /* Group */ switch (ie_data->group_cipher) { +#ifdef CONFIG_WEP case WPA_CIPHER_WEP40: group = "wep40"; break; + case WPA_CIPHER_WEP104: + group = "wep104"; + break; +#endif /* CONFIG_WEP */ case WPA_CIPHER_TKIP: group = "tkip"; break; @@ -4745,9 +4768,6 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop( case WPA_CIPHER_GCMP: group = "gcmp"; break; - case WPA_CIPHER_WEP104: - group = "wep104"; - break; case WPA_CIPHER_CCMP_256: group = "ccmp-256"; break; diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index db76c6ad..ef2339f2 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -77,7 +77,7 @@ CONFIG_DRIVER_WIRED=y #CONFIG_DRIVER_MACSEC_QCA=y # Driver interface for Linux MACsec drivers -#CONFIG_DRIVER_MACSEC_LINUX=y +CONFIG_DRIVER_MACSEC_LINUX=y # Driver interface for the Broadcom RoboSwitch family #CONFIG_DRIVER_ROBOSWITCH=y @@ -183,7 +183,7 @@ CONFIG_EAP_IKEV2=y #CONFIG_EAP_EKE=y # MACsec -#CONFIG_MACSEC=y +CONFIG_MACSEC=y # PKCS#12 (PFX) support (used to read private key and certificate file from # a file that usually has extension .p12 or .pfx) @@ -248,7 +248,7 @@ CONFIG_CTRL_IFACE=y # Simultaneous Authentication of Equals (SAE), WPA3-Personal CONFIG_SAE=y -# Disable scan result processing (ap_mode=1) to save code size by about 1 kB. +# Disable scan result processing (ap_scan=1) to save code size by about 1 kB. # This can be used if ap_scan=1 mode is never enabled. #CONFIG_NO_SCAN_PROCESSING=y @@ -471,11 +471,7 @@ CONFIG_DEBUG_SYSLOG=y # Requires glibc 2.25 to build, falls back to /dev/random if unavailable. #CONFIG_GETRANDOM=y -# IEEE 802.11n (High Throughput) support (mainly for AP mode) -CONFIG_IEEE80211N=y - # IEEE 802.11ac (Very High Throughput) support (mainly for AP mode) -# (depends on CONFIG_IEEE80211N) CONFIG_IEEE80211AC=y # Wireless Network Management (IEEE Std 802.11v-2011) @@ -612,3 +608,12 @@ CONFIG_DPP=y # Configure the building of the interface which allows WAPI configuration. # Note: does not configure WAPI implementation itself. #CONFIG_WAPI_INTERFACE=y + +# Wired equivalent privacy (WEP) +# WEP is an obsolete cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used for anything anymore. The +# functionality needed to use WEP is available in the current wpa_supplicant +# release under this optional build parameter. This functionality is subject to +# be completely removed in a future release. +#CONFIG_WEP=y + diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c index 73649c23..c75ab47c 100644 --- a/wpa_supplicant/dpp_supplicant.c +++ b/wpa_supplicant/dpp_supplicant.c @@ -1,7 +1,7 @@ /* * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -107,6 +107,71 @@ int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd) } +int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Request"); + return -1; + } + + if (dpp_nfc_update_bi(own_bi, peer_bi) < 0) + return -1; + + return peer_bi->id; +} + + +int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd) +{ + const char *pos; + struct dpp_bootstrap_info *peer_bi, *own_bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + own_bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!own_bi) + return -1; + + pos = os_strstr(cmd, " uri="); + if (!pos) + return -1; + pos += 5; + peer_bi = dpp_add_nfc_uri(wpa_s->dpp, pos); + if (!peer_bi) { + wpa_printf(MSG_INFO, + "DPP: Failed to parse URI from NFC Handover Select"); + return -1; + } + + if (peer_bi->curve != own_bi->curve) { + wpa_printf(MSG_INFO, + "DPP: Peer (NFC Handover Selector) used different curve"); + return -1; + } + + return peer_bi->id; +} + + static void wpas_dpp_auth_resp_retry_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; @@ -689,6 +754,8 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) wpa_s->dpp_netrole = DPP_NETROLE_CONFIGURATOR; else wpa_s->dpp_netrole = DPP_NETROLE_STA; + } else { + wpa_s->dpp_netrole = DPP_NETROLE_STA; } pos = os_strstr(cmd, " neg_freq="); @@ -705,12 +772,12 @@ int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd) wpa_s->dpp_auth = NULL; } - auth = dpp_auth_init(wpa_s, peer_bi, own_bi, allowed_roles, neg_freq, - wpa_s->hw.modes, wpa_s->hw.num_modes); + auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, own_bi, allowed_roles, + neg_freq, wpa_s->hw.modes, wpa_s->hw.num_modes); if (!auth) goto fail; wpas_dpp_set_testing_options(wpa_s, auth); - if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) < 0) { + if (dpp_set_configurator(auth, cmd) < 0) { dpp_auth_deinit(auth); goto fail; } @@ -911,6 +978,10 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_printf(MSG_DEBUG, "DPP: Authentication Request from " MACSTR, MAC2STR(src)); +#ifdef CONFIG_DPP2 + wpas_dpp_chirp_stop(wpa_s); +#endif /* CONFIG_DPP2 */ + r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, &r_bootstrap_len); if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { @@ -949,7 +1020,8 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, wpa_s->dpp_gas_client = 0; wpa_s->dpp_auth_ok_on_ack = 0; - wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s, wpa_s->dpp_allowed_roles, + wpa_s->dpp_auth = dpp_auth_req_rx(wpa_s->dpp, wpa_s, + wpa_s->dpp_allowed_roles, wpa_s->dpp_qr_mutual, peer_bi, own_bi, freq, hdr, buf, len); if (!wpa_s->dpp_auth) { @@ -957,7 +1029,7 @@ static void wpas_dpp_rx_auth_req(struct wpa_supplicant *wpa_s, const u8 *src, return; } wpas_dpp_set_testing_options(wpa_s, wpa_s->dpp_auth); - if (dpp_set_configurator(wpa_s->dpp, wpa_s, wpa_s->dpp_auth, + if (dpp_set_configurator(wpa_s->dpp_auth, wpa_s->dpp_configurator_params) < 0) { dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; @@ -1031,8 +1103,10 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, ssid->ssid_len = conf->ssid_len; if (conf->connector) { - ssid->key_mgmt = WPA_KEY_MGMT_DPP; - ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; + if (dpp_akm_dpp(conf->akm)) { + ssid->key_mgmt = WPA_KEY_MGMT_DPP; + ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; + } ssid->dpp_connector = os_strdup(conf->connector); if (!ssid->dpp_connector) goto fail; @@ -1061,7 +1135,7 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s, if (!conf->connector || dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) { - if (!conf->connector) + if (!conf->connector || !dpp_akm_dpp(conf->akm)) ssid->key_mgmt = 0; if (dpp_akm_psk(conf->akm)) ssid->key_mgmt |= WPA_KEY_MGMT_PSK | @@ -1203,6 +1277,32 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s, } +static int wpas_dpp_handle_key_pkg(struct wpa_supplicant *wpa_s, + struct dpp_asymmetric_key *key) +{ +#ifdef CONFIG_DPP2 + int res; + + if (!key) + return 0; + + wpa_printf(MSG_DEBUG, "DPP: Received Configurator backup"); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED); + + while (key) { + res = dpp_configurator_from_backup(wpa_s->dpp, key); + if (res < 0) + return -1; + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFIGURATOR_ID "%d", + res); + key = key->next; + } +#endif /* CONFIG_DPP2 */ + + return 0; +} + + static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, @@ -1259,6 +1359,8 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token, } if (auth->num_conf_obj) wpas_dpp_post_process_config(wpa_s, auth); + if (wpas_dpp_handle_key_pkg(wpa_s, auth->conf_key_pkg) < 0) + goto fail; status = DPP_STATUS_OK; #ifdef CONFIG_TESTING_OPTIONS @@ -1605,6 +1707,76 @@ static int wpas_dpp_process_conf_obj(void *ctx, return res; } + +static void wpas_dpp_remove_bi(void *ctx, struct dpp_bootstrap_info *bi) +{ + struct wpa_supplicant *wpa_s = ctx; + + if (bi == wpa_s->dpp_chirp_bi) + wpas_dpp_chirp_stop(wpa_s); +} + + +static void +wpas_dpp_rx_presence_announcement(struct wpa_supplicant *wpa_s, const u8 *src, + const u8 *hdr, const u8 *buf, size_t len, + unsigned int freq) +{ + const u8 *r_bootstrap; + u16 r_bootstrap_len; + struct dpp_bootstrap_info *peer_bi; + struct dpp_authentication *auth; + + if (!wpa_s->dpp) + return; + + if (wpa_s->dpp_auth) { + wpa_printf(MSG_DEBUG, + "DPP: Ignore Presence Announcement during ongoing Authentication"); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Presence Announcement from " MACSTR, + MAC2STR(src)); + + r_bootstrap = dpp_get_attr(buf, len, DPP_ATTR_R_BOOTSTRAP_KEY_HASH, + &r_bootstrap_len); + if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_FAIL + "Missing or invalid required Responder Bootstrapping Key Hash attribute"); + return; + } + wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Bootstrapping Key Hash", + r_bootstrap, r_bootstrap_len); + peer_bi = dpp_bootstrap_find_chirp(wpa_s->dpp, r_bootstrap); + if (!peer_bi) { + wpa_printf(MSG_DEBUG, + "DPP: No matching bootstrapping information found"); + return; + } + + auth = dpp_auth_init(wpa_s->dpp, wpa_s, peer_bi, NULL, + DPP_CAPAB_CONFIGURATOR, freq, NULL, 0); + if (!auth) + return; + wpas_dpp_set_testing_options(wpa_s, auth); + if (dpp_set_configurator(auth, wpa_s->dpp_configurator_params) < 0) { + dpp_auth_deinit(auth); + return; + } + + auth->neg_freq = freq; + + if (!is_zero_ether_addr(peer_bi->mac_addr)) + os_memcpy(auth->peer_mac_addr, peer_bi->mac_addr, ETH_ALEN); + + wpa_s->dpp_auth = auth; + if (wpas_dpp_auth_init_next(wpa_s) < 0) { + dpp_auth_deinit(wpa_s->dpp_auth); + wpa_s->dpp_auth = NULL; + } +} + #endif /* CONFIG_DPP2 */ @@ -2069,6 +2241,7 @@ wpas_dpp_rx_pkex_commit_reveal_resp(struct wpa_supplicant *wpa_s, const u8 *src, if (wpas_dpp_auth_init(wpa_s, cmd) < 0) { wpa_printf(MSG_DEBUG, "DPP: Authentication initialization failed"); + offchannel_send_action_done(wpa_s); return; } } @@ -2149,6 +2322,10 @@ void wpas_dpp_rx_action(struct wpa_supplicant *wpa_s, const u8 *src, case DPP_PA_CONNECTION_STATUS_RESULT: wpas_dpp_rx_conn_status_result(wpa_s, src, hdr, buf, len); break; + case DPP_PA_PRESENCE_ANNOUNCEMENT: + wpas_dpp_rx_presence_announcement(wpa_s, src, hdr, buf, len, + freq); + break; #endif /* CONFIG_DPP2 */ default: wpa_printf(MSG_DEBUG, @@ -2271,13 +2448,13 @@ int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd) int ret = -1; char *curve = NULL; - auth = os_zalloc(sizeof(*auth)); + auth = dpp_alloc_auth(wpa_s->dpp, wpa_s); if (!auth) return -1; curve = get_param(cmd, " curve="); wpas_dpp_set_testing_options(wpa_s, auth); - if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 && + if (dpp_set_configurator(auth, cmd) == 0 && dpp_configurator_own_config(auth, curve, 0) == 0) ret = wpas_dpp_handle_config_obj(wpa_s, auth, &auth->conf_obj[0]); @@ -2549,6 +2726,8 @@ int wpas_dpp_pkex_remove(struct wpa_supplicant *wpa_s, const char *id) void wpas_dpp_stop(struct wpa_supplicant *wpa_s) { + if (wpa_s->dpp_auth || wpa_s->dpp_pkex) + offchannel_send_action_done(wpa_s); dpp_auth_deinit(wpa_s->dpp_auth); wpa_s->dpp_auth = NULL; dpp_pkex_free(wpa_s->dpp_pkex); @@ -2579,6 +2758,7 @@ int wpas_dpp_init(struct wpa_supplicant *wpa_s) config.cb_ctx = wpa_s; #ifdef CONFIG_DPP2 config.process_conf_obj = wpas_dpp_process_conf_obj; + config.remove_bi = wpas_dpp_remove_bi; #endif /* CONFIG_DPP2 */ wpa_s->dpp = dpp_global_init(&config); return wpa_s->dpp ? 0 : -1; @@ -2610,6 +2790,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_dpp_conn_status_result_timeout, wpa_s, NULL); dpp_pfs_free(wpa_s->dpp_pfs); wpa_s->dpp_pfs = NULL; + wpas_dpp_chirp_stop(wpa_s); #endif /* CONFIG_DPP2 */ offchannel_send_action_done(wpa_s); wpas_dpp_listen_stop(wpa_s); @@ -2622,6 +2803,7 @@ void wpas_dpp_deinit(struct wpa_supplicant *wpa_s) #ifdef CONFIG_DPP2 + int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd) { struct dpp_controller_config config; @@ -2638,4 +2820,270 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd) config.configurator_params = wpa_s->dpp_configurator_params; return dpp_controller_start(wpa_s->dpp, &config); } + + +static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx); + +static void wpas_dpp_chirp_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + wpa_printf(MSG_DEBUG, "DPP: No chirp response received"); + offchannel_send_action_done(wpa_s); + wpas_dpp_chirp_next(wpa_s, NULL); +} + + +static void wpas_dpp_chirp_tx_status(struct wpa_supplicant *wpa_s, + unsigned int freq, const u8 *dst, + const u8 *src, const u8 *bssid, + const u8 *data, size_t data_len, + enum offchannel_send_action_result result) +{ + if (result == OFFCHANNEL_SEND_ACTION_FAILED) { + wpa_printf(MSG_DEBUG, "DPP: Failed to send chirp on %d MHz", + wpa_s->dpp_chirp_freq); + if (eloop_register_timeout(0, 0, wpas_dpp_chirp_next, + wpa_s, NULL) < 0) + wpas_dpp_chirp_stop(wpa_s); + return; + } + + wpa_printf(MSG_DEBUG, "DPP: Chirp send completed - wait for response"); + if (eloop_register_timeout(2, 0, wpas_dpp_chirp_timeout, + wpa_s, NULL) < 0) + wpas_dpp_chirp_stop(wpa_s); +} + + +static void wpas_dpp_chirp_start(struct wpa_supplicant *wpa_s) +{ + wpa_printf(MSG_DEBUG, "DPP: Chirp on %d MHz", wpa_s->dpp_chirp_freq); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR " freq=%u type=%d", + MAC2STR(broadcast), wpa_s->dpp_chirp_freq, + DPP_PA_PRESENCE_ANNOUNCEMENT); + if (offchannel_send_action( + wpa_s, wpa_s->dpp_chirp_freq, broadcast, + wpa_s->own_addr, broadcast, + wpabuf_head(wpa_s->dpp_presence_announcement), + wpabuf_len(wpa_s->dpp_presence_announcement), + 2000, wpas_dpp_chirp_tx_status, 0) < 0) + wpas_dpp_chirp_stop(wpa_s); +} + + +static void wpas_dpp_chirp_scan_res_handler(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ + struct dpp_bootstrap_info *bi = wpa_s->dpp_chirp_bi; + unsigned int i; + struct hostapd_hw_modes *mode; + int c; + struct wpa_bss *bss; + + if (!bi) + return; + + wpa_s->dpp_chirp_scan_done = 1; + + os_free(wpa_s->dpp_chirp_freqs); + wpa_s->dpp_chirp_freqs = NULL; + + /* Channels from own bootstrapping info */ + for (i = 0; i < bi->num_freq; i++) + int_array_add_unique(&wpa_s->dpp_chirp_freqs, bi->freq[i]); + + /* Preferred chirping channels */ + int_array_add_unique(&wpa_s->dpp_chirp_freqs, 2437); + + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, + HOSTAPD_MODE_IEEE80211A, 0); + if (mode) { + int chan44 = 0, chan149 = 0; + + for (c = 0; c < mode->num_channels; c++) { + struct hostapd_channel_data *chan = &mode->channels[c]; + + if (chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_RADAR)) + continue; + if (chan->freq == 5220) + chan44 = 1; + if (chan->freq == 5745) + chan149 = 1; + } + if (chan149) + int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5745); + else if (chan44) + int_array_add_unique(&wpa_s->dpp_chirp_freqs, 5220); + } + + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, + HOSTAPD_MODE_IEEE80211AD, 0); + if (mode) { + for (c = 0; c < mode->num_channels; c++) { + struct hostapd_channel_data *chan = &mode->channels[c]; + + if ((chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_RADAR)) || + chan->freq != 60480) + continue; + int_array_add_unique(&wpa_s->dpp_chirp_freqs, 60480); + break; + } + } + + /* Add channels from scan results for APs that advertise Configurator + * Connectivity element */ + dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { + if (wpa_bss_get_vendor_ie(bss, DPP_CC_IE_VENDOR_TYPE)) + int_array_add_unique(&wpa_s->dpp_chirp_freqs, + bss->freq); + } + + if (!wpa_s->dpp_chirp_freqs || + eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL) < 0) + wpas_dpp_chirp_stop(wpa_s); +} + + +static void wpas_dpp_chirp_next(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + int i; + + if (wpa_s->dpp_chirp_listen) + wpas_dpp_listen_stop(wpa_s); + + if (wpa_s->dpp_chirp_freq == 0) { + if (wpa_s->dpp_chirp_round % 4 == 0 && + !wpa_s->dpp_chirp_scan_done) { + wpa_printf(MSG_DEBUG, + "DPP: Update channel list for chirping"); + wpa_s->scan_req = MANUAL_SCAN_REQ; + wpa_s->scan_res_handler = + wpas_dpp_chirp_scan_res_handler; + wpa_supplicant_req_scan(wpa_s, 0, 0); + return; + } + wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[0]; + wpa_s->dpp_chirp_round++; + wpa_printf(MSG_DEBUG, "DPP: Start chirping round %d", + wpa_s->dpp_chirp_round); + } else { + for (i = 0; wpa_s->dpp_chirp_freqs[i]; i++) + if (wpa_s->dpp_chirp_freqs[i] == wpa_s->dpp_chirp_freq) + break; + if (!wpa_s->dpp_chirp_freqs[i]) { + wpa_printf(MSG_DEBUG, + "DPP: Previous chirp freq %d not found", + wpa_s->dpp_chirp_freq); + return; + } + i++; + if (wpa_s->dpp_chirp_freqs[i]) { + wpa_s->dpp_chirp_freq = wpa_s->dpp_chirp_freqs[i]; + } else { + wpa_s->dpp_chirp_iter--; + if (wpa_s->dpp_chirp_iter <= 0) { + wpa_printf(MSG_DEBUG, + "DPP: Chirping iterations completed"); + wpas_dpp_chirp_stop(wpa_s); + return; + } + wpa_s->dpp_chirp_freq = 0; + wpa_s->dpp_chirp_scan_done = 0; + if (eloop_register_timeout(30, 0, wpas_dpp_chirp_next, + wpa_s, NULL) < 0) { + wpas_dpp_chirp_stop(wpa_s); + return; + } + if (wpa_s->dpp_chirp_listen) { + wpa_printf(MSG_DEBUG, + "DPP: Listen on %d MHz during chirp 30 second wait", + wpa_s->dpp_chirp_listen); + wpas_dpp_listen_start(wpa_s, + wpa_s->dpp_chirp_listen); + } else { + wpa_printf(MSG_DEBUG, + "DPP: Wait 30 seconds before starting the next chirping round"); + } + return; + } + } + + wpas_dpp_chirp_start(wpa_s); +} + + +int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd) +{ + const char *pos; + int iter = 1, listen_freq = 0; + struct dpp_bootstrap_info *bi; + + pos = os_strstr(cmd, " own="); + if (!pos) + return -1; + pos += 5; + bi = dpp_bootstrap_get_id(wpa_s->dpp, atoi(pos)); + if (!bi) { + wpa_printf(MSG_DEBUG, + "DPP: Identified bootstrap info not found"); + return -1; + } + + pos = os_strstr(cmd, " iter="); + if (pos) { + iter = atoi(pos + 6); + if (iter <= 0) + return -1; + } + + pos = os_strstr(cmd, " listen="); + if (pos) { + listen_freq = atoi(pos + 8); + if (iter <= 0) + return -1; + } + + wpas_dpp_chirp_stop(wpa_s); + wpa_s->dpp_allowed_roles = DPP_CAPAB_ENROLLEE; + wpa_s->dpp_qr_mutual = 0; + wpa_s->dpp_chirp_bi = bi; + wpa_s->dpp_presence_announcement = dpp_build_presence_announcement(bi); + if (!wpa_s->dpp_presence_announcement) + return -1; + wpa_s->dpp_chirp_iter = iter; + wpa_s->dpp_chirp_round = 0; + wpa_s->dpp_chirp_scan_done = 0; + wpa_s->dpp_chirp_listen = listen_freq; + + return eloop_register_timeout(0, 0, wpas_dpp_chirp_next, wpa_s, NULL); +} + + +void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s) +{ + if (wpa_s->dpp_presence_announcement) { + offchannel_send_action_done(wpa_s); + wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CHIRP_STOPPED); + } + wpa_s->dpp_chirp_bi = NULL; + wpabuf_free(wpa_s->dpp_presence_announcement); + wpa_s->dpp_presence_announcement = NULL; + if (wpa_s->dpp_chirp_listen) + wpas_dpp_listen_stop(wpa_s); + wpa_s->dpp_chirp_listen = 0; + wpa_s->dpp_chirp_freq = 0; + os_free(wpa_s->dpp_chirp_freqs); + wpa_s->dpp_chirp_freqs = NULL; + eloop_cancel_timeout(wpas_dpp_chirp_next, wpa_s, NULL); + eloop_cancel_timeout(wpas_dpp_chirp_timeout, wpa_s, NULL); + if (wpa_s->scan_res_handler == wpas_dpp_chirp_scan_res_handler) { + wpas_abort_ongoing_scan(wpa_s); + wpa_s->scan_res_handler = NULL; + } +} + #endif /* CONFIG_DPP2 */ diff --git a/wpa_supplicant/dpp_supplicant.h b/wpa_supplicant/dpp_supplicant.h index 607036a3..2ce378dc 100644 --- a/wpa_supplicant/dpp_supplicant.h +++ b/wpa_supplicant/dpp_supplicant.h @@ -1,7 +1,7 @@ /* * wpa_supplicant - DPP * Copyright (c) 2017, Qualcomm Atheros, Inc. - * Copyright (c) 2018-2019, The Linux Foundation + * Copyright (c) 2018-2020, The Linux Foundation * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -14,6 +14,8 @@ enum dpp_status_error; int wpas_dpp_qr_code(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_nfc_uri(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_nfc_handover_req(struct wpa_supplicant *wpa_s, const char *cmd); +int wpas_dpp_nfc_handover_sel(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_auth_init(struct wpa_supplicant *wpa_s, const char *cmd); int wpas_dpp_listen(struct wpa_supplicant *wpa_s, const char *cmd); void wpas_dpp_listen_stop(struct wpa_supplicant *wpa_s); @@ -33,5 +35,7 @@ int wpas_dpp_controller_start(struct wpa_supplicant *wpa_s, const char *cmd); void wpas_dpp_connected(struct wpa_supplicant *wpa_s); void wpas_dpp_send_conn_status_result(struct wpa_supplicant *wpa_s, enum dpp_status_error result); +int wpas_dpp_chirp(struct wpa_supplicant *wpa_s, const char *cmd); +void wpas_dpp_chirp_stop(struct wpa_supplicant *wpa_s); #endif /* DPP_SUPPLICANT_H */ diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index cf9972a6..6a03d8e9 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -124,13 +124,8 @@ static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s) return -1; } -static inline struct wpa_scan_results * wpa_drv_get_scan_results2( - struct wpa_supplicant *wpa_s) -{ - if (wpa_s->driver->get_scan_results2) - return wpa_s->driver->get_scan_results2(wpa_s->drv_priv); - return NULL; -} +struct wpa_scan_results * +wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s); static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid) { @@ -152,18 +147,38 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) -{ + const u8 *key, size_t key_len, + enum key_flag key_flag) +{ + struct wpa_driver_set_key_params params; + + os_memset(¶ms, 0, sizeof(params)); + params.ifname = wpa_s->ifname; + params.alg = alg; + params.addr = addr; + params.key_idx = key_idx; + params.set_tx = set_tx; + params.seq = seq; + params.seq_len = seq_len; + params.key = key; + params.key_len = key_len; + params.key_flag = key_flag; + if (alg != WPA_ALG_NONE) { - if (key_idx >= 0 && key_idx <= 6) + /* keyidx = 1 can be either a broadcast or--with + * Extended Key ID--a unicast key. Use bit 15 for + * the pairwise keyidx 1 which is hopefully high enough + * to not clash with future extensions. + */ + if (key_idx == 1 && (key_flag & KEY_FLAG_PAIRWISE)) + wpa_s->keys_cleared &= ~BIT(15); + else if (key_idx >= 0 && key_idx <= 5) wpa_s->keys_cleared &= ~BIT(key_idx); else wpa_s->keys_cleared = 0; } if (wpa_s->driver->set_key) { - return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv, - alg, addr, key_idx, set_tx, - seq, seq_len, key, key_len); + return wpa_s->driver->set_key(wpa_s->drv_priv, ¶ms); } return -1; } @@ -304,12 +319,12 @@ static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s, static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s, const u8 *data, size_t data_len, int noack, - unsigned int freq) + unsigned int freq, unsigned int wait) { if (wpa_s->driver->send_mlme) return wpa_s->driver->send_mlme(wpa_s->drv_priv, data, data_len, noack, - freq, NULL, 0); + freq, NULL, 0, 0, wait); return -1; } @@ -347,6 +362,17 @@ static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s, return -1; } +static inline int wpa_drv_tx_control_port(struct wpa_supplicant *wpa_s, + const u8 *dest, u16 proto, + const u8 *buf, size_t len, + int no_encrypt) +{ + if (!wpa_s->driver->tx_control_port) + return -1; + return wpa_s->driver->tx_control_port(wpa_s->drv_priv, dest, proto, + buf, len, no_encrypt); +} + static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s, const u8 *addr, const u8 *data, size_t data_len, int encrypt, @@ -494,13 +520,8 @@ static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s, return -1; } -static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, - struct wpa_signal_info *si) -{ - if (wpa_s->driver->signal_poll) - return wpa_s->driver->signal_poll(wpa_s->drv_priv, si); - return -1; -} +int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, + struct wpa_signal_info *si); static inline int wpa_drv_channel_info(struct wpa_supplicant *wpa_s, struct wpa_channel_info *ci) @@ -681,6 +702,13 @@ static inline int wpa_drv_set_qos_map(struct wpa_supplicant *wpa_s, qos_map_set_len); } +static inline int wpa_drv_get_wowlan(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->driver->get_wowlan) + return 0; + return wpa_s->driver->get_wowlan(wpa_s->drv_priv); +} + static inline int wpa_drv_wowlan(struct wpa_supplicant *wpa_s, const struct wowlan_triggers *triggers) { diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c index 53d75853..2fa49681 100644 --- a/wpa_supplicant/eapol_test.c +++ b/wpa_supplicant/eapol_test.c @@ -1390,7 +1390,7 @@ int main(int argc, char *argv[]) eapol_test.ctrl_iface = 1; break; case 'v': - printf("eapol_test v" VERSION_STR "\n"); + printf("eapol_test v%s\n", VERSION_STR); return 0; case 'W': wait_for_monitor++; diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 4c459cfe..cf561083 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -188,6 +188,16 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s) drv_ssid_len) == 0) return 0; /* current profile still in use */ +#ifdef CONFIG_OWE + if ((wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_OWE) && + wpa_s->current_bss && + (wpa_s->current_bss->flags & WPA_BSS_OWE_TRANSITION) && + drv_ssid_len == wpa_s->current_bss->ssid_len && + os_memcmp(drv_ssid, wpa_s->current_bss->ssid, + drv_ssid_len) == 0) + return 0; /* current profile still in use */ +#endif /* CONFIG_OWE */ + wpa_msg(wpa_s, MSG_DEBUG, "Driver-initiated BSS selection changed the SSID to %s", wpa_ssid_txt(drv_ssid, drv_ssid_len)); @@ -479,6 +489,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s, #ifndef CONFIG_NO_SCAN_PROCESSING +#ifdef CONFIG_WEP static int has_wep_key(struct wpa_ssid *ssid) { int i; @@ -490,6 +501,7 @@ static int has_wep_key(struct wpa_ssid *ssid) return 0; } +#endif /* CONFIG_WEP */ static int wpa_supplicant_match_privacy(struct wpa_bss *bss, @@ -510,8 +522,10 @@ static int wpa_supplicant_match_privacy(struct wpa_bss *bss, return 1; #endif /* CONFIG_OWE */ +#ifdef CONFIG_WEP if (has_wep_key(ssid)) privacy = 1; +#endif /* CONFIG_WEP */ #ifdef IEEE8021X_EAPOL if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && @@ -540,17 +554,21 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, int proto_match = 0; const u8 *rsn_ie, *wpa_ie; int ret; +#ifdef CONFIG_WEP int wep_ok; +#endif /* CONFIG_WEP */ ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss); if (ret >= 0) return ret; +#ifdef CONFIG_WEP /* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */ wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) && (((ssid->key_mgmt & WPA_KEY_MGMT_NONE) && ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) || (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)); +#endif /* CONFIG_WEP */ rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN); while ((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_OSEN)) && rsn_ie) { @@ -567,6 +585,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, if (!ie.has_group) ie.group_cipher = wpa_default_rsn_cipher(bss->freq); +#ifdef CONFIG_WEP if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) { @@ -575,6 +594,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, " selected based on TSN in RSN IE"); return 1; } +#endif /* CONFIG_WEP */ if (!(ie.proto & ssid->proto) && !(ssid->proto & WPA_PROTO_OSEN)) { @@ -655,6 +675,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, break; } +#ifdef CONFIG_WEP if (wep_ok && (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104))) { @@ -663,6 +684,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, " selected based on TSN in WPA IE"); return 1; } +#endif /* CONFIG_WEP */ if (!(ie.proto & ssid->proto)) { if (debug_print) @@ -772,8 +794,8 @@ static int freq_allowed(int *freqs, int freq) } -static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - int debug_print) +static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_bss *bss, int debug_print) { const struct hostapd_hw_modes *mode = NULL, *modes; const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES }; @@ -853,7 +875,9 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, #ifdef CONFIG_SAE if (flagged && ((rate_ie[j] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) { - if (wpa_s->conf->sae_pwe == 0) { + if (wpa_s->conf->sae_pwe == 0 && + !ssid->sae_password_id && + wpa_key_mgmt_sae(ssid->key_mgmt)) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, " SAE H2E disabled"); @@ -971,6 +995,24 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, *ret_ssid = pos; *ret_ssid_len = ssid_len; + if (!(bss->flags & WPA_BSS_OWE_TRANSITION)) { + struct wpa_ssid *ssid; + + for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { + if (wpas_network_disabled(wpa_s, ssid)) + continue; + if (ssid->ssid_len == ssid_len && + os_memcmp(ssid->ssid, pos, ssid_len) == 0) { + /* OWE BSS in transition mode for a currently + * enabled OWE network. */ + wpa_dbg(wpa_s, MSG_DEBUG, + "OWE: transition mode OWE SSID for active OWE profile"); + bss->flags |= WPA_BSS_OWE_TRANSITION; + break; + } + } + } + if (bss->ssid_len > 0) return; @@ -1011,10 +1053,33 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, wpa_ssid_txt(pos, ssid_len)); os_memcpy(bss->ssid, pos, ssid_len); bss->ssid_len = ssid_len; + bss->flags |= WPA_BSS_OWE_TRANSITION; #endif /* CONFIG_OWE */ } +static int disabled_freq(struct wpa_supplicant *wpa_s, int freq) +{ + int i, j; + + if (!wpa_s->hw.modes || !wpa_s->hw.num_modes) + return 0; + + for (j = 0; j < wpa_s->hw.num_modes; j++) { + struct hostapd_hw_modes *mode = &wpa_s->hw.modes[j]; + + for (i = 0; i < mode->num_channels; i++) { + struct hostapd_channel_data *chan = &mode->channels[i]; + + if (chan->freq == freq) + return !!(chan->flag & HOSTAPD_CHAN_DISABLED); + } + } + + return 1; +} + + struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, int i, struct wpa_bss *bss, struct wpa_ssid *group, @@ -1106,6 +1171,12 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, return NULL; } + if (disabled_freq(wpa_s, bss->freq)) { + if (debug_print) + wpa_dbg(wpa_s, MSG_DEBUG, " skip - channel disabled"); + return NULL; + } + wpa = wpa_ie_len > 0 || rsn_ie_len > 0; for (ssid = group; ssid; ssid = only_first_ssid ? NULL : ssid->pnext) { @@ -1206,6 +1277,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, continue; } +#ifdef CONFIG_WEP if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) && has_wep_key(ssid)) { if (debug_print) @@ -1213,6 +1285,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, " skip - ignore WPA/WPA2 AP for WEP network block"); continue; } +#endif /* CONFIG_WEP */ if ((ssid->key_mgmt & WPA_KEY_MGMT_OSEN) && !osen && !rsn_osen) { @@ -1262,7 +1335,7 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_MESH */ - if (!rate_match(wpa_s, bss, debug_print)) { + if (!rate_match(wpa_s, ssid, bss, debug_print)) { if (debug_print) wpa_dbg(wpa_s, MSG_DEBUG, " skip - rate sets do not match"); @@ -1270,7 +1343,8 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s, } #ifdef CONFIG_SAE - if (wpa_s->conf->sae_pwe == 1 && + if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) && + wpa_s->conf->sae_pwe != 3 && wpa_key_mgmt_sae(ssid->key_mgmt) && (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) || ie[1] < 1 || @@ -1446,8 +1520,9 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, wpa_s->owe_transition_select = 0; if (!*selected_ssid) continue; - wpa_dbg(wpa_s, MSG_DEBUG, " selected BSS " MACSTR + wpa_dbg(wpa_s, MSG_DEBUG, " selected %sBSS " MACSTR " ssid='%s'", + bss == wpa_s->current_bss ? "current ": "", MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len)); return bss; @@ -1461,7 +1536,7 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s, struct wpa_ssid **selected_ssid) { struct wpa_bss *selected = NULL; - int prio; + size_t prio; struct wpa_ssid *next_ssid = NULL; struct wpa_ssid *ssid; @@ -1616,7 +1691,7 @@ int wpa_supplicant_connect(struct wpa_supplicant *wpa_s, static struct wpa_ssid * wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s) { - int prio; + size_t prio; struct wpa_ssid *ssid; for (prio = 0; prio < wpa_s->conf->num_prio; prio++) { @@ -1672,6 +1747,31 @@ static void wpa_supplicant_rsn_preauth_scan_results( } +#ifndef CONFIG_NO_ROAMING + +static int wpas_get_snr_signal_info(u32 frequency, int avg_signal, int noise) +{ + if (noise == WPA_INVALID_NOISE) + noise = IS_5GHZ(frequency) ? DEFAULT_NOISE_FLOOR_5GHZ : + DEFAULT_NOISE_FLOOR_2GHZ; + return avg_signal - noise; +} + + +static unsigned int +wpas_get_est_throughput_from_bss_snr(const struct wpa_supplicant *wpa_s, + const struct wpa_bss *bss, int snr) +{ + int rate = wpa_bss_get_max_rate(bss); + const u8 *ies = (const void *) (bss + 1); + size_t ie_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; + + return wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr); +} + +#endif /* CONFIG_NO_ROAMING */ + + static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, struct wpa_bss *selected, struct wpa_ssid *ssid) @@ -1680,7 +1780,10 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, #ifndef CONFIG_NO_ROAMING int min_diff, diff; int to_5ghz; - int cur_est, sel_est; + int cur_level; + unsigned int cur_est, sel_est; + struct wpa_signal_info si; + int cur_snr = 0; #endif /* CONFIG_NO_ROAMING */ if (wpa_s->reassociate) @@ -1731,7 +1834,41 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, return 1; } - if (selected->est_throughput > current_bss->est_throughput + 5000) { + cur_level = current_bss->level; + cur_est = current_bss->est_throughput; + sel_est = selected->est_throughput; + + /* + * Try to poll the signal from the driver since this will allow to get + * more accurate values. In some cases, there can be big differences + * between the RSSI of the Probe Response frames of the AP we are + * associated with and the Beacon frames we hear from the same AP after + * association. This can happen, e.g., when there are two antennas that + * hear the AP very differently. If the driver chooses to hear the + * Probe Response frames during the scan on the "bad" antenna because + * it wants to save power, but knows to choose the other antenna after + * association, we will hear our AP with a low RSSI as part of the + * scan even when we can hear it decently on the other antenna. To cope + * with this, ask the driver to teach us how it hears the AP. Also, the + * scan results may be a bit old, since we can very quickly get fresh + * information about our currently associated AP. + */ + if (wpa_drv_signal_poll(wpa_s, &si) == 0 && + (si.avg_beacon_signal || si.avg_signal)) { + cur_level = si.avg_beacon_signal ? si.avg_beacon_signal : + si.avg_signal; + cur_snr = wpas_get_snr_signal_info(si.frequency, cur_level, + si.current_noise); + + cur_est = wpas_get_est_throughput_from_bss_snr(wpa_s, + current_bss, + cur_snr); + wpa_dbg(wpa_s, MSG_DEBUG, + "Using signal poll values for the current BSS: level=%d snr=%d est_throughput=%u", + cur_level, cur_snr, cur_est); + } + + if (sel_est > cur_est + 5000) { wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS has better estimated throughput"); return 1; @@ -1739,59 +1876,59 @@ static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s, to_5ghz = selected->freq > 4000 && current_bss->freq < 4000; - if (current_bss->level < 0 && - current_bss->level > selected->level + to_5ghz * 2) { + if (cur_level < 0 && cur_level > selected->level + to_5ghz * 2 && + sel_est < cur_est * 1.2) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better " "signal level"); return 0; } - if (current_bss->est_throughput > selected->est_throughput + 5000) { + if (cur_est > sel_est + 5000) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better estimated throughput"); return 0; } - cur_est = current_bss->est_throughput; - sel_est = selected->est_throughput; - min_diff = 2; - if (current_bss->level < 0) { - if (current_bss->level < -85) - min_diff = 1; - else if (current_bss->level < -80) - min_diff = 2; - else if (current_bss->level < -75) - min_diff = 3; - else if (current_bss->level < -70) - min_diff = 4; - else - min_diff = 5; - if (cur_est > sel_est * 1.5) - min_diff += 10; - else if (cur_est > sel_est * 1.2) - min_diff += 5; - else if (cur_est > sel_est * 1.1) - min_diff += 2; - else if (cur_est > sel_est) - min_diff++; - } - if (to_5ghz) { - int reduce = 2; - - /* Make it easier to move to 5 GHz band */ - if (sel_est > cur_est * 1.5) - reduce = 5; - else if (sel_est > cur_est * 1.2) - reduce = 4; - else if (sel_est > cur_est * 1.1) - reduce = 3; - - if (min_diff > reduce) - min_diff -= reduce; - else - min_diff = 0; + if (cur_snr > GREAT_SNR) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Skip roam - Current BSS has good SNR (%u > %u)", + cur_snr, GREAT_SNR); + return 0; } - diff = abs(current_bss->level - selected->level); + + if (cur_level < -85) /* ..-86 dBm */ + min_diff = 1; + else if (cur_level < -80) /* -85..-81 dBm */ + min_diff = 2; + else if (cur_level < -75) /* -80..-76 dBm */ + min_diff = 3; + else if (cur_level < -70) /* -75..-71 dBm */ + min_diff = 4; + else if (cur_level < 0) /* -70..-1 dBm */ + min_diff = 5; + else /* unspecified units (not in dBm) */ + min_diff = 2; + + if (cur_est > sel_est * 1.5) + min_diff += 10; + else if (cur_est > sel_est * 1.2) + min_diff += 5; + else if (cur_est > sel_est * 1.1) + min_diff += 2; + else if (cur_est > sel_est) + min_diff++; + else if (sel_est > cur_est * 1.5) + min_diff -= 10; + else if (sel_est > cur_est * 1.2) + min_diff -= 5; + else if (sel_est > cur_est * 1.1) + min_diff -= 2; + else if (sel_est > cur_est) + min_diff--; + + if (to_5ghz) + min_diff -= 2; + diff = selected->level - cur_level; if (diff < min_diff) { wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference in signal level (%d < %d)", @@ -1887,15 +2024,6 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, goto scan_work_done; } - if (ap) { - wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode"); -#ifdef CONFIG_AP - if (wpa_s->ap_iface->scan_cb) - wpa_s->ap_iface->scan_cb(wpa_s->ap_iface); -#endif /* CONFIG_AP */ - goto scan_work_done; - } - wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available (own=%u ext=%u)", wpa_s->own_scan_running, data ? data->scan_info.external_scan : 0); @@ -1912,6 +2040,15 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpas_notify_scan_done(wpa_s, 1); + if (ap) { + wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode"); +#ifdef CONFIG_AP + if (wpa_s->ap_iface->scan_cb) + wpa_s->ap_iface->scan_cb(wpa_s->ap_iface); +#endif /* CONFIG_AP */ + goto scan_work_done; + } + if (data && data->scan_info.external_scan) { wpa_dbg(wpa_s, MSG_DEBUG, "Do not use results from externally requested scan operation for network selection"); wpa_scan_results_free(scan_res); @@ -2194,7 +2331,8 @@ int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s) return -1; os_get_reltime(&now); - if (os_reltime_expired(&now, &wpa_s->last_scan, 5)) { + if (os_reltime_expired(&now, &wpa_s->last_scan, + SCAN_RES_VALID_FOR_CONNECT)) { wpa_printf(MSG_DEBUG, "Fast associate: Old scan results"); return -1; } @@ -2327,28 +2465,41 @@ static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s, const u8 *map_sub_elem, *pos; size_t len; - if (!wpa_s->current_ssid || - !wpa_s->current_ssid->multi_ap_backhaul_sta || - !ies || - ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) - return; + wpa_s->multi_ap_ie = 0; - if (!elems.multi_ap || elems.multi_ap_len < 7) { - wpa_printf(MSG_INFO, "AP doesn't support Multi-AP protocol"); - goto fail; - } + if (!ies || + ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed || + !elems.multi_ap || elems.multi_ap_len < 7) + return; pos = elems.multi_ap + 4; len = elems.multi_ap_len - 4; map_sub_elem = get_ie(pos, len, MULTI_AP_SUB_ELEM_TYPE); - if (!map_sub_elem || map_sub_elem[1] < 1) { - wpa_printf(MSG_INFO, "invalid Multi-AP sub elem type"); + if (!map_sub_elem || map_sub_elem[1] < 1) + return; + + wpa_s->multi_ap_backhaul = !!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS); + wpa_s->multi_ap_fronthaul = !!(map_sub_elem[2] & + MULTI_AP_FRONTHAUL_BSS); + wpa_s->multi_ap_ie = 1; +} + + +static void multi_ap_set_4addr_mode(struct wpa_supplicant *wpa_s) +{ + if (!wpa_s->current_ssid || + !wpa_s->current_ssid->multi_ap_backhaul_sta) + return; + + if (!wpa_s->multi_ap_ie) { + wpa_printf(MSG_INFO, + "AP does not include valid Multi-AP element"); goto fail; } - if (!(map_sub_elem[2] & MULTI_AP_BACKHAUL_BSS)) { - if ((map_sub_elem[2] & MULTI_AP_FRONTHAUL_BSS) && + if (!wpa_s->multi_ap_backhaul) { + if (wpa_s->multi_ap_fronthaul && wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS) { wpa_printf(MSG_INFO, "WPS active, accepting fronthaul-only BSS"); @@ -2472,8 +2623,14 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s, wpa_s->connection_set = 1; wpa_s->connection_ht = req_elems.ht_capabilities && resp_elems.ht_capabilities; + /* Do not include subset of VHT on 2.4 GHz vendor + * extension in consideration for reporting VHT + * association. */ wpa_s->connection_vht = req_elems.vht_capabilities && - resp_elems.vht_capabilities; + resp_elems.vht_capabilities && + (!data->assoc_info.freq || + wpas_freq_to_band(data->assoc_info.freq) != + BAND_2_4_GHZ); wpa_s->connection_he = req_elems.he_capabilities && resp_elems.he_capabilities; @@ -2818,6 +2975,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #endif /* CONFIG_AP */ eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); + wpa_s->own_reconnect_req = 0; ft_completed = wpa_ft_is_completed(wpa_s->wpa); if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0) @@ -2867,6 +3025,8 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, } } + multi_ap_set_4addr_mode(wpa_s); + if (wpa_s->conf->ap_scan == 1 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) { if (wpa_supplicant_assoc_update_ie(wpa_s) < 0 && new_bss) @@ -2971,6 +3131,13 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_s->last_eapol_matches_bssid = 0; #ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->rsne_override_eapol) { + wpa_printf(MSG_DEBUG, + "TESTING: RSNE EAPOL-Key msg 2/4 override"); + wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, + wpabuf_head(wpa_s->rsne_override_eapol), + wpabuf_len(wpa_s->rsne_override_eapol)); + } if (wpa_s->rsnxe_override_eapol) { wpa_printf(MSG_DEBUG, "TESTING: RSNXE EAPOL-Key msg 2/4 override"); @@ -2999,6 +3166,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, wpa_s->pending_eapol_rx = NULL; } +#ifdef CONFIG_WEP if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE || wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) && wpa_s->current_ssid && @@ -3006,6 +3174,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, /* Set static WEP keys again */ wpa_set_wep_keys(wpa_s, wpa_s->current_ssid); } +#endif /* CONFIG_WEP */ #ifdef CONFIG_IBSS_RSN if (wpa_s->current_ssid && @@ -3051,6 +3220,10 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid); #endif /* CONFIG_MBO */ + +#ifdef CONFIG_DPP2 + wpa_s->dpp_pfs_fallback = 0; +#endif /* CONFIG_DPP2 */ } @@ -3178,21 +3351,25 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, if (wpa_s->wpa_state == WPA_COMPLETED && wpa_s->current_ssid && wpa_s->current_ssid->mode == WPAS_MODE_INFRA && - !locally_generated && - disconnect_reason_recoverable(reason_code)) { + (wpa_s->own_reconnect_req || + (!locally_generated && + disconnect_reason_recoverable(reason_code)))) { /* * It looks like the AP has dropped association with - * us, but could allow us to get back in. Try to - * reconnect to the same BSS without full scan to save - * time for some common cases. + * us, but could allow us to get back in. This is also + * triggered for cases where local reconnection request + * is used to force reassociation with the same BSS. + * Try to reconnect to the same BSS without a full scan + * to save time for some common cases. */ fast_reconnect = wpa_s->current_bss; fast_reconnect_ssid = wpa_s->current_ssid; - } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) + } else if (wpa_s->wpa_state >= WPA_ASSOCIATING) { wpa_supplicant_req_scan(wpa_s, 0, 100000); - else + } else { wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new " "immediate scan"); + } } else { wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not " "try to re-connect"); @@ -4216,6 +4393,39 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_OWE */ +#ifdef CONFIG_DPP2 + /* Try to follow AP's PFS policy. WLAN_STATUS_ASSOC_DENIED_UNSPEC is + * the status code defined in the DPP R2 tech spec. + * WLAN_STATUS_AKMP_NOT_VALID is addressed in the same manner as an + * interoperability workaround with older hostapd implementation. */ + if (wpa_s->current_ssid && + wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_DPP && + wpa_s->current_ssid->dpp_pfs == 0 && + (data->assoc_reject.status_code == + WLAN_STATUS_ASSOC_DENIED_UNSPEC || + data->assoc_reject.status_code == WLAN_STATUS_AKMP_NOT_VALID)) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + struct wpa_bss *bss = wpa_s->current_bss; + + wpa_s->current_ssid->dpp_pfs_fallback ^= 1; + if (!bss) + bss = wpa_supplicant_get_new_bss(wpa_s, bssid); + if (!bss || wpa_s->dpp_pfs_fallback) { + wpa_printf(MSG_DEBUG, + "DPP: Updated PFS policy for next try"); + wpas_connection_failed(wpa_s, bssid); + wpa_supplicant_mark_disassoc(wpa_s); + return; + } + wpa_printf(MSG_DEBUG, "DPP: Try again with updated PFS policy"); + wpa_s->dpp_pfs_fallback = 1; + wpas_connect_work_done(wpa_s); + wpa_supplicant_mark_disassoc(wpa_s); + wpa_supplicant_connect(wpa_s, bss, ssid); + return; + } +#endif /* CONFIG_DPP2 */ + #ifdef CONFIG_MBO if (data->assoc_reject.status_code == WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS && @@ -4282,11 +4492,44 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s, } +static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s, + struct unprot_beacon *data) +{ + struct wpabuf *buf; + int res; + + if (!data || wpa_s->wpa_state != WPA_COMPLETED || + os_memcmp(data->sa, wpa_s->bssid, ETH_ALEN) != 0) + return; + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_UNPROT_BEACON MACSTR, + MAC2STR(data->sa)); + + buf = wpabuf_alloc(4); + if (!buf) + return; + + wpabuf_put_u8(buf, WLAN_ACTION_WNM); + wpabuf_put_u8(buf, WNM_NOTIFICATION_REQ); + wpabuf_put_u8(buf, 1); /* Dialog Token */ + wpabuf_put_u8(buf, WNM_NOTIF_TYPE_BEACON_PROTECTION_FAILURE); + + res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, + wpa_s->own_addr, wpa_s->bssid, + wpabuf_head(buf), wpabuf_len(buf), 0); + if (res < 0) + wpa_printf(MSG_DEBUG, + "Failed to send WNM-Notification Request frame"); + + wpabuf_free(buf); +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { struct wpa_supplicant *wpa_s = ctx; int resched; + struct os_reltime age, clear_at; #ifndef CONFIG_NO_STDOUT_DEBUG int level = MSG_DEBUG; #endif /* CONFIG_NO_STDOUT_DEBUG */ @@ -4589,6 +4832,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s->assoc_freq = data->ch_switch.freq; wpa_s->current_ssid->frequency = data->ch_switch.freq; +#ifdef CONFIG_SME + switch (data->ch_switch.ch_offset) { + case 1: + wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE; + break; + case -1: + wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW; + break; + default: + wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN; + break; + } +#endif /* CONFIG_SME */ + #ifdef CONFIG_AP if (wpa_s->current_ssid->mode == WPAS_MODE_AP || wpa_s->current_ssid->mode == WPAS_MODE_P2P_GO || @@ -4811,6 +5068,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, case EVENT_INTERFACE_ENABLED: wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled"); if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) { + eloop_cancel_timeout(wpas_clear_disabled_interface, + wpa_s, NULL); wpa_supplicant_update_mac_addr(wpa_s); wpa_supplicant_set_default_scan_ies(wpa_s); if (wpa_s->p2p_mgmt) { @@ -4879,8 +5138,20 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1); } wpa_supplicant_mark_disassoc(wpa_s); - if (!wpa_s->conf->bss_no_flush_when_down) - wpa_bss_flush(wpa_s); + os_reltime_age(&wpa_s->last_scan, &age); + if (age.sec >= SCAN_RES_VALID_FOR_CONNECT) { + clear_at.sec = SCAN_RES_VALID_FOR_CONNECT; + clear_at.usec = 0; + } else { + struct os_reltime tmp; + + tmp.sec = SCAN_RES_VALID_FOR_CONNECT; + tmp.usec = 0; + os_reltime_sub(&tmp, &age, &clear_at); + } + eloop_register_timeout(clear_at.sec, clear_at.usec, + wpas_clear_disabled_interface, + wpa_s, NULL); radio_remove_works(wpa_s, NULL, 0); wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED); @@ -5057,6 +5328,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->sta_opmode.rx_nss); #endif /* CONFIG_AP */ break; + case EVENT_UNPROT_BEACON: + wpas_event_unprot_beacon(wpa_s, &data->unprot_beacon); + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break; diff --git a/wpa_supplicant/examples/dpp-nfc.py b/wpa_supplicant/examples/dpp-nfc.py new file mode 100755 index 00000000..f49da34f --- /dev/null +++ b/wpa_supplicant/examples/dpp-nfc.py @@ -0,0 +1,692 @@ +#!/usr/bin/python3 +# +# Example nfcpy to wpa_supplicant wrapper for DPP NFC operations +# Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi> +# Copyright (c) 2019-2020, The Linux Foundation +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. + +import os +import sys +import time +import threading +import argparse + +import nfc +import ndef + +import logging + +scriptsdir = os.path.dirname(os.path.realpath("dpp-nfc.py")) +sys.path.append(os.path.join(scriptsdir, '..', '..', 'wpaspy')) +import wpaspy + +wpas_ctrl = '/var/run/wpa_supplicant' +ifname = None +init_on_touch = False +in_raw_mode = False +prev_tcgetattr = 0 +no_input = False +srv = None +continue_loop = True +terminate_now = False +summary_file = None +success_file = None + +def summary(txt): + print(txt) + if summary_file: + with open(summary_file, 'a') as f: + f.write(txt + "\n") + +def success_report(txt): + summary(txt) + if success_file: + with open(success_file, 'a') as f: + f.write(txt + "\n") + +def wpas_connect(): + ifaces = [] + if os.path.isdir(wpas_ctrl): + try: + ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)] + except OSError as error: + print("Could not find wpa_supplicant: ", error) + return None + + if len(ifaces) < 1: + print("No wpa_supplicant control interface found") + return None + + for ctrl in ifaces: + if ifname: + if ifname not in ctrl: + continue + try: + print("Trying to use control interface " + ctrl) + wpas = wpaspy.Ctrl(ctrl) + return wpas + except Exception as e: + pass + return None + +def dpp_nfc_uri_process(uri): + wpas = wpas_connect() + if wpas is None: + return False + peer_id = wpas.request("DPP_NFC_URI " + uri) + if "FAIL" in peer_id: + print("Could not parse DPP URI from NFC URI record") + return False + peer_id = int(peer_id) + print("peer_id=%d" % peer_id) + cmd = "DPP_AUTH_INIT peer=%d" % peer_id + res = wpas.request(cmd) + if "OK" not in res: + print("Failed to initiate DPP Authentication") + return False + print("DPP Authentication initiated") + return True + +def dpp_hs_tag_read(record): + wpas = wpas_connect() + if wpas is None: + return False + print(record) + if len(record.data) < 5: + print("Too short DPP HS") + return False + if record.data[0] != 0: + print("Unexpected URI Identifier Code") + return False + uribuf = record.data[1:] + try: + uri = uribuf.decode() + except: + print("Invalid URI payload") + return False + print("URI: " + uri) + if not uri.startswith("DPP:"): + print("Not a DPP URI") + return False + return dpp_nfc_uri_process(uri) + +def get_status(wpas, extra=None): + if extra: + extra = "-" + extra + else: + extra = "" + res = wpas.request("STATUS" + extra) + lines = res.splitlines() + vals = dict() + for l in lines: + try: + [name, value] = l.split('=', 1) + except ValueError: + logger.info("Ignore unexpected status line: " + l) + continue + vals[name] = value + return vals + +def get_status_field(wpas, field, extra=None): + vals = get_status(wpas, extra) + if field in vals: + return vals[field] + return None + +def own_addr(wpas): + return get_status_field(wpas, "address") + +def dpp_bootstrap_gen(wpas, type="qrcode", chan=None, mac=None, info=None, + curve=None, key=None): + cmd = "DPP_BOOTSTRAP_GEN type=" + type + if chan: + cmd += " chan=" + chan + if mac: + if mac is True: + mac = own_addr(wpas) + cmd += " mac=" + mac.replace(':', '') + if info: + cmd += " info=" + info + if curve: + cmd += " curve=" + curve + if key: + cmd += " key=" + key + res = wpas.request(cmd) + if "FAIL" in res: + raise Exception("Failed to generate bootstrapping info") + return int(res) + +def wpas_get_nfc_uri(start_listen=True): + wpas = wpas_connect() + if wpas is None: + return None + global own_id, chanlist + own_id = dpp_bootstrap_gen(wpas, type="nfc-uri", chan=chanlist, mac=True) + res = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip() + if "FAIL" in res: + return None + if start_listen: + wpas.request("DPP_LISTEN 2412 netrole=configurator") + return res + +def wpas_report_handover_req(uri): + wpas = wpas_connect() + if wpas is None: + return None + global own_id + cmd = "DPP_NFC_HANDOVER_REQ own=%d uri=%s" % (own_id, uri) + return wpas.request(cmd) + +def wpas_report_handover_sel(uri): + wpas = wpas_connect() + if wpas is None: + return None + global own_id + cmd = "DPP_NFC_HANDOVER_SEL own=%d uri=%s" % (own_id, uri) + return wpas.request(cmd) + +def dpp_handover_client(llc): + uri = wpas_get_nfc_uri(start_listen=False) + uri = ndef.UriRecord(uri) + print("NFC URI record for DPP: " + str(uri)) + carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data) + hr = ndef.HandoverRequestRecord(version="1.4", crn=os.urandom(2)) + hr.add_alternative_carrier('active', carrier.name) + message = [hr, carrier] + print("NFC Handover Request message for DPP: " + str(message)) + + client = nfc.handover.HandoverClient(llc) + try: + summary("Trying to initiate NFC connection handover") + client.connect() + summary("Connected for handover") + except nfc.llcp.ConnectRefused: + summary("Handover connection refused") + client.close() + return + except Exception as e: + summary("Other exception: " + str(e)) + client.close() + return + + summary("Sending handover request") + + if not client.send_records(message): + summary("Failed to send handover request") + client.close() + return + + summary("Receiving handover response") + message = client.recv_records(timeout=3.0) + if message is None: + summary("No response received") + client.close() + return + print("Received message: " + str(message)) + if len(message) < 1 or \ + not isinstance(message[0], ndef.HandoverSelectRecord): + summary("Response was not Hs - received: " + message.type) + client.close() + return + + print("Received message") + print("alternative carriers: " + str(message[0].alternative_carriers)) + + dpp_found = False + for carrier in message: + if isinstance(carrier, ndef.HandoverSelectRecord): + continue + print("Remote carrier type: " + carrier.type) + if carrier.type == "application/vnd.wfa.dpp": + if len(carrier.data) == 0 or carrier.data[0] != 0: + print("URI Identifier Code 'None' not seen") + continue + print("DPP carrier type match - send to wpa_supplicant") + dpp_found = True + uri = carrier.data[1:].decode("utf-8") + print("DPP URI: " + uri) + res = wpas_report_handover_sel(uri) + if res is None or "FAIL" in res: + summary("DPP handover report rejected") + break + + success_report("DPP handover reported successfully (initiator)") + print("peer_id=" + res) + peer_id = int(res) + # TODO: Single Configurator instance + wpas = wpas_connect() + if wpas is None: + break + res = wpas.request("DPP_CONFIGURATOR_ADD") + if "FAIL" in res: + print("Failed to initiate Configurator") + break + conf_id = int(res) + global own_id + print("Initiate DPP authentication") + cmd = "DPP_AUTH_INIT peer=%d own=%d conf=sta-dpp configurator=%d" % (peer_id, own_id, conf_id) + res = wpas.request(cmd) + if "FAIL" in res: + print("Failed to initiate DPP authentication") + break + + if not dpp_found: + print("DPP carrier not seen in response - allow peer to initiate a new handover with different parameters") + client.close() + print("Returning from dpp_handover_client") + return + + print("Remove peer") + client.close() + print("Done with handover") + global only_one + if only_one: + print("only_one -> stop loop") + global continue_loop + continue_loop = False + + global no_wait + if no_wait: + print("Trying to exit..") + global terminate_now + terminate_now = True + + print("Returning from dpp_handover_client") + +class HandoverServer(nfc.handover.HandoverServer): + def __init__(self, llc): + super(HandoverServer, self).__init__(llc) + self.sent_carrier = None + self.ho_server_processing = False + self.success = False + self.try_own = False + + def process_handover_request_message(self, records): + self.ho_server_processing = True + clear_raw_mode() + print("\nHandoverServer - request received: " + str(records)) + + carrier = None + hs = ndef.HandoverSelectRecord('1.4') + sel = [hs] + + found = False + + for carrier in records: + if isinstance(carrier, ndef.HandoverRequestRecord): + continue + print("Remote carrier type: " + carrier.type) + if carrier.type == "application/vnd.wfa.dpp": + print("DPP carrier type match - add DPP carrier record") + if len(carrier.data) == 0 or carrier.data[0] != 0: + print("URI Identifier Code 'None' not seen") + continue + uri = carrier.data[1:].decode("utf-8") + print("Received DPP URI: " + uri) + + data = wpas_get_nfc_uri(start_listen=False) + print("Own URI (pre-processing): %s" % data) + + res = wpas_report_handover_req(uri) + if res is None or "FAIL" in res: + print("DPP handover request processing failed") + continue + + found = True + self.received_carrier = carrier + + wpas = wpas_connect() + if wpas is None: + continue + global own_id + data = wpas.request("DPP_BOOTSTRAP_GET_URI %d" % own_id).rstrip() + if "FAIL" in data: + continue + print("Own URI (post-processing): %s" % data) + uri = ndef.UriRecord(data) + print("Own bootstrapping NFC URI record: " + str(uri)) + + info = wpas.request("DPP_BOOTSTRAP_INFO %d" % own_id) + freq = None + for line in info.splitlines(): + if line.startswith("use_freq="): + freq = int(line.split('=')[1]) + if freq is None: + print("No channel negotiated over NFC - use channel 1") + freq = 2412 + res = wpas.request("DPP_LISTEN %d" % freq) + if "OK" not in res: + print("Failed to start DPP listen") + break + + carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data) + print("Own DPP carrier record: " + str(carrier)) + hs.add_alternative_carrier('active', carrier.name) + sel = [hs, carrier] + break + + summary("Sending handover select: " + str(sel)) + if found: + self.success = True + else: + self.try_own = True + return sel + +def clear_raw_mode(): + import sys, tty, termios + global prev_tcgetattr, in_raw_mode + if not in_raw_mode: + return + fd = sys.stdin.fileno() + termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr) + in_raw_mode = False + +def getch(): + import sys, tty, termios, select + global prev_tcgetattr, in_raw_mode + fd = sys.stdin.fileno() + prev_tcgetattr = termios.tcgetattr(fd) + ch = None + try: + tty.setraw(fd) + in_raw_mode = True + [i, o, e] = select.select([fd], [], [], 0.05) + if i: + ch = sys.stdin.read(1) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, prev_tcgetattr) + in_raw_mode = False + return ch + +def dpp_tag_read(tag): + success = False + for record in tag.ndef.records: + print(record) + print("record type " + record.type) + if record.type == "application/vnd.wfa.dpp": + summary("DPP HS tag - send to wpa_supplicant") + success = dpp_hs_tag_read(record) + break + if isinstance(record, ndef.UriRecord): + print("URI record: uri=" + record.uri) + print("URI record: iri=" + record.iri) + if record.iri.startswith("DPP:"): + print("DPP URI") + if not dpp_nfc_uri_process(record.iri): + break + success = True + else: + print("Ignore unknown URI") + break + + if success: + success_report("Tag read succeeded") + + return success + +def rdwr_connected_write_tag(tag): + summary("Tag found - writing - " + str(tag)) + if not tag.ndef.is_writeable: + print("Not a writable tag") + return + global dpp_tag_data + if tag.ndef.capacity < len(dpp_tag_data): + print("Not enough room for the message") + return + tag.ndef.records = dpp_tag_data + success_report("Tag write succeeded") + print("Done - remove tag") + global only_one + if only_one: + global continue_loop + continue_loop = False + global dpp_sel_wait_remove + return dpp_sel_wait_remove + +def write_nfc_uri(clf, wait_remove=True): + print("Write NFC URI record") + data = wpas_get_nfc_uri() + if data is None: + summary("Could not get NFC URI from wpa_supplicant") + return + + global dpp_sel_wait_remove + dpp_sel_wait_remove = wait_remove + print("URI: %s" % data) + uri = ndef.UriRecord(data) + print(uri) + + print("Touch an NFC tag") + global dpp_tag_data + dpp_tag_data = [uri] + clf.connect(rdwr={'on-connect': rdwr_connected_write_tag}) + +def write_nfc_hs(clf, wait_remove=True): + print("Write NFC Handover Select record on a tag") + data = wpas_get_nfc_uri() + if data is None: + summary("Could not get NFC URI from wpa_supplicant") + return + + global dpp_sel_wait_remove + dpp_sel_wait_remove = wait_remove + print("URI: %s" % data) + uri = ndef.UriRecord(data) + print(uri) + carrier = ndef.Record('application/vnd.wfa.dpp', 'A', uri.data) + hs = ndef.HandoverSelectRecord('1.4') + hs.add_alternative_carrier('active', carrier.name) + print(hs) + print(carrier) + + print("Touch an NFC tag") + global dpp_tag_data + dpp_tag_data = [hs, carrier] + print(dpp_tag_data) + clf.connect(rdwr={'on-connect': rdwr_connected_write_tag}) + +def rdwr_connected(tag): + global only_one, no_wait + summary("Tag connected: " + str(tag)) + + if tag.ndef: + print("NDEF tag: " + tag.type) + print(tag.ndef.records) + success = dpp_tag_read(tag) + if only_one and success: + global continue_loop + continue_loop = False + else: + summary("Not an NDEF tag - remove tag") + return True + + return not no_wait + +def llcp_worker(llc): + global init_on_touch + if init_on_touch: + print("Starting handover client") + dpp_handover_client(llc) + print("Exiting llcp_worker thread (init_in_touch)") + return + + global no_input + if no_input: + print("Wait for handover to complete") + else: + print("Wait for handover to complete - press 'i' to initiate") + global srv + global wait_connection + while not wait_connection and srv.sent_carrier is None: + if srv.try_own: + srv.try_own = False + print("Try to initiate another handover with own parameters") + dpp_handover_client(llc) + print("Exiting llcp_worker thread (retry with own parameters)") + return + if srv.ho_server_processing: + time.sleep(0.025) + elif no_input: + time.sleep(0.5) + else: + res = getch() + if res != 'i': + continue + clear_raw_mode() + print("Starting handover client") + dpp_handover_client(llc) + print("Exiting llcp_worker thread (manual init)") + return + + clear_raw_mode() + print("\rExiting llcp_worker thread") + +def llcp_startup(llc): + print("Start LLCP server") + global srv + srv = HandoverServer(llc) + return llc + +def llcp_connected(llc): + print("P2P LLCP connected") + global wait_connection + wait_connection = False + global init_on_touch + if not init_on_touch: + global srv + srv.start() + if init_on_touch or not no_input: + threading.Thread(target=llcp_worker, args=(llc,)).start() + return True + +def llcp_release(llc): + print("LLCP release") + return True + +def terminate_loop(): + global terminate_now + return terminate_now + +def main(): + clf = nfc.ContactlessFrontend() + + parser = argparse.ArgumentParser(description='nfcpy to wpa_supplicant integration for DPP NFC operations') + parser.add_argument('-d', const=logging.DEBUG, default=logging.INFO, + action='store_const', dest='loglevel', + help='verbose debug output') + parser.add_argument('-q', const=logging.WARNING, action='store_const', + dest='loglevel', help='be quiet') + parser.add_argument('--only-one', '-1', action='store_true', + help='run only one operation and exit') + parser.add_argument('--init-on-touch', '-I', action='store_true', + help='initiate handover on touch') + parser.add_argument('--no-wait', action='store_true', + help='do not wait for tag to be removed before exiting') + parser.add_argument('--ifname', '-i', + help='network interface name') + parser.add_argument('--no-input', '-a', action='store_true', + help='do not use stdout input to initiate handover') + parser.add_argument('--tag-read-only', '-t', action='store_true', + help='tag read only (do not allow connection handover)') + parser.add_argument('--handover-only', action='store_true', + help='connection handover only (do not allow tag read)') + parser.add_argument('--summary', + help='summary file for writing status updates') + parser.add_argument('--success', + help='success file for writing success update') + parser.add_argument('--device', default='usb', help='NFC device to open') + parser.add_argument('--chan', default='81/1', help='channel list') + parser.add_argument('command', choices=['write-nfc-uri', + 'write-nfc-hs'], + nargs='?') + args = parser.parse_args() + print(args) + + global only_one + only_one = args.only_one + + global no_wait + no_wait = args.no_wait + + global chanlist + chanlist = args.chan + + logging.basicConfig(level=args.loglevel) + + global init_on_touch + init_on_touch = args.init_on_touch + + if args.ifname: + global ifname + ifname = args.ifname + print("Selected ifname " + ifname) + + if args.summary: + global summary_file + summary_file = args.summary + + if args.success: + global success_file + success_file = args.success + + if args.no_input: + global no_input + no_input = True + + clf = nfc.ContactlessFrontend() + global wait_connection + + try: + if not clf.open(args.device): + print("Could not open connection with an NFC device") + raise SystemExit + + if args.command == "write-nfc-uri": + write_nfc_uri(clf, wait_remove=not args.no_wait) + raise SystemExit + + if args.command == "write-nfc-hs": + write_nfc_hs(clf, wait_remove=not args.no_wait) + raise SystemExit + + global continue_loop + while continue_loop: + clear_raw_mode() + print("\rWaiting for a tag or peer to be touched") + wait_connection = True + try: + if args.tag_read_only: + if not clf.connect(rdwr={'on-connect': rdwr_connected}): + break + elif args.handover_only: + if not clf.connect(llcp={'on-startup': llcp_startup, + 'on-connect': llcp_connected, + 'on-release': llcp_release}, + terminate=terminate_loop): + break + else: + if not clf.connect(rdwr={'on-connect': rdwr_connected}, + llcp={'on-startup': llcp_startup, + 'on-connect': llcp_connected, + 'on-release': llcp_release}, + terminate=terminate_loop): + break + except Exception as e: + print("clf.connect failed: " + str(e)) + break + + global srv + if only_one and srv and srv.success: + raise SystemExit + + except KeyboardInterrupt: + raise SystemExit + finally: + clf.close() + + raise SystemExit + +if __name__ == '__main__': + main() diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py index 6e3d94e2..2f62e9c9 100644 --- a/wpa_supplicant/examples/p2p/p2p_connect.py +++ b/wpa_supplicant/examples/p2p/p2p_connect.py @@ -108,7 +108,7 @@ class P2P_Connect(): self.path = None try: self.path = self.wpas.GetInterface(ifname) - except: + except dbus.DBusException as exc: if not str(exc).startswith( self.wpas_dbus_interface + \ ".InterfaceUnknown:"): diff --git a/wpa_supplicant/hidl/1.3/p2p_iface.cpp b/wpa_supplicant/hidl/1.3/p2p_iface.cpp index bd893a34..ffa9b6a6 100644 --- a/wpa_supplicant/hidl/1.3/p2p_iface.cpp +++ b/wpa_supplicant/hidl/1.3/p2p_iface.cpp @@ -100,7 +100,7 @@ void setBandScanFreqsList( struct hostapd_hw_modes *mode; int count, i; - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, 0); if (mode == NULL) { /* No channels supported in this band. */ return; diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c index 36c0aff1..02e63904 100644 --- a/wpa_supplicant/ibss_rsn.c +++ b/wpa_supplicant/ibss_rsn.c @@ -64,10 +64,16 @@ static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, { struct ibss_rsn_peer *peer = ctx; struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; + int encrypt = peer->authentication_status & IBSS_RSN_REPORTED_PTK; - wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " - "len=%lu)", - __func__, MAC2STR(dest), proto, (unsigned long) len); + wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR + " proto=0x%04x len=%lu no_encrypt=%d)", + __func__, MAC2STR(dest), proto, (unsigned long) len, + !encrypt); + + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) + return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len, + !encrypt); if (wpa_s->l2) return l2_packet_send(wpa_s->l2, dest, proto, buf, len); @@ -140,7 +146,7 @@ static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer) static int supp_set_key(void *ctx, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) + const u8 *key, size_t key_len, enum key_flag key_flag) { struct ibss_rsn_peer *peer = ctx; @@ -167,7 +173,7 @@ static int supp_set_key(void *ctx, enum wpa_alg alg, if (is_broadcast_ether_addr(addr)) addr = peer->addr; return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx, - set_tx, seq, seq_len, key, key_len); + set_tx, seq, seq_len, key, key_len, key_flag); } @@ -194,7 +200,13 @@ static void supp_cancel_auth_timeout(void *ctx) } -static void supp_deauthenticate(void * ctx, u16 reason_code) +static void supp_deauthenticate(void *ctx, u16 reason_code) +{ + wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); +} + + +static void supp_reconnect(void *ctx) { wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); } @@ -219,6 +231,7 @@ static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, ctx->mlme_setprotection = supp_mlme_setprotection; ctx->cancel_auth_timeout = supp_cancel_auth_timeout; ctx->deauthenticate = supp_deauthenticate; + ctx->reconnect = supp_reconnect; peer->supp = wpa_sm_init(ctx); if (peer->supp == NULL) { wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); @@ -287,6 +300,10 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, "encrypt=%d)", __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) + return wpa_drv_tx_control_port(wpa_s, addr, ETH_P_EAPOL, + data, data_len, !encrypt); + if (wpa_s->l2) return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data, data_len); @@ -296,7 +313,8 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, - const u8 *addr, int idx, u8 *key, size_t key_len) + const u8 *addr, int idx, u8 *key, size_t key_len, + enum key_flag key_flag) { struct ibss_rsn *ibss_rsn = ctx; u8 seq[6]; @@ -335,7 +353,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, } return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx, - 1, seq, 6, key, key_len); + 1, seq, 6, key, key_len, key_flag); } @@ -487,9 +505,6 @@ static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq) const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth); struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; - if (wpa_s->driver->send_frame == NULL) - return -1; - os_memset(&auth, 0, sizeof(auth)); auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, @@ -505,8 +520,7 @@ static int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq) wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR, seq, MAC2STR(da)); - return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth, - auth_length, 0); + return wpa_drv_send_mlme(wpa_s, (u8 *) &auth, auth_length, 0, 0, 0); } @@ -852,7 +866,7 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer " MACSTR, MAC2STR(addr)); wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0, - NULL, 0, NULL, 0); + NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE); } if (peer && diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c index 308366f6..4925b5cd 100644 --- a/wpa_supplicant/mesh_mpm.c +++ b/wpa_supplicant/mesh_mpm.c @@ -233,12 +233,10 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, 2 + 24 + /* peering management */ 2 + 96 + 32 + 32 + /* AMPE (96 + max GTKlen + max IGTKlen) */ 2 + 16; /* MIC */ -#ifdef CONFIG_IEEE80211N if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) { buf_len += 2 + 26 + /* HT capabilities */ 2 + 22; /* HT operation */ } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) { buf_len += 2 + 12 + /* VHT Capabilities */ @@ -354,7 +352,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, wpabuf_put(buf, PMKID_LEN)); } -#ifdef CONFIG_IEEE80211N if (type != PLINK_CLOSE && wpa_s->mesh_ht_enabled) { u8 ht_capa_oper[2 + 26 + 2 + 22]; @@ -362,7 +359,6 @@ static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s, pos = hostapd_eid_ht_operation(bss, pos); wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper); } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC if (type != PLINK_CLOSE && wpa_s->mesh_vht_enabled) { u8 vht_capa_oper[2 + 12 + 2 + 5]; @@ -696,9 +692,7 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, struct mesh_conf *conf = wpa_s->ifmsh->mconf; struct hostapd_data *data = wpa_s->ifmsh->bss[0]; struct sta_info *sta; -#ifdef CONFIG_IEEE80211N struct ieee80211_ht_operation *oper; -#endif /* CONFIG_IEEE80211N */ int ret; if (elems->mesh_config_len >= 7 && @@ -710,11 +704,12 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, } sta = ap_get_sta(data, addr); - if (!sta) { - sta = ap_sta_add(data, addr); - if (!sta) - return NULL; - } + if (sta) + return NULL; + + sta = ap_sta_add(data, addr); + if (!sta) + return NULL; /* Set WMM by default since Mesh STAs are QoS STAs */ sta->flags |= WLAN_STA_WMM; @@ -728,7 +723,6 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, if (!sta->my_lid) mesh_mpm_init_link(wpa_s, sta); -#ifdef CONFIG_IEEE80211N copy_sta_ht_capab(data, sta, elems->ht_capabilities); oper = (struct ieee80211_ht_operation *) elems->ht_operation; @@ -742,7 +736,6 @@ static struct sta_info * mesh_mpm_add_peer(struct wpa_supplicant *wpa_s, } update_ht_state(data, sta); -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC copy_sta_vht_capab(data, sta, elems->vht_capabilities); @@ -876,7 +869,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len); wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher), sta->addr, 0, 0, seq, sizeof(seq), - sta->mtk, sta->mtk_len); + sta->mtk, sta->mtk_len, + KEY_FLAG_PAIRWISE_RX_TX); wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC", sta->mgtk_rsc, sizeof(sta->mgtk_rsc)); @@ -885,7 +879,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher), sta->addr, sta->mgtk_key_id, 0, sta->mgtk_rsc, sizeof(sta->mgtk_rsc), - sta->mgtk, sta->mgtk_len); + sta->mgtk, sta->mgtk_len, + KEY_FLAG_GROUP_RX); if (sta->igtk_len) { wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC", @@ -897,7 +892,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s, wpa_cipher_to_alg(conf->mgmt_group_cipher), sta->addr, sta->igtk_key_id, 0, sta->igtk_rsc, sizeof(sta->igtk_rsc), - sta->igtk, sta->igtk_len); + sta->igtk, sta->igtk_len, + KEY_FLAG_GROUP_RX); } } diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c index e730b633..f19bfbfc 100644 --- a/wpa_supplicant/mesh_rsn.c +++ b/wpa_supplicant/mesh_rsn.c @@ -100,7 +100,8 @@ static const u8 *auth_get_psk(void *ctx, const u8 *addr, static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, - const u8 *addr, int idx, u8 *key, size_t key_len) + const u8 *addr, int idx, u8 *key, size_t key_len, + enum key_flag key_flag) { struct mesh_rsn *mesh_rsn = ctx; u8 seq[6]; @@ -118,7 +119,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx, - 1, seq, 6, key, key_len); + 1, seq, 6, key, key_len, key_flag); } @@ -196,7 +197,8 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL, rsn->igtk_key_id, 1, - seq, sizeof(seq), rsn->igtk, rsn->igtk_len); + seq, sizeof(seq), rsn->igtk, rsn->igtk_len, + KEY_FLAG_GROUP_TX_DEFAULT); } /* group privacy / data frames */ @@ -204,7 +206,7 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, rsn->mgtk, rsn->mgtk_len); wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL, rsn->mgtk_key_id, 1, seq, sizeof(seq), - rsn->mgtk, rsn->mgtk_len); + rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT); return 0; } diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c index b74be7da..e40cf5bb 100644 --- a/wpa_supplicant/offchannel.c +++ b/wpa_supplicant/offchannel.c @@ -226,10 +226,10 @@ void offchannel_send_action_tx_status( } #ifdef CONFIG_P2P - if (wpa_s->p2p_long_listen > 0) { + if (wpa_s->global->p2p_long_listen > 0) { /* Continue the listen */ wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state"); - wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen); + wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen); } #endif /* CONFIG_P2P */ } @@ -246,7 +246,7 @@ void offchannel_send_action_tx_status( * @buf: Frame to transmit starting from the Category field * @len: Length of @buf in bytes * @wait_time: Wait time for response in milliseconds - * @tx_cb: Callback function for indicating TX status or %NULL for now callback + * @tx_cb: Callback function for indicating TX status or %NULL for no callback * @no_cck: Whether CCK rates are to be disallowed for TX rate selection * Returns: 0 on success or -1 on failure * diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c index b15ac9e3..983801fa 100644 --- a/wpa_supplicant/op_classes.c +++ b/wpa_supplicant/op_classes.c @@ -14,6 +14,7 @@ #include "utils/common.h" #include "common/ieee802_11_common.h" #include "wpa_supplicant_i.h" +#include "bss.h" static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, @@ -228,7 +229,8 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, int freq2 = 0; int freq5 = 0; - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op_class->mode, + is_6ghz_op_class(op_class->op_class)); if (!mode) return 0; @@ -355,9 +357,25 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s, } +static int wpas_sta_secondary_channel_offset(struct wpa_bss *bss, u8 *current, + u8 *channel) +{ + + u8 *ies, phy_type; + size_t ies_len; + + if (!bss) + return -1; + ies = (u8 *) (bss + 1); + ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len; + return wpas_get_op_chan_phy(bss->freq, ies, ies_len, current, + channel, &phy_type); +} + + size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, - int freq, u8 *pos, size_t len) + struct wpa_bss *bss, u8 *pos, size_t len) { struct wpabuf *buf; u8 op, current, chan; @@ -365,11 +383,13 @@ size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, size_t res; /* - * Assume 20 MHz channel for now. - * TODO: Use the secondary channel and VHT channel width that will be - * used after association. + * Determine the current operating class correct mode based on + * advertised BSS capabilities, if available. Fall back to a less + * accurate guess based on frequency if the needed IEs are not available + * or used. */ - if (ieee80211_freq_to_channel_ext(freq, 0, CHANWIDTH_USE_HT, + if (wpas_sta_secondary_channel_offset(bss, ¤t, &chan) < 0 && + ieee80211_freq_to_channel_ext(bss->freq, 0, CHANWIDTH_USE_HT, ¤t, &chan) == NUM_HOSTAPD_MODES) return 0; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index a3c4574e..2c8754bd 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1912,7 +1912,7 @@ static int wpas_p2p_freq_to_edmg_channel(struct wpa_supplicant *wpa_s, return -1; hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, - HOSTAPD_MODE_IEEE80211AD); + HOSTAPD_MODE_IEEE80211AD, 0); if (!hwmode) { wpa_printf(MSG_ERROR, "Unsupported AP mode: HOSTAPD_MODE_IEEE80211AD"); @@ -2422,7 +2422,7 @@ static void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res) wpas_start_wps_enrollee(group_wpa_s, res); } - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL); @@ -2701,7 +2701,7 @@ static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf, { struct wpa_supplicant *wpa_s = ctx; return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, - freq); + freq, 0); } @@ -3735,7 +3735,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, if (o->p2p == NO_P2P_SUPP) continue; - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode, + is_6ghz_op_class(o->op_class)); if (mode == NULL) continue; if (mode->mode == HOSTAPD_MODE_IEEE80211G) @@ -3745,23 +3746,32 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw); if (res == ALLOWED) { if (reg == NULL) { + if (cla == P2P_MAX_REG_CLASSES) + continue; wpa_printf(MSG_DEBUG, "P2P: Add operating class %u", o->op_class); reg = &chan->reg_class[cla]; cla++; reg->reg_class = o->op_class; } + if (reg->channels == P2P_MAX_REG_CLASS_CHANNELS) + continue; reg->channel[reg->channels] = ch; reg->channels++; } else if (res == NO_IR && wpa_s->conf->p2p_add_cli_chan) { if (cli_reg == NULL) { + if (cli_cla == P2P_MAX_REG_CLASSES) + continue; wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)", o->op_class); cli_reg = &cli_chan->reg_class[cli_cla]; cli_cla++; cli_reg->reg_class = o->op_class; } + if (cli_reg->channels == + P2P_MAX_REG_CLASS_CHANNELS) + continue; cli_reg->channel[cli_reg->channels] = ch; cli_reg->channels++; } @@ -4758,7 +4768,7 @@ void wpas_p2p_deinit(struct wpa_supplicant *wpa_s) eloop_cancel_timeout(wpas_p2p_psk_failure_removal, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL); wpas_p2p_remove_pending_group_interface(wpa_s); @@ -5643,7 +5653,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr, go_intent = wpa_s->conf->p2p_go_intent; if (!auth) - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; wpa_s->p2p_wps_method = wps_method; wpa_s->p2p_persistent_group = !!persistent_group; @@ -5813,19 +5823,20 @@ void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s, { wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback " "(p2p_long_listen=%d ms pending_action_tx=%p)", - wpa_s->p2p_long_listen, offchannel_pending_action_tx(wpa_s)); + wpa_s->global->p2p_long_listen, + offchannel_pending_action_tx(wpa_s)); wpas_p2p_listen_work_done(wpa_s); if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return; - if (wpa_s->p2p_long_listen > 0) - wpa_s->p2p_long_listen -= wpa_s->max_remain_on_chan; + if (wpa_s->global->p2p_long_listen > 0) + wpa_s->global->p2p_long_listen -= wpa_s->max_remain_on_chan; if (p2p_listen_end(wpa_s->global->p2p, freq) > 0) return; /* P2P module started a new operation */ if (offchannel_pending_action_tx(wpa_s)) return; - if (wpa_s->p2p_long_listen > 0) { + if (wpa_s->global->p2p_long_listen > 0) { wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state"); - wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen); + wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen); } else { /* * When listen duration is over, stop listen & update p2p_state @@ -6298,7 +6309,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, cand = wpa_s->p2p_group_common_freqs[i]; mode = ieee80211_freq_to_chan(cand, &chan); hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, - mode); + mode, is_6ghz_freq(cand)); if (!hwmode || wpas_p2p_verify_channel(wpa_s, hwmode, chan, BW80) != ALLOWED) @@ -6325,7 +6336,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s, cand = wpa_s->p2p_group_common_freqs[i]; mode = ieee80211_freq_to_chan(cand, &chan); hwmode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, - mode); + mode, is_6ghz_freq(cand)); if (!wpas_same_band(wpa_s->current_ssid->frequency, cand) || !hwmode || @@ -6960,7 +6971,7 @@ int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout, u8 seek_cnt, const char **seek_string, int freq) { wpas_p2p_clear_pending_action_tx(wpa_s); - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL || wpa_s->p2p_in_provisioning) { @@ -7005,7 +7016,7 @@ static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s, static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s) { wpas_p2p_clear_pending_action_tx(wpa_s); - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL); @@ -7031,7 +7042,7 @@ void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s) static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx) { struct wpa_supplicant *wpa_s = eloop_ctx; - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; } @@ -7060,7 +7071,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout) timeout = 3600; } eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL); - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; /* * Stop previous find/listen operation to avoid trying to request a new @@ -7072,7 +7083,7 @@ int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout) res = wpas_p2p_listen_start(wpa_s, timeout * 1000); if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) { - wpa_s->p2p_long_listen = timeout * 1000; + wpa_s->global->p2p_long_listen = timeout * 1000; eloop_register_timeout(timeout, 0, wpas_p2p_long_listen_timeout, wpa_s, NULL); @@ -7179,7 +7190,7 @@ static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s) int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr) { - wpa_s->p2p_long_listen = 0; + wpa_s->global->p2p_long_listen = 0; if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) return -1; diff --git a/wpa_supplicant/preauth_test.c b/wpa_supplicant/preauth_test.c index 3f2da34e..4a8f4ff8 100644 --- a/wpa_supplicant/preauth_test.c +++ b/wpa_supplicant/preauth_test.c @@ -41,6 +41,12 @@ static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code) } +static void _wpa_supplicant_reconnect(void *wpa_s) +{ + wpa_supplicant_reconnect(wpa_s); +} + + static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type, const void *data, u16 data_len, size_t *msg_len, void **data_pos) @@ -127,7 +133,8 @@ static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid) static int wpa_supplicant_set_key(void *wpa_s, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) + const u8 *key, size_t key_len, + enum key_flag key_flag) { printf("%s - not implemented\n", __func__); return -1; @@ -146,7 +153,8 @@ static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr, static int wpa_supplicant_add_pmkid(void *wpa_s, void *network_ctx, const u8 *bssid, const u8 *pmkid, const u8 *fils_cache_id, - const u8 *pmk, size_t pmk_len) + const u8 *pmk, size_t pmk_len, + u32 pmk_lifetime, u8 pmk_reauth_threshold) { printf("%s - not implemented\n", __func__); return -1; @@ -244,6 +252,7 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname) ctx->set_config_blob = wpa_supplicant_set_config_blob; ctx->get_config_blob = wpa_supplicant_get_config_blob; ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection; + ctx->reconnect = _wpa_supplicant_reconnect; wpa_s->wpa = wpa_sm_init(ctx); assert(wpa_s->wpa != NULL); diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c index 7930e012..afc11727 100644 --- a/wpa_supplicant/rrm.c +++ b/wpa_supplicant/rrm.c @@ -609,7 +609,8 @@ static int * wpas_channel_report_freqs(struct wpa_supplicant *wpa_s, int active, pos++; left--; - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode, + is_6ghz_op_class(op->op_class)); if (!mode) continue; @@ -661,7 +662,8 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, return NULL; } - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, op->mode, + is_6ghz_op_class(op->op_class)); if (!mode) return NULL; @@ -693,8 +695,8 @@ static int * wpas_beacon_request_freqs(struct wpa_supplicant *wpa_s, } -static int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len, - u8 *op_class, u8 *chan, u8 *phy_type) +int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len, + u8 *op_class, u8 *chan, u8 *phy_type) { const u8 *ie; int sec_chan = 0, vht = 0; diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 4d158a9c..b4757309 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -668,13 +668,14 @@ static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s) static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s, enum hostapd_hw_mode band, - struct wpa_driver_scan_params *params) + struct wpa_driver_scan_params *params, + int is_6ghz) { /* Include only supported channels for the specified band */ struct hostapd_hw_modes *mode; int count, i; - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band, is_6ghz); if (mode == NULL) { /* No channels supported in this band - use empty list */ params->freqs = os_zalloc(sizeof(int)); @@ -701,10 +702,10 @@ static void wpa_setband_scan_freqs(struct wpa_supplicant *wpa_s, return; /* already using a limited channel set */ if (wpa_s->setband == WPA_SETBAND_5G) wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211A, - params); + params, 0); else if (wpa_s->setband == WPA_SETBAND_2G) wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, - params); + params, 0); } @@ -1108,7 +1109,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) tssid = tssid->next) { if (wpas_network_disabled(wpa_s, tssid)) continue; - if ((params.freqs || !freqs_set) && tssid->scan_freq) { + if (((params.freqs || !freqs_set) && + tssid->scan_freq) && + int_array_len(params.freqs) < 100) { int_array_concat(¶ms.freqs, tssid->scan_freq); } else { @@ -1250,7 +1253,8 @@ ssid_list_set: params.bssid = wpa_s->next_scan_bssid; bss = wpa_bss_get_bssid_latest(wpa_s, params.bssid); - if (bss && bss->ssid_len && params.num_ssids == 1 && + if (!wpa_s->next_scan_bssid_wildcard_ssid && + bss && bss->ssid_len && params.num_ssids == 1 && params.ssids[0].ssid_len == 0) { params.ssids[0].ssid = bss->ssid; params.ssids[0].ssid_len = bss->ssid_len; @@ -1327,6 +1331,7 @@ scan: #ifdef CONFIG_INTERWORKING wpa_s->interworking_fast_assoc_tried = 0; #endif /* CONFIG_INTERWORKING */ + wpa_s->next_scan_bssid_wildcard_ssid = 0; if (params.bssid) os_memset(wpa_s->next_scan_bssid, 0, ETH_ALEN); } @@ -1956,20 +1961,6 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res, } -/* - * Channels with a great SNR can operate at full rate. What is a great SNR? - * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general - * rule of thumb is that any SNR above 20 is good." This one - * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23 - * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in - * scan_est_throughput() allow even smaller SNR values for the maximum rates - * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a - * somewhat conservative value here. - */ -#define GREAT_SNR 25 - -#define IS_5GHZ(n) (n > 4000) - /* Compare function for sorting scan results. Return >0 if @b is considered * better. */ static int wpa_scan_result_compar(const void *a, const void *b) @@ -2178,14 +2169,6 @@ void filter_scan_res(struct wpa_supplicant *wpa_s, } -/* - * Noise floor values to use when we have signal strength - * measurements, but no noise floor measurements. These values were - * measured in an office environment with many APs. - */ -#define DEFAULT_NOISE_FLOOR_2GHZ (-89) -#define DEFAULT_NOISE_FLOOR_5GHZ (-92) - void scan_snr(struct wpa_scan_res *res) { if (res->flags & WPA_SCAN_NOISE_INVALID) { @@ -2204,86 +2187,83 @@ void scan_snr(struct wpa_scan_res *res) } -static unsigned int max_ht20_rate(int snr) +static unsigned int interpolate_rate(int snr, int snr0, int snr1, + int rate0, int rate1) +{ + return rate0 + (snr - snr0) * (rate1 - rate0) / (snr1 - snr0); +} + + +#define INTERPOLATE_RATE(snr0, snr1, rate0, rate1) \ + if (snr < (snr1)) \ + return interpolate_rate(snr, (snr0), (snr1), (rate0), (rate1)) + +static unsigned int max_ht20_rate(int snr, int vht) { - if (snr < 6) - return 6500; /* HT20 MCS0 */ - if (snr < 8) - return 13000; /* HT20 MCS1 */ - if (snr < 13) - return 19500; /* HT20 MCS2 */ - if (snr < 17) - return 26000; /* HT20 MCS3 */ - if (snr < 20) - return 39000; /* HT20 MCS4 */ - if (snr < 23) - return 52000; /* HT20 MCS5 */ - if (snr < 24) - return 58500; /* HT20 MCS6 */ - return 65000; /* HT20 MCS7 */ + if (snr < 0) + return 0; + INTERPOLATE_RATE(0, 2, 0, 6500); /* HT20 MCS0 */ + INTERPOLATE_RATE(2, 5, 6500, 13000); /* HT20 MCS1 */ + INTERPOLATE_RATE(5, 9, 13000, 19500); /* HT20 MCS2 */ + INTERPOLATE_RATE(9, 11, 19500, 26000); /* HT20 MCS3 */ + INTERPOLATE_RATE(11, 15, 26000, 39000); /* HT20 MCS4 */ + INTERPOLATE_RATE(15, 18, 39000, 52000); /* HT20 MCS5 */ + INTERPOLATE_RATE(18, 20, 52000, 58500); /* HT20 MCS6 */ + INTERPOLATE_RATE(20, 25, 58500, 65000); /* HT20 MCS7 */ + if (!vht) + return 65000; + INTERPOLATE_RATE(25, 29, 65000, 78000); /* VHT20 MCS8 */ + return 78000; } -static unsigned int max_ht40_rate(int snr) +static unsigned int max_ht40_rate(int snr, int vht) { - if (snr < 3) - return 13500; /* HT40 MCS0 */ - if (snr < 6) - return 27000; /* HT40 MCS1 */ - if (snr < 10) - return 40500; /* HT40 MCS2 */ - if (snr < 15) - return 54000; /* HT40 MCS3 */ - if (snr < 17) - return 81000; /* HT40 MCS4 */ - if (snr < 22) - return 108000; /* HT40 MCS5 */ - if (snr < 24) - return 121500; /* HT40 MCS6 */ - return 135000; /* HT40 MCS7 */ + if (snr < 0) + return 0; + INTERPOLATE_RATE(0, 5, 0, 13500); /* HT40 MCS0 */ + INTERPOLATE_RATE(5, 8, 13500, 27000); /* HT40 MCS1 */ + INTERPOLATE_RATE(8, 12, 27000, 40500); /* HT40 MCS2 */ + INTERPOLATE_RATE(12, 14, 40500, 54000); /* HT40 MCS3 */ + INTERPOLATE_RATE(14, 18, 54000, 81000); /* HT40 MCS4 */ + INTERPOLATE_RATE(18, 21, 81000, 108000); /* HT40 MCS5 */ + INTERPOLATE_RATE(21, 23, 108000, 121500); /* HT40 MCS6 */ + INTERPOLATE_RATE(23, 28, 121500, 135000); /* HT40 MCS7 */ + if (!vht) + return 135000; + INTERPOLATE_RATE(28, 32, 135000, 162000); /* VHT40 MCS8 */ + INTERPOLATE_RATE(32, 34, 162000, 180000); /* VHT40 MCS9 */ + return 180000; } static unsigned int max_vht80_rate(int snr) { - if (snr < 1) + if (snr < 0) return 0; - if (snr < 2) - return 29300; /* VHT80 MCS0 */ - if (snr < 5) - return 58500; /* VHT80 MCS1 */ - if (snr < 9) - return 87800; /* VHT80 MCS2 */ - if (snr < 11) - return 117000; /* VHT80 MCS3 */ - if (snr < 15) - return 175500; /* VHT80 MCS4 */ - if (snr < 16) - return 234000; /* VHT80 MCS5 */ - if (snr < 18) - return 263300; /* VHT80 MCS6 */ - if (snr < 20) - return 292500; /* VHT80 MCS7 */ - if (snr < 22) - return 351000; /* VHT80 MCS8 */ - return 390000; /* VHT80 MCS9 */ + INTERPOLATE_RATE(0, 8, 0, 29300); /* VHT80 MCS0 */ + INTERPOLATE_RATE(8, 11, 29300, 58500); /* VHT80 MCS1 */ + INTERPOLATE_RATE(11, 15, 58500, 87800); /* VHT80 MCS2 */ + INTERPOLATE_RATE(15, 17, 87800, 117000); /* VHT80 MCS3 */ + INTERPOLATE_RATE(17, 21, 117000, 175500); /* VHT80 MCS4 */ + INTERPOLATE_RATE(21, 24, 175500, 234000); /* VHT80 MCS5 */ + INTERPOLATE_RATE(24, 26, 234000, 263300); /* VHT80 MCS6 */ + INTERPOLATE_RATE(26, 31, 263300, 292500); /* VHT80 MCS7 */ + INTERPOLATE_RATE(31, 35, 292500, 351000); /* VHT80 MCS8 */ + INTERPOLATE_RATE(35, 37, 351000, 390000); /* VHT80 MCS9 */ + return 390000; } +#undef INTERPOLATE_RATE -void scan_est_throughput(struct wpa_supplicant *wpa_s, - struct wpa_scan_res *res) + +unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, + const u8 *ies, size_t ies_len, int rate, + int snr) { enum local_hw_capab capab = wpa_s->hw_capab; - int rate; /* max legacy rate in 500 kb/s units */ - const u8 *ie; unsigned int est, tmp; - int snr = res->snr; - - if (res->est_throughput) - return; - - /* Get maximum legacy rate */ - rate = wpa_scan_get_max_rate(res); + const u8 *ie; /* Limit based on estimated SNR */ if (rate > 1 * 2 && snr < 1) @@ -2296,32 +2276,50 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, rate = 9 * 2; else if (rate > 12 * 2 && snr < 7) rate = 12 * 2; + else if (rate > 12 * 2 && snr < 8) + rate = 14 * 2; + else if (rate > 12 * 2 && snr < 9) + rate = 16 * 2; else if (rate > 18 * 2 && snr < 10) rate = 18 * 2; else if (rate > 24 * 2 && snr < 11) rate = 24 * 2; + else if (rate > 24 * 2 && snr < 12) + rate = 27 * 2; + else if (rate > 24 * 2 && snr < 13) + rate = 30 * 2; + else if (rate > 24 * 2 && snr < 14) + rate = 33 * 2; else if (rate > 36 * 2 && snr < 15) rate = 36 * 2; + else if (rate > 36 * 2 && snr < 16) + rate = 39 * 2; + else if (rate > 36 * 2 && snr < 17) + rate = 42 * 2; + else if (rate > 36 * 2 && snr < 18) + rate = 45 * 2; else if (rate > 48 * 2 && snr < 19) rate = 48 * 2; + else if (rate > 48 * 2 && snr < 20) + rate = 51 * 2; else if (rate > 54 * 2 && snr < 21) rate = 54 * 2; est = rate * 500; if (capab == CAPAB_HT || capab == CAPAB_HT40 || capab == CAPAB_VHT) { - ie = wpa_scan_get_ie(res, WLAN_EID_HT_CAP); + ie = get_ie(ies, ies_len, WLAN_EID_HT_CAP); if (ie) { - tmp = max_ht20_rate(snr); + tmp = max_ht20_rate(snr, 0); if (tmp > est) est = tmp; } } if (capab == CAPAB_HT40 || capab == CAPAB_VHT) { - ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION); + ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); if (ie && ie[1] >= 2 && (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { - tmp = max_ht40_rate(snr); + tmp = max_ht40_rate(snr, 0); if (tmp > est) est = tmp; } @@ -2329,22 +2327,22 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, if (capab == CAPAB_VHT) { /* Use +1 to assume VHT is always faster than HT */ - ie = wpa_scan_get_ie(res, WLAN_EID_VHT_CAP); + ie = get_ie(ies, ies_len, WLAN_EID_VHT_CAP); if (ie) { - tmp = max_ht20_rate(snr) + 1; + tmp = max_ht20_rate(snr, 1) + 1; if (tmp > est) est = tmp; - ie = wpa_scan_get_ie(res, WLAN_EID_HT_OPERATION); + ie = get_ie(ies, ies_len, WLAN_EID_HT_OPERATION); if (ie && ie[1] >= 2 && (ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)) { - tmp = max_ht40_rate(snr) + 1; + tmp = max_ht40_rate(snr, 1) + 1; if (tmp > est) est = tmp; } - ie = wpa_scan_get_ie(res, WLAN_EID_VHT_OPERATION); + ie = get_ie(ies, ies_len, WLAN_EID_VHT_OPERATION); if (ie && ie[1] >= 1 && (ie[2] & VHT_OPMODE_CHANNEL_WIDTH_MASK)) { tmp = max_vht80_rate(snr) + 1; @@ -2354,9 +2352,30 @@ void scan_est_throughput(struct wpa_supplicant *wpa_s, } } - /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ + return est; +} + + +void scan_est_throughput(struct wpa_supplicant *wpa_s, + struct wpa_scan_res *res) +{ + int rate; /* max legacy rate in 500 kb/s units */ + int snr = res->snr; + const u8 *ies = (const void *) (res + 1); + size_t ie_len = res->ie_len; + + if (res->est_throughput) + return; + + /* Get maximum legacy rate */ + rate = wpa_scan_get_max_rate(res); + + if (!ie_len) + ie_len = res->beacon_ie_len; + res->est_throughput = + wpas_get_est_tpt(wpa_s, ies, ie_len, rate, snr); - res->est_throughput = est; + /* TODO: channel utilization and AP load (e.g., from AP Beacon) */ } @@ -2611,8 +2630,8 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params) int wpas_start_pno(struct wpa_supplicant *wpa_s) { - int ret, prio; - size_t i, num_ssid, num_match_ssid; + int ret; + size_t prio, i, num_ssid, num_match_ssid; struct wpa_ssid *ssid; struct wpa_driver_scan_params params; struct sched_scan_plan scan_plan; diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h index 58caa781..c9ce2cec 100644 --- a/wpa_supplicant/scan.h +++ b/wpa_supplicant/scan.h @@ -9,6 +9,28 @@ #ifndef SCAN_H #define SCAN_H +/* + * Noise floor values to use when we have signal strength + * measurements, but no noise floor measurements. These values were + * measured in an office environment with many APs. + */ +#define DEFAULT_NOISE_FLOOR_2GHZ (-89) +#define DEFAULT_NOISE_FLOOR_5GHZ (-92) + +/* + * Channels with a great SNR can operate at full rate. What is a great SNR? + * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general + * rule of thumb is that any SNR above 20 is good." This one + * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23 + * recommends 25 as a minimum SNR for 54 Mbps data rate. The estimates used in + * scan_est_throughput() allow even smaller SNR values for the maximum rates + * (21 for 54 Mbps, 22 for VHT80 MCS9, 24 for HT40 and HT20 MCS7). Use 25 as a + * somewhat conservative value here. + */ +#define GREAT_SNR 25 + +#define IS_5GHZ(n) (n > 4000) + int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s); void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec); int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s, @@ -60,6 +82,9 @@ void filter_scan_res(struct wpa_supplicant *wpa_s, void scan_snr(struct wpa_scan_res *res); void scan_est_throughput(struct wpa_supplicant *wpa_s, struct wpa_scan_res *res); +unsigned int wpas_get_est_tpt(const struct wpa_supplicant *wpa_s, + const u8 *ies, size_t ies_len, int rate, + int snr); void wpa_supplicant_set_default_scan_ies(struct wpa_supplicant *wpa_s); #endif /* SCAN_H */ diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index 08d7e3ec..0cc81bf0 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -131,7 +131,10 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, return NULL; } - if (wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) { + if (ssid->sae_password_id && wpa_s->conf->sae_pwe != 3) + use_pt = 1; + + if (use_pt || wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) { bss = wpa_bss_get_bssid_latest(wpa_s, bssid); if (bss) { const u8 *rsnxe; @@ -142,7 +145,9 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, BIT(WLAN_RSNX_CAPAB_SAE_H2E)); } - if (wpa_s->conf->sae_pwe == 1 && !use_pt) { + if ((wpa_s->conf->sae_pwe == 1 || ssid->sae_password_id) && + wpa_s->conf->sae_pwe != 3 && + !use_pt) { wpa_printf(MSG_DEBUG, "SAE: Cannot use H2E with the selected AP"); return NULL; @@ -166,7 +171,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s, os_memcpy(wpa_s->sme.sae.tmp->bssid, bssid, ETH_ALEN); reuse_data: - len = wpa_s->sme.sae_token ? wpabuf_len(wpa_s->sme.sae_token) : 0; + len = wpa_s->sme.sae_token ? 3 + wpabuf_len(wpa_s->sme.sae_token) : 0; if (ssid->sae_password_id) len += 4 + os_strlen(ssid->sae_password_id); buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len); @@ -177,8 +182,11 @@ reuse_data: wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS); } - sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token, - ssid->sae_password_id); + if (sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token, + ssid->sae_password_id) < 0) { + wpabuf_free(buf); + return NULL; + } if (ret_use_pt) *ret_use_pt = use_pt; @@ -281,7 +289,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #if defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS) const u8 *md = NULL; #endif /* CONFIG_IEEE80211R || CONFIG_FILS */ - int i, bssid_changed; + int bssid_changed; struct wpabuf *resp = NULL; u8 ext_capab[18]; int ext_capab_len; @@ -291,6 +299,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #ifdef CONFIG_MBO const u8 *mbo_ie; #endif /* CONFIG_MBO */ + int omit_rsnxe = 0; if (bss == NULL) { wpa_msg(wpa_s, MSG_ERROR, "SME: No scan result available for " @@ -365,18 +374,18 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SAE */ - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ssid->wep_key_len[i]) - params.wep_key[i] = ssid->wep_key[i]; - params.wep_key_len[i] = ssid->wep_key_len[i]; - } - params.wep_tx_keyidx = ssid->wep_tx_keyidx; +#ifdef CONFIG_WEP + { + int i; - bssid_changed = !is_zero_ether_addr(wpa_s->bssid); - os_memset(wpa_s->bssid, 0, ETH_ALEN); - os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); - if (bssid_changed) - wpas_notify_bssid_changed(wpa_s); + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ssid->wep_key_len[i]) + params.wep_key[i] = ssid->wep_key[i]; + params.wep_key_len[i] = ssid->wep_key_len[i]; + } + params.wep_tx_keyidx = ssid->wep_tx_keyidx; + } +#endif /* CONFIG_WEP */ if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) || wpa_bss_get_ie(bss, WLAN_EID_RSN)) && @@ -498,6 +507,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, wpa_dbg(wpa_s, MSG_DEBUG, "SME: FT mobility domain %02x%02x", md[0], md[1]); + omit_rsnxe = !wpa_bss_get_ie(bss, WLAN_EID_RSNX); if (wpa_s->sme.assoc_req_ie_len + 5 < sizeof(wpa_s->sme.assoc_req_ie)) { struct rsn_mdie *mdie; @@ -570,7 +580,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, sme_auth_handle_rrm(wpa_s, bss); wpa_s->sme.assoc_req_ie_len += wpas_supp_op_class_ie( - wpa_s, ssid, bss->freq, + wpa_s, ssid, bss, wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len); @@ -606,7 +616,8 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #endif /* CONFIG_TESTING_OPTIONS */ if (wpa_s->rsnxe_len > 0 && wpa_s->rsnxe_len <= - sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) { + sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len && + !omit_rsnxe) { os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len); wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len; @@ -718,6 +729,12 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, } #endif /* CONFIG_SAE */ + bssid_changed = !is_zero_ether_addr(wpa_s->bssid); + os_memset(wpa_s->bssid, 0, ETH_ALEN); + os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN); + if (bssid_changed) + wpas_notify_bssid_changed(wpa_s); + old_ssid = wpa_s->current_ssid; wpa_s->current_ssid = ssid; wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); @@ -1010,7 +1027,7 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s, bssid, 1, wpa_s->sme.seq_num, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS); - wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0); + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); @@ -1080,7 +1097,7 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s, sme_external_auth_build_buf(buf, resp, wpa_s->own_addr, da, 2, wpa_s->sme.seq_num, WLAN_STATUS_SUCCESS); - wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0); + wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0, 0); wpabuf_free(resp); wpabuf_free(buf); } @@ -1177,11 +1194,16 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, (external || wpa_s->current_bss) && wpa_s->current_ssid) { int default_groups[] = { 19, 20, 21, 0 }; u16 group; + const u8 *token_pos; + size_t token_len; + int h2e = 0; groups = wpa_s->conf->sae_groups; if (!groups || groups[0] <= 0) groups = default_groups; + wpa_hexdump(MSG_DEBUG, "SME: SAE anti-clogging token request", + data, len); if (len < sizeof(le16)) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Too short SAE anti-clogging token request"); @@ -1199,8 +1221,30 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, return -1; } wpabuf_free(wpa_s->sme.sae_token); - wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16), - len - sizeof(le16)); + token_pos = data + sizeof(le16); + token_len = len - sizeof(le16); + if (wpa_s->sme.sae.tmp) + h2e = wpa_s->sme.sae.tmp->h2e; + if (h2e) { + if (token_len < 3) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Too short SAE anti-clogging token container"); + return -1; + } + if (token_pos[0] != WLAN_EID_EXTENSION || + token_pos[1] == 0 || + token_pos[1] > token_len - 2 || + token_pos[2] != WLAN_EID_EXT_ANTI_CLOGGING_TOKEN) { + wpa_dbg(wpa_s, MSG_DEBUG, + "SME: Invalid SAE anti-clogging token container header"); + return -1; + } + token_len = token_pos[1] - 1; + token_pos += 3; + } + wpa_s->sme.sae_token = wpabuf_alloc_copy(token_pos, token_len); + wpa_hexdump_buf(MSG_DEBUG, "SME: Requested anti-clogging token", + wpa_s->sme.sae_token); if (!external) sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 2); @@ -1260,6 +1304,19 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, "SAE: Ignore commit message while waiting for confirm"); return 0; } + if (wpa_s->sme.sae.tmp && wpa_s->sme.sae.tmp->h2e && + status_code == WLAN_STATUS_SUCCESS) { + wpa_printf(MSG_DEBUG, + "SAE: Unexpected use of status code 0 in SAE commit when H2E was expected"); + return -1; + } + if (wpa_s->sme.sae.tmp && !wpa_s->sme.sae.tmp->h2e && + status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) { + wpa_printf(MSG_DEBUG, + "SAE: Unexpected use of status code for H2E in SAE commit when H2E was not expected"); + return -1; + } + if (groups && groups[0] <= 0) groups = NULL; res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, @@ -1736,7 +1793,9 @@ void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode, #ifdef CONFIG_DPP2 if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP && wpa_s->current_ssid && - wpa_s->current_ssid->dpp_netaccesskey) { + wpa_s->current_ssid->dpp_netaccesskey && + wpa_s->current_ssid->dpp_pfs != 2 && + !wpa_s->current_ssid->dpp_pfs_fallback) { struct wpa_ssid *ssid = wpa_s->current_ssid; dpp_pfs_free(wpa_s->dpp_pfs); @@ -1810,6 +1869,9 @@ pfs_fail: params.vhtcaps_mask = &vhtcaps_mask; wpa_supplicant_apply_vht_overrides(wpa_s, wpa_s->current_ssid, ¶ms); #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + wpa_supplicant_apply_he_overrides(wpa_s, wpa_s->current_ssid, ¶ms); +#endif /* CONFIG_HE_OVERRIDES */ #ifdef CONFIG_IEEE80211R if (auth_type == WLAN_AUTH_FT && wpa_s->sme.ft_ies && get_ie(wpa_s->sme.ft_ies, wpa_s->sme.ft_ies_len, @@ -2308,7 +2370,7 @@ static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s, int start, end; mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, - HOSTAPD_MODE_IEEE80211G); + HOSTAPD_MODE_IEEE80211G, 0); if (mode == NULL) { /* No channels supported in this band - use empty list */ params->freqs = os_zalloc(sizeof(int)); @@ -2601,6 +2663,10 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, return; if (wpa_s->sme.sa_query_count > 0) return; +#ifdef CONFIG_TESTING_OPTIONS + if (wpa_s->disable_sa_query) + return; +#endif /* CONFIG_TESTING_OPTIONS */ os_get_reltime(&now); if (wpa_s->sme.last_unprot_disconnect.sec && diff --git a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in index 03ac5070..da69a870 100644 --- a/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in +++ b/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in @@ -12,4 +12,4 @@ Type=simple ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-%I.conf -Dnl80211 -i%I [Install] -Alias=multi-user.target.wants/wpa_supplicant-nl80211@%i.service +WantedBy=multi-user.target diff --git a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in index c8a744d6..ca3054bc 100644 --- a/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in +++ b/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in @@ -12,4 +12,4 @@ Type=simple ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-wired-%I.conf -Dwired -i%I [Install] -Alias=multi-user.target.wants/wpa_supplicant-wired@%i.service +WantedBy=multi-user.target diff --git a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in index 7788b380..55d2b9c8 100644 --- a/wpa_supplicant/systemd/wpa_supplicant.service.arg.in +++ b/wpa_supplicant/systemd/wpa_supplicant.service.arg.in @@ -12,4 +12,4 @@ Type=simple ExecStart=@BINDIR@/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I [Install] -Alias=multi-user.target.wants/wpa_supplicant@%i.service +WantedBy=multi-user.target diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 1c0399f4..2e09102d 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -280,6 +280,15 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, wpa_wnmsleep_install_key(wpa_s->wpa, WNM_SLEEP_SUBELEM_IGTK, ptr); ptr += 10 + WPA_IGTK_LEN; + } else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) { + if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) { + wpa_printf(MSG_DEBUG, + "WNM: Too short BIGTK subelem"); + break; + } + wpa_wnmsleep_install_key(wpa_s->wpa, + WNM_SLEEP_SUBELEM_BIGTK, ptr); + ptr += 10 + WPA_BIGTK_LEN; } else break; /* skip the loop */ } diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index a1b06151..07d5f315 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -502,6 +502,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos) "ignore_auth_resp", #endif /* CONFIG_TESTING_OPTIONS */ "relative_rssi", "relative_band_adjust", + "extended_key_id", }; int i, num_fields = ARRAY_SIZE(fields); @@ -593,7 +594,7 @@ static char ** wpa_cli_complete_get(const char *str, int pos) "tdls_external_control", "osu_dir", "wowlan_triggers", "p2p_search_delay", "mac_addr", "rand_addr_lifetime", "preassoc_mac_addr", "key_mgmt_offload", "passive_scan", - "reassoc_same_bss_optim" + "reassoc_same_bss_optim", "extended_key_id" }; int i, num_fields = ARRAY_SIZE(fields); @@ -1302,7 +1303,7 @@ static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc, char *argv[]) { - return wpa_ctrl_command(ctrl, "LIST_NETWORKS"); + return wpa_cli_cmd(ctrl, "LIST_NETWORKS", 0, argc, argv); } @@ -1441,6 +1442,7 @@ static const char *network_fields[] = { "dot11MeshHoldingTimeout", #endif /* CONFIG_MESH */ "wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid", + "wpa_deny_ptk0_rekey", "enable_edmg", "edmg_channel", #ifdef CONFIG_P2P "go_p2p_dev_addr", "p2p_client_list", "psk_list", @@ -1458,6 +1460,9 @@ static const char *network_fields[] = { "vht_tx_mcs_nss_3", "vht_tx_mcs_nss_4", "vht_tx_mcs_nss_5", "vht_tx_mcs_nss_6", "vht_tx_mcs_nss_7", "vht_tx_mcs_nss_8", #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + "disable_he", +#endif /* CONFIG_HE_OVERRIDES */ "ap_max_inactivity", "dtim_period", "beacon_int", #ifdef CONFIG_MACSEC "macsec_policy", @@ -1782,7 +1787,7 @@ static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[]) } if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) { - printf("Connected to interface '%s.\n", ctrl_ifname); + printf("Connected to interface '%s'.\n", ctrl_ifname); } else { printf("Could not connect to interface '%s' - re-trying\n", ctrl_ifname); @@ -4004,6 +4009,10 @@ static void wpa_cli_action_process(const char *msg) wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, WPS_EVENT_ACTIVE)) { wpa_cli_exec(action_file, ifname, pos); + } else if (str_starts(pos, WPS_EVENT_PIN_ACTIVE)) { + wpa_cli_exec(action_file, ifname, pos); + } else if (str_starts(pos, WPS_EVENT_CANCEL)) { + wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, WPS_EVENT_TIMEOUT)) { wpa_cli_exec(action_file, ifname, pos); } else if (str_starts(pos, WPS_EVENT_FAIL)) { diff --git a/wpa_supplicant/wpa_gui-qt4/peers.cpp b/wpa_supplicant/wpa_gui-qt4/peers.cpp index 3bcf2f51..0a0b3ffc 100644 --- a/wpa_supplicant/wpa_gui-qt4/peers.cpp +++ b/wpa_supplicant/wpa_gui-qt4/peers.cpp @@ -476,7 +476,9 @@ void Peers::add_stations() add_station(info); reply_len = sizeof(reply) - 1; - snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); + res = snprintf(cmd, sizeof(cmd), "STA-NEXT %s", reply); + if (res < 0 || (size_t) res >= sizeof(cmd)) + break; res = wpagui->ctrlRequest(cmd, reply, &reply_len); } while (res >= 0); } diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp index a0aa05ed..9404ab42 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp +++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp @@ -12,6 +12,8 @@ #include <cstdio> #include <unistd.h> +#include <chrono> +#include <thread> #include <QMessageBox> #include <QCloseEvent> #include <QImageReader> @@ -713,9 +715,22 @@ void WpaGui::updateNetworks() strstr(flags, "[DISABLED]") == NULL) first_active = networkSelect->count() - 1; - if (last) - break; start = end + 1; + if (*start && strchr(start, '\n')) + continue; + + /* avoid race conditions */ + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + QString cmd("LIST_NETWORKS LAST_ID="); + cmd.append(id); + if (ctrlRequest(cmd.toLocal8Bit().constData(), buf, &len) < 0) + break; + + buf[len] = '\0'; + start = strchr(buf, '\n'); + if (!start) + break; + start++; } if (networkSelect->count() > 1) diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c index f1973527..c5d71686 100644 --- a/wpa_supplicant/wpa_priv.c +++ b/wpa_supplicant/wpa_priv.c @@ -391,6 +391,7 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface, { struct privsep_cmd_set_key *params; int res; + struct wpa_driver_set_key_params p; if (iface->drv_priv == NULL || iface->driver->set_key == NULL) return; @@ -402,14 +403,19 @@ static void wpa_priv_cmd_set_key(struct wpa_priv_interface *iface, params = buf; - res = iface->driver->set_key(iface->ifname, iface->drv_priv, - params->alg, - params->addr, params->key_idx, - params->set_tx, - params->seq_len ? params->seq : NULL, - params->seq_len, - params->key_len ? params->key : NULL, - params->key_len); + os_memset(&p, 0, sizeof(p)); + p.ifname = iface->ifname; + p.alg = params->alg; + p.addr = params->addr; + p.key_idx = params->key_idx; + p.set_tx = params->set_tx; + p.seq = params->seq_len ? params->seq : NULL; + p.seq_len = params->seq_len; + p.key = params->key_len ? params->key : NULL; + p.key_len = params->key_len; + p.key_flag = params->key_flag; + + res = iface->driver->set_key(iface->drv_priv, &p); wpa_printf(MSG_DEBUG, "drv->set_key: res=%d", res); } @@ -1184,14 +1190,15 @@ static void wpa_priv_fd_workaround(void) static void usage(void) { - printf("wpa_priv v" VERSION_STR "\n" + printf("wpa_priv v%s\n" "Copyright (c) 2007-2017, Jouni Malinen <j@w1.fi> and " "contributors\n" "\n" "usage:\n" " wpa_priv [-Bdd] [-c<ctrl dir>] [-P<pid file>] " "<driver:ifname> \\\n" - " [driver:ifname ...]\n"); + " [driver:ifname ...]\n", + VERSION_STR); } diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 73e63ab5..d4294966 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -130,6 +130,7 @@ static void wpas_update_owe_connect_params(struct wpa_supplicant *wpa_s); #endif /* CONFIG_OWE */ +#ifdef CONFIG_WEP /* Configure default/group WEP keys for static WEP */ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -142,11 +143,15 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) set = 1; wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL, i, i == ssid->wep_tx_keyidx, NULL, 0, - ssid->wep_key[i], ssid->wep_key_len[i]); + ssid->wep_key[i], ssid->wep_key_len[i], + i == ssid->wep_tx_keyidx ? + KEY_FLAG_GROUP_RX_TX_DEFAULT : + KEY_FLAG_GROUP_RX_TX); } return set; } +#endif /* CONFIG_WEP */ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, @@ -200,7 +205,8 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, /* TODO: should actually remember the previously used seq#, both for TX * and RX from each STA.. */ - ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen); + ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen, + KEY_FLAG_GROUP_RX_TX_DEFAULT); os_memset(key, 0, sizeof(key)); return ret; } @@ -393,7 +399,9 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s) void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { +#ifdef CONFIG_WEP int i; +#endif /* CONFIG_WEP */ if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) wpa_s->key_mgmt = WPA_KEY_MGMT_WPS; @@ -411,6 +419,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, wpa_s->group_cipher = WPA_CIPHER_NONE; wpa_s->mgmt_group_cipher = 0; +#ifdef CONFIG_WEP for (i = 0; i < NUM_WEP_KEYS; i++) { if (ssid->wep_key_len[i] > 5) { wpa_s->pairwise_cipher = WPA_CIPHER_WEP104; @@ -422,6 +431,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s, break; } } +#endif /* CONFIG_WEP */ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt); @@ -477,6 +487,31 @@ void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s) } +void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx) +{ + struct wpa_supplicant *wpa_s = eloop_ctx; + + if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED) + return; + wpa_dbg(wpa_s, MSG_DEBUG, "Clear cached state on disabled interface"); + wpa_bss_flush(wpa_s); +} + + +#ifdef CONFIG_TESTING_OPTIONS +void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s) +{ + struct driver_signal_override *dso; + + while ((dso = dl_list_first(&wpa_s->drv_signal_override, + struct driver_signal_override, list))) { + dl_list_del(&dso->list); + os_free(dso); + } +} +#endif /* CONFIG_TESTING_OPTIONS */ + + static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) { int i; @@ -502,10 +537,13 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) wpa_s->last_assoc_req_wpa_ie = NULL; os_free(wpa_s->extra_sae_rejected_groups); wpa_s->extra_sae_rejected_groups = NULL; + wpabuf_free(wpa_s->rsne_override_eapol); + wpa_s->rsne_override_eapol = NULL; wpabuf_free(wpa_s->rsnxe_override_assoc); wpa_s->rsnxe_override_assoc = NULL; wpabuf_free(wpa_s->rsnxe_override_eapol); wpa_s->rsnxe_override_eapol = NULL; + wpas_clear_driver_signal_override(wpa_s); #endif /* CONFIG_TESTING_OPTIONS */ if (wpa_s->conf != NULL) { @@ -552,6 +590,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s) #endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */ eloop_cancel_timeout(wpas_network_reenabled, wpa_s, NULL); + eloop_cancel_timeout(wpas_clear_disabled_interface, wpa_s, NULL); wpas_wps_deinit(wpa_s); @@ -708,12 +747,17 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr) if (wpa_s->keys_cleared & BIT(i)) continue; wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0, - NULL, 0); + NULL, 0, KEY_FLAG_GROUP); } - if (!(wpa_s->keys_cleared & BIT(0)) && addr && + /* Pairwise Key ID 1 for Extended Key ID is tracked in bit 15 */ + if (~wpa_s->keys_cleared & (BIT(0) | BIT(15)) && addr && !is_zero_ether_addr(addr)) { - wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, - 0); + if (!(wpa_s->keys_cleared & BIT(0))) + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, + 0, NULL, 0, KEY_FLAG_PAIRWISE); + if (!(wpa_s->keys_cleared & BIT(15))) + wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 1, 0, NULL, + 0, NULL, 0, KEY_FLAG_PAIRWISE); /* MLME-SETPROTECTION.request(None) */ wpa_drv_mlme_setprotection( wpa_s, addr, @@ -1242,7 +1286,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, u8 *wpa_ie, size_t *wpa_ie_len) { struct wpa_ie_data ie; - int sel, proto; + int sel, proto, sae_pwe; const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen; if (bss) { @@ -1421,13 +1465,18 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #endif /* CONFIG_NO_WPA */ sel = ie.key_mgmt & ssid->key_mgmt; - wpa_dbg(wpa_s, MSG_DEBUG, - "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x", - ie.key_mgmt, ssid->key_mgmt, sel); #ifdef CONFIG_SAE if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE)) sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE); #endif /* CONFIG_SAE */ +#ifdef CONFIG_IEEE80211R + if (!(wpa_s->drv_flags & (WPA_DRIVER_FLAGS_SME | + WPA_DRIVER_FLAGS_UPDATE_FT_IES))) + sel &= ~WPA_KEY_MGMT_FT; +#endif /* CONFIG_IEEE80211R */ + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: AP key_mgmt 0x%x network profile key_mgmt 0x%x; available key_mgmt 0x%x", + ie.key_mgmt, ssid->key_mgmt, sel); if (0) { #ifdef CONFIG_IEEE80211R #ifdef CONFIG_SHA384 @@ -1587,7 +1636,34 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #ifdef CONFIG_OCV wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv); #endif /* CONFIG_OCV */ - wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe); + sae_pwe = wpa_s->conf->sae_pwe; + if (ssid->sae_password_id && sae_pwe != 3) + sae_pwe = 1; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, sae_pwe); + + /* Extended Key ID is only supported in infrastructure BSS so far */ + if (ssid->mode == WPAS_MODE_INFRA && wpa_s->conf->extended_key_id && + (ssid->proto & WPA_PROTO_RSN) && + ssid->pairwise_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_CCMP_256 | + WPA_CIPHER_GCMP | WPA_CIPHER_GCMP_256) && + (wpa_s->drv_flags & WPA_DRIVER_FLAGS_EXTENDED_KEY_ID)) { + int use_ext_key_id = 0; + + wpa_msg(wpa_s, MSG_DEBUG, + "WPA: Enable Extended Key ID support"); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, + wpa_s->conf->extended_key_id); + if (bss_rsn && + wpa_s->conf->extended_key_id && + wpa_s->pairwise_cipher != WPA_CIPHER_TKIP && + (ie.capabilities & WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST)) + use_ext_key_id = 1; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, + use_ext_key_id); + } else { + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_EXT_KEY_ID, 0); + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_USE_EXT_KEY_ID, 0); + } if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE"); @@ -1722,6 +1798,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, } else wpa_sm_set_pmk_from_pmksa(wpa_s->wpa); + if (ssid->mode != WPAS_MODE_IBSS && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED) && + (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_NEVER || + (ssid->wpa_deny_ptk0_rekey == PTK0_REKEY_ALLOW_LOCAL_OK && + !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAFE_PTK0_REKEYS)))) { + wpa_msg(wpa_s, MSG_INFO, + "Disable PTK0 rekey support - replaced with reconnect"); + wpa_s->deny_ptk0_rekey = 1; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 1); + } else { + wpa_s->deny_ptk0_rekey = 0; + wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_DENY_PTK0_REKEY, 0); + } + return 0; } @@ -1963,7 +2053,8 @@ static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid) if (!password) password = ssid->passphrase; - if (conf->sae_pwe == 0 || !password) { + if ((conf->sae_pwe == 0 && !ssid->sae_password_id) || !password || + conf->sae_pwe == 3) { /* PT derivation not needed */ sae_deinit_pt(ssid->pt); ssid->pt = NULL; @@ -2018,6 +2109,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, int rand_style; wpa_s->own_disconnect_req = 0; + wpa_s->own_reconnect_req = 0; /* * If we are starting a new connection, any previously pending EAPOL @@ -2031,6 +2123,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s, else rand_style = ssid->mac_addr; + wpa_s->multi_ap_ie = 0; wmm_ac_clear_saved_tspecs(wpa_s); wpa_s->reassoc_same_bss = 0; wpa_s->reassoc_same_ess = 0; @@ -2314,6 +2407,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, /* Allow HE on 2.4 GHz without VHT: see nl80211_put_freq_params() */ if (is_24ghz) freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported; +#ifdef CONFIG_HE_OVERRIDES + if (is_24ghz && ssid->disable_he) + freq->he_enabled = 0; +#endif /* CONFIG_HE_OVERRIDES */ /* Setup higher BW only for 5 GHz */ if (mode->mode != HOSTAPD_MODE_IEEE80211A) @@ -2336,8 +2433,10 @@ void ibss_mesh_setup_freq(struct wpa_supplicant *wpa_s, #ifdef CONFIG_HT_OVERRIDES if (ssid->disable_ht40) { +#ifdef CONFIG_VHT_OVERRIDES if (ssid->disable_vht) return; +#endif /* CONFIG_VHT_OVERRIDES */ goto skip_ht40; } #endif /* CONFIG_HT_OVERRIDES */ @@ -2434,8 +2533,8 @@ skip_ht40: if (!vht_freq.vht_enabled) return; - /* Enable HE for VHT */ - vht_freq.he_enabled = mode->he_capab[ieee80211_mode].he_supported; + /* Enable HE with VHT for 5 GHz */ + freq->he_enabled = mode->he_capab[ieee80211_mode].he_supported; /* setup center_freq1, bandwidth */ for (j = 0; j < ARRAY_SIZE(vht80); j++) { @@ -2510,6 +2609,12 @@ skip_ht40: #endif /* CONFIG_HT_OVERRIDES */ } +#ifdef CONFIG_HE_OVERRIDES + if (ssid->disable_he) { + vht_freq.he_enabled = 0; + freq->he_enabled = 0; + } +#endif /* CONFIG_HE_OVERRIDES */ if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq, freq->channel, ssid->enable_edmg, ssid->edmg_channel, freq->ht_enabled, @@ -2828,7 +2933,7 @@ static u8 * wpas_populate_assoc_ies( #endif /* CONFIG_P2P */ if (bss) { - wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss->freq, + wpa_ie_len += wpas_supp_op_class_ie(wpa_s, ssid, bss, wpa_ie + wpa_ie_len, max_wpa_ie_len - wpa_ie_len); @@ -2977,7 +3082,8 @@ static u8 * wpas_populate_assoc_ies( #ifdef CONFIG_DPP2 if (wpa_sm_get_key_mgmt(wpa_s->wpa) == WPA_KEY_MGMT_DPP && - ssid->dpp_netaccesskey) { + ssid->dpp_netaccesskey && + ssid->dpp_pfs != 2 && !ssid->dpp_pfs_fallback) { dpp_pfs_free(wpa_s->dpp_pfs); wpa_s->dpp_pfs = dpp_pfs_init(ssid->dpp_netaccesskey, ssid->dpp_netaccesskey_len); @@ -3216,7 +3322,7 @@ get_supported_edmg(struct wpa_supplicant *wpa_s, if (hw_mode == NUM_HOSTAPD_MODES) goto fail; - mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode); + mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode, 0); if (!mode) goto fail; @@ -3265,10 +3371,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) struct wpa_supplicant *wpa_s = work->wpa_s; u8 *wpa_ie; const u8 *edmg_ie_oper; - int use_crypt, ret, i, bssid_changed; + int use_crypt, ret, bssid_changed; unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt; struct wpa_driver_associate_params params; +#if defined(CONFIG_WEP) || defined(IEEE8021X_EAPOL) int wep_keys_set = 0; +#endif /* CONFIG_WEP || IEEE8021X_EAPOL */ int assoc_failed = 0; struct wpa_ssid *old_ssid; u8 prev_bssid[ETH_ALEN]; @@ -3375,10 +3483,12 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) { if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) use_crypt = 0; +#ifdef CONFIG_WEP if (wpa_set_wep_keys(wpa_s, ssid)) { use_crypt = 1; wep_keys_set = 1; } +#endif /* CONFIG_WEP */ } if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) use_crypt = 0; @@ -3523,12 +3633,18 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) wpa_s->auth_alg = params.auth_alg; params.mode = ssid->mode; params.bg_scan_period = ssid->bg_scan_period; - for (i = 0; i < NUM_WEP_KEYS; i++) { - if (ssid->wep_key_len[i]) - params.wep_key[i] = ssid->wep_key[i]; - params.wep_key_len[i] = ssid->wep_key_len[i]; +#ifdef CONFIG_WEP + { + int i; + + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (ssid->wep_key_len[i]) + params.wep_key[i] = ssid->wep_key[i]; + params.wep_key_len[i] = ssid->wep_key_len[i]; + } + params.wep_tx_keyidx = ssid->wep_tx_keyidx; } - params.wep_tx_keyidx = ssid->wep_tx_keyidx; +#endif /* CONFIG_WEP */ if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE_PSK) && (params.key_mgmt_suite == WPA_KEY_MGMT_PSK || @@ -3605,6 +3721,9 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.vhtcaps_mask = &vhtcaps_mask; wpa_supplicant_apply_vht_overrides(wpa_s, ssid, ¶ms); #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES + wpa_supplicant_apply_he_overrides(wpa_s, ssid, ¶ms); +#endif /* CONFIG_HE_OVERRIDES */ #ifdef CONFIG_P2P /* @@ -3686,11 +3805,13 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0); } +#ifdef CONFIG_WEP if (wep_keys_set && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC)) { /* Set static WEP keys again */ wpa_set_wep_keys(wpa_s, ssid); } +#endif /* CONFIG_WEP */ if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) { /* @@ -3804,6 +3925,15 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, wpa_supplicant_clear_connection(wpa_s, addr); } + +void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s) +{ + wpa_s->own_reconnect_req = 1; + wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_UNSPECIFIED); + +} + + static void wpa_supplicant_enable_one_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { @@ -4791,6 +4921,9 @@ wpa_supplicant_alloc(struct wpa_supplicant *parent) dl_list_init(&wpa_s->bss_tmp_disallowed); dl_list_init(&wpa_s->fils_hlp_req); +#ifdef CONFIG_TESTING_OPTIONS + dl_list_init(&wpa_s->drv_signal_override); +#endif /* CONFIG_TESTING_OPTIONS */ return wpa_s; } @@ -5153,6 +5286,19 @@ void wpa_supplicant_apply_vht_overrides( #endif /* CONFIG_VHT_OVERRIDES */ +#ifdef CONFIG_HE_OVERRIDES +void wpa_supplicant_apply_he_overrides( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_driver_associate_params *params) +{ + if (!ssid) + return; + + params->disable_he = ssid->disable_he; +} +#endif /* CONFIG_HE_OVERRIDES */ + + static int pcsc_reader_init(struct wpa_supplicant *wpa_s) { #ifdef PCSC_FUNCS @@ -6095,7 +6241,6 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s, wpa_s->drv_capa_known = 1; wpa_s->drv_flags = capa.flags; wpa_s->drv_enc = capa.enc; - wpa_s->drv_smps_modes = capa.smps_modes; wpa_s->drv_rrm_flags = capa.rrm_flags; wpa_s->probe_resp_offloads = capa.probe_resp_offloads; wpa_s->max_scan_ssids = capa.max_scan_ssids; @@ -6319,11 +6464,17 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s, wpa_s->disconnected = 1; if (wpa_s->drv_priv) { - wpa_supplicant_deauthenticate(wpa_s, - WLAN_REASON_DEAUTH_LEAVING); + /* Don't deauthenticate if WoWLAN is enabled */ + if (!wpa_drv_get_wowlan(wpa_s)) { + wpa_supplicant_deauthenticate( + wpa_s, WLAN_REASON_DEAUTH_LEAVING); - wpa_drv_set_countermeasures(wpa_s, 0); - wpa_clear_keys(wpa_s, NULL); + wpa_drv_set_countermeasures(wpa_s, 0); + wpa_clear_keys(wpa_s, NULL); + } else { + wpa_msg(wpa_s, MSG_INFO, + "Do not deauthenticate as part of interface deinit since WoWLAN is enabled"); + } } wpa_supplicant_cleanup(wpa_s); @@ -6704,7 +6855,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) if (params->wpa_debug_file_path) wpa_debug_open_file(params->wpa_debug_file_path); - else + if (!params->wpa_debug_file_path && !params->wpa_debug_syslog) wpa_debug_setup_stdout(); if (params->wpa_debug_syslog) wpa_debug_open_syslog(); @@ -6772,7 +6923,7 @@ struct wpa_global * wpa_supplicant_init(struct wpa_params *params) wpa_debug_timestamp = global->params.wpa_debug_timestamp = params->wpa_debug_timestamp; - wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR); + wpa_printf(MSG_DEBUG, "wpa_supplicant v%s", VERSION_STR); if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); @@ -7036,7 +7187,7 @@ void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid) * There is no point in blacklisting the AP if this event is * generated based on local request to disconnect. */ - if (wpa_s->own_disconnect_req) { + if (wpa_s->own_disconnect_req || wpa_s->own_reconnect_req) { wpa_s->own_disconnect_req = 0; wpa_dbg(wpa_s, MSG_DEBUG, "Ignore connection failure due to local request to disconnect"); @@ -7301,8 +7452,10 @@ int wpa_supplicant_ctrl_rsp_handle(struct wpa_supplicant *wpa_s, int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) { +#ifdef CONFIG_WEP int i; unsigned int drv_enc; +#endif /* CONFIG_WEP */ if (wpa_s->p2p_mgmt) return 1; /* no normal network profiles on p2p_mgmt interface */ @@ -7313,6 +7466,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) if (ssid->disabled) return 1; +#ifdef CONFIG_WEP if (wpa_s->drv_capa_known) drv_enc = wpa_s->drv_enc; else @@ -7330,6 +7484,7 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) continue; return 1; /* invalid WEP key */ } +#endif /* CONFIG_WEP */ if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set && (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk && @@ -7727,12 +7882,17 @@ int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame, struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, - u16 num_modes, enum hostapd_hw_mode mode) + u16 num_modes, enum hostapd_hw_mode mode, + int is_6ghz) { u16 i; for (i = 0; i < num_modes; i++) { - if (modes[i].mode == mode) + if (modes[i].mode != mode || + !modes[i].num_channels || !modes[i].channels) + continue; + if ((!is_6ghz && !is_6ghz_freq(modes[i].channels[0].freq)) || + (is_6ghz && is_6ghz_freq(modes[i].channels[0].freq))) return &modes[i]; } @@ -7909,3 +8069,87 @@ int wpas_disable_mac_addr_randomization(struct wpa_supplicant *wpa_s, return 0; } + + +int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s, + struct wpa_signal_info *si) +{ + int res; + + if (!wpa_s->driver->signal_poll) + return -1; + + res = wpa_s->driver->signal_poll(wpa_s->drv_priv, si); + +#ifdef CONFIG_TESTING_OPTIONS + if (res == 0) { + struct driver_signal_override *dso; + + dl_list_for_each(dso, &wpa_s->drv_signal_override, + struct driver_signal_override, list) { + if (os_memcmp(wpa_s->bssid, dso->bssid, + ETH_ALEN) != 0) + continue; + wpa_printf(MSG_DEBUG, + "Override driver signal_poll information: current_signal: %d->%d avg_signal: %d->%d avg_beacon_signal: %d->%d current_noise: %d->%d", + si->current_signal, + dso->si_current_signal, + si->avg_signal, + dso->si_avg_signal, + si->avg_beacon_signal, + dso->si_avg_beacon_signal, + si->current_noise, + dso->si_current_noise); + si->current_signal = dso->si_current_signal; + si->avg_signal = dso->si_avg_signal; + si->avg_beacon_signal = dso->si_avg_beacon_signal; + si->current_noise = dso->si_current_noise; + break; + } + } +#endif /* CONFIG_TESTING_OPTIONS */ + + return res; +} + + +struct wpa_scan_results * +wpa_drv_get_scan_results2(struct wpa_supplicant *wpa_s) +{ + struct wpa_scan_results *scan_res; +#ifdef CONFIG_TESTING_OPTIONS + size_t idx; +#endif /* CONFIG_TESTING_OPTIONS */ + + if (!wpa_s->driver->get_scan_results2) + return NULL; + + scan_res = wpa_s->driver->get_scan_results2(wpa_s->drv_priv); + +#ifdef CONFIG_TESTING_OPTIONS + for (idx = 0; scan_res && idx < scan_res->num; idx++) { + struct driver_signal_override *dso; + struct wpa_scan_res *res = scan_res->res[idx]; + + dl_list_for_each(dso, &wpa_s->drv_signal_override, + struct driver_signal_override, list) { + if (os_memcmp(res->bssid, dso->bssid, ETH_ALEN) != 0) + continue; + wpa_printf(MSG_DEBUG, + "Override driver scan signal level %d->%d for " + MACSTR, + res->level, dso->scan_level, + MAC2STR(res->bssid)); + res->flags |= WPA_SCAN_QUAL_INVALID; + if (dso->scan_level < 0) + res->flags |= WPA_SCAN_LEVEL_DBM; + else + res->flags &= ~WPA_SCAN_LEVEL_DBM; + res->level = dso->scan_level; + break; + } + } +#endif /* CONFIG_TESTING_OPTIONS */ + + return scan_res; +} diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index 328f91a9..f242c3a9 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -94,11 +94,8 @@ eapol_version=1 # 1: wpa_supplicant initiates scanning and AP selection; if no APs matching to # the currently enabled networks are found, a new network (IBSS or AP mode # operation) may be initialized (if configured) (default) -# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association -# parameters (e.g., WPA IE generation); this mode can also be used with -# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with -# APs (i.e., external program needs to control association). This mode must -# also be used when using wired Ethernet drivers (including MACsec). +# 0: This mode must only be used when using wired Ethernet drivers +# (including MACsec). # 2: like 0, but associate with APs using security policy and SSID (but not # BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to # enable operation with hidden SSIDs and optimized roaming; in this mode, @@ -106,8 +103,8 @@ eapol_version=1 # the driver reports successful association; each network block should have # explicit security policy (i.e., only one option in the lists) for # key_mgmt, pairwise, group, proto variables -# Note: ap_scan=2 should not be used with the nl80211 driver interface (the -# current Linux interface). ap_scan=1 is optimized work working with nl80211. +# Note: ap_scan=0/2 should not be used with the nl80211 driver interface (the +# current Linux interface). ap_scan=1 is the only option working with nl80211. # For finding networks using hidden SSID, scan_ssid=1 in the network block can # be used with nl80211. # When using IBSS or AP mode, ap_scan=2 mode can force the new network to be @@ -426,11 +423,13 @@ fast_reauth=1 #sae_groups=19 20 21 # SAE mechanism for PWE derivation -# 0 = hunting-and-pecking loop only (default) -# 1 = hash-to-element only +# 0 = hunting-and-pecking loop only (default without password identifier) +# 1 = hash-to-element only (default with password identifier) # 2 = both hunting-and-pecking loop and hash-to-element enabled # Note: The default value is likely to change from 0 to 2 once the new # hash-to-element mechanism has received more interoperability testing. +# When using SAE password identifier, the hash-to-element mechanism is used +# regardless of the sae_pwe parameter value. #sae_pwe=0 # Default value for DTIM period (if not overridden in network block) @@ -803,6 +802,11 @@ fast_reauth=1 # Set BIT(1) to Enable OCE in STA-CFON mode #oce=1 +# Extended Key ID support for Individually Addressed frames +# 0 = force off: Do not use Extended Key ID (default) +# 1 = auto: Activate Extended Key ID support if the driver supports it +#extended_key_id=0 + # network block # # Each network (usually AP's sharing the same SSID) is configured as a separate @@ -1102,6 +1106,18 @@ fast_reauth=1 # wpa_ptk_rekey: Maximum lifetime for PTK in seconds. This can be used to # enforce rekeying of PTK to mitigate some attacks against TKIP deficiencies. # +# wpa_deny_ptk0_rekey: Workaround for PTK rekey issues +# PTK0 rekeys (using only one Key ID value for pairwise keys) can degrade the +# security and stability with some cards. +# To avoid the issues wpa_supplicant can replace those PTK rekeys (including +# EAP reauthentications) with fast reconnects. +# +# Available options: +# 0 = always rekey when configured/instructed (default) +# 1 = only rekey when the local driver is explicitly indicating it can perform +# this operation without issues +# 2 = never allow problematic PTK0 rekeys +# # group_rekey: Group rekeying time in seconds. This value, if non-zero, is used # as the dot11RSNAConfigGroupRekeyTime parameter when operating in # Authenticator role in IBSS, or in AP and mesh modes. @@ -1445,6 +1461,12 @@ fast_reauth=1 # 1-65535 = DH Group to use for FILS PFS #fils_dh_group=0 +# DPP PFS +# 0: allow PFS to be used or not used (default) +# 1: require PFS to be used (note: not compatible with DPP R1) +# 2: do not allow PFS to be used +#dpp_pfs=0 + # MAC address policy # 0 = use permanent MAC address # 1 = use random MAC address for each ESS connection diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 967298bf..8b1d0d04 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -47,6 +47,9 @@ struct ctrl_iface_global_priv; struct wpas_dbus_priv; struct wpas_hidl_priv; +/* How many seconds to consider old scan results valid for association. */ +#define SCAN_RES_VALID_FOR_CONNECT 5 + /** * struct wpa_interface - Parameters for wpa_supplicant_add_iface() */ @@ -280,6 +283,7 @@ struct wpa_global { struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */ int p2p_disabled; int cross_connection; + int p2p_long_listen; /* remaining time in long Listen state in ms */ struct wpa_freq_range_list p2p_disallow_freq; struct wpa_freq_range_list p2p_go_avoid_freq; enum wpa_conc_pref { @@ -477,6 +481,16 @@ struct fils_hlp_req { struct wpabuf *pkt; }; +struct driver_signal_override { + struct dl_list list; + u8 bssid[ETH_ALEN]; + int si_current_signal; + int si_avg_signal; + int si_avg_beacon_signal; + int si_current_noise; + int scan_level; +}; + /** * struct wpa_supplicant - Internal data for wpa_supplicant interface * @@ -540,6 +554,7 @@ struct wpa_supplicant { /* Selected configuration (based on Beacon/ProbeResp WPA IE) */ int pairwise_cipher; + int deny_ptk0_rekey; int group_cipher; int key_mgmt; int wpa_proto; @@ -592,8 +607,8 @@ struct wpa_supplicant { * results. */ struct wpa_bss **last_scan_res; - unsigned int last_scan_res_used; - unsigned int last_scan_res_size; + size_t last_scan_res_used; + size_t last_scan_res_size; struct os_reltime last_scan; const struct wpa_driver_ops *driver; @@ -700,6 +715,7 @@ struct wpa_supplicant { int scan_id[MAX_SCAN_ID]; unsigned int scan_id_count; u8 next_scan_bssid[ETH_ALEN]; + unsigned int next_scan_bssid_wildcard_ssid:1; struct wpa_ssid_value *ssids_from_scan_req; unsigned int num_ssids_from_scan_req; @@ -710,7 +726,6 @@ struct wpa_supplicant { u64 drv_flags; unsigned int drv_enc; - unsigned int drv_smps_modes; unsigned int drv_rrm_flags; /* @@ -880,7 +895,6 @@ struct wpa_supplicant { P2P_GROUP_INTERFACE_CLIENT } p2p_group_interface; struct p2p_group *p2p_group; - int p2p_long_listen; /* remaining time in long Listen state in ms */ char p2p_pin[10]; int p2p_wps_method; u8 p2p_auth_invite[ETH_ALEN]; @@ -1064,6 +1078,7 @@ struct wpa_supplicant { unsigned int wmm_ac_supported:1; unsigned int ext_work_in_progress:1; unsigned int own_disconnect_req:1; + unsigned int own_reconnect_req:1; unsigned int ignore_post_flush_scan_res:1; #define MAC_ADDR_RAND_SCAN BIT(0) @@ -1126,6 +1141,7 @@ struct wpa_supplicant { unsigned int p2p_go_csa_on_inv:1; unsigned int ignore_auth_resp:1; unsigned int ignore_assoc_disallow:1; + unsigned int disable_sa_query:1; unsigned int testing_resend_assoc:1; unsigned int ignore_sae_h2e_only:1; struct wpabuf *sae_commit_override; @@ -1136,8 +1152,10 @@ struct wpa_supplicant { size_t last_tk_len; struct wpabuf *last_assoc_req_wpa_ie; int *extra_sae_rejected_groups; + struct wpabuf *rsne_override_eapol; struct wpabuf *rsnxe_override_assoc; struct wpabuf *rsnxe_override_eapol; + struct dl_list drv_signal_override; #endif /* CONFIG_TESTING_OPTIONS */ struct wmm_ac_assoc_data *wmm_ac_assoc_info; @@ -1264,6 +1282,15 @@ struct wpa_supplicant { size_t dpp_last_ssid_len; #ifdef CONFIG_DPP2 struct dpp_pfs *dpp_pfs; + int dpp_pfs_fallback; + struct wpabuf *dpp_presence_announcement; + struct dpp_bootstrap_info *dpp_chirp_bi; + int dpp_chirp_freq; + int *dpp_chirp_freqs; + int dpp_chirp_iter; + int dpp_chirp_round; + int dpp_chirp_scan_done; + int dpp_chirp_listen; #endif /* CONFIG_DPP2 */ #ifdef CONFIG_TESTING_OPTIONS char *dpp_config_obj_override; @@ -1280,6 +1307,9 @@ struct wpa_supplicant { unsigned int enabled_4addr_mode:1; unsigned int multi_bss_support:1; unsigned int drv_authorized_port:1; + unsigned int multi_ap_ie:1; + unsigned int multi_ap_backhaul:1; + unsigned int multi_ap_fronthaul:1; }; @@ -1290,6 +1320,9 @@ void wpa_supplicant_apply_ht_overrides( void wpa_supplicant_apply_vht_overrides( struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, struct wpa_driver_associate_params *params); +void wpa_supplicant_apply_he_overrides( + struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, + struct wpa_driver_associate_params *params); int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s, @@ -1321,6 +1354,7 @@ const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s); void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s); void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason_code); +void wpa_supplicant_reconnect(struct wpa_supplicant *wpa_s); struct wpa_ssid * wpa_supplicant_add_network(struct wpa_supplicant *wpa_s); int wpa_supplicant_remove_network(struct wpa_supplicant *wpa_s, int id); @@ -1386,6 +1420,8 @@ int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style); int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s); void add_freq(int *freqs, int *num_freqs, int freq); +int wpas_get_op_chan_phy(int freq, const u8 *ies, size_t ies_len, + u8 *op_class, u8 *chan, u8 *phy_type); void wpas_rrm_reset(struct wpa_supplicant *wpa_s); void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s, const u8 *report, size_t report_len); @@ -1408,6 +1444,7 @@ int wpas_beacon_rep_scan_process(struct wpa_supplicant *wpa_s, struct scan_info *info); void wpas_clear_beacon_rep_data(struct wpa_supplicant *wpa_s); void wpas_flush_fils_hlp_req(struct wpa_supplicant *wpa_s); +void wpas_clear_disabled_interface(void *eloop_ctx, void *timeout_ctx); /* MBO functions */ @@ -1444,7 +1481,7 @@ enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class, u8 channel, u8 bw); size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid, - int freq, u8 *pos, size_t len); + struct wpa_bss *bss, u8 *pos, size_t len); int * wpas_supp_op_classes(struct wpa_supplicant *wpa_s); int wpas_enable_mac_addr_randomization(struct wpa_supplicant *wpa_s, @@ -1567,7 +1604,8 @@ void fst_wpa_supplicant_fill_iface_obj(struct wpa_supplicant *wpa_s, int wpas_sched_scan_plans_set(struct wpa_supplicant *wpa_s, const char *cmd); struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes, - u16 num_modes, enum hostapd_hw_mode mode); + u16 num_modes, enum hostapd_hw_mode mode, + int is_6ghz); void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid, unsigned int sec, int rssi_threshold); @@ -1588,4 +1626,6 @@ int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s, int wpa_is_fils_supported(struct wpa_supplicant *wpa_s); int wpa_is_fils_sk_pfs_supported(struct wpa_supplicant *wpa_s); +void wpas_clear_driver_signal_override(struct wpa_supplicant *wpa_s); + #endif /* WPA_SUPPLICANT_I_H */ diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index d80b8f28..6bd271e1 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -112,6 +112,14 @@ static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, } #endif /* CONFIG_TESTING_OPTIONS */ + if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_CONTROL_PORT) { + int encrypt = wpa_s->wpa && + wpa_sm_has_ptk_installed(wpa_s->wpa); + + return wpa_drv_tx_control_port(wpa_s, dest, proto, buf, len, + !encrypt); + } + if (wpa_s->l2) { return l2_packet_send(wpa_s->l2, dest, proto, buf, len); } @@ -219,6 +227,7 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf, } +#ifdef CONFIG_WEP /** * wpa_eapol_set_wep_key - set WEP key for the driver * @ctx: Pointer to wpa_supplicant data (wpa_s) @@ -242,8 +251,11 @@ static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx, } return wpa_drv_set_key(wpa_s, WPA_ALG_WEP, unicast ? wpa_s->bssid : NULL, - keyidx, unicast, NULL, 0, key, keylen); + keyidx, unicast, NULL, 0, key, keylen, + unicast ? KEY_FLAG_PAIRWISE_RX_TX : + KEY_FLAG_GROUP_RX_TX_DEFAULT); } +#endif /* CONFIG_WEP */ static void wpa_supplicant_aborted_cached(void *ctx) @@ -340,8 +352,8 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way " "handshake", pmk, pmk_len); - if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk, - pmk_len)) { + if (wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, NULL, 0, pmk, + pmk_len, KEY_FLAG_PMK)) { wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver"); } @@ -386,6 +398,13 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s) curr = bss; break; } +#ifdef CONFIG_OWE + if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_OWE) && + (bss->flags & WPA_BSS_OWE_TRANSITION)) { + curr = bss; + break; + } +#endif /* CONFIG_OWE */ } if (curr) { @@ -476,6 +495,12 @@ static void _wpa_supplicant_deauthenticate(void *wpa_s, u16 reason_code) } +static void _wpa_supplicant_reconnect(void *wpa_s) +{ + wpa_supplicant_reconnect(wpa_s); +} + + static void * wpa_supplicant_get_network_ctx(void *wpa_s) { return wpa_supplicant_get_ssid(wpa_s); @@ -492,7 +517,8 @@ static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid) static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg, const u8 *addr, int key_idx, int set_tx, const u8 *seq, size_t seq_len, - const u8 *key, size_t key_len) + const u8 *key, size_t key_len, + enum key_flag key_flag) { struct wpa_supplicant *wpa_s = _wpa_s; if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) { @@ -507,7 +533,8 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg, } #endif /* CONFIG_TESTING_GET_GTK */ #ifdef CONFIG_TESTING_OPTIONS - if (addr && !is_broadcast_ether_addr(addr)) { + if (addr && !is_broadcast_ether_addr(addr) && + !(key_flag & KEY_FLAG_MODIFY)) { wpa_s->last_tk_alg = alg; os_memcpy(wpa_s->last_tk_addr, addr, ETH_ALEN); wpa_s->last_tk_key_idx = key_idx; @@ -517,7 +544,7 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg, } #endif /* CONFIG_TESTING_OPTIONS */ return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len, - key, key_len); + key, key_len, key_flag); } @@ -547,7 +574,8 @@ static struct wpa_ssid * wpas_get_network_ctx(struct wpa_supplicant *wpa_s, static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx, const u8 *bssid, const u8 *pmkid, const u8 *fils_cache_id, - const u8 *pmk, size_t pmk_len) + const u8 *pmk, size_t pmk_len, + u32 pmk_lifetime, u8 pmk_reauth_threshold) { struct wpa_supplicant *wpa_s = _wpa_s; struct wpa_ssid *ssid; @@ -569,6 +597,8 @@ static int wpa_supplicant_add_pmkid(void *_wpa_s, void *network_ctx, params.pmkid = pmkid; params.pmk = pmk; params.pmk_len = pmk_len; + params.pmk_lifetime = pmk_lifetime; + params.pmk_reauth_threshold = pmk_reauth_threshold; return wpa_drv_add_pmkid(wpa_s, ¶ms); } @@ -1047,6 +1077,21 @@ static void wpa_supplicant_eap_error_cb(void *ctx, int error_code) } +static int wpa_supplicant_eap_auth_start_cb(void *ctx) +{ + struct wpa_supplicant *wpa_s = ctx; + + if (!wpa_s->new_connection && wpa_s->deny_ptk0_rekey && + !wpa_sm_ext_key_id_active(wpa_s->wpa)) { + wpa_msg(wpa_s, MSG_INFO, + "WPA: PTK0 rekey not allowed, reconnecting"); + wpa_supplicant_reconnect(wpa_s); + return -1; + } + return 0; +} + + static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len) { struct wpa_supplicant *wpa_s = ctx; @@ -1102,7 +1147,9 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->preauth = 0; ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done; ctx->eapol_send = wpa_supplicant_eapol_send; +#ifdef CONFIG_WEP ctx->set_wep_key = wpa_eapol_set_wep_key; +#endif /* CONFIG_WEP */ #ifndef CONFIG_NO_CONFIG_BLOBS ctx->set_config_blob = wpa_supplicant_set_config_blob; ctx->get_config_blob = wpa_supplicant_get_config_blob; @@ -1125,6 +1172,7 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) ctx->cert_in_cb = wpa_s->conf->cert_in_cb; ctx->status_cb = wpa_supplicant_status_cb; ctx->eap_error_cb = wpa_supplicant_eap_error_cb; + ctx->confirm_auth_cb = wpa_supplicant_eap_auth_start_cb; ctx->set_anon_id = wpa_supplicant_set_anon_id; ctx->cb_ctx = wpa_s; wpa_s->eapol = eapol_sm_init(ctx); @@ -1160,8 +1208,8 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk, if (wpa_s->conf->key_mgmt_offload && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) - return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, - NULL, 0, pmk, pmk_len); + return wpa_drv_set_key(wpa_s, 0, NULL, 0, 0, + NULL, 0, pmk, pmk_len, KEY_FLAG_PMK); else return 0; } @@ -1193,6 +1241,73 @@ static int wpa_supplicant_channel_info(void *_wpa_s, return wpa_drv_channel_info(wpa_s, ci); } + +static void disable_wpa_wpa2(struct wpa_ssid *ssid) +{ + ssid->proto &= ~WPA_PROTO_WPA; + ssid->proto |= WPA_PROTO_RSN; + ssid->key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256); + ssid->group_cipher &= ~WPA_CIPHER_TKIP; + if (!(ssid->group_cipher & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256))) + ssid->group_cipher |= WPA_CIPHER_CCMP; + ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED; +} + + +static void wpa_supplicant_transition_disable(void *_wpa_s, u8 bitmap) +{ + struct wpa_supplicant *wpa_s = _wpa_s; + struct wpa_ssid *ssid; + int changed = 0; + + wpa_msg(wpa_s, MSG_INFO, TRANSITION_DISABLE "%02x", bitmap); + + ssid = wpa_s->current_ssid; + if (!ssid) + return; + + if ((bitmap & TRANSITION_DISABLE_WPA3_PERSONAL) && + wpa_key_mgmt_sae(wpa_s->key_mgmt) && + (ssid->key_mgmt & (WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE)) && + (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED || + (ssid->group_cipher & WPA_CIPHER_TKIP))) { + wpa_printf(MSG_DEBUG, + "WPA3-Personal transition mode disabled based on AP notification"); + disable_wpa_wpa2(ssid); + changed = 1; + } + + if ((bitmap & TRANSITION_DISABLE_WPA3_ENTERPRISE) && + wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) && + (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | + WPA_KEY_MGMT_FT_IEEE8021X | + WPA_KEY_MGMT_IEEE8021X_SHA256)) && + (ssid->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED || + (ssid->group_cipher & WPA_CIPHER_TKIP))) { + disable_wpa_wpa2(ssid); + changed = 1; + } + + if ((bitmap & TRANSITION_DISABLE_ENHANCED_OPEN) && + wpa_s->key_mgmt == WPA_KEY_MGMT_OWE && + (ssid->key_mgmt & WPA_KEY_MGMT_OWE) && + !ssid->owe_only) { + ssid->owe_only = 1; + changed = 1; + } + + if (!changed) + return; + +#ifndef CONFIG_NO_CONFIG_WRITE + if (wpa_s->conf->update_config && + wpa_config_write(wpa_s->confname, wpa_s->conf)) + wpa_printf(MSG_DEBUG, "Failed to update configuration"); +#endif /* CONFIG_NO_CONFIG_WRITE */ +} + #endif /* CONFIG_NO_WPA */ @@ -1211,6 +1326,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->set_state = _wpa_supplicant_set_state; ctx->get_state = _wpa_supplicant_get_state; ctx->deauthenticate = _wpa_supplicant_deauthenticate; + ctx->reconnect = _wpa_supplicant_reconnect; ctx->set_key = wpa_supplicant_set_key; ctx->get_network_ctx = wpa_supplicant_get_network_ctx; ctx->get_bssid = wpa_supplicant_get_bssid; @@ -1244,6 +1360,7 @@ int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s) ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk; ctx->fils_hlp_rx = wpa_supplicant_fils_hlp_rx; ctx->channel_info = wpa_supplicant_channel_info; + ctx->transition_disable = wpa_supplicant_transition_disable; wpa_s->wpa = wpa_sm_init(ctx); if (wpa_s->wpa == NULL) { @@ -1275,6 +1392,8 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, conf.ssid = ssid->ssid; conf.ssid_len = ssid->ssid_len; conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey; + conf.wpa_deny_ptk0_rekey = ssid->wpa_deny_ptk0_rekey; + conf.owe_ptk_workaround = ssid->owe_ptk_workaround; #ifdef CONFIG_P2P if (ssid->p2p_group && wpa_s->current_bss && !wpa_s->p2p_disable_ip_addr_req) { @@ -1297,6 +1416,7 @@ void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s, conf.fils_cache_id = wpa_bss_get_fils_cache_id(wpa_s->current_bss); #endif /* CONFIG_FILS */ + conf.beacon_prot = ssid->beacon_prot; } wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL); } diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index 8387fc3a..e6171585 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -532,6 +532,7 @@ static int wpa_supplicant_wps_cred(void *ctx, ssid->key_mgmt = WPA_KEY_MGMT_PSK; if (wpa_s->conf->wps_cred_add_sae && cred->key_len != 2 * PMK_LEN) { + ssid->auth_alg = 0; ssid->key_mgmt |= WPA_KEY_MGMT_SAE; ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL; } @@ -1829,6 +1830,10 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "WPS: Check whether PBC session overlap is " "present in scan results; selected BSSID " MACSTR, MAC2STR(selected->bssid)); + if (!is_zero_ether_addr(ssid->bssid)) + wpa_printf(MSG_DEBUG, + "WPS: Network profile limited to accept only a single BSSID " MACSTR, + MAC2STR(ssid->bssid)); /* Make sure that only one AP is in active PBC mode */ wps_ie = wpa_bss_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE); @@ -1849,6 +1854,14 @@ int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s, os_memcmp(selected->bssid, ap->bssid, ETH_ALEN) == 0) continue; + if (!is_zero_ether_addr(ssid->bssid) && + os_memcmp(ap->bssid, ssid->bssid, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, "WPS: Ignore another BSS " MACSTR + " in active PBC mode due to local BSSID limitation", + MAC2STR(ap->bssid)); + continue; + } + wpa_printf(MSG_DEBUG, "WPS: Another BSS in active PBC mode: " MACSTR, MAC2STR(ap->bssid)); wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS", |