diff options
author | Cy Schubert <cy@FreeBSD.org> | 2021-09-03 13:07:19 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2021-09-03 13:08:41 +0000 |
commit | c1d255d3ffdbe447de3ab875bf4e7d7accc5bfc5 (patch) | |
tree | 03efdf1f5caf99bc853ea6a23dfeb79d15ba348d | |
parent | a0c64a443e4cae67a5eea3a61a47d746866de3ee (diff) | |
parent | 2f6c3ea9600b494d24cac5a38c1cea0ac192245e (diff) | |
download | src-c1d255d3ffdb.tar.gz src-c1d255d3ffdb.zip |
wpa: Import wpa_supplicant/hostapd commits up to b4f7506ff
Merge vendor commits 40c7ff83e74eabba5a7e2caefeea12372b2d3f9a,
efec8223892b3e677acb46eae84ec3534989971f, and
2f6c3ea9600b494d24cac5a38c1cea0ac192245e.
Tested by: philip
MFC after: 2 months
504 files changed, 91123 insertions, 19030 deletions
diff --git a/contrib/wpa/CONTRIBUTIONS b/contrib/wpa/CONTRIBUTIONS index c81ad640995a..1b4caf7ac811 100644 --- a/contrib/wpa/CONTRIBUTIONS +++ b/contrib/wpa/CONTRIBUTIONS @@ -56,6 +56,9 @@ In general, the best way of generating a suitable formatted patch file is by committing the changes to a cloned git repository and using git format-patch. The patch can then be sent, e.g., with git send-email. +A list of pending patches waiting for review is available in +Patchwork: https://patchwork.ozlabs.org/project/hostap/list/ + History of license and contributions terms ------------------------------------------ @@ -140,7 +143,7 @@ The license terms used for hostap.git files Modified BSD license (no advertisement clause): -Copyright (c) 2002-2019, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2021, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. Redistribution and use in source and binary forms, with or without diff --git a/contrib/wpa/hostapd/Android.mk b/contrib/wpa/hostapd/Android.mk new file mode 100644 index 000000000000..dd8aa2450d7e --- /dev/null +++ b/contrib/wpa/hostapd/Android.mk @@ -0,0 +1,1152 @@ +# Copyright (C) 2008 The Android Open Source Project +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. +# + +LOCAL_PATH := $(call my-dir) + +WPA_BUILD_HOSTAPD := false +ifneq ($(BOARD_HOSTAPD_DRIVER),) + WPA_BUILD_HOSTAPD := true + CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y +endif + +ifeq ($(WPA_BUILD_HOSTAPD),true) + +include $(LOCAL_PATH)/android.config + +# To ignore possible wrong network configurations +L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS + +L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\" + +# Set Android log name +L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\" + +# Disable unused parameter warnings +L_CFLAGS += -Wno-unused-parameter + +# Set Android extended P2P functionality +L_CFLAGS += -DANDROID_P2P + +ifeq ($(BOARD_HOSTAPD_PRIVATE_LIB),) +L_CFLAGS += -DANDROID_LIB_STUB +endif + +ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB_EVENT),) +L_CFLAGS += -DANDROID_LIB_EVENT +endif + +# Use Android specific directory for control interface sockets +L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\" +L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/hostapd\" + +# Use Android specific directory for hostapd_cli command completion history +L_CFLAGS += -DCONFIG_HOSTAPD_CLI_HISTORY_DIR=\"/data/misc/wifi\" + +# To force sizeof(enum) = 4 +ifeq ($(TARGET_ARCH),arm) +L_CFLAGS += -mabi=aapcs-linux +endif + +INCLUDES = $(LOCAL_PATH) +INCLUDES += $(LOCAL_PATH)/src +INCLUDES += $(LOCAL_PATH)/src/utils +INCLUDES += system/security/keystore/include +ifdef CONFIG_DRIVER_NL80211 +ifneq ($(wildcard external/libnl),) +INCLUDES += external/libnl/include +else +INCLUDES += external/libnl-headers +endif +endif + + +ifndef CONFIG_OS +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_OS=win32 +else +CONFIG_OS=unix +endif +endif + +ifeq ($(CONFIG_OS), internal) +L_CFLAGS += -DOS_NO_C_LIB_DEFINES +endif + +ifdef CONFIG_NATIVE_WINDOWS +L_CFLAGS += -DCONFIG_NATIVE_WINDOWS +LIBS += -lws2_32 +endif + +OBJS = main.c +OBJS += config_file.c + +OBJS += src/ap/hostapd.c +OBJS += src/ap/wpa_auth_glue.c +OBJS += src/ap/drv_callbacks.c +OBJS += src/ap/ap_drv_ops.c +OBJS += src/ap/utils.c +OBJS += src/ap/authsrv.c +OBJS += src/ap/ieee802_1x.c +OBJS += src/ap/ap_config.c +OBJS += src/ap/eap_user_db.c +OBJS += src/ap/ieee802_11_auth.c +OBJS += src/ap/sta_info.c +OBJS += src/ap/wpa_auth.c +OBJS += src/ap/tkip_countermeasures.c +OBJS += src/ap/ap_mlme.c +OBJS += src/ap/wpa_auth_ie.c +OBJS += src/ap/preauth_auth.c +OBJS += src/ap/pmksa_cache_auth.c +OBJS += src/ap/ieee802_11_shared.c +OBJS += src/ap/beacon.c +OBJS += src/ap/bss_load.c +OBJS += src/ap/neighbor_db.c +OBJS += src/ap/rrm.c +OBJS_d = +OBJS_p = +LIBS = +LIBS_c = +HOBJS = +LIBS_h = + +NEED_RC4=y +NEED_AES=y +NEED_MD5=y +NEED_SHA1=y + +OBJS += src/drivers/drivers.c +L_CFLAGS += -DHOSTAPD + +ifdef CONFIG_WPA_TRACE +L_CFLAGS += -DWPA_TRACE +OBJS += src/utils/trace.c +HOBJS += src/utils/trace.c +LDFLAGS += -rdynamic +L_CFLAGS += -funwind-tables +ifdef CONFIG_WPA_TRACE_BFD +L_CFLAGS += -DWPA_TRACE_BFD +LIBS += -lbfd +LIBS_c += -lbfd +LIBS_h += -lbfd +endif +endif + +OBJS += src/utils/eloop.c + +ifdef CONFIG_ELOOP_POLL +L_CFLAGS += -DCONFIG_ELOOP_POLL +endif + +ifdef CONFIG_ELOOP_EPOLL +L_CFLAGS += -DCONFIG_ELOOP_EPOLL +endif + +OBJS += src/utils/common.c +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 +OBJS += src/common/hw_features_common.c + +OBJS += src/eapol_auth/eapol_auth_sm.c + + +ifndef CONFIG_NO_DUMP_STATE +# define HOSTAPD_DUMP_STATE to include support for dumping internal state +# through control interface commands (undefine it, if you want to save in +# binary size) +L_CFLAGS += -DHOSTAPD_DUMP_STATE +OBJS += src/eapol_auth/eapol_auth_dump.c +endif + +ifdef CONFIG_NO_RADIUS +L_CFLAGS += -DCONFIG_NO_RADIUS +CONFIG_NO_ACCOUNTING=y +else +OBJS += src/radius/radius.c +OBJS += src/radius/radius_client.c +OBJS += src/radius/radius_das.c +endif + +ifdef CONFIG_NO_ACCOUNTING +L_CFLAGS += -DCONFIG_NO_ACCOUNTING +else +OBJS += src/ap/accounting.c +endif + +ifdef CONFIG_NO_VLAN +L_CFLAGS += -DCONFIG_NO_VLAN +else +OBJS += src/ap/vlan_init.c +OBJS += src/ap/vlan_ifconfig.c +OBJS += src/ap/vlan.c +ifdef CONFIG_FULL_DYNAMIC_VLAN +# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges +# and VLAN interfaces for the VLAN feature. +L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN +OBJS += src/ap/vlan_full.c +ifdef CONFIG_VLAN_NETLINK +OBJS += src/ap/vlan_util.c +else +OBJS += src/ap/vlan_ioctl.c +endif +endif +endif + +ifdef CONFIG_NO_CTRL_IFACE +L_CFLAGS += -DCONFIG_NO_CTRL_IFACE +else +OBJS += src/common/ctrl_iface_common.c +OBJS += ctrl_iface.c +OBJS += src/ap/ctrl_iface_ap.c +endif + +L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX + +ifdef CONFIG_RSN_PREAUTH +L_CFLAGS += -DCONFIG_RSN_PREAUTH +CONFIG_L2_PACKET=y +endif + +ifdef CONFIG_HS20 +CONFIG_PROXYARP=y +endif + +ifdef CONFIG_PROXYARP +CONFIG_L2_PACKET=y +endif + +ifdef CONFIG_SUITEB +L_CFLAGS += -DCONFIG_SUITEB +endif + +ifdef CONFIG_SUITEB192 +L_CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + +ifdef CONFIG_OCV +L_CFLAGS += -DCONFIG_OCV +OBJS += src/common/ocv.c +endif + +ifdef CONFIG_IEEE80211R +L_CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP +OBJS += src/ap/wpa_auth_ft.c +NEED_AES_UNWRAP=y +NEED_AES_SIV=y +NEED_ETH_P_OUI=y +NEED_HMAC_SHA256_KDF=y +endif + +ifdef NEED_ETH_P_OUI +L_CFLAGS += -DCONFIG_ETH_P_OUI +OBJS += src/ap/eth_p_oui.c +endif + +ifdef CONFIG_SAE +L_CFLAGS += -DCONFIG_SAE +OBJS += src/common/sae.c +ifdef CONFIG_SAE_PK +L_CFLAGS += -DCONFIG_SAE_PK +OBJS += src/common/sae_pk.c +endif +NEED_ECC=y +NEED_DH_GROUPS=y +NEED_HMAC_SHA256_KDF=y +NEED_DRAGONFLY=y +endif + +ifdef CONFIG_OWE +L_CFLAGS += -DCONFIG_OWE +NEED_ECC=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +endif + +ifdef CONFIG_FILS +L_CFLAGS += -DCONFIG_FILS +OBJS += src/ap/fils_hlp.c +NEED_SHA384=y +NEED_AES_SIV=y +ifdef CONFIG_FILS_SK_PFS +L_CFLAGS += -DCONFIG_FILS_SK_PFS +NEED_ECC=y +endif +endif + +ifdef CONFIG_WNM +L_CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP +OBJS += src/ap/wnm_ap.c +endif + +ifdef CONFIG_IEEE80211AC +L_CFLAGS += -DCONFIG_IEEE80211AC +endif + +ifdef CONFIG_IEEE80211AX +L_CFLAGS += -DCONFIG_IEEE80211AX +endif + +ifdef CONFIG_MBO +L_CFLAGS += -DCONFIG_MBO +OBJS += src/ap/mbo_ap.c +endif + +ifdef CONFIG_FST +L_CFLAGS += -DCONFIG_FST +OBJS += src/fst/fst.c +OBJS += src/fst/fst_group.c +OBJS += src/fst/fst_iface.c +OBJS += src/fst/fst_session.c +OBJS += src/fst/fst_ctrl_aux.c +ifdef CONFIG_FST_TEST +L_CFLAGS += -DCONFIG_FST_TEST +endif +ifndef CONFIG_NO_CTRL_IFACE +OBJS += src/fst/fst_ctrl_iface.c +endif +endif + +ifdef CONFIG_WEP +L_CFLAGS += -DCONFIG_WEP +endif + +ifdef CONFIG_NO_TKIP +L_CFLAGS += -DCONFIG_NO_TKIP +endif + + +include $(LOCAL_PATH)/src/drivers/drivers.mk + +OBJS += $(DRV_AP_OBJS) +L_CFLAGS += $(DRV_AP_CFLAGS) +LDFLAGS += $(DRV_AP_LDFLAGS) +LIBS += $(DRV_AP_LIBS) + +ifdef CONFIG_L2_PACKET +ifdef CONFIG_DNET_PCAP +ifdef CONFIG_L2_FREEBSD +LIBS += -lpcap +OBJS += src/l2_packet/l2_packet_freebsd.c +else +LIBS += -ldnet -lpcap +OBJS += src/l2_packet/l2_packet_pcap.c +endif +else +OBJS += src/l2_packet/l2_packet_linux.c +endif +else +OBJS += src/l2_packet/l2_packet_none.c +endif + + +ifdef CONFIG_EAP_MD5 +L_CFLAGS += -DEAP_SERVER_MD5 +OBJS += src/eap_server/eap_server_md5.c +CHAP=y +endif + +ifdef CONFIG_EAP_TLS +L_CFLAGS += -DEAP_SERVER_TLS +OBJS += src/eap_server/eap_server_tls.c +TLS_FUNCS=y +endif + +ifdef CONFIG_EAP_UNAUTH_TLS +L_CFLAGS += -DEAP_SERVER_UNAUTH_TLS +ifndef CONFIG_EAP_TLS +OBJS += src/eap_server/eap_server_tls.c +TLS_FUNCS=y +endif +endif + +ifdef CONFIG_EAP_PEAP +L_CFLAGS += -DEAP_SERVER_PEAP +OBJS += src/eap_server/eap_server_peap.c +OBJS += src/eap_common/eap_peap_common.c +TLS_FUNCS=y +CONFIG_EAP_MSCHAPV2=y +endif + +ifdef CONFIG_EAP_TTLS +L_CFLAGS += -DEAP_SERVER_TTLS +OBJS += src/eap_server/eap_server_ttls.c +TLS_FUNCS=y +CHAP=y +endif + +ifdef CONFIG_EAP_MSCHAPV2 +L_CFLAGS += -DEAP_SERVER_MSCHAPV2 +OBJS += src/eap_server/eap_server_mschapv2.c +MS_FUNCS=y +endif + +ifdef CONFIG_EAP_GTC +L_CFLAGS += -DEAP_SERVER_GTC +OBJS += src/eap_server/eap_server_gtc.c +endif + +ifdef CONFIG_EAP_SIM +L_CFLAGS += -DEAP_SERVER_SIM +OBJS += src/eap_server/eap_server_sim.c +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_AKA +L_CFLAGS += -DEAP_SERVER_AKA +OBJS += src/eap_server/eap_server_aka.c +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_AKA_PRIME +L_CFLAGS += -DEAP_SERVER_AKA_PRIME +endif + +ifdef CONFIG_EAP_SIM_COMMON +OBJS += src/eap_common/eap_sim_common.c +# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be +# replaced with another file implementing the interface specified in +# eap_sim_db.h. +OBJS += src/eap_server/eap_sim_db.c +NEED_FIPS186_2_PRF=y +endif + +ifdef CONFIG_EAP_PAX +L_CFLAGS += -DEAP_SERVER_PAX +OBJS += src/eap_server/eap_server_pax.c src/eap_common/eap_pax_common.c +endif + +ifdef CONFIG_EAP_PSK +L_CFLAGS += -DEAP_SERVER_PSK +OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c +NEED_AES_ENCBLOCK=y +NEED_AES_EAX=y +endif + +ifdef CONFIG_EAP_SAKE +L_CFLAGS += -DEAP_SERVER_SAKE +OBJS += src/eap_server/eap_server_sake.c src/eap_common/eap_sake_common.c +endif + +ifdef CONFIG_EAP_GPSK +L_CFLAGS += -DEAP_SERVER_GPSK +OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c +ifdef CONFIG_EAP_GPSK_SHA256 +L_CFLAGS += -DEAP_GPSK_SHA256 +endif +endif + +ifdef CONFIG_EAP_PWD +L_CFLAGS += -DEAP_SERVER_PWD +OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c +NEED_ECC=y +NEED_DRAGONFLY=y +endif + +ifdef CONFIG_EAP_EKE +L_CFLAGS += -DEAP_SERVER_EKE +OBJS += src/eap_server/eap_server_eke.c src/eap_common/eap_eke_common.c +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +endif + +ifdef CONFIG_EAP_VENDOR_TEST +L_CFLAGS += -DEAP_SERVER_VENDOR_TEST +OBJS += src/eap_server/eap_server_vendor_test.c +endif + +ifdef CONFIG_EAP_FAST +L_CFLAGS += -DEAP_SERVER_FAST +OBJS += src/eap_server/eap_server_fast.c +OBJS += src/eap_common/eap_fast_common.c +TLS_FUNCS=y +NEED_T_PRF=y +NEED_AES_UNWRAP=y +endif + +ifdef CONFIG_EAP_TEAP +L_CFLAGS += -DEAP_SERVER_TEAP +OBJS += src/eap_server/eap_server_teap.c +OBJS += src/eap_common/eap_teap_common.c +TLS_FUNCS=y +NEED_T_PRF=y +NEED_SHA384=y +NEED_TLS_PRF_SHA256=y +NEED_TLS_PRF_SHA384=y +NEED_AES_UNWRAP=y +endif + +ifdef CONFIG_WPS +L_CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC +OBJS += src/utils/uuid.c +OBJS += src/ap/wps_hostapd.c +OBJS += src/eap_server/eap_server_wsc.c src/eap_common/eap_wsc_common.c +OBJS += src/wps/wps.c +OBJS += src/wps/wps_common.c +OBJS += src/wps/wps_attr_parse.c +OBJS += src/wps/wps_attr_build.c +OBJS += src/wps/wps_attr_process.c +OBJS += src/wps/wps_dev_attr.c +OBJS += src/wps/wps_enrollee.c +OBJS += src/wps/wps_registrar.c +NEED_DH_GROUPS=y +NEED_BASE64=y +NEED_AES_CBC=y +NEED_MODEXP=y +CONFIG_EAP=y + +ifdef CONFIG_WPS_NFC +L_CFLAGS += -DCONFIG_WPS_NFC +OBJS += src/wps/ndef.c +NEED_WPS_OOB=y +endif + +ifdef NEED_WPS_OOB +L_CFLAGS += -DCONFIG_WPS_OOB +endif + +ifdef CONFIG_WPS_UPNP +L_CFLAGS += -DCONFIG_WPS_UPNP +OBJS += src/wps/wps_upnp.c +OBJS += src/wps/wps_upnp_ssdp.c +OBJS += src/wps/wps_upnp_web.c +OBJS += src/wps/wps_upnp_event.c +OBJS += src/wps/wps_upnp_ap.c +OBJS += src/wps/upnp_xml.c +OBJS += src/wps/httpread.c +OBJS += src/wps/http_client.c +OBJS += src/wps/http_server.c +endif + +ifdef CONFIG_WPS_STRICT +L_CFLAGS += -DCONFIG_WPS_STRICT +OBJS += src/wps/wps_validate.c +endif + +ifdef CONFIG_WPS_TESTING +L_CFLAGS += -DCONFIG_WPS_TESTING +endif + +endif + +ifdef CONFIG_DPP +L_CFLAGS += -DCONFIG_DPP +OBJS += src/common/dpp.c +OBJS += src/common/dpp_auth.c +OBJS += src/common/dpp_backup.c +OBJS += src/common/dpp_crypto.c +OBJS += src/common/dpp_pkex.c +OBJS += src/common/dpp_reconfig.c +OBJS += src/common/dpp_tcp.c +OBJS += src/ap/dpp_hostapd.c +OBJS += src/ap/gas_query_ap.c +NEED_AES_SIV=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +NEED_ECC=y +NEED_JSON=y +NEED_GAS=y +NEED_BASE64=y +NEED_ASN1=y +ifdef CONFIG_DPP2 +L_CFLAGS += -DCONFIG_DPP2 +endif +endif + +ifdef CONFIG_PASN +L_CFLAGS += -DCONFIG_PASN +L_CFLAGS += -DCONFIG_PTKSA_CACHE +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_SHA256=y +NEED_SHA384=y +OBJS += src/common/ptksa_cache.c +endif + +ifdef CONFIG_EAP_IKEV2 +L_CFLAGS += -DEAP_SERVER_IKEV2 +OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c +OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +NEED_MODEXP=y +NEED_CIPHER=y +endif + +ifdef CONFIG_EAP_TNC +L_CFLAGS += -DEAP_SERVER_TNC +OBJS += src/eap_server/eap_server_tnc.c +OBJS += src/eap_server/tncs.c +NEED_BASE64=y +ifndef CONFIG_DRIVER_BSD +LIBS += -ldl +endif +endif + +# Basic EAP functionality is needed for EAPOL +OBJS += eap_register.c +OBJS += src/eap_server/eap_server.c +OBJS += src/eap_common/eap_common.c +OBJS += src/eap_server/eap_server_methods.c +OBJS += src/eap_server/eap_server_identity.c +L_CFLAGS += -DEAP_SERVER_IDENTITY + +ifdef CONFIG_EAP +L_CFLAGS += -DEAP_SERVER +endif + +ifdef CONFIG_PKCS12 +L_CFLAGS += -DPKCS12_FUNCS +endif + +ifdef NEED_DRAGONFLY +OBJS += src/common/dragonfly.c +endif + +ifdef MS_FUNCS +OBJS += src/crypto/ms_funcs.c +NEED_DES=y +NEED_MD4=y +endif + +ifdef CHAP +OBJS += src/eap_common/chap.c +endif + +ifdef TLS_FUNCS +NEED_DES=y +# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) +L_CFLAGS += -DEAP_TLS_FUNCS +OBJS += src/eap_server/eap_server_tls_common.c +NEED_TLS_PRF=y +endif + +ifndef CONFIG_TLS +CONFIG_TLS=openssl +endif + +ifdef CONFIG_TLSV11 +L_CFLAGS += -DCONFIG_TLSV11 +endif + +ifdef CONFIG_TLSV12 +L_CFLAGS += -DCONFIG_TLSV12 +endif + +ifeq ($(CONFIG_TLS), openssl) +ifdef TLS_FUNCS +OBJS += src/crypto/tls_openssl.c +OBJS += src/crypto/tls_openssl_ocsp.c +LIBS += -lssl +endif +OBJS += src/crypto/crypto_openssl.c +HOBJS += src/crypto/crypto_openssl.c +ifdef NEED_FIPS186_2_PRF +OBJS += src/crypto/fips_prf_openssl.c +endif +NEED_TLS_PRF_SHA256=y +LIBS += -lcrypto +LIBS_h += -lcrypto +ifndef CONFIG_TLS_DEFAULT_CIPHERS +CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW" +endif +L_CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" +endif + +ifeq ($(CONFIG_TLS), gnutls) +ifndef CONFIG_CRYPTO +# default to libgcrypt +CONFIG_CRYPTO=gnutls +endif +ifdef TLS_FUNCS +OBJS += src/crypto/tls_gnutls.c +LIBS += -lgnutls -lgpg-error +endif +OBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c +HOBJS += src/crypto/crypto_$(CONFIG_CRYPTO).c +ifdef NEED_FIPS186_2_PRF +OBJS += src/crypto/fips_prf_internal.c +OBJS += src/crypto/sha1-internal.c +endif +ifeq ($(CONFIG_CRYPTO), gnutls) +LIBS += -lgcrypt +LIBS_h += -lgcrypt +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), nettle) +LIBS += -lnettle -lgmp +LIBS_p += -lnettle -lgmp +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +endif + +ifeq ($(CONFIG_TLS), internal) +ifndef CONFIG_CRYPTO +CONFIG_CRYPTO=internal +endif +ifdef TLS_FUNCS +OBJS += src/crypto/crypto_internal-rsa.c +OBJS += src/crypto/tls_internal.c +OBJS += src/tls/tlsv1_common.c +OBJS += src/tls/tlsv1_record.c +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/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 +NEED_TLS_PRF_SHA256=y +endif +NEED_MODEXP=y +NEED_CIPHER=y +L_CFLAGS += -DCONFIG_TLS_INTERNAL +L_CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER +endif +ifdef NEED_CIPHER +NEED_DES=y +OBJS += src/crypto/crypto_internal-cipher.c +endif +ifdef NEED_MODEXP +OBJS += src/crypto/crypto_internal-modexp.c +OBJS += src/tls/bignum.c +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS += src/crypto/crypto_libtomcrypt.c +LIBS += -ltomcrypt -ltfm +LIBS_h += -ltomcrypt -ltfm +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), internal) +OBJS += src/crypto/crypto_internal.c +NEED_AES_DEC=y +L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL +ifdef CONFIG_INTERNAL_LIBTOMMATH +L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST +L_CFLAGS += -DLTM_FAST +endif +else +LIBS += -ltommath +LIBS_h += -ltommath +endif +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_DES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD4=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), cryptoapi) +OBJS += src/crypto/crypto_cryptoapi.c +OBJS_p += src/crypto/crypto_cryptoapi.c +L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif +endif + +ifeq ($(CONFIG_TLS), none) +ifdef TLS_FUNCS +OBJS += src/crypto/tls_none.c +L_CFLAGS += -DEAP_TLS_NONE +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +endif +OBJS += src/crypto/crypto_none.c +OBJS_p += src/crypto/crypto_none.c +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif + +ifndef TLS_FUNCS +OBJS += src/crypto/tls_none.c +ifeq ($(CONFIG_TLS), internal) +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_RC4=y +endif +endif + +AESOBJS = # none so far +ifdef CONFIG_INTERNAL_AES +AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c +endif + +ifneq ($(CONFIG_TLS), openssl) +AESOBJS += src/crypto/aes-wrap.c +endif +ifdef NEED_AES_EAX +AESOBJS += src/crypto/aes-eax.c +NEED_AES_CTR=y +endif +ifdef NEED_AES_SIV +AESOBJS += src/crypto/aes-siv.c +NEED_AES_CTR=y +endif +ifdef NEED_AES_CTR +AESOBJS += src/crypto/aes-ctr.c +endif +ifdef NEED_AES_ENCBLOCK +AESOBJS += src/crypto/aes-encblock.c +endif +AESOBJS += src/crypto/aes-omac1.c +ifdef NEED_AES_UNWRAP +ifneq ($(CONFIG_TLS), openssl) +NEED_AES_DEC=y +AESOBJS += src/crypto/aes-unwrap.c +endif +endif +ifdef NEED_AES_CBC +NEED_AES_DEC=y +ifneq ($(CONFIG_TLS), openssl) +AESOBJS += src/crypto/aes-cbc.c +endif +endif +ifdef NEED_AES_DEC +ifdef CONFIG_INTERNAL_AES +AESOBJS += src/crypto/aes-internal-dec.c +endif +endif +ifdef NEED_AES +OBJS += $(AESOBJS) +endif + +SHA1OBJS = +ifdef NEED_SHA1 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +SHA1OBJS += src/crypto/sha1.c +endif +endif +SHA1OBJS += src/crypto/sha1-prf.c +ifdef CONFIG_INTERNAL_SHA1 +SHA1OBJS += src/crypto/sha1-internal.c +ifdef NEED_FIPS186_2_PRF +SHA1OBJS += src/crypto/fips_prf_internal.c +endif +endif +ifneq ($(CONFIG_TLS), openssl) +SHA1OBJS += src/crypto/sha1-pbkdf2.c +endif +ifdef NEED_T_PRF +SHA1OBJS += src/crypto/sha1-tprf.c +endif +ifdef NEED_TLS_PRF +SHA1OBJS += src/crypto/sha1-tlsprf.c +endif +endif + +ifdef NEED_SHA1 +OBJS += $(SHA1OBJS) +endif + +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/md5.c +endif +endif + +ifdef NEED_MD5 +ifdef CONFIG_INTERNAL_MD5 +OBJS += src/crypto/md5-internal.c +HOBJS += src/crypto/md5-internal.c +endif +endif + +ifdef NEED_MD4 +ifdef CONFIG_INTERNAL_MD4 +OBJS += src/crypto/md4-internal.c +endif +endif + +ifdef NEED_DES +ifdef CONFIG_INTERNAL_DES +OBJS += src/crypto/des-internal.c +endif +endif + +ifdef CONFIG_NO_RC4 +L_CFLAGS += -DCONFIG_NO_RC4 +endif + +ifdef NEED_RC4 +ifdef CONFIG_INTERNAL_RC4 +ifndef CONFIG_NO_RC4 +OBJS += src/crypto/rc4.c +endif +endif +endif + +L_CFLAGS += -DCONFIG_SHA256 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/sha256.c +endif +endif +OBJS += src/crypto/sha256-prf.c +ifdef CONFIG_INTERNAL_SHA256 +OBJS += src/crypto/sha256-internal.c +endif +ifdef NEED_TLS_PRF_SHA256 +OBJS += src/crypto/sha256-tlsprf.c +endif +ifdef NEED_TLS_PRF_SHA384 +OBJS += src/crypto/sha384-tlsprf.c +endif +ifdef NEED_HMAC_SHA256_KDF +OBJS += src/crypto/sha256-kdf.c +endif +ifdef NEED_HMAC_SHA384_KDF +OBJS += src/crypto/sha384-kdf.c +endif +ifdef NEED_HMAC_SHA512_KDF +OBJS += src/crypto/sha512-kdf.c +endif +ifdef NEED_SHA384 +L_CFLAGS += -DCONFIG_SHA384 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/sha384.c +endif +endif +OBJS += src/crypto/sha384-prf.c +endif +ifdef NEED_SHA512 +L_CFLAGS += -DCONFIG_SHA512 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +OBJS += src/crypto/sha512.c +endif +endif +endif +OBJS += src/crypto/sha512-prf.c +endif + +ifdef CONFIG_INTERNAL_SHA384 +L_CFLAGS += -DCONFIG_INTERNAL_SHA384 +OBJS += src/crypto/sha384-internal.c +endif + +ifdef CONFIG_INTERNAL_SHA512 +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 +ifdef NEED_DH_GROUPS_ALL +L_CFLAGS += -DALL_DH_GROUPS +endif +ifdef CONFIG_INTERNAL_DH_GROUP5 +ifdef NEED_DH_GROUPS +OBJS += src/crypto/dh_group5.c +endif +endif + +ifdef NEED_ECC +L_CFLAGS += -DCONFIG_ECC +endif + +ifdef CONFIG_NO_RANDOM_POOL +L_CFLAGS += -DCONFIG_NO_RANDOM_POOL +else +OBJS += src/crypto/random.c +HOBJS += src/crypto/random.c +HOBJS += src/utils/eloop.c +HOBJS += $(SHA1OBJS) +ifneq ($(CONFIG_TLS), openssl) +HOBJS += src/crypto/md5.c +endif +endif + +ifdef CONFIG_RADIUS_SERVER +L_CFLAGS += -DRADIUS_SERVER +OBJS += src/radius/radius_server.c +endif + +ifdef CONFIG_IPV6 +L_CFLAGS += -DCONFIG_IPV6 +endif + +ifdef CONFIG_DRIVER_RADIUS_ACL +L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL +endif + +ifdef NEED_BASE64 +OBJS += src/utils/base64.c +endif + +ifdef NEED_JSON +OBJS += src/utils/json.c +L_CFLAGS += -DCONFIG_JSON +endif + +ifdef NEED_AP_MLME +OBJS += src/ap/wmm.c +OBJS += src/ap/ap_list.c +OBJS += src/ap/ieee802_11.c +OBJS += src/ap/hw_features.c +OBJS += src/ap/dfs.c +L_CFLAGS += -DNEED_AP_MLME +endif +OBJS += src/ap/ieee802_11_ht.c + +ifdef CONFIG_IEEE80211AC +OBJS += src/ap/ieee802_11_vht.c +endif + +ifdef CONFIG_IEEE80211AX +OBJS += src/ap/ieee802_11_he.c +endif + +ifdef CONFIG_P2P_MANAGER +L_CFLAGS += -DCONFIG_P2P_MANAGER +OBJS += src/ap/p2p_hostapd.c +endif + +ifdef CONFIG_HS20 +L_CFLAGS += -DCONFIG_HS20 +OBJS += src/ap/hs20.c +CONFIG_INTERWORKING=y +endif + +ifdef CONFIG_INTERWORKING +L_CFLAGS += -DCONFIG_INTERWORKING +NEED_GAS=y +endif + +ifdef NEED_GAS +OBJS += src/common/gas.c +OBJS += src/ap/gas_serv.c +endif + +ifdef CONFIG_PROXYARP +L_CFLAGS += -DCONFIG_PROXYARP +OBJS += src/ap/x_snoop.c +OBJS += src/ap/dhcp_snoop.c +ifdef CONFIG_IPV6 +OBJS += src/ap/ndisc_snoop.c +endif +endif + +OBJS += src/drivers/driver_common.c + +ifdef CONFIG_ACS +L_CFLAGS += -DCONFIG_ACS +OBJS += src/ap/acs.c +LIBS += -lm +endif + +ifdef CONFIG_NO_STDOUT_DEBUG +L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG +endif + +ifdef CONFIG_DEBUG_SYSLOG +L_CFLAGS += -DCONFIG_DEBUG_SYSLOG +endif + +ifdef CONFIG_DEBUG_LINUX_TRACING +L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING +endif + +ifdef CONFIG_DEBUG_FILE +L_CFLAGS += -DCONFIG_DEBUG_FILE +endif + +ifdef CONFIG_ANDROID_LOG +L_CFLAGS += -DCONFIG_ANDROID_LOG +endif + +OBJS_c = hostapd_cli.c +OBJS_c += src/common/wpa_ctrl.c +OBJS_c += src/utils/os_$(CONFIG_OS).c +OBJS_c += src/common/cli.c +OBJS_c += src/utils/eloop.c +OBJS_c += src/utils/common.c +ifdef CONFIG_WPA_TRACE +OBJS_c += src/utils/trace.c +endif +OBJS_c += src/utils/wpa_debug.c +ifdef CONFIG_WPA_CLI_EDIT +OBJS_c += src/utils/edit.c +else +OBJS_c += src/utils/edit_simple.c +endif + +######################## + +include $(CLEAR_VARS) +LOCAL_MODULE := hostapd_cli +LOCAL_MODULE_TAGS := debug +LOCAL_PROPRIETARY_MODULE := true +LOCAL_SHARED_LIBRARIES := libc libcutils liblog +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_SRC_FILES := $(OBJS_c) +LOCAL_C_INCLUDES := $(INCLUDES) +include $(BUILD_EXECUTABLE) + +######################## +include $(CLEAR_VARS) +LOCAL_MODULE := hostapd +LOCAL_MODULE_TAGS := optional +LOCAL_PROPRIETARY_MODULE := true +ifdef CONFIG_DRIVER_CUSTOM +LOCAL_STATIC_LIBRARIES := libCustomWifi +endif +ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),) +LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB) +endif +LOCAL_SHARED_LIBRARIES := libc libcutils liblog libcrypto libssl +ifdef CONFIG_DRIVER_NL80211 +ifneq ($(wildcard external/libnl),) +LOCAL_SHARED_LIBRARIES += libnl +else +LOCAL_STATIC_LIBRARIES += libnl_2 +endif +endif +LOCAL_CFLAGS := $(L_CFLAGS) +LOCAL_SRC_FILES := $(OBJS) +LOCAL_C_INCLUDES := $(INCLUDES) +LOCAL_INIT_RC := hostapd.android.rc +include $(BUILD_EXECUTABLE) + +endif # ifeq ($(WPA_BUILD_HOSTAPD),true) diff --git a/contrib/wpa/hostapd/ChangeLog b/contrib/wpa/hostapd/ChangeLog index 6c4410e8ec62..34a8a081879d 100644 --- a/contrib/wpa/hostapd/ChangeLog +++ b/contrib/wpa/hostapd/ChangeLog @@ -362,7 +362,7 @@ ChangeLog for hostapd * RADIUS server functionality - add minimal RADIUS accounting server support (hostapd-as-server); this is mainly to enable testing coverage with hwsim scripts - - allow authentication log to be written into SQLite databse + - allow authentication log to be written into SQLite database - added option for TLS protocol testing of an EAP peer by simulating various misbehaviors/known attacks - MAC ACL support for testing purposes @@ -668,7 +668,7 @@ ChangeLog for hostapd * fixed HT Capabilities IE with nl80211 drivers * moved generic AP functionality code into src/ap * WPS: handle Selected Registrar as union of info from all Registrars - * remove obsolte Prism54.org driver wrapper + * remove obsolete Prism54.org driver wrapper * added internal debugging mechanism with backtrace support and memory allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y) * EAP-FAST server: piggyback Phase 2 start with the end of Phase 1 diff --git a/contrib/wpa/hostapd/Makefile b/contrib/wpa/hostapd/Makefile new file mode 100644 index 000000000000..ac085fd10520 --- /dev/null +++ b/contrib/wpa/hostapd/Makefile @@ -0,0 +1,1375 @@ +ALL=hostapd hostapd_cli +CONFIG_FILE = .config + +include ../src/build.rules + +ifdef LIBS +# If LIBS is set with some global build system defaults, clone those for +# LIBS_c, LIBS_h, and LIBS_n to cover hostapd_cli, hlr_auc_gw, and +# nt_password_hash as well. +ifndef LIBS_c +LIBS_c := $(LIBS) +endif +ifndef LIBS_h +LIBS_h := $(LIBS) +endif +ifndef LIBS_n +LIBS_n := $(LIBS) +endif +ifndef LIBS_s +LIBS_s := $(LIBS) +endif +endif + +CFLAGS += $(EXTRA_CFLAGS) +CFLAGS += -I$(abspath ../src) +CFLAGS += -I$(abspath ../src/utils) + +export BINDIR ?= /usr/local/bin/ + +ifndef CONFIG_NO_GITVER +# Add VERSION_STR postfix for builds from a git repository +ifeq ($(wildcard ../.git),../.git) +GITVER := $(shell git describe --dirty=+) +ifneq ($(GITVER),) +CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\" +endif +endif +endif + +ifdef CONFIG_TESTING_OPTIONS +CFLAGS += -DCONFIG_TESTING_OPTIONS +CONFIG_WPS_TESTING=y +endif + +ifndef CONFIG_OS +ifdef CONFIG_NATIVE_WINDOWS +CONFIG_OS=win32 +else +CONFIG_OS=unix +endif +endif + +ifeq ($(CONFIG_OS), internal) +CFLAGS += -DOS_NO_C_LIB_DEFINES +endif + +ifdef CONFIG_NATIVE_WINDOWS +CFLAGS += -DCONFIG_NATIVE_WINDOWS +LIBS += -lws2_32 +endif + +OBJS += main.o +OBJS += config_file.o + +OBJS += ../src/ap/hostapd.o +OBJS += ../src/ap/wpa_auth_glue.o +OBJS += ../src/ap/drv_callbacks.o +OBJS += ../src/ap/ap_drv_ops.o +OBJS += ../src/ap/utils.o +OBJS += ../src/ap/authsrv.o +OBJS += ../src/ap/ieee802_1x.o +OBJS += ../src/ap/ap_config.o +OBJS += ../src/ap/eap_user_db.o +OBJS += ../src/ap/ieee802_11_auth.o +OBJS += ../src/ap/sta_info.o +OBJS += ../src/ap/wpa_auth.o +OBJS += ../src/ap/tkip_countermeasures.o +OBJS += ../src/ap/ap_mlme.o +OBJS += ../src/ap/wpa_auth_ie.o +OBJS += ../src/ap/preauth_auth.o +OBJS += ../src/ap/pmksa_cache_auth.o +OBJS += ../src/ap/ieee802_11_shared.o +OBJS += ../src/ap/beacon.o +OBJS += ../src/ap/bss_load.o +OBJS += ../src/ap/neighbor_db.o +OBJS += ../src/ap/rrm.o + +OBJS_c = hostapd_cli.o +OBJS_c += ../src/common/wpa_ctrl.o +OBJS_c += ../src/utils/os_$(CONFIG_OS).o +OBJS_c += ../src/common/cli.o + +NEED_RC4=y +NEED_AES=y +NEED_MD5=y +NEED_SHA1=y + +OBJS += ../src/drivers/drivers.o +CFLAGS += -DHOSTAPD + +ifdef CONFIG_TAXONOMY +CFLAGS += -DCONFIG_TAXONOMY +OBJS += ../src/ap/taxonomy.o +endif + +ifdef CONFIG_MODULE_TESTS +CFLAGS += -DCONFIG_MODULE_TESTS +OBJS += hapd_module_tests.o +endif + +ifdef CONFIG_WPA_TRACE +CFLAGS += -DWPA_TRACE +OBJS += ../src/utils/trace.o +HOBJS += ../src/utils/trace.o +LDFLAGS += -rdynamic +CFLAGS += -funwind-tables +ifdef CONFIG_WPA_TRACE_BFD +CFLAGS += -DPACKAGE="hostapd" -DWPA_TRACE_BFD +LIBS += -lbfd -ldl -liberty -lz +LIBS_c += -lbfd -ldl -liberty -lz +LIBS_h += -lbfd -ldl -liberty -lz +LIBS_n += -lbfd -ldl -liberty -lz +LIBS_s += -lbfd -ldl -liberty -lz +endif +endif + +ifndef CONFIG_ELOOP +CONFIG_ELOOP=eloop +endif +OBJS += ../src/utils/$(CONFIG_ELOOP).o +OBJS_c += ../src/utils/$(CONFIG_ELOOP).o + +ifeq ($(CONFIG_ELOOP), eloop) +# Using glibc < 2.17 requires -lrt for clock_gettime() +LIBS += -lrt +LIBS_c += -lrt +LIBS_h += -lrt +LIBS_n += -lrt +endif + +ifdef CONFIG_ELOOP_POLL +CFLAGS += -DCONFIG_ELOOP_POLL +endif + +ifdef CONFIG_ELOOP_EPOLL +CFLAGS += -DCONFIG_ELOOP_EPOLL +endif + +ifdef CONFIG_ELOOP_KQUEUE +CFLAGS += -DCONFIG_ELOOP_KQUEUE +endif + +OBJS += ../src/utils/common.o +OBJS_c += ../src/utils/common.o +OBJS += ../src/utils/wpa_debug.o +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 +OBJS += ../src/common/hw_features_common.o + +OBJS += ../src/eapol_auth/eapol_auth_sm.o + + +ifdef CONFIG_CODE_COVERAGE +CFLAGS += -O0 -fprofile-arcs -ftest-coverage +LIBS += -lgcov +LIBS_c += -lgcov +LIBS_h += -lgcov +LIBS_n += -lgcov +endif + +ifndef CONFIG_NO_DUMP_STATE +# define HOSTAPD_DUMP_STATE to include support for dumping internal state +# through control interface commands (undefine it, if you want to save in +# binary size) +CFLAGS += -DHOSTAPD_DUMP_STATE +OBJS += ../src/eapol_auth/eapol_auth_dump.o +endif + +ifdef CONFIG_NO_RADIUS +CFLAGS += -DCONFIG_NO_RADIUS +CONFIG_NO_ACCOUNTING=y +else +OBJS += ../src/radius/radius.o +OBJS += ../src/radius/radius_client.o +OBJS += ../src/radius/radius_das.o +endif + +ifdef CONFIG_NO_ACCOUNTING +CFLAGS += -DCONFIG_NO_ACCOUNTING +else +OBJS += ../src/ap/accounting.o +endif + +ifdef CONFIG_NO_VLAN +CFLAGS += -DCONFIG_NO_VLAN +else +OBJS += ../src/ap/vlan_init.o +OBJS += ../src/ap/vlan_ifconfig.o +OBJS += ../src/ap/vlan.o +ifdef CONFIG_FULL_DYNAMIC_VLAN +# Define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges +# and VLAN interfaces for the VLAN feature. +CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN +OBJS += ../src/ap/vlan_full.o +ifdef CONFIG_VLAN_NETLINK +OBJS += ../src/ap/vlan_util.o +else +OBJS += ../src/ap/vlan_ioctl.o +endif +endif +endif + +ifdef CONFIG_NO_CTRL_IFACE +CFLAGS += -DCONFIG_NO_CTRL_IFACE +else +ifeq ($(CONFIG_CTRL_IFACE), udp) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +else +ifeq ($(CONFIG_CTRL_IFACE), udp6) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +else +ifeq ($(CONFIG_CTRL_IFACE), udp-remote) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +else +ifeq ($(CONFIG_CTRL_IFACE), udp6-remote) +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +else +CFLAGS += -DCONFIG_CTRL_IFACE_UNIX +endif +endif +endif +endif +OBJS += ../src/common/ctrl_iface_common.o +OBJS += ctrl_iface.o +OBJS += ../src/ap/ctrl_iface_ap.o +endif + +ifndef CONFIG_NO_CTRL_IFACE +CFLAGS += -DCONFIG_CTRL_IFACE +endif + +ifdef CONFIG_RSN_PREAUTH +CFLAGS += -DCONFIG_RSN_PREAUTH +CONFIG_L2_PACKET=y +endif + +ifdef CONFIG_HS20 +CONFIG_PROXYARP=y +endif + +ifdef CONFIG_PROXYARP +CONFIG_L2_PACKET=y +endif + +ifdef CONFIG_SUITEB +CFLAGS += -DCONFIG_SUITEB +endif + +ifdef CONFIG_SUITEB192 +CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + +ifdef CONFIG_OCV +CFLAGS += -DCONFIG_OCV +OBJS += ../src/common/ocv.o +endif + +ifdef CONFIG_IEEE80211R +CFLAGS += -DCONFIG_IEEE80211R -DCONFIG_IEEE80211R_AP +OBJS += ../src/ap/wpa_auth_ft.o +NEED_AES_UNWRAP=y +NEED_AES_SIV=y +NEED_ETH_P_OUI=y +NEED_HMAC_SHA256_KDF=y +endif + +ifdef NEED_ETH_P_OUI +CFLAGS += -DCONFIG_ETH_P_OUI +OBJS += ../src/ap/eth_p_oui.o +endif + +ifdef CONFIG_SAE +CFLAGS += -DCONFIG_SAE +OBJS += ../src/common/sae.o +ifdef CONFIG_SAE_PK +CFLAGS += -DCONFIG_SAE_PK +OBJS += ../src/common/sae_pk.o +endif +NEED_ECC=y +NEED_DH_GROUPS=y +NEED_HMAC_SHA256_KDF=y +NEED_AP_MLME=y +NEED_DRAGONFLY=y +endif + +ifdef CONFIG_OWE +CFLAGS += -DCONFIG_OWE +NEED_ECC=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +endif + +ifdef CONFIG_AIRTIME_POLICY +CFLAGS += -DCONFIG_AIRTIME_POLICY +OBJS += ../src/ap/airtime_policy.o +endif + +ifdef CONFIG_FILS +CFLAGS += -DCONFIG_FILS +OBJS += ../src/ap/fils_hlp.o +NEED_SHA384=y +NEED_AES_SIV=y +ifdef CONFIG_FILS_SK_PFS +CFLAGS += -DCONFIG_FILS_SK_PFS +NEED_ECC=y +endif +endif + +ifdef CONFIG_WNM +CFLAGS += -DCONFIG_WNM -DCONFIG_WNM_AP +OBJS += ../src/ap/wnm_ap.o +endif + +ifdef CONFIG_IEEE80211AC +CFLAGS += -DCONFIG_IEEE80211AC +endif + +ifdef CONFIG_IEEE80211AX +CFLAGS += -DCONFIG_IEEE80211AX +OBJS += ../src/ap/ieee802_11_he.o +endif + +ifdef CONFIG_MBO +CFLAGS += -DCONFIG_MBO +OBJS += ../src/ap/mbo_ap.o +endif + +include ../src/drivers/drivers.mak +OBJS += $(DRV_AP_OBJS) +CFLAGS += $(DRV_AP_CFLAGS) +LDFLAGS += $(DRV_AP_LDFLAGS) +LIBS += $(DRV_AP_LIBS) + +ifdef CONFIG_L2_PACKET +ifdef CONFIG_DNET_PCAP +ifdef CONFIG_L2_FREEBSD +LIBS += -lpcap +OBJS += ../src/l2_packet/l2_packet_freebsd.o +else +LIBS += -ldnet -lpcap +OBJS += ../src/l2_packet/l2_packet_pcap.o +endif +else +OBJS += ../src/l2_packet/l2_packet_linux.o +endif +else +OBJS += ../src/l2_packet/l2_packet_none.o +endif + + +ifdef CONFIG_ERP +CFLAGS += -DCONFIG_ERP +NEED_HMAC_SHA256_KDF=y +endif + +ifdef CONFIG_EAP_MD5 +CFLAGS += -DEAP_SERVER_MD5 +OBJS += ../src/eap_server/eap_server_md5.o +CHAP=y +endif + +ifdef CONFIG_EAP_TLS +CFLAGS += -DEAP_SERVER_TLS +OBJS += ../src/eap_server/eap_server_tls.o +TLS_FUNCS=y +endif + +ifdef CONFIG_EAP_UNAUTH_TLS +CFLAGS += -DEAP_SERVER_UNAUTH_TLS +ifndef CONFIG_EAP_TLS +OBJS += ../src/eap_server/eap_server_tls.o +TLS_FUNCS=y +endif +endif + +ifdef CONFIG_EAP_PEAP +CFLAGS += -DEAP_SERVER_PEAP +OBJS += ../src/eap_server/eap_server_peap.o +OBJS += ../src/eap_common/eap_peap_common.o +TLS_FUNCS=y +CONFIG_EAP_MSCHAPV2=y +endif + +ifdef CONFIG_EAP_TTLS +CFLAGS += -DEAP_SERVER_TTLS +OBJS += ../src/eap_server/eap_server_ttls.o +TLS_FUNCS=y +CHAP=y +endif + +ifdef CONFIG_EAP_MSCHAPV2 +CFLAGS += -DEAP_SERVER_MSCHAPV2 +OBJS += ../src/eap_server/eap_server_mschapv2.o +MS_FUNCS=y +endif + +ifdef CONFIG_EAP_GTC +CFLAGS += -DEAP_SERVER_GTC +OBJS += ../src/eap_server/eap_server_gtc.o +endif + +ifdef CONFIG_EAP_SIM +CFLAGS += -DEAP_SERVER_SIM +OBJS += ../src/eap_server/eap_server_sim.o +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_AKA +CFLAGS += -DEAP_SERVER_AKA +OBJS += ../src/eap_server/eap_server_aka.o +CONFIG_EAP_SIM_COMMON=y +NEED_AES_CBC=y +endif + +ifdef CONFIG_EAP_AKA_PRIME +CFLAGS += -DEAP_SERVER_AKA_PRIME +endif + +ifdef CONFIG_EAP_SIM_COMMON +OBJS += ../src/eap_common/eap_sim_common.o +# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be +# replaced with another file implementing the interface specified in +# eap_sim_db.h. +OBJS += ../src/eap_server/eap_sim_db.o +NEED_FIPS186_2_PRF=y +endif + +ifdef CONFIG_EAP_PAX +CFLAGS += -DEAP_SERVER_PAX +OBJS += ../src/eap_server/eap_server_pax.o ../src/eap_common/eap_pax_common.o +endif + +ifdef CONFIG_EAP_PSK +CFLAGS += -DEAP_SERVER_PSK +OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o +NEED_AES_ENCBLOCK=y +NEED_AES_EAX=y +endif + +ifdef CONFIG_EAP_SAKE +CFLAGS += -DEAP_SERVER_SAKE +OBJS += ../src/eap_server/eap_server_sake.o ../src/eap_common/eap_sake_common.o +endif + +ifdef CONFIG_EAP_GPSK +CFLAGS += -DEAP_SERVER_GPSK +OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o +ifdef CONFIG_EAP_GPSK_SHA256 +CFLAGS += -DEAP_GPSK_SHA256 +endif +endif + +ifdef CONFIG_EAP_PWD +CFLAGS += -DEAP_SERVER_PWD +OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o +NEED_ECC=y +NEED_DRAGONFLY=y +endif + +ifdef CONFIG_EAP_EKE +CFLAGS += -DEAP_SERVER_EKE +OBJS += ../src/eap_server/eap_server_eke.o ../src/eap_common/eap_eke_common.o +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +endif + +ifdef CONFIG_EAP_VENDOR_TEST +CFLAGS += -DEAP_SERVER_VENDOR_TEST +OBJS += ../src/eap_server/eap_server_vendor_test.o +endif + +ifdef CONFIG_EAP_FAST +CFLAGS += -DEAP_SERVER_FAST +OBJS += ../src/eap_server/eap_server_fast.o +OBJS += ../src/eap_common/eap_fast_common.o +TLS_FUNCS=y +NEED_T_PRF=y +NEED_AES_UNWRAP=y +endif + +ifdef CONFIG_EAP_TEAP +CFLAGS += -DEAP_SERVER_TEAP +OBJS += ../src/eap_server/eap_server_teap.o +OBJS += ../src/eap_common/eap_teap_common.o +TLS_FUNCS=y +NEED_T_PRF=y +NEED_SHA384=y +NEED_TLS_PRF_SHA256=y +NEED_TLS_PRF_SHA384=y +NEED_AES_UNWRAP=y +endif + +ifdef CONFIG_WPS +CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC +OBJS += ../src/utils/uuid.o +OBJS += ../src/ap/wps_hostapd.o +OBJS += ../src/eap_server/eap_server_wsc.o ../src/eap_common/eap_wsc_common.o +OBJS += ../src/wps/wps.o +OBJS += ../src/wps/wps_common.o +OBJS += ../src/wps/wps_attr_parse.o +OBJS += ../src/wps/wps_attr_build.o +OBJS += ../src/wps/wps_attr_process.o +OBJS += ../src/wps/wps_dev_attr.o +OBJS += ../src/wps/wps_enrollee.o +OBJS += ../src/wps/wps_registrar.o +NEED_DH_GROUPS=y +NEED_BASE64=y +NEED_AES_CBC=y +NEED_MODEXP=y +CONFIG_EAP=y + +ifdef CONFIG_WPS_NFC +CFLAGS += -DCONFIG_WPS_NFC +OBJS += ../src/wps/ndef.o +NEED_WPS_OOB=y +endif + +ifdef NEED_WPS_OOB +CFLAGS += -DCONFIG_WPS_OOB +endif + +ifdef CONFIG_WPS_UPNP +CFLAGS += -DCONFIG_WPS_UPNP +OBJS += ../src/wps/wps_upnp.o +OBJS += ../src/wps/wps_upnp_ssdp.o +OBJS += ../src/wps/wps_upnp_web.o +OBJS += ../src/wps/wps_upnp_event.o +OBJS += ../src/wps/wps_upnp_ap.o +OBJS += ../src/wps/upnp_xml.o +OBJS += ../src/wps/httpread.o +OBJS += ../src/wps/http_client.o +OBJS += ../src/wps/http_server.o +endif + +ifdef CONFIG_WPS_STRICT +CFLAGS += -DCONFIG_WPS_STRICT +OBJS += ../src/wps/wps_validate.o +endif + +ifdef CONFIG_WPS_TESTING +CFLAGS += -DCONFIG_WPS_TESTING +endif + +endif + +ifdef CONFIG_DPP +CFLAGS += -DCONFIG_DPP +OBJS += ../src/common/dpp.o +OBJS += ../src/common/dpp_auth.o +OBJS += ../src/common/dpp_backup.o +OBJS += ../src/common/dpp_crypto.o +OBJS += ../src/common/dpp_pkex.o +OBJS += ../src/common/dpp_reconfig.o +OBJS += ../src/common/dpp_tcp.o +OBJS += ../src/ap/dpp_hostapd.o +OBJS += ../src/ap/gas_query_ap.o +NEED_AES_SIV=y +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_HMAC_SHA512_KDF=y +NEED_SHA384=y +NEED_SHA512=y +NEED_ECC=y +NEED_JSON=y +NEED_GAS=y +NEED_BASE64=y +NEED_ASN1=y +ifdef CONFIG_DPP2 +CFLAGS += -DCONFIG_DPP2 +endif +endif + +ifdef CONFIG_PASN +CFLAGS += -DCONFIG_PASN +CFLAGS += -DCONFIG_PTKSA_CACHE +NEED_HMAC_SHA256_KDF=y +NEED_HMAC_SHA384_KDF=y +NEED_SHA256=y +NEED_SHA384=y +OBJS += ../src/common/ptksa_cache.o +endif + +ifdef CONFIG_EAP_IKEV2 +CFLAGS += -DEAP_SERVER_IKEV2 +OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o +OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o +NEED_DH_GROUPS=y +NEED_DH_GROUPS_ALL=y +NEED_MODEXP=y +NEED_CIPHER=y +endif + +ifdef CONFIG_EAP_TNC +CFLAGS += -DEAP_SERVER_TNC +OBJS += ../src/eap_server/eap_server_tnc.o +OBJS += ../src/eap_server/tncs.o +NEED_BASE64=y +ifndef CONFIG_DRIVER_BSD +LIBS += -ldl +endif +endif + +ifdef CONFIG_MACSEC +CFLAGS += -DCONFIG_MACSEC +OBJS += ../src/ap/wpa_auth_kay.o +OBJS += ../src/pae/ieee802_1x_cp.o +OBJS += ../src/pae/ieee802_1x_kay.o +OBJS += ../src/pae/ieee802_1x_key.o +OBJS += ../src/pae/ieee802_1x_secy_ops.o +endif + +# Basic EAP functionality is needed for EAPOL +OBJS += eap_register.o +OBJS += ../src/eap_server/eap_server.o +OBJS += ../src/eap_common/eap_common.o +OBJS += ../src/eap_server/eap_server_methods.o +OBJS += ../src/eap_server/eap_server_identity.o +CFLAGS += -DEAP_SERVER_IDENTITY + +ifdef CONFIG_EAP +CFLAGS += -DEAP_SERVER +endif + +ifdef CONFIG_PKCS12 +CFLAGS += -DPKCS12_FUNCS +endif + +ifdef NEED_DRAGONFLY +OBJS += ../src/common/dragonfly.o +endif + +ifdef MS_FUNCS +OBJS += ../src/crypto/ms_funcs.o +NEED_DES=y +NEED_MD4=y +endif + +ifdef CHAP +OBJS += ../src/eap_common/chap.o +endif + +ifdef TLS_FUNCS +NEED_DES=y +# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS) +CFLAGS += -DEAP_TLS_FUNCS +OBJS += ../src/eap_server/eap_server_tls_common.o +NEED_TLS_PRF=y +endif + +ifndef CONFIG_TLS +CONFIG_TLS=openssl +endif + +ifdef CONFIG_TLSV11 +CFLAGS += -DCONFIG_TLSV11 +endif + +ifdef CONFIG_TLSV12 +CFLAGS += -DCONFIG_TLSV12 +endif + +ifeq ($(CONFIG_TLS), wolfssl) +CONFIG_CRYPTO=wolfssl +ifdef TLS_FUNCS +OBJS += ../src/crypto/tls_wolfssl.o +LIBS += -lwolfssl -lm +endif +OBJS += ../src/crypto/crypto_wolfssl.o +HOBJS += ../src/crypto/crypto_wolfssl.o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_wolfssl.o +endif +NEED_TLS_PRF_SHA256=y +LIBS += -lwolfssl -lm +LIBS_h += -lwolfssl -lm +ifdef CONFIG_TLS_ADD_DL +LIBS += -ldl +LIBS_h += -ldl +endif +endif + +ifeq ($(CONFIG_TLS), openssl) +CONFIG_CRYPTO=openssl +ifdef TLS_FUNCS +OBJS += ../src/crypto/tls_openssl.o +OBJS += ../src/crypto/tls_openssl_ocsp.o +LIBS += -lssl +endif +OBJS += ../src/crypto/crypto_openssl.o +HOBJS += ../src/crypto/crypto_openssl.o +SOBJS += ../src/crypto/crypto_openssl.o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_openssl.o +endif +NEED_TLS_PRF_SHA256=y +LIBS += -lcrypto +LIBS_h += -lcrypto +LIBS_n += -lcrypto +LIBS_s += -lcrypto +ifdef CONFIG_TLS_ADD_DL +LIBS += -ldl +LIBS_h += -ldl +LIBS_s += -ldl +endif +ifndef CONFIG_TLS_DEFAULT_CIPHERS +CONFIG_TLS_DEFAULT_CIPHERS = "DEFAULT:!EXP:!LOW" +endif +CFLAGS += -DTLS_DEFAULT_CIPHERS=\"$(CONFIG_TLS_DEFAULT_CIPHERS)\" +endif + +ifeq ($(CONFIG_TLS), gnutls) +ifndef CONFIG_CRYPTO +# default to libgcrypt +CONFIG_CRYPTO=gnutls +endif +ifdef TLS_FUNCS +OBJS += ../src/crypto/tls_gnutls.o +LIBS += -lgnutls -lgpg-error +endif +OBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +HOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_internal.o +SHA1OBJS += ../src/crypto/sha1-internal.o +endif +ifeq ($(CONFIG_CRYPTO), gnutls) +LIBS += -lgcrypt +LIBS_h += -lgcrypt +LIBS_n += -lgcrypt +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), nettle) +LIBS += -lnettle -lgmp +LIBS_p += -lnettle -lgmp +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +endif + +ifeq ($(CONFIG_TLS), internal) +ifndef CONFIG_CRYPTO +CONFIG_CRYPTO=internal +endif +ifdef TLS_FUNCS +OBJS += ../src/crypto/crypto_internal-rsa.o +OBJS += ../src/crypto/tls_internal.o +OBJS += ../src/tls/tlsv1_common.o +OBJS += ../src/tls/tlsv1_record.o +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/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 +NEED_TLS_PRF_SHA256=y +endif +NEED_MODEXP=y +NEED_CIPHER=y +CFLAGS += -DCONFIG_TLS_INTERNAL +CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER +endif +ifdef NEED_CIPHER +NEED_DES=y +OBJS += ../src/crypto/crypto_internal-cipher.o +endif +ifdef NEED_MODEXP +OBJS += ../src/crypto/crypto_internal-modexp.o +OBJS += ../src/tls/bignum.o +endif +ifeq ($(CONFIG_CRYPTO), libtomcrypt) +OBJS += ../src/crypto/crypto_libtomcrypt.o +LIBS += -ltomcrypt -ltfm +LIBS_h += -ltomcrypt -ltfm +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), internal) +OBJS += ../src/crypto/crypto_internal.o +NEED_AES_DEC=y +CFLAGS += -DCONFIG_CRYPTO_INTERNAL +ifdef CONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST +CFLAGS += -DLTM_FAST +endif +else +LIBS += -ltommath +LIBS_h += -ltommath +endif +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_DES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD4=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_SHA384=y +CONFIG_INTERNAL_SHA512=y +CONFIG_INTERNAL_RC4=y +CONFIG_INTERNAL_DH_GROUP5=y +endif +ifeq ($(CONFIG_CRYPTO), cryptoapi) +OBJS += ../src/crypto/crypto_cryptoapi.o +OBJS_p += ../src/crypto/crypto_cryptoapi.o +CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif +endif + +ifeq ($(CONFIG_TLS), linux) +OBJS += ../src/crypto/crypto_linux.o +ifdef TLS_FUNCS +OBJS += ../src/crypto/crypto_internal-rsa.o +OBJS += ../src/crypto/tls_internal.o +OBJS += ../src/tls/tlsv1_common.o +OBJS += ../src/tls/tlsv1_record.o +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/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 +NEED_TLS_PRF_SHA256=y +endif +NEED_MODEXP=y +NEED_CIPHER=y +CFLAGS += -DCONFIG_TLS_INTERNAL +CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER +endif +ifdef NEED_MODEXP +OBJS += ../src/crypto/crypto_internal-modexp.o +OBJS += ../src/tls/bignum.o +CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +CFLAGS += -DLTM_FAST +endif +CONFIG_INTERNAL_DH_GROUP5=y +ifdef NEED_FIPS186_2_PRF +OBJS += ../src/crypto/fips_prf_internal.o +OBJS += ../src/crypto/sha1-internal.o +endif +endif + +ifeq ($(CONFIG_TLS), none) +ifdef TLS_FUNCS +OBJS += ../src/crypto/tls_none.o +CFLAGS += -DEAP_TLS_NONE +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +endif +OBJS += ../src/crypto/crypto_none.o +OBJS_p += ../src/crypto/crypto_none.o +CONFIG_INTERNAL_SHA256=y +CONFIG_INTERNAL_RC4=y +endif + +ifndef TLS_FUNCS +OBJS += ../src/crypto/tls_none.o +ifeq ($(CONFIG_TLS), internal) +CONFIG_INTERNAL_AES=y +CONFIG_INTERNAL_SHA1=y +CONFIG_INTERNAL_MD5=y +CONFIG_INTERNAL_RC4=y +endif +endif + +AESOBJS = # none so far +ifdef CONFIG_INTERNAL_AES +AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o +endif + +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) +AESOBJS += ../src/crypto/aes-wrap.o +endif +endif +ifdef NEED_AES_EAX +AESOBJS += ../src/crypto/aes-eax.o +NEED_AES_CTR=y +endif +ifdef NEED_AES_SIV +AESOBJS += ../src/crypto/aes-siv.o +NEED_AES_CTR=y +endif +ifdef NEED_AES_CTR +AESOBJS += ../src/crypto/aes-ctr.o +endif +ifdef NEED_AES_ENCBLOCK +AESOBJS += ../src/crypto/aes-encblock.o +endif +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) +AESOBJS += ../src/crypto/aes-omac1.o +endif +endif +ifdef NEED_AES_UNWRAP +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) +NEED_AES_DEC=y +AESOBJS += ../src/crypto/aes-unwrap.o +endif +endif +endif +endif +ifdef NEED_AES_CBC +NEED_AES_DEC=y +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) +AESOBJS += ../src/crypto/aes-cbc.o +endif +endif +endif +endif +ifdef NEED_AES_DEC +ifdef CONFIG_INTERNAL_AES +AESOBJS += ../src/crypto/aes-internal-dec.o +endif +endif +ifdef NEED_AES +OBJS += $(AESOBJS) +endif + +ifdef NEED_SHA1 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +SHA1OBJS += ../src/crypto/sha1.o +endif +endif +endif +endif +SHA1OBJS += ../src/crypto/sha1-prf.o +ifdef CONFIG_INTERNAL_SHA1 +SHA1OBJS += ../src/crypto/sha1-internal.o +ifdef NEED_FIPS186_2_PRF +SHA1OBJS += ../src/crypto/fips_prf_internal.o +endif +endif +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), wolfssl) +SHA1OBJS += ../src/crypto/sha1-pbkdf2.o +endif +endif +ifdef NEED_T_PRF +SHA1OBJS += ../src/crypto/sha1-tprf.o +endif +ifdef NEED_TLS_PRF +SHA1OBJS += ../src/crypto/sha1-tlsprf.o +endif +endif + +ifdef NEED_SHA1 +OBJS += $(SHA1OBJS) +endif + +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +OBJS += ../src/crypto/md5.o +endif +endif +endif +endif + +ifdef NEED_MD5 +ifdef CONFIG_INTERNAL_MD5 +OBJS += ../src/crypto/md5-internal.o +HOBJS += ../src/crypto/md5-internal.o +endif +endif + +ifdef NEED_MD4 +ifdef CONFIG_INTERNAL_MD4 +OBJS += ../src/crypto/md4-internal.o +endif +endif + +ifdef NEED_DES +CFLAGS += -DCONFIG_DES +ifdef CONFIG_INTERNAL_DES +OBJS += ../src/crypto/des-internal.o +endif +endif + +ifdef CONFIG_NO_RC4 +CFLAGS += -DCONFIG_NO_RC4 +endif + +ifdef NEED_RC4 +ifdef CONFIG_INTERNAL_RC4 +ifndef CONFIG_NO_RC4 +OBJS += ../src/crypto/rc4.o +endif +endif +endif + +CFLAGS += -DCONFIG_SHA256 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +OBJS += ../src/crypto/sha256.o +endif +endif +endif +endif +OBJS += ../src/crypto/sha256-prf.o +ifdef CONFIG_INTERNAL_SHA256 +OBJS += ../src/crypto/sha256-internal.o +endif +ifdef NEED_TLS_PRF_SHA256 +OBJS += ../src/crypto/sha256-tlsprf.o +endif +ifdef NEED_TLS_PRF_SHA384 +OBJS += ../src/crypto/sha384-tlsprf.o +endif +ifdef NEED_HMAC_SHA256_KDF +OBJS += ../src/crypto/sha256-kdf.o +endif +ifdef NEED_HMAC_SHA384_KDF +OBJS += ../src/crypto/sha384-kdf.o +endif +ifdef NEED_HMAC_SHA512_KDF +OBJS += ../src/crypto/sha512-kdf.o +endif +ifdef NEED_SHA384 +CFLAGS += -DCONFIG_SHA384 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +OBJS += ../src/crypto/sha384.o +endif +endif +endif +endif +OBJS += ../src/crypto/sha384-prf.o +endif +ifdef NEED_SHA512 +CFLAGS += -DCONFIG_SHA512 +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), gnutls) +ifneq ($(CONFIG_TLS), wolfssl) +OBJS += ../src/crypto/sha512.o +endif +endif +endif +endif +OBJS += ../src/crypto/sha512-prf.o +endif + +ifdef CONFIG_INTERNAL_SHA384 +CFLAGS += -DCONFIG_INTERNAL_SHA384 +OBJS += ../src/crypto/sha384-internal.o +endif + +ifdef CONFIG_INTERNAL_SHA512 +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 +ifdef NEED_DH_GROUPS_ALL +CFLAGS += -DALL_DH_GROUPS +endif +ifdef CONFIG_INTERNAL_DH_GROUP5 +ifdef NEED_DH_GROUPS +OBJS += ../src/crypto/dh_group5.o +endif +endif + +ifdef NEED_ECC +CFLAGS += -DCONFIG_ECC +endif + +ifdef CONFIG_NO_RANDOM_POOL +CFLAGS += -DCONFIG_NO_RANDOM_POOL +else +ifdef CONFIG_GETRANDOM +CFLAGS += -DCONFIG_GETRANDOM +endif +OBJS += ../src/crypto/random.o +HOBJS += ../src/crypto/random.o +HOBJS += ../src/utils/eloop.o +HOBJS += $(SHA1OBJS) +ifneq ($(CONFIG_TLS), openssl) +ifneq ($(CONFIG_TLS), linux) +ifneq ($(CONFIG_TLS), wolfssl) +HOBJS += ../src/crypto/md5.o +endif +endif +endif +endif + +ifdef CONFIG_RADIUS_SERVER +CFLAGS += -DRADIUS_SERVER +OBJS += ../src/radius/radius_server.o +endif + +ifdef CONFIG_IPV6 +CFLAGS += -DCONFIG_IPV6 +endif + +ifdef CONFIG_DRIVER_RADIUS_ACL +CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL +endif + +ifdef NEED_BASE64 +OBJS += ../src/utils/base64.o +endif + +ifdef NEED_JSON +OBJS += ../src/utils/json.o +CFLAGS += -DCONFIG_JSON +endif + +ifdef NEED_AP_MLME +OBJS += ../src/ap/wmm.o +OBJS += ../src/ap/ap_list.o +OBJS += ../src/ap/ieee802_11.o +OBJS += ../src/ap/hw_features.o +OBJS += ../src/ap/dfs.o +CFLAGS += -DNEED_AP_MLME +endif +OBJS += ../src/ap/ieee802_11_ht.o + +ifdef CONFIG_IEEE80211AC +OBJS += ../src/ap/ieee802_11_vht.o +endif + +ifdef CONFIG_P2P_MANAGER +CFLAGS += -DCONFIG_P2P_MANAGER +OBJS += ../src/ap/p2p_hostapd.o +endif + +ifdef CONFIG_HS20 +CFLAGS += -DCONFIG_HS20 +OBJS += ../src/ap/hs20.o +CONFIG_INTERWORKING=y +endif + +ifdef CONFIG_INTERWORKING +CFLAGS += -DCONFIG_INTERWORKING +NEED_GAS=y +endif + +ifdef NEED_GAS +OBJS += ../src/common/gas.o +OBJS += ../src/ap/gas_serv.o +endif + +ifdef CONFIG_PROXYARP +CFLAGS += -DCONFIG_PROXYARP +OBJS += ../src/ap/x_snoop.o +OBJS += ../src/ap/dhcp_snoop.o +ifdef CONFIG_IPV6 +OBJS += ../src/ap/ndisc_snoop.o +endif +endif + +OBJS += ../src/drivers/driver_common.o + +ifdef CONFIG_WPA_CLI_EDIT +OBJS_c += ../src/utils/edit.o +else +OBJS_c += ../src/utils/edit_simple.o +endif + +ifdef CONFIG_ACS +CFLAGS += -DCONFIG_ACS +OBJS += ../src/ap/acs.o +LIBS += -lm +endif + +ifdef CONFIG_NO_STDOUT_DEBUG +CFLAGS += -DCONFIG_NO_STDOUT_DEBUG +endif + +ifdef CONFIG_DEBUG_SYSLOG +CFLAGS += -DCONFIG_DEBUG_SYSLOG +endif + +ifdef CONFIG_DEBUG_LINUX_TRACING +CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING +endif + +ifdef CONFIG_DEBUG_FILE +CFLAGS += -DCONFIG_DEBUG_FILE +endif + +ifdef CONFIG_SQLITE +CFLAGS += -DCONFIG_SQLITE +LIBS += -lsqlite3 +LIBS_h += -lsqlite3 +endif + +ifdef CONFIG_FST +CFLAGS += -DCONFIG_FST +OBJS += ../src/fst/fst.o +OBJS += ../src/fst/fst_group.o +OBJS += ../src/fst/fst_iface.o +OBJS += ../src/fst/fst_session.o +OBJS += ../src/fst/fst_ctrl_aux.o +ifdef CONFIG_FST_TEST +CFLAGS += -DCONFIG_FST_TEST +endif +ifndef CONFIG_NO_CTRL_IFACE +OBJS += ../src/fst/fst_ctrl_iface.o +endif +endif + +ifdef CONFIG_WEP +CFLAGS += -DCONFIG_WEP +endif + +ifdef CONFIG_NO_TKIP +CFLAGS += -DCONFIG_NO_TKIP +endif + +$(DESTDIR)$(BINDIR)/%: % + install -D $(<) $(@) + +install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL)) + +_OBJS_VAR := OBJS +include ../src/objs.mk + +hostapd: $(OBJS) + $(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS) + @$(E) " LD " $@ + +ifdef CONFIG_WPA_TRACE +OBJS_c += ../src/utils/trace.o +endif + +_OBJS_VAR := OBJS_c +include ../src/objs.mk + +hostapd_cli: $(OBJS_c) + $(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c) + @$(E) " LD " $@ + +NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) +NOBJS += ../src/utils/common.o +ifdef NEED_RC4 +ifdef CONFIG_INTERNAL_RC4 +ifndef CONFIG_NO_RC4 +NOBJS += ../src/crypto/rc4.o +endif +endif +endif +ifdef CONFIG_INTERNAL_MD5 +NOBJS += ../src/crypto/md5-internal.o +endif +NOBJS += ../src/crypto/crypto_$(CONFIG_CRYPTO).o +NOBJS += ../src/utils/os_$(CONFIG_OS).o +NOBJS += ../src/utils/wpa_debug.o +NOBJS += ../src/utils/wpabuf.o +ifdef CONFIG_WPA_TRACE +NOBJS += ../src/utils/trace.o +endif + +HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o +HOBJS += ../src/crypto/aes-encblock.o +ifdef CONFIG_INTERNAL_AES +HOBJS += ../src/crypto/aes-internal.o +HOBJS += ../src/crypto/aes-internal-enc.o +endif +ifeq ($(CONFIG_TLS), linux) +HOBJS += ../src/crypto/crypto_linux.o +endif + +SOBJS += sae_pk_gen.o +SOBJS += ../src/utils/common.o +SOBJS += ../src/utils/os_$(CONFIG_OS).o +SOBJS += ../src/utils/base64.o +SOBJS += ../src/utils/wpa_debug.o +SOBJS += ../src/utils/wpabuf.o +ifdef CONFIG_WPA_TRACE +SOBJS += ../src/utils/trace.o +endif +SOBJS += ../src/common/ieee802_11_common.o +SOBJS += ../src/common/sae.o +SOBJS += ../src/common/sae_pk.o +SOBJS += ../src/common/dragonfly.o +SOBJS += $(AESOBJS) +SOBJS += ../src/crypto/sha256-prf.o +SOBJS += ../src/crypto/sha384-prf.o +SOBJS += ../src/crypto/sha512-prf.o +SOBJS += ../src/crypto/dh_groups.o +SOBJS += ../src/crypto/sha256-kdf.o +SOBJS += ../src/crypto/sha384-kdf.o +SOBJS += ../src/crypto/sha512-kdf.o + +_OBJS_VAR := NOBJS +include ../src/objs.mk +_OBJS_VAR := HOBJS +include ../src/objs.mk +_OBJS_VAR := SOBJS +include ../src/objs.mk + +nt_password_hash: $(NOBJS) + $(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n) + @$(E) " LD " $@ + +hlr_auc_gw: $(HOBJS) + $(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h) + @$(E) " LD " $@ + +sae_pk_gen: $(SOBJS) + $(Q)$(CC) $(LDFLAGS) -o sae_pk_gen $(SOBJS) $(LIBS_s) + @$(E) " LD " $@ + +.PHONY: lcov-html +lcov-html: + lcov -c -d $(BUILDDIR) > lcov.info + genhtml lcov.info --output-directory lcov-html + +clean: common-clean + rm -f core *~ nt_password_hash hlr_auc_gw + rm -f sae_pk_gen + rm -f lcov.info + rm -rf lcov-html diff --git a/contrib/wpa/hostapd/android.config b/contrib/wpa/hostapd/android.config new file mode 100644 index 000000000000..c8b3afabef8d --- /dev/null +++ b/contrib/wpa/hostapd/android.config @@ -0,0 +1,214 @@ +# Example hostapd build time configuration +# +# This file lists the configuration options that are used when building the +# hostapd binary. All lines starting with # are ignored. Configuration option +# lines must be commented out complete, if they are not to be included, i.e., +# just setting VARIABLE=n is not disabling that variable. +# +# This file is included in Makefile, so variables like CFLAGS and LIBS can also +# be modified from here. In most cass, these lines should use += in order not +# to override previous values of the variables. + +# Driver interface for Host AP driver +#CONFIG_DRIVER_HOSTAP=y + +# Driver interface for wired authenticator +#CONFIG_DRIVER_WIRED=y + +# Driver interface for drivers using the nl80211 kernel interface +#CONFIG_DRIVER_NL80211=y +# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be +# shipped with your distribution yet. If that is the case, you need to build +# newer libnl version and point the hostapd build to use it. +#LIBNL=/usr/src/libnl +#CFLAGS += -I$(LIBNL)/include +#LIBS += -L$(LIBNL)/lib +CONFIG_LIBNL20=y + +# QCA vendor extensions to nl80211 +CONFIG_DRIVER_NL80211_QCA=y + +# Broadcom vendor extensions to nl80211 +#CONFIG_DRIVER_NL80211_BRCM=y + +# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) +#CONFIG_DRIVER_BSD=y +#CFLAGS += -I/usr/local/include +#LIBS += -L/usr/local/lib +#LIBS_p += -L/usr/local/lib +#LIBS_c += -L/usr/local/lib + +# Driver interface for no driver (e.g., RADIUS server only) +#CONFIG_DRIVER_NONE=y + +# WPA2/IEEE 802.11i RSN pre-authentication +#CONFIG_RSN_PREAUTH=y + +# Support Operating Channel Validation +#CONFIG_OCV=y + +# Integrated EAP server +#CONFIG_EAP=y + +# EAP-MD5 for the integrated EAP server +#CONFIG_EAP_MD5=y + +# EAP-TLS for the integrated EAP server +#CONFIG_EAP_TLS=y + +# EAP-MSCHAPv2 for the integrated EAP server +#CONFIG_EAP_MSCHAPV2=y + +# EAP-PEAP for the integrated EAP server +#CONFIG_EAP_PEAP=y + +# EAP-GTC for the integrated EAP server +#CONFIG_EAP_GTC=y + +# EAP-TTLS for the integrated EAP server +#CONFIG_EAP_TTLS=y + +# EAP-SIM for the integrated EAP server +#CONFIG_EAP_SIM=y + +# EAP-AKA for the integrated EAP server +#CONFIG_EAP_AKA=y + +# EAP-AKA' for the integrated EAP server +# This requires CONFIG_EAP_AKA to be enabled, too. +#CONFIG_EAP_AKA_PRIME=y + +# EAP-PAX for the integrated EAP server +#CONFIG_EAP_PAX=y + +# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK) +#CONFIG_EAP_PSK=y + +# EAP-SAKE for the integrated EAP server +#CONFIG_EAP_SAKE=y + +# EAP-GPSK for the integrated EAP server +#CONFIG_EAP_GPSK=y +# Include support for optional SHA256 cipher suite in EAP-GPSK +#CONFIG_EAP_GPSK_SHA256=y + +# EAP-FAST for the integrated EAP server +# Note: Default OpenSSL package does not include support for all the +# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL, +# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch) +# to add the needed functions. +#CONFIG_EAP_FAST=y + +# Wi-Fi Protected Setup (WPS) +CONFIG_WPS=y +# Enable UPnP support for external WPS Registrars +#CONFIG_WPS_UPNP=y + +# EAP-IKEv2 +#CONFIG_EAP_IKEV2=y + +# Trusted Network Connect (EAP-TNC) +#CONFIG_EAP_TNC=y + +# PKCS#12 (PFX) support (used to read private key and certificate file from +# a file that usually has extension .p12 or .pfx) +CONFIG_PKCS12=y + +# RADIUS authentication server. This provides access to the integrated EAP +# server from external hosts using RADIUS. +#CONFIG_RADIUS_SERVER=y + +# Build IPv6 support for RADIUS operations +CONFIG_IPV6=y + +# IEEE Std 802.11r-2008 (Fast BSS Transition) +#CONFIG_IEEE80211R=y + +# Use the hostapd's IEEE 802.11 authentication (ACL), but without +# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211) +#CONFIG_DRIVER_RADIUS_ACL=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. +#CONFIG_NO_STDOUT_DEBUG=y + +# Add support for writing debug log to Android logcat instead of standard output +CONFIG_ANDROID_LOG=y + +# Remove support for RADIUS accounting +#CONFIG_NO_ACCOUNTING=y + +# Remove support for RADIUS +CONFIG_NO_RADIUS=y + +# Remove support for VLANs +#CONFIG_NO_VLAN=y + +# Remove support for dumping internal state through control interface commands +# This can be used to reduce binary size at the cost of disabling a debugging +# option. +#CONFIG_NO_DUMP_STATE=y + +# Select wrapper for operatins system and C library specific functions +# unix = UNIX/POSIX like systems (default) +# win32 = Windows systems +# none = Empty template +CONFIG_OS=unix + +# Enable tracing code for developer debugging +# This tracks use of memory allocations and other registrations and reports +# incorrect use with a backtrace of call (or allocation) location. +#CONFIG_WPA_TRACE=y +# For BSD, comment out these. +#LIBS += -lexecinfo +#LIBS_p += -lexecinfo +#LIBS_c += -lexecinfo + +# Use libbfd to get more details for developer debugging +# This enables use of libbfd to get more detailed symbols for the backtraces +# generated by CONFIG_WPA_TRACE=y. +#CONFIG_WPA_TRACE_BFD=y +# For BSD, comment out these. +#LIBS += -lbfd -liberty -lz +#LIBS_p += -lbfd -liberty -lz +#LIBS_c += -lbfd -liberty -lz + +# Should we use poll instead of select? Select is used by default. +#CONFIG_ELOOP_POLL=y + +# Should we use epoll instead of select? Select is used by default. +#CONFIG_ELOOP_EPOLL=y + +# Enable AP +CONFIG_AP=y + +# Enable Fast Session Transfer (FST) +#CONFIG_FST=y + +# Multiband Operation support +# These extensions facilitate efficient use of multiple frequency bands +# available to the AP and the devices that may associate with it. +#CONFIG_MBO=y + +# Include internal line edit mode in hostapd_cli. +CONFIG_WPA_CLI_EDIT=y + +# Opportunistic Wireless Encryption (OWE) +# Experimental implementation of draft-harkins-owe-07.txt +#CONFIG_OWE=y + +# Wpa_supplicant's random pool is not necessary on Android. Randomness is +# already provided by the entropymixer service which ensures sufficient +# entropy is maintained across reboots. Commit b410eb1913 'Initialize +# /dev/urandom earlier in boot' seeds /dev/urandom with that entropy before +# either wpa_supplicant or hostapd are run. +CONFIG_NO_RANDOM_POOL=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/contrib/wpa/hostapd/config_file.c b/contrib/wpa/hostapd/config_file.c index e09e6e141ba4..9bc1dc7756e9 100644 --- a/contrib/wpa/hostapd/config_file.c +++ b/contrib/wpa/hostapd/config_file.c @@ -14,6 +14,7 @@ #include "utils/common.h" #include "utils/uuid.h" #include "common/ieee802_11_defs.h" +#include "common/sae.h" #include "crypto/sha256.h" #include "crypto/tls.h" #include "drivers/driver.h" @@ -340,7 +341,7 @@ static int hostapd_config_read_eap_user(const char *fname, struct hostapd_radius_attr *attr, *a; attr = hostapd_parse_radius_attr(buf + 19); if (attr == NULL) { - wpa_printf(MSG_ERROR, "Invalid radius_auth_req_attr: %s", + wpa_printf(MSG_ERROR, "Invalid radius_accept_attr: %s", buf + 19); user = NULL; /* already in the BSS list */ goto failed; @@ -711,12 +712,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value) val |= WPA_KEY_MGMT_FT_IEEE8021X_SHA384; #endif /* CONFIG_SHA384 */ #endif /* CONFIG_IEEE80211R_AP */ -#ifdef CONFIG_IEEE80211W else if (os_strcmp(start, "WPA-PSK-SHA256") == 0) val |= WPA_KEY_MGMT_PSK_SHA256; else if (os_strcmp(start, "WPA-EAP-SHA256") == 0) val |= WPA_KEY_MGMT_IEEE8021X_SHA256; -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE else if (os_strcmp(start, "SAE") == 0) val |= WPA_KEY_MGMT_SAE; @@ -755,6 +754,10 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value) else if (os_strcmp(start, "OSEN") == 0) val |= WPA_KEY_MGMT_OSEN; #endif /* CONFIG_HS20 */ +#ifdef CONFIG_PASN + else if (os_strcmp(start, "PASN") == 0) + val |= WPA_KEY_MGMT_PASN; +#endif /* CONFIG_PASN */ else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", line, start); @@ -795,6 +798,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) { @@ -845,6 +849,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) @@ -942,104 +947,6 @@ static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname) } -/* convert floats with one decimal place to value*10 int, i.e., - * "1.5" will return 15 */ -static int hostapd_config_read_int10(const char *value) -{ - int i, d; - char *pos; - - i = atoi(value); - pos = os_strchr(value, '.'); - d = 0; - if (pos) { - pos++; - if (*pos >= '0' && *pos <= '9') - d = *pos - '0'; - } - - return i * 10 + d; -} - - -static int valid_cw(int cw) -{ - return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 || - cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 || - cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 || - cw == 32767); -} - - -enum { - IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */ - IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */ - IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */ - IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */ -}; - -static int hostapd_config_tx_queue(struct hostapd_config *conf, - const char *name, const char *val) -{ - int num; - const char *pos; - struct hostapd_tx_queue_params *queue; - - /* skip 'tx_queue_' prefix */ - pos = name + 9; - if (os_strncmp(pos, "data", 4) == 0 && - pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') { - num = pos[4] - '0'; - pos += 6; - } else if (os_strncmp(pos, "after_beacon_", 13) == 0 || - os_strncmp(pos, "beacon_", 7) == 0) { - wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); - return 0; - } else { - wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos); - return -1; - } - - if (num >= NUM_TX_QUEUES) { - /* for backwards compatibility, do not trigger failure */ - wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name); - return 0; - } - - queue = &conf->tx_queue[num]; - - if (os_strcmp(pos, "aifs") == 0) { - queue->aifs = atoi(val); - if (queue->aifs < 0 || queue->aifs > 255) { - wpa_printf(MSG_ERROR, "Invalid AIFS value %d", - queue->aifs); - return -1; - } - } else if (os_strcmp(pos, "cwmin") == 0) { - queue->cwmin = atoi(val); - if (!valid_cw(queue->cwmin)) { - wpa_printf(MSG_ERROR, "Invalid cwMin value %d", - queue->cwmin); - return -1; - } - } else if (os_strcmp(pos, "cwmax") == 0) { - queue->cwmax = atoi(val); - if (!valid_cw(queue->cwmax)) { - wpa_printf(MSG_ERROR, "Invalid cwMax value %d", - queue->cwmax); - return -1; - } - } else if (os_strcmp(pos, "burst") == 0) { - queue->burst = hostapd_config_read_int10(val); - } else { - wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos); - return -1; - } - - return 0; -} - - #ifdef CONFIG_IEEE80211R_AP static int rkh_derive_key(const char *pos, u8 *key, size_t key_len) @@ -1153,7 +1060,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) { @@ -1173,14 +1079,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]")) @@ -1214,7 +1112,6 @@ static int hostapd_config_ht_capab(struct hostapd_config *conf, return 0; } -#endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211AC @@ -1323,6 +1220,32 @@ static u8 set_he_cap(int val, u8 mask) return (u8) (mask & (val << find_bit_offset(mask))); } + +static int hostapd_parse_he_srg_bitmap(u8 *bitmap, char *val) +{ + int bitpos; + char *pos, *end; + + os_memset(bitmap, 0, 8); + pos = val; + while (*pos != '\0') { + end = os_strchr(pos, ' '); + if (end) + *end = '\0'; + + bitpos = atoi(pos); + if (bitpos < 0 || bitpos > 64) + return -1; + + bitmap[bitpos / 8] |= BIT(bitpos % 8); + if (!end) + break; + pos = end + 1; + } + + return 0; +} + #endif /* CONFIG_IEEE80211AX */ @@ -2300,6 +2223,35 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val) pw->vlan_id = atoi(pos2); } +#ifdef CONFIG_SAE_PK + pos2 = os_strstr(pos, "|pk="); + if (pos2) { + const char *epos; + char *tmp; + + if (!end) + end = pos2; + pos2 += 4; + epos = os_strchr(pos2, '|'); + if (epos) { + tmp = os_malloc(epos - pos2 + 1); + if (!tmp) + goto fail; + os_memcpy(tmp, pos2, epos - pos2); + tmp[epos - pos2] = '\0'; + } else { + tmp = os_strdup(pos2); + if (!tmp) + goto fail; + } + + pw->pk = sae_parse_pk(tmp); + str_clear_free(tmp); + if (!pw->pk) + goto fail; + } +#endif /* CONFIG_SAE_PK */ + pos2 = os_strstr(pos, "|id="); if (pos2) { if (!end) @@ -2322,6 +2274,18 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val) pw->password[end - val] = '\0'; } +#ifdef CONFIG_SAE_PK + if (pw->pk && +#ifdef CONFIG_TESTING_OPTIONS + !bss->sae_pk_password_check_skip && +#endif /* CONFIG_TESTING_OPTIONS */ + !sae_pk_valid_password(pw->password)) { + wpa_printf(MSG_INFO, + "Invalid SAE password for a SAE-PK sae_password entry"); + goto fail; + } +#endif /* CONFIG_SAE_PK */ + pw->next = bss->sae_passwords; bss->sae_passwords = pw; @@ -2329,6 +2293,9 @@ static int parse_sae_password(struct hostapd_bss_config *bss, const char *val) fail: str_clear_free(pw->password); os_free(pw->identifier); +#ifdef CONFIG_SAE_PK + sae_deinit_pk(pw->pk); +#endif /* CONFIG_SAE_PK */ os_free(pw); return -1; } @@ -2365,6 +2332,22 @@ fail: #endif /* CONFIG_DPP2 */ +static int get_hex_config(u8 *buf, size_t max_len, int line, + const char *field, const char *val) +{ + size_t hlen = os_strlen(val), len = hlen / 2; + u8 tmp[EXT_CAPA_MAX_LEN]; + + os_memset(tmp, 0, EXT_CAPA_MAX_LEN); + if (hlen & 1 || len > EXT_CAPA_MAX_LEN || hexstr2bin(val, tmp, len)) { + wpa_printf(MSG_ERROR, "Line %d: Invalid %s", line, field); + return -1; + } + os_memcpy(buf, tmp, EXT_CAPA_MAX_LEN); + return 0; +} + + static int hostapd_config_fill(struct hostapd_config *conf, struct hostapd_bss_config *bss, const char *buf, char *pos, int line) @@ -2473,6 +2456,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); @@ -2484,12 +2474,13 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->ieee802_1x = atoi(pos); } else if (os_strcmp(buf, "eapol_version") == 0) { int eapol_version = atoi(pos); - #ifdef CONFIG_MACSEC - if (eapol_version < 1 || eapol_version > 3) { + int max_ver = 3; #else /* CONFIG_MACSEC */ - if (eapol_version < 1 || eapol_version > 2) { + int max_ver = 2; #endif /* CONFIG_MACSEC */ + + if (eapol_version < 1 || eapol_version > max_ver) { wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL version (%d): '%s'.", line, eapol_version, pos); @@ -2547,6 +2538,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->tls_session_lifetime = atoi(pos); } else if (os_strcmp(buf, "tls_flags") == 0) { bss->tls_flags = parse_tls_flags(pos); + } else if (os_strcmp(buf, "max_auth_rounds") == 0) { + bss->max_auth_rounds = atoi(pos); + } else if (os_strcmp(buf, "max_auth_rounds_short") == 0) { + bss->max_auth_rounds_short = atoi(pos); } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) { os_free(bss->ocsp_stapling_response); bss->ocsp_stapling_response = os_strdup(pos); @@ -2611,7 +2606,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "eap_teap_auth") == 0) { int val = atoi(pos); - if (val < 0 || val > 1) { + if (val < 0 || val > 2) { wpa_printf(MSG_ERROR, "Line %d: Invalid eap_teap_auth value", line); @@ -2620,6 +2615,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->eap_teap_auth = val; } else if (os_strcmp(buf, "eap_teap_pac_no_inner") == 0) { bss->eap_teap_pac_no_inner = atoi(pos); + } else if (os_strcmp(buf, "eap_teap_separate_result") == 0) { + bss->eap_teap_separate_result = atoi(pos); + } else if (os_strcmp(buf, "eap_teap_id") == 0) { + bss->eap_teap_id = atoi(pos); #endif /* EAP_SERVER_TEAP */ #ifdef EAP_SERVER_SIM } else if (os_strcmp(buf, "eap_sim_db") == 0) { @@ -2668,6 +2667,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); @@ -2695,6 +2695,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) { @@ -2706,8 +2707,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->eapol_key_index_workaround = atoi(pos); #ifdef CONFIG_IAPP } else if (os_strcmp(buf, "iapp_interface") == 0) { - bss->ieee802_11f = 1; - os_strlcpy(bss->iapp_iface, pos, sizeof(bss->iapp_iface)); + wpa_printf(MSG_INFO, "DEPRECATED: iapp_interface not used"); #endif /* CONFIG_IAPP */ } else if (os_strcmp(buf, "own_ip_addr") == 0) { if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) { @@ -2728,6 +2728,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, return 1; } bss->radius->force_client_addr = 1; + } else if (os_strcmp(buf, "radius_client_dev") == 0) { + os_free(bss->radius->force_client_dev); + bss->radius->force_client_dev = os_strdup(pos); } else if (os_strcmp(buf, "auth_server_addr") == 0) { if (hostapd_config_read_radius_addr( &bss->radius->auth_servers, @@ -2870,6 +2873,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; @@ -2879,6 +2892,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); @@ -3131,6 +3153,8 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "acs_exclude_dfs") == 0) { conf->acs_exclude_dfs = atoi(pos); + } else if (os_strcmp(buf, "op_class") == 0) { + conf->op_class = atoi(pos); } else if (os_strcmp(buf, "channel") == 0) { if (os_strcmp(pos, "acs_survey") == 0) { #ifndef CONFIG_ACS @@ -3145,12 +3169,25 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->channel = atoi(pos); conf->acs = conf->channel == 0; } + } else if (os_strcmp(buf, "edmg_channel") == 0) { + conf->edmg_channel = atoi(pos); + } else if (os_strcmp(buf, "enable_edmg") == 0) { + conf->enable_edmg = atoi(pos); } else if (os_strcmp(buf, "chanlist") == 0) { if (hostapd_parse_chanlist(conf, pos)) { wpa_printf(MSG_ERROR, "Line %d: invalid channel list", line); return 1; } + } else if (os_strcmp(buf, "freqlist") == 0) { + if (freq_range_list_parse(&conf->acs_freq_list, pos)) { + wpa_printf(MSG_ERROR, "Line %d: invalid frequency list", + line); + return 1; + } + conf->acs_freq_list_present = 1; + } else if (os_strcmp(buf, "acs_exclude_6ghz_non_psc") == 0) { + conf->acs_exclude_6ghz_non_psc = atoi(pos); } else if (os_strcmp(buf, "beacon_int") == 0) { int val = atoi(pos); /* MIB defines range as 1..65535, but very small values @@ -3272,6 +3309,16 @@ static int hostapd_config_fill(struct hostapd_config *conf, } conf->rate_type = BEACON_RATE_VHT; conf->beacon_rate = val; + } else if (os_strncmp(pos, "he:", 3) == 0) { + val = atoi(pos + 3); + if (val < 0 || val > 11) { + wpa_printf(MSG_ERROR, + "Line %d: invalid beacon_rate HE-MCS %d", + line, val); + return 1; + } + conf->rate_type = BEACON_RATE_HE; + conf->beacon_rate = val; } else { val = atoi(pos); if (val < 10 || val > 10000) { @@ -3292,6 +3339,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) { @@ -3310,6 +3358,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); @@ -3341,7 +3390,7 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "ap_table_expiration_time") == 0) { conf->ap_table_expiration_time = atoi(pos); } else if (os_strncmp(buf, "tx_queue_", 9) == 0) { - if (hostapd_config_tx_queue(conf, buf, pos)) { + if (hostapd_config_tx_queue(conf->tx_queue, buf, pos)) { wpa_printf(MSG_ERROR, "Line %d: invalid TX queue item", line); return 1; @@ -3372,7 +3421,6 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "use_driver_iface_addr") == 0) { conf->use_driver_iface_addr = atoi(pos); -#ifdef CONFIG_IEEE80211W } else if (os_strcmp(buf, "ieee80211w") == 0) { bss->ieee80211w = atoi(pos); } else if (os_strcmp(buf, "group_mgmt_cipher") == 0) { @@ -3389,6 +3437,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) { @@ -3403,14 +3453,12 @@ static int hostapd_config_fill(struct hostapd_config *conf, line); return 1; } -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_OCV } else if (os_strcmp(buf, "ocv") == 0) { bss->ocv = atoi(pos); 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) { @@ -3423,7 +3471,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); @@ -3456,11 +3503,16 @@ 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) { conf->he_op.he_twt_required = atoi(pos); + } else if (os_strcmp(buf, "he_twt_responder") == 0) { + conf->he_op.he_twt_responder = atoi(pos); } else if (os_strcmp(buf, "he_rts_threshold") == 0) { conf->he_op.he_rts_threshold = atoi(pos); } else if (os_strcmp(buf, "he_basic_mcs_nss_set") == 0) { @@ -3550,19 +3602,53 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->he_mu_edca.he_mu_ac_vo_param[HE_MU_AC_PARAM_TIMER_IDX] = atoi(pos) & 0xff; } else if (os_strcmp(buf, "he_spr_sr_control") == 0) { - conf->spr.sr_control = atoi(pos) & 0xff; + conf->spr.sr_control = atoi(pos) & 0x1f; } else if (os_strcmp(buf, "he_spr_non_srg_obss_pd_max_offset") == 0) { conf->spr.non_srg_obss_pd_max_offset = atoi(pos); } else if (os_strcmp(buf, "he_spr_srg_obss_pd_min_offset") == 0) { conf->spr.srg_obss_pd_min_offset = atoi(pos); } else if (os_strcmp(buf, "he_spr_srg_obss_pd_max_offset") == 0) { conf->spr.srg_obss_pd_max_offset = atoi(pos); + } else if (os_strcmp(buf, "he_spr_srg_bss_colors") == 0) { + if (hostapd_parse_he_srg_bitmap( + conf->spr.srg_bss_color_bitmap, pos)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid srg bss colors list '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "he_spr_srg_partial_bssid") == 0) { + if (hostapd_parse_he_srg_bitmap( + conf->spr.srg_partial_bssid_bitmap, pos)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid srg partial bssid list '%s'", + line, pos); + return 1; + } } else if (os_strcmp(buf, "he_oper_chwidth") == 0) { conf->he_oper_chwidth = atoi(pos); } else if (os_strcmp(buf, "he_oper_centr_freq_seg0_idx") == 0) { conf->he_oper_centr_freq_seg0_idx = atoi(pos); } else if (os_strcmp(buf, "he_oper_centr_freq_seg1_idx") == 0) { conf->he_oper_centr_freq_seg1_idx = atoi(pos); + } else if (os_strcmp(buf, "he_6ghz_max_mpdu") == 0) { + conf->he_6ghz_max_mpdu = atoi(pos); + } else if (os_strcmp(buf, "he_6ghz_max_ampdu_len_exp") == 0) { + conf->he_6ghz_max_ampdu_len_exp = atoi(pos); + } else if (os_strcmp(buf, "he_6ghz_rx_ant_pat") == 0) { + conf->he_6ghz_rx_ant_pat = atoi(pos); + } else if (os_strcmp(buf, "he_6ghz_tx_ant_pat") == 0) { + conf->he_6ghz_tx_ant_pat = atoi(pos); + } else if (os_strcmp(buf, "unsol_bcast_probe_resp_interval") == 0) { + int val = atoi(pos); + + if (val < 0 || val > 20) { + wpa_printf(MSG_ERROR, + "Line %d: invalid unsol_bcast_probe_resp_interval value", + line); + return 1; + } + bss->unsol_bcast_probe_resp_interval = val; #endif /* CONFIG_IEEE80211AX */ } else if (os_strcmp(buf, "max_listen_interval") == 0) { bss->max_listen_interval = atoi(pos); @@ -3744,6 +3830,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); @@ -4144,9 +4233,53 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->own_ie_override = tmp; } else if (os_strcmp(buf, "sae_reflection_attack") == 0) { bss->sae_reflection_attack = atoi(pos); + } else if (os_strcmp(buf, "sae_commit_status") == 0) { + bss->sae_commit_status = atoi(pos); + } else if (os_strcmp(buf, "sae_pk_omit") == 0) { + bss->sae_pk_omit = atoi(pos); + } else if (os_strcmp(buf, "sae_pk_password_check_skip") == 0) { + bss->sae_pk_password_check_skip = atoi(pos); } 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); + } else if (os_strcmp(buf, "ft_rsnxe_used") == 0) { + bss->ft_rsnxe_used = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_eapol_m3") == 0) { + bss->oci_freq_override_eapol_m3 = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_eapol_g1") == 0) { + bss->oci_freq_override_eapol_g1 = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_saquery_req") == 0) { + bss->oci_freq_override_saquery_req = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_saquery_resp") == 0) { + bss->oci_freq_override_saquery_resp = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_ft_assoc") == 0) { + bss->oci_freq_override_ft_assoc = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_fils_assoc") == 0) { + bss->oci_freq_override_fils_assoc = atoi(pos); + } else if (os_strcmp(buf, "oci_freq_override_wnm_sleep") == 0) { + bss->oci_freq_override_wnm_sleep = atoi(pos); #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_SAE } else if (os_strcmp(buf, "sae_password") == 0) { @@ -4162,8 +4295,9 @@ static int hostapd_config_fill(struct hostapd_config *conf, } else if (os_strcmp(buf, "assocresp_elements") == 0) { if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos)) return 1; - } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) { - bss->sae_anti_clogging_threshold = atoi(pos); + } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0 || + os_strcmp(buf, "anti_clogging_threshold") == 0) { + bss->anti_clogging_threshold = atoi(pos); } else if (os_strcmp(buf, "sae_sync") == 0) { bss->sae_sync = atoi(pos); } else if (os_strcmp(buf, "sae_groups") == 0) { @@ -4175,6 +4309,10 @@ static int hostapd_config_fill(struct hostapd_config *conf, } } else if (os_strcmp(buf, "sae_require_mfp") == 0) { bss->sae_require_mfp = atoi(pos); + } else if (os_strcmp(buf, "sae_confirm_immediate") == 0) { + bss->sae_confirm_immediate = atoi(pos); + } else if (os_strcmp(buf, "sae_pwe") == 0) { + bss->sae_pwe = atoi(pos); } else if (os_strcmp(buf, "local_pwr_constraint") == 0) { int val = atoi(pos); if (val < 0 || val > 255) { @@ -4318,12 +4456,24 @@ static int hostapd_config_fill(struct hostapd_config *conf, bss->dhcp_server_port = atoi(pos); } else if (os_strcmp(buf, "dhcp_relay_port") == 0) { bss->dhcp_relay_port = atoi(pos); + } else if (os_strcmp(buf, "fils_discovery_min_interval") == 0) { + bss->fils_discovery_min_int = atoi(pos); + } else if (os_strcmp(buf, "fils_discovery_max_interval") == 0) { + bss->fils_discovery_max_int = atoi(pos); #endif /* CONFIG_FILS */ } else if (os_strcmp(buf, "multicast_to_unicast") == 0) { bss->multicast_to_unicast = atoi(pos); } else if (os_strcmp(buf, "broadcast_deauth") == 0) { bss->broadcast_deauth = atoi(pos); + } else if (os_strcmp(buf, "notify_mgmt_frames") == 0) { + bss->notify_mgmt_frames = atoi(pos); #ifdef CONFIG_DPP + } else if (os_strcmp(buf, "dpp_name") == 0) { + os_free(bss->dpp_name); + bss->dpp_name = os_strdup(pos); + } else if (os_strcmp(buf, "dpp_mud_url") == 0) { + os_free(bss->dpp_mud_url); + bss->dpp_mud_url = os_strdup(pos); } else if (os_strcmp(buf, "dpp_connector") == 0) { os_free(bss->dpp_connector); bss->dpp_connector = os_strdup(pos); @@ -4339,6 +4489,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 @@ -4372,9 +4534,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); @@ -4389,8 +4553,12 @@ static int hostapd_config_fill(struct hostapd_config *conf, conf->rssi_reject_assoc_rssi = atoi(pos); } else if (os_strcmp(buf, "rssi_reject_assoc_timeout") == 0) { conf->rssi_reject_assoc_timeout = atoi(pos); + } else if (os_strcmp(buf, "rssi_ignore_probe_request") == 0) { + conf->rssi_ignore_probe_request = 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); @@ -4506,6 +4674,37 @@ static int hostapd_config_fill(struct hostapd_config *conf, } bss->mka_psk_set |= MKA_PSK_SET_CKN; #endif /* CONFIG_MACSEC */ + } else if (os_strcmp(buf, "disable_11n") == 0) { + bss->disable_11n = !!atoi(pos); + } else if (os_strcmp(buf, "disable_11ac") == 0) { + bss->disable_11ac = !!atoi(pos); + } else if (os_strcmp(buf, "disable_11ax") == 0) { + bss->disable_11ax = !!atoi(pos); +#ifdef CONFIG_PASN +#ifdef CONFIG_TESTING_OPTIONS + } else if (os_strcmp(buf, "force_kdk_derivation") == 0) { + bss->force_kdk_derivation = atoi(pos); + } else if (os_strcmp(buf, "pasn_corrupt_mic") == 0) { + bss->pasn_corrupt_mic = atoi(pos); +#endif /* CONFIG_TESTING_OPTIONS */ + } else if (os_strcmp(buf, "pasn_groups") == 0) { + if (hostapd_parse_intlist(&bss->pasn_groups, pos)) { + wpa_printf(MSG_ERROR, + "Line %d: Invalid pasn_groups value '%s'", + line, pos); + return 1; + } + } else if (os_strcmp(buf, "pasn_comeback_after") == 0) { + bss->pasn_comeback_after = atoi(pos); +#endif /* CONFIG_PASN */ + } else if (os_strcmp(buf, "ext_capa_mask") == 0) { + if (get_hex_config(bss->ext_capa_mask, EXT_CAPA_MAX_LEN, + line, "ext_capa_mask", pos)) + return 1; + } else if (os_strcmp(buf, "ext_capa") == 0) { + if (get_hex_config(bss->ext_capa, EXT_CAPA_MAX_LEN, + line, "ext_capa", pos)) + return 1; } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration item '%s'", diff --git a/contrib/wpa/hostapd/ctrl_iface.c b/contrib/wpa/hostapd/ctrl_iface.c index 0f6dfa13d8f3..4a2d60627070 100644 --- a/contrib/wpa/hostapd/ctrl_iface.c +++ b/contrib/wpa/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 */ @@ -33,6 +37,7 @@ #include "common/dpp.h" #endif /* CONFIG_DPP */ #include "common/wpa_ctrl.h" +#include "common/ptksa_cache.h" #include "crypto/tls.h" #include "drivers/driver.h" #include "eapol_auth/eapol_auth_sm.h" @@ -43,6 +48,7 @@ #include "ap/ap_config.h" #include "ap/ieee802_1x.h" #include "ap/wpa_auth.h" +#include "ap/pmksa_cache_auth.h" #include "ap/ieee802_11.h" #include "ap/sta_info.h" #include "ap/wps_hostapd.h" @@ -55,6 +61,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 +72,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 @@ -130,7 +134,6 @@ static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd, } -#ifdef CONFIG_IEEE80211W #ifdef NEED_AP_MLME static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, const char *txtaddr) @@ -149,7 +152,6 @@ static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd, return 0; } #endif /* NEED_AP_MLME */ -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS @@ -1098,7 +1100,6 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd, } #endif /* CONFIG_FILS */ #endif /* CONFIG_IEEE80211R_AP */ -#ifdef CONFIG_IEEE80211W if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) { ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 "); if (os_snprintf_error(end - pos, ret)) @@ -1111,7 +1112,6 @@ static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd, return pos - buf; pos += ret; } -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_SAE if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) { ret = os_snprintf(pos, end - pos, "SAE "); @@ -1223,6 +1223,52 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, return pos - buf; pos += ret; } + + if (hapd->conf->multi_ap) { + struct hostapd_ssid *ssid = &hapd->conf->multi_ap_backhaul_ssid; + + ret = os_snprintf(pos, end - pos, "multi_ap=%d\n", + hapd->conf->multi_ap); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + + if (ssid->ssid_len) { + ret = os_snprintf(pos, end - pos, + "multi_ap_backhaul_ssid=%s\n", + wpa_ssid_txt(ssid->ssid, + ssid->ssid_len)); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + if (hapd->conf->wps_state && hapd->conf->wpa && + ssid->wpa_passphrase) { + ret = os_snprintf(pos, end - pos, + "multi_ap_backhaul_wpa_passphrase=%s\n", + ssid->wpa_passphrase); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + + if (hapd->conf->wps_state && hapd->conf->wpa && + ssid->wpa_psk && + ssid->wpa_psk->group) { + char hex[PMK_LEN * 2 + 1]; + + wpa_snprintf_hex(hex, sizeof(hex), ssid->wpa_psk->psk, + PMK_LEN); + ret = os_snprintf(pos, end - pos, + "multi_ap_backhaul_wpa_psk=%s\n", + hex); + forced_memzero(hex, sizeof(hex)); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + } #endif /* CONFIG_WPS */ if (hapd->conf->wpa) { @@ -1290,6 +1336,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; } @@ -1330,6 +1392,41 @@ static void hostapd_disassoc_deny_mac(struct hostapd_data *hapd) } } + +static int hostapd_ctrl_iface_set_band(struct hostapd_data *hapd, + const char *bands) +{ + union wpa_event_data event; + u32 setband_mask = WPA_SETBAND_AUTO; + + /* + * For example: + * SET setband 2G,6G + * SET setband 5G + * SET setband AUTO + */ + if (!os_strstr(bands, "AUTO")) { + if (os_strstr(bands, "5G")) + setband_mask |= WPA_SETBAND_5G; + if (os_strstr(bands, "6G")) + setband_mask |= WPA_SETBAND_6G; + if (os_strstr(bands, "2G")) + setband_mask |= WPA_SETBAND_2G; + if (setband_mask == WPA_SETBAND_AUTO) + return -1; + } + + if (hostapd_drv_set_band(hapd, setband_mask) == 0) { + os_memset(&event, 0, sizeof(event)); + event.channel_list_changed.initiator = REGDOM_SET_BY_USER; + event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; + wpa_supplicant_event(hapd, EVENT_CHANNEL_LIST_CHANGED, &event); + } + + return 0; +} + + static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) { char *value; @@ -1372,6 +1469,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hapd->ext_mgmt_frame_handling = atoi(value); } else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) { hapd->ext_eapol_frame_io = atoi(value); + } else if (os_strcasecmp(cmd, "force_backlog_bytes") == 0) { + hapd->force_backlog_bytes = atoi(value); #ifdef CONFIG_DPP } else if (os_strcasecmp(cmd, "dpp_config_obj_override") == 0) { os_free(hapd->dpp_config_obj_override); @@ -1387,6 +1486,8 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) hapd->dpp_ignore_netaccesskey_mismatch = atoi(value); } else if (os_strcasecmp(cmd, "dpp_test") == 0) { dpp_test = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_version_override") == 0) { + dpp_version_override = atoi(value); #endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ #ifdef CONFIG_MBO @@ -1412,7 +1513,19 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) } else if (os_strcasecmp(cmd, "dpp_configurator_params") == 0) { os_free(hapd->dpp_configurator_params); hapd->dpp_configurator_params = os_strdup(value); + } else if (os_strcasecmp(cmd, "dpp_init_max_tries") == 0) { + hapd->dpp_init_max_tries = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_init_retry_time") == 0) { + hapd->dpp_init_retry_time = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_resp_wait_time") == 0) { + hapd->dpp_resp_wait_time = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_resp_max_tries") == 0) { + hapd->dpp_resp_max_tries = atoi(value); + } else if (os_strcasecmp(cmd, "dpp_resp_retry_time") == 0) { + hapd->dpp_resp_retry_time = atoi(value); #endif /* CONFIG_DPP */ + } else if (os_strcasecmp(cmd, "setband") == 0) { + ret = hostapd_ctrl_iface_set_band(hapd, value); } else { ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); if (ret) @@ -1428,7 +1541,37 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) if (ieee802_11_update_beacons(hapd->iface)) wpa_printf(MSG_DEBUG, "Failed to update beacons with WMM parameters"); + } else if (os_strcmp(cmd, "wpa_passphrase") == 0 || + os_strcmp(cmd, "sae_password") == 0 || + os_strcmp(cmd, "sae_pwe") == 0) { + if (hapd->started) + hostapd_setup_sae_pt(hapd->conf); + } else if (os_strcasecmp(cmd, "transition_disable") == 0) { + wpa_auth_set_transition_disable(hapd->wpa_auth, + hapd->conf->transition_disable); } + +#ifdef CONFIG_TESTING_OPTIONS + if (os_strcmp(cmd, "ft_rsnxe_used") == 0) + wpa_auth_set_ft_rsnxe_used(hapd->wpa_auth, + hapd->conf->ft_rsnxe_used); + else if (os_strcmp(cmd, "oci_freq_override_eapol_m3") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_M3, + atoi(value)); + else if (os_strcmp(cmd, "oci_freq_override_eapol_g1") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_EAPOL_G1, + atoi(value)); + else if (os_strcmp(cmd, "oci_freq_override_ft_assoc") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, WPA_AUTH_OCV_OVERRIDE_FT_ASSOC, + atoi(value)); + else if (os_strcmp(cmd, "oci_freq_override_fils_assoc") == 0) + wpa_auth_set_ocv_override_freq( + hapd->wpa_auth, + WPA_AUTH_OCV_OVERRIDE_FILS_ASSOC, atoi(value)); +#endif /* CONFIG_TESTING_OPTIONS */ } return ret; @@ -1628,7 +1771,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; } @@ -1803,6 +1946,52 @@ static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd) } +static int hostapd_ctrl_iface_eapol_tx(struct hostapd_data *hapd, char *cmd) +{ + char *pos, *pos2; + u8 dst[ETH_ALEN], *buf; + int used, ret; + size_t len; + unsigned int prev; + int encrypt = 0; + + wpa_printf(MSG_DEBUG, "External EAPOL TX: %s", cmd); + + pos = cmd; + used = hwaddr_aton2(pos, dst); + if (used < 0) + return -1; + pos += used; + while (*pos == ' ') + pos++; + + pos2 = os_strchr(pos, ' '); + if (pos2) { + len = pos2 - pos; + encrypt = os_strstr(pos2, "encrypt=1") != NULL; + } else { + len = os_strlen(pos); + } + if (len & 1) + return -1; + len /= 2; + + buf = os_malloc(len); + if (!buf || hexstr2bin(pos, buf, len) < 0) { + os_free(buf); + return -1; + } + + prev = hapd->ext_eapol_frame_io; + hapd->ext_eapol_frame_io = 0; + ret = hostapd_wpa_auth_send_eapol(hapd, dst, buf, len, encrypt); + hapd->ext_eapol_frame_io = prev; + os_free(buf); + + return ret; +} + + static u16 ipv4_hdr_checksum(const void *buf, size_t len) { size_t i; @@ -1827,7 +2016,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]; @@ -1843,14 +2032,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"); + "test data: RX - ignore unexpected 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"); @@ -1860,8 +2049,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); } @@ -1914,7 +2103,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; @@ -1953,17 +2142,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; @@ -2109,7 +2298,32 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd) if (hwaddr_aton(cmd, addr)) return -1; -#ifdef CONFIG_IEEE80211W + if (is_broadcast_ether_addr(addr) && os_strstr(cmd, " BIGTK")) { + if (hapd->last_bigtk_alg == WPA_ALG_NONE) + return -1; + + wpa_printf(MSG_INFO, "TESTING: Reset BIPN for BIGTK"); + + /* First, use a zero key to avoid any possible duplicate key + * avoidance in the driver. */ + if (hostapd_drv_set_key(hapd->conf->iface, hapd, + hapd->last_bigtk_alg, + broadcast_ether_addr, + hapd->last_bigtk_key_idx, 0, 1, NULL, 0, + zero, hapd->last_bigtk_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_bigtk_alg, + broadcast_ether_addr, + hapd->last_bigtk_key_idx, 0, 1, NULL, + 0, hapd->last_bigtk, + hapd->last_bigtk_len, + KEY_FLAG_GROUP_TX_DEFAULT); + } + if (is_broadcast_ether_addr(addr) && os_strstr(cmd, "IGTK")) { if (hapd->last_igtk_alg == WPA_ALG_NONE) return -1; @@ -2121,19 +2335,20 @@ 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); } -#endif /* CONFIG_IEEE80211W */ if (is_broadcast_ether_addr(addr)) { if (hapd->last_gtk_alg == WPA_ALG_NONE) @@ -2146,16 +2361,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); @@ -2171,14 +2389,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); } @@ -2187,11 +2407,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, ' '); @@ -2220,13 +2441,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); } @@ -2241,8 +2473,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); } @@ -2265,8 +2498,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)); @@ -2295,8 +2528,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)); @@ -2325,8 +2558,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, @@ -2336,26 +2569,268 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd, plain ? restore_tk : NULL, hapd, sta); } + +static int hostapd_ctrl_rekey_ptk(struct hostapd_data *hapd, const char *cmd) +{ + struct sta_info *sta; + u8 addr[ETH_ALEN]; + + if (hwaddr_aton(cmd, addr)) + return -1; + + sta = ap_get_sta(hapd, addr); + if (!sta || !sta->wpa_sm) + return -1; + + return wpa_auth_rekey_ptk(hapd->wpa_auth, sta->wpa_sm); +} + + +static int hostapd_ctrl_get_pmksa_pmk(struct hostapd_data *hapd, const u8 *addr, + char *buf, size_t buflen) +{ + struct rsn_pmksa_cache_entry *pmksa; + + pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, addr, NULL); + if (!pmksa) + return -1; + + return wpa_snprintf_hex(buf, buflen, pmksa->pmk, pmksa->pmk_len); +} + + +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 hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen); + } + pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); + if (!pmk || !pmk_len) { + wpa_printf(MSG_DEBUG, "No PMK stored for " MACSTR, + MAC2STR(addr)); + return hostapd_ctrl_get_pmksa_pmk(hapd, addr, buf, buflen); + } + + return wpa_snprintf_hex(buf, buflen, pmk, pmk_len); +} + + +static int hostapd_ctrl_register_frame(struct hostapd_data *hapd, + const char *cmd) +{ + u16 type; + char *pos, *end; + u8 match[10]; + size_t match_len; + bool multicast = false; + + type = strtol(cmd, &pos, 16); + if (*pos != ' ') + return -1; + pos++; + end = os_strchr(pos, ' '); + if (end) { + match_len = end - pos; + multicast = os_strstr(end, "multicast") != NULL; + } else { + match_len = os_strlen(pos) / 2; + } + if (hexstr2bin(pos, match, match_len)) + return -1; + + return hostapd_drv_register_frame(hapd, type, match, match_len, + multicast); +} + #endif /* CONFIG_TESTING_OPTIONS */ +#ifdef NEED_AP_MLME +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; +} +#endif /* NEED_AP_MLME */ + + 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 */ - hostapd_chan_switch_vht_config( - iface->bss[i], settings.freq_params.vht_enabled); + /* Save CHAN_SWITCH VHT and HE config */ + hostapd_chan_switch_config(iface->bss[i], + &settings.freq_params); ret = hostapd_switch_channel(iface->bss[i], &settings); if (ret) { @@ -2389,13 +2864,17 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen) { int ret; - char *pos; + char *pos, *temp = NULL; u8 *data = NULL; unsigned int vendor_id, subcmd; + enum nested_attr nested_attr_flag = NESTED_ATTR_UNSPECIFIED; struct wpabuf *reply; size_t data_len = 0; - /* cmd: <vendor id> <subcommand id> [<hex formatted data>] */ + /** + * cmd: <vendor id> <subcommand id> [<hex formatted data>] + * [nested=<0|1>] + */ vendor_id = strtoul(cmd, &pos, 16); if (!isblank((unsigned char) *pos)) return -EINVAL; @@ -2405,7 +2884,9 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd, if (*pos != '\0') { if (!isblank((unsigned char) *pos++)) return -EINVAL; - data_len = os_strlen(pos); + + temp = os_strchr(pos, ' '); + data_len = temp ? (size_t) (temp - pos) : os_strlen(pos); } if (data_len) { @@ -2422,6 +2903,11 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd, } } + pos = os_strstr(cmd, "nested="); + if (pos) + nested_attr_flag = atoi(pos + 7) ? NESTED_ATTR_USED : + NESTED_ATTR_NOT_USED; + reply = wpabuf_alloc((buflen - 1) / 2); if (!reply) { os_free(data); @@ -2429,7 +2915,7 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd, } ret = hostapd_drv_vendor_cmd(hapd, vendor_id, subcmd, data, data_len, - reply); + nested_attr_flag, reply); if (ret == 0) ret = wpa_snprintf_hex(buf, buflen, wpabuf_head_u8(reply), @@ -2679,6 +3165,20 @@ static int hostapd_ctrl_iface_req_beacon(struct hostapd_data *hapd, } +static int hostapd_ctrl_iface_show_neighbor(struct hostapd_data *hapd, + char *buf, size_t buflen) +{ + if (!(hapd->conf->radio_measurements[0] & + WLAN_RRM_CAPS_NEIGHBOR_REPORT)) { + wpa_printf(MSG_ERROR, + "CTRL: SHOW_NEIGHBOR: Neighbor report is not enabled"); + return -1; + } + + return hostapd_neighbor_show(hapd, buf, buflen); +} + + static int hostapd_ctrl_iface_set_neighbor(struct hostapd_data *hapd, char *buf) { struct wpa_ssid_value ssid; @@ -2785,6 +3285,7 @@ static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd, char *buf) { struct wpa_ssid_value ssid; + struct wpa_ssid_value *ssidp = NULL; u8 bssid[ETH_ALEN]; char *tmp; @@ -2794,13 +3295,16 @@ static int hostapd_ctrl_iface_remove_neighbor(struct hostapd_data *hapd, } tmp = os_strstr(buf, "ssid="); - if (!tmp || ssid_parse(tmp + 5, &ssid)) { - wpa_printf(MSG_ERROR, - "CTRL: REMOVE_NEIGHBORr: Bad or missing SSID"); - return -1; + if (tmp) { + ssidp = &ssid; + if (ssid_parse(tmp + 5, &ssid)) { + wpa_printf(MSG_ERROR, + "CTRL: REMOVE_NEIGHBOR: Bad SSID"); + return -1; + } } - return hostapd_neighbor_remove(hapd, bssid, &ssid); + return hostapd_neighbor_remove(hapd, bssid, ssidp); } @@ -2832,6 +3336,34 @@ static int hostapd_ctrl_driver_flags(struct hostapd_iface *iface, char *buf, } +static int hostapd_ctrl_driver_flags2(struct hostapd_iface *iface, char *buf, + size_t buflen) +{ + int ret, i; + char *pos, *end; + + ret = os_snprintf(buf, buflen, "%016llX:\n", + (long long unsigned) iface->drv_flags2); + if (os_snprintf_error(buflen, ret)) + return -1; + + pos = buf + ret; + end = buf + buflen; + + for (i = 0; i < 64; i++) { + if (iface->drv_flags2 & (1LLU << i)) { + ret = os_snprintf(pos, end - pos, "%s\n", + driver_flag2_to_string(1LLU << i)); + if (os_snprintf_error(end - pos, ret)) + return -1; + pos += ret; + } + } + + return pos - buf; +} + + static int hostapd_ctrl_iface_acl_del_mac(struct mac_acl_entry **acl, int *num, const char *txtaddr) { @@ -2934,6 +3466,23 @@ static int hostapd_ctrl_iface_get_capability(struct hostapd_data *hapd, } +#ifdef ANDROID +static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd, + char *buf, size_t buflen) +{ + int ret; + + ret = hostapd_drv_driver_cmd(hapd, cmd, buf, buflen); + if (ret == 0) { + ret = os_snprintf(buf, buflen, "%s\n", "OK"); + if (os_snprintf_error(buflen, ret)) + ret = -1; + } + return ret; +} +#endif /* ANDROID */ + + static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, char *buf, char *reply, int reply_size, @@ -3032,13 +3581,11 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strcmp(buf, "STOP_AP") == 0) { if (hostapd_ctrl_iface_stop_ap(hapd)) reply_len = -1; -#ifdef CONFIG_IEEE80211W #ifdef NEED_AP_MLME } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) { if (hostapd_ctrl_iface_sa_query(hapd, buf + 9)) reply_len = -1; #endif /* NEED_AP_MLME */ -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) { if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8)) @@ -3150,6 +3697,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) { if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0) reply_len = -1; + } else if (os_strncmp(buf, "EAPOL_TX ", 9) == 0) { + if (hostapd_ctrl_iface_eapol_tx(hapd, buf + 9) < 0) + reply_len = -1; } else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) { if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0) reply_len = -1; @@ -3185,9 +3735,18 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) { if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0) reply_len = -1; + } else if (os_strncmp(buf, "REKEY_PTK ", 10) == 0) { + if (hostapd_ctrl_rekey_ptk(hapd, buf + 10) < 0) + reply_len = -1; } 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); + } else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) { + if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0) + reply_len = -1; #endif /* CONFIG_TESTING_OPTIONS */ } else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) { if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12)) @@ -3225,6 +3784,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "SET_NEIGHBOR ", 13) == 0) { if (hostapd_ctrl_iface_set_neighbor(hapd, buf + 13)) reply_len = -1; + } else if (os_strcmp(buf, "SHOW_NEIGHBOR") == 0) { + reply_len = hostapd_ctrl_iface_show_neighbor(hapd, reply, + reply_size); } else if (os_strncmp(buf, "REMOVE_NEIGHBOR ", 16) == 0) { if (hostapd_ctrl_iface_remove_neighbor(hapd, buf + 16)) reply_len = -1; @@ -3240,20 +3802,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strcmp(buf, "DRIVER_FLAGS") == 0) { reply_len = hostapd_ctrl_driver_flags(hapd->iface, reply, reply_size); + } else if (os_strcmp(buf, "DRIVER_FLAGS2") == 0) { + reply_len = hostapd_ctrl_driver_flags2(hapd->iface, reply, + reply_size); } else if (os_strcmp(buf, "TERMINATE") == 0) { eloop_terminate(); } else if (os_strncmp(buf, "ACCEPT_ACL ", 11) == 0) { if (os_strncmp(buf + 11, "ADD_MAC ", 8) == 0) { - if (!hostapd_ctrl_iface_acl_add_mac( + if (hostapd_ctrl_iface_acl_add_mac( + &hapd->conf->accept_mac, + &hapd->conf->num_accept_mac, buf + 19)) + reply_len = -1; + } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) { + if (!hostapd_ctrl_iface_acl_del_mac( &hapd->conf->accept_mac, &hapd->conf->num_accept_mac, buf + 19)) hostapd_disassoc_accept_mac(hapd); else reply_len = -1; - } else if (os_strncmp((buf + 11), "DEL_MAC ", 8) == 0) { - hostapd_ctrl_iface_acl_del_mac( - &hapd->conf->accept_mac, - &hapd->conf->num_accept_mac, buf + 19); } else if (os_strcmp(buf + 11, "SHOW") == 0) { reply_len = hostapd_ctrl_iface_acl_show_mac( hapd->conf->accept_mac, @@ -3262,6 +3828,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, hostapd_ctrl_iface_acl_clear_list( &hapd->conf->accept_mac, &hapd->conf->num_accept_mac); + hostapd_disassoc_accept_mac(hapd); } } else if (os_strncmp(buf, "DENY_ACL ", 9) == 0) { if (os_strncmp(buf + 9, "ADD_MAC ", 8) == 0) { @@ -3269,10 +3836,13 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, &hapd->conf->deny_mac, &hapd->conf->num_deny_mac, buf + 17)) hostapd_disassoc_deny_mac(hapd); + else + reply_len = -1; } else if (os_strncmp(buf + 9, "DEL_MAC ", 8) == 0) { - hostapd_ctrl_iface_acl_del_mac( - &hapd->conf->deny_mac, - &hapd->conf->num_deny_mac, buf + 17); + if (hostapd_ctrl_iface_acl_del_mac( + &hapd->conf->deny_mac, + &hapd->conf->num_deny_mac, buf + 17)) + reply_len = -1; } else if (os_strcmp(buf + 9, "SHOW") == 0) { reply_len = hostapd_ctrl_iface_acl_show_mac( hapd->conf->deny_mac, @@ -3292,6 +3862,33 @@ 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_URI ", 12) == 0) { + res = hostapd_dpp_nfc_uri(hapd, buf + 12); + 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_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) { @@ -3321,6 +3918,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; @@ -3364,6 +3966,21 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "DPP_PKEX_REMOVE ", 16) == 0) { if (hostapd_dpp_pkex_remove(hapd, buf + 16) < 0) reply_len = -1; +#ifdef CONFIG_DPP2 + } else if (os_strncmp(buf, "DPP_CONTROLLER_START ", 21) == 0) { + if (hostapd_dpp_controller_start(hapd, buf + 20) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "DPP_CONTROLLER_START") == 0) { + if (hostapd_dpp_controller_start(hapd, NULL) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "DPP_CONTROLLER_STOP") == 0) { + dpp_controller_stop(hapd->iface->interfaces->dpp); + } else if (os_strncmp(buf, "DPP_CHIRP ", 10) == 0) { + if (hostapd_dpp_chirp(hapd, buf + 9) < 0) + reply_len = -1; + } else if (os_strcmp(buf, "DPP_STOP_CHIRP") == 0) { + hostapd_dpp_chirp_stop(hapd); +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ #ifdef RADIUS_SERVER } else if (os_strncmp(buf, "DAC_REQUEST ", 12) == 0) { @@ -3373,6 +3990,15 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) { reply_len = hostapd_ctrl_iface_get_capability( hapd, buf + 15, reply, reply_size); +#ifdef CONFIG_PASN + } else if (os_strcmp(buf, "PTKSA_CACHE_LIST") == 0) { + reply_len = ptksa_cache_list(hapd->ptksa, reply, reply_size); +#endif /* CONFIG_PASN */ +#ifdef ANDROID + } else if (os_strncmp(buf, "DRIVER ", 7) == 0) { + reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply, + reply_size); +#endif /* ANDROID */ } else { os_memcpy(reply, "UNKNOWN COMMAND\n", 16); reply_len = 16; @@ -3400,7 +4026,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, @@ -3425,28 +4051,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 */ @@ -3535,7 +4163,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; @@ -3849,6 +4477,11 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces) #ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_DPP dpp_test = DPP_TEST_DISABLED; +#ifdef CONFIG_DPP2 + dpp_version_override = 2; +#else /* CONFIG_DPP2 */ + dpp_version_override = 1; +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ #endif /* CONFIG_TESTING_OPTIONS */ @@ -4114,7 +4747,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; @@ -4123,7 +4756,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, @@ -4152,28 +4785,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 */ @@ -4317,7 +4952,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; @@ -4367,6 +5002,8 @@ try_again: return -1; } + wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); + return 0; fail: @@ -4469,6 +5106,8 @@ fail: eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive, interface, NULL); + wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb); + return 0; fail: @@ -4538,37 +5177,43 @@ static int hostapd_ctrl_check_event_enabled(struct wpa_ctrl_dst *dst, } -static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, - enum wpa_msg_type type, - const char *buf, size_t len) +static void hostapd_ctrl_iface_send_internal(int sock, struct dl_list *ctrl_dst, + const char *ifname, int level, + const char *buf, size_t len) { struct wpa_ctrl_dst *dst, *next; - struct dl_list *ctrl_dst; struct msghdr msg; - int idx; - struct iovec io[2]; + int idx, res; + struct iovec io[5]; char levelstr[10]; - int s; - if (type != WPA_MSG_ONLY_GLOBAL) { - s = hapd->ctrl_sock; - ctrl_dst = &hapd->ctrl_dst; - } else { - s = hapd->iface->interfaces->global_ctrl_sock; - ctrl_dst = &hapd->iface->interfaces->global_ctrl_dst; - } - - if (s < 0 || dl_list_empty(ctrl_dst)) + if (sock < 0 || dl_list_empty(ctrl_dst)) return; - os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); - io[0].iov_base = levelstr; - io[0].iov_len = os_strlen(levelstr); - io[1].iov_base = (char *) buf; - io[1].iov_len = len; + res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); + if (os_snprintf_error(sizeof(levelstr), res)) + return; + idx = 0; + if (ifname) { + io[idx].iov_base = "IFNAME="; + io[idx].iov_len = 7; + idx++; + io[idx].iov_base = (char *) ifname; + io[idx].iov_len = os_strlen(ifname); + idx++; + io[idx].iov_base = " "; + io[idx].iov_len = 1; + idx++; + } + io[idx].iov_base = levelstr; + io[idx].iov_len = os_strlen(levelstr); + idx++; + io[idx].iov_base = (char *) buf; + io[idx].iov_len = len; + idx++; os_memset(&msg, 0, sizeof(msg)); msg.msg_iov = io; - msg.msg_iovlen = 2; + msg.msg_iovlen = idx; idx = 0; dl_list_for_each_safe(dst, next, ctrl_dst, struct wpa_ctrl_dst, list) { @@ -4578,22 +5223,16 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, &dst->addr, dst->addrlen); msg.msg_name = &dst->addr; msg.msg_namelen = dst->addrlen; - if (sendmsg(s, &msg, 0) < 0) { + if (sendmsg(sock, &msg, 0) < 0) { int _errno = errno; wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: " "%d - %s", idx, errno, strerror(errno)); dst->errors++; if (dst->errors > 10 || _errno == ENOENT) { - if (type != WPA_MSG_ONLY_GLOBAL) - hostapd_ctrl_iface_detach( - hapd, &dst->addr, - dst->addrlen); - else - hostapd_global_ctrl_iface_detach( - hapd->iface->interfaces, - &dst->addr, - dst->addrlen); + ctrl_iface_detach(ctrl_dst, + &dst->addr, + dst->addrlen); } } else dst->errors = 0; @@ -4602,4 +5241,25 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, } } + +static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level, + enum wpa_msg_type type, + const char *buf, size_t len) +{ + if (type != WPA_MSG_NO_GLOBAL) { + hostapd_ctrl_iface_send_internal( + hapd->iface->interfaces->global_ctrl_sock, + &hapd->iface->interfaces->global_ctrl_dst, + type != WPA_MSG_PER_INTERFACE ? + NULL : hapd->conf->iface, + level, buf, len); + } + + if (type != WPA_MSG_ONLY_GLOBAL) { + hostapd_ctrl_iface_send_internal( + hapd->ctrl_sock, &hapd->ctrl_dst, + NULL, level, buf, len); + } +} + #endif /* CONFIG_NATIVE_WINDOWS */ diff --git a/contrib/wpa/hostapd/defconfig b/contrib/wpa/hostapd/defconfig index 01871c951f3d..666447e4ab40 100644 --- a/contrib/wpa/hostapd/defconfig +++ b/contrib/wpa/hostapd/defconfig @@ -44,15 +44,9 @@ CONFIG_LIBNL32=y # Driver interface for no driver (e.g., RADIUS server only) #CONFIG_DRIVER_NONE=y -# IEEE 802.11F/IAPP -CONFIG_IAPP=y - # WPA2/IEEE 802.11i RSN pre-authentication CONFIG_RSN_PREAUTH=y -# IEEE 802.11w (management frame protection) -CONFIG_IEEE80211W=y - # Support Operating Channel Validation #CONFIG_OCV=y @@ -154,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 @@ -355,12 +346,12 @@ CONFIG_IPV6=y # * ath10k # # For more details refer to: -# http://wireless.kernel.org/en/users/Documentation/acs +# https://wireless.wiki.kernel.org/en/users/documentation/acs # #CONFIG_ACS=y # Multiband Operation support -# These extentions facilitate efficient use of multiple frequency bands +# These extensions facilitate efficient use of multiple frequency bands # available to the AP and the devices that may associate with it. #CONFIG_MBO=y @@ -389,3 +380,25 @@ 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 + +# Remove all TKIP functionality +# TKIP is an old cryptographic data confidentiality algorithm that is not +# considered secure. It should not be used anymore. For now, the default hostapd +# build includes this to allow mixed mode WPA+WPA2 networks to be enabled, but +# that functionality is subject to be removed in the future. +#CONFIG_NO_TKIP=y + +# Pre-Association Security Negotiation (PASN) +# Experimental implementation based on IEEE P802.11z/D2.6 and the protocol +# design is still subject to change. As such, this should not yet be enabled in +# production use. +# This requires CONFIG_IEEE80211W=y to be enabled, too. +#CONFIG_PASN=y diff --git a/contrib/wpa/hostapd/hostapd.android.rc b/contrib/wpa/hostapd/hostapd.android.rc new file mode 100644 index 000000000000..26a87b808914 --- /dev/null +++ b/contrib/wpa/hostapd/hostapd.android.rc @@ -0,0 +1,19 @@ +# +# init.rc fragment for hostapd on Android +# Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi> +# +# This software may be distributed under the terms of the BSD license. +# See README for more details. +# + +on post-fs-data + mkdir /data/misc/wifi/hostapd 0770 wifi wifi + +service hostapd /vendor/bin/hostapd \ + /data/misc/wifi/hostapd.conf + class main + user wifi + writepid /data/misc/wifi/hostapd.pid + group wifi + disabled + oneshot diff --git a/contrib/wpa/hostapd/hostapd.conf b/contrib/wpa/hostapd/hostapd.conf index ce3ecdddf157..b5d15061f850 100644 --- a/contrib/wpa/hostapd/hostapd.conf +++ b/contrib/wpa/hostapd/hostapd.conf @@ -41,7 +41,6 @@ interface=wlan0 # bit 2 (4) = RADIUS # bit 3 (8) = WPA # bit 4 (16) = driver interface -# bit 5 (32) = IAPP # bit 6 (64) = MLME # # Levels (minimum value for logged events): @@ -73,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. # @@ -147,7 +146,8 @@ ssid=test # Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz), # g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used # with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this -# needs to be set to hw_mode=a. When using ACS (see channel parameter), a +# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs +# to be set to hw_mode=a. When using ACS (see channel parameter), a # special value "any" can be used to indicate that any support band can be used. # This special case is currently supported only with drivers with which # offloaded ACS is used. @@ -164,8 +164,14 @@ hw_mode=g # which will enable the ACS survey based algorithm. channel=1 +# Global operating class (IEEE 802.11, Annex E, Table E-4) +# This option allows hostapd to specify the operating class of the channel +# configured with the channel parameter. channel and op_class together can +# uniquely identify channels across different bands, including the 6 GHz band. +#op_class=131 + # ACS tuning - Automatic Channel Selection -# See: http://wireless.kernel.org/en/users/Documentation/acs +# See: https://wireless.wiki.kernel.org/en/users/documentation/acs # # You can customize the ACS survey algorithm with following variables: # @@ -199,11 +205,26 @@ channel=1 #chanlist=100 104 108 112 116 #chanlist=1 6 11-13 +# Frequency list restriction. This option allows hostapd to select one of the +# provided frequencies when a frequency should be automatically selected. +# Frequency list can be provided as range using hyphen ('-') or individual +# frequencies can be specified by comma (',') separated values +# Default: all frequencies allowed in selected hw_mode +#freqlist=2437,5955,5975 +#freqlist=2437,5985-6105 + # Exclude DFS channels from ACS # This option can be used to exclude all DFS channels from the ACS channel list # in cases where the driver supports DFS channels. #acs_exclude_dfs=1 +# Include only preferred scan channels from 6 GHz band for ACS +# This option can be used to include only preferred scan channels in the 6 GHz +# band. This can be useful in particular for devices that operate only a 6 GHz +# BSS without a collocated 2.4/5 GHz BSS. +# Default behavior is to include all PSC and non-PSC channels. +#acs_exclude_6ghz_non_psc=1 + # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535) beacon_int=100 @@ -258,6 +279,8 @@ fragm_threshold=-1 # beacon_rate=ht:<HT MCS> # VHT: # beacon_rate=vht:<VHT MCS> +# HE: +# beacon_rate=he:<HE MCS> # # For example, beacon_rate=10 for 1 Mbps or beacon_rate=60 for 6 Mbps (OFDM). #beacon_rate=10 @@ -550,6 +573,10 @@ wmm_ac_vo_acm=0 # Default: 1 (enabled) #broadcast_deauth=1 +# Get notifications for received Management frames on control interface +# Default: 0 (disabled) +#notify_mgmt_frames=0 + ##### IEEE 802.11n related configuration ###################################### # ieee80211n: Whether IEEE 802.11n (HT) is enabled @@ -559,6 +586,9 @@ wmm_ac_vo_acm=0 # Note: hw_mode=g (2.4 GHz) and hw_mode=a (5 GHz) is used to specify the band. #ieee80211n=1 +# disable_11n: Boolean (0/1) to disable HT for a specific BSS +#disable_11n=0 + # ht_capab: HT capabilities (list of flags) # LDPC coding capability: [LDPC] = supported # Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary @@ -577,8 +607,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) @@ -613,6 +641,9 @@ wmm_ac_vo_acm=0 # Note: hw_mode=a is used to specify that 5 GHz band is used with VHT. #ieee80211ac=1 +# disable_11ac: Boolean (0/1) to disable VHT for a specific BSS +#disable_11ac=0 + # vht_capab: VHT capabilities (list of flags) # # vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454] @@ -767,6 +798,9 @@ wmm_ac_vo_acm=0 # 1 = enabled #ieee80211ax=1 +# disable_11ax: Boolean (0/1) to disable HE for a specific BSS +#disable_11ax=0 + #he_su_beamformer: HE single user beamformer support # 0 = not supported (default) # 1 = supported @@ -785,6 +819,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 @@ -794,12 +831,27 @@ wmm_ac_vo_acm=0 # 1 = required #he_twt_required=0 +#he_twt_responder: Whether TWT (HE) responder is enabled +# 0 = disabled +# 1 = enabled if supported by the driver (default) +#he_twt_responder=1 + #he_rts_threshold: Duration of STA transmission # 0 = not set (default) # unsigned integer = duration in units of 16 us #he_rts_threshold=0 # HE operating channel information; see matching vht_* parameters for details. +# he_oper_centr_freq_seg0_idx field is used to indicate center frequency of 80 +# and 160 MHz bandwidth operation. In 80+80 MHz operation, it is the center +# frequency of the lower frequency segment. he_oper_centr_freq_seg1_idx field +# is used only with 80+80 MHz bandwidth operation and it is used to transmit +# the center frequency of the second segment. +# On the 6 GHz band the center freq calculation starts from 5.950 GHz offset. +# For example idx=3 would result in 5965 MHz center frequency. In addition, +# he_oper_chwidth is ignored, and the channel width is derived from the +# configured operating class or center frequency indexes (see +# IEEE P802.11ax/D6.1 Annex E, Table E-4). #he_oper_chwidth #he_oper_centr_freq_seg0_idx #he_oper_centr_freq_seg1_idx @@ -835,10 +887,82 @@ wmm_ac_vo_acm=0 #he_mu_edca_ac_vo_timer=255 # Spatial Reuse Parameter Set +# +# SR Control field value +# B0 = PSR Disallowed +# B1 = Non-SRG OBSS PD SR Disallowed +# B2 = Non-SRG Offset Present +# B3 = SRG Information Present +# B4 = HESIGA_Spatial_reuse_value15_allowed #he_spr_sr_control +# +# Non-SRG OBSS PD Max Offset (included if he_spr_sr_control B2=1) #he_spr_non_srg_obss_pd_max_offset + +# SRG OBSS PD Min Offset (included if he_spr_sr_control B3=1) #he_spr_srg_obss_pd_min_offset +# +# SRG OBSS PD Max Offset (included if he_spr_sr_control B3=1) #he_spr_srg_obss_pd_max_offset +# +# SPR SRG BSS Color (included if he_spr_sr_control B3=1) +# This config represents SRG BSS Color Bitmap field of Spatial Reuse Parameter +# Set element that indicates the BSS color values used by members of the +# SRG of which the transmitting STA is a member. The value is in range of 0-63. +#he_spr_srg_bss_colors=1 2 10 63 +# +# SPR SRG Partial BSSID (included if he_spr_sr_control B3=1) +# This config represents SRG Partial BSSID Bitmap field of Spatial Reuse +# Parameter Set element that indicates the Partial BSSID values used by members +# of the SRG of which the transmitting STA is a member. The value range +# corresponds to one of the 64 possible values of BSSID[39:44], where the lowest +# numbered bit corresponds to Partial BSSID value 0 and the highest numbered bit +# corresponds to Partial BSSID value 63. +#he_spr_srg_partial_bssid=0 1 3 63 +# +#he_6ghz_max_mpdu: Maximum MPDU Length of HE 6 GHz band capabilities. +# Indicates maximum MPDU length +# 0 = 3895 octets +# 1 = 7991 octets +# 2 = 11454 octets (default) +#he_6ghz_max_mpdu=2 +# +#he_6ghz_max_ampdu_len_exp: Maximum A-MPDU Length Exponent of HE 6 GHz band +# capabilities. Indicates the maximum length of A-MPDU pre-EOF padding that +# the STA can receive. This field is an integer in the range of 0 to 7. +# The length defined by this field is equal to +# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets +# 0 = AMPDU length of 8k +# 1 = AMPDU length of 16k +# 2 = AMPDU length of 32k +# 3 = AMPDU length of 65k +# 4 = AMPDU length of 131k +# 5 = AMPDU length of 262k +# 6 = AMPDU length of 524k +# 7 = AMPDU length of 1048k (default) +#he_6ghz_max_ampdu_len_exp=7 +# +#he_6ghz_rx_ant_pat: Rx Antenna Pattern Consistency of HE 6 GHz capability. +# Indicates the possibility of Rx antenna pattern change +# 0 = Rx antenna pattern might change during the lifetime of an association +# 1 = Rx antenna pattern does not change during the lifetime of an association +# (default) +#he_6ghz_rx_ant_pat=1 +# +#he_6ghz_tx_ant_pat: Tx Antenna Pattern Consistency of HE 6 GHz capability. +# Indicates the possibility of Tx antenna pattern change +# 0 = Tx antenna pattern might change during the lifetime of an association +# 1 = Tx antenna pattern does not change during the lifetime of an association +# (default) +#he_6ghz_tx_ant_pat=1 + +# Unsolicited broadcast Probe Response transmission settings +# This is for the 6 GHz band only. If the interval is set to a non-zero value, +# the AP schedules unsolicited broadcast Probe Response frames to be +# transmitted for in-band discovery. Refer to +# IEEE P802.11ax/D8.0 26.17.2.3.2, AP behavior for fast passive scanning. +# Valid range: 0..20 TUs; default is 0 (disabled) +#unsol_bcast_probe_resp_interval=0 ##### IEEE 802.1X-2004 related configuration ################################## @@ -877,6 +1001,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 @@ -1012,7 +1138,7 @@ eap_server=0 #check_crl=1 # Specify whether to ignore certificate CRL validity time mismatches with -# errors X509_V_ERR_CERT_HAS_EXPIRED and X509_V_ERR_CERT_NOT_YET_VALID. +# errors X509_V_ERR_CRL_HAS_EXPIRED and X509_V_ERR_CRL_NOT_YET_VALID. # # 0 = ignore errors # 1 = do not ignore errors (default) @@ -1081,6 +1207,12 @@ eap_server=0 # [ENABLE-TLSv1.3] = enable TLSv1.3 (experimental - disabled by default) #tls_flags=[flag1][flag2]... +# Maximum number of EAP message rounds with data (default: 100) +#max_auth_rounds=100 + +# Maximum number of short EAP message rounds (default: 50) +#max_auth_rounds_short=50 + # Cached OCSP stapling response (DER encoded) # If set, this file is sent as a certificate status response by the EAP server # if the EAP peer requests certificate status in the ClientHello message. @@ -1167,7 +1299,7 @@ eap_server=0 # should be unique across all issuing servers. In theory, this is a variable # length field, but due to some existing implementations requiring A-ID to be # 16 octets in length, it is strongly recommended to use that length for the -# field to provid interoperability with deployed peer implementations. This +# field to provide interoperability with deployed peer implementations. This # field is configured in hex format. #eap_fast_a_id=101112131415161718191a1b1c1d1e1f @@ -1194,6 +1326,8 @@ eap_server=0 # EAP-TEAP authentication type # 0 = inner EAP (default) # 1 = Basic-Password-Auth +# 2 = Do not require Phase 2 authentication if client can be authenticated +# during Phase 1 #eap_teap_auth=0 # EAP-TEAP authentication behavior when using PAC @@ -1201,6 +1335,20 @@ eap_server=0 # 1 = skip inner authentication (inner EAP/Basic-Password-Auth) #eap_teap_pac_no_inner=0 +# EAP-TEAP behavior with Result TLV +# 0 = include with Intermediate-Result TLV (default) +# 1 = send in a separate message (for testing purposes) +#eap_teap_separate_result=0 + +# EAP-TEAP identities +# 0 = allow any identity type (default) +# 1 = require user identity +# 2 = require machine identity +# 3 = request user identity; accept either user or machine identity +# 4 = request machine identity; accept either user or machine identity +# 5 = require both user and machine identity +#eap_teap_id=0 + # EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND # (default: 0 = disabled). #eap_sim_aka_result_ind=1 @@ -1223,11 +1371,6 @@ eap_server=0 # Whether to enable ERP on the EAP server. #eap_server_erp=1 -##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) ####################### - -# Interface to be used for IAPP broadcast packets -#iapp_interface=eth0 - ##### RADIUS client configuration ############################################# # for IEEE 802.1X with external Authentication Server, IEEE 802.11 @@ -1261,6 +1404,12 @@ own_ip_addr=127.0.0.1 # used, e.g., when the device has multiple IP addresses. #radius_client_addr=127.0.0.1 +# RADIUS client forced local interface. Helps run properly with VRF +# Default is none set which allows the network stack to pick the appropriate +# interface automatically. +# Example below binds to eth0 +#radius_client_dev=eth0 + # RADIUS authentication server #auth_server_addr=127.0.0.1 #auth_server_port=1812 @@ -1466,6 +1615,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 @@ -1566,8 +1726,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) @@ -1618,6 +1796,12 @@ own_ip_addr=127.0.0.1 # 1 = optional # 2 = required #ieee80211w=0 +# The most common configuration options for this based on the PMF (protected +# management frames) certification program are: +# PMF enabled: ieee80211w=1 and wpa_key_mgmt=WPA-EAP WPA-EAP-SHA256 +# PMF required: ieee80211w=2 and wpa_key_mgmt=WPA-EAP-SHA256 +# (and similarly for WPA-PSK and WPA-PSK-SHA256 if WPA2-Personal is used) +# WPA3-Personal-only mode: ieee80211w=2 and wpa_key_mgmt=SAE # Group management cipher suite # Default: AES-128-CMAC (BIP) @@ -1630,6 +1814,13 @@ 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) +# and beacon protection support indication from the driver. +# 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 @@ -1642,9 +1833,25 @@ own_ip_addr=127.0.0.1 # ocv: Operating Channel Validation # This is a countermeasure against multi-channel man-in-the-middle attacks. +# Enabling this depends on the driver's support for OCV when the driver SME is +# used. If hostapd SME is used, this will be enabled just based on this +# configuration. # Enabling this automatically also enables ieee80211w, if not yet enabled. # 0 = disabled (default) # 1 = enabled +# 2 = enabled in workaround mode - Allow STA that claims OCV capability to +# connect even if the STA doesn't send OCI or negotiate PMF. This +# workaround is to improve interoperability with legacy STAs which are +# wrongly copying reserved bits of RSN capabilities from the AP's +# RSNE into (Re)Association Request frames. When this configuration is +# enabled, the AP considers STA is OCV capable only when the STA indicates +# MFP capability in (Re)Association Request frames and sends OCI in +# EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association +# Request frame; otherwise, the AP disables OCV for the current connection +# with the STA. Enabling this workaround mode reduced OCV protection to +# some extend since it allows misbehavior to go through. As such, this +# should be enabled only if interoperability with misbehaving STAs is +# needed. #ocv=1 # disable_pmksa_caching: Disable PMKSA caching @@ -1676,7 +1883,7 @@ own_ip_addr=127.0.0.1 # be followed by optional peer MAC address (dot11RSNAConfigPasswordPeerMac) and # by optional password identifier (dot11RSNAConfigPasswordIdentifier). In # addition, an optional VLAN ID specification can be used to bind the station -# to the specified VLAN whenver the specific SAE password entry is used. +# to the specified VLAN whenever the specific SAE password entry is used. # # If the peer MAC address is not included or is set to the wildcard address # (ff:ff:ff:ff:ff:ff), the entry is available for any station to use. If a @@ -1691,7 +1898,8 @@ own_ip_addr=127.0.0.1 # special meaning of removing all previously added entries. # # sae_password uses the following encoding: -#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>][|id=<identifier>] +#<password/credential>[|mac=<peer mac>][|vlanid=<VLAN ID>] +#[|pk=<m:ECPrivateKey-base64>][|id=<identifier>] # Examples: #sae_password=secret #sae_password=really secret|mac=ff:ff:ff:ff:ff:ff @@ -1701,10 +1909,11 @@ own_ip_addr=127.0.0.1 # SAE threshold for anti-clogging mechanism (dot11RSNASAEAntiCloggingThreshold) # This parameter defines how many open SAE instances can be in progress at the # same time before the anti-clogging mechanism is taken into use. -#sae_anti_clogging_threshold=5 +#sae_anti_clogging_threshold=5 (deprecated) +#anti_clogging_threshold=5 # Maximum number of SAE synchronization errors (dot11RSNASAESync) -# The offending SAe peer will be disconnected if more than this many +# The offending SAE peer will be disconnected if more than this many # synchronization errors happen. #sae_sync=5 @@ -1729,6 +1938,23 @@ own_ip_addr=127.0.0.1 # MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1. #sae_require_mfp=0 +# SAE Confirm behavior +# By default, AP will send out only SAE Commit message in response to a received +# SAE Commit message. This parameter can be set to 1 to override that behavior +# to send both SAE Commit and SAE Confirm messages without waiting for the STA +# to send its SAE Confirm message first. +#sae_confirm_immediate=0 + +# SAE mechanism for PWE derivation +# 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) #fils_cache_id=0011 @@ -1753,6 +1979,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> @@ -1790,6 +2029,45 @@ own_ip_addr=127.0.0.1 # default: 30 TUs (= 30.72 milliseconds) #fils_hlp_wait_time=30 +# FILS Discovery frame transmission minimum and maximum interval settings. +# If fils_discovery_max_interval is non-zero, the AP enables FILS Discovery +# frame transmission. These values use TUs as the unit and have allowed range +# of 0-10000. fils_discovery_min_interval defaults to 20. +#fils_discovery_min_interval=20 +#fils_discovery_max_interval=0 + +# 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 + +# PASN ECDH groups +# PASN implementations are required to support group 19 (NIST P-256). If this +# parameter is not set, only group 19 is supported by default. This +# configuration parameter can be used to specify a limited set of allowed +# groups. The group values are listed in the IANA registry: +# http://www.iana.org/assignments/ipsec-registry/ipsec-registry.xml#ipsec-registry-10 +#pasn_groups=19 20 21 + +# PASN comeback after time in TUs +# In case the AP is temporarily unable to handle a PASN authentication exchange +# due to a too large number of parallel operations, this value indicates to the +# peer after how many TUs it can try the PASN exchange again. +# (default: 10 TUs) +#pasn_comeback_after=10 + ##### IEEE 802.11r configuration ############################################## # Mobility Domain identifier (dot11FTMobilityDomainID, MDID) @@ -1833,7 +2111,7 @@ own_ip_addr=127.0.0.1 # Wildcard entry: # Upon receiving a response from R0KH, it will be added to this list, so # subsequent requests won't be broadcast. If R0KH does not reply, it will be -# blacklisted. +# temporarily blocked (see rkh_neg_timeout). #r0kh=ff:ff:ff:ff:ff:ff * 00112233445566778899aabbccddeeff # List of R1KHs in the same Mobility Domain @@ -1889,7 +2167,7 @@ own_ip_addr=127.0.0.1 #ft_psk_generate_local=0 ##### Neighbor table ########################################################## -# Maximum number of entries kept in AP table (either for neigbor table or for +# Maximum number of entries kept in AP table (either for neighbor table or for # detecting Overlapping Legacy BSS Condition). The oldest entry will be # removed when adding a new entry that would make the list grow over this # limit. Note! WFA certification for IEEE 802.11g requires that OLBC is @@ -2143,6 +2421,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 @@ -2151,6 +2436,31 @@ own_ip_addr=127.0.0.1 # Allow cross connection #allow_cross_connection=1 +##### Device Provisioning Protocol (DPP) ###################################### + +# Name for Enrollee's DPP Configuration Request +#dpp_name=Test + +# MUD URL for Enrollee's DPP Configuration Request (optional) +#dpp_mud_url=https://example.com/mud + +#dpp_connector +#dpp_netaccesskey +#dpp_netaccesskey_expiry +#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 @@ -2531,7 +2841,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) @@ -2546,6 +2856,10 @@ own_ip_addr=127.0.0.1 # threshold (range: 0..255, default=30). #rssi_reject_assoc_timeout=30 +# Ignore Probe Request frames if RSSI is below given threshold (in dBm) +# Allowed range: -60 to -90 dBm; default = 0 (rejection disabled) +#rssi_ignore_probe_request=-75 + ##### Fast Session Transfer (FST) support ##################################### # # The options in this section are only available when the build configuration @@ -2638,6 +2952,19 @@ own_ip_addr=127.0.0.1 # airtime. #airtime_bss_limit=1 +##### EDMG support ############################################################ +# +# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false. +# To configure channel bonding for an EDMG AP use edmg_channel below. +# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be +# configured. +#enable_edmg=1 +# +# Configure channel bonding for AP mode in the 60 GHz band. +# This parameter is relevant only if enable_edmg is set. +# Default value is 0 (no channel bonding). +#edmg_channel=9 + ##### TESTING OPTIONS ######################################################### # # The options in this section are only available when the build configuration diff --git a/contrib/wpa/hostapd/hostapd.wpa_psk b/contrib/wpa/hostapd/hostapd.wpa_psk index 166e59e9c64f..2ce5ff2346df 100644 --- a/contrib/wpa/hostapd/hostapd.wpa_psk +++ b/contrib/wpa/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/contrib/wpa/hostapd/hostapd_cli.c b/contrib/wpa/hostapd/hostapd_cli.c index 046024390f84..eaa628ad0676 100644 --- a/contrib/wpa/hostapd/hostapd_cli.c +++ b/contrib/wpa/hostapd/hostapd_cli.c @@ -54,7 +54,7 @@ static void usage(void) fprintf(stderr, "%s\n", hostapd_cli_version); fprintf(stderr, "\n" - "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] " + "usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvBr] " "[-a<path>] \\\n" " [-P<pid file>] [-G<ping interval>] [command..]\n" "\n" @@ -68,6 +68,9 @@ static void usage(void) " -a<file> run in daemon mode executing the action file " "based on events\n" " from hostapd\n" + " -r try to reconnect when client socket is " + "disconnected.\n" + " This is useful only when used with -a.\n" " -B run a daemon in the background\n" " -i<ifname> Interface to listen on (default: first " "interface found in the\n" @@ -401,7 +404,6 @@ static int hostapd_cli_cmd_signature(struct wpa_ctrl *ctrl, int argc, #endif /* CONFIG_TAXONOMY */ -#ifdef CONFIG_IEEE80211W static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -414,7 +416,6 @@ static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc, snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]); return wpa_ctrl_command(ctrl, buf); } -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS @@ -974,7 +975,7 @@ static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl) dir = opendir(ctrl_iface_dir); if (dir == NULL) { printf("Control interface directory '%s' could not be " - "openned.\n", ctrl_iface_dir); + "opened.\n", ctrl_iface_dir); return; } @@ -1226,14 +1227,15 @@ static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[]) char cmd[256]; int res; - if (argc < 2 || argc > 3) { + if (argc < 2 || argc > 4) { printf("Invalid vendor command\n" - "usage: <vendor id> <command id> [<hex formatted command argument>]\n"); + "usage: <vendor id> <command id> [<hex formatted command argument>] [nested=<0|1>]\n"); return -1; } - res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1], - argc == 3 ? argv[2] : ""); + res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s%s%s", argv[0], + argv[1], argc >= 3 ? argv[2] : "", + argc == 4 ? " " : "", argc == 4 ? argv[3] : ""); if (os_snprintf_error(sizeof(cmd), res)) { printf("Too long VENDOR command.\n"); return -1; @@ -1311,24 +1313,17 @@ static int hostapd_cli_cmd_set_neighbor(struct wpa_ctrl *ctrl, int argc, } -static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc, - char *argv[]) +static int hostapd_cli_cmd_show_neighbor(struct wpa_ctrl *ctrl, int argc, + char *argv[]) { - char cmd[400]; - int res; + return wpa_ctrl_command(ctrl, "SHOW_NEIGHBOR"); +} - if (argc != 2) { - printf("Invalid remove_neighbor command: needs 2 arguments\n"); - return -1; - } - res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NEIGHBOR %s %s", - argv[0], argv[1]); - if (os_snprintf_error(sizeof(cmd), res)) { - printf("Too long REMOVE_NEIGHBOR command.\n"); - return -1; - } - return wpa_ctrl_command(ctrl, cmd); +static int hostapd_cli_cmd_remove_neighbor(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "REMOVE_NEIGHBOR", 1, argc, argv); } @@ -1408,6 +1403,13 @@ static int hostapd_cli_cmd_dpp_bootstrap_info(struct wpa_ctrl *ctrl, int argc, } +static int hostapd_cli_cmd_dpp_bootstrap_set(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "DPP_BOOTSTRAP_SET", 1, argc, argv); +} + + static int hostapd_cli_cmd_dpp_auth_init(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1470,6 +1472,37 @@ static int hostapd_cli_cmd_dpp_pkex_remove(struct wpa_ctrl *ctrl, int argc, return hostapd_cli_cmd(ctrl, "DPP_PKEX_REMOVE", 1, argc, argv); } + +#ifdef CONFIG_DPP2 + +static int hostapd_cli_cmd_dpp_controller_start(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "DPP_CONTROLLER_START", 1, argc, argv); +} + + +static int hostapd_cli_cmd_dpp_controller_stop(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DPP_CONTROLLER_STOP"); +} + + +static int hostapd_cli_cmd_dpp_chirp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "DPP_CHIRP", 1, argc, argv); +} + + +static int hostapd_cli_cmd_dpp_stop_chirp(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + return wpa_ctrl_command(ctrl, "DPP_STOP_CHIRP"); +} + +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ @@ -1508,6 +1541,14 @@ static int hostapd_cli_cmd_reload_wpa_psk(struct wpa_ctrl *ctrl, int argc, } +#ifdef ANDROID +static int hostapd_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[]) +{ + return hostapd_cli_cmd(ctrl, "DRIVER", 1, argc, argv); +} +#endif /* ANDROID */ + + struct hostapd_cli_cmd { const char *cmd; int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]); @@ -1542,10 +1583,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "signature", hostapd_cli_cmd_signature, hostapd_complete_stations, "<addr> = get taxonomy signature for a station" }, #endif /* CONFIG_TAXONOMY */ -#ifdef CONFIG_IEEE80211W { "sa_query", hostapd_cli_cmd_sa_query, hostapd_complete_stations, "<addr> = send SA Query to a station" }, -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_WPS { "wps_pin", hostapd_cli_cmd_wps_pin, NULL, "<uuid> <pin> [timeout] [addr] = add WPS Enrollee PIN" }, @@ -1637,8 +1676,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "set_neighbor", hostapd_cli_cmd_set_neighbor, NULL, "<addr> <ssid=> <nr=> [lci=] [civic=] [stat]\n" " = add AP to neighbor database" }, + { "show_neighbor", hostapd_cli_cmd_show_neighbor, NULL, + " = show neighbor database entries" }, { "remove_neighbor", hostapd_cli_cmd_remove_neighbor, NULL, - "<addr> <ssid=> = remove AP from neighbor database" }, + "<addr> [ssid=<hex>] = remove AP from neighbor database" }, { "req_lci", hostapd_cli_cmd_req_lci, hostapd_complete_stations, "<addr> = send LCI request to a station"}, { "req_range", hostapd_cli_cmd_req_range, NULL, @@ -1656,6 +1697,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { "<id> = get DPP bootstrap URI" }, { "dpp_bootstrap_info", hostapd_cli_cmd_dpp_bootstrap_info, NULL, "<id> = show DPP bootstrap information" }, + { "dpp_bootstrap_set", hostapd_cli_cmd_dpp_bootstrap_set, NULL, + "<id> [conf=..] [ssid=<SSID>] [ssid_charset=#] [psk=<PSK>] [pass=<passphrase>] [configurator=<id>] [conn_status=#] [akm_use_selector=<0|1>] [group_id=..] [expiry=#] [csrattrs=..] = set DPP configurator parameters" }, { "dpp_auth_init", hostapd_cli_cmd_dpp_auth_init, NULL, "peer=<id> [own=<id>] = initiate DPP bootstrapping" }, { "dpp_listen", hostapd_cli_cmd_dpp_listen, NULL, @@ -1676,6 +1719,16 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { "add PKEX code" }, { "dpp_pkex_remove", hostapd_cli_cmd_dpp_pkex_remove, NULL, "*|<id> = remove DPP pkex information" }, +#ifdef CONFIG_DPP2 + { "dpp_controller_start", hostapd_cli_cmd_dpp_controller_start, NULL, + "[tcp_port=<port>] [role=..] = start DPP controller" }, + { "dpp_controller_stop", hostapd_cli_cmd_dpp_controller_stop, NULL, + "= stop DPP controller" }, + { "dpp_chirp", hostapd_cli_cmd_dpp_chirp, NULL, + "own=<BI ID> iter=<count> = start DPP chirp" }, + { "dpp_stop_chirp", hostapd_cli_cmd_dpp_stop_chirp, NULL, + "= stop DPP chirp" }, +#endif /* CONFIG_DPP2 */ #endif /* CONFIG_DPP */ { "accept_acl", hostapd_cli_cmd_accept_macacl, NULL, "=Add/Delete/Show/Clear accept MAC ACL" }, @@ -1687,6 +1740,10 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { "<addr> [req_mode=] <measurement request hexdump> = send a Beacon report request to a station" }, { "reload_wpa_psk", hostapd_cli_cmd_reload_wpa_psk, NULL, "= reload wpa_psk_file only" }, +#ifdef ANDROID + { "driver", hostapd_cli_cmd_driver, NULL, + "<driver sub command> [<hex formatted data>] = send driver command data" }, +#endif /* ANDROID */ { NULL, NULL, NULL, NULL } }; @@ -2011,12 +2068,13 @@ int main(int argc, char *argv[]) int warning_displayed = 0; int c; int daemonize = 0; + int reconnect = 0; if (os_program_init()) return -1; for (;;) { - c = getopt(argc, argv, "a:BhG:i:p:P:s:v"); + c = getopt(argc, argv, "a:BhG:i:p:P:rs:v"); if (c < 0) break; switch (c) { @@ -2045,6 +2103,9 @@ int main(int argc, char *argv[]) case 'P': pid_file = optarg; break; + case 'r': + reconnect = 1; + break; case 's': client_socket_dir = optarg; break; @@ -2087,8 +2148,7 @@ int main(int argc, char *argv[]) printf("Connection established.\n"); break; } - - if (!interactive) { + if (!interactive && !reconnect) { perror("Failed to connect to hostapd - " "wpa_ctrl_open"); return -1; @@ -2106,8 +2166,14 @@ int main(int argc, char *argv[]) return -1; if (daemonize && os_daemonize(pid_file) && eloop_sock_requeue()) return -1; - - if (interactive) + if (reconnect && action_file && ctrl_ifname) { + while (!hostapd_cli_quit) { + if (ctrl_conn) + hostapd_cli_action(ctrl_conn); + os_sleep(1, 0); + hostapd_cli_reconnect(ctrl_ifname); + } + } else if (interactive) hostapd_cli_interactive(); else if (action_file) hostapd_cli_action(ctrl_conn); diff --git a/contrib/wpa/hostapd/main.c b/contrib/wpa/hostapd/main.c index 08896ffe2a79..4f2d1f21659e 100644 --- a/contrib/wpa/hostapd/main.c +++ b/contrib/wpa/hostapd/main.c @@ -81,9 +81,6 @@ static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, case HOSTAPD_MODULE_DRIVER: module_str = "DRIVER"; break; - case HOSTAPD_MODULE_IAPP: - module_str = "IAPP"; - break; case HOSTAPD_MODULE_MLME: module_str = "MLME"; break; @@ -221,7 +218,7 @@ 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->drv_flags2 = capa.flags2; iface->probe_resp_offloads = capa.probe_resp_offloads; /* * Use default extended capa values from per-radio information @@ -263,7 +260,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; @@ -454,11 +451,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); } @@ -676,7 +674,10 @@ int main(int argc, char *argv[]) #endif /* CONFIG_ETH_P_OUI */ #ifdef CONFIG_DPP os_memset(&dpp_conf, 0, sizeof(dpp_conf)); - /* TODO: dpp_conf.msg_ctx? */ + dpp_conf.cb_ctx = &interfaces; +#ifdef CONFIG_DPP2 + dpp_conf.remove_bi = hostapd_dpp_remove_bi; +#endif /* CONFIG_DPP2 */ interfaces.dpp = dpp_global_init(&dpp_conf); if (!interfaces.dpp) return -1; @@ -771,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) @@ -905,8 +906,11 @@ int main(int argc, char *argv[]) !!(interfaces.iface[i]->drv_flags & WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT); hostapd_interface_deinit_free(interfaces.iface[i]); + interfaces.iface[i] = NULL; } os_free(interfaces.iface); + interfaces.iface = NULL; + interfaces.count = 0; #ifdef CONFIG_DPP dpp_global_deinit(interfaces.dpp); diff --git a/contrib/wpa/hostapd/sae_pk_gen.c b/contrib/wpa/hostapd/sae_pk_gen.c new file mode 100644 index 000000000000..c31eff75b538 --- /dev/null +++ b/contrib/wpa/hostapd/sae_pk_gen.c @@ -0,0 +1,196 @@ +/* + * SAE-PK password/modifier generator + * Copyright (c) 2020, The Linux Foundation + * + * 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/base64.h" +#include "crypto/crypto.h" +#include "common/sae.h" + + +int main(int argc, char *argv[]) +{ + char *der = NULL; + size_t der_len; + struct crypto_ec_key *key = NULL; + struct wpabuf *pub = NULL; + u8 *data = NULL, *m; + size_t data_len; + char *b64 = NULL, *pw = NULL, *pos, *src; + int sec, j; + int ret = -1; + u8 hash[SAE_MAX_HASH_LEN]; + char hash_hex[2 * SAE_MAX_HASH_LEN + 1]; + u8 pw_base_bin[SAE_MAX_HASH_LEN]; + u8 *dst; + int group; + size_t hash_len; + unsigned long long i, expected; + char m_hex[2 * SAE_PK_M_LEN + 1]; + u32 sec_1b, val20; + + wpa_debug_level = MSG_INFO; + if (os_program_init() < 0) + goto fail; + + if (argc != 4) { + fprintf(stderr, + "usage: sae_pk_gen <DER ECPrivateKey file> <Sec:3|5> <SSID>\n"); + goto fail; + } + + sec = atoi(argv[2]); + if (sec != 3 && sec != 5) { + fprintf(stderr, + "Invalid Sec value (allowed values: 3 and 5)\n"); + goto fail; + } + sec_1b = sec == 3; + expected = 1; + for (j = 0; j < sec; j++) + expected *= 256; + + der = os_readfile(argv[1], &der_len); + if (!der) { + fprintf(stderr, "Could not read %s: %s\n", + argv[1], strerror(errno)); + goto fail; + } + + key = crypto_ec_key_parse_priv((u8 *) der, der_len); + if (!key) { + fprintf(stderr, "Could not parse ECPrivateKey\n"); + goto fail; + } + + pub = crypto_ec_key_get_subject_public_key(key); + if (!pub) { + fprintf(stderr, "Failed to build SubjectPublicKey\n"); + goto fail; + } + + group = crypto_ec_key_group(key); + switch (group) { + case 19: + hash_len = 32; + break; + case 20: + hash_len = 48; + break; + case 21: + hash_len = 64; + break; + default: + fprintf(stderr, "Unsupported private key group\n"); + goto fail; + } + + data_len = os_strlen(argv[3]) + SAE_PK_M_LEN + wpabuf_len(pub); + data = os_malloc(data_len); + if (!data) { + fprintf(stderr, "No memory for data buffer\n"); + goto fail; + } + os_memcpy(data, argv[3], os_strlen(argv[3])); + m = data + os_strlen(argv[3]); + if (os_get_random(m, SAE_PK_M_LEN) < 0) { + fprintf(stderr, "Could not generate random Modifier M\n"); + goto fail; + } + os_memcpy(m + SAE_PK_M_LEN, wpabuf_head(pub), wpabuf_len(pub)); + + fprintf(stderr, "Searching for a suitable Modifier M value\n"); + for (i = 0;; i++) { + if (sae_hash(hash_len, data, data_len, hash) < 0) { + fprintf(stderr, "Hash failed\n"); + goto fail; + } + if (hash[0] == 0 && hash[1] == 0) { + if ((hash[2] & 0xf0) == 0) + fprintf(stderr, "\r%3.2f%%", + 100.0 * (double) i / (double) expected); + for (j = 2; j < sec; j++) { + if (hash[j]) + break; + } + if (j == sec) + break; + } + inc_byte_array(m, SAE_PK_M_LEN); + } + + if (wpa_snprintf_hex(m_hex, sizeof(m_hex), m, SAE_PK_M_LEN) < 0 || + wpa_snprintf_hex(hash_hex, sizeof(hash_hex), hash, hash_len) < 0) + goto fail; + fprintf(stderr, "\nFound a valid hash in %llu iterations: %s\n", + i + 1, hash_hex); + + b64 = base64_encode(der, der_len, NULL); + if (!b64) + goto fail; + src = pos = b64; + while (*src) { + if (*src != '\n') + *pos++ = *src; + src++; + } + *pos = '\0'; + + /* Skip 8*Sec bits and add Sec_1b as the every 20th bit starting with + * one. */ + os_memset(pw_base_bin, 0, sizeof(pw_base_bin)); + dst = pw_base_bin; + for (j = 0; j < 8 * (int) hash_len / 20; j++) { + val20 = sae_pk_get_be19(hash + sec); + val20 |= sec_1b << 19; + sae_pk_buf_shift_left_19(hash + sec, hash_len - sec); + + if (j & 1) { + *dst |= (val20 >> 16) & 0x0f; + dst++; + *dst++ = (val20 >> 8) & 0xff; + *dst++ = val20 & 0xff; + } else { + *dst++ = (val20 >> 12) & 0xff; + *dst++ = (val20 >> 4) & 0xff; + *dst = (val20 << 4) & 0xf0; + } + } + if (wpa_snprintf_hex(hash_hex, sizeof(hash_hex), + pw_base_bin, hash_len - sec) >= 0) + fprintf(stderr, "PasswordBase binary data for base32: %s", + hash_hex); + + pw = sae_pk_base32_encode(pw_base_bin, 20 * 3 - 5); + if (!pw) + goto fail; + + printf("# SAE-PK password/M/private key for Sec=%d.\n", sec); + printf("sae_password=%s|pk=%s:%s\n", pw, m_hex, b64); + printf("# Longer passwords can be used for improved security at the cost of usability:\n"); + for (j = 4; j <= ((int) hash_len * 8 + 5 - 8 * sec) / 19; j++) { + os_free(pw); + pw = sae_pk_base32_encode(pw_base_bin, 20 * j - 5); + if (pw) + printf("# %s\n", pw); + } + + ret = 0; +fail: + os_free(der); + wpabuf_free(pub); + crypto_ec_key_deinit(key); + os_free(data); + os_free(b64); + os_free(pw); + + os_program_deinit(); + + return ret; +} diff --git a/contrib/wpa/hs20/client/Makefile b/contrib/wpa/hs20/client/Makefile index 67f6f55c5260..4dcfe2d3bf2c 100644 --- a/contrib/wpa/hs20/client/Makefile +++ b/contrib/wpa/hs20/client/Makefile @@ -1,28 +1,6 @@ -all: hs20-osu-client +ALL=hs20-osu-client -ifndef CC -CC=gcc -endif - -ifndef LDO -LDO=$(CC) -endif - -ifeq ($(QUIET), 1) -Q=@ -E=true -else -Q=@ -E=echo -ifeq ($(V), 1) -Q= -E=true -endif -endif - -ifndef CFLAGS -CFLAGS = -MMD -O2 -Wall -g -endif +include ../../src/build.rules CFLAGS += -I../../src/utils CFLAGS += -I../../src/common @@ -30,8 +8,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 @@ -84,23 +71,11 @@ CFLAGS += -DEAP_TLS_OPENSSL OBJS += ../../src/crypto/tls_openssl_ocsp.o LIBS += -lssl -lcrypto +_OBJS_VAR := OBJS +include ../../src/objs.mk hs20-osu-client: $(OBJS) $(Q)$(LDO) $(LDFLAGS) -o hs20-osu-client $(OBJS) $(LIBS) @$(E) " LD " $@ -%.o: %.c - $(Q)$(CC) -c -o $@ $(CFLAGS) $< - @$(E) " CC " $< - -clean: - rm -f core *~ *.o *.d hs20-osu-client - rm -f ../../src/utils/*.o - rm -f ../../src/utils/*.d - rm -f ../../src/common/*.o - rm -f ../../src/common/*.d - rm -f ../../src/crypto/*.o - rm -f ../../src/crypto/*.d - rm -f ../../src/wps/*.o - rm -f ../../src/wps/*.d - --include $(OBJS:%.o=%.d) +clean: common-clean + rm -f core *~ diff --git a/contrib/wpa/hs20/client/est.c b/contrib/wpa/hs20/client/est.c index db65334b20f3..97f9132100c4 100644 --- a/contrib/wpa/hs20/client/est.c +++ b/contrib/wpa/hs20/client/est.c @@ -158,7 +158,7 @@ int est_load_cacerts(struct hs20_osu_client *ctx, const char *url) return -1; } - pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len); + pkcs7 = base64_decode(resp, resp_len, &pkcs7_len); if (pkcs7 && pkcs7_len < resp_len / 2) { wpa_printf(MSG_INFO, "Too short base64 decode (%u bytes; downloaded %u bytes) - assume this was binary", (unsigned int) pkcs7_len, (unsigned int) resp_len); @@ -639,8 +639,7 @@ int est_build_csr(struct hs20_osu_client *ctx, const char *url) return -1; } - attrs = base64_decode((unsigned char *) resp, resp_len, - &attrs_len); + attrs = base64_decode(resp, resp_len, &attrs_len); os_free(resp); if (attrs == NULL) { @@ -734,7 +733,7 @@ int est_simple_enroll(struct hs20_osu_client *ctx, const char *url, } wpa_printf(MSG_DEBUG, "EST simpleenroll response: %s", resp); - pkcs7 = base64_decode((unsigned char *) resp, resp_len, &pkcs7_len); + pkcs7 = base64_decode(resp, resp_len, &pkcs7_len); if (pkcs7 == NULL) { wpa_printf(MSG_INFO, "EST workaround - Could not decode base64, assume this is DER encoded PKCS7"); pkcs7 = os_malloc(resp_len); diff --git a/contrib/wpa/hs20/client/oma_dm_client.c b/contrib/wpa/hs20/client/oma_dm_client.c index d75c84562aca..bcd68b8775d5 100644 --- a/contrib/wpa/hs20/client/oma_dm_client.c +++ b/contrib/wpa/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/contrib/wpa/hs20/client/osu_client.c b/contrib/wpa/hs20/client/osu_client.c index fd99600da788..11bf0db35e93 100644 --- a/contrib/wpa/hs20/client/osu_client.c +++ b/contrib/wpa/hs20/client/osu_client.c @@ -310,7 +310,7 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params, size_t len; u8 digest1[SHA256_MAC_LEN], digest2[SHA256_MAC_LEN]; int res; - unsigned char *b64; + char *b64; FILE *f; url_node = get_node(ctx->xml, params, "CertURL"); @@ -364,7 +364,7 @@ static int download_cert(struct hs20_osu_client *ctx, xml_node_t *params, return -1; } - b64 = base64_encode((unsigned char *) cert, len, NULL); + b64 = base64_encode(cert, len, NULL); os_free(cert); if (b64 == NULL) return -1; @@ -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/contrib/wpa/hs20/client/osu_client.h b/contrib/wpa/hs20/client/osu_client.h index 5c8e6d00b6bb..9b45b03febe2 100644 --- a/contrib/wpa/hs20/client/osu_client.h +++ b/contrib/wpa/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/contrib/wpa/hs20/client/spp_client.c b/contrib/wpa/hs20/client/spp_client.c index c619541ae286..39d10e0362f6 100644 --- a/contrib/wpa/hs20/client/spp_client.c +++ b/contrib/wpa/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/contrib/wpa/hs20/server/Makefile b/contrib/wpa/hs20/server/Makefile new file mode 100644 index 000000000000..0cab6d6b010a --- /dev/null +++ b/contrib/wpa/hs20/server/Makefile @@ -0,0 +1,42 @@ +ALL=hs20_spp_server + +include ../../src/build.rules + +CFLAGS += -I../../src +CFLAGS += -I../../src/utils +CFLAGS += -I../../src/crypto + +LIBS += -lsqlite3 + +# Using glibc < 2.17 requires -lrt for clock_gettime() +LIBS += -lrt + +ifndef CONFIG_NO_GITVER +# Add VERSION_STR postfix for builds from a git repository +ifeq ($(wildcard ../../.git),../../.git) +GITVER := $(shell git describe --dirty=+) +ifneq ($(GITVER),) +CFLAGS += -DGIT_VERSION_STR_POSTFIX=\"-$(GITVER)\" +endif +endif +endif + +OBJS=spp_server.o +OBJS += hs20_spp_server.o +OBJS += ../../src/utils/xml-utils.o +OBJS += ../../src/utils/base64.o +OBJS += ../../src/utils/common.o +OBJS += ../../src/utils/os_unix.o +OBJS += ../../src/utils/wpa_debug.o +OBJS += ../../src/crypto/md5-internal.o +CFLAGS += $(shell xml2-config --cflags) +LIBS += $(shell xml2-config --libs) +OBJS += ../../src/utils/xml_libxml2.o + +_OBJS_VAR := OBJS +include ../../src/objs.mk +hs20_spp_server: $(OBJS) + $(LDO) $(LDFLAGS) -o hs20_spp_server $(OBJS) $(LIBS) + +clean: common-clean + rm -f core *~ diff --git a/contrib/wpa/hs20/server/ca/clean.sh b/contrib/wpa/hs20/server/ca/clean.sh new file mode 100755 index 000000000000..c72dcbda45e9 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/clean.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +for i in server-client server server-revoked user ocsp; do + rm -f $i.csr $i.key $i.pem +done + +rm -f openssl.cnf.tmp +if [ -d demoCA ]; then + rm -r demoCA +fi +rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der +rm -f my-openssl.cnf my-openssl-root.cnf +#rm -r rootCA diff --git a/contrib/wpa/hs20/server/ca/est-csrattrs.cnf b/contrib/wpa/hs20/server/ca/est-csrattrs.cnf new file mode 100644 index 000000000000..b50ea00d0b77 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/est-csrattrs.cnf @@ -0,0 +1,17 @@ +asn1 = SEQUENCE:attrs + +[attrs] +#oid1 = OID:challengePassword +attr1 = SEQUENCE:extreq +oid2 = OID:sha256WithRSAEncryption + +[extreq] +oid = OID:extensionRequest +vals = SET:extreqvals + +[extreqvals] + +oid1 = OID:macAddress +#oid2 = OID:imei +#oid3 = OID:meid +#oid4 = OID:DevId diff --git a/contrib/wpa/hs20/server/ca/est-csrattrs.sh b/contrib/wpa/hs20/server/ca/est-csrattrs.sh new file mode 100755 index 000000000000..0b73a0408284 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/est-csrattrs.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +openssl asn1parse -genconf est-csrattrs.cnf -out est-csrattrs.der -oid hs20.oid +base64 est-csrattrs.der > est-attrs.b64 diff --git a/contrib/wpa/hs20/server/ca/hs20.oid b/contrib/wpa/hs20/server/ca/hs20.oid new file mode 100644 index 000000000000..a829ff29bf44 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/hs20.oid @@ -0,0 +1,7 @@ +1.3.6.1.1.1.1.22 macAddress +1.2.840.113549.1.9.14 extensionRequest +1.3.6.1.4.1.40808.1.1.1 id-wfa-hotspot-friendlyName +1.3.6.1.4.1.40808.1.1.2 id-kp-HS2.0Auth +1.3.6.1.4.1.40808.1.1.3 imei +1.3.6.1.4.1.40808.1.1.4 meid +1.3.6.1.4.1.40808.1.1.5 DevId diff --git a/contrib/wpa/hs20/server/ca/ocsp-req.sh b/contrib/wpa/hs20/server/ca/ocsp-req.sh new file mode 100755 index 000000000000..931a20696d02 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/ocsp-req.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +for i in *.pem; do + echo "===[ $i ]===================" + openssl ocsp -text -CAfile ca.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/ + +# openssl ocsp -text -CAfile rootCA/cacert.pem -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/ + +# openssl ocsp -text -CAfile rootCA/cacert.pem -verify_other demoCA/cacert.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/ +# openssl ocsp -text -CAfile rootCA/cacert.pem -VAfile ca.pem -trust_other -issuer demoCA/cacert.pem -cert $i -url http://localhost:8888/ +done diff --git a/contrib/wpa/hs20/server/ca/ocsp-responder-ica.sh b/contrib/wpa/hs20/server/ca/ocsp-responder-ica.sh new file mode 100755 index 000000000000..116c6e1c3d01 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/ocsp-responder-ica.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +openssl ocsp -index demoCA/index.txt -port 8888 -nmin 5 -rsigner demoCA/cacert.pem -rkey demoCA/private/cakey-plain.pem -CA demoCA/cacert.pem -resp_no_certs -text diff --git a/contrib/wpa/hs20/server/ca/ocsp-responder.sh b/contrib/wpa/hs20/server/ca/ocsp-responder.sh new file mode 100755 index 000000000000..620947d01af0 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/ocsp-responder.sh @@ -0,0 +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 -ignore_err diff --git a/contrib/wpa/hs20/server/ca/ocsp-update-cache.sh b/contrib/wpa/hs20/server/ca/ocsp-update-cache.sh new file mode 100755 index 000000000000..f2b23250cadd --- /dev/null +++ b/contrib/wpa/hs20/server/ca/ocsp-update-cache.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +# NOTE: You may need to replace 'localhost' with your OCSP server hostname. +openssl ocsp \ + -no_nonce \ + -CAfile ca.pem \ + -verify_other demoCA/cacert.pem \ + -issuer demoCA/cacert.pem \ + -cert server.pem \ + -url http://localhost:8888/ \ + -respout ocsp-server-cache.der diff --git a/contrib/wpa/hs20/server/ca/openssl-root.cnf b/contrib/wpa/hs20/server/ca/openssl-root.cnf new file mode 100644 index 000000000000..5bc50be1dbc9 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/openssl-root.cnf @@ -0,0 +1,125 @@ +# OpenSSL configuration file for Hotspot 2.0 PKI (Root CA) + +HOME = . +RANDFILE = $ENV::HOME/.rnd +oid_section = new_oids + +[ new_oids ] + +#logotypeoid=1.3.6.1.5.5.7.1.12 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./rootCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several certificates with same subject +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = optional +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +input_password = @PASSWORD@ +output_password = @PASSWORD@ + +string_mask = utf8only + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = US +countryName_min = 2 +countryName_max = 2 + +localityName = Locality Name (eg, city) +localityName_default = Tuusula + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = WFA Hotspot 2.0 + +##organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = +#@OU@ + +commonName = Common Name (e.g. server FQDN or YOUR name) +#@CN@ +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +[ req_attributes ] + +[ v3_req ] + +# Extensions to add to a certificate request +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName=DNS:example.com,DNS:another.example.com + +[ v3_ca ] + +# Hotspot 2.0 PKI requirements +subjectKeyIdentifier=hash +basicConstraints = critical,CA:true +keyUsage = critical, cRLSign, keyCertSign + +[ crl_ext ] + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ v3_OCSP ] + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = OCSPSigning diff --git a/contrib/wpa/hs20/server/ca/openssl.cnf b/contrib/wpa/hs20/server/ca/openssl.cnf new file mode 100644 index 000000000000..61410138340f --- /dev/null +++ b/contrib/wpa/hs20/server/ca/openssl.cnf @@ -0,0 +1,200 @@ +# OpenSSL configuration file for Hotspot 2.0 PKI (Intermediate CA) + +HOME = . +RANDFILE = $ENV::HOME/.rnd +oid_section = new_oids + +[ new_oids ] + +#logotypeoid=1.3.6.1.5.5.7.1.12 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several certificates with same subject +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = ext_client # The extentions to add to the cert + +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +copy_extensions = copy + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = default # use public key default MD +preserve = no # keep passed DN ordering + +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = supplied +stateOrProvinceName = optional +organizationName = supplied +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_osu_server ] +countryName = match +stateOrProvinceName = optional +organizationName = match +organizationalUnitName = supplied +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +input_password = @PASSWORD@ +output_password = @PASSWORD@ + +string_mask = utf8only + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FI +countryName_min = 2 +countryName_max = 2 + +localityName = Locality Name (eg, city) +localityName_default = Tuusula + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = @DOMAIN@ + +##organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = +#@OU@ + +commonName = Common Name (e.g. server FQDN or YOUR name) +#@CN@ +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +[ req_attributes ] + +[ v3_ca ] + +# Hotspot 2.0 PKI requirements +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always,issuer +basicConstraints = critical, CA:true, pathlen:0 +keyUsage = critical, cRLSign, keyCertSign +authorityInfoAccess = OCSP;URI:@OCSP_URI@ +# For SP intermediate CA +#subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU +#nameConstraints=permitted;DNS:.@DOMAIN@ +#1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn + +[ v3_osu_server ] + +basicConstraints = critical, CA:true, pathlen:0 +keyUsage = critical, keyEncipherment +#@ALTNAME@ + +#logotypeoid=ASN1:SEQUENCE:LogotypeExtn +1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn +[LogotypeExtn] +communityLogos=EXP:0,SEQUENCE:LogotypeInfo +[LogotypeInfo] +# note: implicit tag converted to explicit for CHOICE +direct=EXP:0,SEQUENCE:LogotypeData +[LogotypeData] +image=SEQUENCE:LogotypeImage +[LogotypeImage] +imageDetails=SEQUENCE:LogotypeDetails +imageInfo=SEQUENCE:LogotypeImageInfo +[LogotypeDetails] +mediaType=IA5STRING:image/png +logotypeHash=SEQUENCE:HashAlgAndValues +logotypeURI=SEQUENCE:URI +[HashAlgAndValues] +value1=SEQUENCE:HashAlgAndValueSHA256 +#value2=SEQUENCE:HashAlgAndValueSHA1 +[HashAlgAndValueSHA256] +hashAlg=SEQUENCE:sha256_alg +hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@ +[HashAlgAndValueSHA1] +hashAlg=SEQUENCE:sha1_alg +hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@ +[sha256_alg] +algorithm=OID:sha256 +[sha1_alg] +algorithm=OID:sha1 +[URI] +uri=IA5STRING:@LOGO_URI@ +[LogotypeImageInfo] +# default value color(1), component optional +#type=IMP:0,INTEGER:1 +fileSize=INTEGER:7549 +xSize=INTEGER:128 +ySize=INTEGER:80 +language=IMP:4,IA5STRING:zxx + +[ crl_ext ] + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ v3_OCSP ] + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = OCSPSigning + +[ ext_client ] + +basicConstraints=CA:FALSE +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer +authorityInfoAccess = OCSP;URI:@OCSP_URI@ +#@ALTNAME@ +extendedKeyUsage = clientAuth + +[ ext_server ] + +# Hotspot 2.0 PKI requirements +basicConstraints=critical, CA:FALSE +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer +authorityInfoAccess = OCSP;URI:@OCSP_URI@ +#@ALTNAME@ +extendedKeyUsage = critical, serverAuth +keyUsage = critical, keyEncipherment diff --git a/contrib/wpa/hs20/server/ca/setup.sh b/contrib/wpa/hs20/server/ca/setup.sh new file mode 100755 index 000000000000..78abcccff455 --- /dev/null +++ b/contrib/wpa/hs20/server/ca/setup.sh @@ -0,0 +1,209 @@ +#!/bin/sh + +if [ -z "$OPENSSL" ]; then + OPENSSL=openssl +fi +export OPENSSL_CONF=$PWD/openssl.cnf +PASS=whatever +if [ -z "$DOMAIN" ]; then + DOMAIN=w1.fi +fi +COMPANY=w1.fi +OPER_ENG="engw1.fi TESTING USE" +OPER_FI="finw1.fi TESTIKÄYTTÖ" +CNR="Hotspot 2.0 Trust Root CA - 99" +CNO="ocsp.$DOMAIN" +CNV="osu-revoked.$DOMAIN" +CNOC="osu-client.$DOMAIN" +OSU_SERVER_HOSTNAME="osu.$DOMAIN" +DEBUG=0 +OCSP_URI="http://$CNO:8888/" +LOGO_URI="http://osu.w1.fi/w1fi_logo.png" +LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d" +LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b" + +# Command line overrides +USAGE=$( cat <<EOF +Usage:\n +# -c: Company name, used to generate Subject name CN for Intermediate CA\n +# -C: Subject name CN of the Root CA ($CNR)\n +# -D: Enable debugging (set -x, etc)\n +# -g: Logo sha1 hash ($LOGO_HASH1)\n +# -G: Logo sha256 hash ($LOGO_HASH256)\n +# -h: Show this help message\n +# -l: Logo URI ($LOGO_URI)\n +# -m: Domain ($DOMAIN)\n +# -o: Subject name CN for OSU-Client Server ($CNOC)\n +# -O: Subject name CN for OCSP Server ($CNO)\n +# -p: passphrase for private keys ($PASS)\n +# -r: Operator-english ($OPER_ENG)\n +# -R: Operator-finish ($OPER_FI)\n +# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n +# -u: OCSP-URI ($OCSP_URI)\n +# -V: Subject name CN for OSU-Revoked Server ($CNV)\n +EOF +) + +while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag + do + case $flag in + c) COMPANY=$OPTARG;; + C) CNR=$OPTARG;; + D) DEBUG=1;; + g) LOGO_HASH1=$OPTARG;; + G) LOGO_HASH256=$OPTARG;; + h) echo -e $USAGE; exit 0;; + l) LOGO_URI=$OPTARG;; + m) DOMAIN=$OPTARG;; + o) CNOC=$OPTARG;; + O) CNO=$OPTARG;; + p) PASS=$OPTARG;; + r) OPER_ENG=$OPTARG;; + R) OPER_FI=$OPTARG;; + S) OSU_SERVER_HOSTNAME=$OPTARG;; + u) OCSP_URI=$OPTARG;; + V) CNV=$OPTARG;; + *) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;; + esac +done + +fail() +{ + echo "$*" + exit 1 +} + +echo +echo "---[ Root CA ]----------------------------------------------------------" +echo + +if [ $DEBUG = 1 ] +then + set -x +fi + +# Set the passphrase and some other common config accordingly. +cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \ + > my-openssl-root.cnf + +cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" | +sed "s,@OCSP_URI@,$OCSP_URI," | +sed "s,@LOGO_URI@,$LOGO_URI," | +sed "s,@LOGO_HASH1@,$LOGO_HASH1," | +sed "s,@LOGO_HASH256@,$LOGO_HASH256," | +sed "s/@DOMAIN@/$DOMAIN/" \ + > my-openssl.cnf + + +cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp +mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private +touch rootCA/index.txt +if [ -e rootCA/private/cakey.pem ]; then + echo " * Use existing Root CA" +else + echo " * Generate Root CA private key" + $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key" + echo " * Sign Root CA certificate" + $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate" + $OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER" + sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint" +fi +if [ ! -e rootCA/crlnumber ]; then + echo 00 > rootCA/crlnumber +fi + +echo +echo "---[ Intermediate CA ]--------------------------------------------------" +echo + +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp +mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private +touch demoCA/index.txt +if [ -e demoCA/private/cakey.pem ]; then + echo " * Use existing Intermediate CA" +else + echo " * Generate Intermediate CA private key" + $OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:2048 -keyout demoCA/private/cakey.pem -out demoCA/careq.pem || fail "Failed to generate Intermediate CA private key" + echo " * Sign Intermediate CA certificate" + $OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate" + # horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin + openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS + $OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER." + sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint" +fi +if [ ! -e demoCA/crlnumber ]; then + echo 00 > demoCA/crlnumber +fi + +echo +echo "OCSP responder" +echo + +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp +$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem" + +echo +echo "---[ Server - to be revoked ] ------------------------------------------" +echo + +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp +$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server +$OPENSSL ca -revoke server-revoked.pem -key $PASS + +echo +echo "---[ Server - with client ext key use ] ---------------------------------" +echo "---[ Only used for negative-testing for OSU-client implementation ] -----" +echo + +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp +$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key" +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem" + +echo +echo "---[ User ]-------------------------------------------------------------" +echo + +cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp +$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key" +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem" + +echo +echo "---[ Server ]-----------------------------------------------------------" +echo + +ALT="DNS:$OSU_SERVER_HOSTNAME" +ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG" +ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI" + +cat my-openssl.cnf | + sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" | + sed "s/^##organizationalUnitName/organizationalUnitName/" | + sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" | + sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \ + > openssl.cnf.tmp +echo $OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server +$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -sha256 -new -newkey rsa:2048 -nodes -out server.csr -keyout server.key -reqexts v3_osu_server || fail "Failed to generate server request" +$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server.csr -out server.pem -key $PASS -days 730 -extensions ext_server -policy policy_osu_server || fail "Failed to sign server certificate" + +#dump logotype details for debugging +$OPENSSL x509 -in server.pem -out server.der -outform DER +openssl asn1parse -in server.der -inform DER | grep HEX | tail -1 | sed 's/.*://' | xxd -r -p > logo.der +openssl asn1parse -in logo.der -inform DER > logo.asn1 + + +echo +echo "---[ CRL ]---------------------------------------------------------------" +echo + +$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS + +echo +echo "---[ Verify ]------------------------------------------------------------" +echo + +$OPENSSL verify -CAfile rootCA/cacert.pem demoCA/cacert.pem +$OPENSSL verify -CAfile rootCA/cacert.pem -untrusted demoCA/cacert.pem *.pem + +cat rootCA/cacert.pem demoCA/cacert.pem > ca.pem diff --git a/contrib/wpa/hs20/server/ca/w1fi_logo.png b/contrib/wpa/hs20/server/ca/w1fi_logo.png Binary files differnew file mode 100644 index 000000000000..ac7c259fff2e --- /dev/null +++ b/contrib/wpa/hs20/server/ca/w1fi_logo.png diff --git a/contrib/wpa/hs20/server/hs20-osu-server.txt b/contrib/wpa/hs20/server/hs20-osu-server.txt new file mode 100644 index 000000000000..22478ad9d2cb --- /dev/null +++ b/contrib/wpa/hs20/server/hs20-osu-server.txt @@ -0,0 +1,262 @@ +Hotspot 2.0 OSU server +====================== + +The information in this document is based on the assumption that Ubuntu +16.04 server (64-bit) distribution is used and the web server is +Apache2. Neither of these are requirements for the installation, but if +other combinations are used, the package names and configuration +parameters may need to be adjusted. + +NOTE: This implementation and the example configuration here is meant +only for testing purposes in a lab environment. This design is not +secure to be installed in a publicly available Internet server without +considerable amount of modification and review for security issues. + + +Build dependencies +------------------ + +Ubuntu 16.04 server +- default installation +- upgraded to latest package versions + sudo apt-get update + sudo apt-get upgrade + +Packages needed for running the service: + sudo apt-get install sqlite3 + sudo apt-get install apache2 + sudo apt-get install php-sqlite3 php-xml libapache2-mod-php + +Additional packages needed for building the components: + sudo apt-get install build-essential + sudo apt-get install libsqlite3-dev + sudo apt-get install libssl-dev + sudo apt-get install libxml2-dev + + +Installation location +--------------------- + +Select a location for the installation root directory. The example here +assumes /home/user/hs20-server to be used, but this can be changed by +editing couple of files as indicated below. + +sudo mkdir -p /home/user/hs20-server +sudo chown $USER /home/user/hs20-server +mkdir -p /home/user/hs20-server/spp +mkdir -p /home/user/hs20-server/AS + + +Build +----- + +# hostapd as RADIUS server +cd hostapd + +#example build configuration +cat > .config <<EOF +CONFIG_DRIVER_NONE=y +CONFIG_PKCS12=y +CONFIG_RADIUS_SERVER=y +CONFIG_EAP=y +CONFIG_EAP_TLS=y +CONFIG_EAP_MSCHAPV2=y +CONFIG_EAP_PEAP=y +CONFIG_EAP_GTC=y +CONFIG_EAP_TTLS=y +CONFIG_EAP_SIM=y +CONFIG_EAP_AKA=y +CONFIG_EAP_AKA_PRIME=y +CONFIG_SQLITE=y +CONFIG_HS20=y +EOF + +make hostapd hlr_auc_gw +cp hostapd hlr_auc_gw /home/user/hs20-server/AS + +# build hs20_spp_server +cd ../hs20/server +make clean +make +cp hs20_spp_server /home/user/hs20-server/spp +# prepare database (web server user/group needs to have write access) +mkdir -p /home/user/hs20-server/AS/DB +sudo chgrp www-data /home/user/hs20-server/AS/DB +sudo chmod g+w /home/user/hs20-server/AS/DB +sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql.txt +sudo chgrp www-data /home/user/hs20-server/AS/DB/eap_user.db +sudo chmod g+w /home/user/hs20-server/AS/DB/eap_user.db +# add example configuration (note: need to update URLs to match the system) +sqlite3 /home/user/hs20-server/AS/DB/eap_user.db < sql-example.txt + +# copy PHP scripts +# Modify config.php if different installation directory is used. +# Modify PHP scripts to get the desired behavior for user interaction (or use +# the examples as-is for initial testing). +cp -r www /home/user/hs20-server + +# Create /home/user/hs20-server/terms-and-conditions file (HTML segment to be +# inserted within the BODY section of the page). +cat > /home/user/hs20-server/terms-and-conditions <<EOF +<P>Terms and conditions..</P> +EOF + +# Build local keys and certs +cd ca +# Display help options. +./setup.sh -h + +# Remove old keys, fill in appropriate values, and generate your keys. +# For instance: +./clean.sh +rm -fr rootCA" +old_hostname=myserver.local +./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" \ + -o $old_hostname-osu-client \ + -O $old_hostname-oscp -p lanforge -S $old_hostname \ + -V $old_hostname-osu-revoked \ + -m local -u http://$old_hostname:8888/ + +# Configure subscription policies +mkdir -p /home/user/hs20-server/spp/policy +cat > /home/user/hs20-server/spp/policy/default.xml <<EOF +<Policy> + <PolicyUpdate> + <UpdateInterval>30</UpdateInterval> + <UpdateMethod>ClientInitiated</UpdateMethod> + <Restriction>Unrestricted</Restriction> + <URI>https://policy-server.osu.example.com/hs20/spp.php</URI> + </PolicyUpdate> +</Policy> +EOF + + +# Install Hotspot 2.0 SPP and OMA DM XML schema/DTD files + +# XML schema for SPP +# Copy the latest XML schema into /home/user/hs20-server/spp/spp.xsd + +# OMA DM Device Description Framework DTD +# Copy into /home/user/hs20-server/spp/dm_ddf-v1_2.dtd +# http://www.openmobilealliance.org/tech/DTD/dm_ddf-v1_2.dtd + + +# Configure RADIUS authentication service +# Note: Change the URL to match the setup +# Note: Install AAA server key/certificate and root CA in Key directory + +cat > /home/user/hs20-server/AS/as-sql.conf <<EOF +driver=none +radius_server_clients=as.radius_clients +eap_server=1 +eap_user_file=sqlite:DB/eap_user.db +ca_cert=Key/ca.pem +server_cert=Key/server.pem +private_key=Key/server.key +private_key_passwd=passphrase +eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=eap_sim.db +subscr_remediation_url=https://subscription-server.osu.example.com/hs20/spp.php +EOF + +# Set RADIUS passphrase for the APs +# Note: Modify to match the setup +cat > /home/user/hs20-server/AS/as.radius_clients <<EOF +0.0.0.0/0 radius +EOF + + +Start RADIUS authentication server +---------------------------------- + +cd /home/user/hs20-server/AS +./hostapd -B as-sql.conf + + +OSEN RADIUS server configuration notes + +The OSEN RADIUS server config file should have the 'ocsp_stapling_response' +configuration in it. For example: + +# hostapd-radius config for the radius used by the OSEN AP +interface=eth0#0 +driver=none +logger_syslog=-1 +logger_syslog_level=2 +logger_stdout=-1 +logger_stdout_level=2 +ctrl_interface=/var/run/hostapd +ctrl_interface_group=0 +eap_server=1 +eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user +server_id=ben-ota-2-osen +radius_server_auth_port=1811 +radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients + +ca_cert=/home/user/hs20-server/ca/ca.pem +server_cert=/home/user/hs20-server/ca/server.pem +private_key=/home/user/hs20-server/ca/server.key +private_key_passwd=whatever + +ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der + +The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look +similar to this, and should coorelate with the osu_nai entry in +the non-OSEN VAP config file. For instance: + +# cat hostapd-osen.eap_user +# For OSEN authentication (Hotspot 2.0 Release 2) +"osen@w1.fi" WFA-UNAUTH-TLS + + +# Run OCSP server: +cd /home/user/hs20-server/ca +./ocsp-responder.sh& + +# Update cache (This should be run periodically) +./ocsp-update-cache.sh + + +Configure web server +-------------------- + +Edit /etc/apache2/sites-available/default-ssl + +Add following block just before "SSL Engine Switch" line": + + Alias /hs20/ "/home/user/hs20-server/www/" + <Directory "/home/user/hs20-server/www/"> + Options Indexes MultiViews FollowSymLinks + AllowOverride None + Require all granted + SSLOptions +StdEnvVars + </Directory> + +Update SSL configuration to use the OSU server certificate/key. +They keys and certs are called 'server.key' and 'server.pem' from +ca/setup.sh. + +To support subscription remediation using client certificates, set +"SSLVerifyClient optional" and configure the trust root CA(s) for the +client certificates with SSLCACertificateFile. + +Enable default-ssl site and restart Apache2: + sudo a2ensite default-ssl + sudo a2enmod ssl + sudo service apache2 restart + + +Management UI +------------- + +The sample PHP scripts include a management UI for testing +purposes. That is available at https://<server>/hs20/users.php + + +AP configuration +---------------- + +APs can now be configured to use the OSU server as the RADIUS +authentication server. In addition, the OSU Provider List ANQP element +should be configured to use the SPP (SOAP+XML) option and with the +following Server URL: +https://<server>/hs20/spp.php/signup?realm=example.com diff --git a/contrib/wpa/hs20/server/hs20_spp_server.c b/contrib/wpa/hs20/server/hs20_spp_server.c new file mode 100644 index 000000000000..347c40a73d6a --- /dev/null +++ b/contrib/wpa/hs20/server/hs20_spp_server.c @@ -0,0 +1,207 @@ +/* + * Hotspot 2.0 SPP server - standalone version + * Copyright (c) 2012-2013, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" +#include <time.h> +#include <sqlite3.h> + +#include "common.h" +#include "common/version.h" +#include "xml-utils.h" +#include "spp_server.h" + + +static void write_timestamp(FILE *f) +{ + time_t t; + struct tm *tm; + + time(&t); + tm = localtime(&t); + + fprintf(f, "%04u-%02u-%02u %02u:%02u:%02u ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); +} + + +void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...) +{ + va_list ap; + + if (ctx->debug_log == NULL) + return; + + write_timestamp(ctx->debug_log); + va_start(ap, fmt); + vfprintf(ctx->debug_log, fmt, ap); + va_end(ap); + + fprintf(ctx->debug_log, "\n"); +} + + +void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node) +{ + char *str; + + if (ctx->debug_log == NULL) + return; + str = xml_node_to_str(ctx->xml, node); + if (str == NULL) + return; + + write_timestamp(ctx->debug_log); + fprintf(ctx->debug_log, "%s: '%s'\n", title, str); + os_free(str); +} + + +static int process(struct hs20_svc *ctx) +{ + int dmacc = 0; + xml_node_t *soap, *spp, *resp; + char *user, *realm, *post, *str; + + ctx->addr = getenv("HS20ADDR"); + if (ctx->addr) + debug_print(ctx, 1, "Connection from %s", ctx->addr); + ctx->test = getenv("HS20TEST"); + if (ctx->test) + debug_print(ctx, 1, "Requested test functionality: %s", + ctx->test); + + user = getenv("HS20USER"); + if (user && strlen(user) == 0) + user = NULL; + realm = getenv("HS20REALM"); + if (realm == NULL) { + debug_print(ctx, 1, "HS20REALM not set"); + return -1; + } + post = getenv("HS20POST"); + if (post == NULL) { + debug_print(ctx, 1, "HS20POST not set"); + return -1; + } + + ctx->imsi = getenv("HS20IMSI"); + if (ctx->imsi) + debug_print(ctx, 1, "IMSI %s", ctx->imsi); + + ctx->eap_method = getenv("HS20EAPMETHOD"); + if (ctx->eap_method) + debug_print(ctx, 1, "EAP method %s", ctx->eap_method); + + ctx->id_hash = getenv("HS20IDHASH"); + if (ctx->id_hash) + debug_print(ctx, 1, "ID-HASH %s", ctx->id_hash); + + soap = xml_node_from_buf(ctx->xml, post); + if (soap == NULL) { + debug_print(ctx, 1, "Could not parse SOAP data"); + return -1; + } + debug_dump_node(ctx, "Received SOAP message", soap); + spp = soap_get_body(ctx->xml, soap); + if (spp == NULL) { + debug_print(ctx, 1, "Could not get SPP message"); + xml_node_free(ctx->xml, soap); + return -1; + } + debug_dump_node(ctx, "Received SPP message", spp); + + resp = hs20_spp_server_process(ctx, spp, user, realm, dmacc); + xml_node_free(ctx->xml, soap); + if (resp == NULL && user == NULL) { + debug_print(ctx, 1, "Request HTTP authentication"); + return 2; /* Request authentication */ + } + if (resp == NULL) { + debug_print(ctx, 1, "No response"); + return -1; + } + + soap = soap_build_envelope(ctx->xml, resp); + if (soap == NULL) { + debug_print(ctx, 1, "SOAP envelope building failed"); + return -1; + } + str = xml_node_to_str(ctx->xml, soap); + xml_node_free(ctx->xml, soap); + if (str == NULL) { + debug_print(ctx, 1, "Could not get node string"); + return -1; + } + printf("%s", str); + free(str); + + return 0; +} + + +static void usage(void) +{ + printf("usage:\n" + "hs20_spp_server -r<root directory> [-f<debug log>]\n"); +} + + +int main(int argc, char *argv[]) +{ + struct hs20_svc ctx; + int ret; + + os_memset(&ctx, 0, sizeof(ctx)); + for (;;) { + int c = getopt(argc, argv, "f:r:v"); + if (c < 0) + break; + switch (c) { + case 'f': + if (ctx.debug_log) + break; + ctx.debug_log = fopen(optarg, "a"); + if (ctx.debug_log == NULL) { + printf("Could not write to %s\n", optarg); + return -1; + } + break; + case 'r': + ctx.root_dir = optarg; + break; + case 'v': + printf("hs20_spp_server v%s\n", VERSION_STR); + return 0; + default: + usage(); + return -1; + } + } + if (ctx.root_dir == NULL) { + usage(); + return -1; + } + ctx.xml = xml_node_init_ctx(&ctx, NULL); + if (ctx.xml == NULL) + return -1; + if (hs20_spp_server_init(&ctx) < 0) { + xml_node_deinit_ctx(ctx.xml); + return -1; + } + + ret = process(&ctx); + debug_print(&ctx, 1, "process() --> %d", ret); + + xml_node_deinit_ctx(ctx.xml); + hs20_spp_server_deinit(&ctx); + if (ctx.debug_log) + fclose(ctx.debug_log); + + return ret; +} diff --git a/contrib/wpa/hs20/server/spp_server.c b/contrib/wpa/hs20/server/spp_server.c new file mode 100644 index 000000000000..a50e9074f7b4 --- /dev/null +++ b/contrib/wpa/hs20/server/spp_server.c @@ -0,0 +1,2933 @@ +/* + * Hotspot 2.0 SPP server + * Copyright (c) 2012-2013, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <time.h> +#include <errno.h> +#include <sqlite3.h> + +#include "common.h" +#include "base64.h" +#include "md5_i.h" +#include "xml-utils.h" +#include "spp_server.h" + + +#define SPP_NS_URI "http://www.wi-fi.org/specifications/hotspot2dot0/v1.0/spp" + +#define URN_OMA_DM_DEVINFO "urn:oma:mo:oma-dm-devinfo:1.0" +#define URN_OMA_DM_DEVDETAIL "urn:oma:mo:oma-dm-devdetail:1.0" +#define URN_OMA_DM_DMACC "urn:oma:mo:oma-dm-dmacc:1.0" +#define URN_HS20_PPS "urn:wfa:mo:hotspot2dot0-perprovidersubscription:1.0" + + +/* TODO: timeout to expire sessions */ + +enum hs20_session_operation { + NO_OPERATION, + UPDATE_PASSWORD, + CONTINUE_SUBSCRIPTION_REMEDIATION, + CONTINUE_POLICY_UPDATE, + USER_REMEDIATION, + SUBSCRIPTION_REGISTRATION, + POLICY_REMEDIATION, + POLICY_UPDATE, + FREE_REMEDIATION, + CLEAR_REMEDIATION, + CERT_REENROLL, +}; + + +static char * db_get_session_val(struct hs20_svc *ctx, const char *user, + const char *realm, const char *session_id, + const char *field); +static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm, + const char *field); +static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user, + const char *realm, int use_dmacc); +static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx, + const char *session_id, + const char *user, + const char *realm, + int add_est_user); + + +static int db_add_session(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *sessionid, const char *pw, + const char *redirect_uri, + enum hs20_session_operation operation, + const u8 *mac_addr) +{ + char *sql; + int ret = 0; + char addr[20]; + + if (mac_addr) + snprintf(addr, sizeof(addr), MACSTR, MAC2STR(mac_addr)); + else + addr[0] = '\0'; + sql = sqlite3_mprintf("INSERT INTO sessions(timestamp,id,user,realm," + "operation,password,redirect_uri,mac_addr,test) " + "VALUES " + "(strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')," + "%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)", + sessionid, user ? user : "", realm ? realm : "", + operation, pw ? pw : "", + redirect_uri ? redirect_uri : "", + addr, ctx->test); + if (sql == NULL) + return -1; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add session entry into sqlite " + "database: %s", sqlite3_errmsg(ctx->db)); + ret = -1; + } + sqlite3_free(sql); + return ret; +} + + +static void db_update_session_password(struct hs20_svc *ctx, const char *user, + const char *realm, const char *sessionid, + const char *pw) +{ + char *sql; + + sql = sqlite3_mprintf("UPDATE sessions SET password=%Q WHERE id=%Q AND " + "user=%Q AND realm=%Q", + pw, sessionid, user, realm); + if (sql == NULL) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to update session password: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_update_session_machine_managed(struct hs20_svc *ctx, + const char *user, + const char *realm, + const char *sessionid, + const int pw_mm) +{ + char *sql; + + sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q", + pw_mm ? "1" : "0", sessionid, user, realm); + if (sql == NULL) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, + "Failed to update session machine_managed: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_add_session_pps(struct hs20_svc *ctx, const char *user, + const char *realm, const char *sessionid, + xml_node_t *node) +{ + char *str; + char *sql; + + str = xml_node_to_str(ctx->xml, node); + if (str == NULL) + return; + sql = sqlite3_mprintf("UPDATE sessions SET pps=%Q WHERE id=%Q AND " + "user=%Q AND realm=%Q", + str, sessionid, user, realm); + free(str); + if (sql == NULL) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add session pps: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_add_session_devinfo(struct hs20_svc *ctx, const char *sessionid, + xml_node_t *node) +{ + char *str; + char *sql; + + str = xml_node_to_str(ctx->xml, node); + if (str == NULL) + return; + sql = sqlite3_mprintf("UPDATE sessions SET devinfo=%Q WHERE id=%Q", + str, sessionid); + free(str); + if (sql == NULL) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add session devinfo: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_add_session_devdetail(struct hs20_svc *ctx, + const char *sessionid, + xml_node_t *node) +{ + char *str; + char *sql; + + str = xml_node_to_str(ctx->xml, node); + if (str == NULL) + return; + sql = sqlite3_mprintf("UPDATE sessions SET devdetail=%Q WHERE id=%Q", + str, sessionid); + free(str); + if (sql == NULL) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add session devdetail: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_add_session_dmacc(struct hs20_svc *ctx, const char *sessionid, + const char *username, const char *password) +{ + char *sql; + + sql = sqlite3_mprintf("UPDATE sessions SET osu_user=%Q, osu_password=%Q WHERE id=%Q", + username, password, sessionid); + if (!sql) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add session DMAcc: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_add_session_eap_method(struct hs20_svc *ctx, + const char *sessionid, + const char *method) +{ + char *sql; + + sql = sqlite3_mprintf("UPDATE sessions SET eap_method=%Q WHERE id=%Q", + method, sessionid); + if (!sql) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add session EAP method: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_add_session_id_hash(struct hs20_svc *ctx, const char *sessionid, + const char *id_hash) +{ + char *sql; + + sql = sqlite3_mprintf("UPDATE sessions SET mobile_identifier_hash=%Q WHERE id=%Q", + id_hash, sessionid); + if (!sql) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add session ID hash: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_remove_session(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *sessionid) +{ + char *sql; + + if (user == NULL || realm == NULL) { + sql = sqlite3_mprintf("DELETE FROM sessions WHERE " + "id=%Q", sessionid); + } else { + sql = sqlite3_mprintf("DELETE FROM sessions WHERE " + "user=%Q AND realm=%Q AND id=%Q", + user, realm, sessionid); + } + if (sql == NULL) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to delete session entry from " + "sqlite database: %s", sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void hs20_eventlog(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *sessionid, const char *notes, + const char *dump) +{ + char *sql; + char *user_buf = NULL, *realm_buf = NULL; + + debug_print(ctx, 1, "eventlog: %s", notes); + + if (user == NULL) { + user_buf = db_get_session_val(ctx, NULL, NULL, sessionid, + "user"); + user = user_buf; + realm_buf = db_get_session_val(ctx, NULL, NULL, sessionid, + "realm"); + realm = realm_buf; + } + + sql = sqlite3_mprintf("INSERT INTO eventlog" + "(user,realm,sessionid,timestamp,notes,dump,addr)" + " VALUES (%Q,%Q,%Q," + "strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')," + "%Q,%Q,%Q)", + user, realm, sessionid, notes, + dump ? dump : "", ctx->addr ? ctx->addr : ""); + free(user_buf); + free(realm_buf); + if (sql == NULL) + return; + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add eventlog entry into sqlite " + "database: %s", sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void hs20_eventlog_node(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *sessionid, const char *notes, + xml_node_t *node) +{ + char *str; + + if (node) + str = xml_node_to_str(ctx->xml, node); + else + str = NULL; + hs20_eventlog(ctx, user, realm, sessionid, notes, str); + free(str); +} + + +static void db_update_mo_str(struct hs20_svc *ctx, const char *user, + const char *realm, const char *name, + const char *str) +{ + char *sql; + if (user == NULL || realm == NULL || name == NULL) + return; + sql = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", + name, str, user, realm); + if (sql == NULL) + return; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to update user MO entry in sqlite " + "database: %s", sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); +} + + +static void db_update_mo(struct hs20_svc *ctx, const char *user, + const char *realm, const char *name, xml_node_t *mo) +{ + char *str; + + str = xml_node_to_str(ctx->xml, mo); + if (str == NULL) + return; + + db_update_mo_str(ctx, user, realm, name, str); + free(str); +} + + +static void add_text_node(struct hs20_svc *ctx, xml_node_t *parent, + const char *name, const char *value) +{ + xml_node_create_text(ctx->xml, parent, NULL, name, value ? value : ""); +} + + +static void add_text_node_conf(struct hs20_svc *ctx, const char *realm, + xml_node_t *parent, const char *name, + const char *field) +{ + char *val; + val = db_get_osu_config_val(ctx, realm, field); + xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : ""); + os_free(val); +} + + +static void add_text_node_conf_corrupt(struct hs20_svc *ctx, const char *realm, + xml_node_t *parent, const char *name, + const char *field) +{ + char *val; + + val = db_get_osu_config_val(ctx, realm, field); + if (val) { + size_t len; + + len = os_strlen(val); + if (len > 0) { + if (val[len - 1] == '0') + val[len - 1] = '1'; + else + val[len - 1] = '0'; + } + } + xml_node_create_text(ctx->xml, parent, NULL, name, val ? val : ""); + os_free(val); +} + + +static int new_password(char *buf, int buflen) +{ + int i; + + if (buflen < 1) + return -1; + buf[buflen - 1] = '\0'; + if (os_get_random((unsigned char *) buf, buflen - 1) < 0) + return -1; + + for (i = 0; i < buflen - 1; i++) { + unsigned char val = buf[i]; + val %= 2 * 26 + 10; + if (val < 26) + buf[i] = 'a' + val; + else if (val < 2 * 26) + buf[i] = 'A' + val - 26; + else + buf[i] = '0' + val - 2 * 26; + } + + return 0; +} + + +struct get_db_field_data { + const char *field; + char *value; +}; + + +static int get_db_field(void *ctx, int argc, char *argv[], char *col[]) +{ + struct get_db_field_data *data = ctx; + int i; + + for (i = 0; i < argc; i++) { + if (os_strcmp(col[i], data->field) == 0 && argv[i]) { + os_free(data->value); + data->value = os_strdup(argv[i]); + break; + } + } + + return 0; +} + + +static char * db_get_val(struct hs20_svc *ctx, const char *user, + const char *realm, const char *field, int dmacc) +{ + char *cmd; + struct get_db_field_data data; + + cmd = sqlite3_mprintf("SELECT %s FROM users WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", + field, dmacc ? "osu_user" : "identity", + user, realm); + if (cmd == NULL) + return NULL; + memset(&data, 0, sizeof(data)); + data.field = field; + if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK) + { + debug_print(ctx, 1, "Could not find user '%s'", user); + sqlite3_free(cmd); + return NULL; + } + sqlite3_free(cmd); + + debug_print(ctx, 1, "DB: user='%s' realm='%s' field='%s' dmacc=%d --> " + "value='%s'", user, realm, field, dmacc, data.value); + + return data.value; +} + + +static int db_update_val(struct hs20_svc *ctx, const char *user, + const char *realm, const char *field, + const char *val, int dmacc) +{ + char *cmd; + int ret; + + cmd = sqlite3_mprintf("UPDATE users SET %s=%Q WHERE %s=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", + field, val, dmacc ? "osu_user" : "identity", user, + realm); + if (cmd == NULL) + return -1; + debug_print(ctx, 1, "DB: %s", cmd); + if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, + "Failed to update user in sqlite database: %s", + sqlite3_errmsg(ctx->db)); + ret = -1; + } else { + debug_print(ctx, 1, + "DB: user='%s' realm='%s' field='%s' set to '%s'", + user, realm, field, val); + ret = 0; + } + sqlite3_free(cmd); + + return ret; +} + + +static char * db_get_session_val(struct hs20_svc *ctx, const char *user, + const char *realm, const char *session_id, + const char *field) +{ + char *cmd; + struct get_db_field_data data; + + if (user == NULL || realm == NULL) { + cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE " + "id=%Q", field, session_id); + } else { + cmd = sqlite3_mprintf("SELECT %s FROM sessions WHERE " + "user=%Q AND realm=%Q AND id=%Q", + field, user, realm, session_id); + } + if (cmd == NULL) + return NULL; + debug_print(ctx, 1, "DB: %s", cmd); + memset(&data, 0, sizeof(data)); + data.field = field; + if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK) + { + debug_print(ctx, 1, "DB: Could not find session %s: %s", + session_id, sqlite3_errmsg(ctx->db)); + sqlite3_free(cmd); + return NULL; + } + sqlite3_free(cmd); + + debug_print(ctx, 1, "DB: return '%s'", data.value); + return data.value; +} + + +static int update_password(struct hs20_svc *ctx, const char *user, + const char *realm, const char *pw, int dmacc) +{ + char *cmd; + + cmd = sqlite3_mprintf("UPDATE users SET password=%Q, " + "remediation='' " + "WHERE %s=%Q AND phase2=1", + pw, dmacc ? "osu_user" : "identity", + user); + if (cmd == NULL) + return -1; + debug_print(ctx, 1, "DB: %s", cmd); + if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to update database for user '%s'", + user); + } + sqlite3_free(cmd); + + return 0; +} + + +static int clear_remediation(struct hs20_svc *ctx, const char *user, + const char *realm, int dmacc) +{ + char *cmd; + + cmd = sqlite3_mprintf("UPDATE users SET remediation='' WHERE %s=%Q", + dmacc ? "osu_user" : "identity", + user); + if (cmd == NULL) + return -1; + debug_print(ctx, 1, "DB: %s", cmd); + if (sqlite3_exec(ctx->db, cmd, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to update database for user '%s'", + user); + } + sqlite3_free(cmd); + + return 0; +} + + +static int add_eap_ttls(struct hs20_svc *ctx, xml_node_t *parent) +{ + xml_node_t *node; + + node = xml_node_create(ctx->xml, parent, NULL, "EAPMethod"); + if (node == NULL) + return -1; + + add_text_node(ctx, node, "EAPType", "21"); + add_text_node(ctx, node, "InnerMethod", "MS-CHAP-V2"); + + return 0; +} + + +static xml_node_t * build_username_password(struct hs20_svc *ctx, + xml_node_t *parent, + const char *user, const char *pw) +{ + xml_node_t *node; + char *b64; + size_t len; + + node = xml_node_create(ctx->xml, parent, NULL, "UsernamePassword"); + if (node == NULL) + return NULL; + + add_text_node(ctx, node, "Username", user); + + b64 = base64_encode(pw, strlen(pw), NULL); + if (b64 == NULL) + return NULL; + len = os_strlen(b64); + if (len > 0 && b64[len - 1] == '\n') + b64[len - 1] = '\0'; + add_text_node(ctx, node, "Password", b64); + free(b64); + + return node; +} + + +static int add_username_password(struct hs20_svc *ctx, xml_node_t *cred, + const char *user, const char *pw, + int machine_managed) +{ + xml_node_t *node; + + node = build_username_password(ctx, cred, user, pw); + if (node == NULL) + return -1; + + add_text_node(ctx, node, "MachineManaged", + machine_managed ? "TRUE" : "FALSE"); + add_text_node(ctx, node, "SoftTokenApp", ""); + add_eap_ttls(ctx, node); + + return 0; +} + + +static void add_creation_date(struct hs20_svc *ctx, xml_node_t *cred) +{ + char str[30]; + time_t now; + struct tm tm; + + time(&now); + gmtime_r(&now, &tm); + snprintf(str, sizeof(str), "%04u-%02u-%02uT%02u:%02u:%02uZ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + xml_node_create_text(ctx->xml, cred, NULL, "CreationDate", str); +} + + +static xml_node_t * build_credential_pw(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *pw, int machine_managed) +{ + xml_node_t *cred; + + cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential"); + if (cred == NULL) { + debug_print(ctx, 1, "Failed to create Credential node"); + return NULL; + } + add_creation_date(ctx, cred); + if (add_username_password(ctx, cred, user, pw, machine_managed) < 0) { + xml_node_free(ctx->xml, cred); + return NULL; + } + add_text_node(ctx, cred, "Realm", realm); + + return cred; +} + + +static xml_node_t * build_credential(struct hs20_svc *ctx, + const char *user, const char *realm, + char *new_pw, size_t new_pw_len) +{ + if (new_password(new_pw, new_pw_len) < 0) + return NULL; + debug_print(ctx, 1, "Update password to '%s'", new_pw); + return build_credential_pw(ctx, user, realm, new_pw, 1); +} + + +static xml_node_t * build_credential_cert(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *cert_fingerprint) +{ + xml_node_t *cred, *cert; + + cred = xml_node_create_root(ctx->xml, NULL, NULL, NULL, "Credential"); + if (cred == NULL) { + debug_print(ctx, 1, "Failed to create Credential node"); + return NULL; + } + add_creation_date(ctx, cred); + cert = xml_node_create(ctx->xml, cred, NULL, "DigitalCertificate"); + add_text_node(ctx, cert, "CertificateType", "x509v3"); + add_text_node(ctx, cert, "CertSHA256Fingerprint", cert_fingerprint); + add_text_node(ctx, cred, "Realm", realm); + + return cred; +} + + +static xml_node_t * build_post_dev_data_response(struct hs20_svc *ctx, + xml_namespace_t **ret_ns, + const char *session_id, + const char *status, + const char *error_code) +{ + xml_node_t *spp_node = NULL; + xml_namespace_t *ns; + + spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns, + "sppPostDevDataResponse"); + if (spp_node == NULL) + return NULL; + if (ret_ns) + *ret_ns = ns; + + xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0"); + xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id); + xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status); + + if (error_code) { + xml_node_t *node; + node = xml_node_create(ctx->xml, spp_node, ns, "sppError"); + if (node) + xml_node_add_attr(ctx->xml, node, NULL, "errorCode", + error_code); + } + + return spp_node; +} + + +static int add_update_node(struct hs20_svc *ctx, xml_node_t *spp_node, + xml_namespace_t *ns, const char *uri, + xml_node_t *upd_node) +{ + xml_node_t *node, *tnds; + char *str; + + tnds = mo_to_tnds(ctx->xml, upd_node, 0, NULL, NULL); + if (!tnds) + return -1; + + str = xml_node_to_str(ctx->xml, tnds); + xml_node_free(ctx->xml, tnds); + if (str == NULL) + return -1; + node = xml_node_create_text(ctx->xml, spp_node, ns, "updateNode", str); + free(str); + + xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", uri); + + return 0; +} + + +static xml_node_t * read_subrem_file(struct hs20_svc *ctx, + const char *subrem_id, + char *uri, size_t uri_size) +{ + char fname[200]; + char *buf, *buf2, *pos; + size_t len; + xml_node_t *node; + + os_snprintf(fname, sizeof(fname), "%s/spp/subrem/%s", + ctx->root_dir, subrem_id); + debug_print(ctx, 1, "Use subrem file %s", fname); + + buf = os_readfile(fname, &len); + if (!buf) + return NULL; + buf2 = os_realloc(buf, len + 1); + if (!buf2) { + os_free(buf); + return NULL; + } + buf = buf2; + buf[len] = '\0'; + + pos = os_strchr(buf, '\n'); + if (!pos) { + os_free(buf); + return NULL; + } + *pos++ = '\0'; + os_strlcpy(uri, buf, uri_size); + + node = xml_node_from_buf(ctx->xml, pos); + os_free(buf); + + return node; +} + + +static xml_node_t * build_sub_rem_resp(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *session_id, + int machine_rem, int dmacc) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *cred; + char buf[400]; + char new_pw[33]; + char *status; + char *cert; + + cert = db_get_val(ctx, user, realm, "cert", dmacc); + if (cert && cert[0] == '\0') { + os_free(cert); + cert = NULL; + } + if (cert) { + char *subrem; + + /* No change needed in PPS MO unless specifically asked to */ + cred = NULL; + buf[0] = '\0'; + + subrem = db_get_val(ctx, user, realm, "subrem", dmacc); + if (subrem && subrem[0]) { + cred = read_subrem_file(ctx, subrem, buf, sizeof(buf)); + if (!cred) { + debug_print(ctx, 1, + "Could not create updateNode from subrem file"); + os_free(subrem); + os_free(cert); + return NULL; + } + } + os_free(subrem); + } else { + char *real_user = NULL; + char *pw; + + if (dmacc) { + real_user = db_get_val(ctx, user, realm, "identity", + dmacc); + if (!real_user) { + debug_print(ctx, 1, + "Could not find user identity for dmacc user '%s'", + user); + return NULL; + } + } + + pw = db_get_session_val(ctx, user, realm, session_id, + "password"); + if (pw && pw[0]) { + debug_print(ctx, 1, "New password from the user: '%s'", + pw); + snprintf(new_pw, sizeof(new_pw), "%s", pw); + free(pw); + cred = build_credential_pw(ctx, + real_user ? real_user : user, + realm, new_pw, 0); + } else { + cred = build_credential(ctx, + real_user ? real_user : user, + realm, new_pw, sizeof(new_pw)); + } + + free(real_user); + if (!cred) { + debug_print(ctx, 1, "Could not build credential"); + os_free(cert); + return NULL; + } + + snprintf(buf, sizeof(buf), + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", + realm); + } + + status = "Remediation complete, request sppUpdateResponse"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (spp_node == NULL) { + debug_print(ctx, 1, "Could not build sppPostDevDataResponse"); + os_free(cert); + return NULL; + } + + if ((cred && add_update_node(ctx, spp_node, ns, buf, cred) < 0) || + (!cred && !xml_node_create(ctx->xml, spp_node, ns, "noMOUpdate"))) { + debug_print(ctx, 1, "Could not add update node"); + xml_node_free(ctx->xml, spp_node); + os_free(cert); + return NULL; + } + + hs20_eventlog_node(ctx, user, realm, session_id, + machine_rem ? "machine remediation" : + "user remediation", cred); + xml_node_free(ctx->xml, cred); + + if (cert) { + debug_print(ctx, 1, "Request DB remediation clearing on success notification (certificate credential)"); + db_add_session(ctx, user, realm, session_id, NULL, NULL, + CLEAR_REMEDIATION, NULL); + } else { + debug_print(ctx, 1, "Request DB password update on success " + "notification"); + db_add_session(ctx, user, realm, session_id, new_pw, NULL, + UPDATE_PASSWORD, NULL); + } + os_free(cert); + + return spp_node; +} + + +static xml_node_t * machine_remediation(struct hs20_svc *ctx, + const char *user, + const char *realm, + const char *session_id, int dmacc) +{ + return build_sub_rem_resp(ctx, user, realm, session_id, 1, dmacc); +} + + +static xml_node_t * cert_reenroll(struct hs20_svc *ctx, + const char *user, + const char *realm, + const char *session_id) +{ + db_add_session(ctx, user, realm, session_id, NULL, NULL, + CERT_REENROLL, NULL); + return spp_exec_get_certificate(ctx, session_id, user, realm, 0); +} + + +static xml_node_t * policy_remediation(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *session_id, int dmacc) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *policy; + char buf[400]; + const char *status; + + hs20_eventlog(ctx, user, realm, session_id, + "requires policy remediation", NULL); + + db_add_session(ctx, user, realm, session_id, NULL, NULL, + POLICY_REMEDIATION, NULL); + + policy = build_policy(ctx, user, realm, dmacc); + if (!policy) { + return build_post_dev_data_response( + ctx, NULL, session_id, + "No update available at this time", NULL); + } + + status = "Remediation complete, request sppUpdateResponse"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (spp_node == NULL) + return NULL; + + snprintf(buf, sizeof(buf), + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy", + realm); + + if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) { + xml_node_free(ctx->xml, spp_node); + xml_node_free(ctx->xml, policy); + return NULL; + } + + hs20_eventlog_node(ctx, user, realm, session_id, + "policy update (sub rem)", policy); + xml_node_free(ctx->xml, policy); + + return spp_node; +} + + +static xml_node_t * browser_remediation(struct hs20_svc *ctx, + const char *session_id, + const char *redirect_uri, + const char *uri) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *exec_node; + + if (redirect_uri == NULL) { + debug_print(ctx, 1, "Missing redirectURI attribute for user " + "remediation"); + return NULL; + } + debug_print(ctx, 1, "redirectURI %s", redirect_uri); + + spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", + NULL); + if (spp_node == NULL) + return NULL; + + exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); + xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI", + uri); + return spp_node; +} + + +static xml_node_t * user_remediation(struct hs20_svc *ctx, const char *user, + const char *realm, const char *session_id, + const char *redirect_uri) +{ + char uri[300], *val; + + hs20_eventlog(ctx, user, realm, session_id, + "requires user remediation", NULL); + val = db_get_osu_config_val(ctx, realm, "remediation_url"); + if (val == NULL) + return NULL; + + db_add_session(ctx, user, realm, session_id, NULL, redirect_uri, + USER_REMEDIATION, NULL); + + snprintf(uri, sizeof(uri), "%s%s", val, session_id); + os_free(val); + return browser_remediation(ctx, session_id, redirect_uri, uri); +} + + +static xml_node_t * free_remediation(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *session_id, + const char *redirect_uri) +{ + char uri[300], *val; + + hs20_eventlog(ctx, user, realm, session_id, + "requires free/public account remediation", NULL); + val = db_get_osu_config_val(ctx, realm, "free_remediation_url"); + if (val == NULL) + return NULL; + + db_add_session(ctx, user, realm, session_id, NULL, redirect_uri, + FREE_REMEDIATION, NULL); + + snprintf(uri, sizeof(uri), "%s%s", val, session_id); + os_free(val); + return browser_remediation(ctx, session_id, redirect_uri, uri); +} + + +static xml_node_t * no_sub_rem(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *session_id) +{ + const char *status; + + hs20_eventlog(ctx, user, realm, session_id, + "no subscription mediation available", NULL); + + status = "No update available at this time"; + return build_post_dev_data_response(ctx, NULL, session_id, status, + NULL); +} + + +static xml_node_t * hs20_subscription_remediation(struct hs20_svc *ctx, + const char *user, + const char *realm, + const char *session_id, + int dmacc, + const char *redirect_uri) +{ + char *type, *identity; + xml_node_t *ret; + char *free_account; + + identity = db_get_val(ctx, user, realm, "identity", dmacc); + if (identity == NULL || strlen(identity) == 0) { + hs20_eventlog(ctx, user, realm, session_id, + "user not found in database for remediation", + NULL); + os_free(identity); + return build_post_dev_data_response(ctx, NULL, session_id, + "Error occurred", + "Not found"); + } + os_free(identity); + + free_account = db_get_osu_config_val(ctx, realm, "free_account"); + if (free_account && strcmp(free_account, user) == 0) { + free(free_account); + return no_sub_rem(ctx, user, realm, session_id); + } + free(free_account); + + type = db_get_val(ctx, user, realm, "remediation", dmacc); + if (type && strcmp(type, "free") != 0) { + char *val; + int shared = 0; + val = db_get_val(ctx, user, realm, "shared", dmacc); + if (val) + shared = atoi(val); + free(val); + if (shared) { + free(type); + return no_sub_rem(ctx, user, realm, session_id); + } + } + if (type && strcmp(type, "user") == 0) + ret = user_remediation(ctx, user, realm, session_id, + redirect_uri); + else if (type && strcmp(type, "free") == 0) + ret = free_remediation(ctx, user, realm, session_id, + redirect_uri); + else if (type && strcmp(type, "policy") == 0) + ret = policy_remediation(ctx, user, realm, session_id, dmacc); + else if (type && strcmp(type, "machine") == 0) + ret = machine_remediation(ctx, user, realm, session_id, dmacc); + else if (type && strcmp(type, "reenroll") == 0) + ret = cert_reenroll(ctx, user, realm, session_id); + else + ret = no_sub_rem(ctx, user, realm, session_id); + free(type); + + return ret; +} + + +static xml_node_t * read_policy_file(struct hs20_svc *ctx, + const char *policy_id) +{ + char fname[200]; + + snprintf(fname, sizeof(fname), "%s/spp/policy/%s.xml", + ctx->root_dir, policy_id); + debug_print(ctx, 1, "Use policy file %s", fname); + + return node_from_file(ctx->xml, fname); +} + + +static void update_policy_update_uri(struct hs20_svc *ctx, const char *realm, + xml_node_t *policy) +{ + xml_node_t *node; + char *url; + + node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate/URI"); + if (!node) + return; + + url = db_get_osu_config_val(ctx, realm, "policy_url"); + if (!url) + return; + xml_node_set_text(ctx->xml, node, url); + free(url); +} + + +static xml_node_t * build_policy(struct hs20_svc *ctx, const char *user, + const char *realm, int use_dmacc) +{ + char *policy_id; + xml_node_t *policy, *node; + + policy_id = db_get_val(ctx, user, realm, "policy", use_dmacc); + if (policy_id == NULL || strlen(policy_id) == 0) { + free(policy_id); + policy_id = strdup("default"); + if (policy_id == NULL) + return NULL; + } + policy = read_policy_file(ctx, policy_id); + free(policy_id); + if (policy == NULL) + return NULL; + + update_policy_update_uri(ctx, realm, policy); + + node = get_node_uri(ctx->xml, policy, "Policy/PolicyUpdate"); + if (node && use_dmacc) { + char *pw; + pw = db_get_val(ctx, user, realm, "osu_password", use_dmacc); + if (pw == NULL || + build_username_password(ctx, node, user, pw) == NULL) { + debug_print(ctx, 1, "Failed to add Policy/PolicyUpdate/" + "UsernamePassword"); + free(pw); + xml_node_free(ctx->xml, policy); + return NULL; + } + free(pw); + } + + return policy; +} + + +static xml_node_t * hs20_policy_update(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *session_id, int dmacc) +{ + xml_namespace_t *ns; + xml_node_t *spp_node; + xml_node_t *policy; + char buf[400]; + const char *status; + char *identity; + + identity = db_get_val(ctx, user, realm, "identity", dmacc); + if (identity == NULL || strlen(identity) == 0) { + hs20_eventlog(ctx, user, realm, session_id, + "user not found in database for policy update", + NULL); + os_free(identity); + return build_post_dev_data_response(ctx, NULL, session_id, + "Error occurred", + "Not found"); + } + os_free(identity); + + policy = build_policy(ctx, user, realm, dmacc); + if (!policy) { + return build_post_dev_data_response( + ctx, NULL, session_id, + "No update available at this time", NULL); + } + + db_add_session(ctx, user, realm, session_id, NULL, NULL, POLICY_UPDATE, + NULL); + + status = "Update complete, request sppUpdateResponse"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (spp_node == NULL) + return NULL; + + snprintf(buf, sizeof(buf), + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Policy", + realm); + + if (add_update_node(ctx, spp_node, ns, buf, policy) < 0) { + xml_node_free(ctx->xml, spp_node); + xml_node_free(ctx->xml, policy); + return NULL; + } + + hs20_eventlog_node(ctx, user, realm, session_id, "policy update", + policy); + xml_node_free(ctx->xml, policy); + + return spp_node; +} + + +static xml_node_t * spp_get_mo(struct hs20_svc *ctx, xml_node_t *node, + const char *urn, int *valid, char **ret_err) +{ + xml_node_t *child, *tnds, *mo; + const char *name; + char *mo_urn; + char *str; + char fname[200]; + + *valid = -1; + if (ret_err) + *ret_err = NULL; + + xml_node_for_each_child(ctx->xml, child, node) { + xml_node_for_each_check(ctx->xml, child); + name = xml_node_get_localname(ctx->xml, child); + if (strcmp(name, "moContainer") != 0) + continue; + mo_urn = xml_node_get_attr_value_ns(ctx->xml, child, SPP_NS_URI, + "moURN"); + if (strcasecmp(urn, mo_urn) == 0) { + xml_node_get_attr_value_free(ctx->xml, mo_urn); + break; + } + xml_node_get_attr_value_free(ctx->xml, mo_urn); + } + + if (child == NULL) + return NULL; + + debug_print(ctx, 1, "moContainer text for %s", urn); + debug_dump_node(ctx, "moContainer", child); + + str = xml_node_get_text(ctx->xml, child); + debug_print(ctx, 1, "moContainer payload: '%s'", str); + tnds = xml_node_from_buf(ctx->xml, str); + xml_node_get_text_free(ctx->xml, str); + if (tnds == NULL) { + debug_print(ctx, 1, "could not parse moContainer text"); + return NULL; + } + + snprintf(fname, sizeof(fname), "%s/spp/dm_ddf-v1_2.dtd", ctx->root_dir); + if (xml_validate_dtd(ctx->xml, tnds, fname, ret_err) == 0) + *valid = 1; + else if (ret_err && *ret_err && + os_strcmp(*ret_err, "No declaration for attribute xmlns of element MgmtTree\n") == 0) { + free(*ret_err); + debug_print(ctx, 1, "Ignore OMA-DM DDF DTD validation error for MgmtTree namespace declaration with xmlns attribute"); + *ret_err = NULL; + *valid = 1; + } else + *valid = 0; + + mo = tnds_to_mo(ctx->xml, tnds); + xml_node_free(ctx->xml, tnds); + if (mo == NULL) { + debug_print(ctx, 1, "invalid moContainer for %s", urn); + } + + return mo; +} + + +static xml_node_t * spp_exec_upload_mo(struct hs20_svc *ctx, + const char *session_id, const char *urn) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *node, *exec_node; + + spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", + NULL); + if (spp_node == NULL) + return NULL; + + exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); + + node = xml_node_create(ctx->xml, exec_node, ns, "uploadMO"); + xml_node_add_attr(ctx->xml, node, ns, "moURN", urn); + + return spp_node; +} + + +static xml_node_t * hs20_subscription_registration(struct hs20_svc *ctx, + const char *realm, + const char *session_id, + const char *redirect_uri, + const u8 *mac_addr) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *exec_node; + char uri[300], *val; + + if (db_add_session(ctx, NULL, realm, session_id, NULL, redirect_uri, + SUBSCRIPTION_REGISTRATION, mac_addr) < 0) + return NULL; + val = db_get_osu_config_val(ctx, realm, "signup_url"); + if (val == NULL) + return NULL; + + spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", + NULL); + if (spp_node == NULL) + return NULL; + + exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); + + snprintf(uri, sizeof(uri), "%s%s", val, session_id); + os_free(val); + xml_node_create_text(ctx->xml, exec_node, ns, "launchBrowserToURI", + uri); + return spp_node; +} + + +static xml_node_t * hs20_user_input_remediation(struct hs20_svc *ctx, + const char *user, + const char *realm, int dmacc, + const char *session_id) +{ + return build_sub_rem_resp(ctx, user, realm, session_id, 0, dmacc); +} + + +static char * db_get_osu_config_val(struct hs20_svc *ctx, const char *realm, + const char *field) +{ + char *cmd; + struct get_db_field_data data; + + cmd = sqlite3_mprintf("SELECT value FROM osu_config WHERE realm=%Q AND " + "field=%Q", realm, field); + if (cmd == NULL) + return NULL; + debug_print(ctx, 1, "DB: %s", cmd); + memset(&data, 0, sizeof(data)); + data.field = "value"; + if (sqlite3_exec(ctx->db, cmd, get_db_field, &data, NULL) != SQLITE_OK) + { + debug_print(ctx, 1, "DB: Could not find osu_config %s: %s", + realm, sqlite3_errmsg(ctx->db)); + sqlite3_free(cmd); + return NULL; + } + sqlite3_free(cmd); + + debug_print(ctx, 1, "DB: return '%s'", data.value); + return data.value; +} + + +static xml_node_t * build_pps(struct hs20_svc *ctx, + const char *user, const char *realm, + const char *pw, const char *cert, + int machine_managed, const char *test, + const char *imsi, const char *dmacc_username, + const char *dmacc_password, + xml_node_t *policy_node) +{ + xml_node_t *pps, *c, *trust, *aaa, *aaa1, *upd, *homesp, *p; + xml_node_t *cred, *eap, *userpw; + + pps = xml_node_create_root(ctx->xml, NULL, NULL, NULL, + "PerProviderSubscription"); + if (!pps) { + xml_node_free(ctx->xml, policy_node); + return NULL; + } + + add_text_node(ctx, pps, "UpdateIdentifier", "1"); + + c = xml_node_create(ctx->xml, pps, NULL, "Cred01"); + + add_text_node(ctx, c, "CredentialPriority", "1"); + + if (imsi) + goto skip_aaa_trust_root; + aaa = xml_node_create(ctx->xml, c, NULL, "AAAServerTrustRoot"); + aaa1 = xml_node_create(ctx->xml, aaa, NULL, "AAA1"); + add_text_node_conf(ctx, realm, aaa1, "CertURL", + "aaa_trust_root_cert_url"); + if (test && os_strcmp(test, "corrupt_aaa_hash") == 0) { + debug_print(ctx, 1, + "TEST: Corrupt PPS/Cred*/AAAServerTrustRoot/Root*/CertSHA256FingerPrint"); + add_text_node_conf_corrupt(ctx, realm, aaa1, + "CertSHA256Fingerprint", + "aaa_trust_root_cert_fingerprint"); + } else { + add_text_node_conf(ctx, realm, aaa1, "CertSHA256Fingerprint", + "aaa_trust_root_cert_fingerprint"); + } + + if (test && os_strcmp(test, "corrupt_polupd_hash") == 0) { + debug_print(ctx, 1, + "TEST: Corrupt PPS/Cred*/Policy/PolicyUpdate/Trustroot/CertSHA256FingerPrint"); + p = xml_node_create(ctx->xml, c, NULL, "Policy"); + upd = xml_node_create(ctx->xml, p, NULL, "PolicyUpdate"); + add_text_node(ctx, upd, "UpdateInterval", "30"); + add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated"); + add_text_node(ctx, upd, "Restriction", "Unrestricted"); + add_text_node_conf(ctx, realm, upd, "URI", "policy_url"); + trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot"); + add_text_node_conf(ctx, realm, trust, "CertURL", + "policy_trust_root_cert_url"); + add_text_node_conf_corrupt(ctx, realm, trust, + "CertSHA256Fingerprint", + "policy_trust_root_cert_fingerprint"); + } +skip_aaa_trust_root: + + upd = xml_node_create(ctx->xml, c, NULL, "SubscriptionUpdate"); + add_text_node(ctx, upd, "UpdateInterval", "4294967295"); + add_text_node(ctx, upd, "UpdateMethod", "SPP-ClientInitiated"); + add_text_node(ctx, upd, "Restriction", "HomeSP"); + add_text_node_conf(ctx, realm, upd, "URI", "spp_http_auth_url"); + trust = xml_node_create(ctx->xml, upd, NULL, "TrustRoot"); + add_text_node_conf(ctx, realm, trust, "CertURL", "trust_root_cert_url"); + if (test && os_strcmp(test, "corrupt_subrem_hash") == 0) { + debug_print(ctx, 1, + "TEST: Corrupt PPS/Cred*/SubscriptionUpdate/Trustroot/CertSHA256FingerPrint"); + add_text_node_conf_corrupt(ctx, realm, trust, + "CertSHA256Fingerprint", + "trust_root_cert_fingerprint"); + } else { + add_text_node_conf(ctx, realm, trust, "CertSHA256Fingerprint", + "trust_root_cert_fingerprint"); + } + + if (dmacc_username && + !build_username_password(ctx, upd, dmacc_username, + dmacc_password)) { + xml_node_free(ctx->xml, pps); + xml_node_free(ctx->xml, policy_node); + return NULL; + } + + if (policy_node) + xml_node_add_child(ctx->xml, c, policy_node); + + homesp = xml_node_create(ctx->xml, c, NULL, "HomeSP"); + add_text_node_conf(ctx, realm, homesp, "FriendlyName", "friendly_name"); + add_text_node_conf(ctx, realm, homesp, "FQDN", "fqdn"); + + xml_node_create(ctx->xml, c, NULL, "SubscriptionParameters"); + + cred = xml_node_create(ctx->xml, c, NULL, "Credential"); + add_creation_date(ctx, cred); + if (imsi) { + xml_node_t *sim; + const char *type = "18"; /* default to EAP-SIM */ + + sim = xml_node_create(ctx->xml, cred, NULL, "SIM"); + add_text_node(ctx, sim, "IMSI", imsi); + if (ctx->eap_method && os_strcmp(ctx->eap_method, "AKA") == 0) + type = "23"; + else if (ctx->eap_method && + os_strcmp(ctx->eap_method, "AKA'") == 0) + type = "50"; + add_text_node(ctx, sim, "EAPType", type); + } else if (cert) { + xml_node_t *dc; + dc = xml_node_create(ctx->xml, cred, NULL, + "DigitalCertificate"); + add_text_node(ctx, dc, "CertificateType", "x509v3"); + add_text_node(ctx, dc, "CertSHA256Fingerprint", cert); + } else { + userpw = build_username_password(ctx, cred, user, pw); + add_text_node(ctx, userpw, "MachineManaged", + machine_managed ? "TRUE" : "FALSE"); + eap = xml_node_create(ctx->xml, userpw, NULL, "EAPMethod"); + add_text_node(ctx, eap, "EAPType", "21"); + add_text_node(ctx, eap, "InnerMethod", "MS-CHAP-V2"); + } + add_text_node(ctx, cred, "Realm", realm); + + return pps; +} + + +static xml_node_t * spp_exec_get_certificate(struct hs20_svc *ctx, + const char *session_id, + const char *user, + const char *realm, + int add_est_user) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *enroll, *exec_node; + char *val; + char password[11]; + char *b64; + + if (add_est_user && new_password(password, sizeof(password)) < 0) + return NULL; + + spp_node = build_post_dev_data_response(ctx, &ns, session_id, "OK", + NULL); + if (spp_node == NULL) + return NULL; + + exec_node = xml_node_create(ctx->xml, spp_node, ns, "exec"); + + enroll = xml_node_create(ctx->xml, exec_node, ns, "getCertificate"); + xml_node_add_attr(ctx->xml, enroll, NULL, "enrollmentProtocol", "EST"); + + val = db_get_osu_config_val(ctx, realm, "est_url"); + xml_node_create_text(ctx->xml, enroll, ns, "enrollmentServerURI", + val ? val : ""); + os_free(val); + + if (!add_est_user) + return spp_node; + + xml_node_create_text(ctx->xml, enroll, ns, "estUserID", user); + + b64 = base64_encode(password, strlen(password), NULL); + if (b64 == NULL) { + xml_node_free(ctx->xml, spp_node); + return NULL; + } + xml_node_create_text(ctx->xml, enroll, ns, "estPassword", b64); + free(b64); + + db_update_session_password(ctx, user, realm, session_id, password); + + return spp_node; +} + + +static xml_node_t * hs20_user_input_registration(struct hs20_svc *ctx, + const char *session_id, + int enrollment_done) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *node = NULL; + xml_node_t *pps, *tnds; + char buf[400]; + char *str; + char *user, *realm, *pw, *type, *mm, *test; + const char *status; + int cert = 0; + int machine_managed = 0; + char *fingerprint; + + user = db_get_session_val(ctx, NULL, NULL, session_id, "user"); + realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm"); + pw = db_get_session_val(ctx, NULL, NULL, session_id, "password"); + + if (!user || !realm || !pw) { + debug_print(ctx, 1, "Could not find session info from DB for " + "the new subscription"); + free(user); + free(realm); + free(pw); + return NULL; + } + + mm = db_get_session_val(ctx, NULL, NULL, session_id, "machine_managed"); + if (mm && atoi(mm)) + machine_managed = 1; + free(mm); + + type = db_get_session_val(ctx, NULL, NULL, session_id, "type"); + if (type && strcmp(type, "cert") == 0) + cert = 1; + free(type); + + if (cert && !enrollment_done) { + xml_node_t *ret; + hs20_eventlog(ctx, user, realm, session_id, + "request client certificate enrollment", NULL); + ret = spp_exec_get_certificate(ctx, session_id, user, realm, 1); + free(user); + free(realm); + free(pw); + return ret; + } + + if (!cert && strlen(pw) == 0) { + machine_managed = 1; + free(pw); + pw = malloc(11); + if (pw == NULL || new_password(pw, 11) < 0) { + free(user); + free(realm); + free(pw); + return NULL; + } + } + + status = "Provisioning complete, request sppUpdateResponse"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (spp_node == NULL) + return NULL; + + fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert"); + test = db_get_session_val(ctx, NULL, NULL, session_id, "test"); + if (test) + debug_print(ctx, 1, "TEST: Requested special behavior: %s", + test); + pps = build_pps(ctx, user, realm, pw, + fingerprint ? fingerprint : NULL, machine_managed, + test, NULL, NULL, NULL, NULL); + free(fingerprint); + free(test); + if (!pps) { + xml_node_free(ctx->xml, spp_node); + free(user); + free(realm); + free(pw); + return NULL; + } + + debug_print(ctx, 1, "Request DB subscription registration on success " + "notification"); + if (machine_managed) { + db_update_session_password(ctx, user, realm, session_id, pw); + db_update_session_machine_managed(ctx, user, realm, session_id, + machine_managed); + } + db_add_session_pps(ctx, user, realm, session_id, pps); + + hs20_eventlog_node(ctx, user, realm, session_id, + "new subscription", pps); + free(user); + free(pw); + + tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL); + xml_node_free(ctx->xml, pps); + if (!tnds) { + xml_node_free(ctx->xml, spp_node); + free(realm); + return NULL; + } + + str = xml_node_to_str(ctx->xml, tnds); + xml_node_free(ctx->xml, tnds); + if (str == NULL) { + xml_node_free(ctx->xml, spp_node); + free(realm); + return NULL; + } + + node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str); + free(str); + snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm); + free(realm); + xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf); + xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS); + + return spp_node; +} + + +static xml_node_t * hs20_user_input_free_remediation(struct hs20_svc *ctx, + const char *user, + const char *realm, + const char *session_id) +{ + xml_namespace_t *ns; + xml_node_t *spp_node; + xml_node_t *cred; + char buf[400]; + char *status; + char *free_account, *pw; + + free_account = db_get_osu_config_val(ctx, realm, "free_account"); + if (free_account == NULL) + return NULL; + pw = db_get_val(ctx, free_account, realm, "password", 0); + if (pw == NULL) { + free(free_account); + return NULL; + } + + cred = build_credential_pw(ctx, free_account, realm, pw, 1); + free(free_account); + free(pw); + if (!cred) { + xml_node_free(ctx->xml, cred); + return NULL; + } + + status = "Remediation complete, request sppUpdateResponse"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (spp_node == NULL) + return NULL; + + snprintf(buf, sizeof(buf), + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", + realm); + + if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) { + xml_node_free(ctx->xml, spp_node); + return NULL; + } + + hs20_eventlog_node(ctx, user, realm, session_id, + "free/public remediation", cred); + xml_node_free(ctx->xml, cred); + + return spp_node; +} + + +static xml_node_t * hs20_user_input_complete(struct hs20_svc *ctx, + const char *user, + const char *realm, int dmacc, + const char *session_id) +{ + char *val; + enum hs20_session_operation oper; + + val = db_get_session_val(ctx, user, realm, session_id, "operation"); + if (val == NULL) { + debug_print(ctx, 1, "No session %s found to continue", + session_id); + return NULL; + } + oper = atoi(val); + free(val); + + if (oper == USER_REMEDIATION) { + return hs20_user_input_remediation(ctx, user, realm, dmacc, + session_id); + } + + if (oper == FREE_REMEDIATION) { + return hs20_user_input_free_remediation(ctx, user, realm, + session_id); + } + + if (oper == SUBSCRIPTION_REGISTRATION) { + return hs20_user_input_registration(ctx, session_id, 0); + } + + debug_print(ctx, 1, "User session %s not in state for user input " + "completion", session_id); + return NULL; +} + + +static xml_node_t * hs20_cert_reenroll_complete(struct hs20_svc *ctx, + const char *session_id) +{ + char *user, *realm, *cert; + char *status; + xml_namespace_t *ns; + xml_node_t *spp_node, *cred; + char buf[400]; + + user = db_get_session_val(ctx, NULL, NULL, session_id, "user"); + realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm"); + cert = db_get_session_val(ctx, NULL, NULL, session_id, "cert"); + if (!user || !realm || !cert) { + debug_print(ctx, 1, + "Could not find session info from DB for certificate reenrollment"); + free(user); + free(realm); + free(cert); + return NULL; + } + + cred = build_credential_cert(ctx, user, realm, cert); + if (!cred) { + debug_print(ctx, 1, "Could not build credential"); + free(user); + free(realm); + free(cert); + return NULL; + } + + status = "Remediation complete, request sppUpdateResponse"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (spp_node == NULL) { + debug_print(ctx, 1, "Could not build sppPostDevDataResponse"); + free(user); + free(realm); + free(cert); + xml_node_free(ctx->xml, cred); + return NULL; + } + + snprintf(buf, sizeof(buf), + "./Wi-Fi/%s/PerProviderSubscription/Cred01/Credential", + realm); + + if (add_update_node(ctx, spp_node, ns, buf, cred) < 0) { + debug_print(ctx, 1, "Could not add update node"); + xml_node_free(ctx->xml, spp_node); + free(user); + free(realm); + free(cert); + return NULL; + } + + hs20_eventlog_node(ctx, user, realm, session_id, + "certificate reenrollment", cred); + xml_node_free(ctx->xml, cred); + + free(user); + free(realm); + free(cert); + return spp_node; +} + + +static xml_node_t * hs20_cert_enroll_completed(struct hs20_svc *ctx, + const char *user, + const char *realm, int dmacc, + const char *session_id) +{ + char *val; + enum hs20_session_operation oper; + + val = db_get_session_val(ctx, NULL, NULL, session_id, "operation"); + if (val == NULL) { + debug_print(ctx, 1, "No session %s found to continue", + session_id); + return NULL; + } + oper = atoi(val); + free(val); + + if (oper == SUBSCRIPTION_REGISTRATION) + return hs20_user_input_registration(ctx, session_id, 1); + if (oper == CERT_REENROLL) + return hs20_cert_reenroll_complete(ctx, session_id); + + debug_print(ctx, 1, "User session %s not in state for certificate " + "enrollment completion", session_id); + return NULL; +} + + +static xml_node_t * hs20_cert_enroll_failed(struct hs20_svc *ctx, + const char *user, + const char *realm, int dmacc, + const char *session_id) +{ + char *val; + enum hs20_session_operation oper; + xml_node_t *spp_node, *node; + char *status; + xml_namespace_t *ns; + + val = db_get_session_val(ctx, user, realm, session_id, "operation"); + if (val == NULL) { + debug_print(ctx, 1, "No session %s found to continue", + session_id); + return NULL; + } + oper = atoi(val); + free(val); + + if (oper != SUBSCRIPTION_REGISTRATION) { + debug_print(ctx, 1, "User session %s not in state for " + "enrollment failure", session_id); + return NULL; + } + + status = "Error occurred"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (spp_node == NULL) + return NULL; + node = xml_node_create(ctx->xml, spp_node, ns, "sppError"); + xml_node_add_attr(ctx->xml, node, NULL, "errorCode", + "Credentials cannot be provisioned at this time"); + db_remove_session(ctx, user, realm, session_id); + + return spp_node; +} + + +static xml_node_t * hs20_sim_provisioning(struct hs20_svc *ctx, + const char *user, + const char *realm, int dmacc, + const char *session_id) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *node = NULL; + xml_node_t *pps, *tnds; + char buf[400]; + char *str; + const char *status; + char dmacc_username[32]; + char dmacc_password[32]; + char *policy; + xml_node_t *policy_node = NULL; + + if (!ctx->imsi) { + debug_print(ctx, 1, "IMSI not available for SIM provisioning"); + return NULL; + } + + if (new_password(dmacc_username, sizeof(dmacc_username)) < 0 || + new_password(dmacc_password, sizeof(dmacc_password)) < 0) { + debug_print(ctx, 1, + "Failed to generate DMAcc username/password"); + return NULL; + } + + status = "Provisioning complete, request sppUpdateResponse"; + spp_node = build_post_dev_data_response(ctx, &ns, session_id, status, + NULL); + if (!spp_node) + return NULL; + + policy = db_get_osu_config_val(ctx, realm, "sim_policy"); + if (policy) { + policy_node = read_policy_file(ctx, policy); + os_free(policy); + if (!policy_node) { + xml_node_free(ctx->xml, spp_node); + return NULL; + } + update_policy_update_uri(ctx, realm, policy_node); + node = get_node_uri(ctx->xml, policy_node, + "Policy/PolicyUpdate"); + if (node) + build_username_password(ctx, node, dmacc_username, + dmacc_password); + } + + pps = build_pps(ctx, NULL, realm, NULL, NULL, 0, NULL, ctx->imsi, + dmacc_username, dmacc_password, policy_node); + if (!pps) { + xml_node_free(ctx->xml, spp_node); + return NULL; + } + + debug_print(ctx, 1, + "Request DB subscription registration on success notification"); + if (!user || !user[0]) + user = ctx->imsi; + db_add_session(ctx, user, realm, session_id, NULL, NULL, + SUBSCRIPTION_REGISTRATION, NULL); + db_add_session_dmacc(ctx, session_id, dmacc_username, dmacc_password); + if (ctx->eap_method) + db_add_session_eap_method(ctx, session_id, ctx->eap_method); + if (ctx->id_hash) + db_add_session_id_hash(ctx, session_id, ctx->id_hash); + db_add_session_pps(ctx, user, realm, session_id, pps); + + hs20_eventlog_node(ctx, user, realm, session_id, + "new subscription", pps); + + tnds = mo_to_tnds(ctx->xml, pps, 0, URN_HS20_PPS, NULL); + xml_node_free(ctx->xml, pps); + if (!tnds) { + xml_node_free(ctx->xml, spp_node); + return NULL; + } + + str = xml_node_to_str(ctx->xml, tnds); + xml_node_free(ctx->xml, tnds); + if (!str) { + xml_node_free(ctx->xml, spp_node); + return NULL; + } + + node = xml_node_create_text(ctx->xml, spp_node, ns, "addMO", str); + free(str); + snprintf(buf, sizeof(buf), "./Wi-Fi/%s/PerProviderSubscription", realm); + xml_node_add_attr(ctx->xml, node, ns, "managementTreeURI", buf); + xml_node_add_attr(ctx->xml, node, ns, "moURN", URN_HS20_PPS); + + return spp_node; +} + + +static xml_node_t * hs20_spp_post_dev_data(struct hs20_svc *ctx, + xml_node_t *node, + const char *user, + const char *realm, + const char *session_id, + int dmacc) +{ + const char *req_reason; + char *redirect_uri = NULL; + char *req_reason_buf = NULL; + char str[200]; + xml_node_t *ret = NULL, *devinfo = NULL, *devdetail = NULL; + xml_node_t *mo, *macaddr; + char *version; + int valid; + char *supp, *pos; + char *err; + u8 wifi_mac_addr[ETH_ALEN]; + + version = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI, + "sppVersion"); + if (version == NULL || strstr(version, "1.0") == NULL) { + ret = build_post_dev_data_response( + ctx, NULL, session_id, "Error occurred", + "SPP version not supported"); + hs20_eventlog_node(ctx, user, realm, session_id, + "Unsupported sppVersion", ret); + xml_node_get_attr_value_free(ctx->xml, version); + return ret; + } + xml_node_get_attr_value_free(ctx->xml, version); + + mo = get_node(ctx->xml, node, "supportedMOList"); + if (mo == NULL) { + ret = build_post_dev_data_response( + ctx, NULL, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, session_id, + "No supportedMOList element", ret); + return ret; + } + supp = xml_node_get_text(ctx->xml, mo); + for (pos = supp; pos && *pos; pos++) + *pos = tolower(*pos); + if (supp == NULL || + strstr(supp, URN_OMA_DM_DEVINFO) == NULL || + strstr(supp, URN_OMA_DM_DEVDETAIL) == NULL || + strstr(supp, URN_HS20_PPS) == NULL) { + xml_node_get_text_free(ctx->xml, supp); + ret = build_post_dev_data_response( + ctx, NULL, session_id, "Error occurred", + "One or more mandatory MOs not supported"); + hs20_eventlog_node(ctx, user, realm, session_id, + "Unsupported MOs", ret); + return ret; + } + xml_node_get_text_free(ctx->xml, supp); + + req_reason_buf = xml_node_get_attr_value(ctx->xml, node, + "requestReason"); + if (req_reason_buf == NULL) { + debug_print(ctx, 1, "No requestReason attribute"); + return NULL; + } + req_reason = req_reason_buf; + + redirect_uri = xml_node_get_attr_value(ctx->xml, node, "redirectURI"); + + debug_print(ctx, 1, "requestReason: %s sessionID: %s redirectURI: %s", + req_reason, session_id, redirect_uri); + snprintf(str, sizeof(str), "sppPostDevData: requestReason=%s", + req_reason); + hs20_eventlog(ctx, user, realm, session_id, str, NULL); + + devinfo = spp_get_mo(ctx, node, URN_OMA_DM_DEVINFO, &valid, &err); + if (devinfo == NULL) { + ret = build_post_dev_data_response(ctx, NULL, session_id, + "Error occurred", "Other"); + hs20_eventlog_node(ctx, user, realm, session_id, + "No DevInfo moContainer in sppPostDevData", + ret); + os_free(err); + goto out; + } + + hs20_eventlog_node(ctx, user, realm, session_id, + "Received DevInfo MO", devinfo); + if (valid == 0) { + hs20_eventlog(ctx, user, realm, session_id, + "OMA-DM DDF DTD validation errors in DevInfo MO", + err); + ret = build_post_dev_data_response(ctx, NULL, session_id, + "Error occurred", "Other"); + os_free(err); + goto out; + } + os_free(err); + if (user) + db_update_mo(ctx, user, realm, "devinfo", devinfo); + + devdetail = spp_get_mo(ctx, node, URN_OMA_DM_DEVDETAIL, &valid, &err); + if (devdetail == NULL) { + ret = build_post_dev_data_response(ctx, NULL, session_id, + "Error occurred", "Other"); + hs20_eventlog_node(ctx, user, realm, session_id, + "No DevDetail moContainer in sppPostDevData", + ret); + os_free(err); + goto out; + } + + hs20_eventlog_node(ctx, user, realm, session_id, + "Received DevDetail MO", devdetail); + if (valid == 0) { + hs20_eventlog(ctx, user, realm, session_id, + "OMA-DM DDF DTD validation errors " + "in DevDetail MO", err); + ret = build_post_dev_data_response(ctx, NULL, session_id, + "Error occurred", "Other"); + os_free(err); + goto out; + } + os_free(err); + + os_memset(wifi_mac_addr, 0, ETH_ALEN); + macaddr = get_node(ctx->xml, devdetail, + "Ext/org.wi-fi/Wi-Fi/Wi-FiMACAddress"); + if (macaddr) { + char *addr, buf[50]; + + addr = xml_node_get_text(ctx->xml, macaddr); + if (addr && hwaddr_compact_aton(addr, wifi_mac_addr) == 0) { + snprintf(buf, sizeof(buf), "DevDetail MAC address: " + MACSTR, MAC2STR(wifi_mac_addr)); + hs20_eventlog(ctx, user, realm, session_id, buf, NULL); + xml_node_get_text_free(ctx->xml, addr); + } else { + hs20_eventlog(ctx, user, realm, session_id, + "Could not extract MAC address from DevDetail", + NULL); + } + } else { + hs20_eventlog(ctx, user, realm, session_id, + "No MAC address in DevDetail", NULL); + } + + if (user) + db_update_mo(ctx, user, realm, "devdetail", devdetail); + + if (user) + mo = spp_get_mo(ctx, node, URN_HS20_PPS, &valid, &err); + else { + mo = NULL; + err = NULL; + } + if (user && mo) { + hs20_eventlog_node(ctx, user, realm, session_id, + "Received PPS MO", mo); + if (valid == 0) { + hs20_eventlog(ctx, user, realm, session_id, + "OMA-DM DDF DTD validation errors " + "in PPS MO", err); + xml_node_get_attr_value_free(ctx->xml, redirect_uri); + os_free(err); + return build_post_dev_data_response( + ctx, NULL, session_id, + "Error occurred", "Other"); + } + db_update_mo(ctx, user, realm, "pps", mo); + db_update_val(ctx, user, realm, "fetch_pps", "0", dmacc); + xml_node_free(ctx->xml, mo); + } + os_free(err); + + if (user && !mo) { + char *fetch; + int fetch_pps; + + fetch = db_get_val(ctx, user, realm, "fetch_pps", dmacc); + fetch_pps = fetch ? atoi(fetch) : 0; + free(fetch); + + if (fetch_pps) { + enum hs20_session_operation oper; + if (strcasecmp(req_reason, "Subscription remediation") + == 0) + oper = CONTINUE_SUBSCRIPTION_REMEDIATION; + else if (strcasecmp(req_reason, "Policy update") == 0) + oper = CONTINUE_POLICY_UPDATE; + else + oper = NO_OPERATION; + if (db_add_session(ctx, user, realm, session_id, NULL, + NULL, oper, NULL) < 0) + goto out; + + ret = spp_exec_upload_mo(ctx, session_id, + URN_HS20_PPS); + hs20_eventlog_node(ctx, user, realm, session_id, + "request PPS MO upload", + ret); + goto out; + } + } + + if (user && strcasecmp(req_reason, "MO upload") == 0) { + char *val = db_get_session_val(ctx, user, realm, session_id, + "operation"); + enum hs20_session_operation oper; + if (!val) { + debug_print(ctx, 1, "No session %s found to continue", + session_id); + goto out; + } + oper = atoi(val); + free(val); + if (oper == CONTINUE_SUBSCRIPTION_REMEDIATION) + req_reason = "Subscription remediation"; + else if (oper == CONTINUE_POLICY_UPDATE) + req_reason = "Policy update"; + else { + debug_print(ctx, 1, + "No pending operation in session %s", + session_id); + goto out; + } + } + + if (strcasecmp(req_reason, "Subscription registration") == 0) { + ret = hs20_subscription_registration(ctx, realm, session_id, + redirect_uri, + wifi_mac_addr); + hs20_eventlog_node(ctx, user, realm, session_id, + "subscription registration response", + ret); + goto out; + } + if (user && strcasecmp(req_reason, "Subscription remediation") == 0) { + ret = hs20_subscription_remediation(ctx, user, realm, + session_id, dmacc, + redirect_uri); + hs20_eventlog_node(ctx, user, realm, session_id, + "subscription remediation response", + ret); + goto out; + } + if (user && strcasecmp(req_reason, "Policy update") == 0) { + ret = hs20_policy_update(ctx, user, realm, session_id, dmacc); + hs20_eventlog_node(ctx, user, realm, session_id, + "policy update response", + ret); + goto out; + } + + if (strcasecmp(req_reason, "User input completed") == 0) { + db_add_session_devinfo(ctx, session_id, devinfo); + db_add_session_devdetail(ctx, session_id, devdetail); + ret = hs20_user_input_complete(ctx, user, realm, dmacc, + session_id); + hs20_eventlog_node(ctx, user, realm, session_id, + "user input completed response", ret); + goto out; + } + + if (strcasecmp(req_reason, "Certificate enrollment completed") == 0) { + ret = hs20_cert_enroll_completed(ctx, user, realm, dmacc, + session_id); + hs20_eventlog_node(ctx, user, realm, session_id, + "certificate enrollment response", ret); + goto out; + } + + if (strcasecmp(req_reason, "Certificate enrollment failed") == 0) { + ret = hs20_cert_enroll_failed(ctx, user, realm, dmacc, + session_id); + hs20_eventlog_node(ctx, user, realm, session_id, + "certificate enrollment failed response", + ret); + goto out; + } + + if (strcasecmp(req_reason, "Subscription provisioning") == 0) { + ret = hs20_sim_provisioning(ctx, user, realm, dmacc, + session_id); + hs20_eventlog_node(ctx, user, realm, session_id, + "subscription provisioning response", + ret); + goto out; + } + + debug_print(ctx, 1, "Unsupported requestReason '%s' user '%s'", + req_reason, user); +out: + xml_node_get_attr_value_free(ctx->xml, req_reason_buf); + xml_node_get_attr_value_free(ctx->xml, redirect_uri); + if (devinfo) + xml_node_free(ctx->xml, devinfo); + if (devdetail) + xml_node_free(ctx->xml, devdetail); + return ret; +} + + +static xml_node_t * build_spp_exchange_complete(struct hs20_svc *ctx, + const char *session_id, + const char *status, + const char *error_code) +{ + xml_namespace_t *ns; + xml_node_t *spp_node, *node; + + spp_node = xml_node_create_root(ctx->xml, SPP_NS_URI, "spp", &ns, + "sppExchangeComplete"); + + + xml_node_add_attr(ctx->xml, spp_node, ns, "sppVersion", "1.0"); + xml_node_add_attr(ctx->xml, spp_node, ns, "sessionID", session_id); + xml_node_add_attr(ctx->xml, spp_node, ns, "sppStatus", status); + + if (error_code) { + node = xml_node_create(ctx->xml, spp_node, ns, "sppError"); + xml_node_add_attr(ctx->xml, node, NULL, "errorCode", + error_code); + } + + return spp_node; +} + + +static int add_subscription(struct hs20_svc *ctx, const char *session_id) +{ + char *user, *realm, *pw, *pw_mm, *pps, *str; + char *osu_user, *osu_password, *eap_method; + char *policy = NULL; + char *sql; + int ret = -1; + char *free_account; + int free_acc; + char *type; + int cert = 0; + char *cert_pem, *fingerprint; + const char *method; + + user = db_get_session_val(ctx, NULL, NULL, session_id, "user"); + realm = db_get_session_val(ctx, NULL, NULL, session_id, "realm"); + pw = db_get_session_val(ctx, NULL, NULL, session_id, "password"); + pw_mm = db_get_session_val(ctx, NULL, NULL, session_id, + "machine_managed"); + pps = db_get_session_val(ctx, NULL, NULL, session_id, "pps"); + cert_pem = db_get_session_val(ctx, NULL, NULL, session_id, "cert_pem"); + fingerprint = db_get_session_val(ctx, NULL, NULL, session_id, "cert"); + type = db_get_session_val(ctx, NULL, NULL, session_id, "type"); + if (type && strcmp(type, "cert") == 0) + cert = 1; + free(type); + osu_user = db_get_session_val(ctx, NULL, NULL, session_id, "osu_user"); + osu_password = db_get_session_val(ctx, NULL, NULL, session_id, + "osu_password"); + eap_method = db_get_session_val(ctx, NULL, NULL, session_id, + "eap_method"); + + if (!user || !realm || !pw) { + debug_print(ctx, 1, "Could not find session info from DB for " + "the new subscription"); + goto out; + } + + free_account = db_get_osu_config_val(ctx, realm, "free_account"); + free_acc = free_account && strcmp(free_account, user) == 0; + free(free_account); + + policy = db_get_osu_config_val(ctx, realm, "sim_policy"); + + debug_print(ctx, 1, + "New subscription: user='%s' realm='%s' free_acc=%d", + user, realm, free_acc); + debug_print(ctx, 1, "New subscription: pps='%s'", pps); + + sql = sqlite3_mprintf("UPDATE eventlog SET user=%Q, realm=%Q WHERE " + "sessionid=%Q AND (user='' OR user IS NULL)", + user, realm, session_id); + if (sql) { + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to update eventlog in " + "sqlite database: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); + } + + if (free_acc) { + hs20_eventlog(ctx, user, realm, session_id, + "completed shared free account registration", + NULL); + ret = 0; + goto out; + } + + str = db_get_session_val(ctx, NULL, NULL, session_id, "mac_addr"); + + if (eap_method && eap_method[0]) + method = eap_method; + else + method = cert ? "TLS" : "TTLS-MSCHAPV2"; + sql = sqlite3_mprintf("INSERT INTO users(identity,realm,phase2,methods,cert,cert_pem,machine_managed,mac_addr,osu_user,osu_password,policy) VALUES (%Q,%Q,%d,%Q,%Q,%Q,%d,%Q,%Q,%Q,%Q)", + user, realm, cert ? 0 : 1, + method, + fingerprint ? fingerprint : "", + cert_pem ? cert_pem : "", + pw_mm && atoi(pw_mm) ? 1 : 0, + str ? str : "", + osu_user ? osu_user : "", + osu_password ? osu_password : "", + policy ? policy : ""); + free(str); + if (sql == NULL) + goto out; + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) { + debug_print(ctx, 1, "Failed to add user in sqlite database: %s", + sqlite3_errmsg(ctx->db)); + sqlite3_free(sql); + goto out; + } + sqlite3_free(sql); + + if (cert) + ret = 0; + else + ret = update_password(ctx, user, realm, pw, 0); + if (ret < 0) { + sql = sqlite3_mprintf("DELETE FROM users WHERE identity=%Q AND realm=%Q AND (phase2=1 OR methods='TLS')", + user, realm); + if (sql) { + debug_print(ctx, 1, "DB: %s", sql); + sqlite3_exec(ctx->db, sql, NULL, NULL, NULL); + sqlite3_free(sql); + } + } + + if (pps) + db_update_mo_str(ctx, user, realm, "pps", pps); + + str = db_get_session_val(ctx, NULL, NULL, session_id, "devinfo"); + if (str) { + db_update_mo_str(ctx, user, realm, "devinfo", str); + free(str); + } + + str = db_get_session_val(ctx, NULL, NULL, session_id, "devdetail"); + if (str) { + db_update_mo_str(ctx, user, realm, "devdetail", str); + free(str); + } + + if (cert && user) { + const char *serialnum; + + str = db_get_session_val(ctx, NULL, NULL, session_id, + "mac_addr"); + + if (os_strncmp(user, "cert-", 5) == 0) + serialnum = user + 5; + else + serialnum = ""; + sql = sqlite3_mprintf("INSERT OR REPLACE INTO cert_enroll (mac_addr,user,realm,serialnum) VALUES(%Q,%Q,%Q,%Q)", + str ? str : "", user, realm ? realm : "", + serialnum); + free(str); + if (sql) { + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != + SQLITE_OK) { + debug_print(ctx, 1, + "Failed to add cert_enroll entry into sqlite database: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); + } + } + + str = db_get_session_val(ctx, NULL, NULL, session_id, + "mobile_identifier_hash"); + if (str) { + sql = sqlite3_mprintf("DELETE FROM sim_provisioning WHERE mobile_identifier_hash=%Q", + str); + if (sql) { + debug_print(ctx, 1, "DB: %s", sql); + if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != + SQLITE_OK) { + debug_print(ctx, 1, + "Failed to delete pending sim_provisioning entry: %s", + sqlite3_errmsg(ctx->db)); + } + sqlite3_free(sql); + } + os_free(str); + } + + if (ret == 0) { + hs20_eventlog(ctx, user, realm, session_id, + "completed subscription registration", NULL); + } + +out: + free(user); + free(realm); + free(pw); + free(pw_mm); + free(pps); + free(cert_pem); + free(fingerprint); + free(osu_user); + free(osu_password); + free(eap_method); + os_free(policy); + return ret; +} + + +static xml_node_t * hs20_spp_update_response(struct hs20_svc *ctx, + xml_node_t *node, + const char *user, + const char *realm, + const char *session_id, + int dmacc) +{ + char *status; + xml_node_t *ret; + char *val; + enum hs20_session_operation oper; + + status = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI, + "sppStatus"); + if (status == NULL) { + debug_print(ctx, 1, "No sppStatus attribute"); + return NULL; + } + + debug_print(ctx, 1, "sppUpdateResponse: sppStatus: %s sessionID: %s", + status, session_id); + + val = db_get_session_val(ctx, NULL, NULL, session_id, "operation"); + if (!val) { + debug_print(ctx, 1, + "No session active for sessionID: %s", + session_id); + oper = NO_OPERATION; + } else + oper = atoi(val); + + if (strcasecmp(status, "OK") == 0) { + char *new_pw = NULL; + + xml_node_get_attr_value_free(ctx->xml, status); + + if (oper == USER_REMEDIATION) { + new_pw = db_get_session_val(ctx, user, realm, + session_id, "password"); + if (new_pw == NULL || strlen(new_pw) == 0) { + free(new_pw); + ret = build_spp_exchange_complete( + ctx, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, + session_id, "No password " + "had been assigned for " + "session", ret); + db_remove_session(ctx, user, realm, session_id); + return ret; + } + oper = UPDATE_PASSWORD; + } + if (oper == UPDATE_PASSWORD) { + if (!new_pw) { + new_pw = db_get_session_val(ctx, user, realm, + session_id, + "password"); + if (!new_pw) { + db_remove_session(ctx, user, realm, + session_id); + return NULL; + } + } + debug_print(ctx, 1, "Update user '%s' password in DB", + user); + if (update_password(ctx, user, realm, new_pw, dmacc) < + 0) { + debug_print(ctx, 1, "Failed to update user " + "'%s' password in DB", user); + ret = build_spp_exchange_complete( + ctx, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, + session_id, "Failed to " + "update database", ret); + db_remove_session(ctx, user, realm, session_id); + return ret; + } + hs20_eventlog(ctx, user, realm, + session_id, "Updated user password " + "in database", NULL); + } + if (oper == CLEAR_REMEDIATION) { + debug_print(ctx, 1, + "Clear remediation requirement for user '%s' in DB", + user); + if (clear_remediation(ctx, user, realm, dmacc) < 0) { + debug_print(ctx, 1, + "Failed to clear remediation requirement for user '%s' in DB", + user); + ret = build_spp_exchange_complete( + ctx, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, + session_id, + "Failed to update database", + ret); + db_remove_session(ctx, user, realm, session_id); + return ret; + } + hs20_eventlog(ctx, user, realm, + session_id, + "Cleared remediation requirement in database", + NULL); + } + if (oper == SUBSCRIPTION_REGISTRATION) { + if (add_subscription(ctx, session_id) < 0) { + debug_print(ctx, 1, "Failed to add " + "subscription into DB"); + ret = build_spp_exchange_complete( + ctx, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, + session_id, "Failed to " + "update database", ret); + db_remove_session(ctx, user, realm, session_id); + return ret; + } + } + if (oper == POLICY_REMEDIATION || oper == POLICY_UPDATE) { + char *val; + val = db_get_val(ctx, user, realm, "remediation", + dmacc); + if (val && strcmp(val, "policy") == 0) + db_update_val(ctx, user, realm, "remediation", + "", dmacc); + free(val); + } + if (oper == POLICY_UPDATE) + db_update_val(ctx, user, realm, "polupd_done", "1", + dmacc); + if (oper == CERT_REENROLL) { + char *new_user; + char event[200]; + + new_user = db_get_session_val(ctx, NULL, NULL, + session_id, "user"); + if (!new_user) { + debug_print(ctx, 1, + "Failed to find new user name (cert-serialnum)"); + ret = build_spp_exchange_complete( + ctx, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, + session_id, + "Failed to find new user name (cert reenroll)", + ret); + db_remove_session(ctx, NULL, NULL, session_id); + return ret; + } + + debug_print(ctx, 1, + "Update certificate user entry to use the new serial number (old=%s new=%s)", + user, new_user); + os_snprintf(event, sizeof(event), "renamed user to: %s", + new_user); + hs20_eventlog(ctx, user, realm, session_id, event, + NULL); + + if (db_update_val(ctx, user, realm, "identity", + new_user, 0) < 0 || + db_update_val(ctx, new_user, realm, "remediation", + "", 0) < 0) { + debug_print(ctx, 1, + "Failed to update user name (cert-serialnum)"); + ret = build_spp_exchange_complete( + ctx, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, + session_id, + "Failed to update user name (cert reenroll)", + ret); + db_remove_session(ctx, NULL, NULL, session_id); + os_free(new_user); + return ret; + } + + os_free(new_user); + } + ret = build_spp_exchange_complete( + ctx, session_id, + "Exchange complete, release TLS connection", NULL); + hs20_eventlog_node(ctx, user, realm, session_id, + "Exchange completed", ret); + db_remove_session(ctx, NULL, NULL, session_id); + return ret; + } + + ret = build_spp_exchange_complete(ctx, session_id, "Error occurred", + "Other"); + hs20_eventlog_node(ctx, user, realm, session_id, "Error occurred", ret); + db_remove_session(ctx, user, realm, session_id); + xml_node_get_attr_value_free(ctx->xml, status); + return ret; +} + + +#define SPP_SESSION_ID_LEN 16 + +static char * gen_spp_session_id(void) +{ + FILE *f; + int i; + char *session; + + session = os_malloc(SPP_SESSION_ID_LEN * 2 + 1); + if (session == NULL) + return NULL; + + f = fopen("/dev/urandom", "r"); + if (f == NULL) { + os_free(session); + return NULL; + } + for (i = 0; i < SPP_SESSION_ID_LEN; i++) + os_snprintf(session + i * 2, 3, "%02x", fgetc(f)); + + fclose(f); + return session; +} + +xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node, + const char *auth_user, + const char *auth_realm, int dmacc) +{ + xml_node_t *ret = NULL; + char *session_id; + const char *op_name; + char *xml_err; + char fname[200]; + + debug_dump_node(ctx, "received request", node); + + if (!dmacc && auth_user && auth_realm) { + char *real; + real = db_get_val(ctx, auth_user, auth_realm, "identity", 0); + if (!real) { + real = db_get_val(ctx, auth_user, auth_realm, + "identity", 1); + if (real) + dmacc = 1; + } + os_free(real); + } + + snprintf(fname, sizeof(fname), "%s/spp/spp.xsd", ctx->root_dir); + if (xml_validate(ctx->xml, node, fname, &xml_err) < 0) { + /* + * We may not be able to extract the sessionID from invalid + * input, but well, we can try. + */ + session_id = xml_node_get_attr_value_ns(ctx->xml, node, + SPP_NS_URI, + "sessionID"); + debug_print(ctx, 1, + "SPP message failed validation, xsd file: %s xml-error: %s", + fname, xml_err); + hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, + "SPP message failed validation", node); + hs20_eventlog(ctx, auth_user, auth_realm, session_id, + "Validation errors", xml_err); + os_free(xml_err); + xml_node_get_attr_value_free(ctx->xml, session_id); + /* TODO: what to return here? */ + ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL, + "SppValidationError"); + return ret; + } + + session_id = xml_node_get_attr_value_ns(ctx->xml, node, SPP_NS_URI, + "sessionID"); + if (session_id) { + char *tmp; + debug_print(ctx, 1, "Received sessionID %s", session_id); + tmp = os_strdup(session_id); + xml_node_get_attr_value_free(ctx->xml, session_id); + if (tmp == NULL) + return NULL; + session_id = tmp; + } else { + session_id = gen_spp_session_id(); + if (session_id == NULL) { + debug_print(ctx, 1, "Failed to generate sessionID"); + return NULL; + } + debug_print(ctx, 1, "Generated sessionID %s", session_id); + } + + op_name = xml_node_get_localname(ctx->xml, node); + if (op_name == NULL) { + debug_print(ctx, 1, "Could not get op_name"); + return NULL; + } + + if (strcmp(op_name, "sppPostDevData") == 0) { + hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, + "sppPostDevData received and validated", + node); + ret = hs20_spp_post_dev_data(ctx, node, auth_user, auth_realm, + session_id, dmacc); + } else if (strcmp(op_name, "sppUpdateResponse") == 0) { + hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, + "sppUpdateResponse received and validated", + node); + ret = hs20_spp_update_response(ctx, node, auth_user, + auth_realm, session_id, dmacc); + } else { + hs20_eventlog_node(ctx, auth_user, auth_realm, session_id, + "Unsupported SPP message received and " + "validated", node); + debug_print(ctx, 1, "Unsupported operation '%s'", op_name); + /* TODO: what to return here? */ + ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL, + "SppUnknownCommandError"); + } + os_free(session_id); + + if (ret == NULL) { + /* TODO: what to return here? */ + ret = xml_node_create_root(ctx->xml, NULL, NULL, NULL, + "SppInternalError"); + } + + return ret; +} + + +int hs20_spp_server_init(struct hs20_svc *ctx) +{ + char fname[200]; + ctx->db = NULL; + snprintf(fname, sizeof(fname), "%s/AS/DB/eap_user.db", ctx->root_dir); + if (sqlite3_open(fname, &ctx->db)) { + printf("Failed to open sqlite database: %s\n", + sqlite3_errmsg(ctx->db)); + sqlite3_close(ctx->db); + return -1; + } + + return 0; +} + + +void hs20_spp_server_deinit(struct hs20_svc *ctx) +{ + sqlite3_close(ctx->db); + ctx->db = NULL; +} diff --git a/contrib/wpa/hs20/server/spp_server.h b/contrib/wpa/hs20/server/spp_server.h new file mode 100644 index 000000000000..421974c607b8 --- /dev/null +++ b/contrib/wpa/hs20/server/spp_server.h @@ -0,0 +1,36 @@ +/* + * Hotspot 2.0 SPP server + * Copyright (c) 2012-2013, Qualcomm Atheros, Inc. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SPP_SERVER_H +#define SPP_SERVER_H + +struct hs20_svc { + const void *ctx; + struct xml_node_ctx *xml; + char *root_dir; + FILE *debug_log; + sqlite3 *db; + const char *addr; + const char *test; + const char *imsi; + const char *eap_method; + const char *id_hash; +}; + + +void debug_print(struct hs20_svc *ctx, int print, const char *fmt, ...) + __attribute__ ((format (printf, 3, 4))); +void debug_dump_node(struct hs20_svc *ctx, const char *title, xml_node_t *node); + +xml_node_t * hs20_spp_server_process(struct hs20_svc *ctx, xml_node_t *node, + const char *auth_user, + const char *auth_realm, int dmacc); +int hs20_spp_server_init(struct hs20_svc *ctx); +void hs20_spp_server_deinit(struct hs20_svc *ctx); + +#endif /* SPP_SERVER_H */ diff --git a/contrib/wpa/hs20/server/sql-example.txt b/contrib/wpa/hs20/server/sql-example.txt new file mode 100644 index 000000000000..20dcf2f5c688 --- /dev/null +++ b/contrib/wpa/hs20/server/sql-example.txt @@ -0,0 +1,17 @@ +INSERT INTO osu_config(realm,field,value) VALUES('example.com','fqdn','example.com'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','friendly_name','Example Operator'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','spp_http_auth_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/spp-root-ca.der'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_url','https://osu-server.osu.example.com/hs20/files/aaa-root-ca.der'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','aaa_trust_root_cert_fingerprint','5b393a9246865569485c2605c3304e48212b449367858299beba9384c4cf4647'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_account','free'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','policy_url','https://subscription-server.osu.example.com/hs20/spp.php?realm=example.com'); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','remediation_url','https://subscription-server.osu.example.com/hs20/remediation.php?session_id='); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','free_remediation_url','https://subscription-server.osu.example.com/hs20/free-remediation.php?session_id='); +INSERT INTO osu_config(realm,field,value) VALUES('example.com','signup_url','https://subscription-server.osu.example.com/hs20/signup.php?session_id='); + + +INSERT INTO users(identity,realm,methods,password,phase2,shared) VALUES('free','example.com','TTLS-MSCHAPV2','free',1,1); + +INSERT INTO wildcards(identity,methods) VALUES('','TTLS,TLS'); diff --git a/contrib/wpa/hs20/server/sql.txt b/contrib/wpa/hs20/server/sql.txt new file mode 100644 index 000000000000..2cc6edea4063 --- /dev/null +++ b/contrib/wpa/hs20/server/sql.txt @@ -0,0 +1,108 @@ +CREATE TABLE eventlog( + user TEXT, + realm TEXT, + sessionid TEXT COLLATE NOCASE, + timestamp TEXT, + notes TEXT, + dump TEXT, + addr TEXT +); + +CREATE TABLE sessions( + timestamp TEXT, + id TEXT COLLATE NOCASE, + user TEXT, + realm TEXT, + password TEXT, + machine_managed BOOLEAN, + operation INTEGER, + type TEXT, + pps TEXT, + redirect_uri TEXT, + devinfo TEXT, + devdetail TEXT, + cert TEXT, + cert_pem TEXT, + mac_addr TEXT, + osu_user TEXT, + osu_password TEXT, + eap_method TEXT, + mobile_identifier_hash TEXT, + test TEXT +); + +CREATE index sessions_id_index ON sessions(id); + +CREATE TABLE osu_config( + realm TEXT, + field TEXT, + value TEXT +); + +CREATE TABLE users( + identity TEXT PRIMARY KEY, + methods TEXT, + password TEXT, + machine_managed BOOLEAN, + remediation TEXT, + phase2 INTEGER, + realm TEXT, + policy TEXT, + devinfo TEXT, + devdetail TEXT, + pps TEXT, + fetch_pps INTEGER, + osu_user TEXT, + osu_password TEXT, + shared INTEGER, + cert TEXT, + cert_pem TEXT, + t_c_timestamp INTEGER, + mac_addr TEXT, + last_msk TEXT, + polupd_done TEXT, + subrem TEXT +); + +CREATE TABLE wildcards( + identity TEXT PRIMARY KEY, + methods TEXT +); + +CREATE TABLE authlog( + timestamp TEXT, + session TEXT, + nas_ip TEXT, + username TEXT, + note TEXT +); + +CREATE TABLE pending_tc( + mac_addr TEXT PRIMARY KEY, + identity TEXT +); + +CREATE TABLE current_sessions( + mac_addr TEXT PRIMARY KEY, + identity TEXT, + start_time TEXT, + nas TEXT, + hs20_t_c_filtering BOOLEAN, + waiting_coa_ack BOOLEAN, + coa_ack_received BOOLEAN +); + +CREATE TABLE cert_enroll( + mac_addr TEXT PRIMARY KEY, + user TEXT, + realm TEXT, + serialnum TEXT +); + +CREATE TABLE sim_provisioning( + mobile_identifier_hash TEXT PRIMARY KEY, + imsi TEXT, + mac_addr TEXT, + eap_method TEXT, + timestamp TEXT +); diff --git a/contrib/wpa/hs20/server/www/add-free.php b/contrib/wpa/hs20/server/www/add-free.php new file mode 100644 index 000000000000..1efc65563274 --- /dev/null +++ b/contrib/wpa/hs20/server/www/add-free.php @@ -0,0 +1,50 @@ +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_POST["id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]); +else + die("Missing session id"); +if (strlen($id) < 32) + die("Invalid session id"); + +$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} + +$uri = $row['redirect_uri']; +$rowid = $row['rowid']; +$realm = $row['realm']; + +$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch(); +if (!$row || strlen($row['value']) == 0) { + die("Free account disabled"); +} + +$user = $row['value']; + +$row = $db->query("SELECT password FROM users WHERE identity='$user' AND realm='$realm'")->fetch(); +if (!$row) + die("Free account not found"); + +$pw = $row['password']; + +if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', machine_managed='1' WHERE rowid=$rowid")) { + die("Failed to update session database"); +} + +$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " . + "VALUES ('$user', '$realm', '$id', " . + "strftime('%Y-%m-%d %H:%M:%f','now'), " . + "'completed user input response for a new PPS MO')"); + +header("Location: $uri", true, 302); + +?> diff --git a/contrib/wpa/hs20/server/www/add-mo.php b/contrib/wpa/hs20/server/www/add-mo.php new file mode 100644 index 000000000000..a3b4513531f8 --- /dev/null +++ b/contrib/wpa/hs20/server/www/add-mo.php @@ -0,0 +1,56 @@ +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_POST["id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]); +else + die("Missing session id"); + +$user = $_POST["user"]; +$pw = $_POST["password"]; +if (strlen($id) < 32 || !isset($user) || !isset($pw)) { + die("Invalid POST data"); +} + +if (strlen($user) < 1 || strncasecmp($user, "cert-", 5) == 0) { + echo "<html><body><p><red>Invalid username</red></p>\n"; + echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n"; + echo "</body></html>\n"; + exit; +} + +$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} +$realm = $row['realm']; + +$userrow = $db->query("SELECT identity FROM users WHERE identity='$user' AND realm='$realm'")->fetch(); +if ($userrow) { + echo "<html><body><p><red>Selected username is not available</red></p>\n"; + echo "<a href=\"signup.php?session_id=$id\">Try again</a>\n"; + echo "</body></html>\n"; + exit; +} + +$uri = $row['redirect_uri']; +$rowid = $row['rowid']; + +if (!$db->exec("UPDATE sessions SET user='$user', password='$pw', realm='$realm', type='password' WHERE rowid=$rowid")) { + die("Failed to update session database"); +} + +$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " . + "VALUES ('$user', '$realm', '$id', " . + "strftime('%Y-%m-%d %H:%M:%f','now'), " . + "'completed user input response for a new PPS MO')"); + +header("Location: $uri", true, 302); + +?> diff --git a/contrib/wpa/hs20/server/www/cert-enroll.php b/contrib/wpa/hs20/server/www/cert-enroll.php new file mode 100644 index 000000000000..f023ca5a5b03 --- /dev/null +++ b/contrib/wpa/hs20/server/www/cert-enroll.php @@ -0,0 +1,39 @@ +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_GET["id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]); +else + die("Missing session id"); +if (strlen($id) < 32) + die("Invalid session id"); + +$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} + +$uri = $row['redirect_uri']; +$rowid = $row['rowid']; +$realm = $row['realm']; + +$user = sha1(mt_rand()); + +if (!$db->exec("UPDATE sessions SET user='$user', type='cert' WHERE rowid=$rowid")) { + die("Failed to update session database"); +} + +$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " . + "VALUES ('', '$realm', '$id', " . + "strftime('%Y-%m-%d %H:%M:%f','now'), " . + "'completed user input response for client certificate enrollment')"); + +header("Location: $uri", true, 302); + +?> diff --git a/contrib/wpa/hs20/server/www/config.php b/contrib/wpa/hs20/server/www/config.php new file mode 100644 index 000000000000..4272b102a88c --- /dev/null +++ b/contrib/wpa/hs20/server/www/config.php @@ -0,0 +1,7 @@ +<?php +$osu_root = "/home/user/hs20-server"; +$osu_db = "sqlite:$osu_root/AS/DB/eap_user.db"; +$t_c_file = "$osu_root/terms-and-conditions"; +$t_c_timestamp = 123456789; +$hostapd_ctrl = "udg:///home/user/hs20-server/AS/ctrl/as" +?> diff --git a/contrib/wpa/hs20/server/www/est.php b/contrib/wpa/hs20/server/www/est.php new file mode 100644 index 000000000000..b7fb260d56c4 --- /dev/null +++ b/contrib/wpa/hs20/server/www/est.php @@ -0,0 +1,232 @@ +<?php + +require('config.php'); + +$params = explode("/", $_SERVER["PATH_INFO"], 3); +$realm = $params[1]; +$cmd = $params[2]; +$method = $_SERVER["REQUEST_METHOD"]; + +unset($user); +unset($rowid); + +$db = new PDO($osu_db); +if (!$db) { + error_log("EST: Could not access database"); + die("Could not access database"); +} + +if (!empty($_SERVER['PHP_AUTH_DIGEST'])) { + $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, + 'uri'=>1, 'response'=>1); + $data = array(); + $keys = implode('|', array_keys($needed)); + preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', + $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER); + foreach ($matches as $m) { + $data[$m[1]] = $m[3] ? $m[3] : $m[4]; + unset($needed[$m[1]]); + } + if ($needed) { + error_log("EST: Missing auth parameter"); + die('Authentication failed'); + } + $user = $data['username']; + if (strlen($user) < 1) { + error_log("EST: Empty username"); + die('Authentication failed'); + } + + $sql = "SELECT rowid,password,operation FROM sessions " . + "WHERE user='$user' AND realm='$realm'"; + $q = $db->query($sql); + if (!$q) { + error_log("EST: Session not found for user=$user realm=$realm"); + die("Session not found"); + } + $row = $q->fetch(); + if (!$row) { + error_log("EST: Session fetch failed for user=$user realm=$realm"); + die('Session not found'); + } + $rowid = $row['rowid']; + + $oper = $row['operation']; + if ($oper != '5') { + error_log("EST: Unexpected operation $oper for user=$user realm=$realm"); + die("Session not found"); + } + $pw = $row['password']; + if (strlen($pw) < 1) { + error_log("EST: Empty password for user=$user realm=$realm"); + die('Authentication failed'); + } + + $A1 = md5($user . ':' . $realm . ':' . $pw); + $A2 = md5($method . ':' . $data['uri']); + $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' . + $data['cnonce'] . ':' . $data['qop'] . ':' . $A2); + if ($data['response'] != $resp) { + error_log("EST: Incorrect authentication response for user=$user realm=$realm"); + die('Authentication failed'); + } +} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) && + $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" && + isset($_SERVER["SSL_CLIENT_M_SERIAL"])) { + $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"]; + $sql = "SELECT rowid,password,operation FROM sessions " . + "WHERE user='$user' AND realm='$realm'"; + $q = $db->query($sql); + if (!$q) { + error_log("EST: Session not found for user=$user realm=$realm"); + die("Session not found"); + } + $row = $q->fetch(); + if (!$row) { + error_log("EST: Session fetch failed for user=$user realm=$realm"); + die('Session not found'); + } + $rowid = $row['rowid']; + + $oper = $row['operation']; + if ($oper != '10') { + error_log("EST: Unexpected operation $oper for user=$user realm=$realm"); + die("Session not found"); + } +} + + +if ($method == "GET" && $cmd == "cacerts") { + $fname = "$osu_root/est/$realm-cacerts.pkcs7"; + if (!file_exists($fname)) { + error_log("EST: cacerts - unknown realm $realm"); + die("Unknown realm"); + } + + header("Content-Transfer-Encoding: base64"); + header("Content-Type: application/pkcs7-mime"); + + $data = file_get_contents($fname); + echo wordwrap(base64_encode($data), 72, "\n", true); + echo "\n"; + error_log("EST: cacerts"); +} else if ($method == "GET" && $cmd == "csrattrs") { + header("Content-Transfer-Encoding: base64"); + header("Content-Type: application/csrattrs"); + readfile("$osu_root/est/est-attrs.b64"); + error_log("EST: csrattrs"); +} else if ($method == "POST" && + ($cmd == "simpleenroll" || $cmd == "simplereenroll")) { + $reenroll = $cmd == "simplereenroll"; + if (!$reenroll && (!isset($user) || strlen($user) == 0)) { + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Digest realm="'.$realm. + '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); + error_log("EST: simpleenroll - require authentication"); + die('Authentication required'); + } + if ($reenroll && + (!isset($user) || + !isset($_SERVER["SSL_CLIENT_VERIFY"]) || + $_SERVER["SSL_CLIENT_VERIFY"] != "SUCCESS")) { + header('HTTP/1.1 403 Forbidden'); + error_log("EST: simplereenroll - require certificate authentication"); + die('Authentication required'); + } + if (!isset($_SERVER["CONTENT_TYPE"])) { + error_log("EST: simpleenroll without Content-Type"); + die("Missing Content-Type"); + } + if (!stristr($_SERVER["CONTENT_TYPE"], "application/pkcs10")) { + error_log("EST: simpleenroll - unexpected Content-Type: " . + $_SERVER["CONTENT_TYPE"]); + die("Unexpected Content-Type"); + } + + $data = file_get_contents("php://input"); + error_log("EST: simpleenroll - POST data from php://input: " . $data); + $req = base64_decode($data); + if ($req == FALSE) { + error_log("EST: simpleenroll - Invalid base64-encoded PKCS#10 data"); + die("Invalid base64-encoded PKCS#10 data"); + } + $cadir = "$osu_root/est"; + $reqfile = "$cadir/tmp/cert-req.pkcs10"; + $f = fopen($reqfile, "wb"); + fwrite($f, $req); + fclose($f); + + $req_pem = "$reqfile.pem"; + if (file_exists($req_pem)) + unlink($req_pem); + exec("openssl req -in $reqfile -inform DER -out $req_pem -outform PEM"); + if (!file_exists($req_pem)) { + error_log("EST: simpleenroll - Failed to parse certificate request"); + die("Failed to parse certificate request"); + } + + /* FIX: validate request and add HS 2.0 extensions to cert */ + $cert_pem = "$cadir/tmp/req-signed.pem"; + if (file_exists($cert_pem)) + unlink($cert_pem); + exec("openssl x509 -req -in $req_pem -CAkey $cadir/cakey.pem -out $cert_pem -CA $cadir/cacert.pem -CAserial $cadir/serial -days 365 -text"); + if (!file_exists($cert_pem)) { + error_log("EST: simpleenroll - Failed to sign certificate"); + die("Failed to sign certificate"); + } + + $cert = file_get_contents($cert_pem); + $handle = popen("openssl x509 -in $cert_pem -serial -noout", "r"); + $serial = fread($handle, 200); + pclose($handle); + $pattern = "/serial=(?P<snhex>[0-9a-fA-F:]*)/m"; + preg_match($pattern, $serial, $matches); + if (!isset($matches['snhex']) || strlen($matches['snhex']) < 1) { + error_log("EST: simpleenroll - Could not get serial number"); + die("Could not get serial number"); + } + $sn = str_replace(":", "", strtoupper($matches['snhex'])); + + $user = "cert-$sn"; + error_log("EST: user = $user"); + + $cert_der = "$cadir/tmp/req-signed.der"; + if (file_exists($cert_der)) + unlink($cert_der); + exec("openssl x509 -in $cert_pem -inform PEM -out $cert_der -outform DER"); + if (!file_exists($cert_der)) { + error_log("EST: simpleenroll - Failed to convert certificate"); + die("Failed to convert certificate"); + } + $der = file_get_contents($cert_der); + $fingerprint = hash("sha256", $der); + error_log("EST: sha256(DER cert): $fingerprint"); + + $pkcs7 = "$cadir/tmp/est-client.pkcs7"; + if (file_exists($pkcs7)) + unlink($pkcs7); + exec("openssl crl2pkcs7 -nocrl -certfile $cert_pem -out $pkcs7 -outform DER"); + if (!file_exists($pkcs7)) { + error_log("EST: simpleenroll - Failed to prepare PKCS#7 file"); + die("Failed to prepare PKCS#7 file"); + } + + if (!$db->exec("UPDATE sessions SET user='$user', cert='$fingerprint', cert_pem='$cert' WHERE rowid=$rowid")) { + error_log("EST: simpleenroll - Failed to update session database"); + die("Failed to update session database"); + } + + header("Content-Transfer-Encoding: base64"); + header("Content-Type: application/pkcs7-mime"); + + $data = file_get_contents($pkcs7); + $resp = wordwrap(base64_encode($data), 72, "\n", true); + echo $resp . "\n"; + error_log("EST: simpleenroll - PKCS#7 response: " . $resp); +} else { + header("HTTP/1.0 404 Not Found"); + error_log("EST: Unexpected method or path"); + die("Unexpected method or path"); +} + +?> diff --git a/contrib/wpa/hs20/server/www/free-remediation.php b/contrib/wpa/hs20/server/www/free-remediation.php new file mode 100644 index 000000000000..5648b30e8d6b --- /dev/null +++ b/contrib/wpa/hs20/server/www/free-remediation.php @@ -0,0 +1,19 @@ +<html> +<head> +<title>Hotspot 2.0 - public and free hotspot - remediation</title> +</head> +<body> + +<h3>Hotspot 2.0 - public and free hotspot</h3> + +<p>Terms and conditions have changed. You need to accept the new terms +to continue using this network.</p> + +<p>Terms and conditions..</p> + +<?php +echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Accept</a><br>\n"; +?> + +</body> +</html> diff --git a/contrib/wpa/hs20/server/www/free.php b/contrib/wpa/hs20/server/www/free.php new file mode 100644 index 000000000000..8195069ed8ff --- /dev/null +++ b/contrib/wpa/hs20/server/www/free.php @@ -0,0 +1,23 @@ +<html> +<head> +<title>Hotspot 2.0 - public and free hotspot</title> +</head> +<body> + +<?php + +$id = $_GET["session_id"]; + +echo "<h3>Hotspot 2.0 - public and free hotspot</h3>\n"; + +echo "<form action=\"add-free.php\" method=\"POST\">\n"; +echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n"; + +?> + +<p>Terms and conditions..</p> +<input type="submit" value="Accept"> +</form> + +</body> +</html> diff --git a/contrib/wpa/hs20/server/www/redirect.php b/contrib/wpa/hs20/server/www/redirect.php new file mode 100644 index 000000000000..8fc9cd644273 --- /dev/null +++ b/contrib/wpa/hs20/server/www/redirect.php @@ -0,0 +1,32 @@ +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_GET["id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["id"]); +else + $id = 0; + +$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} + +$uri = $row['redirect_uri']; + +header("Location: $uri", true, 302); + +$user = $row['user']; +$realm = $row['realm']; + +$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " . + "VALUES ('$user', '$realm', '$id', " . + "strftime('%Y-%m-%d %H:%M:%f','now'), " . + "'redirected after user input')"); + +?> diff --git a/contrib/wpa/hs20/server/www/remediation-pw.php b/contrib/wpa/hs20/server/www/remediation-pw.php new file mode 100644 index 000000000000..76fdccbdf9f7 --- /dev/null +++ b/contrib/wpa/hs20/server/www/remediation-pw.php @@ -0,0 +1,41 @@ +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_POST["id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_POST["id"]); +else + die("Missing session id"); + +$pw = $_POST["password"]; +if (strlen($id) < 32 || !isset($pw)) { + die("Invalid POST data"); +} + +$row = $db->query("SELECT rowid,* FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} +$user = $row['user']; +$realm = $row['realm']; + +$uri = $row['redirect_uri']; +$rowid = $row['rowid']; + +if (!$db->exec("UPDATE sessions SET password='$pw' WHERE rowid=$rowid")) { + die("Failed to update session database"); +} + +$db->exec("INSERT INTO eventlog(user,realm,sessionid,timestamp,notes) " . + "VALUES ('$user', '$realm', '$id', " . + "strftime('%Y-%m-%d %H:%M:%f','now'), " . + "'completed user input response for subscription remediation')"); + +header("Location: $uri", true, 302); + +?> diff --git a/contrib/wpa/hs20/server/www/remediation.php b/contrib/wpa/hs20/server/www/remediation.php new file mode 100644 index 000000000000..3628065ac225 --- /dev/null +++ b/contrib/wpa/hs20/server/www/remediation.php @@ -0,0 +1,55 @@ +<html> +<head> +<title>Hotspot 2.0 subscription remediation</title> +</head> +<body> + +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_GET["session_id"])) + $id = preg_replace("/[^a-fA-F0-9]/", "", $_GET["session_id"]); +else + $id = 0; +echo "SessionID: " . $id . "<br>\n"; + +$row = $db->query("SELECT * FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found"); +} + +$username = $row['user']; +echo "User: " . $username . "@" . $row['realm'] . "<br>\n"; + +$user = $db->query("SELECT machine_managed,methods FROM users WHERE identity='$username'")->fetch(); +if ($user == false) { + die("User not found"); +} + +echo "<hr><br>\n"; + +$cert = $user['methods'] == "TLS" || strncmp($username, "cert-", 5) == 0; + +if ($cert) { + echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n"; +} else if ($user['machine_managed'] == "1") { + echo "<a href=\"redirect.php?id=" . $_GET["session_id"] . "\">Complete user subscription remediation</a><br>\n"; + echo "This will provide a new machine-generated password.<br>\n"; +} else { + echo "<form action=\"remediation-pw.php\" method=\"POST\">\n"; + echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n"; + echo "New password: <input type=\"password\" name=\"password\"><br>\n"; + echo "<input type=\"submit\" value=\"Change password\">\n"; + echo "</form>\n"; +} + +?> + +</body> +</html> diff --git a/contrib/wpa/hs20/server/www/signup.php b/contrib/wpa/hs20/server/www/signup.php new file mode 100644 index 000000000000..80a9d403e8fc --- /dev/null +++ b/contrib/wpa/hs20/server/www/signup.php @@ -0,0 +1,59 @@ +<html> +<head> +<title>Hotspot 2.0 signup</title> +</head> +<body> + +<?php + +$id = $_GET["session_id"]; + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +$row = $db->query("SELECT realm,test FROM sessions WHERE id='$id'")->fetch(); +if ($row == false) { + die("Session not found for id: $id"); +} +$realm = $row['realm']; +$test = $row['test']; + +if (strlen($test) > 0) { + echo "<p style=\"color:#FF0000\">Special test functionality: $test</red></big></p>\n"; +} + +echo "<h3>Sign up for a subscription - $realm</h3>\n"; + +echo "<p>This page can be used to select between three different types of subscriptions for testing purposes.</p>\n"; + +echo "<h4>Option 1 - shared free access credential</h4>\n"; + +$row = $db->query("SELECT value FROM osu_config WHERE realm='$realm' AND field='free_account'")->fetch(); +if ($row && strlen($row['value']) > 0) { + echo "<p><a href=\"free.php?session_id=$id\">Sign up for free access</a></p>\n"; +} + +echo "<h4>Option 2 - username/password credential</h4>\n"; + +echo "<form action=\"add-mo.php\" method=\"POST\">\n"; +echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n"; +?> +Select a username and password. Leave password empty to get automatically +generated and machine managed password.<br> +Username: <input type="text" name="user"><br> +Password: <input type="password" name="password"><br> +<input type="submit" value="Complete subscription registration"> +</form> + +<?php +echo "<h4>Option 3 - client certificate credential</h4>\n"; + +echo "<p><a href=\"cert-enroll.php?id=$id\">Enroll a client certificate</a></p>\n" +?> + +</body> +</html> diff --git a/contrib/wpa/hs20/server/www/spp.php b/contrib/wpa/hs20/server/www/spp.php new file mode 100644 index 000000000000..c56d3d69e0ed --- /dev/null +++ b/contrib/wpa/hs20/server/www/spp.php @@ -0,0 +1,168 @@ +<?php + +require('config.php'); + +if (!stristr($_SERVER["CONTENT_TYPE"], "application/soap+xml")) { + error_log("spp.php - Unexpected Content-Type " . $_SERVER["CONTENT_TYPE"]); + die("Unexpected Content-Type"); +} + +if ($_SERVER["REQUEST_METHOD"] != "POST") { + error_log("spp.php - Unexpected method " . $_SERVER["REQUEST_METHOD"]); + die("Unexpected method"); +} + +if (isset($_GET["realm"])) { + $realm = $_GET["realm"]; + $realm = PREG_REPLACE("/[^0-9a-zA-Z\.\-]/i", '', $realm); +} else { + error_log("spp.php - Realm not specified"); + die("Realm not specified"); +} + +if (isset($_GET["test"])) + $test = PREG_REPLACE("/[^0-9a-zA-Z\_\-]/i", '', $_GET["test"]); +else + $test = ""; + +unset($user); +putenv("HS20CERT"); + +if (!empty($_SERVER['PHP_AUTH_DIGEST'])) { + $needed = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, + 'uri'=>1, 'response'=>1); + $data = array(); + $keys = implode('|', array_keys($needed)); + preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', + $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER); + foreach ($matches as $m) { + $data[$m[1]] = $m[3] ? $m[3] : $m[4]; + unset($needed[$m[1]]); + } + if ($needed) { + error_log("spp.php - Authentication failed - missing: " . print_r($needed)); + die('Authentication failed'); + } + $user = $data['username']; + if (strlen($user) < 1) { + error_log("spp.php - Authentication failed - empty username"); + die('Authentication failed'); + } + + + $db = new PDO($osu_db); + if (!$db) { + error_log("spp.php - Could not access database"); + die("Could not access database"); + } + $row = $db->query("SELECT password FROM users " . + "WHERE identity='$user' AND realm='$realm'")->fetch(); + if (!$row) { + $row = $db->query("SELECT osu_password FROM users " . + "WHERE osu_user='$user' AND realm='$realm'")->fetch(); + $pw = $row['osu_password']; + } else + $pw = $row['password']; + if (!$row) { + error_log("spp.php - Authentication failed - user '$user' not found"); + die('Authentication failed'); + } + if (strlen($pw) < 1) { + error_log("spp.php - Authentication failed - empty password"); + die('Authentication failed'); + } + + $A1 = md5($user . ':' . $realm . ':' . $pw); + $A2 = md5($_SERVER['REQUEST_METHOD'] . ':' . $data['uri']); + $resp = md5($A1 . ':' . $data['nonce'] . ':' . $data['nc'] . ':' . + $data['cnonce'] . ':' . $data['qop'] . ':' . $A2); + if ($data['response'] != $resp) { + error_log("Authentication failure - response mismatch"); + die('Authentication failed'); + } +} else if (isset($_SERVER["SSL_CLIENT_VERIFY"]) && + $_SERVER["SSL_CLIENT_VERIFY"] == "SUCCESS" && + isset($_SERVER["SSL_CLIENT_M_SERIAL"])) { + $user = "cert-" . $_SERVER["SSL_CLIENT_M_SERIAL"]; + putenv("HS20CERT=yes"); +} else if (isset($_GET["hotspot2dot0-mobile-identifier-hash"])) { + $id_hash = $_GET["hotspot2dot0-mobile-identifier-hash"]; + $id_hash = PREG_REPLACE("/[^0-9a-h]/i", '', $id_hash); + + $db = new PDO($osu_db); + if (!$db) { + error_log("spp.php - Could not access database"); + die("Could not access database"); + } + + $row = $db->query("SELECT * FROM sim_provisioning " . + "WHERE mobile_identifier_hash='$id_hash'")->fetch(); + if (!$row) { + error_log("spp.php - SIM provisioning failed - mobile_identifier_hash not found"); + die('SIM provisioning failed - mobile_identifier_hash not found'); + } + + $imsi = $row['imsi']; + $mac_addr = $row['mac_addr']; + $eap_method = $row['eap_method']; + + $row = $db->query("SELECT COUNT(*) FROM osu_config " . + "WHERE realm='$realm'")->fetch(); + if (!$row || intval($row[0]) < 1) { + error_log("spp.php - SIM provisioning failed - realm $realm not found"); + die('SIM provisioning failed'); + } + + error_log("spp.php - SIM provisioning for IMSI $imsi"); + putenv("HS20SIMPROV=yes"); + putenv("HS20IMSI=$imsi"); + putenv("HS20MACADDR=$mac_addr"); + putenv("HS20EAPMETHOD=$eap_method"); + putenv("HS20IDHASH=$id_hash"); +} else if (!isset($_SERVER["PATH_INFO"]) || + $_SERVER["PATH_INFO"] != "/signup") { + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Digest realm="'.$realm. + '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); + error_log("spp.php - Authentication required (not signup)"); + die('Authentication required (not signup)'); +} + + +if (isset($user) && strlen($user) > 0) + putenv("HS20USER=$user"); +else + putenv("HS20USER"); + +putenv("HS20REALM=$realm"); +$postdata = file_get_contents("php://input"); +putenv("HS20POST=$postdata"); +$addr = $_SERVER["REMOTE_ADDR"]; +putenv("HS20ADDR=$addr"); +putenv("HS20TEST=$test"); + +$last = exec("$osu_root/spp/hs20_spp_server -r$osu_root -f/tmp/hs20_spp_server.log", $output, $ret); + +if ($ret == 2) { + if (empty($_SERVER['PHP_AUTH_DIGEST'])) { + header('HTTP/1.1 401 Unauthorized'); + header('WWW-Authenticate: Digest realm="'.$realm. + '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); + error_log("spp.php - Authentication required (ret 2)"); + die('Authentication required'); + } else { + error_log("spp.php - Unexpected authentication error"); + die("Unexpected authentication error"); + } +} +if ($ret != 0) { + error_log("spp.php - Failed to process SPP request"); + die("Failed to process SPP request"); +} +//error_log("spp.php: Response: " . implode($output)); + +header("Content-Type: application/soap+xml"); + +echo implode($output); + +?> diff --git a/contrib/wpa/hs20/server/www/terms.php b/contrib/wpa/hs20/server/www/terms.php new file mode 100644 index 000000000000..acba23ef1ad7 --- /dev/null +++ b/contrib/wpa/hs20/server/www/terms.php @@ -0,0 +1,87 @@ +<?php + +require('config.php'); + +function print_header() +{ + echo "<html>\n"; + echo "<head><title>HS 2.0 Terms and Conditions</title></head>\n"; + echo "<body>\n"; +} + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (!isset($_GET["addr"])) { + die("Missing addr parameter"); +} +$addr = $_GET["addr"]; + +$accept = isset($_GET["accept"]) && $_GET["accept"] == "yes"; + +$res = $db->prepare("SELECT identity FROM pending_tc WHERE mac_addr=?"); +$res->execute(array($addr)); +$row = $res->fetch(); +if (!$row) { + die("No pending session for the specified MAC address"); +} +$identity = $row[0]; + +if (!$accept) { + print_header(); + + echo "<p>Accept the following terms and conditions by clicking here: <a href=\"terms.php?addr=$addr&accept=yes\">Accept</a></p>\n<hr>\n"; + readfile($t_c_file); +} else { + $res = $db->prepare("UPDATE users SET t_c_timestamp=? WHERE identity=?"); + if (!$res->execute(array($t_c_timestamp, $identity))) { + die("Failed to update user account."); + } + + $res = $db->prepare("DELETE FROM pending_tc WHERE mac_addr=?"); + $res->execute(array($addr)); + + $fp = fsockopen($hostapd_ctrl); + if (!$fp) { + die("Could not connect to hostapd(AS)"); + } + + fwrite($fp, "DAC_REQUEST coa $addr t_c_clear"); + fclose($fp); + + $waiting = true; + $ack = false; + for ($i = 1; $i <= 10; $i++) { + $res = $db->prepare("SELECT waiting_coa_ack,coa_ack_received FROM current_sessions WHERE mac_addr=?"); + $res->execute(array($addr)); + $row = $res->fetch(); + if (!$row) { + die("No current session for the specified MAC address"); + } + if (strlen($row[0]) > 0) + $waiting = $row[0] == 1; + if (strlen($row[1]) > 0) + $ack = $row[1] == 1; + $res->closeCursor(); + if (!$waiting) + break; + sleep(1); + } + if ($ack) { + header('X-WFA-Hotspot20-Filtering: removed'); + print_header(); + echo "<p>Terms and conditions were accepted.</p>\n"; + + echo "<P>Filtering disabled.</P>\n"; + } else { + print_header(); + echo "<P>Failed to disable filtering.</P>\n"; + } +} + +?> + +</body> +</html> diff --git a/contrib/wpa/hs20/server/www/users.php b/contrib/wpa/hs20/server/www/users.php new file mode 100644 index 000000000000..2bd555275dda --- /dev/null +++ b/contrib/wpa/hs20/server/www/users.php @@ -0,0 +1,377 @@ +<?php + +require('config.php'); + +$db = new PDO($osu_db); +if (!$db) { + die($sqliteerror); +} + +if (isset($_GET["id"])) { + $id = $_GET["id"]; + if (!is_numeric($id)) + $id = 0; +} else + $id = 0; +if (isset($_GET["cmd"])) + $cmd = $_GET["cmd"]; +else + $cmd = ''; + +if ($cmd == 'eventlog' && $id > 0) { + $row = $db->query("SELECT dump FROM eventlog WHERE rowid=$id")->fetch(); + $dump = $row['dump']; + if ($dump[0] == '<') { + header("Content-type: text/xml"); + echo "<?xml version=\"1.0\"?>\n"; + echo $dump; + } else { + header("Content-type: text/plain"); + echo $dump; + } + exit; +} + +if ($cmd == 'mo' && $id > 0) { + $mo = $_GET["mo"]; + if (!isset($mo)) + exit; + if ($mo != "devinfo" && $mo != "devdetail" && $mo != "pps") + exit; + $row = $db->query("SELECT $mo FROM users WHERE rowid=$id")->fetch(); + header("Content-type: text/xml"); + echo "<?xml version=\"1.0\"?>\n"; + echo $row[$mo]; + exit; +} + +if ($cmd == 'cert' && $id > 0) { + $row = $db->query("SELECT cert_pem FROM users WHERE rowid=$id")->fetch(); + header("Content-type: text/plain"); + echo $row['cert_pem']; + exit; +} + +?> + +<html> +<head><title>HS 2.0 users</title></head> +<body> + +<?php + +if ($cmd == 'subrem-clear' && $id > 0) { + $db->exec("UPDATE users SET remediation='' WHERE rowid=$id"); +} +if ($cmd == 'subrem-add-user' && $id > 0) { + $db->exec("UPDATE users SET remediation='user' WHERE rowid=$id"); +} +if ($cmd == 'subrem-add-machine' && $id > 0) { + $db->exec("UPDATE users SET remediation='machine' WHERE rowid=$id"); +} +if ($cmd == 'subrem-add-reenroll' && $id > 0) { + $db->exec("UPDATE users SET remediation='reenroll' WHERE rowid=$id"); +} +if ($cmd == 'subrem-add-policy' && $id > 0) { + $db->exec("UPDATE users SET remediation='policy' WHERE rowid=$id"); +} +if ($cmd == 'subrem-add-free' && $id > 0) { + $db->exec("UPDATE users SET remediation='free' WHERE rowid=$id"); +} +if ($cmd == 'fetch-pps-on' && $id > 0) { + $db->exec("UPDATE users SET fetch_pps=1 WHERE rowid=$id"); +} +if ($cmd == 'fetch-pps-off' && $id > 0) { + $db->exec("UPDATE users SET fetch_pps=0 WHERE rowid=$id"); +} +if ($cmd == 'reset-pw' && $id > 0) { + $db->exec("UPDATE users SET password='ChangeMe' WHERE rowid=$id"); +} +if ($cmd == "policy" && $id > 0 && isset($_GET["policy"])) { + $policy = $_GET["policy"]; + if ($policy == "no-policy" || + is_readable("$osu_root/spp/policy/$policy.xml")) { + $db->exec("UPDATE users SET policy='$policy' WHERE rowid=$id"); + } +} +if ($cmd == "account-type" && $id > 0 && isset($_GET["type"])) { + $type = $_GET["type"]; + if ($type == "shared") + $db->exec("UPDATE users SET shared=1 WHERE rowid=$id"); + if ($type == "default") + $db->exec("UPDATE users SET shared=0 WHERE rowid=$id"); +} + +if ($cmd == "set-osu-cred" && $id > 0) { + $osu_user = $_POST["osu_user"]; + $osu_password = $_POST["osu_password"]; + if (strlen($osu_user) == 0) + $osu_password = ""; + $db->exec("UPDATE users SET osu_user='$osu_user', osu_password='$osu_password' WHERE rowid=$id"); +} + +if ($cmd == 'clear-t-c' && $id > 0) { + $db->exec("UPDATE users SET t_c_timestamp=NULL WHERE rowid=$id"); +} + +$dump = 0; + +if ($id > 0) { + +if (isset($_GET["dump"])) { + $dump = $_GET["dump"]; + if (!is_numeric($dump)) + $dump = 0; +} else + $dump = 0; + +echo "[<a href=\"users.php\">All users</a>] "; +if ($dump == 0) + echo "[<a href=\"users.php?id=$id&dump=1\">Include debug dump</a>] "; +else + echo "[<a href=\"users.php?id=$id\">Without debug dump</a>] "; +echo "<br>\n"; + +$row = $db->query("SELECT rowid,* FROM users WHERE rowid=$id")->fetch(); + +echo "<H3>" . $row['identity'] . "@" . $row['realm'] . "</H3>\n"; + +echo "MO: "; +if (strlen($row['devinfo']) > 0) { + echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devinfo\">DevInfo</a>]\n"; +} +if (strlen($row['devdetail']) > 0) { + echo "[<a href=\"users.php?cmd=mo&id=$id&mo=devdetail\">DevDetail</a>]\n"; +} +if (strlen($row['pps']) > 0) { + echo "[<a href=\"users.php?cmd=mo&id=$id&mo=pps\">PPS</a>]\n"; +} +if (strlen($row['cert_pem']) > 0) { + echo "[<a href=\"users.php?cmd=cert&id=$id\">Certificate</a>]\n"; +} +echo "<BR>\n"; + +echo "Fetch PPS MO: "; +if ($row['fetch_pps'] == "1") { + echo "On next connection " . + "[<a href=\"users.php?cmd=fetch-pps-off&id=$id\">" . + "do not fetch</a>]<br>\n"; +} else { + echo "Do not fetch " . + "[<a href=\"users.php?cmd=fetch-pps-on&id=$id\">" . + "request fetch</a>]<br>\n"; +} + +$cert = $row['cert']; +if (strlen($cert) > 0) { + echo "Certificate fingerprint: $cert<br>\n"; +} + +echo "Remediation: "; +$rem = $row['remediation']; +if ($rem == "") { + echo "Not required"; + echo " [<a href=\"users.php?cmd=subrem-add-user&id=" . + $row['rowid'] . "\">add:user</a>]"; + echo " [<a href=\"users.php?cmd=subrem-add-machine&id=" . + $row['rowid'] . "\">add:machine</a>]"; + if ($row['methods'] == 'TLS') { + echo " [<a href=\"users.php?cmd=subrem-add-reenroll&id=" . + $row['rowid'] . "\">add:reenroll</a>]"; + } + echo " [<a href=\"users.php?cmd=subrem-add-policy&id=" . + $row['rowid'] . "\">add:policy</a>]"; + echo " [<a href=\"users.php?cmd=subrem-add-free&id=" . + $row['rowid'] . "\">add:free</a>]"; +} else if ($rem == "user") { + echo "User [<a href=\"users.php?cmd=subrem-clear&id=" . + $row['rowid'] . "\">clear</a>]"; +} else if ($rem == "policy") { + echo "Policy [<a href=\"users.php?cmd=subrem-clear&id=" . + $row['rowid'] . "\">clear</a>]"; +} else if ($rem == "free") { + echo "Free [<a href=\"users.php?cmd=subrem-clear&id=" . + $row['rowid'] . "\">clear</a>]"; +} else if ($rem == "reenroll") { + echo "Reenroll [<a href=\"users.php?cmd=subrem-clear&id=" . + $row['rowid'] . "\">clear</a>]"; +} else { + echo "Machine [<a href=\"users.php?cmd=subrem-clear&id=" . + $row['rowid'] . "\">clear</a>]"; +} +echo "<br>\n"; + +if (strncmp($row['identity'], "cert-", 5) != 0) + echo "Machine managed: " . ($row['machine_managed'] == "1" ? "TRUE" : "FALSE") . "<br>\n"; + +echo "<form>Policy: <select name=\"policy\" " . + "onChange=\"window.location='users.php?cmd=policy&id=" . + $row['rowid'] . "&policy=' + this.value;\">\n"; +echo "<option value=\"" . $row['policy'] . "\" selected>" . $row['policy'] . + "</option>\n"; +$files = scandir("$osu_root/spp/policy"); +foreach ($files as $file) { + if (!preg_match("/.xml$/", $file)) + continue; + if ($file == $row['policy'] . ".xml") + continue; + $p = substr($file, 0, -4); + echo "<option value=\"$p\">$p</option>\n"; +} +echo "<option value=\"no-policy\">no policy</option>\n"; +echo "</select></form>\n"; + +echo "<form>Account type: <select name=\"type\" " . + "onChange=\"window.location='users.php?cmd=account-type&id=" . + $row['rowid'] . "&type=' + this.value;\">\n"; +if ($row['shared'] > 0) { + $default_sel = ""; + $shared_sel = " selected"; +} else { + $default_sel = " selected"; + $shared_sel = ""; +} +echo "<option value=\"default\"$default_sel>default</option>\n"; +echo "<option value=\"shared\"$shared_sel>shared</option>\n"; +echo "</select></form>\n"; + +echo "Phase 2 method(s): " . $row['methods'] . "<br>\n"; + +echo "<br>\n"; +echo "<a href=\"users.php?cmd=reset-pw&id=" . + $row['rowid'] . "\">Reset AAA password</a><br>\n"; + +echo "<br>\n"; +echo "<form action=\"users.php?cmd=set-osu-cred&id=" . $row['rowid'] . + "\" method=\"POST\">\n"; +echo "OSU credentials (if username empty, AAA credentials are used):<br>\n"; +echo "username: <input type=\"text\" name=\"osu_user\" value=\"" . + $row['osu_user'] . "\">\n"; +echo "password: <input type=\"password\" name=\"osu_password\">\n"; +echo "<input type=\"submit\" value=\"Set OSU credentials\">\n"; +echo "</form>\n"; + +if (strlen($row['t_c_timestamp']) > 0) { + echo "<br>\n"; + echo "<a href=\"users.php?cmd=clear-t-c&id=" . + $row['rowid'] . + "\">Clear Terms and Conditions acceptance</a><br>\n"; +} + +echo "<hr>\n"; + +$user = $row['identity']; +$osu_user = $row['osu_user']; +$realm = $row['realm']; +} + +if ($id > 0 || ($id == 0 && $cmd == 'eventlog')) { + + if ($id == 0) { + echo "[<a href=\"users.php\">All users</a>] "; + echo "<br>\n"; + } + +echo "<table border=1>\n"; +echo "<tr>"; +if ($id == 0) { + echo "<th>user<th>realm"; +} +echo "<th>time<th>address<th>sessionID<th>notes"; +if ($dump > 0) + echo "<th>dump"; +echo "\n"; +if (isset($_GET["limit"])) { + $limit = $_GET["limit"]; + if (!is_numeric($limit)) + $limit = 20; +} else + $limit = 20; +if ($id == 0) + $res = $db->query("SELECT rowid,* FROM eventlog ORDER BY timestamp DESC LIMIT $limit"); +else if (strlen($osu_user) > 0) + $res = $db->query("SELECT rowid,* FROM eventlog WHERE (user='$user' OR user='$osu_user') AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit"); +else + $res = $db->query("SELECT rowid,* FROM eventlog WHERE user='$user' AND realm='$realm' ORDER BY timestamp DESC LIMIT $limit"); +foreach ($res as $row) { + echo "<tr>"; + if ($id == 0) { + echo "<td>" . $row['user'] . "\n"; + echo "<td>" . $row['realm'] . "\n"; + } + echo "<td>" . $row['timestamp'] . "\n"; + echo "<td>" . $row['addr'] . "\n"; + echo "<td>" . $row['sessionid'] . "\n"; + echo "<td>" . $row['notes'] . "\n"; + $d = $row['dump']; + if (strlen($d) > 0) { + echo "[<a href=\"users.php?cmd=eventlog&id=" . $row['rowid'] . + "\">"; + if ($d[0] == '<') + echo "XML"; + else + echo "txt"; + echo "</a>]\n"; + if ($dump > 0) + echo "<td>" . htmlspecialchars($d) . "\n"; + } +} +echo "</table>\n"; + +} + + +if ($id == 0 && $cmd != 'eventlog') { + +echo "[<a href=\"users.php?cmd=eventlog&limit=50\">Eventlog</a>] "; +echo "<br>\n"; + +echo "<table border=1 cellspacing=0 cellpadding=0>\n"; +echo "<tr><th>User<th>Realm<th><small>Remediation</small><th>Policy<th><small>Account type</small><th><small>Phase 2 method(s)</small><th>DevId<th>MAC Address<th>T&C\n"; + +$res = $db->query('SELECT rowid,* FROM users WHERE (phase2=1 OR methods=\'TLS\') ORDER BY identity'); +foreach ($res as $row) { + echo "<tr><td><a href=\"users.php?id=" . $row['rowid'] . "\"> " . + $row['identity'] . " </a>"; + echo "<td>" . $row['realm']; + $rem = $row['remediation']; + echo "<td>"; + if ($rem == "") { + echo "-"; + } else if ($rem == "user") { + echo "User"; + } else if ($rem == "policy") { + echo "Policy"; + } else if ($rem == "free") { + echo "Free"; + } else if ($rem == "reenroll") { + echo "Reenroll"; + } else { + echo "Machine"; + } + echo "<td>" . $row['policy']; + if ($row['shared'] > 0) + echo "<td>shared"; + else + echo "<td>default"; + echo "<td><small>" . $row['methods'] . "</small>"; + echo "<td>"; + $xml = xml_parser_create(); + xml_parse_into_struct($xml, $row['devinfo'], $devinfo); + foreach($devinfo as $k) { + if ($k['tag'] == 'DEVID') { + echo "<small>" . $k['value'] . "</small>"; + break; + } + } + echo "<td><small>" . $row['mac_addr'] . "</small>"; + echo "<td><small>" . $row['t_c_timestamp'] . "</small>"; + echo "\n"; +} +echo "</table>\n"; + +} + +?> + +</html> diff --git a/contrib/wpa/src/Makefile b/contrib/wpa/src/Makefile new file mode 100644 index 000000000000..6eb7f2acb5a1 --- /dev/null +++ b/contrib/wpa/src/Makefile @@ -0,0 +1,12 @@ +SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p pae radius rsn_supp tls utils wps +SUBDIRS += fst + +all: + for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done + +clean: + $(Q)for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done + $(Q)rm -f *~ + +install: + for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done diff --git a/contrib/wpa/src/ap/Makefile b/contrib/wpa/src/ap/Makefile new file mode 100644 index 000000000000..a1e9b7c44d2f --- /dev/null +++ b/contrib/wpa/src/ap/Makefile @@ -0,0 +1,60 @@ +CFLAGS += -DHOSTAPD +CFLAGS += -DNEED_AP_MLME +CFLAGS += -DCONFIG_ETH_P_OUI +CFLAGS += -DCONFIG_HS20 +CFLAGS += -DCONFIG_INTERWORKING +CFLAGS += -DCONFIG_IEEE80211R +CFLAGS += -DCONFIG_IEEE80211R_AP +CFLAGS += -DCONFIG_WPS +CFLAGS += -DCONFIG_PROXYARP +CFLAGS += -DCONFIG_IPV6 +CFLAGS += -DCONFIG_AIRTIME_POLICY + +LIB_OBJS= \ + accounting.o \ + ap_config.o \ + ap_drv_ops.o \ + ap_list.o \ + ap_mlme.o \ + airtime_policy.o \ + authsrv.o \ + beacon.o \ + bss_load.o \ + ctrl_iface_ap.o \ + dfs.o \ + dhcp_snoop.o \ + drv_callbacks.o \ + eap_user_db.o \ + eth_p_oui.o \ + gas_serv.o \ + hostapd.o \ + hs20.o \ + hw_features.o \ + ieee802_11_auth.o \ + ieee802_11.o \ + ieee802_11_ht.o \ + ieee802_11_shared.o \ + ieee802_11_vht.o \ + ieee802_1x.o \ + neighbor_db.o \ + ndisc_snoop.o \ + p2p_hostapd.o \ + pmksa_cache_auth.o \ + preauth_auth.o \ + rrm.o \ + sta_info.o \ + tkip_countermeasures.o \ + utils.o \ + vlan.o \ + vlan_ifconfig.o \ + vlan_init.o \ + wmm.o \ + wnm_ap.o \ + wpa_auth.o \ + wpa_auth_ft.o \ + wpa_auth_glue.o \ + wpa_auth_ie.o \ + wps_hostapd.o \ + x_snoop.o + +include ../lib.rules diff --git a/contrib/wpa/src/ap/acs.c b/contrib/wpa/src/ap/acs.c index 11178a1f047c..a112045364e3 100644 --- a/contrib/wpa/src/ap/acs.c +++ b/contrib/wpa/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; @@ -363,40 +372,47 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface, } -static int acs_usable_ht40_chan(const struct hostapd_channel_data *chan) +static int acs_usable_bw40_chan(const struct hostapd_channel_data *chan) { - const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, - 157, 184, 192 }; + const int allowed[] = { 5180, 5220, 5260, 5300, 5500, 5540, 5580, 5620, + 5660, 5745, 5785, 4920, 4960, 5955, 5995, 6035, + 6075, 6115, 6155, 6195, 6235, 6275, 6315, 6355, + 6395, 6435, 6475, 6515, 6555, 6595, 6635, 6675, + 6715, 6755, 6795, 6835, 6875, 6915, 6955, 6995, + 7035, 7075 }; unsigned int i; for (i = 0; i < ARRAY_SIZE(allowed); i++) - if (chan->chan == allowed[i]) + if (chan->freq == allowed[i]) return 1; return 0; } -static int acs_usable_vht80_chan(const struct hostapd_channel_data *chan) +static int acs_usable_bw80_chan(const struct hostapd_channel_data *chan) { - const int allowed[] = { 36, 52, 100, 116, 132, 149 }; + const int allowed[] = { 5180, 5260, 5550, 5580, 5660, 5745, 5955, 6035, + 6115, 6195, 6275, 6355, 6435, 6515, 6595, 6675, + 6755, 6835, 6915, 6995 }; unsigned int i; for (i = 0; i < ARRAY_SIZE(allowed); i++) - if (chan->chan == allowed[i]) + if (chan->freq == allowed[i]) return 1; return 0; } -static int acs_usable_vht160_chan(const struct hostapd_channel_data *chan) +static int acs_usable_bw160_chan(const struct hostapd_channel_data *chan) { - const int allowed[] = { 36, 100 }; + const int allowed[] = { 5180, 5500, 5955, 6115, 6275, 6435, 6595, 6755, + 6915 }; unsigned int i; for (i = 0; i < ARRAY_SIZE(allowed); i++) - if (chan->chan == allowed[i]) + if (chan->freq == allowed[i]) return 1; return 0; @@ -453,21 +469,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; } - /* We need at least survey data for one channel */ - return !!valid; + 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; + } + + return 0; } @@ -489,14 +519,25 @@ static int is_in_chanlist(struct hostapd_iface *iface, } -static void acs_survey_all_chans_intereference_factor( - struct hostapd_iface *iface) +static int is_in_freqlist(struct hostapd_iface *iface, + struct hostapd_channel_data *chan) +{ + if (!iface->conf->acs_freq_list.num) + return 1; + + return freq_range_list_includes(&iface->conf->acs_freq_list, + chan->freq); +} + + +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; @@ -504,6 +545,9 @@ static void acs_survey_all_chans_intereference_factor( if (!is_in_chanlist(iface, chan)) continue; + if (!is_in_freqlist(iface, chan)) + continue; + wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)", chan->chan, chan->freq); @@ -515,14 +559,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 +593,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 +643,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 @@ -628,6 +672,9 @@ acs_find_ideal_chan(struct hostapd_iface *iface) if (!is_in_chanlist(iface, chan)) continue; + if (!is_in_freqlist(iface, chan)) + continue; + if (!chan_bw_allowed(chan, bw, 1, 1)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: BW %u is not supported", @@ -637,31 +684,33 @@ 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 && - iface->conf->ieee80211n && - iface->conf->secondary_channel && - !acs_usable_ht40_chan(chan)) { - wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40", + if (mode->mode == HOSTAPD_MODE_IEEE80211A && + ((iface->conf->ieee80211n && + iface->conf->secondary_channel) || + is_6ghz_freq(chan->freq)) && + !acs_usable_bw40_chan(chan)) { + wpa_printf(MSG_DEBUG, + "ACS: Channel %d: not allowed as primary channel for 40 MHz bandwidth", chan->chan); 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 && - !acs_usable_vht80_chan(chan)) { + !acs_usable_bw80_chan(chan)) { wpa_printf(MSG_DEBUG, - "ACS: Channel %d: not allowed as primary channel for VHT80", + "ACS: Channel %d: not allowed as primary channel for 80 MHz bandwidth", chan->chan); continue; } if (hostapd_get_oper_chwidth(iface->conf) == CHANWIDTH_160MHZ && - !acs_usable_vht160_chan(chan)) { + !acs_usable_bw160_chan(chan)) { wpa_printf(MSG_DEBUG, - "ACS: Channel %d: not allowed as primary channel for VHT160", + "ACS: Channel %d: not allowed as primary channel for 160 MHz bandwidth", chan->chan); continue; } @@ -698,7 +747,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 +793,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 +812,78 @@ 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; + + if (is_6ghz_op_class(iface->conf->op_class)) { + bw = op_class_to_bandwidth(iface->conf->op_class); + n_chans = bw / 20; + goto bw_selected; + } + + /* 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); + +bw_selected: + /* 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 +939,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; } @@ -862,6 +975,7 @@ static void acs_study(struct hostapd_iface *iface) } iface->conf->channel = ideal_chan->chan; + iface->freq = ideal_chan->freq; if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) acs_adjust_center_freq(iface); @@ -917,31 +1031,67 @@ 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; + + if (!is_in_freqlist(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) { + wpa_printf(MSG_ERROR, "ACS: No available channels found"); + os_free(params.freqs); + return -1; + } + iface->scan_cb = acs_scan_complete; wpa_printf(MSG_DEBUG, "ACS: Scanning %d / %d", @@ -971,7 +1121,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/contrib/wpa/src/ap/airtime_policy.c b/contrib/wpa/src/ap/airtime_policy.c index f56ca5bddc3f..abe817c5b015 100644 --- a/contrib/wpa/src/ap/airtime_policy.c +++ b/contrib/wpa/src/ap/airtime_policy.c @@ -79,6 +79,10 @@ static void count_backlogged_sta(struct hostapd_data *hapd) for (sta = hapd->sta_list; sta; sta = sta->next) { if (hostapd_drv_read_sta_data(hapd, &data, sta->addr)) continue; +#ifdef CONFIG_TESTING_OPTIONS + if (hapd->force_backlog_bytes) + data.backlog_bytes = 1; +#endif /* CONFIG_TESTING_OPTIONS */ if (data.backlog_bytes > 0) set_new_backlog_time(hapd, sta, &now); @@ -134,8 +138,8 @@ static void update_airtime_weights(void *eloop_data, void *user_data) unsigned int num_sta_min = 0, num_sta_prod = 1, num_sta_sum = 0, wt_sum = 0; unsigned int quantum; - Boolean all_div_min = TRUE; - Boolean apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC; + bool all_div_min = true; + bool apply_limit = iface->conf->airtime_mode == AIRTIME_MODE_DYNAMIC; int wt, num_bss = 0, max_wt = 0; size_t i; @@ -169,7 +173,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data) * integers. */ if (bss->num_backlogged_sta && bss->num_backlogged_sta % num_sta_min > 0) - all_div_min = FALSE; + all_div_min = false; /* If we're in LIMIT mode, we only apply the weight * scaling when the BSS(es) marked as limited would a @@ -178,7 +182,7 @@ static void update_airtime_weights(void *eloop_data, void *user_data) if (!apply_limit && bss->conf->airtime_limit) { if (bss->num_backlogged_sta * wt_sum > bss->conf->airtime_weight * num_sta_sum) - apply_limit = TRUE; + apply_limit = true; } } if (all_div_min) diff --git a/contrib/wpa/src/ap/ap_config.c b/contrib/wpa/src/ap/ap_config.c index 90348e1ddb97..7b6d54c35fc2 100644 --- a/contrib/wpa/src/ap/ap_config.c +++ b/contrib/wpa/src/ap/ap_config.c @@ -16,6 +16,7 @@ #include "common/ieee802_1x_defs.h" #include "common/eapol_common.h" #include "common/dhcp.h" +#include "common/sae.h" #include "eap_common/eap_wsc_common.h" #include "eap_server/eap.h" #include "wpa_auth.h" @@ -53,23 +54,33 @@ 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 = DEFAULT_WPA_DISABLE_EAPOL_KEY_RETRIES; bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK; +#ifdef CONFIG_NO_TKIP + bss->wpa_pairwise = WPA_CIPHER_CCMP; + bss->wpa_group = WPA_CIPHER_CCMP; +#else /* CONFIG_NO_TKIP */ bss->wpa_pairwise = WPA_CIPHER_TKIP; bss->wpa_group = WPA_CIPHER_TKIP; +#endif /* CONFIG_NO_TKIP */ bss->rsn_pairwise = 0; bss->max_num_sta = MAX_STA_COUNT; @@ -86,11 +97,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->pwd_group = 19; /* ECC: GF(p=256) */ -#ifdef CONFIG_IEEE80211W bss->assoc_sa_query_max_timeout = 1000; bss->assoc_sa_query_retry_timeout = 201; bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC; -#endif /* CONFIG_IEEE80211W */ #ifdef EAP_SERVER_FAST /* both anonymous and authenticated provisioning */ bss->eap_fast_prov = 3; @@ -112,7 +121,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->radius_das_time_window = 300; - bss->sae_anti_clogging_threshold = 5; + bss->anti_clogging_threshold = 5; bss->sae_sync = 5; bss->gas_frag_limit = 1400; @@ -122,6 +131,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) bss->fils_hlp_wait_time = 30; bss->dhcp_server_port = DHCP_SERVER_PORT; bss->dhcp_relay_port = DHCP_SERVER_PORT; + bss->fils_discovery_min_int = 20; #endif /* CONFIG_FILS */ bss->broadcast_deauth = 1; @@ -135,6 +145,9 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) * completed and tested with other implementations. */ bss->tls_flags = TLS_CONN_DISABLE_TLSv1_3; + bss->max_auth_rounds = 100; + bss->max_auth_rounds_short = 50; + bss->send_probe_response = 1; #ifdef CONFIG_HS20 @@ -148,6 +161,15 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) /* Default to strict CRL checking. */ bss->check_crl_strict = 1; + +#ifdef CONFIG_TESTING_OPTIONS + bss->sae_commit_status = -1; +#endif /* CONFIG_TESTING_OPTIONS */ + +#ifdef CONFIG_PASN + /* comeback after 10 TUs */ + bss->pasn_comeback_after = 10; +#endif /* CONFIG_PASN */ } @@ -249,6 +271,14 @@ 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; + conf->he_op.he_twt_responder = 1; + conf->he_6ghz_max_mpdu = 2; + conf->he_6ghz_max_ampdu_len_exp = 7; + conf->he_6ghz_rx_ant_pat = 1; + conf->he_6ghz_tx_ant_pat = 1; #endif /* CONFIG_IEEE80211AX */ /* The third octet of the country string uses an ASCII space character @@ -299,6 +329,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++; @@ -329,6 +360,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 { @@ -346,8 +379,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; } @@ -375,16 +409,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; @@ -402,6 +437,8 @@ static int hostapd_config_read_wpa_psk(const char *fname, } } + psk->wps = wps; + psk->next = ssid->wpa_psk; ssid->wpa_psk = psk; } @@ -433,10 +470,53 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid) } +int hostapd_setup_sae_pt(struct hostapd_bss_config *conf) +{ +#ifdef CONFIG_SAE + struct hostapd_ssid *ssid = &conf->ssid; + struct sae_password_entry *pw; + + if ((conf->sae_pwe == 0 && !hostapd_sae_pw_id_in_use(conf) && + !hostapd_sae_pk_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); + ssid->pt = NULL; + if (ssid->wpa_passphrase) { + ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid, + ssid->ssid_len, + (const u8 *) ssid->wpa_passphrase, + os_strlen(ssid->wpa_passphrase), + NULL); + if (!ssid->pt) + return -1; + } + + for (pw = conf->sae_passwords; pw; pw = pw->next) { + sae_deinit_pt(pw->pt); + pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid, + ssid->ssid_len, + (const u8 *) pw->password, + os_strlen(pw->password), + pw->identifier); + if (!pw->pt) + return -1; + } +#endif /* CONFIG_SAE */ + + return 0; +} + + int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf) { struct hostapd_ssid *ssid = &conf->ssid; + if (hostapd_setup_sae_pt(conf) < 0) + return -1; + if (ssid->wpa_passphrase != NULL) { if (ssid->wpa_psk != NULL) { wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK " @@ -581,6 +661,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; @@ -589,6 +670,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) @@ -642,6 +724,12 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf) pw = pw->next; str_clear_free(tmp->password); os_free(tmp->identifier); +#ifdef CONFIG_SAE + sae_deinit_pt(tmp->pt); +#endif /* CONFIG_SAE */ +#ifdef CONFIG_SAE_PK + sae_deinit_pk(tmp->pk); +#endif /* CONFIG_SAE_PK */ os_free(tmp); } } @@ -674,10 +762,15 @@ 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 */ +#ifdef CONFIG_SAE + sae_deinit_pt(conf->ssid.pt); +#endif /* CONFIG_SAE */ hostapd_config_free_eap_users(conf->eap_user); os_free(conf->eap_user_sqlite); @@ -692,6 +785,7 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) conf->radius->num_auth_servers); hostapd_config_free_radius(conf->radius->acct_servers, conf->radius->num_acct_servers); + os_free(conf->radius->force_client_dev); } hostapd_config_free_radius_attr(conf->radius_auth_req_attr); hostapd_config_free_radius_attr(conf->radius_acct_req_attr); @@ -765,6 +859,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); @@ -832,6 +927,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); @@ -840,6 +941,8 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) hostapd_config_free_fils_realms(conf); #ifdef CONFIG_DPP + os_free(conf->dpp_name); + os_free(conf->dpp_mud_url); os_free(conf->dpp_connector); wpabuf_free(conf->dpp_netaccesskey); wpabuf_free(conf->dpp_csign); @@ -864,6 +967,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) } #endif /* CONFIG_AIRTIME_POLICY */ +#ifdef CONFIG_PASN + os_free(conf->pasn_groups); +#endif /* CONFIG_PASN */ + os_free(conf); } @@ -885,6 +992,7 @@ void hostapd_config_free(struct hostapd_config *conf) os_free(conf->supported_rates); os_free(conf->basic_rates); os_free(conf->acs_ch_list.range); + os_free(conf->acs_freq_list.range); os_free(conf->driver_params); #ifdef CONFIG_ACS os_free(conf->acs_chan_bias); @@ -1027,10 +1135,85 @@ const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf, } +#ifdef CONFIG_SAE_PK +static bool hostapd_sae_pk_password_without_pk(struct hostapd_bss_config *bss) +{ + struct sae_password_entry *pw; + bool res = false; + + if (bss->ssid.wpa_passphrase && +#ifdef CONFIG_TESTING_OPTIONS + !bss->sae_pk_password_check_skip && +#endif /* CONFIG_TESTING_OPTIONS */ + sae_pk_valid_password(bss->ssid.wpa_passphrase)) + res = true; + + for (pw = bss->sae_passwords; pw; pw = pw->next) { + if (!pw->pk && +#ifdef CONFIG_TESTING_OPTIONS + !bss->sae_pk_password_check_skip && +#endif /* CONFIG_TESTING_OPTIONS */ + sae_pk_valid_password(pw->password)) + return true; + + if (bss->ssid.wpa_passphrase && res && pw->pk && + os_strcmp(bss->ssid.wpa_passphrase, pw->password) == 0) + res = false; + } + + return res; +} +#endif /* CONFIG_SAE_PK */ + + +static bool hostapd_config_check_bss_6g(struct hostapd_bss_config *bss) +{ + if (bss->wpa != WPA_PROTO_RSN) { + wpa_printf(MSG_ERROR, + "Pre-RSNA security methods are not allowed in 6 GHz"); + return false; + } + + if (bss->ieee80211w != MGMT_FRAME_PROTECTION_REQUIRED) { + wpa_printf(MSG_ERROR, + "Management frame protection is required in 6 GHz"); + return false; + } + + if (bss->wpa_key_mgmt & (WPA_KEY_MGMT_PSK | + WPA_KEY_MGMT_FT_PSK | + WPA_KEY_MGMT_PSK_SHA256)) { + wpa_printf(MSG_ERROR, "Invalid AKM suite for 6 GHz"); + return false; + } + + if (bss->rsn_pairwise & (WPA_CIPHER_WEP40 | + WPA_CIPHER_WEP104 | + WPA_CIPHER_TKIP)) { + wpa_printf(MSG_ERROR, + "Invalid pairwise cipher suite for 6 GHz"); + return false; + } + + if (bss->wpa_group & (WPA_CIPHER_WEP40 | + WPA_CIPHER_WEP104 | + WPA_CIPHER_TKIP)) { + wpa_printf(MSG_ERROR, "Invalid group cipher suite for 6 GHz"); + return false; + } + + return true; +} + + static int hostapd_config_check_bss(struct hostapd_bss_config *bss, struct hostapd_config *conf, int full_config) { + if (full_config && is_6ghz_op_class(conf->op_class) && + !hostapd_config_check_bss_6g(bss)) + return -1; + if (full_config && bss->ieee802_1x && !bss->eap_server && !bss->radius->auth_servers) { wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no " @@ -1038,6 +1221,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, return -1; } +#ifdef CONFIG_WEP if (bss->wpa) { int wep, i; @@ -1055,6 +1239,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 && @@ -1102,52 +1287,75 @@ 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; + bss->disable_11n = true; wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not " "allowed, disabling HT capabilities"); } +#ifdef CONFIG_WEP if (full_config && conf->ieee80211n && bss->ssid.security_policy == SECURITY_STATIC_WEP) { - bss->disable_11n = 1; + bss->disable_11n = true; 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) && !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) { - bss->disable_11n = 1; + bss->disable_11n = true; wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 " "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; + bss->disable_11ac = true; 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) && !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) { - bss->disable_11ac = 1; + bss->disable_11ac = true; wpa_printf(MSG_ERROR, "VHT (IEEE 802.11ac) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling VHT capabilities"); } #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_IEEE80211AX +#ifdef CONFIG_WEP + if (full_config && conf->ieee80211ax && + bss->ssid.security_policy == SECURITY_STATIC_WEP) { + bss->disable_11ax = true; + wpa_printf(MSG_ERROR, + "HE (IEEE 802.11ax) with WEP is not allowed, disabling HE capabilities"); + } +#endif /* CONFIG_WEP */ + + if (full_config && conf->ieee80211ax && bss->wpa && + !(bss->wpa_pairwise & WPA_CIPHER_CCMP) && + !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | + WPA_CIPHER_CCMP_256 | WPA_CIPHER_GCMP_256))) + { + bss->disable_11ax = true; + wpa_printf(MSG_ERROR, + "HE (IEEE 802.11ax) with WPA/WPA2 requires CCMP/GCMP to be enabled, disabling HE capabilities"); + } +#endif /* CONFIG_IEEE80211AX */ + #ifdef CONFIG_WPS if (full_config && bss->wps_state && bss->ignore_broadcast_ssid) { wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid " @@ -1155,12 +1363,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) || @@ -1204,6 +1414,15 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, } #endif /* CONFIG_OCV */ +#ifdef CONFIG_SAE_PK + if (full_config && hostapd_sae_pk_in_use(bss) && + hostapd_sae_pk_password_without_pk(bss)) { + wpa_printf(MSG_ERROR, + "SAE-PK: SAE password uses SAE-PK style, but does not have PK configured"); + return -1; + } +#endif /* CONFIG_SAE_PK */ + return 0; } @@ -1284,11 +1503,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; @@ -1314,6 +1535,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 ? @@ -1324,11 +1546,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) @@ -1339,6 +1563,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; @@ -1377,3 +1602,38 @@ int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf) return 2; return with_id; } + + +bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf) +{ +#ifdef CONFIG_SAE_PK + struct sae_password_entry *pw; + + for (pw = conf->sae_passwords; pw; pw = pw->next) { + if (pw->pk) + return true; + } +#endif /* CONFIG_SAE_PK */ + + return false; +} + + +#ifdef CONFIG_SAE_PK +bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf) +{ + bool with_pk = false; + struct sae_password_entry *pw; + + if (conf->ssid.wpa_passphrase) + return false; + + for (pw = conf->sae_passwords; pw; pw = pw->next) { + if (!pw->pk) + return false; + with_pk = true; + } + + return with_pk; +} +#endif /* CONFIG_SAE_PK */ diff --git a/contrib/wpa/src/ap/ap_config.h b/contrib/wpa/src/ap/ap_config.h index ea581a822277..ced36f9cc828 100644 --- a/contrib/wpa/src/ap/ap_config.h +++ b/contrib/wpa/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; @@ -99,8 +104,11 @@ struct hostapd_ssid { struct hostapd_wpa_psk *wpa_psk; char *wpa_passphrase; 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 @@ -150,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]; @@ -188,15 +197,6 @@ struct hostapd_radius_attr { #define NUM_TX_QUEUES 4 - -struct hostapd_tx_queue_params { - int aifs; - int cwmin; - int cwmax; - int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */ -}; - - #define MAX_ROAMING_CONSORTIUM_LEN 15 struct hostapd_roaming_consortium { @@ -251,6 +251,8 @@ struct sae_password_entry { char *identifier; u8 peer_addr[ETH_ALEN]; int vlan_id; + struct sae_pt *pt; + struct sae_pk *pk; }; struct dpp_controller_conf { @@ -265,6 +267,8 @@ struct airtime_sta_weight { u8 addr[ETH_ALEN]; }; +#define EXT_CAPA_MAX_LEN 15 + /** * struct hostapd_bss_config - Per-BSS configuration */ @@ -317,18 +321,16 @@ 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; - int ieee802_11f; /* use IEEE 802.11f (IAPP) */ - char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast - * frames */ - enum macaddr_acl { ACCEPT_UNLESS_DENIED = 0, DENY_UNLESS_ACCEPTED = 1, @@ -346,15 +348,15 @@ 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; -#ifdef CONFIG_IEEE80211W enum mfp_options ieee80211w; int group_mgmt_cipher; + int beacon_prot; /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ unsigned int assoc_sa_query_max_timeout; /* dot11AssociationSAQueryRetryTimeout (in TUs) */ int assoc_sa_query_retry_timeout; -#endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_OCV int ocv; /* Operating Channel Validation */ #endif /* CONFIG_OCV */ @@ -371,6 +373,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; @@ -415,6 +418,8 @@ struct hostapd_bss_config { unsigned int crl_reload_interval; unsigned int tls_session_lifetime; unsigned int tls_flags; + unsigned int max_auth_rounds; + unsigned int max_auth_rounds_short; char *ocsp_stapling_response; char *ocsp_stapling_response_multi; char *dh_file; @@ -429,6 +434,8 @@ struct hostapd_bss_config { int pac_key_refresh_time; int eap_teap_auth; int eap_teap_pac_no_inner; + int eap_teap_separate_result; + int eap_teap_id; int eap_sim_aka_result_ind; int eap_sim_id; int tnc; @@ -497,6 +504,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; @@ -525,8 +533,9 @@ struct hostapd_bss_config { #define TDLS_PROHIBIT BIT(0) #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1) int tdls; - int disable_11n; - int disable_11ac; + bool disable_11n; + bool disable_11ac; + bool disable_11ax; /* IEEE 802.11v */ int time_advertisement; @@ -648,9 +657,11 @@ struct hostapd_bss_config { struct wpabuf *vendor_elements; struct wpabuf *assocresp_elements; - unsigned int sae_anti_clogging_threshold; + unsigned int anti_clogging_threshold; unsigned int sae_sync; int sae_require_mfp; + int sae_confirm_immediate; + int sae_pwe; int *sae_groups; struct sae_password_entry *sae_passwords; @@ -661,7 +672,26 @@ struct hostapd_bss_config { u8 bss_load_test_set; struct wpabuf *own_ie_override; int sae_reflection_attack; + int sae_commit_status; + int sae_pk_omit; + int sae_pk_password_check_skip; 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; + int ft_rsnxe_used; + unsigned int oci_freq_override_eapol_m3; + unsigned int oci_freq_override_eapol_g1; + unsigned int oci_freq_override_saquery_req; + unsigned int oci_freq_override_saquery_resp; + unsigned int oci_freq_override_ft_assoc; + unsigned int oci_freq_override_fils_assoc; + unsigned int oci_freq_override_wnm_sleep; #endif /* CONFIG_TESTING_OPTIONS */ #define MESH_ENABLED BIT(0) @@ -702,19 +732,27 @@ struct hostapd_bss_config { unsigned int fils_hlp_wait_time; u16 dhcp_server_port; u16 dhcp_relay_port; + u32 fils_discovery_min_int; + u32 fils_discovery_max_int; #endif /* CONFIG_FILS */ int multicast_to_unicast; int broadcast_deauth; + int notify_mgmt_frames; + #ifdef CONFIG_DPP + char *dpp_name; + char *dpp_mud_url; char *dpp_connector; struct wpabuf *dpp_netaccesskey; unsigned int dpp_netaccesskey_expiry; 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 */ @@ -724,12 +762,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 */ @@ -827,15 +868,41 @@ struct hostapd_bss_config { */ u8 mka_psk_set; #endif /* CONFIG_MACSEC */ + +#ifdef CONFIG_PASN +#ifdef CONFIG_TESTING_OPTIONS + /* + * Normally, KDK should be derived if and only if both sides support + * secure LTF. Allow forcing KDK derivation for testing purposes. + */ + int force_kdk_derivation; + + /* If set, corrupt the MIC in the 2nd Authentication frame of PASN */ + int pasn_corrupt_mic; +#endif /* CONFIG_TESTING_OPTIONS */ + + int *pasn_groups; + + /* + * The time in TUs after which the non-AP STA is requested to retry the + * PASN authentication in case there are too many parallel operations. + */ + u16 pasn_comeback_after; +#endif /* CONFIG_PASN */ + + unsigned int unsol_bcast_probe_resp_interval; + + u8 ext_capa_mask[EXT_CAPA_MAX_LEN]; + u8 ext_capa[EXT_CAPA_MAX_LEN]; }; /** * struct he_phy_capabilities_info - HE PHY capabilities */ struct he_phy_capabilities_info { - Boolean he_su_beamformer; - Boolean he_su_beamformee; - Boolean he_mu_beamformer; + bool he_su_beamformer; + bool he_su_beamformee; + bool he_mu_beamformer; }; /** @@ -843,8 +910,11 @@ 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; + u8 he_twt_responder; u16 he_rts_threshold; u16 he_basic_mcs_nss_set; }; @@ -857,8 +927,8 @@ struct spatial_reuse { u8 non_srg_obss_pd_max_offset; u8 srg_obss_pd_min_offset; u8 srg_obss_pd_max_offset; - u8 srg_obss_color_bitmap; - u8 srg_obss_color_partial_bitmap; + u8 srg_bss_color_bitmap[8]; + u8 srg_partial_bssid_bitmap[8]; }; /** @@ -871,11 +941,17 @@ struct hostapd_config { u16 beacon_int; int rts_threshold; int fragm_threshold; + u8 op_class; u8 channel; + int enable_edmg; + u8 edmg_channel; u8 acs; struct wpa_freq_range_list acs_ch_list; + struct wpa_freq_range_list acs_freq_list; + u8 acs_freq_list_present; int acs_exclude_dfs; enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */ + int acs_exclude_6ghz_non_psc; enum { LONG_PREAMBLE = 0, SHORT_PREAMBLE = 1 @@ -987,6 +1063,10 @@ struct hostapd_config { u8 he_oper_chwidth; u8 he_oper_centr_freq_seg0_idx; u8 he_oper_centr_freq_seg1_idx; + u8 he_6ghz_max_mpdu; + u8 he_6ghz_max_ampdu_len_exp; + u8 he_6ghz_rx_ant_pat; + u8 he_6ghz_tx_ant_pat; #endif /* CONFIG_IEEE80211AX */ /* VHT enable/disable config from CHAN_SWITCH */ @@ -994,8 +1074,14 @@ struct hostapd_config { #define CH_SWITCH_VHT_DISABLED BIT(1) unsigned int ch_switch_vht_config; + /* HE enable/disable config from CHAN_SWITCH */ +#define CH_SWITCH_HE_ENABLED BIT(0) +#define CH_SWITCH_HE_DISABLED BIT(1) + unsigned int ch_switch_he_config; + int rssi_reject_assoc_rssi; int rssi_reject_assoc_timeout; + int rssi_ignore_probe_request; #ifdef CONFIG_AIRTIME_POLICY enum { @@ -1100,5 +1186,8 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config); void hostapd_set_security_params(struct hostapd_bss_config *bss, int full_config); int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf); +bool hostapd_sae_pk_in_use(struct hostapd_bss_config *conf); +bool hostapd_sae_pk_exclusively(struct hostapd_bss_config *conf); +int hostapd_setup_sae_pt(struct hostapd_bss_config *conf); #endif /* HOSTAPD_CONFIG_H */ diff --git a/contrib/wpa/src/ap/ap_drv_ops.c b/contrib/wpa/src/ap/ap_drv_ops.c index c0ededabe979..d1642d7dff15 100644 --- a/contrib/wpa/src/ap/ap_drv_ops.c +++ b/contrib/wpa/src/ap/ap_drv_ops.c @@ -10,6 +10,7 @@ #include "utils/common.h" #include "common/ieee802_11_defs.h" +#include "common/ieee802_11_common.h" #include "common/hw_features_common.h" #include "wps/wps.h" #include "p2p/p2p.h" @@ -107,6 +108,10 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd, goto fail; #endif /* CONFIG_FILS */ + pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf)); + if (add_buf_data(&assocresp, buf, pos - buf) < 0) + goto fail; + if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 || add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0) goto fail; @@ -305,9 +310,7 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname, params.wpa_pairwise = hapd->conf->wpa_pairwise; params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt; params.rsn_preauth = hapd->conf->rsn_preauth; -#ifdef CONFIG_IEEE80211W params.ieee80211w = hapd->conf->ieee80211w; -#endif /* CONFIG_IEEE80211W */ } return hostapd_set_ieee8021x(hapd, ¶ms); } @@ -348,7 +351,7 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr, u16 auth_alg) { if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL) - return 0; + return -EOPNOTSUPP; return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg); } @@ -415,6 +418,7 @@ int hostapd_sta_add(struct hostapd_data *hapd, const struct ieee80211_vht_capabilities *vht_capab, const struct ieee80211_he_capabilities *he_capab, size_t he_capab_len, + const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, int set) { @@ -436,6 +440,7 @@ int hostapd_sta_add(struct hostapd_data *hapd, params.vht_capabilities = vht_capab; params.he_capab = he_capab; params.he_capab_len = he_capab_len; + params.he_6ghz_capab = he_6ghz_capab; params.vht_opmode_enabled = !!(flags & WLAN_STA_VHT_OPMODE_ENABLED); params.vht_opmode = vht_opmode; params.flags = hostapd_sta_flags_to_drv(flags); @@ -540,7 +545,8 @@ int hostapd_flush(struct hostapd_data *hapd) int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, - int freq, int channel, int ht_enabled, int vht_enabled, + int freq, int channel, int edmg, u8 edmg_channel, + int ht_enabled, int vht_enabled, int he_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1) @@ -548,7 +554,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, struct hostapd_freq_params data; struct hostapd_hw_modes *cmode = hapd->iface->current_mode; - if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled, + if (hostapd_set_freq_params(&data, mode, freq, channel, edmg, + edmg_channel, ht_enabled, vht_enabled, he_enabled, sec_channel_offset, oper_chwidth, center_segment0, center_segment1, @@ -583,7 +590,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); @@ -645,6 +652,12 @@ int hostapd_drv_none(struct hostapd_data *hapd) } +bool hostapd_drv_nl80211(struct hostapd_data *hapd) +{ + return hapd->driver && os_strcmp(hapd->driver->name, "nl80211") == 0; +} + + int hostapd_driver_scan(struct hostapd_data *hapd, struct wpa_driver_scan_params *params) { @@ -675,36 +688,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); } @@ -810,7 +828,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, return -1; } - if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled, + if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0, + ht_enabled, vht_enabled, he_enabled, sec_channel_offset, oper_chwidth, center_segment0, center_segment1, @@ -850,10 +869,24 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd, for (i = 0; i < mode->num_channels; i++) { struct hostapd_channel_data *chan = &mode->channels[i]; - if ((acs_ch_list_all || - freq_range_list_includes(&hapd->iface->conf->acs_ch_list, - chan->chan)) && - !(chan->flag & HOSTAPD_CHAN_DISABLED) && + if (!acs_ch_list_all && + (hapd->iface->conf->acs_freq_list.num && + !freq_range_list_includes( + &hapd->iface->conf->acs_freq_list, + chan->freq))) + continue; + if (!acs_ch_list_all && + (!hapd->iface->conf->acs_freq_list_present && + hapd->iface->conf->acs_ch_list.num && + !freq_range_list_includes( + &hapd->iface->conf->acs_ch_list, + chan->chan))) + continue; + if (is_6ghz_freq(chan->freq) && + hapd->iface->conf->acs_exclude_6ghz_non_psc && + !is_6ghz_psc_frequency(chan->freq)) + continue; + if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && !(hapd->iface->conf->acs_exclude_dfs && (chan->flag & HOSTAPD_CHAN_RADAR))) int_array_add_unique(freq_list, chan->freq); @@ -879,10 +912,9 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) { struct drv_acs_params params; int ret, i, acs_ch_list_all = 0; - u8 *channels = NULL; - unsigned int num_channels = 0; struct hostapd_hw_modes *mode; int *freq_list = NULL; + enum hostapd_hw_mode selected_mode; if (hapd->driver == NULL || hapd->driver->do_acs == NULL) return 0; @@ -894,42 +926,27 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) * If no chanlist config parameter is provided, include all enabled * channels of the selected hw_mode. */ - if (!hapd->iface->conf->acs_ch_list.num) - acs_ch_list_all = 1; - - mode = hapd->iface->current_mode; - if (mode) { - channels = os_malloc(mode->num_channels); - if (channels == NULL) - return -1; - - for (i = 0; i < mode->num_channels; i++) { - struct hostapd_channel_data *chan = &mode->channels[i]; - if (!acs_ch_list_all && - !freq_range_list_includes( - &hapd->iface->conf->acs_ch_list, - chan->chan)) - continue; - if (hapd->iface->conf->acs_exclude_dfs && - (chan->flag & HOSTAPD_CHAN_RADAR)) - continue; - if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) { - channels[num_channels++] = chan->chan; - int_array_add_unique(&freq_list, chan->freq); - } - } - } else { - for (i = 0; i < hapd->iface->num_hw_features; i++) { - mode = &hapd->iface->hw_features[i]; - hostapd_get_hw_mode_any_channels(hapd, mode, - acs_ch_list_all, - &freq_list); - } + if (hapd->iface->conf->acs_freq_list_present) + acs_ch_list_all = !hapd->iface->conf->acs_freq_list.num; + else + acs_ch_list_all = !hapd->iface->conf->acs_ch_list.num; + + if (hapd->iface->current_mode) + selected_mode = hapd->iface->current_mode->mode; + else + selected_mode = HOSTAPD_MODE_IEEE80211ANY; + + for (i = 0; i < hapd->iface->num_hw_features; i++) { + mode = &hapd->iface->hw_features[i]; + if (selected_mode != HOSTAPD_MODE_IEEE80211ANY && + selected_mode != mode->mode) + continue; + hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all, + &freq_list); } - params.ch_list = channels; - params.ch_list_len = num_channels; 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 & @@ -953,8 +970,11 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd) params.ch_width = 160; } + if (hapd->iface->conf->op_class) + params.ch_width = op_class_to_bandwidth( + hapd->iface->conf->op_class); ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms); - os_free(channels); + os_free(freq_list); return ret; } @@ -968,3 +988,11 @@ int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer, return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code, ie, ielen); } + + +int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable) +{ + if (!hapd->driver || !hapd->driver->dpp_listen || !hapd->drv_priv) + return 0; + return hapd->driver->dpp_listen(hapd->drv_priv, enable); +} diff --git a/contrib/wpa/src/ap/ap_drv_ops.h b/contrib/wpa/src/ap/ap_drv_ops.h index ca7f7abe01fd..61c8f64eb471 100644 --- a/contrib/wpa/src/ap/ap_drv_ops.h +++ b/contrib/wpa/src/ap/ap_drv_ops.h @@ -43,6 +43,7 @@ int hostapd_sta_add(struct hostapd_data *hapd, const struct ieee80211_vht_capabilities *vht_capab, const struct ieee80211_he_capabilities *he_capab, size_t he_capab_len, + const struct ieee80211_he_6ghz_band_cap *he_6ghz_capab, u32 flags, u8 qosinfo, u8 vht_opmode, int supp_p2p_ps, int set); int hostapd_set_privacy(struct hostapd_data *hapd, int enabled); @@ -62,7 +63,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, const u8 *addr, int idx, u8 *seq); int hostapd_flush(struct hostapd_data *hapd); int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode, - int freq, int channel, int ht_enabled, int vht_enabled, + int freq, int channel, int edmg, u8 edmg_channel, + int ht_enabled, int vht_enabled, int he_enabled, int sec_channel_offset, int oper_chwidth, int center_segment0, int center_segment1); int hostapd_set_rts(struct hostapd_data *hapd, int rts); @@ -79,6 +81,7 @@ hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes, u16 *flags, u8 *dfs_domain); int hostapd_driver_commit(struct hostapd_data *hapd); int hostapd_drv_none(struct hostapd_data *hapd); +bool hostapd_drv_nl80211(struct hostapd_data *hapd); int hostapd_driver_scan(struct hostapd_data *hapd, struct wpa_driver_scan_params *params); struct wpa_scan_results * hostapd_driver_get_scan_results( @@ -88,14 +91,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, @@ -132,6 +134,7 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, int hostapd_drv_do_acs(struct hostapd_data *hapd); int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer, u16 reason_code, const u8 *ie, size_t ielen); +int hostapd_drv_dpp_listen(struct hostapd_data *hapd, bool enable); #include "drivers/driver.h" @@ -348,12 +351,13 @@ static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd, static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd, int vendor_id, int subcmd, const u8 *data, size_t data_len, + enum nested_attr nested_attr_flag, struct wpabuf *buf) { if (hapd->driver == NULL || hapd->driver->vendor_cmd == NULL) return -1; return hapd->driver->vendor_cmd(hapd->drv_priv, vendor_id, subcmd, data, - data_len, buf); + data_len, nested_attr_flag, buf); } static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd) @@ -381,4 +385,35 @@ hostapd_drv_send_external_auth_status(struct hostapd_data *hapd, return hapd->driver->send_external_auth_status(hapd->drv_priv, params); } +static inline int +hostapd_drv_set_band(struct hostapd_data *hapd, u32 band_mask) +{ + if (!hapd->driver || !hapd->drv_priv || !hapd->driver->set_band) + return -1; + return hapd->driver->set_band(hapd->drv_priv, band_mask); +} + +#ifdef ANDROID +static inline int hostapd_drv_driver_cmd(struct hostapd_data *hapd, + char *cmd, char *buf, size_t buf_len) +{ + if (!hapd->driver->driver_cmd) + return -1; + return hapd->driver->driver_cmd(hapd->drv_priv, cmd, buf, buf_len); +} +#endif /* ANDROID */ + +#ifdef CONFIG_TESTING_OPTIONS +static inline int +hostapd_drv_register_frame(struct hostapd_data *hapd, u16 type, + const u8 *match, size_t match_len, + bool multicast) +{ + if (!hapd->driver || !hapd->drv_priv || !hapd->driver->register_frame) + return -1; + return hapd->driver->register_frame(hapd->drv_priv, type, match, + match_len, multicast); +} +#endif /* CONFIG_TESTING_OPTIONS */ + #endif /* AP_DRV_OPS */ diff --git a/contrib/wpa/src/ap/ap_list.c b/contrib/wpa/src/ap/ap_list.c index 8bf6ddec8d37..20be7f8f881d 100644 --- a/contrib/wpa/src/ap/ap_list.c +++ b/contrib/wpa/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/contrib/wpa/src/ap/authsrv.c b/contrib/wpa/src/ap/authsrv.c index 4f5fe7db4482..8e12daf40a46 100644 --- a/contrib/wpa/src/ap/authsrv.c +++ b/contrib/wpa/src/ap/authsrv.c @@ -110,28 +110,10 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) srv.auth_port = conf->radius_server_auth_port; srv.acct_port = conf->radius_server_acct_port; srv.conf_ctx = hapd; - srv.eap_sim_db_priv = hapd->eap_sim_db_priv; - srv.ssl_ctx = hapd->ssl_ctx; - srv.msg_ctx = hapd->msg_ctx; - srv.pac_opaque_encr_key = conf->pac_opaque_encr_key; - srv.eap_fast_a_id = conf->eap_fast_a_id; - srv.eap_fast_a_id_len = conf->eap_fast_a_id_len; - srv.eap_fast_a_id_info = conf->eap_fast_a_id_info; - srv.eap_fast_prov = conf->eap_fast_prov; - srv.pac_key_lifetime = conf->pac_key_lifetime; - srv.pac_key_refresh_time = conf->pac_key_refresh_time; - srv.eap_teap_auth = conf->eap_teap_auth; - srv.eap_teap_pac_no_inner = conf->eap_teap_pac_no_inner; - srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; - srv.eap_sim_id = conf->eap_sim_id; - srv.tnc = conf->tnc; - srv.wps = hapd->wps; srv.ipv6 = conf->radius_server_ipv6; srv.get_eap_user = hostapd_radius_get_eap_user; srv.eap_req_id_text = conf->eap_req_id_text; srv.eap_req_id_text_len = conf->eap_req_id_text_len; - srv.pwd_group = conf->pwd_group; - srv.server_id = conf->server_id ? conf->server_id : "hostapd"; srv.sqlite_file = conf->eap_user_sqlite; #ifdef CONFIG_RADIUS_TEST srv.dump_msk_file = conf->dump_msk_file; @@ -142,10 +124,8 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd) srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url; srv.t_c_server_url = conf->t_c_server_url; #endif /* CONFIG_HS20 */ - srv.erp = conf->eap_server_erp; srv.erp_domain = conf->erp_domain; - srv.tls_session_lifetime = conf->tls_session_lifetime; - srv.tls_flags = conf->tls_flags; + srv.eap_cfg = hapd->eap_cfg; hapd->radius_srv = radius_server_init(&srv); if (hapd->radius_srv == NULL) { @@ -193,6 +173,60 @@ static void authsrv_tls_event(void *ctx, enum tls_event ev, #endif /* EAP_TLS_FUNCS */ +static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd) +{ + struct eap_config *cfg; + + cfg = os_zalloc(sizeof(*cfg)); + if (!cfg) + return NULL; + + cfg->eap_server = hapd->conf->eap_server; + cfg->ssl_ctx = hapd->ssl_ctx; + cfg->msg_ctx = hapd->msg_ctx; + cfg->eap_sim_db_priv = hapd->eap_sim_db_priv; + cfg->tls_session_lifetime = hapd->conf->tls_session_lifetime; + cfg->tls_flags = hapd->conf->tls_flags; + cfg->max_auth_rounds = hapd->conf->max_auth_rounds; + cfg->max_auth_rounds_short = hapd->conf->max_auth_rounds_short; + if (hapd->conf->pac_opaque_encr_key) + cfg->pac_opaque_encr_key = + os_memdup(hapd->conf->pac_opaque_encr_key, 16); + if (hapd->conf->eap_fast_a_id) { + cfg->eap_fast_a_id = os_memdup(hapd->conf->eap_fast_a_id, + hapd->conf->eap_fast_a_id_len); + cfg->eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; + } + if (hapd->conf->eap_fast_a_id_info) + cfg->eap_fast_a_id_info = + os_strdup(hapd->conf->eap_fast_a_id_info); + cfg->eap_fast_prov = hapd->conf->eap_fast_prov; + cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime; + cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time; + cfg->eap_teap_auth = hapd->conf->eap_teap_auth; + cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner; + cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result; + cfg->eap_teap_id = hapd->conf->eap_teap_id; + cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; + cfg->eap_sim_id = hapd->conf->eap_sim_id; + cfg->tnc = hapd->conf->tnc; + cfg->wps = hapd->wps; + cfg->fragment_size = hapd->conf->fragment_size; + cfg->pwd_group = hapd->conf->pwd_group; + cfg->pbc_in_m1 = hapd->conf->pbc_in_m1; + if (hapd->conf->server_id) { + cfg->server_id = (u8 *) os_strdup(hapd->conf->server_id); + cfg->server_id_len = os_strlen(hapd->conf->server_id); + } else { + cfg->server_id = (u8 *) os_strdup("hostapd"); + cfg->server_id_len = 7; + } + cfg->erp = hapd->conf->eap_server_erp; + + return cfg; +} + + int authsrv_init(struct hostapd_data *hapd) { #ifdef EAP_TLS_FUNCS @@ -273,6 +307,14 @@ int authsrv_init(struct hostapd_data *hapd) } #endif /* EAP_SIM_DB */ + hapd->eap_cfg = authsrv_eap_config(hapd); + if (!hapd->eap_cfg) { + wpa_printf(MSG_ERROR, + "Failed to build EAP server configuration"); + authsrv_deinit(hapd); + return -1; + } + #ifdef RADIUS_SERVER if (hapd->conf->radius_server_clients && hostapd_setup_radius_srv(hapd)) @@ -303,4 +345,7 @@ void authsrv_deinit(struct hostapd_data *hapd) hapd->eap_sim_db_priv = NULL; } #endif /* EAP_SIM_DB */ + + eap_server_config_free(hapd->eap_cfg); + hapd->eap_cfg = NULL; } diff --git a/contrib/wpa/src/ap/beacon.c b/contrib/wpa/src/ap/beacon.c index a51b94960bed..15fc2b3db064 100644 --- a/contrib/wpa/src/ap/beacon.c +++ b/contrib/wpa/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) +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; + + ie = hostapd_vendor_wpa_ie(hapd, WPA_IE_VENDOR_TYPE); + if (!ie || 2U + ie[1] > len) + return pos; - os_memcpy(eid, ie, ielen); - return eid + ielen; + 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]; } @@ -395,16 +458,20 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, } #ifdef CONFIG_IEEE80211AX - if (hapd->iconf->ieee80211ax) { + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { buflen += 3 + sizeof(struct ieee80211_he_capabilities) + 3 + sizeof(struct ieee80211_he_operation) + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) + 3 + sizeof(struct ieee80211_spatial_reuse); + if (is_6ghz_op_class(hapd->iconf->op_class)) + buflen += sizeof(struct ieee80211_he_6ghz_oper_info) + + 3 + sizeof(struct ieee80211_he_6ghz_band_cap); } #endif /* CONFIG_IEEE80211AX */ 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,13 +522,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) - 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); @@ -470,15 +534,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); @@ -498,22 +555,34 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #endif /* CONFIG_FST */ #ifdef CONFIG_IEEE80211AC - if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { + if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac && + !is_6ghz_op_class(hapd->iconf->op_class)) { pos = hostapd_eid_vht_capabilities(hapd, pos, 0); pos = hostapd_eid_vht_operation(hapd, pos); pos = hostapd_eid_txpower_envelope(hapd, pos); - pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); } #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax && + is_6ghz_op_class(hapd->iconf->op_class)) + pos = hostapd_eid_txpower_envelope(hapd, pos); +#endif /* CONFIG_IEEE80211AX */ + + if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) || + (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)) + pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); + pos = hostapd_eid_fils_indic(hapd, pos, 0); + pos = hostapd_get_rsnxe(hapd, pos, epos - pos); #ifdef CONFIG_IEEE80211AX - if (hapd->iconf->ieee80211ax) { + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { 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); + pos = hostapd_eid_he_6ghz_band_cap(hapd, pos); } #endif /* CONFIG_IEEE80211AX */ @@ -522,9 +591,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) - 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); @@ -553,11 +622,11 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #ifdef CONFIG_HS20 pos = hostapd_eid_hs20_indication(hapd, pos); - pos = hostapd_eid_osen(hapd, pos); #endif /* CONFIG_HS20 */ 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), @@ -579,7 +648,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; @@ -590,20 +661,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; @@ -741,11 +822,11 @@ 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 (hapd->iconf->rssi_ignore_probe_request && ssi_signal && + ssi_signal < hapd->iconf->rssi_ignore_probe_request) + return; if (len < IEEE80211_HDRLEN) return; @@ -754,10 +835,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 @@ -836,7 +915,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; @@ -868,7 +947,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 @@ -881,6 +961,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) { @@ -985,9 +1071,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"); @@ -1038,6 +1124,23 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, #endif /* NEED_AP_MLME */ +#ifdef CONFIG_IEEE80211AX +/* Unsolicited broadcast Probe Response transmission, 6 GHz only */ +static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd, + struct wpa_driver_ap_params *params) +{ + if (!is_6ghz_op_class(hapd->iconf->op_class)) + return NULL; + + params->unsol_bcast_probe_resp_interval = + hapd->conf->unsol_bcast_probe_resp_interval; + + return hostapd_gen_probe_resp(hapd, NULL, 0, + ¶ms->unsol_bcast_probe_resp_tmpl_len); +} +#endif /* CONFIG_IEEE80211AX */ + + void sta_track_del(struct hostapd_sta_info *info) { #ifdef CONFIG_TAXONOMY @@ -1048,6 +1151,243 @@ void sta_track_del(struct hostapd_sta_info *info) } +#ifdef CONFIG_FILS + +static u16 hostapd_fils_discovery_cap(struct hostapd_data *hapd) +{ + u16 cap_info, phy_index = 0; + u8 chwidth = FD_CAP_BSS_CHWIDTH_20, mcs_nss_size = 4; + struct hostapd_hw_modes *mode = hapd->iface->current_mode; + + cap_info = FD_CAP_ESS; + if (hapd->conf->wpa) + cap_info |= FD_CAP_PRIVACY; + + if (is_6ghz_op_class(hapd->iconf->op_class)) { + phy_index = FD_CAP_PHY_INDEX_HE; + + switch (hapd->iconf->op_class) { + case 135: + mcs_nss_size += 4; + /* fallthrough */ + case 134: + mcs_nss_size += 4; + chwidth = FD_CAP_BSS_CHWIDTH_160_80_80; + break; + case 133: + chwidth = FD_CAP_BSS_CHWIDTH_80; + break; + case 132: + chwidth = FD_CAP_BSS_CHWIDTH_40; + break; + } + } else { + switch (hostapd_get_oper_chwidth(hapd->iconf)) { + case CHANWIDTH_80P80MHZ: + mcs_nss_size += 4; + /* fallthrough */ + case CHANWIDTH_160MHZ: + mcs_nss_size += 4; + chwidth = FD_CAP_BSS_CHWIDTH_160_80_80; + break; + case CHANWIDTH_80MHZ: + chwidth = FD_CAP_BSS_CHWIDTH_80; + break; + case CHANWIDTH_USE_HT: + if (hapd->iconf->secondary_channel) + chwidth = FD_CAP_BSS_CHWIDTH_40; + else + chwidth = FD_CAP_BSS_CHWIDTH_20; + break; + } + +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) + phy_index = FD_CAP_PHY_INDEX_HE; +#endif /* CONFIG_IEEE80211AX */ +#ifdef CONFIG_IEEE80211AC + if (!phy_index && + hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) + phy_index = FD_CAP_PHY_INDEX_VHT; +#endif /* CONFIG_IEEE80211AC */ + if (!phy_index && + hapd->iconf->ieee80211n && !hapd->conf->disable_11n) + phy_index = FD_CAP_PHY_INDEX_HT; + } + + cap_info |= phy_index << FD_CAP_PHY_INDEX_SHIFT; + cap_info |= chwidth << FD_CAP_BSS_CHWIDTH_SHIFT; + + if (mode) { + u16 *mcs = (u16 *) mode->he_capab[IEEE80211_MODE_AP].mcs; + int i; + u16 nss = 0; + + for (i = 0; i < HE_NSS_MAX_STREAMS; i++) { + u16 nss_mask = 0x3 << (i * 2); + + if (mcs_nss_size == 4 && + (((mcs[0] & nss_mask) == nss_mask) || + ((mcs[1] & nss_mask) == nss_mask))) + continue; + + if (mcs_nss_size == 8 && + (((mcs[2] & nss_mask) == nss_mask) || + ((mcs[3] & nss_mask) == nss_mask))) + continue; + + if (mcs_nss_size == 12 && + (((mcs[4] & nss_mask) == nss_mask) || + ((mcs[5] & nss_mask) == nss_mask))) + continue; + + nss++; + } + + if (nss > 4) + cap_info |= FD_CAP_NSS_5_8 << FD_CAP_NSS_SHIFT; + else if (nss) + cap_info |= (nss - 1) << FD_CAP_NSS_SHIFT; + } + + return cap_info; +} + + +static u8 * hostapd_gen_fils_discovery(struct hostapd_data *hapd, size_t *len) +{ + struct ieee80211_mgmt *head; + const u8 *mobility_domain; + u8 *pos, *length_pos, buf[200]; + u16 ctl = 0; + u8 fd_rsn_info[5]; + size_t total_len, buf_len; + + total_len = 24 + 2 + 12; + + /* FILS Discovery Frame Control */ + ctl = (sizeof(hapd->conf->ssid.short_ssid) - 1) | + FD_FRAME_CTL_SHORT_SSID_PRESENT | + FD_FRAME_CTL_LENGTH_PRESENT | + FD_FRAME_CTL_CAP_PRESENT; + total_len += 4 + 1 + 2; + + /* Check for optional subfields and calculate length */ + if (wpa_auth_write_fd_rsn_info(hapd->wpa_auth, fd_rsn_info)) { + ctl |= FD_FRAME_CTL_RSN_INFO_PRESENT; + total_len += sizeof(fd_rsn_info); + } + + mobility_domain = hostapd_wpa_ie(hapd, WLAN_EID_MOBILITY_DOMAIN); + if (mobility_domain) { + ctl |= FD_FRAME_CTL_MD_PRESENT; + total_len += 3; + } + + pos = hostapd_eid_fils_indic(hapd, buf, 0); + buf_len = pos - buf; + total_len += buf_len; + + head = os_zalloc(total_len); + if (!head) + return NULL; + + head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, + WLAN_FC_STYPE_ACTION); + os_memset(head->da, 0xff, ETH_ALEN); + os_memcpy(head->sa, hapd->own_addr, ETH_ALEN); + os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN); + + head->u.action.category = WLAN_ACTION_PUBLIC; + head->u.action.u.public_action.action = WLAN_PA_FILS_DISCOVERY; + + pos = &head->u.action.u.public_action.variable[0]; + + /* FILS Discovery Information field */ + + /* FILS Discovery Frame Control */ + WPA_PUT_LE16(pos, ctl); + pos += 2; + + /* Hardware or low-level driver will fill in the Timestamp value */ + pos += 8; + + /* Beacon Interval */ + WPA_PUT_LE16(pos, hapd->iconf->beacon_int); + pos += 2; + + /* Short SSID */ + WPA_PUT_LE32(pos, hapd->conf->ssid.short_ssid); + pos += sizeof(hapd->conf->ssid.short_ssid); + + /* Store position of FILS discovery information element Length field */ + length_pos = pos++; + + /* FD Capability */ + WPA_PUT_LE16(pos, hostapd_fils_discovery_cap(hapd)); + pos += 2; + + /* Operating Class - not present */ + + /* Primary Channel - not present */ + + /* AP Configuration Sequence Number - not present */ + + /* Access Network Options - not present */ + + /* FD RSN Information */ + if (ctl & FD_FRAME_CTL_RSN_INFO_PRESENT) { + os_memcpy(pos, fd_rsn_info, sizeof(fd_rsn_info)); + pos += sizeof(fd_rsn_info); + } + + /* Channel Center Frequency Segment 1 - not present */ + + /* Mobility Domain */ + if (ctl & FD_FRAME_CTL_MD_PRESENT) { + os_memcpy(pos, &mobility_domain[2], 3); + pos += 3; + } + + /* Fill in the Length field value */ + *length_pos = pos - (length_pos + 1); + + /* FILS Indication element */ + if (buf_len) { + os_memcpy(pos, buf, buf_len); + pos += buf_len; + } + + *len = pos - (u8 *) head; + wpa_hexdump(MSG_DEBUG, "FILS Discovery frame template", + head, pos - (u8 *) head); + return (u8 *) head; +} + + +/* Configure FILS Discovery frame transmission parameters */ +static u8 * hostapd_fils_discovery(struct hostapd_data *hapd, + struct wpa_driver_ap_params *params) +{ + params->fd_max_int = hapd->conf->fils_discovery_max_int; + if (is_6ghz_op_class(hapd->iconf->op_class) && + params->fd_max_int > FD_MAX_INTERVAL_6GHZ) + params->fd_max_int = FD_MAX_INTERVAL_6GHZ; + + params->fd_min_int = hapd->conf->fils_discovery_min_int; + if (params->fd_min_int > params->fd_max_int) + params->fd_min_int = params->fd_max_int; + + if (params->fd_max_int) + return hostapd_gen_fils_discovery(hapd, + ¶ms->fd_frame_tmpl_len); + + return NULL; +} + +#endif /* CONFIG_FILS */ + + int ieee802_11_build_ap_params(struct hostapd_data *hapd, struct wpa_driver_ap_params *params) { @@ -1058,7 +1398,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 @@ -1087,16 +1427,20 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #endif /* CONFIG_IEEE80211AC */ #ifdef CONFIG_IEEE80211AX - if (hapd->iconf->ieee80211ax) { + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { tail_len += 3 + sizeof(struct ieee80211_he_capabilities) + 3 + sizeof(struct ieee80211_he_operation) + 3 + sizeof(struct ieee80211_he_mu_edca_parameter_set) + 3 + sizeof(struct ieee80211_spatial_reuse); + if (is_6ghz_op_class(hapd->iconf->op_class)) + tail_len += sizeof(struct ieee80211_he_6ghz_oper_info) + + 3 + sizeof(struct ieee80211_he_6ghz_band_cap); } #endif /* CONFIG_IEEE80211AX */ 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) { @@ -1105,6 +1449,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); @@ -1145,8 +1490,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); @@ -1163,18 +1507,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) - 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); @@ -1183,15 +1520,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); @@ -1214,23 +1544,35 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #endif /* CONFIG_FST */ #ifdef CONFIG_IEEE80211AC - if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) { + if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac && + !is_6ghz_op_class(hapd->iconf->op_class)) { tailpos = hostapd_eid_vht_capabilities(hapd, tailpos, 0); tailpos = hostapd_eid_vht_operation(hapd, tailpos); tailpos = hostapd_eid_txpower_envelope(hapd, tailpos); - tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos); } #endif /* CONFIG_IEEE80211AC */ +#ifdef CONFIG_IEEE80211AX + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax && + is_6ghz_op_class(hapd->iconf->op_class)) + tailpos = hostapd_eid_txpower_envelope(hapd, tailpos); +#endif /* CONFIG_IEEE80211AX */ + + if ((hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) || + (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax)) + tailpos = hostapd_eid_wb_chsw_wrapper(hapd, tailpos); + tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0); + tailpos = hostapd_get_rsnxe(hapd, tailpos, tailend - tailpos); #ifdef CONFIG_IEEE80211AX - if (hapd->iconf->ieee80211ax) { + if (hapd->iconf->ieee80211ax && !hapd->conf->disable_11ax) { 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); + tailpos = hostapd_eid_he_6ghz_band_cap(hapd, tailpos); } #endif /* CONFIG_IEEE80211AX */ @@ -1239,11 +1581,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) - 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); @@ -1271,12 +1611,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, #ifdef CONFIG_HS20 tailpos = hostapd_eid_hs20_indication(hapd, tailpos); - tailpos = hostapd_eid_osen(hapd, tailpos); #endif /* CONFIG_HS20 */ 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), @@ -1315,10 +1655,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 || < |