aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@FreeBSD.org>2015-10-14 04:30:17 +0000
committerRui Paulo <rpaulo@FreeBSD.org>2015-10-14 04:30:17 +0000
commitb834757ea3bcd1bba3381ff7cab216458d8f7efb (patch)
treedadb24e00f30aa959ea0981e649b18c668304498
parentfbffd80fb2ba16c68f799da68a119d5e69643604 (diff)
downloadsrc-b834757ea3bcd1bba3381ff7cab216458d8f7efb.tar.gz
src-b834757ea3bcd1bba3381ff7cab216458d8f7efb.zip
Import wpa_supplicant/hostapd 2.5.vendor/wpa/2.5
Major changes: bunch of CVEs fixed, tab completion for wpa_cli and misc bug fixes.
Notes
Notes: svn path=/vendor/wpa/dist/; revision=289284 svn path=/vendor/wpa/2.5/; revision=289285; tag=vendor/wpa/2.5
-rw-r--r--hostapd/ChangeLog36
-rw-r--r--hostapd/Makefile55
-rw-r--r--hostapd/config_file.c164
-rw-r--r--hostapd/config_file.h2
-rw-r--r--hostapd/ctrl_iface.c814
-rw-r--r--hostapd/defconfig12
-rw-r--r--hostapd/hlr_auc_gw.c48
-rw-r--r--hostapd/hlr_auc_gw.milenage_db4
-rw-r--r--hostapd/hostapd.conf115
-rw-r--r--hostapd/hostapd_cli.c91
-rw-r--r--hostapd/main.c43
-rw-r--r--hs20/client/Makefile6
-rw-r--r--hs20/client/osu_client.c77
-rw-r--r--hs20/client/spp_client.c15
-rw-r--r--patches/openssl-0.9.8zf-tls-extensions.patch398
-rw-r--r--src/Makefile1
-rw-r--r--src/ap/Makefile65
-rw-r--r--src/ap/accounting.c12
-rw-r--r--src/ap/acs.c13
-rw-r--r--src/ap/ap_config.c53
-rw-r--r--src/ap/ap_config.h35
-rw-r--r--src/ap/ap_drv_ops.c123
-rw-r--r--src/ap/ap_drv_ops.h1
-rw-r--r--src/ap/ap_list.c13
-rw-r--r--src/ap/ap_list.h5
-rw-r--r--src/ap/authsrv.c18
-rw-r--r--src/ap/beacon.c165
-rw-r--r--src/ap/beacon.h5
-rw-r--r--src/ap/ctrl_iface_ap.c13
-rw-r--r--src/ap/dfs.c32
-rw-r--r--src/ap/drv_callbacks.c172
-rw-r--r--src/ap/eap_user_db.c16
-rw-r--r--src/ap/hostapd.c245
-rw-r--r--src/ap/hostapd.h27
-rw-r--r--src/ap/hw_features.c63
-rw-r--r--src/ap/hw_features.h5
-rw-r--r--src/ap/ieee802_11.c162
-rw-r--r--src/ap/ieee802_11.h8
-rw-r--r--src/ap/ieee802_11_auth.c25
-rw-r--r--src/ap/ieee802_11_auth.h1
-rw-r--r--src/ap/ieee802_11_ht.c25
-rw-r--r--src/ap/ieee802_11_vht.c3
-rw-r--r--src/ap/ieee802_1x.c86
-rw-r--r--src/ap/ieee802_1x.h1
-rw-r--r--src/ap/ndisc_snoop.c51
-rw-r--r--src/ap/sta_info.c67
-rw-r--r--src/ap/sta_info.h12
-rw-r--r--src/ap/utils.c11
-rw-r--r--src/ap/vlan_init.c155
-rw-r--r--src/ap/vlan_init.h2
-rw-r--r--src/ap/vlan_util.c55
-rw-r--r--src/ap/wmm.c3
-rw-r--r--src/ap/wpa_auth.c118
-rw-r--r--src/ap/wpa_auth.h17
-rw-r--r--src/ap/wpa_auth_ft.c21
-rw-r--r--src/ap/wpa_auth_glue.c24
-rw-r--r--src/ap/wpa_auth_i.h2
-rw-r--r--src/ap/wpa_auth_ie.c20
-rw-r--r--src/ap/wps_hostapd.c89
-rw-r--r--src/ap/x_snoop.c8
-rw-r--r--src/common/Makefile26
-rw-r--r--src/common/common_module_tests.c37
-rw-r--r--src/common/defs.h10
-rw-r--r--src/common/hw_features_common.c103
-rw-r--r--src/common/hw_features_common.h1
-rw-r--r--src/common/ieee802_11_common.c280
-rw-r--r--src/common/ieee802_11_common.h26
-rw-r--r--src/common/ieee802_11_defs.h117
-rw-r--r--src/common/privsep_commands.h35
-rw-r--r--src/common/qca-vendor.h113
-rw-r--r--src/common/sae.c391
-rw-r--r--src/common/sae.h3
-rw-r--r--src/common/version.h2
-rw-r--r--src/common/wpa_common.c182
-rw-r--r--src/common/wpa_common.h16
-rw-r--r--src/common/wpa_ctrl.c26
-rw-r--r--src/common/wpa_ctrl.h20
-rw-r--r--src/crypto/crypto.h30
-rw-r--r--src/crypto/crypto_cryptoapi.c783
-rw-r--r--src/crypto/crypto_module_tests.c59
-rw-r--r--src/crypto/crypto_openssl.c169
-rw-r--r--src/crypto/dh_groups.c2
-rw-r--r--src/crypto/fips_prf_openssl.c16
-rw-r--r--src/crypto/ms_funcs.c29
-rw-r--r--src/crypto/ms_funcs.h2
-rw-r--r--src/crypto/random.c1
-rw-r--r--src/crypto/sha1-tlsprf.c5
-rw-r--r--src/crypto/sha1-tprf.c2
-rw-r--r--src/crypto/sha256-kdf.c3
-rw-r--r--src/crypto/sha384-prf.c100
-rw-r--r--src/crypto/sha384.h5
-rw-r--r--src/crypto/tls.h94
-rw-r--r--src/crypto/tls_gnutls.c52
-rw-r--r--src/crypto/tls_internal.c120
-rw-r--r--src/crypto/tls_none.c40
-rw-r--r--src/crypto/tls_openssl.c835
-rw-r--r--src/crypto/tls_schannel.c763
-rw-r--r--src/drivers/driver.h100
-rw-r--r--src/drivers/driver_atheros.c85
-rw-r--r--src/drivers/driver_bsd.c6
-rw-r--r--src/drivers/driver_hostap.c43
-rw-r--r--src/drivers/driver_hostap.h2
-rw-r--r--src/drivers/driver_ndis.c8
-rw-r--r--src/drivers/driver_nl80211.c455
-rw-r--r--src/drivers/driver_nl80211.h9
-rw-r--r--src/drivers/driver_nl80211_android.c34
-rw-r--r--src/drivers/driver_nl80211_capa.c90
-rw-r--r--src/drivers/driver_nl80211_event.c63
-rw-r--r--src/drivers/driver_nl80211_scan.c10
-rw-r--r--src/drivers/driver_privsep.c94
-rw-r--r--src/drivers/driver_wext.c133
-rw-r--r--src/drivers/drivers.c2
-rw-r--r--src/drivers/drivers.mak4
-rw-r--r--src/drivers/linux_ioctl.c23
-rw-r--r--src/drivers/linux_ioctl.h1
-rw-r--r--src/drivers/nl80211_copy.h236
-rw-r--r--src/eap_common/Makefile29
-rw-r--r--src/eap_common/eap_common.c2
-rw-r--r--src/eap_common/eap_fast_common.c41
-rw-r--r--src/eap_common/eap_pwd_common.c17
-rw-r--r--src/eap_common/eap_pwd_common.h13
-rw-r--r--src/eap_common/eap_sake_common.c86
-rw-r--r--src/eap_common/ikev2_common.c6
-rw-r--r--src/eap_peer/Makefile18
-rw-r--r--src/eap_peer/eap.c14
-rw-r--r--src/eap_peer/eap.h2
-rw-r--r--src/eap_peer/eap_aka.c2
-rw-r--r--src/eap_peer/eap_eke.c105
-rw-r--r--src/eap_peer/eap_fast.c78
-rw-r--r--src/eap_peer/eap_gpsk.c27
-rw-r--r--src/eap_peer/eap_i.h8
-rw-r--r--src/eap_peer/eap_mschapv2.c6
-rw-r--r--src/eap_peer/eap_pax.c2
-rw-r--r--src/eap_peer/eap_peap.c18
-rw-r--r--src/eap_peer/eap_pwd.c116
-rw-r--r--src/eap_peer/eap_sake.c25
-rw-r--r--src/eap_peer/eap_sim.c2
-rw-r--r--src/eap_peer/eap_tls.c18
-rw-r--r--src/eap_peer/eap_tls_common.c137
-rw-r--r--src/eap_peer/eap_tls_common.h2
-rw-r--r--src/eap_peer/eap_ttls.c41
-rw-r--r--src/eap_peer/eap_wsc.c3
-rw-r--r--src/eap_server/Makefile19
-rw-r--r--src/eap_server/eap.h6
-rw-r--r--src/eap_server/eap_i.h3
-rw-r--r--src/eap_server/eap_server.c47
-rw-r--r--src/eap_server/eap_server_eke.c24
-rw-r--r--src/eap_server/eap_server_fast.c2
-rw-r--r--src/eap_server/eap_server_mschapv2.c13
-rw-r--r--src/eap_server/eap_server_peap.c147
-rw-r--r--src/eap_server/eap_server_pwd.c64
-rw-r--r--src/eap_server/eap_server_tls.c58
-rw-r--r--src/eap_server/eap_server_tls_common.c53
-rw-r--r--src/eap_server/eap_server_ttls.c111
-rw-r--r--src/eap_server/eap_tls_common.h2
-rw-r--r--src/eapol_auth/Makefile14
-rw-r--r--src/eapol_auth/eapol_auth_sm.c101
-rw-r--r--src/eapol_auth/eapol_auth_sm.h6
-rw-r--r--src/eapol_supp/Makefile16
-rw-r--r--src/eapol_supp/eapol_supp_sm.c15
-rw-r--r--src/fst/Makefile8
-rw-r--r--src/fst/fst.c225
-rw-r--r--src/fst/fst.h296
-rw-r--r--src/fst/fst_ctrl_aux.c69
-rw-r--r--src/fst/fst_ctrl_aux.h91
-rw-r--r--src/fst/fst_ctrl_defs.h109
-rw-r--r--src/fst/fst_ctrl_iface.c948
-rw-r--r--src/fst/fst_ctrl_iface.h45
-rw-r--r--src/fst/fst_defs.h87
-rw-r--r--src/fst/fst_group.c462
-rw-r--r--src/fst/fst_group.h75
-rw-r--r--src/fst/fst_iface.c79
-rw-r--r--src/fst/fst_iface.h135
-rw-r--r--src/fst/fst_internal.h49
-rw-r--r--src/fst/fst_session.c1620
-rw-r--r--src/fst/fst_session.h80
-rw-r--r--src/l2_packet/Makefile14
-rw-r--r--src/p2p/Makefile27
-rw-r--r--src/p2p/p2p.c282
-rw-r--r--src/p2p/p2p.h136
-rw-r--r--src/p2p/p2p_build.c360
-rw-r--r--src/p2p/p2p_dev_disc.c2
-rw-r--r--src/p2p/p2p_go_neg.c213
-rw-r--r--src/p2p/p2p_group.c40
-rw-r--r--src/p2p/p2p_i.h38
-rw-r--r--src/p2p/p2p_invitation.c23
-rw-r--r--src/p2p/p2p_parse.c25
-rw-r--r--src/p2p/p2p_pd.c400
-rw-r--r--src/p2p/p2p_utils.c58
-rw-r--r--src/radius/Makefile1
-rw-r--r--src/radius/radius.c12
-rw-r--r--src/radius/radius_das.c2
-rw-r--r--src/radius/radius_server.c20
-rw-r--r--src/radius/radius_server.h2
-rw-r--r--src/rsn_supp/Makefile28
-rw-r--r--src/rsn_supp/tdls.c23
-rw-r--r--src/rsn_supp/wpa.c27
-rw-r--r--src/rsn_supp/wpa_ft.c4
-rw-r--r--src/rsn_supp/wpa_ie.c18
-rw-r--r--src/rsn_supp/wpa_ie.h2
-rw-r--r--src/tls/libtommath.c5
-rw-r--r--src/tls/tlsv1_client.c8
-rw-r--r--src/tls/tlsv1_client.h2
-rw-r--r--src/tls/tlsv1_server.c8
-rw-r--r--src/tls/tlsv1_server.h2
-rw-r--r--src/tls/x509v3.c2
-rw-r--r--src/utils/browser-wpadebug.c6
-rw-r--r--src/utils/common.c97
-rw-r--r--src/utils/common.h41
-rw-r--r--src/utils/eloop.c45
-rw-r--r--src/utils/http_curl.c14
-rw-r--r--src/utils/includes.h7
-rw-r--r--src/utils/os.h15
-rw-r--r--src/utils/os_internal.c6
-rw-r--r--src/utils/os_none.c6
-rw-r--r--src/utils/os_unix.c120
-rw-r--r--src/utils/os_win32.c18
-rw-r--r--src/utils/radiotap.c4
-rw-r--r--src/utils/utils_module_tests.c440
-rw-r--r--src/utils/wpa_debug.c90
-rw-r--r--src/utils/wpa_debug.h27
-rw-r--r--src/utils/wpabuf.c2
-rw-r--r--src/wps/Makefile39
-rw-r--r--src/wps/http_client.c42
-rw-r--r--src/wps/http_server.c8
-rw-r--r--src/wps/httpread.c123
-rw-r--r--src/wps/ndef.c16
-rw-r--r--src/wps/wps.c15
-rw-r--r--src/wps/wps.h7
-rw-r--r--src/wps/wps_attr_parse.c43
-rw-r--r--src/wps/wps_attr_parse.h41
-rw-r--r--src/wps/wps_common.c4
-rw-r--r--src/wps/wps_defs.h6
-rw-r--r--src/wps/wps_enrollee.c7
-rw-r--r--src/wps/wps_er.c27
-rw-r--r--src/wps/wps_er_ssdp.c4
-rw-r--r--src/wps/wps_module_tests.c4
-rw-r--r--src/wps/wps_registrar.c14
-rw-r--r--src/wps/wps_upnp.c7
-rw-r--r--src/wps/wps_upnp_ap.c6
-rw-r--r--src/wps/wps_upnp_event.c8
-rw-r--r--src/wps/wps_upnp_ssdp.c19
-rw-r--r--src/wps/wps_upnp_web.c15
-rw-r--r--src/wps/wps_validate.c2
-rw-r--r--wpa_supplicant/ChangeLog63
-rw-r--r--wpa_supplicant/Makefile102
-rw-r--r--wpa_supplicant/ap.c46
-rw-r--r--wpa_supplicant/ap.h2
-rw-r--r--wpa_supplicant/bss.c76
-rw-r--r--wpa_supplicant/bss.h2
-rw-r--r--wpa_supplicant/config.c69
-rw-r--r--wpa_supplicant/config.h86
-rw-r--r--wpa_supplicant/config_file.c67
-rw-r--r--wpa_supplicant/config_ssid.h17
-rw-r--r--wpa_supplicant/ctrl_iface.c751
-rw-r--r--wpa_supplicant/ctrl_iface_named_pipe.c3
-rw-r--r--wpa_supplicant/ctrl_iface_udp.c3
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c118
-rw-r--r--wpa_supplicant/dbus/dbus_new.c378
-rw-r--r--wpa_supplicant/dbus/dbus_new.h43
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c128
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h6
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c317
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.h22
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_wps.c26
-rw-r--r--wpa_supplicant/dbus/dbus_new_helpers.c7
-rw-r--r--wpa_supplicant/dbus/dbus_new_introspect.c2
-rw-r--r--wpa_supplicant/dbus/dbus_old.c10
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.c26
-rw-r--r--wpa_supplicant/defconfig9
-rw-r--r--wpa_supplicant/doc/docbook/eapol_test.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.813
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.sgml17
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.conf.52
-rw-r--r--wpa_supplicant/driver_i.h40
-rw-r--r--wpa_supplicant/eapol_test.c131
-rwxr-xr-xwpa_supplicant/eapol_test.py142
-rw-r--r--wpa_supplicant/events.c279
-rw-r--r--wpa_supplicant/hs20_supplicant.c18
-rw-r--r--wpa_supplicant/ibss_rsn.c6
-rw-r--r--wpa_supplicant/interworking.c16
-rw-r--r--wpa_supplicant/main.c18
-rw-r--r--wpa_supplicant/mesh.c17
-rw-r--r--wpa_supplicant/mesh_mpm.c9
-rw-r--r--wpa_supplicant/mesh_rsn.c8
-rw-r--r--wpa_supplicant/notify.c58
-rw-r--r--wpa_supplicant/notify.h9
-rw-r--r--wpa_supplicant/p2p_supplicant.c2402
-rw-r--r--wpa_supplicant/p2p_supplicant.h33
-rw-r--r--wpa_supplicant/p2p_supplicant_sd.c1273
-rw-r--r--wpa_supplicant/preauth_test.c2
-rw-r--r--wpa_supplicant/scan.c76
-rw-r--r--wpa_supplicant/sme.c70
-rw-r--r--wpa_supplicant/wpa_cli.c511
-rw-r--r--wpa_supplicant/wpa_priv.c155
-rw-r--r--wpa_supplicant/wpa_supplicant.c379
-rw-r--r--wpa_supplicant/wpa_supplicant.conf47
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h81
-rw-r--r--wpa_supplicant/wpas_glue.c61
-rw-r--r--wpa_supplicant/wpas_glue.h3
-rw-r--r--wpa_supplicant/wps_supplicant.c122
-rw-r--r--wpa_supplicant/wps_supplicant.h1
307 files changed, 20840 insertions, 6450 deletions
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index e6f8c6a03e07..af54e1e5b4e4 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,41 @@
ChangeLog for hostapd
+2015-09-27 - v2.5
+ * fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
+ [http://w1.fi/security/2015-2/] (CVE-2015-4141)
+ * fixed WMM Action frame parser
+ [http://w1.fi/security/2015-3/] (CVE-2015-4142)
+ * fixed EAP-pwd server missing payload length validation
+ [http://w1.fi/security/2015-4/]
+ (CVE-2015-4143, CVE-2015-4144, CVE-2015-4145)
+ * fixed validation of WPS and P2P NFC NDEF record payload length
+ [http://w1.fi/security/2015-5/]
+ * nl80211:
+ - fixed vendor command handling to check OUI properly
+ * fixed hlr_auc_gw build with OpenSSL
+ * hlr_auc_gw: allow Milenage RES length to be reduced
+ * disable HT for a station that does not support WMM/QoS
+ * added support for hashed password (NtHash) in EAP-pwd server
+ * fixed and extended dynamic VLAN cases
+ * added EAP-EKE server support for deriving Session-Id
+ * set Acct-Session-Id to a random value to make it more likely to be
+ unique even if the device does not have a proper clock
+ * added more 2.4 GHz channels for 20/40 MHz HT co-ex scan
+ * modified SAE routines to be more robust and PWE generation to be
+ stronger against timing attacks
+ * added support for Brainpool Elliptic Curves with SAE
+ * increases maximum value accepted for cwmin/cwmax
+ * added support for CCMP-256 and GCMP-256 as group ciphers with FT
+ * added Fast Session Transfer (FST) module
+ * removed optional fields from RSNE when using FT with PMF
+ (workaround for interoperability issues with iOS 8.4)
+ * added EAP server support for TLS session resumption
+ * fixed key derivation for Suite B 192-bit AKM (this breaks
+ compatibility with the earlier version)
+ * added mechanism to track unconnected stations and do minimal band
+ steering
+ * number of small fixes
+
2015-03-15 - v2.4
* allow OpenSSL cipher configuration to be set for internal EAP server
(openssl_ciphers parameter)
diff --git a/hostapd/Makefile b/hostapd/Makefile
index eace68cd051b..a812b9d661c3 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -107,7 +107,16 @@ 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
+
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
@@ -227,6 +236,7 @@ CFLAGS += -DCONFIG_SAE
OBJS += ../src/common/sae.o
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_AP_MLME=y
endif
ifdef CONFIG_WNM
@@ -531,8 +541,14 @@ HOBJS += ../src/crypto/crypto_openssl.o
ifdef NEED_FIPS186_2_PRF
OBJS += ../src/crypto/fips_prf_openssl.o
endif
+NEED_SHA256=y
+NEED_TLS_PRF_SHA256=y
LIBS += -lcrypto
LIBS_h += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_h += -ldl
+endif
endif
ifeq ($(CONFIG_TLS), gnutls)
@@ -553,17 +569,6 @@ CONFIG_INTERNAL_RC4=y
CONFIG_INTERNAL_DH_GROUP5=y
endif
-ifeq ($(CONFIG_TLS), schannel)
-ifdef TLS_FUNCS
-OBJS += ../src/crypto/tls_schannel.o
-endif
-OBJS += ../src/crypto/crypto_cryptoapi.o
-OBJS_p += ../src/crypto/crypto_cryptoapi.o
-CONFIG_INTERNAL_SHA256=y
-CONFIG_INTERNAL_RC4=y
-CONFIG_INTERNAL_DH_GROUP5=y
-endif
-
ifeq ($(CONFIG_TLS), internal)
ifndef CONFIG_CRYPTO
CONFIG_CRYPTO=internal
@@ -694,8 +699,10 @@ endif
endif
ifdef NEED_AES_CBC
NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += ../src/crypto/aes-cbc.o
endif
+endif
ifdef NEED_AES_DEC
ifdef CONFIG_INTERNAL_AES
AESOBJS += ../src/crypto/aes-internal-dec.o
@@ -754,11 +761,17 @@ 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
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
@@ -778,6 +791,7 @@ endif
endif
ifdef NEED_SHA384
CFLAGS += -DCONFIG_SHA384
+OBJS += ../src/crypto/sha384-prf.o
endif
ifdef NEED_DH_GROUPS
@@ -803,8 +817,10 @@ OBJS += ../src/crypto/random.o
HOBJS += ../src/crypto/random.o
HOBJS += ../src/utils/eloop.o
HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
HOBJS += ../src/crypto/md5.o
endif
+endif
ifdef CONFIG_RADIUS_SERVER
CFLAGS += -DRADIUS_SERVER
@@ -903,6 +919,21 @@ 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
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
@@ -965,9 +996,11 @@ 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
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 53143f76cfe8..82ac61d7729a 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -222,9 +222,15 @@ static int hostapd_config_read_eap_user(const char *fname,
return 0;
if (os_strncmp(fname, "sqlite:", 7) == 0) {
+#ifdef CONFIG_SQLITE
os_free(conf->eap_user_sqlite);
conf->eap_user_sqlite = os_strdup(fname + 7);
return 0;
+#else /* CONFIG_SQLITE */
+ wpa_printf(MSG_ERROR,
+ "EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build.");
+ return -1;
+#endif /* CONFIG_SQLITE */
}
f = fopen(fname, "r");
@@ -775,6 +781,24 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
}
+static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
+{
+ char *pos;
+
+ /* for backwards compatibility, translate ' ' in conf str to ',' */
+ pos = val;
+ while (pos) {
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ *pos++ = ',';
+ }
+ if (freq_range_list_parse(&conf->acs_ch_list, val))
+ return -1;
+
+ return 0;
+}
+
+
static int hostapd_parse_intlist(int **int_list, char *val)
{
int *list;
@@ -875,7 +899,9 @@ static int hostapd_config_read_int10(const char *value)
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 == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
+ cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
+ cw == 32767);
}
@@ -886,11 +912,11 @@ enum {
IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
};
-static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
- char *val)
+static int hostapd_config_tx_queue(struct hostapd_config *conf,
+ const char *name, const char *val)
{
int num;
- char *pos;
+ const char *pos;
struct hostapd_tx_queue_params *queue;
/* skip 'tx_queue_' prefix */
@@ -1134,13 +1160,23 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
if (os_strstr(capab, "[BF-ANTENNA-2]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ if (os_strstr(capab, "[BF-ANTENNA-3]") &&
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ conf->vht_capab |= (2 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+ if (os_strstr(capab, "[BF-ANTENNA-4]") &&
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ conf->vht_capab |= (3 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
+ if (os_strstr(capab, "[SOUNDING-DIMENSION-3]") &&
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+ conf->vht_capab |= (2 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
+ if (os_strstr(capab, "[SOUNDING-DIMENSION-4]") &&
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+ conf->vht_capab |= (3 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
if (os_strstr(capab, "[MU-BEAMFORMER]"))
conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
- if (os_strstr(capab, "[MU-BEAMFORMEE]"))
- conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
if (os_strstr(capab, "[VHT-TXOP-PS]"))
conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
if (os_strstr(capab, "[HTC-VHT]"))
@@ -1699,7 +1735,7 @@ static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
char *str;
str = wpa_config_parse_string(pos, &slen);
- if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+ if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
os_free(str);
return -1;
@@ -1900,7 +1936,7 @@ fail:
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
- char *buf, char *pos, int line)
+ const char *buf, char *pos, int line)
{
if (os_strcmp(buf, "interface") == 0) {
os_strlcpy(conf->bss[0]->iface, pos,
@@ -1946,7 +1982,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
} else if (os_strcmp(buf, "ssid") == 0) {
bss->ssid.ssid_len = os_strlen(pos);
- if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+ if (bss->ssid.ssid_len > SSID_MAX_LEN ||
bss->ssid.ssid_len < 1) {
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
line, pos);
@@ -1957,7 +1993,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "ssid2") == 0) {
size_t slen;
char *str = wpa_config_parse_string(pos, &slen);
- if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+ if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
line, pos);
os_free(str);
@@ -2043,6 +2079,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->private_key_passwd = os_strdup(pos);
} else if (os_strcmp(buf, "check_crl") == 0) {
bss->check_crl = atoi(pos);
+ } else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
+ bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
@@ -2515,13 +2553,17 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
else if (os_strcmp(pos, "ad") == 0)
conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+ else if (os_strcmp(pos, "any") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
else {
wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
- if (os_strcmp(pos, "a") == 0)
+ if (os_strcmp(pos, "ad") == 0)
+ bss->wps_rf_bands = WPS_RF_60GHZ;
+ else if (os_strcmp(pos, "a") == 0)
bss->wps_rf_bands = WPS_RF_50GHZ;
else if (os_strcmp(pos, "g") == 0 ||
os_strcmp(pos, "b") == 0)
@@ -2542,12 +2584,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
return 1;
#else /* CONFIG_ACS */
+ conf->acs = 1;
conf->channel = 0;
#endif /* CONFIG_ACS */
- } else
+ } else {
conf->channel = atoi(pos);
+ conf->acs = conf->channel == 0;
+ }
} else if (os_strcmp(buf, "chanlist") == 0) {
- if (hostapd_parse_intlist(&conf->chanlist, pos)) {
+ if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
line);
return 1;
@@ -2810,7 +2855,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->wps_pin_requests);
bss->wps_pin_requests = os_strdup(pos);
} else if (os_strcmp(buf, "device_name") == 0) {
- if (os_strlen(pos) > 32) {
+ if (os_strlen(pos) > WPS_DEV_NAME_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: Too long "
"device_name", line);
return 1;
@@ -3111,6 +3156,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->disable_dgaf = atoi(pos);
} else if (os_strcmp(buf, "proxy_arp") == 0) {
bss->proxy_arp = atoi(pos);
+ } else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
+ bss->na_mcast_to_ucast = atoi(pos);
} else if (os_strcmp(buf, "osen") == 0) {
bss->osen = atoi(pos);
} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
@@ -3223,6 +3270,24 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->bss_load_test_set = 1;
} else if (os_strcmp(buf, "radio_measurements") == 0) {
bss->radio_measurements = atoi(pos);
+ } else if (os_strcmp(buf, "own_ie_override") == 0) {
+ struct wpabuf *tmp;
+ size_t len = os_strlen(pos) / 2;
+
+ tmp = wpabuf_alloc(len);
+ if (!tmp)
+ return 1;
+
+ if (hexstr2bin(pos, wpabuf_put(tmp, len), len)) {
+ wpabuf_free(tmp);
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid own_ie_override '%s'",
+ line, pos);
+ return 1;
+ }
+
+ wpabuf_free(bss->own_ie_override);
+ bss->own_ie_override = tmp;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strcmp(buf, "vendor_elements") == 0) {
struct wpabuf *elems;
@@ -3276,6 +3341,74 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "wowlan_triggers") == 0) {
os_free(bss->wowlan_triggers);
bss->wowlan_triggers = os_strdup(pos);
+#ifdef CONFIG_FST
+ } else if (os_strcmp(buf, "fst_group_id") == 0) {
+ size_t len = os_strlen(pos);
+
+ if (!len || len >= sizeof(conf->fst_cfg.group_id)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid fst_group_id value '%s'",
+ line, pos);
+ return 1;
+ }
+
+ if (conf->fst_cfg.group_id[0]) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Duplicate fst_group value '%s'",
+ line, pos);
+ return 1;
+ }
+
+ os_strlcpy(conf->fst_cfg.group_id, pos,
+ sizeof(conf->fst_cfg.group_id));
+ } else if (os_strcmp(buf, "fst_priority") == 0) {
+ char *endp;
+ long int val;
+
+ if (!*pos) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: fst_priority value not supplied (expected 1..%u)",
+ line, FST_MAX_PRIO_VALUE);
+ return -1;
+ }
+
+ val = strtol(pos, &endp, 0);
+ if (*endp || val < 1 || val > FST_MAX_PRIO_VALUE) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid fst_priority %ld (%s) (expected 1..%u)",
+ line, val, pos, FST_MAX_PRIO_VALUE);
+ return 1;
+ }
+ conf->fst_cfg.priority = (u8) val;
+ } else if (os_strcmp(buf, "fst_llt") == 0) {
+ char *endp;
+ long int val;
+
+ if (!*pos) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: fst_llt value not supplied (expected 1..%u)",
+ line, FST_MAX_LLT_MS);
+ return -1;
+ }
+ val = strtol(pos, &endp, 0);
+ if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
+ line, val, pos, FST_MAX_LLT_MS);
+ return 1;
+ }
+ conf->fst_cfg.llt = (u32) val;
+#endif /* CONFIG_FST */
+ } else if (os_strcmp(buf, "track_sta_max_num") == 0) {
+ conf->track_sta_max_num = atoi(pos);
+ } else if (os_strcmp(buf, "track_sta_max_age") == 0) {
+ conf->track_sta_max_age = atoi(pos);
+ } else if (os_strcmp(buf, "no_probe_resp_if_seen_on") == 0) {
+ os_free(bss->no_probe_resp_if_seen_on);
+ bss->no_probe_resp_if_seen_on = os_strdup(pos);
+ } else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
+ os_free(bss->no_auth_if_seen_on);
+ bss->no_auth_if_seen_on = os_strdup(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
@@ -3378,7 +3511,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
int hostapd_set_iface(struct hostapd_config *conf,
- struct hostapd_bss_config *bss, char *field, char *value)
+ struct hostapd_bss_config *bss, const char *field,
+ char *value)
{
int errors;
size_t i;
diff --git a/hostapd/config_file.h b/hostapd/config_file.h
index fba57b87ad7c..c98bdb683ba1 100644
--- a/hostapd/config_file.h
+++ b/hostapd/config_file.h
@@ -11,7 +11,7 @@
struct hostapd_config * hostapd_config_read(const char *fname);
int hostapd_set_iface(struct hostapd_config *conf,
- struct hostapd_bss_config *bss, char *field,
+ struct hostapd_bss_config *bss, const char *field,
char *value);
#endif /* CONFIG_FILE_H */
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 86f1aa6dfdb2..cb6fb1757708 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -25,6 +25,7 @@
#include "common/ieee802_11_defs.h"
#include "crypto/tls.h"
#include "drivers/driver.h"
+#include "eapol_auth/eapol_auth_sm.h"
#include "radius/radius_client.h"
#include "radius/radius_server.h"
#include "l2_packet/l2_packet.h"
@@ -43,10 +44,13 @@
#include "ap/beacon.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
+#include "fst/fst_ctrl_iface.h"
#include "config_file.h"
#include "ctrl_iface.h"
+#define HOSTAPD_CLI_DUP_VALUE_MAX_LEN 256
+
struct wpa_ctrl_dst {
struct wpa_ctrl_dst *next;
struct sockaddr_un addr;
@@ -57,6 +61,7 @@ struct wpa_ctrl_dst {
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ enum wpa_msg_type type,
const char *buf, size_t len);
@@ -1055,6 +1060,97 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
#endif /* CONFIG_WNM */
+static int hostapd_ctrl_iface_get_key_mgmt(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ int ret = 0;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ WPA_ASSERT(hapd->conf->wpa_key_mgmt);
+
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+ ret = os_snprintf(pos, end - pos, "WPA-PSK ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+ ret = os_snprintf(pos, end - pos, "WPA-EAP ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+ ret = os_snprintf(pos, end - pos, "FT-PSK ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+ ret = os_snprintf(pos, end - pos, "FT-EAP ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#ifdef CONFIG_SAE
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+ ret = os_snprintf(pos, end - pos, "FT-SAE ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+#endif /* CONFIG_IEEE80211R */
+#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))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+ ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
+ if (os_snprintf_error(end - pos, ret))
+ 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 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+#endif /* CONFIG_SAE */
+ if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+ if (hapd->conf->wpa_key_mgmt &
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos,
+ "WPA-EAP-SUITE-B-192 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
+ if (pos > buf && *(pos - 1) == ' ') {
+ *(pos - 1) = '\0';
+ pos--;
+ }
+
+ return pos - buf;
+}
+
+
static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
@@ -1104,82 +1200,20 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
}
#endif /* CONFIG_WPS */
+ if (hapd->conf->wpa) {
+ ret = os_snprintf(pos, end - pos, "wpa=%d\n", hapd->conf->wpa);
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
+
if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
ret = os_snprintf(pos, end - pos, "key_mgmt=");
if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
- if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
- ret = os_snprintf(pos, end - pos, "WPA-PSK ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
- ret = os_snprintf(pos, end - pos, "WPA-EAP ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
-#ifdef CONFIG_IEEE80211R
- if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
- ret = os_snprintf(pos, end - pos, "FT-PSK ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
- ret = os_snprintf(pos, end - pos, "FT-EAP ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
-#ifdef CONFIG_SAE
- if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
- ret = os_snprintf(pos, end - pos, "FT-SAE ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
-#endif /* CONFIG_SAE */
-#endif /* CONFIG_IEEE80211R */
-#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))
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
- ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
- if (os_snprintf_error(end - pos, ret))
- 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 ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
-#endif /* CONFIG_SAE */
- if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
- ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
- if (hapd->conf->wpa_key_mgmt &
- WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
- ret = os_snprintf(pos, end - pos,
- "WPA-EAP-SUITE-B-192 ");
- if (os_snprintf_error(end - pos, ret))
- return pos - buf;
- pos += ret;
- }
+ pos += hostapd_ctrl_iface_get_key_mgmt(hapd, pos, end - pos);
ret = os_snprintf(pos, end - pos, "\n");
if (os_snprintf_error(end - pos, ret))
@@ -1528,7 +1562,7 @@ void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
{
struct hostapd_data *hapd = ctx;
const struct ether_header *eth;
- const struct iphdr *ip;
+ struct iphdr ip;
const u8 *pos;
unsigned int i;
@@ -1536,14 +1570,14 @@ void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
return;
eth = (const struct ether_header *) buf;
- ip = (const struct iphdr *) (eth + 1);
- pos = (const u8 *) (ip + 1);
+ 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.ihl != 5 || ip.version != 4 ||
+ ntohs(ip.tot_len) != HWSIM_IP_LEN)
return;
- for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+ for (i = 0; i < HWSIM_IP_LEN - sizeof(ip); i++) {
if (*pos != (u8) i)
return;
pos++;
@@ -1599,7 +1633,7 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
int used;
long int val;
u8 tos;
- u8 buf[HWSIM_PACKETLEN];
+ u8 buf[2 + HWSIM_PACKETLEN];
struct ether_header *eth;
struct iphdr *ip;
u8 *dpos;
@@ -1627,7 +1661,7 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
return -1;
tos = val;
- eth = (struct ether_header *) buf;
+ eth = (struct ether_header *) &buf[2];
os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
os_memcpy(eth->ether_shost, src, ETH_ALEN);
eth->ether_type = htons(ETHERTYPE_IP);
@@ -1639,14 +1673,14 @@ static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
ip->tos = tos;
ip->tot_len = htons(HWSIM_IP_LEN);
ip->protocol = 1;
- ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
- ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
+ 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));
dpos = (u8 *) (ip + 1);
for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
*dpos++ = i;
- if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, buf,
+ if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, &buf[2],
HWSIM_PACKETLEN) < 0)
return -1;
@@ -1746,6 +1780,45 @@ static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
#endif /* WPA_TRACE_BFD */
}
+
+static int hostapd_ctrl_test_fail(struct hostapd_data *hapd, char *cmd)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_test_fail_func[256];
+ extern unsigned int wpa_trace_test_fail_after;
+ char *pos;
+
+ wpa_trace_test_fail_after = atoi(cmd);
+ pos = os_strchr(cmd, ':');
+ if (pos) {
+ pos++;
+ os_strlcpy(wpa_trace_test_fail_func, pos,
+ sizeof(wpa_trace_test_fail_func));
+ } else {
+ wpa_trace_test_fail_after = 0;
+ }
+
+ return 0;
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+static int hostapd_ctrl_get_fail(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_test_fail_func[256];
+ extern unsigned int wpa_trace_test_fail_after;
+
+ return os_snprintf(buf, buflen, "%u:%s", wpa_trace_test_fail_after,
+ wpa_trace_test_fail_func);
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -1847,41 +1920,134 @@ static int hostapd_ctrl_iface_vendor(struct hostapd_data *hapd, char *cmd,
}
-static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
- void *sock_ctx)
+static int hostapd_ctrl_iface_eapol_reauth(struct hostapd_data *hapd,
+ const char *cmd)
{
- struct hostapd_data *hapd = eloop_ctx;
- char buf[4096];
- int res;
- struct sockaddr_un from;
- socklen_t fromlen = sizeof(from);
- char *reply;
- const int reply_size = 4096;
- int reply_len;
- int level = MSG_DEBUG;
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
- (struct sockaddr *) &from, &fromlen);
- if (res < 0) {
- wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
- strerror(errno));
- return;
+ if (hwaddr_aton(cmd, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->eapol_sm)
+ return -1;
+
+ eapol_auth_reauthenticate(sta->eapol_sm);
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_eapol_set(struct hostapd_data *hapd, char *cmd)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+ char *pos = cmd, *param;
+
+ if (hwaddr_aton(pos, addr) || pos[17] != ' ')
+ return -1;
+ pos += 18;
+ param = pos;
+ pos = os_strchr(pos, ' ');
+ if (!pos)
+ return -1;
+ *pos++ = '\0';
+
+ sta = ap_get_sta(hapd, addr);
+ if (!sta || !sta->eapol_sm)
+ return -1;
+
+ return eapol_auth_set_conf(sta->eapol_sm, param, pos);
+}
+
+
+static int hostapd_ctrl_iface_log_level(struct hostapd_data *hapd, char *cmd,
+ char *buf, size_t buflen)
+{
+ char *pos, *end, *stamp;
+ int ret;
+
+ /* cmd: "LOG_LEVEL [<level>]" */
+ if (*cmd == '\0') {
+ pos = buf;
+ end = buf + buflen;
+ ret = os_snprintf(pos, end - pos, "Current level: %s\n"
+ "Timestamp: %d\n",
+ debug_level_str(wpa_debug_level),
+ wpa_debug_timestamp);
+ if (os_snprintf_error(end - pos, ret))
+ ret = 0;
+
+ return ret;
}
- buf[res] = '\0';
- if (os_strcmp(buf, "PING") == 0)
- level = MSG_EXCESSIVE;
- wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
- reply = os_malloc(reply_size);
- if (reply == NULL) {
- if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen) < 0) {
- wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
- strerror(errno));
+ while (*cmd == ' ')
+ cmd++;
+
+ stamp = os_strchr(cmd, ' ');
+ if (stamp) {
+ *stamp++ = '\0';
+ while (*stamp == ' ') {
+ stamp++;
}
- return;
}
+ if (os_strlen(cmd)) {
+ int level = str_to_debug_level(cmd);
+ if (level < 0)
+ return -1;
+ wpa_debug_level = level;
+ }
+
+ if (stamp && os_strlen(stamp))
+ wpa_debug_timestamp = atoi(stamp);
+
+ os_memcpy(buf, "OK\n", 3);
+ return 3;
+}
+
+
+#ifdef NEED_AP_MLME
+static int hostapd_ctrl_iface_track_sta_list(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ char *pos, *end;
+ struct hostapd_sta_info *info;
+ struct os_reltime now;
+
+ sta_track_expire(iface, 0);
+
+ pos = buf;
+ end = buf + buflen;
+
+ os_get_reltime(&now);
+ dl_list_for_each_reverse(info, &iface->sta_seen,
+ struct hostapd_sta_info, list) {
+ struct os_reltime age;
+ int ret;
+
+ os_reltime_sub(&now, &info->last_seen, &age);
+ ret = os_snprintf(pos, end - pos, MACSTR " %u\n",
+ MAC2STR(info->addr), (unsigned int) age.sec);
+ if (os_snprintf_error(end - pos, ret))
+ break;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+#endif /* NEED_AP_MLME */
+
+
+static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ char *buf, char *reply,
+ int reply_size,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ int reply_len, res;
+
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
@@ -1938,13 +2104,13 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
reply_size);
} else if (os_strcmp(buf, "ATTACH") == 0) {
- if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
+ if (hostapd_ctrl_iface_attach(hapd, from, fromlen))
reply_len = -1;
} else if (os_strcmp(buf, "DETACH") == 0) {
- if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
+ if (hostapd_ctrl_iface_detach(hapd, from, fromlen))
reply_len = -1;
} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
- if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
+ if (hostapd_ctrl_iface_level(hapd, from, fromlen,
buf + 6))
reply_len = -1;
} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
@@ -2079,6 +2245,11 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
reply_size);
+ } else if (os_strncmp(buf, "TEST_FAIL ", 10) == 0) {
+ if (hostapd_ctrl_test_fail(hapd, buf + 10) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "GET_FAIL") == 0) {
+ reply_len = hostapd_ctrl_get_fail(hapd, reply, reply_size);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -2091,6 +2262,20 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
#ifdef RADIUS_SERVER
radius_server_erp_flush(hapd->radius_srv);
#endif /* RADIUS_SERVER */
+ } else if (os_strncmp(buf, "EAPOL_REAUTH ", 13) == 0) {
+ if (hostapd_ctrl_iface_eapol_reauth(hapd, buf + 13))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "EAPOL_SET ", 10) == 0) {
+ if (hostapd_ctrl_iface_eapol_set(hapd, buf + 10))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
+ reply_len = hostapd_ctrl_iface_log_level(
+ hapd, buf + 9, reply, reply_size);
+#ifdef NEED_AP_MLME
+ } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) {
+ reply_len = hostapd_ctrl_iface_track_sta_list(
+ hapd, reply, reply_size);
+#endif /* NEED_AP_MLME */
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -2100,6 +2285,50 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
+
+ return reply_len;
+}
+
+
+static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ char buf[4096];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char *reply;
+ const int reply_size = 4096;
+ int reply_len;
+ int level = MSG_DEBUG;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+ strerror(errno));
+ return;
+ }
+ buf[res] = '\0';
+ if (os_strcmp(buf, "PING") == 0)
+ level = MSG_EXCESSIVE;
+ wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
+
+ reply = os_malloc(reply_size);
+ if (reply == NULL) {
+ if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
+ return;
+ }
+
+ reply_len = hostapd_ctrl_iface_receive_process(hapd, buf,
+ reply, reply_size,
+ &from, fromlen);
+
if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
fromlen) < 0) {
wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
@@ -2130,13 +2359,14 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
}
-static void hostapd_ctrl_iface_msg_cb(void *ctx, int level, int global,
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+ enum wpa_msg_type type,
const char *txt, size_t len)
{
struct hostapd_data *hapd = ctx;
if (hapd == NULL)
return;
- hostapd_ctrl_iface_send(hapd, level, txt, len);
+ hostapd_ctrl_iface_send(hapd, level, type, txt, len);
}
@@ -2359,6 +2589,58 @@ static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
}
+static int hostapd_global_ctrl_iface_attach(struct hapd_interfaces *interfaces,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ dst->next = interfaces->global_ctrl_dst;
+ interfaces->global_ctrl_dst = dst;
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached (global)",
+ from->sun_path,
+ fromlen - offsetof(struct sockaddr_un, sun_path));
+ return 0;
+}
+
+
+static int hostapd_global_ctrl_iface_detach(struct hapd_interfaces *interfaces,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst, *prev = NULL;
+
+ dst = interfaces->global_ctrl_dst;
+ while (dst) {
+ if (fromlen == dst->addrlen &&
+ os_memcmp(from->sun_path, dst->addr.sun_path,
+ fromlen - offsetof(struct sockaddr_un, sun_path))
+ == 0) {
+ wpa_hexdump(MSG_DEBUG,
+ "CTRL_IFACE monitor detached (global)",
+ from->sun_path,
+ fromlen -
+ offsetof(struct sockaddr_un, sun_path));
+ if (prev == NULL)
+ interfaces->global_ctrl_dst = dst->next;
+ else
+ prev->next = dst->next;
+ os_free(dst);
+ return 0;
+ }
+ prev = dst;
+ dst = dst->next;
+ }
+ return -1;
+}
+
+
static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
{
#ifdef CONFIG_WPS_TESTING
@@ -2369,6 +2651,214 @@ static void hostapd_ctrl_iface_flush(struct hapd_interfaces *interfaces)
}
+#ifdef CONFIG_FST
+
+static int
+hostapd_global_ctrl_iface_fst_attach(struct hapd_interfaces *interfaces,
+ const char *cmd)
+{
+ char ifname[IFNAMSIZ + 1];
+ struct fst_iface_cfg cfg;
+ struct hostapd_data *hapd;
+ struct fst_wpa_obj iface_obj;
+
+ if (!fst_parse_attach_command(cmd, ifname, sizeof(ifname), &cfg)) {
+ hapd = hostapd_get_iface(interfaces, ifname);
+ if (hapd) {
+ if (hapd->iface->fst) {
+ wpa_printf(MSG_INFO, "FST: Already attached");
+ return -1;
+ }
+ fst_hostapd_fill_iface_obj(hapd, &iface_obj);
+ hapd->iface->fst = fst_attach(ifname, hapd->own_addr,
+ &iface_obj, &cfg);
+ if (hapd->iface->fst)
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+
+static int
+hostapd_global_ctrl_iface_fst_detach(struct hapd_interfaces *interfaces,
+ const char *cmd)
+{
+ char ifname[IFNAMSIZ + 1];
+ struct hostapd_data * hapd;
+
+ if (!fst_parse_detach_command(cmd, ifname, sizeof(ifname))) {
+ hapd = hostapd_get_iface(interfaces, ifname);
+ if (hapd) {
+ if (!fst_iface_detach(ifname)) {
+ hapd->iface->fst = NULL;
+ hapd->iface->fst_ies = NULL;
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+#endif /* CONFIG_FST */
+
+
+static struct hostapd_data *
+hostapd_interfaces_get_hapd(struct hapd_interfaces *interfaces,
+ const char *ifname)
+{
+ size_t i, j;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_data *hapd;
+
+ hapd = iface->bss[j];
+ if (os_strcmp(ifname, hapd->conf->iface) == 0)
+ return hapd;
+ }
+ }
+
+ return NULL;
+}
+
+
+static int hostapd_ctrl_iface_dup_param(struct hostapd_data *src_hapd,
+ struct hostapd_data *dst_hapd,
+ const char *param)
+{
+ int res;
+ char *value;
+
+ value = os_zalloc(HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
+ if (!value) {
+ wpa_printf(MSG_ERROR,
+ "DUP: cannot allocate buffer to stringify %s",
+ param);
+ goto error_return;
+ }
+
+ if (os_strcmp(param, "wpa") == 0) {
+ os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%d",
+ src_hapd->conf->wpa);
+ } else if (os_strcmp(param, "wpa_key_mgmt") == 0 &&
+ src_hapd->conf->wpa_key_mgmt) {
+ res = hostapd_ctrl_iface_get_key_mgmt(
+ src_hapd, value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN);
+ if (os_snprintf_error(HOSTAPD_CLI_DUP_VALUE_MAX_LEN, res))
+ goto error_stringify;
+ } else if (os_strcmp(param, "wpa_pairwise") == 0 &&
+ src_hapd->conf->wpa_pairwise) {
+ res = wpa_write_ciphers(value,
+ value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
+ src_hapd->conf->wpa_pairwise, " ");
+ if (res < 0)
+ goto error_stringify;
+ } else if (os_strcmp(param, "rsn_pairwise") == 0 &&
+ src_hapd->conf->rsn_pairwise) {
+ res = wpa_write_ciphers(value,
+ value + HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
+ src_hapd->conf->rsn_pairwise, " ");
+ if (res < 0)
+ goto error_stringify;
+ } else if (os_strcmp(param, "wpa_passphrase") == 0 &&
+ src_hapd->conf->ssid.wpa_passphrase) {
+ os_snprintf(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN, "%s",
+ src_hapd->conf->ssid.wpa_passphrase);
+ } else if (os_strcmp(param, "wpa_psk") == 0 &&
+ src_hapd->conf->ssid.wpa_psk_set) {
+ wpa_snprintf_hex(value, HOSTAPD_CLI_DUP_VALUE_MAX_LEN,
+ src_hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
+ } else {
+ wpa_printf(MSG_WARNING, "DUP: %s cannot be duplicated", param);
+ goto error_return;
+ }
+
+ res = hostapd_set_iface(dst_hapd->iconf, dst_hapd->conf, param, value);
+ os_free(value);
+ return res;
+
+error_stringify:
+ wpa_printf(MSG_ERROR, "DUP: cannot stringify %s", param);
+error_return:
+ os_free(value);
+ return -1;
+}
+
+
+static int
+hostapd_global_ctrl_iface_dup_network(struct hapd_interfaces *interfaces,
+ char *cmd)
+{
+ char *p_start = cmd, *p_end;
+ struct hostapd_data *src_hapd, *dst_hapd;
+
+ /* cmd: "<src ifname> <dst ifname> <variable name> */
+
+ p_end = os_strchr(p_start, ' ');
+ if (!p_end) {
+ wpa_printf(MSG_ERROR, "DUP: no src ifname found in cmd: '%s'",
+ cmd);
+ return -1;
+ }
+
+ *p_end = '\0';
+ src_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
+ if (!src_hapd) {
+ wpa_printf(MSG_ERROR, "DUP: no src ifname found: '%s'",
+ p_start);
+ return -1;
+ }
+
+ p_start = p_end + 1;
+ p_end = os_strchr(p_start, ' ');
+ if (!p_end) {
+ wpa_printf(MSG_ERROR, "DUP: no dst ifname found in cmd: '%s'",
+ cmd);
+ return -1;
+ }
+
+ *p_end = '\0';
+ dst_hapd = hostapd_interfaces_get_hapd(interfaces, p_start);
+ if (!dst_hapd) {
+ wpa_printf(MSG_ERROR, "DUP: no dst ifname found: '%s'",
+ p_start);
+ return -1;
+ }
+
+ p_start = p_end + 1;
+ return hostapd_ctrl_iface_dup_param(src_hapd, dst_hapd, p_start);
+}
+
+
+static int hostapd_global_ctrl_iface_ifname(struct hapd_interfaces *interfaces,
+ const char *ifname,
+ char *buf, char *reply,
+ int reply_size,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct hostapd_data *hapd;
+
+ hapd = hostapd_interfaces_get_hapd(interfaces, ifname);
+ if (hapd == NULL) {
+ int res;
+
+ res = os_snprintf(reply, reply_size, "FAIL-NO-IFNAME-MATCH\n");
+ if (os_snprintf_error(reply_size, res))
+ return -1;
+ return res;
+ }
+
+ return hostapd_ctrl_iface_receive_process(hapd, buf, reply,reply_size,
+ from, fromlen);
+}
+
+
static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -2377,8 +2867,9 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
int res;
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
- char reply[24];
+ char *reply;
int reply_len;
+ const int reply_size = 4096;
res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
(struct sockaddr *) &from, &fromlen);
@@ -2390,9 +2881,31 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
buf[res] = '\0';
wpa_printf(MSG_DEBUG, "Global ctrl_iface command: %s", buf);
+ reply = os_malloc(reply_size);
+ if (reply == NULL) {
+ if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+ strerror(errno));
+ }
+ return;
+ }
+
os_memcpy(reply, "OK\n", 3);
reply_len = 3;
+ if (os_strncmp(buf, "IFNAME=", 7) == 0) {
+ char *pos = os_strchr(buf + 7, ' ');
+
+ if (pos) {
+ *pos++ = '\0';
+ reply_len = hostapd_global_ctrl_iface_ifname(
+ interfaces, buf + 7, pos, reply, reply_size,
+ &from, fromlen);
+ goto send_reply;
+ }
+ }
+
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
@@ -2407,18 +2920,47 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
reply_len = -1;
+ } else if (os_strcmp(buf, "ATTACH") == 0) {
+ if (hostapd_global_ctrl_iface_attach(interfaces, &from,
+ fromlen))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "DETACH") == 0) {
+ if (hostapd_global_ctrl_iface_detach(interfaces, &from,
+ fromlen))
+ reply_len = -1;
#ifdef CONFIG_MODULE_TESTS
} else if (os_strcmp(buf, "MODULE_TESTS") == 0) {
int hapd_module_tests(void);
if (hapd_module_tests() < 0)
reply_len = -1;
#endif /* CONFIG_MODULE_TESTS */
+#ifdef CONFIG_FST
+ } else if (os_strncmp(buf, "FST-ATTACH ", 11) == 0) {
+ if (!hostapd_global_ctrl_iface_fst_attach(interfaces, buf + 11))
+ reply_len = os_snprintf(reply, reply_size, "OK\n");
+ else
+ reply_len = -1;
+ } else if (os_strncmp(buf, "FST-DETACH ", 11) == 0) {
+ if (!hostapd_global_ctrl_iface_fst_detach(interfaces, buf + 11))
+ reply_len = os_snprintf(reply, reply_size, "OK\n");
+ else
+ reply_len = -1;
+ } else if (os_strncmp(buf, "FST-MANAGER ", 12) == 0) {
+ reply_len = fst_ctrl_iface_receive(buf + 12, reply, reply_size);
+#endif /* CONFIG_FST */
+ } else if (os_strncmp(buf, "DUP_NETWORK ", 12) == 0) {
+ if (!hostapd_global_ctrl_iface_dup_network(interfaces,
+ buf + 12))
+ reply_len = os_snprintf(reply, reply_size, "OK\n");
+ else
+ reply_len = -1;
} else {
wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
"ignored");
reply_len = -1;
}
+send_reply:
if (reply_len < 0) {
os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
@@ -2429,6 +2971,7 @@ static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
strerror(errno));
}
+ os_free(reply);
}
@@ -2566,6 +3109,7 @@ fail:
void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
{
char *fname = NULL;
+ struct wpa_ctrl_dst *dst, *prev;
if (interfaces->global_ctrl_sock > -1) {
eloop_unregister_read_sock(interfaces->global_ctrl_sock);
@@ -2590,13 +3134,23 @@ void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
strerror(errno));
}
}
- os_free(interfaces->global_iface_path);
- interfaces->global_iface_path = NULL;
+ }
+
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = NULL;
+
+ dst = interfaces->global_ctrl_dst;
+ interfaces->global_ctrl_dst = NULL;
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ os_free(prev);
}
}
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+ enum wpa_msg_type type,
const char *buf, size_t len)
{
struct wpa_ctrl_dst *dst, *next;
@@ -2604,9 +3158,17 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
int idx;
struct iovec io[2];
char levelstr[10];
+ int s;
- dst = hapd->ctrl_dst;
- if (hapd->ctrl_sock < 0 || dst == NULL)
+ if (type != WPA_MSG_ONLY_GLOBAL) {
+ s = hapd->ctrl_sock;
+ dst = hapd->ctrl_dst;
+ } else {
+ s = hapd->iface->interfaces->global_ctrl_sock;
+ dst = hapd->iface->interfaces->global_ctrl_dst;
+ }
+
+ if (s < 0 || dst == NULL)
return;
os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
@@ -2627,16 +3189,22 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
offsetof(struct sockaddr_un, sun_path));
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
- if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
+ if (sendmsg(s, &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) {
- hostapd_ctrl_iface_detach(
- hapd, &dst->addr,
- dst->addrlen);
+ 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);
}
} else
dst->errors = 0;
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 4cde2b563483..430f7584b167 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -240,6 +240,12 @@ CONFIG_IPV6=y
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
+# 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
+
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
@@ -283,6 +289,12 @@ CONFIG_IPV6=y
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
+# Enable Fast Session Transfer (FST)
+#CONFIG_FST=y
+
+# Enable CLI commands for FST testing
+#CONFIG_FST_TEST=y
+
# Testing options
# This can be used to enable some testing options (see also the example
# configuration file) that are really useful only for testing clients that
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 42d59dba7ede..84d0308262e6 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -87,6 +87,7 @@ struct milenage_parameters {
u8 amf[2];
u8 sqn[6];
int set;
+ size_t res_len;
};
static struct milenage_parameters *milenage_db = NULL;
@@ -96,6 +97,7 @@ static struct milenage_parameters *milenage_db = NULL;
#define EAP_AKA_RAND_LEN 16
#define EAP_AKA_AUTN_LEN 16
#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MIN_LEN 4
#define EAP_AKA_RES_MAX_LEN 16
#define EAP_AKA_IK_LEN 16
#define EAP_AKA_CK_LEN 16
@@ -124,7 +126,8 @@ static int db_table_create_milenage(sqlite3 *db)
" ki CHAR(32) NOT NULL,"
" opc CHAR(32) NOT NULL,"
" amf CHAR(4) NOT NULL,"
- " sqn CHAR(12) NOT NULL"
+ " sqn CHAR(12) NOT NULL,"
+ " res_len INTEGER"
");";
printf("Adding database table for milenage information\n");
@@ -190,6 +193,10 @@ static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
printf("Invalid sqn value in database\n");
return -1;
}
+
+ if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
+ m->res_len = atoi(argv[i]);
+ }
}
return 0;
@@ -206,8 +213,7 @@ static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
"%llu", imsi);
os_snprintf(cmd, sizeof(cmd),
- "SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
- imsi);
+ "SELECT * FROM milenage WHERE imsi=%llu;", imsi);
if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
NULL) != SQLITE_OK)
return NULL;
@@ -424,7 +430,7 @@ static int read_milenage(const char *fname)
while (fgets(buf, sizeof(buf), f)) {
line++;
- /* Parse IMSI Ki OPc AMF SQN */
+ /* Parse IMSI Ki OPc AMF SQN [RES_len] */
buf[sizeof(buf) - 1] = '\0';
if (buf[0] == '#')
continue;
@@ -515,7 +521,19 @@ static int read_milenage(const char *fname)
ret = -1;
break;
}
- pos = pos2 + 1;
+
+ if (pos2) {
+ pos = pos2 + 1;
+ m->res_len = atoi(pos);
+ if (m->res_len &&
+ (m->res_len < EAP_AKA_RES_MIN_LEN ||
+ m->res_len > EAP_AKA_RES_MAX_LEN)) {
+ printf("%s:%d - Invalid RES_len (%s)\n",
+ fname, line, pos);
+ ret = -1;
+ break;
+ }
+ }
m->next = milenage_db;
milenage_db = m;
@@ -532,7 +550,7 @@ static int read_milenage(const char *fname)
static void update_milenage_file(const char *fname)
{
FILE *f, *f2;
- char buf[500], *pos;
+ char name[500], buf[500], *pos;
char *end = buf + sizeof(buf);
struct milenage_parameters *m;
size_t imsi_len;
@@ -543,10 +561,10 @@ static void update_milenage_file(const char *fname)
return;
}
- snprintf(buf, sizeof(buf), "%s.new", fname);
- f2 = fopen(buf, "w");
+ snprintf(name, sizeof(name), "%s.new", fname);
+ f2 = fopen(name, "w");
if (f2 == NULL) {
- printf("Could not write Milenage data file '%s'\n", buf);
+ printf("Could not write Milenage data file '%s'\n", name);
fclose(f);
return;
}
@@ -588,14 +606,14 @@ static void update_milenage_file(const char *fname)
fclose(f2);
fclose(f);
- snprintf(buf, sizeof(buf), "%s.bak", fname);
- if (rename(fname, buf) < 0) {
+ snprintf(name, sizeof(name), "%s.bak", fname);
+ if (rename(fname, name) < 0) {
perror("rename");
return;
}
- snprintf(buf, sizeof(buf), "%s.new", fname);
- if (rename(buf, fname) < 0) {
+ snprintf(name, sizeof(name), "%s.new", fname);
+ if (rename(name, fname) < 0) {
perror("rename");
return;
}
@@ -798,6 +816,10 @@ static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
}
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
autn, ik, ck, res, &res_len);
+ if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
+ m->res_len <= EAP_AKA_RES_MAX_LEN &&
+ m->res_len < res_len)
+ res_len = m->res_len;
} else {
printf("Unknown IMSI: %s\n", imsi);
#ifdef AKA_USE_FIXED_TEST_VALUES
diff --git a/hostapd/hlr_auc_gw.milenage_db b/hostapd/hlr_auc_gw.milenage_db
index ecd06d72096d..c156a29aeda0 100644
--- a/hostapd/hlr_auc_gw.milenage_db
+++ b/hostapd/hlr_auc_gw.milenage_db
@@ -5,8 +5,10 @@
# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
# dummy values will need to be included in this file.
-# IMSI Ki OPc AMF SQN
+# IMSI Ki OPc AMF SQN [RES_len]
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+# Example using truncated 32-bit RES instead of 64-bit default
+232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4
# These values are from Test Set 19 which has the AMF separation bit set to 1
# and as such, is suitable for EAP-AKA' test.
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 9e81e9e98683..a0071f7d82c4 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -127,7 +127,9 @@ ssid=test
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
-# specify band)
+# specify band). 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.
# Default: IEEE 802.11b
hw_mode=g
@@ -170,8 +172,11 @@ channel=1
# Channel list restriction. This option allows hostapd to select one of the
# provided channels when a channel should be automatically selected.
-# Default: not set (allow any enabled channel to be selected)
+# Channel list can be provided as range using hyphen ('-') or individual
+# channels can be specified by space (' ') seperated values
+# Default: all channels allowed in selected hw_mode
#chanlist=100 104 108 112 116
+#chanlist=1 6 11-13
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@@ -275,8 +280,9 @@ ignore_broadcast_ssid=0
# (data0 is the highest priority queue)
# parameters:
# aifs: AIFS (default 2)
-# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
-# cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
+# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191,
+# 16383, 32767)
+# cwmax: cwMax (same values as cwMin, cwMax >= cwMin)
# burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
# bursting
#
@@ -337,8 +343,9 @@ ignore_broadcast_ssid=0
# note - txop_limit is in units of 32microseconds
# note - acm is admission control mandatory flag. 0 = admission control not
# required, 1 = mandatory
-# note - here cwMin and cmMax are in exponent form. the actual cw value used
-# will be (2^n)-1 where n is the value given here
+# note - Here cwMin and cmMax are in exponent form. The actual cw value used
+# will be (2^n)-1 where n is the value given here. The allowed range for these
+# wmm_ac_??_{cwmin,cwmax} is 0..15 with cwmax >= cwmin.
#
wmm_enabled=1
#
@@ -575,14 +582,16 @@ wmm_ac_vo_acm=0
# 0 = Not supported (default)
# 1 = Supported
#
-# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
+# Compressed Steering Number of Beamformer Antennas Supported:
+# [BF-ANTENNA-2] [BF-ANTENNA-3] [BF-ANTENNA-4]
# Beamformee's capability indicating the maximum number of beamformer
# antennas the beamformee can support when sending compressed beamforming
# feedback
# If SU beamformer capable, set to maximum value minus 1
# else reserved (default)
#
-# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
+# Number of Sounding Dimensions:
+# [SOUNDING-DIMENSION-2] [SOUNDING-DIMENSION-3] [SOUNDING-DIMENSION-4]
# Beamformer's capability indicating the maximum value of the NUM_STS parameter
# in the TXVECTOR of a VHT NDP
# If SU beamformer capable, set to maximum value minus 1
@@ -593,11 +602,6 @@ wmm_ac_vo_acm=0
# 0 = Not supported or sent by Non-AP STA (default)
# 1 = Supported
#
-# MU Beamformee Capable: [MU-BEAMFORMEE]
-# Indicates support for operation as an MU beamformee
-# 0 = Not supported or sent by AP (default)
-# 1 = Supported
-#
# VHT TXOP PS: [VHT-TXOP-PS]
# Indicates whether or not the AP supports VHT TXOP Power Save Mode
# or whether or not the STA is in VHT TXOP Power Save mode
@@ -764,6 +768,12 @@ eap_server=0
# 2 = check all CRLs in the certificate path
#check_crl=1
+# TLS Session Lifetime in seconds
+# This can be used to allow TLS sessions to be cached and resumed with an
+# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
+# (default: 0 = session caching and resumption disabled)
+#tls_session_lifetime=3600
+
# 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.
@@ -787,7 +797,7 @@ eap_server=0
# is in DSA parameters format, it will be automatically converted into DH
# params. This parameter is required if anonymous EAP-FAST is used.
# You can generate DH parameters file with OpenSSL, e.g.,
-# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
+# "openssl dhparam -out /etc/hostapd.dh.pem 2048"
#dh_file=/etc/hostapd.dh.pem
# OpenSSL cipher string
@@ -1247,6 +1257,11 @@ own_ip_addr=127.0.0.1
# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
#pmk_r1_push=1
+# Whether to enable FT-over-DS
+# 0 = FT-over-DS disabled
+# 1 = FT-over-DS enabled (default)
+#ft_over_ds=1
+
##### Neighbor table ##########################################################
# Maximum number of entries kept in AP table (either for neigbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
@@ -1264,6 +1279,43 @@ own_ip_addr=127.0.0.1
# default: 60
#ap_table_expiration_time=3600
+# Maximum number of stations to track on the operating channel
+# This can be used to detect dualband capable stations before they have
+# associated, e.g., to provide guidance on which colocated BSS to use.
+# Default: 0 (disabled)
+#track_sta_max_num=100
+
+# Maximum age of a station tracking entry in seconds
+# Default: 180
+#track_sta_max_age=180
+
+# Do not reply to group-addressed Probe Request from a station that was seen on
+# another radio.
+# Default: Disabled
+#
+# This can be used with enabled track_sta_max_num configuration on another
+# interface controlled by the same hostapd process to restrict Probe Request
+# frame handling from replying to group-addressed Probe Request frames from a
+# station that has been detected to be capable of operating on another band,
+# e.g., to try to reduce likelihood of the station selecting a 2.4 GHz BSS when
+# the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
+#
+# Note: Enabling this can cause connectivity issues and increase latency for
+# discovering the AP.
+#no_probe_resp_if_seen_on=wlan1
+
+# Reject authentication from a station that was seen on another radio.
+# Default: Disabled
+#
+# This can be used with enabled track_sta_max_num configuration on another
+# interface controlled by the same hostapd process to reject authentication
+# attempts from a station that has been detected to be capable of operating on
+# another band, e.g., to try to reduce likelihood of the station selecting a
+# 2.4 GHz BSS when the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
+#
+# Note: Enabling this can cause connectivity issues and increase latency for
+# connecting with the AP.
+#no_auth_if_seen_on=wlan1
##### Wi-Fi Protected Setup (WPS) #############################################
@@ -1430,7 +1482,7 @@ own_ip_addr=127.0.0.1
# 12-digit, all-numeric code that identifies the consumer package.
#upc=123456789012
-# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band, ad = 60 GHz)
# This value should be set according to RF band(s) supported by the AP if
# hw_mode is not set. For dual band dual concurrent devices, this needs to be
# set to ag to allow both RF bands to be advertized.
@@ -1490,6 +1542,13 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#proxy_arp=1
+# IPv6 Neighbor Advertisement multicast-to-unicast conversion
+# This can be used with Proxy ARP to allow multicast NAs to be forwarded to
+# associated STAs using link layer unicast delivery.
+# 0 = disabled (default)
+# 1 = enabled
+#na_mcast_to_ucast=0
+
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
@@ -1738,6 +1797,32 @@ own_ip_addr=127.0.0.1
#
#osu_server_uri=...
+##### Fast Session Transfer (FST) support #####################################
+#
+# The options in this section are only available when the build configuration
+# option CONFIG_FST is set while compiling hostapd. They allow this interface
+# to be a part of FST setup.
+#
+# FST is the transfer of a session from a channel to another channel, in the
+# same or different frequency bands.
+#
+# For detals, see IEEE Std 802.11ad-2012.
+
+# Identifier of an FST Group the interface belongs to.
+#fst_group_id=bond0
+
+# Interface priority within the FST Group.
+# Announcing a higher priority for an interface means declaring it more
+# preferable for FST switch.
+# fst_priority is in 1..255 range with 1 being the lowest priority.
+#fst_priority=100
+
+# Default LLT value for this interface in milliseconds. The value used in case
+# no value provided during session setup. Default is 50 ms.
+# fst_llt is in 1..4294967 range (due to spec limitation, see 10.32.2.2
+# Transitioning between states).
+#fst_llt=100
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 3f00cbbf0cc7..46c2f37e4601 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -10,22 +10,23 @@
#include <dirent.h>
#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/edit.h"
#include "common/version.h"
-static const char *hostapd_cli_version =
+static const char *const hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
-static const char *hostapd_cli_license =
+static const char *const hostapd_cli_license =
"This software may be distributed under the terms of the BSD license.\n"
"See README for more details.\n";
-static const char *hostapd_cli_full_license =
+static const char *const hostapd_cli_full_license =
"This software may be distributed under the terms of the BSD license.\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
@@ -56,7 +57,7 @@ static const char *hostapd_cli_full_license =
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n";
-static const char *commands_help =
+static const char *const commands_help =
"Commands:\n"
" mib get MIB variables (dot1x, dot11, radius)\n"
" sta <addr> get MIB variables for one station\n"
@@ -96,6 +97,7 @@ static int hostapd_cli_attached = 0;
#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
#endif /* CONFIG_CTRL_IFACE_DIR */
static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
+static const char *client_socket_dir = NULL;
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
@@ -111,13 +113,15 @@ static void usage(void)
"\n"
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
"[-a<path>] \\\n"
- " [-G<ping interval>] [command..]\n"
+ " [-P<pid file>] [-G<ping interval>] [command..]\n"
"\n"
"Options:\n"
" -h help (show this usage text)\n"
" -v shown version information\n"
" -p<path> path to find control sockets (default: "
"/var/run/hostapd)\n"
+ " -s<dir_path> dir path to open client sockets (default: "
+ CONFIG_CTRL_IFACE_DIR ")\n"
" -a<file> run in daemon mode executing the action file "
"based on events\n"
" from hostapd\n"
@@ -144,7 +148,14 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
return NULL;
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
- ctrl_conn = wpa_ctrl_open(cfile);
+ if (client_socket_dir && client_socket_dir[0] &&
+ access(client_socket_dir, F_OK) < 0) {
+ perror(client_socket_dir);
+ free(cfile);
+ return NULL;
+ }
+
+ ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
free(cfile);
return ctrl_conn;
}
@@ -541,7 +552,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[256];
- char ssid_hex[2 * 32 + 1];
+ char ssid_hex[2 * SSID_MAX_LEN + 1];
char key_hex[2 * 64 + 1];
int i;
@@ -552,7 +563,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
}
ssid_hex[0] = '\0';
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < SSID_MAX_LEN; i++) {
if (argv[0][i] == '\0')
break;
os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
@@ -921,6 +932,35 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+#ifdef CONFIG_FST
+static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+ int i;
+ int total;
+
+ if (argc <= 0) {
+ printf("FST command: parameters are required.\n");
+ return -1;
+ }
+
+ total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
+
+ for (i = 0; i < argc; i++) {
+ res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
+ argv[i]);
+ if (os_snprintf_error(sizeof(cmd) - total, res)) {
+ printf("Too long fst command.\n");
+ return -1;
+ }
+ total += res;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_FST */
+
+
static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
@@ -1009,12 +1049,31 @@ static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
}
+static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
+ argc >= 1 ? " " : "",
+ argc >= 1 ? argv[0] : "",
+ argc == 2 ? " " : "",
+ argc == 2 ? argv[1] : "");
+ if (os_snprintf_error(sizeof(cmd), res)) {
+ printf("Too long option\n");
+ return -1;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
};
-static struct hostapd_cli_cmd hostapd_cli_commands[] = {
+static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "ping", hostapd_cli_cmd_ping },
{ "mib", hostapd_cli_cmd_mib },
{ "relog", hostapd_cli_cmd_relog },
@@ -1048,6 +1107,9 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "get_config", hostapd_cli_cmd_get_config },
{ "help", hostapd_cli_cmd_help },
{ "interface", hostapd_cli_cmd_interface },
+#ifdef CONFIG_FST
+ { "fst", hostapd_cli_cmd_fst },
+#endif /* CONFIG_FST */
{ "level", hostapd_cli_cmd_level },
{ "license", hostapd_cli_cmd_license },
{ "quit", hostapd_cli_cmd_quit },
@@ -1063,13 +1125,14 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "reload", hostapd_cli_cmd_reload },
{ "disable", hostapd_cli_cmd_disable },
{ "erp_flush", hostapd_cli_cmd_erp_flush },
+ { "log_level", hostapd_cli_cmd_log_level },
{ NULL, NULL }
};
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- struct hostapd_cli_cmd *cmd, *match = NULL;
+ const struct hostapd_cli_cmd *cmd, *match = NULL;
int count;
count = 0;
@@ -1284,7 +1347,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
- c = getopt(argc, argv, "a:BhG:i:p:v");
+ c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
if (c < 0)
break;
switch (c) {
@@ -1310,6 +1373,12 @@ int main(int argc, char *argv[])
case 'p':
ctrl_iface_dir = optarg;
break;
+ case 'P':
+ pid_file = optarg;
+ break;
+ case 's':
+ client_socket_dir = optarg;
+ break;
default:
usage();
return -1;
diff --git a/hostapd/main.c b/hostapd/main.c
index dd389a8d66a3..6c7406af447e 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -24,6 +24,7 @@
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
+#include "fst/fst.h"
#include "config_file.h"
#include "eap_register.h"
#include "ctrl_iface.h"
@@ -533,6 +534,28 @@ static int gen_uuid(const char *txt_addr)
#endif /* CONFIG_WPS */
+#ifndef HOSTAPD_CLEANUP_INTERVAL
+#define HOSTAPD_CLEANUP_INTERVAL 10
+#endif /* HOSTAPD_CLEANUP_INTERVAL */
+
+static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
+{
+ hostapd_periodic_iface(iface);
+ return 0;
+}
+
+
+/* Periodic cleanup tasks */
+static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hapd_interfaces *interfaces = eloop_ctx;
+
+ eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
+ hostapd_periodic, interfaces, NULL);
+ hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL);
+}
+
+
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
@@ -561,6 +584,7 @@ int main(int argc, char *argv[])
interfaces.global_iface_path = NULL;
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
+ interfaces.global_ctrl_dst = NULL;
for (;;) {
c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
@@ -661,10 +685,24 @@ int main(int argc, char *argv[])
}
if (hostapd_global_init(&interfaces, entropy_file)) {
- wpa_printf(MSG_ERROR, "Failed to initilize global context");
+ wpa_printf(MSG_ERROR, "Failed to initialize global context");
return -1;
}
+ eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
+ hostapd_periodic, &interfaces, NULL);
+
+ if (fst_global_init()) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize global FST context");
+ goto out;
+ }
+
+#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
+ if (!fst_global_add_ctrl(fst_ctrl_cli))
+ wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
+#endif /* CONFIG_FST && CONFIG_CTRL_IFACE */
+
/* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
interfaces.iface[i] = hostapd_interface_init(&interfaces,
@@ -749,6 +787,7 @@ int main(int argc, char *argv[])
}
os_free(interfaces.iface);
+ eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
hostapd_global_deinit(pid_file);
os_free(pid_file);
@@ -758,6 +797,8 @@ int main(int argc, char *argv[])
os_free(bss_config);
+ fst_global_deinit();
+
os_program_deinit();
return ret;
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index ca67b54da2ee..94cd5f14df14 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -67,7 +67,13 @@ OBJS += ../../src/crypto/sha256-internal.o
CFLAGS += $(shell xml2-config --cflags)
LIBS += $(shell xml2-config --libs)
+
+# Allow static/custom linking of libcurl.
+ifdef CUST_CURL_LINKAGE
+LIBS += ${CUST_CURL_LINKAGE}
+else
LIBS += -lcurl
+endif
CFLAGS += -DEAP_TLS_OPENSSL
LIBS += -lssl -lcrypto
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index de7f351da244..0315f7b75ad4 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -25,6 +25,8 @@
#include "crypto/sha256.h"
#include "osu_client.h"
+const char *spp_xsd_fname = "spp.xsd";
+
void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
{
@@ -540,6 +542,7 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
uri);
write_result(ctx, "Unsupported location for addMO to "
"add PPS MO (extra directory): '%s'", uri);
+ free(fqdn);
return -1;
}
*pos = '\0'; /* remove trailing slash and PPS node name */
@@ -547,8 +550,9 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn);
if (!server_dnsname_suffix_match(ctx, fqdn)) {
- wpa_printf(MSG_INFO, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
- fqdn);
+ wpa_printf(MSG_INFO,
+ "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d",
+ fqdn, (int) ctx->server_dnsname_count);
write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
fqdn);
free(fqdn);
@@ -2094,10 +2098,14 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
}
ctx->no_reconnect = 1;
- if (methods & 0x02)
+ if (methods & 0x02) {
+ wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect");
res = cmd_prov(ctx, url);
- else if (methods & 0x01)
+ } else if (methods & 0x01) {
+ wpa_printf(MSG_DEBUG,
+ "Calling cmd_oma_dm_prov from osu_connect");
res = cmd_oma_dm_prov(ctx, url);
+ }
wpa_printf(MSG_INFO, "Remove OSU network connection");
write_summary(ctx, "Remove OSU network connection");
@@ -2139,7 +2147,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir);
osu = parse_osu_providers(fname, &osu_count);
if (osu == NULL) {
- wpa_printf(MSG_INFO, "Could not any OSU providers from %s",
+ wpa_printf(MSG_INFO, "Could not find any OSU providers from %s",
fname);
write_result(ctx, "No OSU providers available");
return -1;
@@ -2290,12 +2298,19 @@ selected:
}
if (connect == 2) {
- if (last->methods & 0x02)
+ if (last->methods & 0x02) {
+ wpa_printf(MSG_DEBUG,
+ "Calling cmd_prov from cmd_osu_select");
ret = cmd_prov(ctx, last->url);
- else if (last->methods & 0x01)
+ } else if (last->methods & 0x01) {
+ wpa_printf(MSG_DEBUG,
+ "Calling cmd_oma_dm_prov from cmd_osu_select");
ret = cmd_oma_dm_prov(ctx, last->url);
- else
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "No supported OSU provisioning method");
ret = -1;
+ }
} else if (connect)
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
last->url, last->methods,
@@ -2690,7 +2705,7 @@ static char * get_hostname(const char *url)
end = os_strchr(pos, '/');
end2 = os_strchr(pos, ':');
- if (end && end2 && end2 < end)
+ if ((end && end2 && end2 < end) || (!end && end2))
end = end2;
if (end)
end--;
@@ -2720,8 +2735,8 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
int found;
char *host = NULL;
- wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d)",
- !ctx->no_osu_cert_validation);
+ wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)",
+ !ctx->no_osu_cert_validation, ctx->server_url);
host = get_hostname(ctx->server_url);
@@ -2810,17 +2825,21 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
char *name = ctx->icon_filename[j];
size_t name_len = os_strlen(name);
- wpa_printf(MSG_INFO, "Looking for icon file name '%s' match",
- name);
+ wpa_printf(MSG_INFO,
+ "[%i] Looking for icon file name '%s' match",
+ j, name);
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
size_t uri_len = os_strlen(logo->uri);
char *pos;
- wpa_printf(MSG_INFO, "Comparing to '%s' uri_len=%d name_len=%d",
- logo->uri, (int) uri_len, (int) name_len);
- if (uri_len < 1 + name_len)
+ wpa_printf(MSG_INFO,
+ "[%i] 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");
continue;
+ }
pos = &logo->uri[uri_len - name_len - 1];
if (*pos != '/')
continue;
@@ -2847,17 +2866,30 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
- if (logo->hash_len != 32)
+ if (logo->hash_len != 32) {
+ wpa_printf(MSG_INFO,
+ "[%i][%i] Icon hash length invalid (should be 32): %d",
+ j, i, (int) logo->hash_len);
continue;
+ }
if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
found = 1;
break;
}
+
+ wpa_printf(MSG_DEBUG,
+ "[%u][%u] 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]",
+ ctx->icon_hash[j], 32);
}
if (!found) {
- wpa_printf(MSG_INFO, "No icon hash match found");
- write_result(ctx, "No icon hash match found");
+ wpa_printf(MSG_INFO,
+ "No icon hash match (by hash) found");
+ write_result(ctx,
+ "No icon hash match (by hash) found");
return -1;
}
}
@@ -2955,6 +2987,7 @@ static void usage(void)
" [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n"
+ " [-x<spp.xsd file name>] \\\n"
" <command> [arguments..]\n"
"commands:\n"
"- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n"
@@ -2996,7 +3029,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hi:KNO:qr:s:S:tw:");
+ c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
if (c < 0)
break;
switch (c) {
@@ -3034,6 +3067,9 @@ int main(int argc, char *argv[])
case 'w':
wpas_ctrl_path = optarg;
break;
+ case 'x':
+ spp_xsd_fname = optarg;
+ break;
case 'h':
default:
usage();
@@ -3108,6 +3144,7 @@ int main(int argc, char *argv[])
exit(0);
}
ctx.ca_fname = argv[optind + 2];
+ wpa_printf(MSG_DEBUG, "Calling cmd_prov from main");
cmd_prov(&ctx, argv[optind + 1]);
} else if (strcmp(argv[optind], "sim_prov") == 0) {
if (argc - optind < 2) {
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index 302a05040df6..c619541ae286 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -21,6 +21,8 @@
#include "osu_client.h"
+extern const char *spp_xsd_fname;
+
static int hs20_spp_update_response(struct hs20_osu_client *ctx,
const char *session_id,
const char *spp_status,
@@ -59,7 +61,7 @@ static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
return -1;
}
- ret = xml_validate(xctx, node, "spp.xsd", &err);
+ ret = xml_validate(xctx, node, spp_xsd_fname, &err);
if (ret < 0) {
wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
write_summary(ctx, "SPP XML schema validation failed");
@@ -77,9 +79,14 @@ static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
xml_node_t *fnode, *tnds;
char *str;
+ errno = 0;
fnode = node_from_file(ctx, fname);
- if (!fnode)
+ if (!fnode) {
+ wpa_printf(MSG_ERROR,
+ "Failed to create XML node from file: %s, possible error: %s",
+ fname, strerror(errno));
return;
+ }
tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
xml_node_free(ctx, fnode);
if (!tnds)
@@ -952,7 +959,9 @@ int cmd_prov(struct hs20_osu_client *ctx, const char *url)
return -1;
}
- wpa_printf(MSG_INFO, "Credential provisioning requested");
+ wpa_printf(MSG_INFO,
+ "Credential provisioning requested - URL: %s ca_fname: %s",
+ url, ctx->ca_fname ? ctx->ca_fname : "N/A");
os_free(ctx->server_url);
ctx->server_url = os_strdup(url);
diff --git a/patches/openssl-0.9.8zf-tls-extensions.patch b/patches/openssl-0.9.8zf-tls-extensions.patch
new file mode 100644
index 000000000000..3a8f90e40ce2
--- /dev/null
+++ b/patches/openssl-0.9.8zf-tls-extensions.patch
@@ -0,0 +1,398 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8zf does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
+--- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/s3_clnt.c 2015-03-24 16:19:14.043911769 +0200
+@@ -760,6 +760,23 @@ int ssl3_get_server_hello(SSL *s)
+ goto f_err;
+ }
+
++#ifndef OPENSSL_NO_TLSEXT
++ /* check if we want to resume the session based on external pre-shared secret */
++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
++ SSL_CIPHER *pref_cipher = NULL;
++
++ s->session->master_key_length = sizeof(s->session->master_key);
++ if (s->tls_session_secret_cb(s, s->session->master_key,
++ &s->session->master_key_length,
++ NULL, &pref_cipher,
++ s->tls_session_secret_cb_arg)) {
++ s->session->cipher = pref_cipher ?
++ pref_cipher : ssl_get_cipher_by_char(s, p + j);
++ s->s3->flags |= SSL3_FLAGS_CCS_OK;
++ }
++ }
++#endif /* OPENSSL_NO_TLSEXT */
++
+ if (j != 0 && j == s->session->session_id_length
+ && memcmp(p, s->session->session_id, j) == 0) {
+ if (s->sid_ctx_length != s->session->sid_ctx_length
+@@ -2684,12 +2701,8 @@ int ssl3_check_finished(SSL *s)
+ {
+ int ok;
+ long n;
+- /*
+- * If we have no ticket or session ID is non-zero length (a match of a
+- * non-zero session length would never reach here) it cannot be a resumed
+- * session.
+- */
+- if (!s->session->tlsext_tick || s->session->session_id_length)
++ /* If we have no ticket it cannot be a resumed session. */
++ if (!s->session->tlsext_tick)
+ return 1;
+ /*
+ * this function is called when we really expect a Certificate message,
+diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
+--- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/s3_srvr.c 2015-03-24 16:23:34.567909681 +0200
+@@ -999,6 +999,59 @@ int ssl3_get_client_hello(SSL *s)
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
+ goto err;
+ }
++
++ /* Check if we want to use external pre-shared secret for this
++ * handshake for not reused session only. We need to generate
++ * server_random before calling tls_session_secret_cb in order to allow
++ * SessionTicket processing to use it in key derivation. */
++ {
++ unsigned long Time;
++ unsigned char *pos;
++ Time = (unsigned long)time(NULL); /* Time */
++ pos = s->s3->server_random;
++ l2n(Time, pos);
++ if (RAND_pseudo_bytes(pos, SSL3_RANDOM_SIZE - 4) <= 0) {
++ al = SSL_AD_INTERNAL_ERROR;
++ goto f_err;
++ }
++ }
++
++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
++ SSL_CIPHER *pref_cipher = NULL;
++
++ s->session->master_key_length = sizeof(s->session->master_key);
++ if (s->tls_session_secret_cb(s, s->session->master_key,
++ &s->session->master_key_length,
++ ciphers, &pref_cipher,
++ s->tls_session_secret_cb_arg)) {
++ s->hit = 1;
++ s->session->ciphers = ciphers;
++ s->session->verify_result = X509_V_OK;
++
++ ciphers = NULL;
++
++ /* check if some cipher was preferred by call back */
++ pref_cipher = pref_cipher ? pref_cipher :
++ ssl3_choose_cipher(s, s->session->ciphers,
++ SSL_get_ciphers(s));
++ if (pref_cipher == NULL) {
++ al = SSL_AD_HANDSHAKE_FAILURE;
++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
++ goto f_err;
++ }
++
++ s->session->cipher = pref_cipher;
++
++ if (s->cipher_list)
++ sk_SSL_CIPHER_free(s->cipher_list);
++
++ if (s->cipher_list_by_id)
++ sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++ }
++ }
+ #endif
+ /*
+ * Worst case, we will use the NULL compression, but if we have other
+@@ -1143,15 +1196,21 @@ int ssl3_send_server_hello(SSL *s)
+ unsigned char *buf;
+ unsigned char *p, *d;
+ int i, sl;
+- unsigned long l, Time;
++ unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++ unsigned long Time;
++#endif
+
+ if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
+ buf = (unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ p = s->s3->server_random;
++ /* Generate server_random if it was not needed previously */
+ Time = (unsigned long)time(NULL); /* Time */
+ l2n(Time, p);
+ if (RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE - 4) <= 0)
+ return -1;
++#endif
+ /* Do the message type and length last */
+ d = p = &(buf[4]);
+
+diff -upr openssl-0.9.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
+--- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl_err.c 2015-03-24 16:35:58.627903717 +0200
+@@ -316,6 +316,7 @@ static ERR_STRING_DATA SSL_str_functs[]
+ {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
++ {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
+ {0, NULL}
+ };
+
+diff -upr openssl-0.9.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
+--- openssl-0.9.8zf.orig/ssl/ssl.h 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl.h 2015-03-24 16:25:44.339908641 +0200
+@@ -349,6 +349,7 @@ extern "C" {
+ * function parameters used to prototype callbacks in SSL_CTX.
+ */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st {
+@@ -366,6 +367,12 @@ typedef struct ssl_cipher_st {
+
+ DECLARE_STACK_OF(SSL_CIPHER)
+
++typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data,
++ int len, void *arg);
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
++ STACK_OF(SSL_CIPHER) *peer_ciphers,
++ SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st {
+ int version;
+@@ -1116,6 +1123,18 @@ struct ssl_st {
+ int tlsext_ocsp_resplen;
+ /* RFC4507 session ticket expected to be received or sent */
+ int tlsext_ticket_expected;
++
++ /* TLS Session Ticket extension override */
++ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
++
++ /* TLS Session Ticket extension callback */
++ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
++ void *tls_session_ticket_ext_cb_arg;
++
++ /* TLS pre-shared secret session resumption */
++ tls_session_secret_cb_fn tls_session_secret_cb;
++ void *tls_session_secret_cb_arg;
++
+ SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */
+ # define session_ctx initial_ctx
+ # else
+@@ -1772,6 +1791,17 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id, void *cm);
+ # endif
+
++/* TLS extensions functions */
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++ void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s,
++ tls_session_secret_cb_fn tls_session_secret_cb,
++ void *arg);
++
+ /* BEGIN ERROR CODES */
+ /*
+ * The following lines are auto generated by the script mkerr.pl. Any changes
+@@ -1977,6 +2007,7 @@ void ERR_load_SSL_strings(void);
+ # define SSL_F_TLS1_ENC 210
+ # define SSL_F_TLS1_SETUP_KEY_BLOCK 211
+ # define SSL_F_WRITE_PENDING 212
++#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
+
+ /* Reason codes. */
+ # define SSL_R_APP_DATA_IN_HANDSHAKE 100
+diff -upr openssl-0.9.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
+--- openssl-0.9.8zf.orig/ssl/ssl_sess.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl_sess.c 2015-03-24 16:28:04.819907515 +0200
+@@ -716,6 +716,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ return (s->session_timeout);
+ }
+
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(
++ SSL *s,
++ int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++ STACK_OF(SSL_CIPHER) *peer_ciphers,
++ SSL_CIPHER **cipher, void *arg), void *arg)
++{
++ if (s == NULL)
++ return 0;
++ s->tls_session_secret_cb = tls_session_secret_cb;
++ s->tls_session_secret_cb_arg = arg;
++ return 1;
++}
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++ void *arg)
++{
++ if (s == NULL)
++ return 0;
++ s->tls_session_ticket_ext_cb = cb;
++ s->tls_session_ticket_ext_cb_arg = arg;
++ return 1;
++}
++
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
++{
++ if (s->version >= TLS1_VERSION) {
++ if (s->tlsext_session_ticket) {
++ OPENSSL_free(s->tlsext_session_ticket);
++ s->tlsext_session_ticket = NULL;
++ }
++
++ s->tlsext_session_ticket = OPENSSL_malloc(
++ sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
++ if (!s->tlsext_session_ticket) {
++ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
++
++ if (ext_data) {
++ s->tlsext_session_ticket->length = ext_len;
++ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
++ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
++ } else {
++ s->tlsext_session_ticket->length = 0;
++ s->tlsext_session_ticket->data = NULL;
++ }
++
++ return 1;
++ }
++
++ return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st {
+ SSL_CTX *ctx;
+ long time;
+diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
+--- openssl-0.9.8zf.orig/ssl/t1_lib.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/t1_lib.c 2015-03-24 16:32:46.923905254 +0200
+@@ -108,6 +108,11 @@ int tls1_new(SSL *s)
+
+ void tls1_free(SSL *s)
+ {
++#ifndef OPENSSL_NO_TLSEXT
++ if (s->tlsext_session_ticket) {
++ OPENSSL_free(s->tlsext_session_ticket);
++ }
++#endif
+ ssl3_free(s);
+ }
+
+@@ -206,8 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
+ int ticklen;
+ if (!s->new_session && s->session && s->session->tlsext_tick)
+ ticklen = s->session->tlsext_ticklen;
+- else
++ else if (s->session && s->tlsext_session_ticket &&
++ s->tlsext_session_ticket->data) {
++ ticklen = s->tlsext_session_ticket->length;
++ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++ if (!s->session->tlsext_tick)
++ return NULL;
++ memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data,
++ ticklen);
++ s->session->tlsext_ticklen = ticklen;
++ } else
+ ticklen = 0;
++ if (ticklen == 0 && s->tlsext_session_ticket &&
++ s->tlsext_session_ticket->data == NULL)
++ goto skip_ext;
+ /*
+ * Check for enough room 2 for extension type, 2 for len rest for
+ * ticket
+@@ -221,6 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ ret += ticklen;
+ }
+ }
++skip_ext:
+
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ s->version != DTLS1_VERSION) {
+@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
+ if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
++ } else if (type == TLSEXT_TYPE_session_ticket) {
++ if (s->tls_session_ticket_ext_cb &&
++ !s->tls_session_ticket_ext_cb(s, data, size,
++ s->tls_session_ticket_ext_cb_arg))
++ {
++ *al = TLS1_AD_INTERNAL_ERROR;
++ return 0;
++ }
+ } else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) {
+
+@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
+ }
+ tlsext_servername = 1;
+ } else if (type == TLSEXT_TYPE_session_ticket) {
++ if (s->tls_session_ticket_ext_cb &&
++ !s->tls_session_ticket_ext_cb(
++ s, data, size,
++ s->tls_session_ticket_ext_cb_arg)) {
++ *al = TLS1_AD_INTERNAL_ERROR;
++ return 0;
++ }
+ if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ || (size > 0)) {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+@@ -993,6 +1026,14 @@ int tls1_process_ticket(SSL *s, unsigned
+ s->tlsext_ticket_expected = 1;
+ return 0; /* Cache miss */
+ }
++ if (s->tls_session_secret_cb) {
++ /* Indicate cache miss here and instead of
++ * generating the session from ticket now,
++ * trigger abbreviated handshake based on
++ * external mechanism to calculate the master
++ * secret later. */
++ return 0;
++ }
+ return tls_decrypt_ticket(s, p, size, session_id, len, ret);
+ }
+ p += size;
+diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
+--- openssl-0.9.8zf.orig/ssl/tls1.h 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
+@@ -460,6 +460,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ # define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
+ # endif
+
++/* TLS extension struct */
++struct tls_session_ticket_ext_st {
++ unsigned short length;
++ void *data;
++};
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
+--- openssl-0.9.8zf.orig/util/ssleay.num 2015-03-19 15:47:15.000000000 +0200
++++ openssl-0.9.8zf/util/ssleay.num 2015-03-24 16:33:51.127904739 +0200
+@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
+ SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
+ SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
++SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT
diff --git a/src/Makefile b/src/Makefile
index 10e0171b0c6d..c9e84c11de7a 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,4 +1,5 @@
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
diff --git a/src/ap/Makefile b/src/ap/Makefile
index adfd3dfd5b9b..98788fef797e 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -1,8 +1,67 @@
-all:
- @echo Nothing to be made.
+all: libap.a
clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a
install:
@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DHOSTAPD
+CFLAGS += -DNEED_AP_MLME
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_INTERWORKING
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_WPS
+CFLAGS += -DCONFIG_PROXYARP
+CFLAGS += -DCONFIG_IAPP
+
+LIB_OBJS= \
+ accounting.o \
+ ap_config.o \
+ ap_drv_ops.o \
+ ap_list.o \
+ ap_mlme.o \
+ authsrv.o \
+ beacon.o \
+ bss_load.o \
+ ctrl_iface_ap.o \
+ dfs.o \
+ dhcp_snoop.o \
+ drv_callbacks.o \
+ eap_user_db.o \
+ gas_serv.o \
+ hostapd.o \
+ hs20.o \
+ hw_features.o \
+ iapp.o \
+ ieee802_11_auth.o \
+ ieee802_11.o \
+ ieee802_11_ht.o \
+ ieee802_11_shared.o \
+ ieee802_11_vht.o \
+ ieee802_1x.o \
+ ndisc_snoop.o \
+ p2p_hostapd.o \
+ peerkey_auth.o \
+ pmksa_cache_auth.o \
+ preauth_auth.o \
+ sta_info.o \
+ tkip_countermeasures.o \
+ utils.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
+
+libap.a: $(LIB_OBJS)
+ $(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 7c55146b2c5c..a096de4d3e51 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -459,10 +459,14 @@ int accounting_init(struct hostapd_data *hapd)
{
struct os_time now;
- /* Acct-Session-Id should be unique over reboots. If reliable clock is
- * not available, this could be replaced with reboot counter, etc. */
+ /* Acct-Session-Id should be unique over reboots. Using a random number
+ * is preferred. If that is not available, take the current time. Mix
+ * in microseconds to make this more likely to be unique. */
os_get_time(&now);
- hapd->acct_session_id_hi = now.sec;
+ if (os_get_random((u8 *) &hapd->acct_session_id_hi,
+ sizeof(hapd->acct_session_id_hi)) < 0)
+ hapd->acct_session_id_hi = now.sec;
+ hapd->acct_session_id_hi ^= now.usec;
if (radius_client_register(hapd->radius, RADIUS_ACCT,
accounting_receive, hapd))
@@ -475,7 +479,7 @@ int accounting_init(struct hostapd_data *hapd)
/**
- * accounting_deinit: Deinitilize accounting
+ * accounting_deinit: Deinitialize accounting
* @hapd: hostapd BSS data
*/
void accounting_deinit(struct hostapd_data *hapd)
diff --git a/src/ap/acs.c b/src/ap/acs.c
index ae7f6c309289..03d797fe8836 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -479,16 +479,10 @@ static int acs_usable_chan(struct hostapd_channel_data *chan)
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
- int *entry;
-
- if (!iface->conf->chanlist)
+ if (!iface->conf->acs_ch_list.num)
return 1;
- for (entry = iface->conf->chanlist; *entry != -1; entry++) {
- if (*entry == chan->chan)
- return 1;
- }
- return 0;
+ return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
}
@@ -900,6 +894,9 @@ static int acs_request_scan(struct hostapd_iface *iface)
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
*freq++ = chan->freq;
}
*freq = 0;
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 76011dc07fd4..9a96e50b7385 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -172,6 +172,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ap_table_max_size = 255;
conf->ap_table_expiration_time = 60;
+ conf->track_sta_max_age = 180;
#ifdef CONFIG_TESTING_OPTIONS
conf->ignore_probe_probability = 0.0;
@@ -181,6 +182,8 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->corrupt_gtk_rekey_mic_probability = 0.0;
#endif /* CONFIG_TESTING_OPTIONS */
+ conf->acs = 0;
+ conf->acs_ch_list.num = 0;
#ifdef CONFIG_ACS
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
@@ -559,6 +562,13 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->server_id);
+#ifdef CONFIG_TESTING_OPTIONS
+ wpabuf_free(conf->own_ie_override);
+#endif /* CONFIG_TESTING_OPTIONS */
+
+ os_free(conf->no_probe_resp_if_seen_on);
+ os_free(conf->no_auth_if_seen_on);
+
os_free(conf);
}
@@ -579,7 +589,7 @@ void hostapd_config_free(struct hostapd_config *conf)
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
- os_free(conf->chanlist);
+ os_free(conf->acs_ch_list.range);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
@@ -817,9 +827,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
- !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
- "WPA2/CCMP forced WPS to be disabled");
+ "WPA2/CCMP/GCMP forced WPS to be disabled");
bss->wps_state = 0;
}
#endif /* CONFIG_WPS */
@@ -841,6 +851,29 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
+static int hostapd_config_check_cw(struct hostapd_config *conf, int queue)
+{
+ int tx_cwmin = conf->tx_queue[queue].cwmin;
+ int tx_cwmax = conf->tx_queue[queue].cwmax;
+ int ac_cwmin = conf->wmm_ac_params[queue].cwmin;
+ int ac_cwmax = conf->wmm_ac_params[queue].cwmax;
+
+ if (tx_cwmin > tx_cwmax) {
+ wpa_printf(MSG_ERROR,
+ "Invalid TX queue cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)",
+ tx_cwmin, tx_cwmax);
+ return -1;
+ }
+ if (ac_cwmin > ac_cwmax) {
+ wpa_printf(MSG_ERROR,
+ "Invalid WMM AC cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)",
+ ac_cwmin, ac_cwmax);
+ return -1;
+ }
+ return 0;
+}
+
+
int hostapd_config_check(struct hostapd_config *conf, int full_config)
{
size_t i;
@@ -870,6 +903,11 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
return -1;
}
+ for (i = 0; i < NUM_TX_QUEUES; i++) {
+ if (hostapd_config_check_cw(conf, i))
+ return -1;
+ }
+
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
return -1;
@@ -937,10 +975,11 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
bss->rsn_pairwise = WPA_CIPHER_CCMP;
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
- bss->wpa_group = WPA_CIPHER_NONE;
- bss->wpa_pairwise = WPA_CIPHER_NONE;
- bss->rsn_pairwise = WPA_CIPHER_NONE;
- if (full_config)
+ if (full_config) {
+ bss->wpa_group = WPA_CIPHER_NONE;
+ bss->wpa_pairwise = WPA_CIPHER_NONE;
+ bss->rsn_pairwise = WPA_CIPHER_NONE;
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
+ }
}
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 961d2dd389f8..de470a969b50 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration definitions and helpers functions
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,8 +12,10 @@
#include "common/defs.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
+#include "fst/fst.h"
/**
* mesh_conf - local MBSS state and settings
@@ -31,8 +33,8 @@ struct mesh_conf {
u8 mesh_sp_id;
/* Authentication Protocol Identifier */
u8 mesh_auth_id;
- u8 *ies;
- int ie_len;
+ u8 *rsn_ie;
+ int rsn_ie_len;
#define MESH_CONF_SEC_NONE BIT(0)
#define MESH_CONF_SEC_AUTH BIT(1)
#define MESH_CONF_SEC_AMPE BIT(2)
@@ -57,8 +59,6 @@ struct hostapd_radius_servers;
struct ft_remote_r0kh;
struct ft_remote_r1kh;
-#define HOSTAPD_MAX_SSID_LEN 32
-
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
@@ -78,7 +78,7 @@ typedef enum hostap_security_policy {
} secpolicy;
struct hostapd_ssid {
- u8 ssid[HOSTAPD_MAX_SSID_LEN];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
@@ -114,12 +114,10 @@ struct hostapd_vlan {
struct hostapd_vlan *next;
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
char ifname[IFNAMSIZ + 1];
+ int configured;
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
-#define DVLAN_CLEAN_BR 0x1
-#define DVLAN_CLEAN_VLAN 0x2
-#define DVLAN_CLEAN_VLAN_PORT 0x4
#define DVLAN_CLEAN_WLAN_PORT 0x8
int clean;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -332,6 +330,7 @@ struct hostapd_bss_config {
char *private_key;
char *private_key_passwd;
int check_crl;
+ unsigned int tls_session_lifetime;
char *ocsp_stapling_response;
char *dh_file;
char *openssl_ciphers;
@@ -490,6 +489,7 @@ struct hostapd_bss_config {
int osen;
int proxy_arp;
+ int na_mcast_to_ucast;
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
@@ -510,7 +510,7 @@ struct hostapd_bss_config {
char file[256];
} *hs20_icons;
size_t hs20_icons_count;
- u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
+ u8 osu_ssid[SSID_MAX_LEN];
size_t osu_ssid_len;
struct hs20_osu_provider {
unsigned int friendly_name_count;
@@ -545,6 +545,7 @@ struct hostapd_bss_config {
#ifdef CONFIG_TESTING_OPTIONS
u8 bss_load_test[5];
u8 bss_load_test_set;
+ struct wpabuf *own_ie_override;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
@@ -553,6 +554,9 @@ struct hostapd_bss_config {
int radio_measurements;
int vendor_vht;
+
+ char *no_probe_resp_if_seen_on;
+ char *no_auth_if_seen_on;
};
@@ -568,7 +572,8 @@ struct hostapd_config {
int fragm_threshold;
u8 send_probe_response;
u8 channel;
- int *chanlist;
+ u8 acs;
+ struct wpa_freq_range_list acs_ch_list;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
@@ -584,6 +589,9 @@ struct hostapd_config {
int ap_table_max_size;
int ap_table_expiration_time;
+ unsigned int track_sta_max_num;
+ unsigned int track_sta_max_age;
+
char country[3]; /* first two octets: country code as described in
* ISO/IEC 3166-1. Third octet:
* ' ' (ascii 32): all environments
@@ -620,6 +628,7 @@ struct hostapd_config {
u16 ht_capab;
int ieee80211n;
int secondary_channel;
+ int no_pri_sec_switch;
int require_ht;
int obss_interval;
u32 vht_capab;
@@ -629,6 +638,10 @@ struct hostapd_config {
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
+#ifdef CONFIG_FST
+ struct fst_iface_cfg fst_cfg;
+#endif /* CONFIG_FST */
+
#ifdef CONFIG_P2P
u8 p2p_go_ctwindow;
#endif /* CONFIG_P2P */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index e16306c4e106..6cafcb749351 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -81,6 +81,22 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
wpabuf_put_data(proberesp, buf, pos - buf);
}
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies) {
+ size_t add = wpabuf_len(hapd->iface->fst_ies);
+
+ if (wpabuf_resize(&beacon, add) < 0)
+ goto fail;
+ wpabuf_put_buf(beacon, hapd->iface->fst_ies);
+ if (wpabuf_resize(&proberesp, add) < 0)
+ goto fail;
+ wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
+ if (wpabuf_resize(&assocresp, add) < 0)
+ goto fail;
+ wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
+ }
+#endif /* CONFIG_FST */
+
if (hapd->wps_beacon_ie) {
if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
0)
@@ -217,6 +233,15 @@ void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
}
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+ return 0;
+
+ return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL);
+}
+
+
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
{
struct wpabuf *beacon, *proberesp, *assocresp;
@@ -281,8 +306,14 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
params.wpa = hapd->conf->wpa;
params.ieee802_1x = hapd->conf->ieee802_1x;
params.wpa_group = hapd->conf->wpa_group;
- params.wpa_pairwise = hapd->conf->wpa_pairwise |
- hapd->conf->rsn_pairwise;
+ if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
+ (WPA_PROTO_WPA | WPA_PROTO_RSN))
+ params.wpa_pairwise = hapd->conf->wpa_pairwise |
+ hapd->conf->rsn_pairwise;
+ else if (hapd->conf->wpa & WPA_PROTO_RSN)
+ params.wpa_pairwise = hapd->conf->rsn_pairwise;
+ else if (hapd->conf->wpa & WPA_PROTO_WPA)
+ 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
@@ -618,7 +649,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
- return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
+ return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
}
@@ -712,16 +743,100 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
}
+static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
+ struct hostapd_hw_modes *mode,
+ int acs_ch_list_all,
+ int **freq_list)
+{
+ int i;
+
+ 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))
+ int_array_add_unique(freq_list, chan->freq);
+ }
+}
+
+
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;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
+
os_memset(&params, 0, sizeof(params));
params.hw_mode = hapd->iface->conf->hw_mode;
+
+ /*
+ * 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 (!(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);
+ }
+ }
+
+ params.ch_list = channels;
+ params.ch_list_len = num_channels;
+ params.freq_list = freq_list;
+
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
- return hapd->driver->do_acs(hapd->drv_priv, &params);
+ params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
+ params.ch_width = 20;
+ if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
+ params.ch_width = 40;
+
+ /* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
+ */
+ if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
+ if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ params.ch_width = 80;
+ else if (hapd->iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_160MHZ ||
+ hapd->iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_80P80MHZ)
+ params.ch_width = 160;
+ }
+
+ ret = hapd->driver->do_acs(hapd->drv_priv, &params);
+ os_free(channels);
+
+ return ret;
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 5d07e71f1bf1..82eaf3f08bb5 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -24,6 +24,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
struct wpabuf *proberesp,
struct wpabuf *assocresp);
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 04a56a95efd9..8bf6ddec8d37 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -193,14 +193,14 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
- if (elems->erp_info && elems->erp_info_len == 1)
+ if (elems->erp_info)
ap->erp = elems->erp_info[0];
else
ap->erp = -1;
- if (elems->ds_params && elems->ds_params_len == 1)
+ if (elems->ds_params)
ap->channel = elems->ds_params[0];
- else if (elems->ht_operation && elems->ht_operation_len >= 1)
+ else if (elems->ht_operation)
ap->channel = elems->ht_operation[0];
else if (fi)
ap->channel = fi->channel;
@@ -248,15 +248,12 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
}
-static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
+void ap_list_timer(struct hostapd_iface *iface)
{
- struct hostapd_iface *iface = eloop_ctx;
struct os_reltime now;
struct ap_info *ap;
int set_beacon = 0;
- eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
-
if (!iface->ap_list)
return;
@@ -305,13 +302,11 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
int ap_list_init(struct hostapd_iface *iface)
{
- eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
return 0;
}
void ap_list_deinit(struct hostapd_iface *iface)
{
- eloop_cancel_timeout(ap_list_timer, iface, NULL);
hostapd_free_aps(iface);
}
diff --git a/src/ap/ap_list.h b/src/ap/ap_list.h
index 93dc0eda88d3..9e0353cfec95 100644
--- a/src/ap/ap_list.h
+++ b/src/ap/ap_list.h
@@ -39,6 +39,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
#ifdef NEED_AP_MLME
int ap_list_init(struct hostapd_iface *iface);
void ap_list_deinit(struct hostapd_iface *iface);
+void ap_list_timer(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline int ap_list_init(struct hostapd_iface *iface)
{
@@ -48,6 +49,10 @@ static inline int ap_list_init(struct hostapd_iface *iface)
static inline void ap_list_deinit(struct hostapd_iface *iface)
{
}
+
+static inline void ap_list_timer(struct hostapd_iface *iface)
+{
+}
#endif /* NEED_AP_MLME */
#endif /* AP_LIST_H */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index bd1778e41865..934dcfc8d631 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -55,10 +55,11 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
{
const struct hostapd_eap_user *eap_user;
int i;
+ int rv = -1;
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
if (eap_user == NULL)
- return -1;
+ goto out;
if (user == NULL)
return 0;
@@ -72,7 +73,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
- return -1;
+ goto out;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
@@ -83,8 +84,13 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr;
+ rv = 0;
- return 0;
+out:
+ if (rv)
+ wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
+
+ return rv;
}
@@ -126,6 +132,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
#endif /* CONFIG_HS20 */
srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
+ srv.tls_session_lifetime = conf->tls_session_lifetime;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@@ -145,9 +152,12 @@ int authsrv_init(struct hostapd_data *hapd)
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
hapd->conf->private_key || hapd->conf->dh_file)) {
+ struct tls_config conf;
struct tls_connection_params params;
- hapd->ssl_ctx = tls_init(NULL);
+ os_memset(&conf, 0, sizeof(conf));
+ conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
+ hapd->ssl_ctx = tls_init(&conf);
if (hapd->ssl_ctx == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
authsrv_deinit(hapd);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index e575b65cbf3a..5fe8fd5660b4 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -360,7 +360,6 @@ static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
- struct sta_info *sta,
const struct ieee80211_mgmt *req,
int is_p2p, size_t *resp_len)
{
@@ -378,6 +377,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
if (hapd->p2p_probe_resp_ie)
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies)
+ buflen += wpabuf_len(hapd->iface->fst_ies);
+#endif /* CONFIG_FST */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
if (hapd->conf->vendor_vht) {
@@ -402,7 +405,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* hardware or low-level driver will setup seq_ctrl and timestamp */
resp->u.probe_resp.capab_info =
- host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+ host_to_le16(hostapd_own_capab_info(hapd));
pos = resp->u.probe_resp.variable;
*pos++ = WLAN_EID_SSID;
@@ -450,6 +453,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
&hapd->cs_c_off_proberesp);
+
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies) {
+ os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
+ wpabuf_len(hapd->iface->fst_ies));
+ pos += wpabuf_len(hapd->iface->fst_ies);
+ }
+#endif /* CONFIG_FST */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
pos = hostapd_eid_vht_capabilities(hapd, pos);
@@ -540,6 +552,102 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
}
+void sta_track_expire(struct hostapd_iface *iface, int force)
+{
+ struct os_reltime now;
+ struct hostapd_sta_info *info;
+
+ if (!iface->num_sta_seen)
+ return;
+
+ os_get_reltime(&now);
+ while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
+ list))) {
+ if (!force &&
+ !os_reltime_expired(&now, &info->last_seen,
+ iface->conf->track_sta_max_age))
+ break;
+ force = 0;
+
+ wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for "
+ MACSTR, iface->bss[0]->conf->iface,
+ MAC2STR(info->addr));
+ dl_list_del(&info->list);
+ iface->num_sta_seen--;
+ os_free(info);
+ }
+}
+
+
+static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
+ const u8 *addr)
+{
+ struct hostapd_sta_info *info;
+
+ dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list)
+ if (os_memcmp(addr, info->addr, ETH_ALEN) == 0)
+ return info;
+
+ return NULL;
+}
+
+
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
+{
+ struct hostapd_sta_info *info;
+
+ info = sta_track_get(iface, addr);
+ if (info) {
+ /* Move the most recent entry to the end of the list */
+ dl_list_del(&info->list);
+ dl_list_add_tail(&iface->sta_seen, &info->list);
+ os_get_reltime(&info->last_seen);
+ return;
+ }
+
+ /* Add a new entry */
+ info = os_zalloc(sizeof(*info));
+ os_memcpy(info->addr, addr, ETH_ALEN);
+ os_get_reltime(&info->last_seen);
+
+ if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
+ /* Expire oldest entry to make room for a new one */
+ sta_track_expire(iface, 1);
+ }
+
+ wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for "
+ MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr));
+ dl_list_add_tail(&iface->sta_seen, &info->list);
+ iface->num_sta_seen++;
+}
+
+
+struct hostapd_data *
+sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
+ const char *ifname)
+{
+ struct hapd_interfaces *interfaces = iface->interfaces;
+ size_t i, j;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_data *hapd = NULL;
+
+ iface = interfaces->iface[i];
+ for (j = 0; j < iface->num_bss; j++) {
+ hapd = iface->bss[j];
+ if (os_strcmp(ifname, hapd->conf->iface) == 0)
+ break;
+ hapd = NULL;
+ }
+
+ if (hapd && sta_track_get(iface, addr))
+ return hapd;
+ }
+
+ return NULL;
+}
+
+
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@@ -548,7 +656,6 @@ void handle_probe_req(struct hostapd_data *hapd,
struct ieee802_11_elems elems;
const u8 *ie;
size_t ie_len;
- struct sta_info *sta = NULL;
size_t i, resp_len;
int noack;
enum ssid_match_result res;
@@ -556,6 +663,8 @@ void handle_probe_req(struct hostapd_data *hapd,
ie = mgmt->u.probe_req.variable;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
return;
+ if (hapd->iconf->track_sta_max_num)
+ sta_track_add(hapd->iface, mgmt->sa);
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
@@ -590,7 +699,7 @@ void handle_probe_req(struct hostapd_data *hapd,
* is less likely to see them (Probe Request frame sent on a
* neighboring, but partially overlapping, channel).
*/
- if (elems.ds_params && elems.ds_params_len == 1 &&
+ if (elems.ds_params &&
hapd->iface->current_mode &&
(hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
@@ -635,8 +744,6 @@ void handle_probe_req(struct hostapd_data *hapd,
return;
}
- sta = ap_get_sta(hapd, mgmt->sa);
-
#ifdef CONFIG_P2P
if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
@@ -649,10 +756,7 @@ void handle_probe_req(struct hostapd_data *hapd,
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
elems.ssid_list, elems.ssid_list_len);
- if (res != NO_SSID_MATCH) {
- if (sta)
- sta->ssid_probe = &hapd->conf->ssid;
- } else {
+ if (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")%s",
@@ -709,6 +813,18 @@ void handle_probe_req(struct hostapd_data *hapd,
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
+ if (hapd->conf->no_probe_resp_if_seen_on &&
+ is_multicast_ether_addr(mgmt->da) &&
+ is_multicast_ether_addr(mgmt->bssid) &&
+ sta_track_seen_on(hapd->iface, mgmt->sa,
+ hapd->conf->no_probe_resp_if_seen_on)) {
+ wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
+ " since STA has been seen on %s",
+ hapd->conf->iface, MAC2STR(mgmt->sa),
+ hapd->conf->no_probe_resp_if_seen_on);
+ return;
+ }
+
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
@@ -719,7 +835,7 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_TESTING_OPTIONS */
- resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+ resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
&resp_len);
if (resp == NULL)
return;
@@ -774,7 +890,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
"this");
/* Generate a Probe Response template for the non-P2P case */
- return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+ return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
}
#endif /* NEED_AP_MLME */
@@ -804,6 +920,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
if (hapd->p2p_beacon_ie)
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies)
+ tail_len += wpabuf_len(hapd->iface->fst_ies);
+#endif /* CONFIG_FST */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
@@ -833,7 +953,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
host_to_le16(hapd->iconf->beacon_int);
/* hardware or low-level driver will setup seq_ctrl and timestamp */
- capab_info = hostapd_own_capab_info(hapd, NULL, 0);
+ capab_info = hostapd_own_capab_info(hapd);
head->u.beacon.capab_info = host_to_le16(capab_info);
pos = &head->u.beacon.variable[0];
@@ -902,6 +1022,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
&hapd->cs_c_off_beacon);
+
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies) {
+ os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies),
+ wpabuf_len(hapd->iface->fst_ies));
+ tailpos += wpabuf_len(hapd->iface->fst_ies);
+ }
+#endif /* CONFIG_FST */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
@@ -963,8 +1092,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->basic_rates = hapd->iface->basic_rates;
params->ssid = hapd->conf->ssid.ssid;
params->ssid_len = hapd->conf->ssid.ssid_len;
- params->pairwise_ciphers = hapd->conf->wpa_pairwise |
- hapd->conf->rsn_pairwise;
+ if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
+ (WPA_PROTO_WPA | WPA_PROTO_RSN))
+ params->pairwise_ciphers = hapd->conf->wpa_pairwise |
+ hapd->conf->rsn_pairwise;
+ else if (hapd->conf->wpa & WPA_PROTO_RSN)
+ params->pairwise_ciphers = hapd->conf->rsn_pairwise;
+ else if (hapd->conf->wpa & WPA_PROTO_WPA)
+ params->pairwise_ciphers = hapd->conf->wpa_pairwise;
params->group_cipher = hapd->conf->wpa_group;
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index 722159a7500c..d98f42e8157a 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -21,5 +21,10 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface);
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params);
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
+void sta_track_expire(struct hostapd_iface *iface, int force);
+struct hostapd_data *
+sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
+ const char *ifname);
#endif /* BEACON_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 41ab988277bb..c98978f33d05 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -12,6 +12,7 @@
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "eapol_auth/eapol_auth_sm.h"
+#include "fst/fst_ctrl_iface.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
@@ -153,6 +154,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
}
#endif /* CONFIG_SAE */
+ if (sta->vlan_id > 0) {
+ res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
+ sta->vlan_id);
+ if (!os_snprintf_error(buflen - len, res))
+ len += res;
+ }
+
return len;
}
@@ -199,7 +207,10 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
return -1;
}
- return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
+ ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
+ ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
+
+ return ret;
}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index da6fd4646710..715f19b6ac7b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -122,6 +122,20 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
}
+static struct hostapd_channel_data *
+dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
+{
+ int i;
+
+ for (i = first_chan_idx; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == freq)
+ return &mode->channels[i];
+ }
+
+ return NULL;
+}
+
+
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans,
int skip_radar)
@@ -129,15 +143,15 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *first_chan, *chan;
int i;
- if (first_chan_idx + num_chans >= mode->num_channels)
+ if (first_chan_idx + num_chans > mode->num_channels)
return 0;
first_chan = &mode->channels[first_chan_idx];
for (i = 0; i < num_chans; i++) {
- chan = &mode->channels[first_chan_idx + i];
-
- if (first_chan->freq + i * 20 != chan->freq)
+ chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
+ first_chan_idx);
+ if (!chan)
return 0;
if (!dfs_channel_available(chan, skip_radar))
@@ -151,16 +165,10 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
- int *entry;
-
- if (!iface->conf->chanlist)
+ if (!iface->conf->acs_ch_list.num)
return 1;
- for (entry = iface->conf->chanlist; *entry != -1; entry++) {
- if (*entry == chan->chan)
- return 1;
- }
- return 0;
+ return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index a0adc67db430..ca8b75c83906 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -18,6 +18,7 @@
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
+#include "fst/fst.h"
#include "wnm_ap.h"
#include "hostapd.h"
#include "ieee802_11.h"
@@ -42,10 +43,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@@ -58,8 +59,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
* running, so better make sure we stop processing such an
* event here.
*/
- wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
- "no address");
+ wpa_printf(MSG_DEBUG,
+ "hostapd_notif_assoc: Skip event with no address");
return -1;
}
random_add_randomness(addr, ETH_ALEN);
@@ -89,8 +90,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
} else {
ie = NULL;
ielen = 0;
- wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
- "(Re)AssocReq");
+ wpa_printf(MSG_DEBUG,
+ "STA did not include WPS/RSN/WPA IE in (Re)AssocReq");
}
sta = ap_get_sta(hapd, addr);
@@ -126,8 +127,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
- elems.ht_capabilities_len >=
- sizeof(struct ieee80211_ht_capabilities) &&
(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
struct ieee80211_ht_capabilities *ht_cap =
@@ -157,13 +156,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->hs20_ie = NULL;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_FST
+ wpabuf_free(sta->mb_ies);
+ if (hapd->iface->fst)
+ sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
+ else
+ sta->mb_ies = NULL;
+#endif /* CONFIG_FST */
+
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
if (hapd->conf->wps_state) {
- wpa_printf(MSG_DEBUG, "STA did not include "
- "WPA/RSN IE in (Re)Association "
- "Request - possible WPS use");
+ wpa_printf(MSG_DEBUG,
+ "STA did not include WPA/RSN IE in (Re)Association Request - possible WPS use");
sta->flags |= WLAN_STA_MAYBE_WPS;
goto skip_wpa_check;
}
@@ -176,13 +182,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
+
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
if (wps) {
if (wps_is_20(wps)) {
- wpa_printf(MSG_DEBUG, "WPS: STA "
- "supports WPS 2.0");
+ wpa_printf(MSG_DEBUG,
+ "WPS: STA supports WPS 2.0");
sta->flags |= WLAN_STA_WPS2;
}
wpabuf_free(wps);
@@ -196,16 +203,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->addr,
p2p_dev_addr);
if (sta->wpa_sm == NULL) {
- wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
- "machine");
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize WPA state machine");
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
ie, ielen,
elems.mdie, elems.mdie_len);
if (res != WPA_IE_OK) {
- wpa_printf(MSG_DEBUG, "WPA/RSN information element "
- "rejected? (res %u)", res);
+ wpa_printf(MSG_DEBUG,
+ "WPA/RSN information element rejected? (res %u)",
+ res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
if (res == WPA_INVALID_GROUP) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
@@ -248,14 +256,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (sta->sa_query_count == 0)
ap_sta_start_sa_query(hapd, sta);
-#ifdef CONFIG_IEEE80211R
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
p - buf);
-#endif /* CONFIG_IEEE80211R */
return 0;
}
@@ -283,6 +289,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
+
if (req_ies)
wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
WPS_IE_VENDOR_TYPE);
@@ -299,8 +306,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (wps) {
sta->flags |= WLAN_STA_WPS;
if (wps_is_20(wps)) {
- wpa_printf(MSG_DEBUG, "WPS: STA supports "
- "WPS 2.0");
+ wpa_printf(MSG_DEBUG,
+ "WPS: STA supports WPS 2.0");
sta->flags |= WLAN_STA_WPS2;
}
} else
@@ -322,8 +329,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr, NULL);
if (sta->wpa_sm == NULL) {
- wpa_printf(MSG_WARNING, "Failed to initialize WPA "
- "state machine");
+ wpa_printf(MSG_WARNING,
+ "Failed to initialize WPA state machine");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
@@ -395,8 +402,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
* was running, so better make sure we stop processing such an
* event here.
*/
- wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
- "with no address");
+ wpa_printf(MSG_DEBUG,
+ "hostapd_notif_disassoc: Skip event with no address");
return;
}
@@ -405,8 +412,9 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
- wpa_printf(MSG_DEBUG, "Disassociation notification for "
- "unknown STA " MACSTR, MAC2STR(addr));
+ wpa_printf(MSG_DEBUG,
+ "Disassociation notification for unknown STA "
+ MACSTR, MAC2STR(addr));
return;
}
@@ -427,8 +435,8 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
return;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
- "missing ACKs");
+ HOSTAPD_LEVEL_INFO,
+ "disconnected due to excessive missing ACKs");
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
if (sta)
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
@@ -452,8 +460,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
channel = hostapd_hw_get_channel(hapd, freq);
if (!channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING, "driver switched to "
- "bad channel!");
+ HOSTAPD_LEVEL_WARNING,
+ "driver switched to bad channel!");
return;
}
@@ -532,10 +540,9 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
#ifdef CONFIG_ACS
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
- u8 pri_channel, u8 sec_channel)
+ struct acs_selected_channels *acs_res)
{
- int channel;
- int ret;
+ int ret, i;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@@ -543,29 +550,73 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
return;
}
- hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
+ if (!hapd->iface->current_mode) {
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ struct hostapd_hw_modes *mode =
+ &hapd->iface->hw_features[i];
- channel = pri_channel;
- if (!channel) {
+ if (mode->mode == acs_res->hw_mode) {
+ hapd->iface->current_mode = mode;
+ break;
+ }
+ }
+ if (!hapd->iface->current_mode) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "driver selected to bad hw_mode");
+ return;
+ }
+ }
+
+ hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
+
+ if (!acs_res->pri_channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
return;
}
- hapd->iconf->channel = channel;
+ hapd->iconf->channel = acs_res->pri_channel;
+ hapd->iconf->acs = 1;
- if (sec_channel == 0)
+ if (acs_res->sec_channel == 0)
hapd->iconf->secondary_channel = 0;
- else if (sec_channel < pri_channel)
+ else if (acs_res->sec_channel < acs_res->pri_channel)
hapd->iconf->secondary_channel = -1;
- else if (sec_channel > pri_channel)
+ else if (acs_res->sec_channel > acs_res->pri_channel)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
return;
}
+ if (hapd->iface->conf->ieee80211ac) {
+ /* set defaults for backwards compatibility */
+ hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
+ hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
+ hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ if (acs_res->ch_width == 80) {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ } else if (acs_res->ch_width == 160) {
+ if (acs_res->vht_seg1_center_ch == 0) {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_chwidth =
+ VHT_CHANWIDTH_160MHZ;
+ } else {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_centr_freq_seg1_idx =
+ acs_res->vht_seg1_center_ch;
+ hapd->iconf->vht_oper_chwidth =
+ VHT_CHANWIDTH_80P80MHZ;
+ }
+ }
+ }
+
ret = hostapd_acs_completed(hapd->iface, 0);
if (ret) {
wpa_printf(MSG_ERROR,
@@ -647,8 +698,8 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr, NULL);
if (sta->wpa_sm == NULL) {
- wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
- "state machine");
+ wpa_printf(MSG_DEBUG,
+ "FT: Failed to initialize WPA state machine");
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@@ -683,7 +734,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
return; /* handled by the driver */
- wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
+ wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
mgmt->u.action.category, (int) plen);
sta = ap_get_sta(hapd, mgmt->sa);
@@ -694,6 +745,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211R
if (mgmt->u.action.category == WLAN_ACTION_FT) {
const u8 *payload = drv_mgmt->frame + 24 + 1;
+
wpa_ft_action_rx(sta->wpa_sm, payload, plen);
}
#endif /* CONFIG_IEEE80211R */
@@ -710,6 +762,13 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
}
#endif /* CONFIG_WNM */
+#ifdef CONFIG_FST
+ if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
+ fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
+ return;
+ }
+#endif /* CONFIG_FST */
+
}
@@ -761,6 +820,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
if (hapd->ext_mgmt_frame_handling) {
size_t hex_len = 2 * rx_mgmt->frame_len + 1;
char *hex = os_malloc(hex_len);
+
if (hex) {
wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
rx_mgmt->frame_len);
@@ -778,8 +838,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
hapd = get_hapd_bssid(iface, bssid);
if (hapd == NULL) {
- u16 fc;
- fc = le_to_host16(hdr->frame_control);
+ u16 fc = le_to_host16(hdr->frame_control);
/*
* Drop frames to unknown BSSIDs except for Beacon frames which
@@ -798,6 +857,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
if (hapd == HAPD_BROADCAST) {
size_t i;
+
ret = 0;
for (i = 0; i < iface->num_bss; i++) {
/* if bss is set, driver will call this function for
@@ -824,6 +884,7 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
size_t len, u16 stype, int ok)
{
struct ieee80211_hdr *hdr;
+
hdr = (struct ieee80211_hdr *) buf;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
if (hapd == NULL || hapd == HAPD_BROADCAST)
@@ -837,6 +898,7 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta = ap_get_sta(hapd, addr);
+
if (sta)
return 0;
@@ -863,11 +925,10 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
size_t j;
for (j = 0; j < iface->num_bss; j++) {
- if ((sta = ap_get_sta(iface->bss[j], src))) {
- if (sta->flags & WLAN_STA_ASSOC) {
- hapd = iface->bss[j];
- break;
- }
+ sta = ap_get_sta(iface->bss[j], src);
+ if (sta && sta->flags & WLAN_STA_ASSOC) {
+ hapd = iface->bss[j];
+ break;
}
}
@@ -927,7 +988,8 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
return;
- wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
+ wpa_printf(MSG_DEBUG,
+ "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
survey->freq,
(unsigned long int) survey->channel_time,
(unsigned long int) survey->channel_time_busy);
@@ -1061,6 +1123,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
+
hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
fc = le_to_host16(hdr->frame_control);
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -1248,9 +1311,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
#ifdef CONFIG_ACS
case EVENT_ACS_CHANNEL_SELECTED:
- hostapd_acs_channel_selected(
- hapd, data->acs_selected_channels.pri_channel,
- data->acs_selected_channels.sec_channel);
+ hostapd_acs_channel_selected(hapd,
+ &data->acs_selected_channels);
break;
#endif /* CONFIG_ACS */
default:
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index 559d77f9ef2b..082d0f53175e 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -138,8 +138,12 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
char id_str[256], cmd[300];
size_t i;
- if (identity_len >= sizeof(id_str))
+ if (identity_len >= sizeof(id_str)) {
+ wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
+ __func__, (int) identity_len,
+ (int) (sizeof(id_str)));
return NULL;
+ }
os_memcpy(id_str, identity, identity_len);
id_str[identity_len] = '\0';
for (i = 0; i < identity_len; i++) {
@@ -182,7 +186,9 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
- wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+ wpa_printf(MSG_DEBUG,
+ "DB: Failed to complete SQL operation: %s db: %s",
+ sqlite3_errmsg(db), hapd->conf->eap_user_sqlite);
} else if (hapd->tmp_eap_user.next)
user = &hapd->tmp_eap_user;
@@ -192,8 +198,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
NULL) != SQLITE_OK) {
- wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
- "operation");
+ wpa_printf(MSG_DEBUG,
+ "DB: Failed to complete SQL operation: %s db: %s",
+ sqlite3_errmsg(db),
+ hapd->conf->eap_user_sqlite);
} else if (hapd->tmp_eap_user.next) {
user = &hapd->tmp_eap_user;
os_free(user->identity);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3e4e16b4f396..c09c17a44696 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -17,6 +17,7 @@
#include "eap_server/tncs.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
+#include "fst/fst.h"
#include "hostapd.h"
#include "authsrv.h"
#include "sta_info.h"
@@ -179,6 +180,7 @@ int hostapd_reload_config(struct hostapd_iface *iface)
hapd = iface->bss[j];
hapd->iconf = newconf;
hapd->iconf->channel = oldconf->channel;
+ hapd->iconf->acs = oldconf->acs;
hapd->iconf->secondary_channel = oldconf->secondary_channel;
hapd->iconf->ieee80211n = oldconf->ieee80211n;
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
@@ -259,6 +261,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL;
+ hapd->num_probereq_cb = 0;
#ifdef CONFIG_P2P
wpabuf_free(hapd->p2p_beacon_ie);
@@ -353,6 +356,22 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
}
+static void sta_track_deinit(struct hostapd_iface *iface)
+{
+ struct hostapd_sta_info *info;
+
+ if (!iface->num_sta_seen)
+ return;
+
+ while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
+ list))) {
+ dl_list_del(&info->list);
+ iface->num_sta_seen--;
+ os_free(info);
+ }
+}
+
+
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
@@ -368,6 +387,7 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
os_free(iface->basic_rates);
iface->basic_rates = NULL;
ap_list_deinit(iface);
+ sta_track_deinit(iface);
}
@@ -861,7 +881,7 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
{
struct hostapd_bss_config *conf = hapd->conf;
- u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
+ u8 ssid[SSID_MAX_LEN + 1];
int ssid_len, set_ssid;
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
@@ -1363,6 +1383,132 @@ fail:
}
+#ifdef CONFIG_FST
+
+static const u8 * fst_hostapd_get_bssid_cb(void *ctx)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hapd->own_addr;
+}
+
+
+static void fst_hostapd_get_channel_info_cb(void *ctx,
+ enum hostapd_hw_mode *hw_mode,
+ u8 *channel)
+{
+ struct hostapd_data *hapd = ctx;
+
+ *hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel);
+}
+
+
+static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
+{
+ struct hostapd_data *hapd = ctx;
+
+ if (hapd->iface->fst_ies != fst_ies) {
+ hapd->iface->fst_ies = fst_ies;
+ if (ieee802_11_set_beacon(hapd))
+ wpa_printf(MSG_WARNING, "FST: Cannot set beacon");
+ }
+}
+
+
+static int fst_hostapd_send_action_cb(void *ctx, const u8 *da,
+ struct wpabuf *buf)
+{
+ struct hostapd_data *hapd = ctx;
+
+ return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da,
+ wpabuf_head(buf), wpabuf_len(buf));
+}
+
+
+static const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+
+ return sta ? sta->mb_ies : NULL;
+}
+
+
+static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
+ const u8 *buf, size_t size)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta = ap_get_sta(hapd, addr);
+
+ if (sta) {
+ struct mb_ies_info info;
+
+ if (!mb_ies_info_by_ies(&info, buf, size)) {
+ wpabuf_free(sta->mb_ies);
+ sta->mb_ies = mb_ies_by_info(&info);
+ }
+ }
+}
+
+
+static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
+{
+ struct sta_info *s = (struct sta_info *) *get_ctx;
+
+ if (mb_only) {
+ for (; s && !s->mb_ies; s = s->next)
+ ;
+ }
+
+ if (s) {
+ *get_ctx = (struct fst_get_peer_ctx *) s->next;
+
+ return s->addr;
+ }
+
+ *get_ctx = NULL;
+ return NULL;
+}
+
+
+static const u8 * fst_hostapd_get_peer_first(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
+{
+ struct hostapd_data *hapd = ctx;
+
+ *get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list;
+
+ return fst_hostapd_get_sta(get_ctx, mb_only);
+}
+
+
+static const u8 * fst_hostapd_get_peer_next(void *ctx,
+ struct fst_get_peer_ctx **get_ctx,
+ Boolean mb_only)
+{
+ return fst_hostapd_get_sta(get_ctx, mb_only);
+}
+
+
+void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
+ struct fst_wpa_obj *iface_obj)
+{
+ iface_obj->ctx = hapd;
+ iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
+ iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
+ iface_obj->set_ies = fst_hostapd_set_ies_cb;
+ iface_obj->send_action = fst_hostapd_send_action_cb;
+ iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
+ iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb;
+ iface_obj->get_peer_first = fst_hostapd_get_peer_first;
+ iface_obj->get_peer_next = fst_hostapd_get_peer_next;
+}
+
+#endif /* CONFIG_FST */
+
+
/**
* hostapd_setup_interface_complete - Complete interface setup
*
@@ -1495,6 +1641,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_tx_queue_params(iface);
ap_list_init(iface);
+ dl_list_init(&iface->sta_seen);
hostapd_set_acl(hapd);
@@ -1528,6 +1675,22 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
#ifdef NEED_AP_MLME
dfs_offload:
#endif /* NEED_AP_MLME */
+
+#ifdef CONFIG_FST
+ if (hapd->iconf->fst_cfg.group_id[0]) {
+ struct fst_wpa_obj iface_obj;
+
+ fst_hostapd_fill_iface_obj(hapd, &iface_obj);
+ iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr,
+ &iface_obj, &hapd->iconf->fst_cfg);
+ if (!iface->fst) {
+ wpa_printf(MSG_ERROR, "Could not attach to FST %s",
+ hapd->iconf->fst_cfg.group_id);
+ goto fail;
+ }
+ }
+#endif /* CONFIG_FST */
+
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
@@ -1544,6 +1707,12 @@ fail:
wpa_printf(MSG_ERROR, "Interface initialization failed");
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
+#ifdef CONFIG_FST
+ if (iface->fst) {
+ fst_detach(iface->fst);
+ iface->fst = NULL;
+ }
+#endif /* CONFIG_FST */
if (iface->interfaces && iface->interfaces->terminate_on_error)
eloop_terminate();
return -1;
@@ -1643,6 +1812,13 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
iface->wait_channel_update = 0;
+#ifdef CONFIG_FST
+ if (iface->fst) {
+ fst_detach(iface->fst);
+ iface->fst = NULL;
+ }
+#endif /* CONFIG_FST */
+
for (j = iface->num_bss - 1; j >= 0; j--)
hostapd_bss_deinit(iface->bss[j]);
}
@@ -2029,7 +2205,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)
static struct hostapd_config *
hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
- const char *ctrl_iface)
+ const char *ctrl_iface, const char *driver)
{
struct hostapd_bss_config *bss;
struct hostapd_config *conf;
@@ -2042,6 +2218,21 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
return NULL;
}
+ if (driver) {
+ int j;
+
+ for (j = 0; wpa_drivers[j]; j++) {
+ if (os_strcmp(driver, wpa_drivers[j]->name) == 0) {
+ conf->driver = wpa_drivers[j];
+ goto skip;
+ }
+ }
+
+ wpa_printf(MSG_ERROR,
+ "Invalid/unknown driver '%s' - registering the default driver",
+ driver);
+ }
+
conf->driver = wpa_drivers[0];
if (conf->driver == NULL) {
wpa_printf(MSG_ERROR, "No driver wrappers registered!");
@@ -2049,6 +2240,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
return NULL;
}
+skip:
bss = conf->last_bss = conf->bss[0];
os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
@@ -2209,8 +2401,14 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
if (conf && conf->bss)
os_strlcpy(conf->bss[0]->iface, buf,
sizeof(conf->bss[0]->iface));
- } else
- conf = hostapd_config_alloc(interfaces, buf, ptr);
+ } else {
+ char *driver = os_strchr(ptr, ' ');
+
+ if (driver)
+ *driver++ = '\0';
+ conf = hostapd_config_alloc(interfaces, buf, ptr, driver);
+ }
+
if (conf == NULL || conf->bss == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
"for configuration", __func__);
@@ -2722,4 +2920,43 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
hostapd_enable_iface(iface);
}
+
+struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
+ const char *ifname)
+{
+ size_t i, j;
+
+ for (i = 0; i < interfaces->count; i++) {
+ struct hostapd_iface *iface = interfaces->iface[i];
+
+ for (j = 0; j < iface->num_bss; j++) {
+ struct hostapd_data *hapd = iface->bss[j];
+
+ if (os_strcmp(ifname, hapd->conf->iface) == 0)
+ return hapd;
+ }
+ }
+
+ return NULL;
+}
+
#endif /* NEED_AP_MLME */
+
+
+void hostapd_periodic_iface(struct hostapd_iface *iface)
+{
+ size_t i;
+
+ ap_list_timer(iface);
+
+ for (i = 0; i < iface->num_bss; i++) {
+ struct hostapd_data *hapd = iface->bss[i];
+
+ if (!hapd->started)
+ continue;
+
+#ifndef CONFIG_NO_RADIUS
+ hostapd_acl_expire(hapd);
+#endif /* CONFIG_NO_RADIUS */
+ }
+}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 75cc24edb665..dcf51f00f78d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -41,6 +41,7 @@ struct hapd_interfaces {
size_t count;
int global_ctrl_sock;
+ struct wpa_ctrl_dst *global_ctrl_dst;
char *global_iface_path;
char *global_iface_name;
#ifndef CONFIG_NATIVE_WINDOWS
@@ -49,6 +50,9 @@ struct hapd_interfaces {
struct hostapd_iface **iface;
size_t terminate_on_error;
+#ifndef CONFIG_NO_VLAN
+ struct dynamic_iface *vlan_priv;
+#endif /* CONFIG_NO_VLAN */
};
enum hostapd_chan_status {
@@ -265,6 +269,7 @@ struct hostapd_data {
/** Key used for generating SAE anti-clogging tokens */
u8 sae_token_key[8];
struct os_reltime last_sae_token_key_update;
+ int dot11RSNASAERetransPeriod; /* msec */
#endif /* CONFIG_SAE */
#ifdef CONFIG_TESTING_OPTIONS
@@ -276,6 +281,12 @@ struct hostapd_data {
};
+struct hostapd_sta_info {
+ struct dl_list list;
+ u8 addr[ETH_ALEN];
+ struct os_reltime last_seen;
+};
+
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
@@ -305,6 +316,10 @@ struct hostapd_iface {
unsigned int wait_channel_update:1;
unsigned int cac_started:1;
+#ifdef CONFIG_FST
+ struct fst_iface *fst;
+ const struct wpabuf *fst_ies;
+#endif /* CONFIG_FST */
/*
* When set, indicates that the driver will handle the AP
@@ -400,6 +415,9 @@ struct hostapd_iface {
void (*scan_cb)(struct hostapd_iface *iface);
int num_ht40_scan_tries;
+
+ struct dl_list sta_seen; /* struct hostapd_sta_info */
+ unsigned int num_sta_seen;
};
/* hostapd.c */
@@ -437,6 +455,7 @@ void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
+void hostapd_periodic_iface(struct hostapd_iface *iface);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
@@ -464,4 +483,12 @@ const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
size_t identity_len, int phase2);
+struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
+ const char *ifname);
+
+#ifdef CONFIG_FST
+void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
+ struct fst_wpa_obj *iface_obj);
+#endif /* CONFIG_FST */
+
#endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 05431d32c205..fc8786dc311c 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -260,8 +260,14 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
- if (res == 2)
- ieee80211n_switch_pri_sec(iface);
+ if (res == 2) {
+ if (iface->conf->no_pri_sec_switch) {
+ wpa_printf(MSG_DEBUG,
+ "Cannot switch PRI/SEC channels due to local constraint");
+ } else {
+ ieee80211n_switch_pri_sec(iface);
+ }
+ }
return !!res;
}
@@ -347,8 +353,13 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
sec_freq = pri_freq + 20;
else
sec_freq = pri_freq - 20;
- affected_start = (pri_freq + sec_freq) / 2 - 25;
- affected_end = (pri_freq + sec_freq) / 2 + 25;
+ /*
+ * Note: Need to find the PRI channel also in cases where the affected
+ * channel is the SEC channel of a 40 MHz BSS, so need to include the
+ * scanning coverage here to be 40 MHz from the center frequency.
+ */
+ affected_start = (pri_freq + sec_freq) / 2 - 40;
+ affected_end = (pri_freq + sec_freq) / 2 + 40;
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
affected_start, affected_end);
@@ -510,7 +521,11 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
- if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ /*
+ * Driver ACS chosen channel may not be HT40 due to internal driver
+ * restrictions.
+ */
+ if (!iface->conf->acs && (conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
!(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [HT40*]");
@@ -717,6 +732,15 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
int ret;
if (!iface->conf->ieee80211n)
return 0;
+
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211B &&
+ iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G &&
+ (iface->conf->ht_capab & HT_CAP_INFO_DSSS_CCK40MHZ)) {
+ wpa_printf(MSG_DEBUG,
+ "Disable HT capability [DSSS_CCK-40] on 5 GHz band");
+ iface->conf->ht_capab &= ~HT_CAP_INFO_DSSS_CCK40MHZ;
+ }
+
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#ifdef CONFIG_IEEE80211AC
@@ -740,6 +764,9 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int i;
struct hostapd_channel_data *chan;
+ if (!iface->current_mode)
+ return 0;
+
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->chan != channel)
@@ -801,6 +828,12 @@ hostapd_check_chans(struct hostapd_iface *iface)
static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
{
+ if (!iface->current_mode) {
+ hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Hardware does not support configured mode");
+ return;
+ }
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
@@ -891,14 +924,18 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
}
if (iface->current_mode == NULL) {
- wpa_printf(MSG_ERROR, "Hardware does not support configured "
- "mode");
- hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_WARNING,
- "Hardware does not support configured mode "
- "(%d) (hw_mode in hostapd.conf)",
- (int) iface->conf->hw_mode);
- return -2;
+ if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
+ !(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
+ {
+ wpa_printf(MSG_ERROR,
+ "Hardware does not support configured mode");
+ hostapd_logger(iface->bss[0], NULL,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_WARNING,
+ "Hardware does not support configured mode (%d) (hw_mode in hostapd.conf)",
+ (int) iface->conf->hw_mode);
+ return -2;
+ }
}
switch (hostapd_check_chans(iface)) {
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 0f67ab8e5f37..ca7f22ba205b 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -36,6 +36,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
return -1;
}
+static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
+{
+ return -1;
+}
+
static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
return -100;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 89911b1fdd42..7bb18c01d1a1 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -23,6 +23,7 @@
#include "radius/radius_client.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
+#include "fst/fst.h"
#include "hostapd.h"
#include "beacon.h"
#include "ieee802_11_auth.h"
@@ -38,6 +39,7 @@
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "wnm_ap.h"
+#include "hw_features.h"
#include "ieee802_11.h"
#include "dfs.h"
@@ -132,8 +134,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
}
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
- int probe)
+u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
int privacy;
@@ -166,20 +167,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
privacy = 1;
#endif /* CONFIG_HS20 */
- if (sta) {
- int policy, def_klen;
- if (probe && sta->ssid_probe) {
- policy = sta->ssid_probe->security_policy;
- def_klen = sta->ssid_probe->wep.default_len;
- } else {
- policy = sta->ssid->security_policy;
- def_klen = sta->ssid->wep.default_len;
- }
- privacy = policy != SECURITY_PLAINTEXT;
- if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
- privacy = 0;
- }
-
if (privacy)
capab |= WLAN_CAPABILITY_PRIVACY;
@@ -206,6 +193,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
}
+#ifndef CONFIG_NO_RC4
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
u16 auth_transaction, const u8 *challenge,
int iswep)
@@ -259,6 +247,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
}
+#endif /* CONFIG_NO_RC4 */
static void send_auth_reply(struct hostapd_data *hapd,
@@ -328,7 +317,6 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
#ifdef CONFIG_SAE
-#define dot11RSNASAERetransPeriod 40 /* msec */
#define dot11RSNASAESync 5 /* attempts */
@@ -511,12 +499,14 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
switch (sta->sae->state) {
case SAE_COMMITTED:
ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
- eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ eloop_register_timeout(0,
+ hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
break;
case SAE_CONFIRMED:
ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
- eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ eloop_register_timeout(0,
+ hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
break;
default:
@@ -542,7 +532,7 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
return;
eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
- eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
}
@@ -624,7 +614,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 0);
if (ret)
return ret;
@@ -784,6 +774,12 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
&token_len, hapd->conf->sae_groups);
+ if (resp == SAE_SILENTLY_DISCARD) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Drop commit message from " MACSTR " due to reflection attack",
+ MAC2STR(sta->addr));
+ return;
+ }
if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
@@ -934,6 +930,16 @@ static void handle_auth(struct hostapd_data *hapd,
challenge ? " challenge" : "",
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
+#ifdef CONFIG_NO_RC4
+ if (auth_alg == WLAN_AUTH_SHARED_KEY) {
+ wpa_printf(MSG_INFO,
+ "Unsupported authentication algorithm (%d)",
+ auth_alg);
+ resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+ goto fail;
+ }
+#endif /* CONFIG_NO_RC4 */
+
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
goto fail;
@@ -972,6 +978,61 @@ static void handle_auth(struct hostapd_data *hapd,
goto fail;
}
+ if (hapd->conf->no_auth_if_seen_on) {
+ struct hostapd_data *other;
+
+ other = sta_track_seen_on(hapd->iface, mgmt->sa,
+ hapd->conf->no_auth_if_seen_on);
+ if (other) {
+ u8 *pos;
+ u32 info;
+ u8 op_class, channel, phytype;
+
+ wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
+ MACSTR " since STA has been seen on %s",
+ hapd->conf->iface, MAC2STR(mgmt->sa),
+ hapd->conf->no_auth_if_seen_on);
+
+ resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
+ pos = &resp_ies[0];
+ *pos++ = WLAN_EID_NEIGHBOR_REPORT;
+ *pos++ = 13;
+ os_memcpy(pos, other->own_addr, ETH_ALEN);
+ pos += ETH_ALEN;
+ info = 0; /* TODO: BSSID Information */
+ WPA_PUT_LE32(pos, info);
+ pos += 4;
+ if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
+ phytype = 8; /* dmg */
+ else if (other->iconf->ieee80211ac)
+ phytype = 9; /* vht */
+ else if (other->iconf->ieee80211n)
+ phytype = 7; /* ht */
+ else if (other->iconf->hw_mode ==
+ HOSTAPD_MODE_IEEE80211A)
+ phytype = 4; /* ofdm */
+ else if (other->iconf->hw_mode ==
+ HOSTAPD_MODE_IEEE80211G)
+ phytype = 6; /* erp */
+ else
+ phytype = 5; /* hrdsss */
+ if (ieee80211_freq_to_channel_ext(
+ hostapd_hw_get_freq(other,
+ other->iconf->channel),
+ other->iconf->secondary_channel,
+ other->iconf->ieee80211ac,
+ &op_class, &channel) == NUM_HOSTAPD_MODES) {
+ op_class = 0;
+ channel = other->iconf->channel;
+ }
+ *pos++ = op_class;
+ *pos++ = channel;
+ *pos++ = phytype;
+ resp_ies_len = pos - &resp_ies[0];
+ goto fail;
+ }
+ }
+
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
&acct_interim_interval, &vlan_id,
@@ -1081,6 +1142,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta);
break;
+#ifndef CONFIG_NO_RC4
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
fc & WLAN_FC_ISWEP);
@@ -1094,6 +1156,7 @@ static void handle_auth(struct hostapd_data *hapd,
resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
}
break;
+#endif /* CONFIG_NO_RC4 */
#ifdef CONFIG_IEEE80211R
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
@@ -1297,8 +1360,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
#ifdef CONFIG_IEEE80211N
- resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
- elems.ht_capabilities_len);
+ resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
@@ -1311,14 +1373,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
- elems.vht_capabilities_len);
- if (resp != WLAN_STATUS_SUCCESS)
- return resp;
+ if (hapd->iconf->ieee80211ac) {
+ resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
- resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
- if (resp != WLAN_STATUS_SUCCESS)
- return resp;
+ resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
!(sta->flags & WLAN_STA_VHT)) {
@@ -1546,6 +1609,14 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
sta->hs20_ie = NULL;
#endif /* CONFIG_HS20 */
+#ifdef CONFIG_FST
+ wpabuf_free(sta->mb_ies);
+ if (hapd->iface->fst)
+ sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
+ else
+ sta->mb_ies = NULL;
+#endif /* CONFIG_FST */
+
return WLAN_STATUS_SUCCESS;
}
@@ -1594,7 +1665,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
send_len = IEEE80211_HDRLEN;
send_len += sizeof(reply->u.assoc_resp);
reply->u.assoc_resp.capab_info =
- host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
+ host_to_le16(hostapd_own_capab_info(hapd));
reply->u.assoc_resp.status_code = host_to_le16(status_code);
reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
/* Supported rates */
@@ -1634,6 +1705,14 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies) {
+ os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
+ wpabuf_len(hapd->iface->fst_ies));
+ p += wpabuf_len(hapd->iface->fst_ies);
+ }
+#endif /* CONFIG_FST */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
p = hostapd_eid_vendor_vht(hapd, p);
@@ -2112,10 +2191,20 @@ static int handle_action(struct hostapd_data *hapd,
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
return 1;
#endif /* CONFIG_WNM */
+#ifdef CONFIG_FST
+ case WLAN_ACTION_FST:
+ if (hapd->iface->fst)
+ fst_rx_action(hapd->iface->fst, mgmt, len);
+ else
+ wpa_printf(MSG_DEBUG,
+ "FST: Ignore FST Action frame - no FST attached");
+ return 1;
+#endif /* CONFIG_FST */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
#ifdef CONFIG_IEEE80211N
- if (mgmt->u.action.u.public_action.action ==
+ if (len >= IEEE80211_HDRLEN + 2 &&
+ mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
wpa_printf(MSG_DEBUG,
"HT20/40 coex mgmt frame received from STA "
@@ -2248,6 +2337,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
return 0;
}
+ if (hapd->iconf->track_sta_max_num)
+ sta_track_add(hapd->iface, mgmt->sa);
+
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
@@ -2335,7 +2427,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
char *ifname_wds)
{
int i;
- struct hostapd_ssid *ssid = sta->ssid;
+ struct hostapd_ssid *ssid = &hapd->conf->ssid;
if (hapd->conf->ieee802_1x || hapd->conf->wpa)
return;
@@ -2473,11 +2565,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
* so bind it to the selected VLAN interface now, since the
* interface selection is not going to change anymore.
*/
- if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+ if (ap_sta_bind_vlan(hapd, sta) < 0)
return;
} else if (sta->vlan_id) {
/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
- if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+ if (ap_sta_bind_vlan(hapd, sta) < 0)
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 41c27d906e72..44c1bff364ac 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -14,6 +14,7 @@ struct hostapd_data;
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
+struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@@ -40,8 +41,7 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
return 0;
}
#endif /* NEED_AP_MLME */
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
- int probe);
+u16 hostapd_own_capab_info(struct hostapd_data *hapd);
void ap_ht2040_timeout(void *eloop_data, void *user_data);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
@@ -62,7 +62,7 @@ void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *ht_capab, size_t ht_capab_len);
+ const u8 *ht_capab);
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ie, size_t len);
@@ -70,7 +70,7 @@ void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *vht_capab, size_t vht_capab_len);
+ const u8 *vht_capab);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 56c3ce0313d4..531a67da412c 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -399,19 +399,15 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
/**
* hostapd_acl_expire - ACL cache expiration callback
- * @eloop_ctx: struct hostapd_data *
- * @timeout_ctx: Not used
+ * @hapd: struct hostapd_data *
*/
-static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
+void hostapd_acl_expire(struct hostapd_data *hapd)
{
- struct hostapd_data *hapd = eloop_ctx;
struct os_reltime now;
os_get_reltime(&now);
hostapd_acl_expire_cache(hapd, &now);
hostapd_acl_expire_queries(hapd, &now);
-
- eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
@@ -561,6 +557,19 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
!cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
+
+ if (cache->vlan_id &&
+ !hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
+ hostapd_logger(hapd, query->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN ID %d received from RADIUS server",
+ cache->vlan_id);
+ cache->vlan_id = 0;
+ }
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
+ !cache->vlan_id)
+ cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
@@ -602,8 +611,6 @@ int hostapd_acl_init(struct hostapd_data *hapd)
if (radius_client_register(hapd->radius, RADIUS_AUTH,
hostapd_acl_recv_radius, hapd))
return -1;
-
- eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
#endif /* CONFIG_NO_RADIUS */
return 0;
@@ -619,8 +626,6 @@ void hostapd_acl_deinit(struct hostapd_data *hapd)
struct hostapd_acl_query_data *query, *prev;
#ifndef CONFIG_NO_RADIUS
- eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
-
hostapd_acl_cache_free(hapd->acl_cache);
#endif /* CONFIG_NO_RADIUS */
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index 2bc1065a226c..b66f244b3ebc 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -24,5 +24,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
+void hostapd_acl_expire(struct hostapd_data *hapd);
#endif /* IEEE802_11_AUTH_H */
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 4b0653de95db..11fde2a26394 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -209,7 +209,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
struct hostapd_iface *iface = hapd->iface;
struct ieee80211_2040_bss_coex_ie *bc_ie;
struct ieee80211_2040_intol_chan_report *ic_report;
- int is_ht_allowed = 1;
+ int is_ht40_allowed = 1;
int i;
const u8 *start = (const u8 *) mgmt;
const u8 *data = start + IEEE80211_HDRLEN + 2;
@@ -242,7 +242,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"20 MHz BSS width request bit is set in BSS coexistence information field");
- is_ht_allowed = 0;
+ is_ht40_allowed = 0;
}
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
@@ -250,7 +250,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"40 MHz intolerant bit is set in BSS coexistence information field");
- is_ht_allowed = 0;
+ is_ht40_allowed = 0;
}
if (start + len - data >= 3 &&
@@ -276,13 +276,13 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
HOSTAPD_LEVEL_DEBUG,
"20_40_INTOLERANT channel %d reported",
chan);
- is_ht_allowed = 0;
+ is_ht40_allowed = 0;
}
}
- wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
- is_ht_allowed, iface->num_sta_ht40_intolerant);
+ wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
+ is_ht40_allowed, iface->num_sta_ht40_intolerant);
- if (!is_ht_allowed &&
+ if (!is_ht40_allowed &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
if (iface->conf->secondary_channel) {
hostapd_logger(hapd, mgmt->sa,
@@ -310,12 +310,15 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *ht_capab, size_t ht_capab_len)
+ const u8 *ht_capab)
{
- /* Disable HT caps for STAs associated to no-HT BSSes. */
+ /*
+ * Disable HT caps for STAs associated to no-HT BSSes, or for stations
+ * that did not specify a valid WMM IE in the (Re)Association Request
+ * frame.
+ */
if (!ht_capab ||
- ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
- hapd->conf->disable_11n) {
+ !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 171538ad74a7..5bf1b5d72002 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -132,11 +132,10 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *vht_capab, size_t vht_capab_len)
+ const u8 *vht_capab)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
- vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
hapd->conf->disable_11ac ||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 79dc0f957488..0f2d428cf752 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -125,6 +125,9 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_NO_RC4
+
static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
struct sta_info *sta,
int idx, int broadcast,
@@ -204,7 +207,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
}
-void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
+static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_authenticator *eapol = hapd->eapol_auth;
struct eapol_state_machine *sm = sta->eapol_sm;
@@ -259,6 +262,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
}
}
+#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_FIPS */
+
const char *radius_mode_txt(struct hostapd_data *hapd)
{
@@ -346,7 +352,8 @@ static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
return -1;
}
- suite = wpa_cipher_to_suite((hapd->conf->wpa & 0x2) ?
+ suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) ||
+ hapd->conf->osen) ?
WPA_PROTO_RSN : WPA_PROTO_WPA,
hapd->conf->wpa_group);
if (!hostapd_config_get_radius_attr(req_attr,
@@ -453,7 +460,7 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211R */
- if (hapd->conf->wpa && sta->wpa_sm &&
+ if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
return -1;
@@ -599,7 +606,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
goto fail;
}
- if (eap && !radius_msg_add_eap(msg, eap, len)) {
+ if (!radius_msg_add_eap(msg, eap, len)) {
wpa_printf(MSG_INFO, "Could not add EAP-Message");
goto fail;
}
@@ -1108,8 +1115,6 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
- int old_vlanid;
-
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
"PMK from PMKSA cache - skip IEEE 802.1X/EAP");
@@ -1123,11 +1128,8 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->authFail = FALSE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
- old_vlanid = sta->vlan_id;
pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
- if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- sta->vlan_id = 0;
- ap_sta_bind_vlan(hapd, sta, old_vlanid);
+ ap_sta_bind_vlan(hapd, sta);
} else {
if (reassoc) {
/*
@@ -1290,7 +1292,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
struct sta_info *sta,
struct radius_msg *msg)
{
- u8 *class;
+ u8 *attr_class;
size_t class_len;
struct eapol_state_machine *sm = sta->eapol_sm;
int count, i;
@@ -1312,12 +1314,12 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
nclass_count = 0;
- class = NULL;
+ attr_class = NULL;
for (i = 0; i < count; i++) {
do {
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
- &class, &class_len,
- class) < 0) {
+ &attr_class, &class_len,
+ attr_class) < 0) {
i = count;
break;
}
@@ -1327,7 +1329,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
if (nclass[nclass_count].data == NULL)
break;
- os_memcpy(nclass[nclass_count].data, class, class_len);
+ os_memcpy(nclass[nclass_count].data, attr_class, class_len);
nclass[nclass_count].len = class_len;
nclass_count++;
}
@@ -1590,7 +1592,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct sta_info *sta;
u32 session_timeout = 0, termination_action, acct_interim_interval;
- int session_timeout_set, old_vlanid = 0;
+ int session_timeout_set, vlan_id = 0;
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
@@ -1657,20 +1659,27 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
- if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- sta->vlan_id = 0;
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ vlan_id = 0;
#ifndef CONFIG_NO_VLAN
- else {
- old_vlanid = sta->vlan_id;
- sta->vlan_id = radius_msg_get_vlanid(msg);
- }
- if (sta->vlan_id > 0 &&
- hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
+ else
+ vlan_id = radius_msg_get_vlanid(msg);
+ if (vlan_id > 0 &&
+ hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
- "VLAN ID %d", sta->vlan_id);
- } else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
+ "VLAN ID %d", vlan_id);
+ } else if (vlan_id > 0) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN ID %d received from RADIUS server",
+ vlan_id);
+ break;
+ } else if (hapd->conf->ssid.dynamic_vlan ==
+ DYNAMIC_VLAN_REQUIRED) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
@@ -1681,7 +1690,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
}
#endif /* CONFIG_NO_VLAN */
- if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
+ sta->vlan_id = vlan_id;
+ if ((sta->flags & WLAN_STA_ASSOC) &&
+ ap_sta_bind_vlan(hapd, sta) < 0)
break;
sta->session_timeout_set = !!session_timeout_set;
@@ -1926,10 +1937,11 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
struct hostapd_data *hapd = ctx;
const struct hostapd_eap_user *eap_user;
int i;
+ int rv = -1;
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
if (eap_user == NULL)
- return -1;
+ goto out;
os_memset(user, 0, sizeof(*user));
user->phase2 = phase2;
@@ -1941,7 +1953,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
- return -1;
+ goto out;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
@@ -1951,8 +1963,13 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
+ rv = 0;
- return 0;
+out:
+ if (rv)
+ wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
+
+ return rv;
}
@@ -2012,9 +2029,13 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
{
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_NO_RC4
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
ieee802_1x_tx_key(hapd, sta);
+#endif /* CONFIG_NO_RC4 */
+#endif /* CONFIG_FIPS */
}
@@ -2085,6 +2106,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
conf.erp = hapd->conf->eap_server_erp;
+ conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
@@ -2332,9 +2354,9 @@ void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
}
-static const char * bool_txt(Boolean bool)
+static const char * bool_txt(Boolean val)
{
- return bool ? "TRUE" : "FALSE";
+ return val ? "TRUE" : "FALSE";
}
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index de6e0e75fac3..14d69556993c 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -23,7 +23,6 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_free_station(struct sta_info *sta);
-void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
index b0d42dcd82c4..4a87721e2ecf 100644
--- a/src/ap/ndisc_snoop.c
+++ b/src/ap/ndisc_snoop.c
@@ -81,12 +81,24 @@ static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
}
+static void ucast_to_stas(struct hostapd_data *hapd, const u8 *buf, size_t len)
+{
+ struct sta_info *sta;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!(sta->flags & WLAN_STA_AUTHORIZED))
+ continue;
+ x_snoop_mcast_to_ucast_convert_send(hapd, sta, (u8 *) buf, len);
+ }
+}
+
+
static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
struct hostapd_data *hapd = ctx;
struct icmpv6_ndmsg *msg;
- struct in6_addr *saddr;
+ struct in6_addr saddr;
struct sta_info *sta;
int res;
char addrtxt[INET6_ADDRSTRLEN + 1];
@@ -101,25 +113,30 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
if (msg->opt_type != SOURCE_LL_ADDR)
return;
- saddr = &msg->ipv6h.ip6_src;
- if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
- saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
+ /*
+ * IPv6 header may not be 32-bit aligned in the buffer, so use
+ * a local copy to avoid unaligned reads.
+ */
+ os_memcpy(&saddr, &msg->ipv6h.ip6_src, sizeof(saddr));
+ if (!(saddr.s6_addr32[0] == 0 && saddr.s6_addr32[1] == 0 &&
+ saddr.s6_addr32[2] == 0 && saddr.s6_addr32[3] == 0)) {
if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
return;
sta = ap_get_sta(hapd, msg->opt_lladdr);
if (!sta)
return;
- if (sta_has_ip6addr(sta, saddr))
+ if (sta_has_ip6addr(sta, &saddr))
return;
- if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
- == NULL)
+ if (inet_ntop(AF_INET6, &saddr, addrtxt,
+ sizeof(addrtxt)) == NULL)
addrtxt[0] = '\0';
wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for "
MACSTR, addrtxt, MAC2STR(sta->addr));
- hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
- res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
+ hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &saddr);
+ res = hostapd_drv_br_add_ip_neigh(hapd, 6,
+ (u8 *) &saddr,
128, sta->addr);
if (res) {
wpa_printf(MSG_ERROR,
@@ -128,21 +145,17 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
return;
}
- if (sta_ip6addr_add(sta, saddr))
+ if (sta_ip6addr_add(sta, &saddr))
return;
}
break;
case ROUTER_ADVERTISEMENT:
- if (!hapd->conf->disable_dgaf)
- return;
- /* fall through */
+ if (hapd->conf->disable_dgaf)
+ ucast_to_stas(hapd, buf, len);
+ break;
case NEIGHBOR_ADVERTISEMENT:
- for (sta = hapd->sta_list; sta; sta = sta->next) {
- if (!(sta->flags & WLAN_STA_AUTHORIZED))
- continue;
- x_snoop_mcast_to_ucast_convert_send(hapd, sta,
- (u8 *) buf, len);
- }
+ if (hapd->conf->na_mcast_to_ucast)
+ ucast_to_stas(hapd, buf, len);
break;
default:
break;
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 7e75e1a61e1a..d64307ccfd08 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -16,6 +16,7 @@
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
+#include "fst/fst.h"
#include "hostapd.h"
#include "accounting.h"
#include "ieee802_1x.h"
@@ -171,6 +172,19 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
+#ifndef CONFIG_NO_VLAN
+ if (sta->vlan_id_bound) {
+ /*
+ * Need to remove the STA entry before potentially removing the
+ * VLAN.
+ */
+ if (hapd->iface->driver_ap_teardown &&
+ !(sta->flags & WLAN_STA_PREAUTH))
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ }
+#endif /* CONFIG_NO_VLAN */
+
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
@@ -283,6 +297,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
wpabuf_free(sta->hs20_ie);
+#ifdef CONFIG_FST
+ wpabuf_free(sta->mb_ies);
+#endif /* CONFIG_FST */
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
@@ -619,7 +636,6 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
hapd->sta_list = sta;
hapd->num_sta++;
ap_sta_hash_add(hapd, sta);
- sta->ssid = &hapd->conf->ssid;
ap_sta_remove_in_other_bss(hapd, sta);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
dl_list_init(&sta->ip6addr);
@@ -768,26 +784,19 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
#endif /* CONFIG_WPS */
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
- int old_vlanid)
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
{
#ifndef CONFIG_NO_VLAN
const char *iface;
struct hostapd_vlan *vlan = NULL;
int ret;
-
- /*
- * Do not proceed furthur if the vlan id remains same. We do not want
- * duplicate dynamic vlan entries.
- */
- if (sta->vlan_id == old_vlanid)
- return 0;
+ int old_vlanid = sta->vlan_id_bound;
iface = hapd->conf->iface;
- if (sta->ssid->vlan[0])
- iface = sta->ssid->vlan;
+ if (hapd->conf->ssid.vlan[0])
+ iface = hapd->conf->ssid.vlan;
- if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
else if (sta->vlan_id > 0) {
struct hostapd_vlan *wildcard_vlan = NULL;
@@ -805,6 +814,14 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
iface = vlan->ifname;
}
+ /*
+ * Do not increment ref counters if the VLAN ID remains same, but do
+ * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
+ * have been called before.
+ */
+ if (sta->vlan_id == old_vlanid)
+ goto skip_counting;
+
if (sta->vlan_id > 0 && vlan == NULL) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
@@ -825,7 +842,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
}
iface = vlan->ifname;
- if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+ if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
@@ -838,7 +855,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
"interface '%s'", iface);
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
- if (sta->vlan_id > 0) {
+ if (vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan++;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
@@ -852,7 +869,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
* configuration for the case where hostapd did not yet know
* which keys are to be used when the interface was added.
*/
- if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+ if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
@@ -862,6 +879,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
}
}
+ /* ref counters have been increased, so mark the station */
+ sta->vlan_id_bound = sta->vlan_id;
+
+skip_counting:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
"'%s'", iface);
@@ -876,10 +897,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
"entry to vlan_id=%d", sta->vlan_id);
}
-done:
/* During 1x reauth, if the vlan id changes, then remove the old id. */
- if (old_vlanid > 0)
+ if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
vlan_remove_dynamic(hapd, old_vlanid);
+done:
return ret;
#else /* CONFIG_NO_VLAN */
@@ -1043,6 +1064,16 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED "%s", buf);
}
+
+#ifdef CONFIG_FST
+ if (hapd->iface->fst) {
+ if (authorized)
+ fst_notify_peer_connected(hapd->iface->fst, sta->addr);
+ else
+ fst_notify_peer_disconnected(hapd->iface->fst,
+ sta->addr);
+ }
+#endif /* CONFIG_FST */
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 57551ab17d5d..420d64e5793b 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -117,10 +117,8 @@ struct sta_info {
struct wpa_state_machine *wpa_sm;
struct rsn_preauth_interface *preauth_iface;
- struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
- struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
-
- int vlan_id;
+ int vlan_id; /* 0: none, >0: VID */
+ int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
@@ -155,6 +153,9 @@ struct sta_info {
struct wpabuf *hs20_deauth_req;
char *hs20_session_info_url;
int hs20_disassoc_timer;
+#ifdef CONFIG_FST
+ struct wpabuf *mb_ies; /* MB IEs from (Re)Association Request */
+#endif /* CONFIG_FST */
struct os_reltime connected_time;
@@ -218,8 +219,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
int ap_sta_wps_cancel(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx);
#endif /* CONFIG_WPS */
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
- int old_vlanid);
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 931968c84b0e..fcb371bec283 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
+#include "fst/fst.h"
#include "sta_info.h"
#include "hostapd.h"
@@ -55,10 +56,20 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
ohapd = iface->bss[j];
if (ohapd == data->hapd)
continue;
+#ifdef CONFIG_FST
+ /* Don't prune STAs belong to same FST */
+ if (ohapd->iface->fst &&
+ data->hapd->iface->fst &&
+ fst_are_ifaces_aggregated(ohapd->iface->fst,
+ data->hapd->iface->fst))
+ continue;
+#endif /* CONFIG_FST */
osta = ap_get_sta(ohapd, data->addr);
if (!osta)
continue;
+ wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR,
+ ohapd->conf->iface, MAC2STR(osta->addr));
ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
}
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index dc6501997db0..fd1c8ddacee6 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -9,6 +9,13 @@
*/
#include "utils/includes.h"
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
#include "utils/common.h"
#include "hostapd.h"
@@ -20,12 +27,6 @@
#ifdef CONFIG_FULL_DYNAMIC_VLAN
-#include <net/if.h>
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bridge.h>
-
#include "drivers/priv_netlink.h"
#include "utils/eloop.h"
@@ -34,6 +35,90 @@ struct full_dynamic_vlan {
int s; /* socket on which to listen for new/removed interfaces. */
};
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+
+struct dynamic_iface {
+ char ifname[IFNAMSIZ + 1];
+ int usage;
+ int clean;
+ struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+ int clean)
+{
+ struct dynamic_iface *next, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ }
+
+ if (next) {
+ next->usage++;
+ next->clean |= clean;
+ return;
+ }
+
+ if (!clean)
+ return;
+
+ next = os_zalloc(sizeof(*next));
+ if (!next)
+ return;
+ os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+ next->usage = 1;
+ next->clean = clean;
+ next->next = *dynamic_ifaces;
+ *dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+ struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+ int clean;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ prev = next;
+ }
+
+ if (!next)
+ return 0;
+
+ next->usage--;
+ if (next->usage)
+ return 0;
+
+ if (prev)
+ prev->next = next->next;
+ else
+ *dynamic_ifaces = next->next;
+ clean = next->clean;
+ os_free(next);
+
+ return clean;
+}
+
static int ifconfig_helper(const char *if_name, int up)
{
@@ -481,11 +566,13 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
+ int clean;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0) {
+ if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
+ vlan->configured = 1;
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
@@ -500,8 +587,8 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
"brvlan%d", vlan->vlan_id);
}
- if (!br_addbr(br_name))
- vlan->clean |= DVLAN_CLEAN_BR;
+ dyn_iface_get(hapd, br_name,
+ br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
ifconfig_up(br_name);
@@ -517,13 +604,16 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
+ clean = 0;
ifconfig_up(tagged_interface);
if (!vlan_add(tagged_interface, vlan->vlan_id,
vlan_ifname))
- vlan->clean |= DVLAN_CLEAN_VLAN;
+ clean |= DVLAN_CLEAN_VLAN;
if (!br_addif(br_name, vlan_ifname))
- vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
+ clean |= DVLAN_CLEAN_VLAN_PORT;
+
+ dyn_iface_get(hapd, vlan_ifname, clean);
ifconfig_up(vlan_ifname);
}
@@ -547,13 +637,15 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
+ int clean;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
first = prev = vlan;
while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0) {
+ if (os_strcmp(ifname, vlan->ifname) == 0 &&
+ vlan->configured) {
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
hapd->conf->vlan_bridge,
@@ -581,20 +673,27 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
os_snprintf(vlan_ifname,
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
- if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
+
+ clean = dyn_iface_put(hapd, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN_PORT)
br_delif(br_name, vlan_ifname);
- ifconfig_down(vlan_ifname);
- if (vlan->clean & DVLAN_CLEAN_VLAN)
+ if (clean & DVLAN_CLEAN_VLAN) {
+ ifconfig_down(vlan_ifname);
vlan_rem(vlan_ifname);
+ }
}
- if ((vlan->clean & DVLAN_CLEAN_BR) &&
+ clean = dyn_iface_put(hapd, br_name);
+ if ((clean & DVLAN_CLEAN_BR) &&
br_getnumports(br_name) == 0) {
ifconfig_down(br_name);
br_delbr(br_name);
}
+ }
+ if (os_strcmp(ifname, vlan->ifname) == 0) {
if (vlan == first) {
hapd->conf->vlan = vlan->next;
} else {
@@ -651,6 +750,11 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
if (!ifname[0])
return;
+ if (del && if_nametoindex(ifname)) {
+ /* interface still exists, race condition ->
+ * iface has just been recreated */
+ return;
+ }
wpa_printf(MSG_DEBUG,
"VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
@@ -778,8 +882,7 @@ static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
- struct hostapd_ssid *mssid, const char *dyn_vlan)
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
{
int i;
@@ -789,10 +892,11 @@ int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
* functions for setting up dynamic broadcast keys. */
for (i = 0; i < 4; i++) {
- if (mssid->wep.key[i] &&
+ if (hapd->conf->ssid.wep.key[i] &&
hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
- i == mssid->wep.idx, NULL, 0,
- mssid->wep.key[i], mssid->wep.len[i]))
+ i == hapd->conf->ssid.wep.idx, NULL, 0,
+ hapd->conf->ssid.wep.key[i],
+ hapd->conf->ssid.wep.len[i]))
{
wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
"encryption for dynamic VLAN");
@@ -953,7 +1057,8 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
return 1;
- wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
+ wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
+ __func__, hapd->conf->iface, vlan_id);
vlan = hapd->conf->vlan;
while (vlan) {
@@ -967,8 +1072,12 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
if (vlan == NULL)
return 1;
- if (vlan->dynamic_vlan == 0)
+ if (vlan->dynamic_vlan == 0) {
hostapd_vlan_if_remove(hapd, vlan->ifname);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ vlan_dellink(vlan->ifname, hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ }
return 0;
}
diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h
index 781eaac441be..fc39443e5d34 100644
--- a/src/ap/vlan_init.h
+++ b/src/ap/vlan_init.h
@@ -18,7 +18,6 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
int vlan_id);
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
- struct hostapd_ssid *mssid,
const char *dyn_vlan);
#else /* CONFIG_NO_VLAN */
static inline int vlan_init(struct hostapd_data *hapd)
@@ -43,7 +42,6 @@ static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
}
static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
- struct hostapd_ssid *mssid,
const char *dyn_vlan)
{
return -1;
diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
index cc54051b1eca..d4e0efb9b024 100644
--- a/src/ap/vlan_util.c
+++ b/src/ap/vlan_util.c
@@ -31,7 +31,7 @@
*/
int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
- int ret = -1;
+ int err, ret = -1;
struct nl_sock *handle = NULL;
struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
@@ -58,14 +58,18 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
goto vlan_add_error;
}
- if (nl_connect(handle, NETLINK_ROUTE) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+ err = nl_connect(handle, NETLINK_ROUTE);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
+ nl_geterror(err));
goto vlan_add_error;
}
- if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+ err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
+ if (err < 0) {
cache = NULL;
- wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+ wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
+ nl_geterror(err));
goto vlan_add_error;
}
@@ -92,23 +96,29 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
goto vlan_add_error;
}
- if (rtnl_link_set_type(rlink, "vlan") < 0) {
- wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
+ err = rtnl_link_set_type(rlink, "vlan");
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s",
+ nl_geterror(err));
goto vlan_add_error;
}
rtnl_link_set_link(rlink, if_idx);
rtnl_link_set_name(rlink, vlan_if_name);
- if (rtnl_link_vlan_set_id(rlink, vid) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
+ err = rtnl_link_vlan_set_id(rlink, vid);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s",
+ nl_geterror(err));
goto vlan_add_error;
}
- if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) {
+ err = rtnl_link_add(handle, rlink, NLM_F_CREATE);
+ if (err < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
- "vlan %d on %s (%d)",
- vlan_if_name, vid, if_name, if_idx);
+ "vlan %d on %s (%d): %s",
+ vlan_if_name, vid, if_name, if_idx,
+ nl_geterror(err));
goto vlan_add_error;
}
@@ -127,7 +137,7 @@ vlan_add_error:
int vlan_rem(const char *if_name)
{
- int ret = -1;
+ int err, ret = -1;
struct nl_sock *handle = NULL;
struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
@@ -140,14 +150,18 @@ int vlan_rem(const char *if_name)
goto vlan_rem_error;
}
- if (nl_connect(handle, NETLINK_ROUTE) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+ err = nl_connect(handle, NETLINK_ROUTE);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
+ nl_geterror(err));
goto vlan_rem_error;
}
- if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+ err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
+ if (err < 0) {
cache = NULL;
- wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+ wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
+ nl_geterror(err));
goto vlan_rem_error;
}
@@ -158,9 +172,10 @@ int vlan_rem(const char *if_name)
goto vlan_rem_error;
}
- if (rtnl_link_delete(handle, rlink) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s",
- if_name);
+ err = rtnl_link_delete(handle, rlink);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s",
+ if_name, nl_geterror(err));
goto vlan_rem_error;
}
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 6d4177c2a847..314e244bc956 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -274,6 +274,9 @@ void hostapd_wmm_action(struct hostapd_data *hapd,
return;
}
+ if (left < 0)
+ return; /* not a valid WMM Action frame */
+
/* extract the tspec info element */
if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 9c5f6094acbb..2760a3f3a00e 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -45,6 +45,12 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, struct wpa_ptk *ptk);
+static void wpa_group_free(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group);
+static void wpa_group_get(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group);
+static void wpa_group_put(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group);
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -67,6 +73,14 @@ static inline int wpa_auth_mic_failure_report(
}
+static inline void wpa_auth_psk_failure_report(
+ struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+ if (wpa_auth->cb.psk_failure_report)
+ wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
+}
+
+
static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var,
int value)
@@ -254,15 +268,22 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
- struct wpa_group *group;
+ struct wpa_group *group, *next;
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
- for (group = wpa_auth->group; group; group = group->next) {
+ group = wpa_auth->group;
+ while (group) {
+ wpa_group_get(wpa_auth, group);
+
group->GTKReKey = TRUE;
do {
group->changed = FALSE;
wpa_group_sm_step(wpa_auth, group);
} while (group->changed);
+
+ next = group->next;
+ wpa_group_put(wpa_auth, group);
+ group = next;
}
if (wpa_auth->conf.wpa_group_rekey) {
@@ -565,6 +586,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
sm->wpa_auth = wpa_auth;
sm->group = wpa_auth->group;
+ wpa_group_get(sm->wpa_auth, sm->group);
return sm;
}
@@ -643,6 +665,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#endif /* CONFIG_IEEE80211R */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
+ wpa_group_put(sm->wpa_auth, sm->group);
os_free(sm);
}
@@ -1517,6 +1540,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
else
WPA_PUT_BE16(key->key_data_length,
key_data_len);
+#ifndef CONFIG_NO_RC4
} else if (sm->PTK.kek_len == 16) {
u8 ek[32];
os_memcpy(key->key_iv,
@@ -1532,6 +1556,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
else
WPA_PUT_BE16(key->key_data_length,
key_data_len);
+#endif /* CONFIG_NO_RC4 */
} else {
os_free(hdr);
os_free(buf);
@@ -1646,7 +1671,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
}
-int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
+int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
{
int remove_ptk = 1;
@@ -1734,6 +1759,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
wpa_remove_ptk(sm);
}
+ if (sm->in_step_loop) {
+ /*
+ * wpa_sm_step() is already running - avoid recursive call to
+ * it by making the existing loop process the new update.
+ */
+ sm->changed = TRUE;
+ return 0;
+ }
return wpa_sm_step(sm);
}
@@ -1818,9 +1851,13 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
group->reject_4way_hs_for_entropy = FALSE;
}
- wpa_group_init_gmk_and_counter(wpa_auth, group);
- wpa_gtk_update(wpa_auth, group);
- wpa_group_config_group_keys(wpa_auth, group);
+ if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
+ wpa_gtk_update(wpa_auth, group) < 0 ||
+ wpa_group_config_group_keys(wpa_auth, group) < 0) {
+ wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
+ group->first_sta_seen = FALSE;
+ group->reject_4way_hs_for_entropy = TRUE;
+ }
}
@@ -1985,7 +2022,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_ptk PTK;
- int ok = 0;
+ int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
@@ -2001,6 +2038,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->p2p_dev_addr, pmk);
if (pmk == NULL)
break;
+ psk_found = 1;
} else
pmk = sm->PMK;
@@ -2020,6 +2058,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
+ if (psk_found)
+ wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
return;
}
@@ -2983,9 +3023,9 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
}
-static const char * wpa_bool_txt(int bool)
+static const char * wpa_bool_txt(int val)
{
- return bool ? "TRUE" : "FALSE";
+ return val ? "TRUE" : "FALSE";
}
@@ -3270,6 +3310,63 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
}
+/*
+ * Remove and free the group from wpa_authenticator. This is triggered by a
+ * callback to make sure nobody is currently iterating the group list while it
+ * gets modified.
+ */
+static void wpa_group_free(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ struct wpa_group *prev = wpa_auth->group;
+
+ wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d",
+ group->vlan_id);
+
+ while (prev) {
+ if (prev->next == group) {
+ /* This never frees the special first group as needed */
+ prev->next = group->next;
+ os_free(group);
+ break;
+ }
+ prev = prev->next;
+ }
+
+}
+
+
+/* Increase the reference counter for group */
+static void wpa_group_get(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ /* Skip the special first group */
+ if (wpa_auth->group == group)
+ return;
+
+ group->references++;
+}
+
+
+/* Decrease the reference counter and maybe free the group */
+static void wpa_group_put(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
+{
+ /* Skip the special first group */
+ if (wpa_auth->group == group)
+ return;
+
+ group->references--;
+ if (group->references)
+ return;
+ wpa_group_free(wpa_auth, group);
+}
+
+
+/*
+ * Add a group that has its references counter set to zero. Caller needs to
+ * call wpa_group_get() on the return value to mark the entry in use.
+ */
static struct wpa_group *
wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
@@ -3320,7 +3417,10 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
"machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+ wpa_group_get(sm->wpa_auth, group);
+ wpa_group_put(sm->wpa_auth, sm->group);
sm->group = group;
+
return 0;
}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 2788e657435d..fd04f169433a 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,9 @@
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
+
+#define MAX_OWN_IE_OVERRIDE 256
#ifdef _MSC_VER
#pragma pack(push, 1)
@@ -146,8 +149,7 @@ struct wpa_auth_config {
int group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
-#define SSID_LEN 32
- u8 ssid[SSID_LEN];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
@@ -164,6 +166,8 @@ struct wpa_auth_config {
int ap_mlme;
#ifdef CONFIG_TESTING_OPTIONS
double corrupt_gtk_rekey_mic_probability;
+ u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
+ size_t own_ie_override_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
@@ -189,6 +193,7 @@ struct wpa_auth_callbacks {
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
int (*mic_failure_report)(void *ctx, const u8 *addr);
+ void (*psk_failure_report)(void *ctx, const u8 *addr);
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
@@ -251,12 +256,12 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len);
-typedef enum {
+enum wpa_event {
WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
WPA_REAUTH_EAPOL, WPA_ASSOC_FT
-} wpa_event;
+};
void wpa_remove_ptk(struct wpa_state_machine *sm);
-int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
+int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event);
void wpa_auth_sm_notify(struct wpa_state_machine *sm);
void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index ef3249a3eb9b..eeaffbf63516 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -534,10 +534,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
return pos;
}
-#ifdef NEED_AP_MLME
- if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+ if (parse.wmm_tspec) {
struct wmm_tspec_element *tspec;
- int res;
if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
@@ -555,7 +553,13 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
}
tspec = (struct wmm_tspec_element *) pos;
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
- res = wmm_process_tspec(tspec);
+ }
+
+#ifdef NEED_AP_MLME
+ if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+ int res;
+
+ res = wmm_process_tspec((struct wmm_tspec_element *) pos);
wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
rdie->status_code =
@@ -566,20 +570,17 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
else {
/* TSPEC accepted; include updated TSPEC in response */
rdie->descr_count = 1;
- pos += sizeof(*tspec);
+ pos += sizeof(struct wmm_tspec_element);
}
return pos;
}
#endif /* NEED_AP_MLME */
if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
- struct wmm_tspec_element *tspec;
int res;
- tspec = (struct wmm_tspec_element *) pos;
- os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
- sizeof(*tspec));
+ sizeof(struct wmm_tspec_element));
if (res >= 0) {
if (res)
rdie->status_code = host_to_le16(res);
@@ -587,7 +588,7 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
/* TSPEC accepted; include updated TSPEC in
* response */
rdie->descr_count = 1;
- pos += sizeof(*tspec);
+ pos += sizeof(struct wmm_tspec_element);
}
return pos;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 7f8320708c39..f98cc50599e3 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
+#include "common/wpa_ctrl.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
@@ -53,8 +54,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
wconf->ssid_len = conf->ssid.ssid_len;
- if (wconf->ssid_len > SSID_LEN)
- wconf->ssid_len = SSID_LEN;
+ if (wconf->ssid_len > SSID_MAX_LEN)
+ wconf->ssid_len = SSID_MAX_LEN;
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN);
@@ -91,6 +92,13 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#ifdef CONFIG_TESTING_OPTIONS
wconf->corrupt_gtk_rekey_mic_probability =
iconf->corrupt_gtk_rekey_mic_probability;
+ if (conf->own_ie_override &&
+ wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) {
+ wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override);
+ os_memcpy(wconf->own_ie_override,
+ wpabuf_head(conf->own_ie_override),
+ wconf->own_ie_override_len);
+ }
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@@ -144,6 +152,14 @@ static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
}
+static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr)
+{
+ struct hostapd_data *hapd = ctx;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
+ MAC2STR(addr));
+}
+
+
static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
wpa_eapol_variable var, int value)
{
@@ -579,6 +595,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
cb.logger = hostapd_wpa_auth_logger;
cb.disconnect = hostapd_wpa_auth_disconnect;
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+ cb.psk_failure_report = hostapd_wpa_auth_psk_failure_report;
cb.set_eapol = hostapd_wpa_auth_set_eapol;
cb.get_eapol = hostapd_wpa_auth_get_eapol;
cb.get_psk = hostapd_wpa_auth_get_psk;
@@ -620,7 +637,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
}
#ifdef CONFIG_IEEE80211R
- if (!hostapd_drv_none(hapd)) {
+ if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds &&
+ wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
hapd->conf->bridge :
hapd->conf->iface, NULL, ETH_P_RRB,
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 7b2cd3ea8ed4..57b098f2ed72 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -169,6 +169,8 @@ struct wpa_group {
u8 IGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
#endif /* CONFIG_IEEE80211W */
+ /* Number of references except those in struct wpa_group->next */
+ unsigned int references;
};
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index f2872970affe..eafb828b8d60 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -261,7 +261,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
#ifdef CONFIG_IEEE80211W
- if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+ if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+ conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (pos + 2 + 4 > buf + len)
return -1;
if (pmkid == NULL) {
@@ -377,6 +378,23 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
u8 *pos, buf[128];
int res;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (wpa_auth->conf.own_ie_override_len) {
+ wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
+ wpa_auth->conf.own_ie_override,
+ wpa_auth->conf.own_ie_override_len);
+ os_free(wpa_auth->wpa_ie);
+ wpa_auth->wpa_ie =
+ os_malloc(wpa_auth->conf.own_ie_override_len);
+ if (wpa_auth->wpa_ie == NULL)
+ return -1;
+ os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override,
+ wpa_auth->conf.own_ie_override_len);
+ wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len;
+ return 0;
+ }
+#endif /* CONFIG_TESTING_OPTIONS */
+
pos = buf;
if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index b0e8b0bfcac3..cde31e60e03b 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -324,7 +324,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
bss->wps_state = 2;
- if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+ if (cred->ssid_len <= SSID_MAX_LEN) {
os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
bss->ssid.ssid_len = cred->ssid_len;
bss->ssid.ssid_set = 1;
@@ -347,8 +347,12 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
bss->wpa_pairwise = 0;
- if (cred->encr_type & WPS_ENCR_AES)
- bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+ if (cred->encr_type & WPS_ENCR_AES) {
+ if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
+ bss->wpa_pairwise |= WPA_CIPHER_GCMP;
+ else
+ bss->wpa_pairwise |= WPA_CIPHER_CCMP;
+ }
if (cred->encr_type & WPS_ENCR_TKIP)
bss->wpa_pairwise |= WPA_CIPHER_TKIP;
bss->rsn_pairwise = bss->wpa_pairwise;
@@ -448,6 +452,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
os_free(hapd->wps->network_key);
hapd->wps->network_key = NULL;
hapd->wps->network_key_len = 0;
+ } else if ((cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) &&
+ (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN)) {
+ wpa_printf(MSG_INFO, "WPS: Invalid key length %lu for WPA/WPA2",
+ (unsigned long) cred->key_len);
+ return -1;
} else {
if (hapd->wps->network_key == NULL ||
hapd->wps->network_key_len < cred->key_len) {
@@ -530,7 +539,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "wpa_pairwise=");
prefix = "";
if (cred->encr_type & WPS_ENCR_AES) {
- fprintf(nconf, "CCMP");
+ if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
+ fprintf(nconf, "GCMP");
+ else
+ fprintf(nconf, "CCMP");
+
prefix = " ";
}
if (cred->encr_type & WPS_ENCR_TKIP) {
@@ -844,7 +857,9 @@ static int hostapd_wps_rf_band_cb(void *ctx)
struct hostapd_data *hapd = ctx;
return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
- WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+ WPS_RF_50GHZ :
+ hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
+ WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
}
@@ -856,8 +871,10 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
wpabuf_free(hapd->wps_probe_resp_ie);
hapd->wps_probe_resp_ie = NULL;
- if (deinit_only)
+ if (deinit_only) {
+ hostapd_reset_ap_wps_ie(hapd);
return;
+ }
hostapd_set_ap_wps_ie(hapd);
}
@@ -1039,7 +1056,9 @@ int hostapd_init_wps(struct hostapd_data *hapd,
} else {
wps->dev.rf_bands =
hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
- WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+ WPS_RF_50GHZ :
+ hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
+ WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
}
if (conf->wpa & WPA_PROTO_RSN) {
@@ -1285,30 +1304,53 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
}
+struct wps_button_pushed_ctx {
+ const u8 *p2p_dev_addr;
+ unsigned int count;
+};
+
static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
{
- const u8 *p2p_dev_addr = ctx;
- if (hapd->wps == NULL)
- return -1;
- return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
+ struct wps_button_pushed_ctx *data = ctx;
+
+ if (hapd->wps) {
+ data->count++;
+ return wps_registrar_button_pushed(hapd->wps->registrar,
+ data->p2p_dev_addr);
+ }
+
+ return 0;
}
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr)
{
- return hostapd_wps_for_each(hapd, wps_button_pushed,
- (void *) p2p_dev_addr);
+ struct wps_button_pushed_ctx ctx;
+ int ret;
+
+ os_memset(&ctx, 0, sizeof(ctx));
+ ctx.p2p_dev_addr = p2p_dev_addr;
+ ret = hostapd_wps_for_each(hapd, wps_button_pushed, &ctx);
+ if (ret == 0 && !ctx.count)
+ ret = -1;
+ return ret;
}
+struct wps_cancel_ctx {
+ unsigned int count;
+};
+
static int wps_cancel(struct hostapd_data *hapd, void *ctx)
{
- if (hapd->wps == NULL)
- return -1;
+ struct wps_cancel_ctx *data = ctx;
- wps_registrar_wps_cancel(hapd->wps->registrar);
- ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+ if (hapd->wps) {
+ data->count++;
+ wps_registrar_wps_cancel(hapd->wps->registrar);
+ ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+ }
return 0;
}
@@ -1316,7 +1358,14 @@ static int wps_cancel(struct hostapd_data *hapd, void *ctx)
int hostapd_wps_cancel(struct hostapd_data *hapd)
{
- return hostapd_wps_for_each(hapd, wps_cancel, NULL);
+ struct wps_cancel_ctx ctx;
+ int ret;
+
+ os_memset(&ctx, 0, sizeof(ctx));
+ ret = hostapd_wps_for_each(hapd, wps_cancel, &ctx);
+ if (ret == 0 && !ctx.count)
+ ret = -1;
+ return ret;
}
@@ -1546,6 +1595,10 @@ struct wps_ap_pin_data {
static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
{
struct wps_ap_pin_data *data = ctx;
+
+ if (!hapd->wps)
+ return 0;
+
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(data->pin_txt);
#ifdef CONFIG_WPS_UPNP
diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c
index 8f77015ef57f..aef9a53c46cf 100644
--- a/src/ap/x_snoop.c
+++ b/src/ap/x_snoop.c
@@ -51,6 +51,14 @@ int x_snoop_init(struct hostapd_data *hapd)
return -1;
}
+#ifdef CONFIG_IPV6
+ if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable multicast snooping on the bridge");
+ return -1;
+ }
+#endif /* CONFIG_IPV6 */
+
return 0;
}
diff --git a/src/common/Makefile b/src/common/Makefile
index adfd3dfd5b9b..e703630835e1 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -1,8 +1,28 @@
-all:
- @echo Nothing to be made.
+all: libcommon.a
clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcommon.a
install:
@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_SAE
+CFLAGS += -DCONFIG_SUITE
+CFLAGS += -DCONFIG_SUITEB
+
+LIB_OBJS= \
+ gas.o \
+ hw_features_common.o \
+ ieee802_11_common.o \
+ sae.o \
+ wpa_common.o
+
+libcommon.a: $(LIB_OBJS)
+ $(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 56b11220c9ed..d69448bd3800 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -1,6 +1,6 @@
/*
* common module tests
- * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,8 @@
#include "utils/common.h"
#include "ieee802_11_common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
#include "wpa_common.h"
@@ -46,6 +48,10 @@ static const struct ieee802_11_parse_test_data parse_tests[] = {
{ (u8 *) "\x6e\x00", 2, ParseOK, 1 },
{ (u8 *) "\xc7\x00", 2, ParseOK, 1 },
{ (u8 *) "\xc7\x01\x00", 3, ParseOK, 1 },
+ { (u8 *) "\x03\x00\x2a\x00\x36\x00\x37\x00\x38\x00\x2d\x00\x3d\x00\xbf\x00\xc0\x00",
+ 18, ParseOK, 9 },
+ { (u8 *) "\x8b\x00", 2, ParseOK, 1 },
+ { (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
{ NULL, 0, ParseOK, 0 }
};
@@ -158,6 +164,34 @@ static int rsn_ie_parse_tests(void)
}
+static int gas_tests(void)
+{
+ struct wpabuf *buf;
+
+ wpa_printf(MSG_INFO, "gas tests");
+ gas_anqp_set_len(NULL);
+
+ buf = wpabuf_alloc(1);
+ if (buf == NULL)
+ return -1;
+ gas_anqp_set_len(buf);
+ wpabuf_free(buf);
+
+ buf = wpabuf_alloc(20);
+ if (buf == NULL)
+ return -1;
+ wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+ wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_be32(buf, 0);
+ wpabuf_put_u8(buf, 0);
+ gas_anqp_set_len(buf);
+ wpabuf_free(buf);
+
+ return 0;
+}
+
+
int common_module_tests(void)
{
int ret = 0;
@@ -165,6 +199,7 @@ int common_module_tests(void)
wpa_printf(MSG_INFO, "common module tests");
if (ieee802_11_parse_tests() < 0 ||
+ gas_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;
diff --git a/src/common/defs.h b/src/common/defs.h
index b5f4f801eda2..6aea3751a2bc 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -174,7 +174,7 @@ enum wpa_states {
/**
* WPA_INTERFACE_DISABLED - Interface disabled
*
- * This stat eis entered if the network interface is disabled, e.g.,
+ * This state is entered if the network interface is disabled, e.g.,
* due to rfkill. wpa_supplicant refuses any new operations that would
* use the radio until the interface has been enabled.
*/
@@ -295,6 +295,7 @@ enum hostapd_hw_mode {
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
HOSTAPD_MODE_IEEE80211AD,
+ HOSTAPD_MODE_IEEE80211ANY,
NUM_HOSTAPD_MODES
};
@@ -310,6 +311,7 @@ enum wpa_ctrl_req_type {
WPA_CTRL_REQ_EAP_OTP,
WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
+ WPA_CTRL_REQ_PSK_PASSPHRASE,
NUM_WPA_CTRL_REQS
};
@@ -326,4 +328,10 @@ enum mesh_plink_state {
PLINK_BLOCKED,
};
+enum set_band {
+ WPA_SETBAND_AUTO,
+ WPA_SETBAND_5G,
+ WPA_SETBAND_2G
+};
+
#endif /* DEFS_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index e8babb52a9c5..9c37ea63ca87 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -88,8 +88,8 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
int sec_chan)
{
int ok, j, first;
- int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
+ int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
+ 149, 157, 184, 192 };
size_t k;
if (pri_chan == sec_chan || !sec_chan)
@@ -152,8 +152,7 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
*pri_chan = *sec_chan = 0;
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
- if (elems.ht_operation &&
- elems.ht_operation_len >= sizeof(*oper)) {
+ if (elems.ht_operation) {
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
*pri_chan = oper->primary_chan;
if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
@@ -177,10 +176,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
size_t i;
int match;
- if (!mode || !scan_res || !pri_chan || !sec_chan)
- return 0;
-
- if (pri_chan == sec_chan)
+ if (!mode || !scan_res || !pri_chan || !sec_chan ||
+ pri_chan == sec_chan)
return 0;
pri_freq = hw_get_freq(mode, pri_chan);
@@ -238,7 +235,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
}
-int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
+static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start,
+ int end)
{
struct ieee802_11_elems elems;
struct ieee80211_ht_operation *oper;
@@ -253,8 +251,7 @@ int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
return 1;
}
- if (elems.ht_operation &&
- elems.ht_operation_len >= sizeof(*oper)) {
+ if (elems.ht_operation) {
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
return 0;
@@ -275,10 +272,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
int affected_start, affected_end;
size_t i;
- if (!mode || !scan_res || !pri_chan || !sec_chan)
- return 0;
-
- if (pri_chan == sec_chan)
+ if (!mode || !scan_res || !pri_chan || !sec_chan ||
+ pri_chan == sec_chan)
return 0;
pri_freq = hw_get_freq(mode, pri_chan);
@@ -335,9 +330,7 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
0);
- if (elems.ht_capabilities &&
- elems.ht_capabilities_len >=
- sizeof(struct ieee80211_ht_capabilities)) {
+ if (elems.ht_capabilities) {
struct ieee80211_ht_capabilities *ht_cap =
(struct ieee80211_ht_capabilities *)
elems.ht_capabilities;
@@ -363,8 +356,6 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps)
{
- int tmp;
-
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
@@ -378,11 +369,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
if (data->vht_enabled) switch (vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
- if (center_segment1)
- return -1;
- if (center_segment0 != 0 &&
- 5000 + center_segment0 * 5 != data->center_freq1 &&
- 2407 + center_segment0 * 5 != data->center_freq1)
+ if (center_segment1 ||
+ (center_segment0 != 0 &&
+ 5000 + center_segment0 * 5 != data->center_freq1 &&
+ 2407 + center_segment0 * 5 != data->center_freq1))
return -1;
break;
case VHT_CHANWIDTH_80P80MHZ:
@@ -398,19 +388,38 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
/* fall through */
case VHT_CHANWIDTH_80MHZ:
data->bandwidth = 80;
- if (vht_oper_chwidth == 1 && center_segment1)
+ if ((vht_oper_chwidth == 1 && center_segment1) ||
+ (vht_oper_chwidth == 3 && !center_segment1) ||
+ !sec_channel_offset)
return -1;
- if (vht_oper_chwidth == 3 && !center_segment1)
- return -1;
- if (!sec_channel_offset)
- return -1;
- /* primary 40 part must match the HT configuration */
- tmp = (30 + freq - 5000 - center_segment0 * 5) / 20;
- tmp /= 2;
- if (data->center_freq1 != 5000 +
- center_segment0 * 5 - 20 + 40 * tmp)
- return -1;
- data->center_freq1 = 5000 + center_segment0 * 5;
+ if (!center_segment0) {
+ if (channel <= 48)
+ center_segment0 = 42;
+ else if (channel <= 64)
+ center_segment0 = 58;
+ else if (channel <= 112)
+ center_segment0 = 106;
+ else if (channel <= 128)
+ center_segment0 = 122;
+ else if (channel <= 144)
+ center_segment0 = 138;
+ else if (channel <= 161)
+ center_segment0 = 155;
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ } else {
+ /*
+ * Note: HT/VHT config and params are coupled. Check if
+ * HT40 channel band is in VHT80 Pri channel band
+ * configuration.
+ */
+ if (center_segment0 == channel + 6 ||
+ center_segment0 == channel + 2 ||
+ center_segment0 == channel - 2 ||
+ center_segment0 == channel - 6)
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ else
+ return -1;
+ }
break;
case VHT_CHANWIDTH_160MHZ:
data->bandwidth = 160;
@@ -424,13 +433,21 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
if (!sec_channel_offset)
return -1;
- /* primary 40 part must match the HT configuration */
- tmp = (70 + freq - 5000 - center_segment0 * 5) / 20;
- tmp /= 2;
- if (data->center_freq1 != 5000 +
- center_segment0 * 5 - 60 + 40 * tmp)
+ /*
+ * Note: HT/VHT config and params are coupled. Check if
+ * HT40 channel band is in VHT160 channel band configuration.
+ */
+ if (center_segment0 == channel + 14 ||
+ center_segment0 == channel + 10 ||
+ center_segment0 == channel + 6 ||
+ center_segment0 == channel + 2 ||
+ center_segment0 == channel - 2 ||
+ center_segment0 == channel - 6 ||
+ center_segment0 == channel - 10 ||
+ center_segment0 == channel - 14)
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ else
return -1;
- data->center_freq1 = 5000 + center_segment0 * 5;
break;
}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 7f43d00c5b27..7360b4e3efed 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -26,7 +26,6 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
int check_40mhz_5g(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan);
-int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end);
int check_40mhz_2g4(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index aca0b73223bb..d07a316a7929 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,8 @@
#include "common.h"
#include "defs.h"
+#include "wpa_common.h"
+#include "qca-vendor.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
@@ -146,6 +148,20 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
}
break;
+ case OUI_QCA:
+ switch (pos[3]) {
+ case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST:
+ elems->pref_freq_list = pos;
+ elems->pref_freq_list_len = elen;
+ break;
+ default:
+ wpa_printf(MSG_EXCESSIVE,
+ "Unknown QCA information element ignored (type=%d len=%lu)",
+ pos[3], (unsigned long) elen);
+ return -1;
+ }
+ break;
+
default:
wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
"information element ignored (vendor OUI "
@@ -196,6 +212,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
switch (id) {
case WLAN_EID_SSID:
+ if (elen > SSID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "Ignored too long SSID element (elen=%u)",
+ elen);
+ break;
+ }
elems->ssid = pos;
elems->ssid_len = elen;
break;
@@ -204,8 +226,9 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->supp_rates_len = elen;
break;
case WLAN_EID_DS_PARAMS:
+ if (elen < 1)
+ break;
elems->ds_params = pos;
- elems->ds_params_len = elen;
break;
case WLAN_EID_CF_PARAMS:
case WLAN_EID_TIM:
@@ -215,8 +238,9 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->challenge_len = elen;
break;
case WLAN_EID_ERP_INFO:
+ if (elen < 1)
+ break;
elems->erp_info = pos;
- elems->erp_info_len = elen;
break;
case WLAN_EID_EXT_SUPP_RATES:
elems->ext_supp_rates = pos;
@@ -239,24 +263,31 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->supp_channels_len = elen;
break;
case WLAN_EID_MOBILITY_DOMAIN:
+ if (elen < sizeof(struct rsn_mdie))
+ break;
elems->mdie = pos;
elems->mdie_len = elen;
break;
case WLAN_EID_FAST_BSS_TRANSITION:
+ if (elen < sizeof(struct rsn_ftie))
+ break;
elems->ftie = pos;
elems->ftie_len = elen;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
+ if (elen != 5)
+ break;
elems->timeout_int = pos;
- elems->timeout_int_len = elen;
break;
case WLAN_EID_HT_CAP:
+ if (elen < sizeof(struct ieee80211_ht_capabilities))
+ break;
elems->ht_capabilities = pos;
- elems->ht_capabilities_len = elen;
break;
case WLAN_EID_HT_OPERATION:
+ if (elen < sizeof(struct ieee80211_ht_operation))
+ break;
elems->ht_operation = pos;
- elems->ht_operation_len = elen;
break;
case WLAN_EID_MESH_CONFIG:
elems->mesh_config = pos;
@@ -271,12 +302,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->peer_mgmt_len = elen;
break;
case WLAN_EID_VHT_CAP:
+ if (elen < sizeof(struct ieee80211_vht_capabilities))
+ break;
elems->vht_capabilities = pos;
- elems->vht_capabilities_len = elen;
break;
case WLAN_EID_VHT_OPERATION:
+ if (elen < sizeof(struct ieee80211_vht_operation))
+ break;
elems->vht_operation = pos;
- elems->vht_operation_len = elen;
break;
case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
if (elen != 1)
@@ -321,6 +354,18 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
/* after mic everything is encrypted, so stop. */
left = elen;
break;
+ case WLAN_EID_MULTI_BAND:
+ if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
+ wpa_printf(MSG_MSGDUMP,
+ "IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)",
+ id, elen);
+ break;
+ }
+
+ elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
+ elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
+ elems->mb_ies.nof_ies++;
+ break;
default:
unknown++;
if (!show_errors)
@@ -486,14 +531,14 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
ac->aifs = v;
} else if (os_strcmp(pos, "cwmin") == 0) {
v = atoi(val);
- if (v < 0 || v > 12) {
+ if (v < 0 || v > 15) {
wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
return -1;
}
ac->cwmin = v;
} else if (os_strcmp(pos, "cwmax") == 0) {
v = atoi(val);
- if (v < 0 || v > 12) {
+ if (v < 0 || v > 15) {
wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
return -1;
}
@@ -523,50 +568,163 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
- enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
+ u8 op_class;
+
+ return ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, channel);
+}
+
+
+/**
+ * ieee80211_freq_to_channel_ext - Convert frequency into channel info
+ * for HT40 and VHT. DFS channels are not covered.
+ * @freq: Frequency (MHz) to convert
+ * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
+ * @vht: 0 - non-VHT, 1 - 80 MHz
+ * @op_class: Buffer for returning operating class
+ * @channel: Buffer for returning channel number
+ * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
+ */
+enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
+ int sec_channel, int vht,
+ u8 *op_class, u8 *channel)
+{
+ /* TODO: more operating classes */
+
+ if (sec_channel > 1 || sec_channel < -1)
+ return NUM_HOSTAPD_MODES;
if (freq >= 2412 && freq <= 2472) {
- mode = HOSTAPD_MODE_IEEE80211G;
+ if ((freq - 2407) % 5)
+ return NUM_HOSTAPD_MODES;
+
+ if (vht)
+ return NUM_HOSTAPD_MODES;
+
+ /* 2.407 GHz, channels 1..13 */
+ if (sec_channel == 1)
+ *op_class = 83;
+ else if (sec_channel == -1)
+ *op_class = 84;
+ else
+ *op_class = 81;
+
*channel = (freq - 2407) / 5;
- } else if (freq == 2484) {
- mode = HOSTAPD_MODE_IEEE80211B;
+
+ return HOSTAPD_MODE_IEEE80211G;
+ }
+
+ if (freq == 2484) {
+ if (sec_channel || vht)
+ return NUM_HOSTAPD_MODES;
+
+ *op_class = 82; /* channel 14 */
*channel = 14;
- } else if (freq >= 4900 && freq < 5000) {
- mode = HOSTAPD_MODE_IEEE80211A;
+
+ return HOSTAPD_MODE_IEEE80211B;
+ }
+
+ if (freq >= 4900 && freq < 5000) {
+ if ((freq - 4000) % 5)
+ return NUM_HOSTAPD_MODES;
*channel = (freq - 4000) / 5;
- } else if (freq >= 5000 && freq < 5900) {
- mode = HOSTAPD_MODE_IEEE80211A;
+ *op_class = 0; /* TODO */
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 5 GHz, channels 36..48 */
+ if (freq >= 5180 && freq <= 5240) {
+ if ((freq - 5000) % 5)
+ return NUM_HOSTAPD_MODES;
+
+ if (sec_channel == 1)
+ *op_class = 116;
+ else if (sec_channel == -1)
+ *op_class = 117;
+ else if (vht)
+ *op_class = 128;
+ else
+ *op_class = 115;
+
+ *channel = (freq - 5000) / 5;
+
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 5 GHz, channels 149..161 */
+ if (freq >= 5745 && freq <= 5805) {
+ if ((freq - 5000) % 5)
+ return NUM_HOSTAPD_MODES;
+
+ if (sec_channel == 1)
+ *op_class = 126;
+ else if (sec_channel == -1)
+ *op_class = 127;
+ else if (vht)
+ *op_class = 128;
+ else
+ *op_class = 124;
+
*channel = (freq - 5000) / 5;
- } else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
- mode = HOSTAPD_MODE_IEEE80211AD;
+
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 5 GHz, channels 149..169 */
+ if (freq >= 5745 && freq <= 5845) {
+ if ((freq - 5000) % 5)
+ return NUM_HOSTAPD_MODES;
+
+ *op_class = 125;
+
+ *channel = (freq - 5000) / 5;
+
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ if (freq >= 5000 && freq < 5900) {
+ if ((freq - 5000) % 5)
+ return NUM_HOSTAPD_MODES;
+ *channel = (freq - 5000) / 5;
+ *op_class = 0; /* TODO */
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
+ /* 56.16 GHz, channel 1..4 */
+ if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
+ if (sec_channel || vht)
+ return NUM_HOSTAPD_MODES;
+
*channel = (freq - 56160) / 2160;
+ *op_class = 180;
+
+ return HOSTAPD_MODE_IEEE80211AD;
}
- return mode;
+ return NUM_HOSTAPD_MODES;
}
-static const char *us_op_class_cc[] = {
+static const char *const us_op_class_cc[] = {
"US", "CA", NULL
};
-static const char *eu_op_class_cc[] = {
+static const char *const eu_op_class_cc[] = {
"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
};
-static const char *jp_op_class_cc[] = {
+static const char *const jp_op_class_cc[] = {
"JP", NULL
};
-static const char *cn_op_class_cc[] = {
- "CN", "CA", NULL
+static const char *const cn_op_class_cc[] = {
+ "CN", NULL
};
-static int country_match(const char *cc[], const char *country)
+static int country_match(const char *const cc[], const char *const country)
{
int i;
@@ -612,6 +770,10 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
+ case 5: /* channels 149,153,157,161,165 */
+ if (chan < 149 || chan > 165)
+ return -1;
+ return 5000 + 5 * chan;
case 34: /* 60 GHz band, channels 1..3 */
if (chan < 1 || chan > 3)
return -1;
@@ -764,12 +926,15 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
return -1;
return 5000 + 5 * chan;
case 124: /* channels 149,153,157,161 */
- case 125: /* channels 149,153,157,161,165,169 */
case 126: /* channels 149,157; 40 MHz */
case 127: /* channels 153,161; 40 MHz */
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
+ case 125: /* channels 149,153,157,161,165,169 */
+ if (chan < 149 || chan > 169)
+ return -1;
+ return 5000 + 5 * chan;
case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
if (chan < 36 || chan > 161)
@@ -921,3 +1086,62 @@ const char * fc2str(u16 fc)
return "WLAN_FC_TYPE_UNKNOWN";
#undef C2S
}
+
+
+int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
+ size_t ies_len)
+{
+ os_memset(info, 0, sizeof(*info));
+
+ while (ies_buf && ies_len >= 2 &&
+ info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
+ size_t len = 2 + ies_buf[1];
+
+ if (len > ies_len) {
+ wpa_hexdump(MSG_DEBUG, "Truncated IEs",
+ ies_buf, ies_len);
+ return -1;
+ }
+
+ if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
+ wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
+ info->ies[info->nof_ies].ie = ies_buf + 2;
+ info->ies[info->nof_ies].ie_len = ies_buf[1];
+ info->nof_ies++;
+ }
+
+ ies_len -= len;
+ ies_buf += len;
+ }
+
+ return 0;
+}
+
+
+struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
+{
+ struct wpabuf *mb_ies = NULL;
+
+ WPA_ASSERT(info != NULL);
+
+ if (info->nof_ies) {
+ u8 i;
+ size_t mb_ies_size = 0;
+
+ for (i = 0; i < info->nof_ies; i++)
+ mb_ies_size += 2 + info->ies[i].ie_len;
+
+ mb_ies = wpabuf_alloc(mb_ies_size);
+ if (mb_ies) {
+ for (i = 0; i < info->nof_ies; i++) {
+ wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND);
+ wpabuf_put_u8(mb_ies, info->ies[i].ie_len);
+ wpabuf_put_data(mb_ies,
+ info->ies[i].ie,
+ info->ies[i].ie_len);
+ }
+ }
+ }
+
+ return mb_ies;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 7f0b296d2b00..55ce0223d923 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -9,6 +9,16 @@
#ifndef IEEE802_11_COMMON_H
#define IEEE802_11_COMMON_H
+#define MAX_NOF_MB_IES_SUPPORTED 5
+
+struct mb_ies_info {
+ struct {
+ const u8 *ie;
+ u8 ie_len;
+ } ies[MAX_NOF_MB_IES_SUPPORTED];
+ u8 nof_ies;
+};
+
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
@@ -48,12 +58,11 @@ struct ieee802_11_elems {
const u8 *osen;
const u8 *ampe;
const u8 *mic;
+ const u8 *pref_freq_list;
u8 ssid_len;
u8 supp_rates_len;
- u8 ds_params_len;
u8 challenge_len;
- u8 erp_info_len;
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
@@ -63,14 +72,9 @@ struct ieee802_11_elems {
u8 supp_channels_len;
u8 mdie_len;
u8 ftie_len;
- u8 timeout_int_len;
- u8 ht_capabilities_len;
- u8 ht_operation_len;
u8 mesh_config_len;
u8 mesh_id_len;
u8 peer_mgmt_len;
- u8 vht_capabilities_len;
- u8 vht_operation_len;
u8 vendor_ht_cap_len;
u8 vendor_vht_len;
u8 p2p_len;
@@ -83,6 +87,8 @@ struct ieee802_11_elems {
u8 osen_len;
u8 ampe_len;
u8 mic_len;
+ u8 pref_freq_list_len;
+ struct mb_ies_info mb_ies;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -108,9 +114,15 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
+enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
+ int sec_channel, int vht,
+ u8 *op_class, u8 *channel);
int ieee80211_is_dfs(int freq);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
+int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
+ size_t ies_len);
+struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
const char * fc2str(u16 fc);
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 2e51935b8e3b..44530ce3cee6 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -10,6 +10,8 @@
#ifndef IEEE802_11_DEFS_H
#define IEEE802_11_DEFS_H
+#include <utils/common.h>
+
/* IEEE 802.11 defines */
#define WLAN_FC_PVER 0x0003
@@ -163,7 +165,10 @@
#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
#define WLAN_STATUS_TRANSMISSION_FAILURE 79
+#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82
+#define WLAN_STATUS_PENDING_ADMITTING_FST_SESSION 86
#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
+#define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99
#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
@@ -269,6 +274,8 @@
#define WLAN_EID_AMPE 139
#define WLAN_EID_MIC 140
#define WLAN_EID_CCKM 156
+#define WLAN_EID_MULTI_BAND 158
+#define WLAN_EID_SESSION_TRANSITION 164
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
@@ -297,6 +304,7 @@
#define WLAN_ACTION_TDLS 12
#define WLAN_ACTION_SELF_PROTECTED 15
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
+#define WLAN_ACTION_FST 18
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Public action codes */
@@ -470,35 +478,35 @@ struct ieee80211_mgmt {
le16 auth_transaction;
le16 status_code;
/* possibly followed by Challenge text */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED auth;
struct {
le16 reason_code;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED deauth;
struct {
le16 capab_info;
le16 listen_interval;
/* followed by SSID and Supported rates */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED assoc_req;
struct {
le16 capab_info;
le16 status_code;
le16 aid;
/* followed by Supported rates */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED assoc_resp, reassoc_resp;
struct {
le16 capab_info;
le16 listen_interval;
u8 current_ap[6];
/* followed by SSID and Supported rates */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED reassoc_req;
struct {
le16 reason_code;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED disassoc;
struct {
u8 timestamp[8];
@@ -506,7 +514,7 @@ struct ieee80211_mgmt {
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params, TIM */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED beacon;
struct {
/* only variable items: SSID, Supported rates */
@@ -518,7 +526,7 @@ struct ieee80211_mgmt {
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED probe_resp;
struct {
u8 category;
@@ -527,7 +535,7 @@ struct ieee80211_mgmt {
u8 action_code;
u8 dialog_token;
u8 status_code;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED wmm_action;
struct{
u8 action_code;
@@ -541,14 +549,14 @@ struct ieee80211_mgmt {
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
- u8 variable[0]; /* FT Request */
+ u8 variable[]; /* FT Request */
} STRUCT_PACKED ft_action_req;
struct {
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
le16 status_code;
- u8 variable[0]; /* FT Request */
+ u8 variable[]; /* FT Request */
} STRUCT_PACKED ft_action_resp;
struct {
u8 action;
@@ -561,23 +569,23 @@ struct ieee80211_mgmt {
struct {
u8 action;
u8 dialogtoken;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED wnm_sleep_req;
struct {
u8 action;
u8 dialogtoken;
le16 keydata_len;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED wnm_sleep_resp;
struct {
u8 action;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED public_action;
struct {
u8 action; /* 9 */
u8 oui[3];
/* Vendor-specific content */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED vs_public_action;
struct {
u8 action; /* 7 */
@@ -589,7 +597,7 @@ struct ieee80211_mgmt {
* Session Information URL (optional),
* BSS Transition Candidate List
* Entries */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED bss_tm_req;
struct {
u8 action; /* 8 */
@@ -599,7 +607,7 @@ struct ieee80211_mgmt {
/* Target BSSID (optional),
* BSS Transition Candidate List
* Entries (optional) */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED bss_tm_resp;
struct {
u8 action; /* 6 */
@@ -607,12 +615,16 @@ struct ieee80211_mgmt {
u8 query_reason;
/* BSS Transition Candidate List
* Entries (optional) */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED bss_tm_query;
struct {
u8 action; /* 15 */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED slf_prot_action;
+ struct {
+ u8 action;
+ u8 variable[];
+ } STRUCT_PACKED fst_action;
} u;
} STRUCT_PACKED action;
} u;
@@ -1065,6 +1077,15 @@ enum p2p_attr_id {
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7)
+/* P2PS Coordination Protocol Transport Bitmap */
+#define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0)
+#define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1)
+
+struct p2ps_feature_capab {
+ u8 cpt;
+ u8 reserved;
+} STRUCT_PACKED;
+
/* Invitation Flags */
#define P2P_INVITATION_FLAGS_TYPE BIT(0)
@@ -1354,4 +1375,62 @@ struct rrm_link_measurement_report {
u8 variable[0];
} STRUCT_PACKED;
+#define SSID_MAX_LEN 32
+
+/* IEEE Std 802.11ad-2012 - Multi-band element */
+struct multi_band_ie {
+ u8 eid; /* WLAN_EID_MULTI_BAND */
+ u8 len;
+ u8 mb_ctrl;
+ u8 band_id;
+ u8 op_class;
+ u8 chan;
+ u8 bssid[ETH_ALEN];
+ le16 beacon_int;
+ u8 tsf_offs[8];
+ u8 mb_connection_capability;
+ u8 fst_session_tmout;
+ /* Optional:
+ * STA MAC Address
+ * Pairwise Cipher Suite Count
+ * Pairwise Cipher Suite List
+ */
+ u8 variable[0];
+} STRUCT_PACKED;
+
+enum mb_ctrl_sta_role {
+ MB_STA_ROLE_AP = 0,
+ MB_STA_ROLE_TDLS_STA = 1,
+ MB_STA_ROLE_IBSS_STA = 2,
+ MB_STA_ROLE_PCP = 3,
+ MB_STA_ROLE_NON_PCP_NON_AP = 4
+};
+
+#define MB_CTRL_ROLE_MASK (BIT(0) | BIT(1) | BIT(2))
+#define MB_CTRL_ROLE(ctrl) ((u8) ((ctrl) & MB_CTRL_ROLE_MASK))
+#define MB_CTRL_STA_MAC_PRESENT ((u8) (BIT(3)))
+#define MB_CTRL_PAIRWISE_CIPHER_SUITE_PRESENT ((u8) (BIT(4)))
+
+enum mb_band_id {
+ MB_BAND_ID_WIFI_2_4GHZ = 2, /* 2.4 GHz */
+ MB_BAND_ID_WIFI_5GHZ = 4, /* 4.9 and 5 GHz */
+ MB_BAND_ID_WIFI_60GHZ = 5, /* 60 GHz */
+};
+
+#define MB_CONNECTION_CAPABILITY_AP ((u8) (BIT(0)))
+#define MB_CONNECTION_CAPABILITY_PCP ((u8) (BIT(1)))
+#define MB_CONNECTION_CAPABILITY_DLS ((u8) (BIT(2)))
+#define MB_CONNECTION_CAPABILITY_TDLS ((u8) (BIT(3)))
+#define MB_CONNECTION_CAPABILITY_IBSS ((u8) (BIT(4)))
+
+/* IEEE Std 802.11ad-2014 - FST Action field */
+enum fst_action {
+ FST_ACTION_SETUP_REQUEST = 0,
+ FST_ACTION_SETUP_RESPONSE = 1,
+ FST_ACTION_TEAR_DOWN = 2,
+ FST_ACTION_ACK_REQUEST = 3,
+ FST_ACTION_ACK_RESPONSE = 4,
+ FST_ACTION_ON_CHANNEL_TUNNEL = 5,
+};
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index 4dc34c4ad322..8dff30382b60 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -9,6 +9,8 @@
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
+#include "common/ieee802_11_defs.h"
+
enum privsep_cmd {
PRIVSEP_CMD_REGISTER,
PRIVSEP_CMD_UNREGISTER,
@@ -24,12 +26,31 @@ enum privsep_cmd {
PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
PRIVSEP_CMD_L2_SEND,
PRIVSEP_CMD_SET_COUNTRY,
+ PRIVSEP_CMD_AUTHENTICATE,
+};
+
+struct privsep_cmd_authenticate
+{
+ int freq;
+ u8 bssid[ETH_ALEN];
+ u8 ssid[SSID_MAX_LEN];
+ size_t ssid_len;
+ int auth_alg;
+ size_t ie_len;
+ u8 wep_key[4][16];
+ size_t wep_key_len[4];
+ int wep_tx_keyidx;
+ int local_state_change;
+ int p2p;
+ size_t sae_data_len;
+ /* followed by ie_len bytes of ie */
+ /* followed by sae_data_len bytes of sae_data */
};
struct privsep_cmd_associate
{
u8 bssid[ETH_ALEN];
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int hwmode;
int freq;
@@ -66,6 +87,18 @@ enum privsep_event {
PRIVSEP_EVENT_STKSTART,
PRIVSEP_EVENT_FT_RESPONSE,
PRIVSEP_EVENT_RX_EAPOL,
+ PRIVSEP_EVENT_SCAN_STARTED,
+ PRIVSEP_EVENT_AUTH,
+};
+
+struct privsep_event_auth {
+ u8 peer[ETH_ALEN];
+ u8 bssid[ETH_ALEN];
+ u16 auth_type;
+ u16 auth_transaction;
+ u16 status_code;
+ size_t ies_len;
+ /* followed by ies_len bytes of ies */
};
#endif /* PRIVSEP_COMMANDS_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 2117ee7028c1..28985f5194e2 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -132,7 +132,7 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50,
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51,
QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
- /* 53 - reserved for QCA */
+ /* 53 - reserved - was used by QCA, but not in use anymore */
QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56,
@@ -142,6 +142,20 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
/* 61-90 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT = 94,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT = 95,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER = 96,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS = 97,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS = 98,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100,
+ QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101,
+ QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG = 102,
+ QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103,
+ QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104,
+ QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
};
@@ -162,6 +176,15 @@ enum qca_wlan_vendor_attr {
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
QCA_WLAN_VENDOR_ATTR_TEST = 8,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
+ /* Unsigned 32-bit value. */
+ QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA = 9,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10,
+ /* Unsigned 32-bit value */
+ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
+ /* Unsigned 32-bit value from enum qca_set_band. */
+ QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -195,6 +218,12 @@ enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+ QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
@@ -206,6 +235,7 @@ enum qca_wlan_vendor_acs_hw_mode {
QCA_ACS_MODE_IEEE80211G,
QCA_ACS_MODE_IEEE80211A,
QCA_ACS_MODE_IEEE80211AD,
+ QCA_ACS_MODE_IEEE80211ANY,
};
/**
@@ -215,10 +245,13 @@ enum qca_wlan_vendor_acs_hw_mode {
* management offload, a mechanism where the station's firmware
* does the exchange with the AP to establish the temporal keys
* after roaming, rather than having the user space wpa_supplicant do it.
+ * @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
+ * band selection based on channel selection results.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
+ QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@@ -243,4 +276,82 @@ enum qca_wlan_vendor_attr_data_offload_ind {
QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_MAX =
QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST - 1
};
+
+enum qca_vendor_attr_get_preferred_freq_list {
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID,
+ /* A 32-unsigned value; the interface type/mode for which the preferred
+ * frequency list is requested (see enum qca_iface_type for possible
+ * values); used in GET_PREFERRED_FREQ_LIST command from user-space to
+ * kernel and in the kernel response back to user-space.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
+ /* An array of 32-unsigned values; values are frequency (MHz); sent
+ * from kernel space to user space.
+ */
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX =
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST - 1
+};
+
+enum qca_vendor_attr_probable_oper_channel {
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_INVALID,
+ /* 32-bit unsigned value; indicates the connection/iface type likely to
+ * come on this channel (see enum qca_iface_type).
+ */
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
+ /* 32-bit unsigned value; the frequency (MHz) of the probable channel */
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX =
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST - 1
+};
+
+enum qca_iface_type {
+ QCA_IFACE_TYPE_STA,
+ QCA_IFACE_TYPE_AP,
+ QCA_IFACE_TYPE_P2P_CLIENT,
+ QCA_IFACE_TYPE_P2P_GO,
+ QCA_IFACE_TYPE_IBSS,
+ QCA_IFACE_TYPE_TDLS,
+};
+
+enum qca_set_band {
+ QCA_SETBAND_AUTO,
+ QCA_SETBAND_5G,
+ QCA_SETBAND_2G,
+};
+
+/* IEEE 802.11 Vendor Specific elements */
+
+/**
+ * enum qca_vendor_element_id - QCA Vendor Specific element types
+ *
+ * These values are used to identify QCA Vendor Specific elements. The
+ * payload of the element starts with the three octet OUI (OUI_QCA) and
+ * is followed by a single octet type which is defined by this enum.
+ *
+ * @QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST: P2P preferred channel list.
+ * This element can be used to specify preference order for supported
+ * channels. The channels in this list are in preference order (the first
+ * one has the highest preference) and are described as a pair of
+ * (global) Operating Class and Channel Number (each one octet) fields.
+ *
+ * This extends the standard P2P functionality by providing option to have
+ * more than one preferred operating channel. When this element is present,
+ * it replaces the preference indicated in the Operating Channel attribute.
+ * For supporting other implementations, the Operating Channel attribute is
+ * expected to be used with the highest preference channel. Similarly, all
+ * the channels included in this Preferred channel list element are
+ * expected to be included in the Channel List attribute.
+ *
+ * This vendor element may be included in GO Negotiation Request, P2P
+ * Invitation Request, and Provision Discovery Request frames.
+ */
+enum qca_vendor_element_id {
+ QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 588895808fde..503fa1d7b9a9 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -1,6 +1,6 @@
/*
* Simultaneous authentication of equals
- * Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -124,9 +124,7 @@ static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
return NULL;
for (;;) {
- if (iter++ > 100)
- return NULL;
- if (random_get_bytes(val, order_len) < 0)
+ if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
return NULL;
if (order_len_bits % 8)
buf_shift_right(val, order_len, 8 - order_len_bits % 8);
@@ -171,17 +169,107 @@ static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
}
+static struct crypto_bignum *
+get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
+ int *r_odd)
+{
+ for (;;) {
+ struct crypto_bignum *r;
+ u8 tmp[SAE_MAX_ECC_PRIME_LEN];
+
+ if (random_get_bytes(tmp, prime_len) < 0)
+ break;
+ if (prime_bits % 8)
+ buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
+ if (os_memcmp(tmp, prime, prime_len) >= 0)
+ continue;
+ r = crypto_bignum_init_set(tmp, prime_len);
+ if (!r)
+ break;
+ if (crypto_bignum_is_zero(r)) {
+ crypto_bignum_deinit(r, 0);
+ continue;
+ }
+
+ *r_odd = tmp[prime_len - 1] & 0x01;
+ return r;
+ }
+
+ return NULL;
+}
+
+
+static int is_quadratic_residue_blind(struct sae_data *sae,
+ const u8 *prime, size_t bits,
+ const struct crypto_bignum *qr,
+ const struct crypto_bignum *qnr,
+ const struct crypto_bignum *y_sqr)
+{
+ struct crypto_bignum *r, *num;
+ int r_odd, check, res = -1;
+
+ /*
+ * Use the blinding technique to mask y_sqr while determining
+ * whether it is a quadratic residue modulo p to avoid leaking
+ * timing information while determining the Legendre symbol.
+ *
+ * v = y_sqr
+ * r = a random number between 1 and p-1, inclusive
+ * num = (v * r * r) modulo p
+ */
+ r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
+ if (!r)
+ return -1;
+
+ num = crypto_bignum_init();
+ if (!num ||
+ crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
+ crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
+ goto fail;
+
+ if (r_odd) {
+ /*
+ * num = (num * qr) module p
+ * LGR(num, p) = 1 ==> quadratic residue
+ */
+ if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
+ goto fail;
+ check = 1;
+ } else {
+ /*
+ * num = (num * qnr) module p
+ * LGR(num, p) = -1 ==> quadratic residue
+ */
+ if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
+ goto fail;
+ check = -1;
+ }
+
+ res = crypto_bignum_legendre(num, sae->tmp->prime);
+ if (res == -2) {
+ res = -1;
+ goto fail;
+ }
+ res = res == check;
+fail:
+ crypto_bignum_deinit(num, 1);
+ crypto_bignum_deinit(r, 1);
+ return res;
+}
+
+
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
- struct crypto_ec_point *pwe)
+ const u8 *prime,
+ const struct crypto_bignum *qr,
+ const struct crypto_bignum *qnr,
+ struct crypto_bignum **ret_x_cand)
{
- u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN];
- struct crypto_bignum *x;
- int y_bit;
+ u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *y_sqr, *x_cand;
+ int res;
size_t bits;
- if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
- sae->tmp->prime_len) < 0)
- return -1;
+ *ret_x_cand = NULL;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
@@ -197,20 +285,23 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
return 0;
- y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
-
- x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
- if (x == NULL)
+ x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
+ if (!x_cand)
+ return -1;
+ y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
+ if (!y_sqr) {
+ crypto_bignum_deinit(x_cand, 1);
return -1;
- if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) {
- crypto_bignum_deinit(x, 0);
- wpa_printf(MSG_DEBUG, "SAE: No solution found");
- return 0;
}
- crypto_bignum_deinit(x, 0);
- wpa_printf(MSG_DEBUG, "SAE: PWE found");
+ res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
+ crypto_bignum_deinit(y_sqr, 1);
+ if (res <= 0) {
+ crypto_bignum_deinit(x_cand, 1);
+ return res;
+ }
+ *ret_x_cand = x_cand;
return 1;
}
@@ -288,24 +379,77 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
}
+static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
+ const struct crypto_bignum *prime_bn,
+ size_t prime_bits, struct crypto_bignum **qr,
+ struct crypto_bignum **qnr)
+{
+ *qr = NULL;
+ *qnr = NULL;
+
+ while (!(*qr) || !(*qnr)) {
+ u8 tmp[SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_bignum *q;
+ int res;
+
+ if (random_get_bytes(tmp, prime_len) < 0)
+ break;
+ if (prime_bits % 8)
+ buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
+ if (os_memcmp(tmp, prime, prime_len) >= 0)
+ continue;
+ q = crypto_bignum_init_set(tmp, prime_len);
+ if (!q)
+ break;
+ res = crypto_bignum_legendre(q, prime_bn);
+
+ if (res == 1 && !(*qr))
+ *qr = q;
+ else if (res == -1 && !(*qnr))
+ *qnr = q;
+ else
+ crypto_bignum_deinit(q, 0);
+ }
+
+ return (*qr && *qnr) ? 0 : -1;
+}
+
+
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len)
{
- u8 counter, k = 4;
+ u8 counter, k = 40;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[2];
size_t len[2];
- int found = 0;
- struct crypto_ec_point *pwe_tmp;
+ u8 dummy_password[32];
+ size_t dummy_password_len;
+ int pwd_seed_odd = 0;
+ u8 prime[SAE_MAX_ECC_PRIME_LEN];
+ size_t prime_len;
+ struct crypto_bignum *x = NULL, *qr, *qnr;
+ size_t bits;
+ int res;
- if (sae->tmp->pwe_ecc == NULL) {
- sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
- if (sae->tmp->pwe_ecc == NULL)
- return -1;
- }
- pwe_tmp = crypto_ec_point_init(sae->tmp->ec);
- if (pwe_tmp == NULL)
+ dummy_password_len = password_len;
+ if (dummy_password_len > sizeof(dummy_password))
+ dummy_password_len = sizeof(dummy_password);
+ if (random_get_bytes(dummy_password, dummy_password_len) < 0)
+ return -1;
+
+ prime_len = sae->tmp->prime_len;
+ if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
+ prime_len) < 0)
+ return -1;
+ bits = crypto_ec_prime_len_bits(sae->tmp->ec);
+
+ /*
+ * Create a random quadratic residue (qr) and quadratic non-residue
+ * (qnr) modulo p for blinding purposes during the loop.
+ */
+ if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
+ &qr, &qnr) < 0)
return -1;
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
@@ -313,8 +457,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
+ * base = password
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
- * password || counter)
+ * base || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
@@ -328,9 +473,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
- for (counter = 1; counter < k || !found; counter++) {
+ for (counter = 1; counter <= k || !x; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
- int res;
+ struct crypto_bignum *x_cand;
if (counter > 200) {
/* This should not happen in practice */
@@ -342,25 +487,58 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
pwd_seed) < 0)
break;
+
res = sae_test_pwd_seed_ecc(sae, pwd_seed,
- found ? pwe_tmp :
- sae->tmp->pwe_ecc);
+ prime, qr, qnr, &x_cand);
if (res < 0)
- break;
- if (res == 0)
- continue;
- if (found) {
- wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was "
- "already selected)");
- } else {
- wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
- found = 1;
+ goto fail;
+ if (res > 0 && !x) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Selected pwd-seed with counter %u",
+ counter);
+ x = x_cand;
+ pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
+ os_memset(pwd_seed, 0, sizeof(pwd_seed));
+
+ /*
+ * Use a dummy password for the following rounds, if
+ * any.
+ */
+ addr[0] = dummy_password;
+ len[0] = dummy_password_len;
+ } else if (res > 0) {
+ crypto_bignum_deinit(x_cand, 1);
}
}
- crypto_ec_point_deinit(pwe_tmp, 1);
+ if (!x) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
+ res = -1;
+ goto fail;
+ }
- return found ? 0 : -1;
+ if (!sae->tmp->pwe_ecc)
+ sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
+ if (!sae->tmp->pwe_ecc)
+ res = -1;
+ else
+ res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
+ sae->tmp->pwe_ecc, x,
+ pwd_seed_odd);
+ crypto_bignum_deinit(x, 1);
+ if (res < 0) {
+ /*
+ * This should not happen since we already checked that there
+ * is a result.
+ */
+ wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
+ }
+
+fail:
+ crypto_bignum_deinit(qr, 0);
+ crypto_bignum_deinit(qnr, 0);
+
+ return res;
}
@@ -472,27 +650,41 @@ static int sae_derive_commit(struct sae_data *sae)
{
struct crypto_bignum *mask;
int ret = -1;
+ unsigned int counter = 0;
+
+ do {
+ counter++;
+ if (counter > 100) {
+ /*
+ * This cannot really happen in practice if the random
+ * number generator is working. Anyway, to avoid even a
+ * theoretical infinite loop, break out after 100
+ * attemps.
+ */
+ return -1;
+ }
- mask = sae_get_rand_and_mask(sae);
- if (mask == NULL) {
- wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
- return -1;
- }
-
- /* commit-scalar = (rand + mask) modulo r */
- if (!sae->tmp->own_commit_scalar) {
- sae->tmp->own_commit_scalar = crypto_bignum_init();
- if (!sae->tmp->own_commit_scalar)
- goto fail;
- }
- crypto_bignum_add(sae->tmp->sae_rand, mask,
- sae->tmp->own_commit_scalar);
- crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
- sae->tmp->own_commit_scalar);
+ mask = sae_get_rand_and_mask(sae);
+ if (mask == NULL) {
+ wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
+ return -1;
+ }
- if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0)
- goto fail;
- if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)
+ /* commit-scalar = (rand + mask) modulo r */
+ if (!sae->tmp->own_commit_scalar) {
+ sae->tmp->own_commit_scalar = crypto_bignum_init();
+ if (!sae->tmp->own_commit_scalar)
+ goto fail;
+ }
+ crypto_bignum_add(sae->tmp->sae_rand, mask,
+ sae->tmp->own_commit_scalar);
+ crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
+ sae->tmp->own_commit_scalar);
+ } while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
+ crypto_bignum_is_one(sae->tmp->own_commit_scalar));
+
+ if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
+ (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
goto fail;
ret = 0;
@@ -506,15 +698,12 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
struct sae_data *sae)
{
- if (sae->tmp == NULL)
- return -1;
- if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
- password_len) < 0)
- return -1;
- if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
- password_len) < 0)
- return -1;
- if (sae_derive_commit(sae) < 0)
+ if (sae->tmp == NULL ||
+ (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
+ password_len) < 0) ||
+ (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
+ password_len) < 0) ||
+ sae_derive_commit(sae) < 0)
return -1;
return 0;
}
@@ -780,8 +969,9 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- /* 0 < scalar < r */
+ /* 1 < scalar < r */
if (crypto_bignum_is_zero(peer_scalar) ||
+ crypto_bignum_is_one(peer_scalar) ||
crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
crypto_bignum_deinit(peer_scalar, 0);
@@ -847,7 +1037,8 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
const u8 *end)
{
- struct crypto_bignum *res;
+ struct crypto_bignum *res, *one;
+ const u8 one_bin[1] = { 0x01 };
if (pos + sae->tmp->prime_len > end) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
@@ -862,18 +1053,23 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
crypto_bignum_init_set(pos, sae->tmp->prime_len);
if (sae->tmp->peer_commit_element_ffc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
+ /* 1 < element < p - 1 */
+ res = crypto_bignum_init();
+ one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
+ if (!res || !one ||
+ crypto_bignum_sub(sae->tmp->prime, one, res) ||
+ crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
- crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc,
- sae->tmp->prime) >= 0) {
+ crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
+ crypto_bignum_deinit(res, 0);
+ crypto_bignum_deinit(one, 0);
wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
+ crypto_bignum_deinit(one, 0);
/* scalar-op(r, ELEMENT) = 1 modulo p */
- res = crypto_bignum_init();
- if (res == NULL ||
- crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
+ if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
sae->tmp->order, sae->tmp->prime, res) < 0 ||
!crypto_bignum_is_one(res)) {
wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
@@ -918,7 +1114,34 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
return res;
/* commit-element */
- return sae_parse_commit_element(sae, pos, end);
+ res = sae_parse_commit_element(sae, pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+
+ /*
+ * Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
+ * the values we sent which would be evidence of a reflection attack.
+ */
+ if (!sae->tmp->own_commit_scalar ||
+ crypto_bignum_cmp(sae->tmp->own_commit_scalar,
+ sae->peer_commit_scalar) != 0 ||
+ (sae->tmp->dh &&
+ (!sae->tmp->own_commit_element_ffc ||
+ crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
+ sae->tmp->peer_commit_element_ffc) != 0)) ||
+ (sae->tmp->ec &&
+ (!sae->tmp->own_commit_element_ecc ||
+ crypto_ec_point_cmp(sae->tmp->ec,
+ sae->tmp->own_commit_element_ecc,
+ sae->tmp->peer_commit_element_ecc) != 0)))
+ return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
+
+ /*
+ * This is a reflection attack - return special value to trigger caller
+ * to silently discard the frame instead of replying with a specific
+ * status code.
+ */
+ return SAE_SILENTLY_DISCARD;
}
diff --git a/src/common/sae.h b/src/common/sae.h
index 3ebf40cf4a45..c07026cd497c 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -18,6 +18,9 @@
#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+/* Special value returned by sae_parse_commit() */
+#define SAE_SILENTLY_DISCARD 65535
+
struct sae_temporary_data {
u8 kck[SAE_KCK_LEN];
struct crypto_bignum *own_commit_scalar;
diff --git a/src/common/version.h b/src/common/version.h
index e39a8dbf92e7..a5cc5b7b5bcc 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "2.4" VERSION_STR_POSTFIX
+#define VERSION_STR "2.5" VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index de81d53694c2..e9d4248d72d4 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -170,6 +170,12 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+#ifdef CONFIG_SUITEB192
+ if (wpa_key_mgmt_sha384(akmp))
+ sha384_prf(pmk, pmk_len, label, data, sizeof(data),
+ tmp, ptk_len);
+ else
+#endif /* CONFIG_SUITEB192 */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
@@ -207,8 +213,10 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic)
{
- u8 *buf, *pos;
- size_t buf_len;
+ const u8 *addr[9];
+ size_t len[9];
+ size_t i, num_elem = 0;
+ u8 zero_mic[16];
if (kck_len != 16) {
wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
@@ -216,48 +224,58 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
return -1;
}
- buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
- buf = os_malloc(buf_len);
- if (buf == NULL)
- return -1;
+ addr[num_elem] = sta_addr;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+
+ addr[num_elem] = ap_addr;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+
+ addr[num_elem] = &transaction_seqnum;
+ len[num_elem] = 1;
+ num_elem++;
- pos = buf;
- os_memcpy(pos, sta_addr, ETH_ALEN);
- pos += ETH_ALEN;
- os_memcpy(pos, ap_addr, ETH_ALEN);
- pos += ETH_ALEN;
- *pos++ = transaction_seqnum;
if (rsnie) {
- os_memcpy(pos, rsnie, rsnie_len);
- pos += rsnie_len;
+ addr[num_elem] = rsnie;
+ len[num_elem] = rsnie_len;
+ num_elem++;
}
if (mdie) {
- os_memcpy(pos, mdie, mdie_len);
- pos += mdie_len;
+ addr[num_elem] = mdie;
+ len[num_elem] = mdie_len;
+ num_elem++;
}
if (ftie) {
- struct rsn_ftie *_ftie;
- os_memcpy(pos, ftie, ftie_len);
- if (ftie_len < 2 + sizeof(*_ftie)) {
- os_free(buf);
+ if (ftie_len < 2 + sizeof(struct rsn_ftie))
return -1;
- }
- _ftie = (struct rsn_ftie *) (pos + 2);
- os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
- pos += ftie_len;
+
+ /* IE hdr and mic_control */
+ addr[num_elem] = ftie;
+ len[num_elem] = 2 + 2;
+ num_elem++;
+
+ /* MIC field with all zeros */
+ os_memset(zero_mic, 0, sizeof(zero_mic));
+ addr[num_elem] = zero_mic;
+ len[num_elem] = sizeof(zero_mic);
+ num_elem++;
+
+ /* Rest of FTIE */
+ addr[num_elem] = ftie + 2 + 2 + 16;
+ len[num_elem] = ftie_len - (2 + 2 + 16);
+ num_elem++;
}
if (ric) {
- os_memcpy(pos, ric, ric_len);
- pos += ric_len;
+ addr[num_elem] = ric;
+ len[num_elem] = ric_len;
+ num_elem++;
}
- wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
- if (omac1_aes_128(kck, buf, pos - buf, mic)) {
- os_free(buf);
+ for (i = 0; i < num_elem; i++)
+ wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
+ if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
return -1;
- }
-
- os_free(buf);
return 0;
}
@@ -344,6 +362,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
parse->rsn_pmkid = data.pmkid;
break;
case WLAN_EID_MOBILITY_DOMAIN:
+ if (pos[1] < sizeof(struct rsn_mdie))
+ return -1;
parse->mdie = pos + 2;
parse->mdie_len = pos[1];
break;
@@ -356,6 +376,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
return -1;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
+ if (pos[1] != 5)
+ break;
parse->tie = pos + 2;
parse->tie_len = pos[1];
break;
@@ -416,14 +438,10 @@ static int rsn_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
return WPA_CIPHER_NONE;
- if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
- return WPA_CIPHER_WEP40;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
- if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
- return WPA_CIPHER_WEP104;
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
@@ -474,15 +492,15 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
+ return WPA_KEY_MGMT_OSEN;
return 0;
}
-static int wpa_cipher_valid_group(int cipher)
+int wpa_cipher_valid_group(int cipher)
{
return wpa_cipher_valid_pairwise(cipher) ||
- cipher == WPA_CIPHER_WEP104 ||
- cipher == WPA_CIPHER_WEP40 ||
cipher == WPA_CIPHER_GTK_NOT_USED;
}
@@ -508,7 +526,6 @@ int wpa_cipher_valid_mgmt_group(int cipher)
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
- const struct rsn_ie_hdr *hdr;
const u8 *pos;
int left;
int i, count;
@@ -538,18 +555,29 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
return -1;
}
- hdr = (const struct rsn_ie_hdr *) rsn_ie;
+ if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
+ rsn_ie[1] == rsn_ie_len - 2 &&
+ WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
+ pos = rsn_ie + 6;
+ left = rsn_ie_len - 6;
- if (hdr->elem_id != WLAN_EID_RSN ||
- hdr->len != rsn_ie_len - 2 ||
- WPA_GET_LE16(hdr->version) != RSN_VERSION) {
- wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
- __func__);
- return -2;
- }
+ data->proto = WPA_PROTO_OSEN;
+ } else {
+ const struct rsn_ie_hdr *hdr;
- pos = (const u8 *) (hdr + 1);
- left = rsn_ie_len - sizeof(*hdr);
+ hdr = (const struct rsn_ie_hdr *) rsn_ie;
+
+ if (hdr->elem_id != WLAN_EID_RSN ||
+ hdr->len != rsn_ie_len - 2 ||
+ WPA_GET_LE16(hdr->version) != RSN_VERSION) {
+ wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+ __func__);
+ return -2;
+ }
+
+ pos = (const u8 *) (hdr + 1);
+ left = rsn_ie_len - sizeof(*hdr);
+ }
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
@@ -667,14 +695,10 @@ static int wpa_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
return WPA_CIPHER_NONE;
- if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
- return WPA_CIPHER_WEP40;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
- if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
- return WPA_CIPHER_WEP104;
return 0;
}
@@ -709,11 +733,6 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
data->num_pmkid = 0;
data->mgmt_group_cipher = 0;
- if (wpa_ie_len == 0) {
- /* No WPA IE - fail silently */
- return -1;
- }
-
if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
__func__, (unsigned long) wpa_ie_len);
@@ -814,7 +833,7 @@ void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
{
- u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
+ u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
u8 *pos, r0_key_data[48], hash[32];
const u8 *addr[2];
@@ -828,7 +847,7 @@ void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
* PMK-R0 = L(R0-Key-Data, 0, 256)
* PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
*/
- if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
+ if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
return;
pos = buf;
*pos++ = ssid_len;
@@ -1279,6 +1298,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
os_memmove(rpos + 2, rpos, end - rpos);
*rpos++ = 0;
*rpos++ = 0;
+ added += 2;
+ start[1] += 2;
+ rend = rpos;
} else {
/* Skip RSN Capabilities */
rpos += 2;
@@ -1291,7 +1313,7 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
if (rpos == rend) {
/* No PMKID-Count field included; add it */
- os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
+ os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos);
WPA_PUT_LE16(rpos, 1);
rpos += 2;
os_memcpy(rpos, pmkid, PMKID_LEN);
@@ -1306,7 +1328,7 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
}
WPA_PUT_LE16(rpos, 1);
rpos += 2;
- os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
+ os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos);
os_memcpy(rpos, pmkid, PMKID_LEN);
added += PMKID_LEN;
start[1] += PMKID_LEN;
@@ -1335,10 +1357,6 @@ int wpa_cipher_key_len(int cipher)
return 16;
case WPA_CIPHER_TKIP:
return 32;
- case WPA_CIPHER_WEP104:
- return 13;
- case WPA_CIPHER_WEP40:
- return 5;
}
return 0;
@@ -1354,9 +1372,6 @@ int wpa_cipher_rsc_len(int cipher)
case WPA_CIPHER_GCMP:
case WPA_CIPHER_TKIP:
return 6;
- case WPA_CIPHER_WEP104:
- case WPA_CIPHER_WEP40:
- return 0;
}
return 0;
@@ -1376,9 +1391,6 @@ int wpa_cipher_to_alg(int cipher)
return WPA_ALG_GCMP;
case WPA_CIPHER_TKIP:
return WPA_ALG_TKIP;
- case WPA_CIPHER_WEP104:
- case WPA_CIPHER_WEP40:
- return WPA_ALG_WEP;
case WPA_CIPHER_AES_128_CMAC:
return WPA_ALG_IGTK;
case WPA_CIPHER_BIP_GMAC_128:
@@ -1416,12 +1428,6 @@ u32 wpa_cipher_to_suite(int proto, int cipher)
if (cipher & WPA_CIPHER_TKIP)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
- if (cipher & WPA_CIPHER_WEP104)
- return (proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
- if (cipher & WPA_CIPHER_WEP40)
- return (proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
if (cipher & WPA_CIPHER_NONE)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
@@ -1525,10 +1531,6 @@ int wpa_pick_group_cipher(int ciphers)
return WPA_CIPHER_GTK_NOT_USED;
if (ciphers & WPA_CIPHER_TKIP)
return WPA_CIPHER_TKIP;
- if (ciphers & WPA_CIPHER_WEP104)
- return WPA_CIPHER_WEP104;
- if (ciphers & WPA_CIPHER_WEP40)
- return WPA_CIPHER_WEP40;
return -1;
}
@@ -1626,20 +1628,6 @@ int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
return -1;
pos += ret;
}
- if (ciphers & WPA_CIPHER_WEP104) {
- ret = os_snprintf(pos, end - pos, "%sWEP104",
- pos == start ? "" : delim);
- if (os_snprintf_error(end - pos, ret))
- return -1;
- pos += ret;
- }
- if (ciphers & WPA_CIPHER_WEP40) {
- ret = os_snprintf(pos, end - pos, "%sWEP40",
- pos == start ? "" : delim);
- if (os_snprintf_error(end - pos, ret))
- return -1;
- pos += ret;
- }
if (ciphers & WPA_CIPHER_NONE) {
ret = os_snprintf(pos, end - pos, "%sNONE",
pos == start ? "" : delim);
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 091e317fdd68..c08f6514ab57 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -9,8 +9,6 @@
#ifndef WPA_COMMON_H
#define WPA_COMMON_H
-#define WPA_MAX_SSID_LEN 32
-
/* IEEE 802.11i */
#define PMKID_LEN 16
#define PMK_LEN 32
@@ -24,8 +22,8 @@
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
#define WPA_ALLOWED_GROUP_CIPHERS \
-(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \
-WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
+(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | \
+WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
WPA_CIPHER_GTK_NOT_USED)
#define WPA_SELECTOR_LEN 4
@@ -42,13 +40,8 @@ WPA_CIPHER_GTK_NOT_USED)
#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0)
#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
-#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
-#if 0
-#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
-#endif
#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
-#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
@@ -70,13 +63,11 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
-#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#if 0
#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#endif
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
-#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
@@ -308,7 +299,6 @@ struct wpa_igtk_kde {
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 ft_capab;
@@ -336,7 +326,6 @@ struct rsn_rdie {
le16 status_code;
} STRUCT_PACKED;
-#endif /* CONFIG_IEEE80211R */
#ifdef _MSC_VER
#pragma pack(pop)
@@ -446,6 +435,7 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
int wpa_cipher_to_alg(int cipher);
+int wpa_cipher_valid_group(int cipher);
int wpa_cipher_valid_pairwise(int cipher);
int wpa_cipher_valid_mgmt_group(int cipher);
u32 wpa_cipher_to_suite(int proto, int cipher);
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index ccaaf1b056b5..5733aa605d18 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -21,6 +21,7 @@
#ifdef ANDROID
#include <dirent.h>
+#include <sys/stat.h>
#include <cutils/sockets.h>
#include "private/android_filesystem_config.h"
#endif /* ANDROID */
@@ -84,6 +85,13 @@ struct wpa_ctrl {
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
+ return wpa_ctrl_open2(ctrl_path, NULL);
+}
+
+
+struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
+ const char *cli_path)
+{
struct wpa_ctrl *ctrl;
static int counter = 0;
int ret;
@@ -107,10 +115,18 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again:
- ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
- CONFIG_CTRL_IFACE_CLIENT_DIR "/"
- CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
- (int) getpid(), counter);
+ if (cli_path && cli_path[0] == '/') {
+ ret = os_snprintf(ctrl->local.sun_path,
+ sizeof(ctrl->local.sun_path),
+ "%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+ cli_path, (int) getpid(), counter);
+ } else {
+ ret = os_snprintf(ctrl->local.sun_path,
+ sizeof(ctrl->local.sun_path),
+ CONFIG_CTRL_IFACE_CLIENT_DIR "/"
+ CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+ (int) getpid(), counter);
+ }
if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
close(ctrl->s);
os_free(ctrl);
@@ -136,6 +152,8 @@ try_again:
#ifdef ANDROID
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+ /* Set group even if we do not have privileges to change owner */
+ chown(ctrl->local.sun_path, -1, AID_WIFI);
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 1d19fc550df6..3de46823588b 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -28,6 +28,8 @@ extern "C" {
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
/** Association rejected during connection attempt */
#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
+/** Authentication rejected during connection attempt */
+#define WPA_EVENT_AUTH_REJECT "CTRL-EVENT-AUTH-REJECT "
/** wpa_supplicant is exiting */
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
/** Password change was completed successfully */
@@ -68,6 +70,8 @@ extern "C" {
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
+/** No suitable network was found */
+#define WPA_EVENT_NETWORK_NOT_FOUND "CTRL-EVENT-NETWORK-NOT-FOUND "
/** Change in the signal level was reported by the driver */
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
/** Regulatory domain channel */
@@ -227,6 +231,7 @@ extern "C" {
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
@@ -276,6 +281,7 @@ extern "C" {
#define WPA_BSS_MASK_MESH_SCAN BIT(18)
#define WPA_BSS_MASK_SNR BIT(19)
#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20)
+#define WPA_BSS_MASK_FST BIT(21)
/* VENDOR_ELEM_* frame id values */
@@ -312,6 +318,20 @@ enum wpa_vendor_elem_frame {
*/
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
+/**
+ * wpa_ctrl_open2 - Open a control interface to wpa_supplicant/hostapd
+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
+ * @cli_path: Path for client UNIX domain sockets; ignored if UDP socket
+ * is used.
+ * Returns: Pointer to abstract control interface data or %NULL on failure
+ *
+ * This function is used to open a control interface to wpa_supplicant/hostapd
+ * when the socket path for client need to be specified explicitly. Default
+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd and client
+ * socket path is /tmp.
+ */
+struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path, const char *cli_path);
+
/**
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index f2d5662ff01e..534c4bd78654 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -614,6 +614,15 @@ int crypto_bignum_is_zero(const struct crypto_bignum *a);
int crypto_bignum_is_one(const struct crypto_bignum *a);
/**
+ * crypto_bignum_legendre - Compute the Legendre symbol (a/p)
+ * @a: Bignum
+ * @p: Bignum
+ * Returns: Legendre symbol -1,0,1 on success; -2 on calculation failure
+ */
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+ const struct crypto_bignum *p);
+
+/**
* struct crypto_ec - Elliptic curve context
*
* Internal data structure for EC implementation. The contents is specific
@@ -758,6 +767,16 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
const struct crypto_bignum *x, int y_bit);
/**
+ * crypto_ec_point_compute_y_sqr - Compute y^2 = x^3 + ax + b
+ * @e: EC context from crypto_ec_init()
+ * @x: x coordinate
+ * Returns: y^2 on success, %NULL failure
+ */
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x);
+
+/**
* crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
* @e: EC context from crypto_ec_init()
* @p: EC point
@@ -776,4 +795,15 @@ int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
const struct crypto_ec_point *p);
+/**
+ * crypto_ec_point_cmp - Compare two EC points
+ * @e: EC context from crypto_ec_init()
+ * @a: EC point
+ * @b: EC point
+ * Returns: 0 on equal, non-zero otherwise
+ */
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+ const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_cryptoapi.c b/src/crypto/crypto_cryptoapi.c
deleted file mode 100644
index 55a069b0d036..000000000000
--- a/src/crypto/crypto_cryptoapi.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Crypto wrapper for Microsoft CryptoAPI
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-
-#include "common.h"
-#include "crypto.h"
-
-#ifndef MS_ENH_RSA_AES_PROV
-#ifdef UNICODE
-#define MS_ENH_RSA_AES_PROV \
-L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#else
-#define MS_ENH_RSA_AES_PROV \
-"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
-#endif
-#endif /* MS_ENH_RSA_AES_PROV */
-
-#ifndef CALG_HMAC
-#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
-#endif
-
-#ifdef __MINGW32_VERSION
-/*
- * MinGW does not yet include all the needed definitions for CryptoAPI, so
- * define here whatever extra is needed.
- */
-
-static BOOL WINAPI
-(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
- PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
-= NULL; /* to be loaded from crypt32.dll */
-
-
-static int mingw_load_crypto_func(void)
-{
- HINSTANCE dll;
-
- /* MinGW does not yet have full CryptoAPI support, so load the needed
- * function here. */
-
- if (CryptImportPublicKeyInfo)
- return 0;
-
- dll = LoadLibrary("crypt32");
- if (dll == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
- "library");
- return -1;
- }
-
- CryptImportPublicKeyInfo = GetProcAddress(
- dll, "CryptImportPublicKeyInfo");
- if (CryptImportPublicKeyInfo == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
- "CryptImportPublicKeyInfo() address from "
- "crypt32 library");
- return -1;
- }
-
- return 0;
-}
-
-#else /* __MINGW32_VERSION */
-
-static int mingw_load_crypto_func(void)
-{
- return 0;
-}
-
-#endif /* __MINGW32_VERSION */
-
-
-static void cryptoapi_report_error(const char *msg)
-{
- char *s, *pos;
- DWORD err = GetLastError();
-
- if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM,
- NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
- }
-
- pos = s;
- while (*pos) {
- if (*pos == '\n' || *pos == '\r') {
- *pos = '\0';
- break;
- }
- pos++;
- }
-
- wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
- LocalFree(s);
-}
-
-
-int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
-{
- HCRYPTPROV prov;
- HCRYPTHASH hash;
- size_t i;
- DWORD hlen;
- int ret = 0;
-
- if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- return -1;
- }
-
- if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
- cryptoapi_report_error("CryptCreateHash");
- CryptReleaseContext(prov, 0);
- return -1;
- }
-
- for (i = 0; i < num_elem; i++) {
- if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
- cryptoapi_report_error("CryptHashData");
- CryptDestroyHash(hash);
- CryptReleaseContext(prov, 0);
- }
- }
-
- hlen = hash_len;
- if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
- cryptoapi_report_error("CryptGetHashParam");
- ret = -1;
- }
-
- CryptDestroyHash(hash);
- CryptReleaseContext(prov, 0);
-
- return ret;
-}
-
-
-int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
-}
-
-
-void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
-{
- u8 next, tmp;
- int i;
- HCRYPTPROV prov;
- HCRYPTKEY ckey;
- DWORD dlen;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[8];
- } key_blob;
- DWORD mode = CRYPT_MODE_ECB;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.hdr.aiKeyAlg = CALG_DES;
- key_blob.len = 8;
-
- /* Add parity bits to the key */
- next = 0;
- for (i = 0; i < 7; i++) {
- tmp = key[i];
- key_blob.key[i] = (tmp >> i) | next | 1;
- next = tmp << (7 - i);
- }
- key_blob.key[i] = next | 1;
-
- if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
- "%d", (int) GetLastError());
- return;
- }
-
- if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
- &ckey)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
- (int) GetLastError());
- CryptReleaseContext(prov, 0);
- return;
- }
-
- if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
- "failed: %d", (int) GetLastError());
- CryptDestroyKey(ckey);
- CryptReleaseContext(prov, 0);
- return;
- }
-
- os_memcpy(cypher, clear, 8);
- dlen = 8;
- if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
- (int) GetLastError());
- os_memset(cypher, 0, 8);
- }
-
- CryptDestroyKey(ckey);
- CryptReleaseContext(prov, 0);
-}
-
-
-int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
-}
-
-
-int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
-{
- return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
-}
-
-
-struct aes_context {
- HCRYPTPROV prov;
- HCRYPTKEY ckey;
-};
-
-
-void * aes_encrypt_init(const u8 *key, size_t len)
-{
- struct aes_context *akey;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[16];
- } key_blob;
- DWORD mode = CRYPT_MODE_ECB;
-
- if (len != 16)
- return NULL;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.hdr.aiKeyAlg = CALG_AES_128;
- key_blob.len = len;
- os_memcpy(key_blob.key, key, len);
-
- akey = os_zalloc(sizeof(*akey));
- if (akey == NULL)
- return NULL;
-
- if (!CryptAcquireContext(&akey->prov, NULL,
- MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
- CRYPT_VERIFYCONTEXT)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
- "%d", (int) GetLastError());
- os_free(akey);
- return NULL;
- }
-
- if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
- 0, 0, &akey->ckey)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
- (int) GetLastError());
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- return NULL;
- }
-
- if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
- "failed: %d", (int) GetLastError());
- CryptDestroyKey(akey->ckey);
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- return NULL;
- }
-
- return akey;
-}
-
-
-void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
-{
- struct aes_context *akey = ctx;
- DWORD dlen;
-
- os_memcpy(crypt, plain, 16);
- dlen = 16;
- if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
- (int) GetLastError());
- os_memset(crypt, 0, 16);
- }
-}
-
-
-void aes_encrypt_deinit(void *ctx)
-{
- struct aes_context *akey = ctx;
- if (akey) {
- CryptDestroyKey(akey->ckey);
- CryptReleaseContext(akey->prov, 0);
- os_free(akey);
- }
-}
-
-
-void * aes_decrypt_init(const u8 *key, size_t len)
-{
- return aes_encrypt_init(key, len);
-}
-
-
-void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
-{
- struct aes_context *akey = ctx;
- DWORD dlen;
-
- os_memcpy(plain, crypt, 16);
- dlen = 16;
-
- if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
- (int) GetLastError());
- }
-}
-
-
-void aes_decrypt_deinit(void *ctx)
-{
- aes_encrypt_deinit(ctx);
-}
-
-
-struct crypto_hash {
- enum crypto_hash_alg alg;
- int error;
- HCRYPTPROV prov;
- HCRYPTHASH hash;
- HCRYPTKEY key;
-};
-
-struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
- size_t key_len)
-{
- struct crypto_hash *ctx;
- ALG_ID calg;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[32];
- } key_blob;
-
- os_memset(&key_blob, 0, sizeof(key_blob));
- switch (alg) {
- case CRYPTO_HASH_ALG_MD5:
- calg = CALG_MD5;
- break;
- case CRYPTO_HASH_ALG_SHA1:
- calg = CALG_SHA;
- break;
- case CRYPTO_HASH_ALG_HMAC_MD5:
- case CRYPTO_HASH_ALG_HMAC_SHA1:
- calg = CALG_HMAC;
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- /*
- * Note: RC2 is not really used, but that can be used to
- * import HMAC keys of up to 16 byte long.
- * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
- * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
- */
- key_blob.hdr.aiKeyAlg = CALG_RC2;
- key_blob.len = key_len;
- if (key_len > sizeof(key_blob.key))
- return NULL;
- os_memcpy(key_blob.key, key, key_len);
- break;
- default:
- return NULL;
- }
-
- ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- ctx->alg = alg;
-
- if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- os_free(ctx);
- return NULL;
- }
-
- if (calg == CALG_HMAC) {
-#ifndef CRYPT_IPSEC_HMAC_KEY
-#define CRYPT_IPSEC_HMAC_KEY 0x00000100
-#endif
- if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
- sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
- &ctx->key)) {
- cryptoapi_report_error("CryptImportKey");
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
- }
-
- if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
- cryptoapi_report_error("CryptCreateHash");
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
-
- if (calg == CALG_HMAC) {
- HMAC_INFO info;
- os_memset(&info, 0, sizeof(info));
- switch (alg) {
- case CRYPTO_HASH_ALG_HMAC_MD5:
- info.HashAlgid = CALG_MD5;
- break;
- case CRYPTO_HASH_ALG_HMAC_SHA1:
- info.HashAlgid = CALG_SHA;
- break;
- default:
- /* unreachable */
- break;
- }
-
- if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
- 0)) {
- cryptoapi_report_error("CryptSetHashParam");
- CryptDestroyHash(ctx->hash);
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
- return NULL;
- }
- }
-
- return ctx;
-}
-
-
-void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
-{
- if (ctx == NULL || ctx->error)
- return;
-
- if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
- cryptoapi_report_error("CryptHashData");
- ctx->error = 1;
- }
-}
-
-
-int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
-{
- int ret = 0;
- DWORD hlen;
-
- if (ctx == NULL)
- return -2;
-
- if (mac == NULL || len == NULL)
- goto done;
-
- if (ctx->error) {
- ret = -2;
- goto done;
- }
-
- hlen = *len;
- if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
- cryptoapi_report_error("CryptGetHashParam");
- ret = -2;
- }
- *len = hlen;
-
-done:
- if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
- ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
- CryptDestroyKey(ctx->key);
-
- os_free(ctx);
-
- return ret;
-}
-
-
-struct crypto_cipher {
- HCRYPTPROV prov;
- HCRYPTKEY key;
-};
-
-
-struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
- const u8 *iv, const u8 *key,
- size_t key_len)
-{
- struct crypto_cipher *ctx;
- struct {
- BLOBHEADER hdr;
- DWORD len;
- BYTE key[32];
- } key_blob;
- DWORD mode = CRYPT_MODE_CBC;
-
- key_blob.hdr.bType = PLAINTEXTKEYBLOB;
- key_blob.hdr.bVersion = CUR_BLOB_VERSION;
- key_blob.hdr.reserved = 0;
- key_blob.len = key_len;
- if (key_len > sizeof(key_blob.key))
- return NULL;
- os_memcpy(key_blob.key, key, key_len);
-
- switch (alg) {
- case CRYPTO_CIPHER_ALG_AES:
- if (key_len == 32)
- key_blob.hdr.aiKeyAlg = CALG_AES_256;
- else if (key_len == 24)
- key_blob.hdr.aiKeyAlg = CALG_AES_192;
- else
- key_blob.hdr.aiKeyAlg = CALG_AES_128;
- break;
- case CRYPTO_CIPHER_ALG_3DES:
- key_blob.hdr.aiKeyAlg = CALG_3DES;
- break;
- case CRYPTO_CIPHER_ALG_DES:
- key_blob.hdr.aiKeyAlg = CALG_DES;
- break;
- case CRYPTO_CIPHER_ALG_RC2:
- key_blob.hdr.aiKeyAlg = CALG_RC2;
- break;
- case CRYPTO_CIPHER_ALG_RC4:
- key_blob.hdr.aiKeyAlg = CALG_RC4;
- break;
- default:
- return NULL;
- }
-
- ctx = os_zalloc(sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
- PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
- cryptoapi_report_error("CryptAcquireContext");
- goto fail1;
- }
-
- if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
- sizeof(key_blob), 0, 0, &ctx->key)) {
- cryptoapi_report_error("CryptImportKey");
- goto fail2;
- }
-
- if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
- cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
- goto fail3;
- }
-
- if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
- cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
- goto fail3;
- }
-
- return ctx;
-
-fail3:
- CryptDestroyKey(ctx->key);
-fail2:
- CryptReleaseContext(ctx->prov, 0);
-fail1:
- os_free(ctx);
- return NULL;
-}
-
-
-int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
- u8 *crypt, size_t len)
-{
- DWORD dlen;
-
- os_memcpy(crypt, plain, len);
- dlen = len;
- if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
- cryptoapi_report_error("CryptEncrypt");
- os_memset(crypt, 0, len);
- return -1;
- }
-
- return 0;
-}
-
-
-int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
- u8 *plain, size_t len)
-{
- DWORD dlen;
-
- os_memcpy(plain, crypt, len);
- dlen = len;
- if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
- cryptoapi_report_error("CryptDecrypt");
- return -1;
- }
-
- return 0;
-}
-
-
-void crypto_cipher_deinit(struct crypto_cipher *ctx)
-{
- CryptDestroyKey(ctx->key);
- CryptReleaseContext(ctx->prov, 0);
- os_free(ctx);
-}
-
-
-struct crypto_public_key {
- HCRYPTPROV prov;
- HCRYPTKEY rsa;
-};
-
-struct crypto_private_key {
- HCRYPTPROV prov;
- HCRYPTKEY rsa;
-};
-
-
-struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
-{
- /* Use crypto_public_key_from_cert() instead. */
- return NULL;
-}
-
-
-struct crypto_private_key * crypto_private_key_import(const u8 *key,
- size_t len,
- const char *passwd)
-{
- /* TODO */
- return NULL;
-}
-
-
-struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
- size_t len)
-{
- struct crypto_public_key *pk;
- PCCERT_CONTEXT cc;
-
- pk = os_zalloc(sizeof(*pk));
- if (pk == NULL)
- return NULL;
-
- cc = CertCreateCertificateContext(X509_ASN_ENCODING |
- PKCS_7_ASN_ENCODING, buf, len);
- if (!cc) {
- cryptoapi_report_error("CryptCreateCertificateContext");
- os_free(pk);
- return NULL;
- }
-
- if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
- 0)) {
- cryptoapi_report_error("CryptAcquireContext");
- os_free(pk);
- CertFreeCertificateContext(cc);
- return NULL;
- }
-
- if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
- PKCS_7_ASN_ENCODING,
- &cc->pCertInfo->SubjectPublicKeyInfo,
- &pk->rsa)) {
- cryptoapi_report_error("CryptImportPublicKeyInfo");
- CryptReleaseContext(pk->prov, 0);
- os_free(pk);
- CertFreeCertificateContext(cc);
- return NULL;
- }
-
- CertFreeCertificateContext(cc);
-
- return pk;
-}
-
-
-int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
- const u8 *in, size_t inlen,
- u8 *out, size_t *outlen)
-{
- DWORD clen;
- u8 *tmp;
- size_t i;
-
- if (*outlen < inlen)
- return -1;
- tmp = malloc(*outlen);
- if (tmp == NULL)
- return -1;
-
- os_memcpy(tmp, in, inlen);
- clen = inlen;
- if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
- "public key: %d", (int) GetLastError());
- os_free(tmp);
- return -1;
- }
-
- *outlen = clen;
-
- /* Reverse the output */
- for (i = 0; i < *outlen; i++)
- out[i] = tmp[*outlen - 1 - i];
-
- os_free(tmp);
-
- return 0;
-}
-
-
-int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
- const u8 *in, size_t inlen,
- u8 *out, size_t *outlen)
-{
- /* TODO */
- return -1;
-}
-
-
-void crypto_public_key_free(struct crypto_public_key *key)
-{
- if (key) {
- CryptDestroyKey(key->rsa);
- CryptReleaseContext(key->prov, 0);
- os_free(key);
- }
-}
-
-
-void crypto_private_key_free(struct crypto_private_key *key)
-{
- if (key) {
- CryptDestroyKey(key->rsa);
- CryptReleaseContext(key->prov, 0);
- os_free(key);
- }
-}
-
-
-int crypto_global_init(void)
-{
- return mingw_load_crypto_func();
-}
-
-
-void crypto_global_deinit(void)
-{
-}
-
-
-int crypto_mod_exp(const u8 *base, size_t base_len,
- const u8 *power, size_t power_len,
- const u8 *modulus, size_t modulus_len,
- u8 *result, size_t *result_len)
-{
- /* TODO */
- return -1;
-}
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index 7137c27d0e8c..581005df3e39 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -161,7 +161,7 @@ struct omac1_test_vector {
u8 tag[16];
};
-static struct omac1_test_vector omac1_test_vectors[] =
+static const struct omac1_test_vector omac1_test_vectors[] =
{
{
{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
@@ -210,7 +210,8 @@ static struct omac1_test_vector omac1_test_vectors[] =
};
-static int test_omac1_vector(struct omac1_test_vector *tv, unsigned int i)
+static int test_omac1_vector(const struct omac1_test_vector *tv,
+ unsigned int i)
{
u8 key[] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
@@ -515,6 +516,7 @@ static int test_key_wrap(void)
0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
};
+#ifndef CONFIG_BORINGSSL
/* RFC 3394 - Test vector 4.2 */
u8 kek42[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -530,6 +532,7 @@ static int test_key_wrap(void)
0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
};
+#endif /* CONFIG_BORINGSSL */
/* RFC 3394 - Test vector 4.3 */
u8 kek43[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -546,6 +549,7 @@ static int test_key_wrap(void)
0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
};
+#ifndef CONFIG_BORINGSSL
/* RFC 3394 - Test vector 4.4 */
u8 kek44[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -563,6 +567,7 @@ static int test_key_wrap(void)
0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
};
+#endif /* CONFIG_BORINGSSL */
/* RFC 3394 - Test vector 4.5 */
u8 kek45[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -623,6 +628,7 @@ static int test_key_wrap(void)
ret++;
}
+#ifndef CONFIG_BORINGSSL
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.2");
if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
result)) {
@@ -642,6 +648,7 @@ static int test_key_wrap(void)
wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
ret++;
}
+#endif /* CONFIG_BORINGSSL */
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.3");
if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
@@ -663,6 +670,7 @@ static int test_key_wrap(void)
ret++;
}
+#ifndef CONFIG_BORINGSSL
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.4");
if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
result)) {
@@ -682,6 +690,7 @@ static int test_key_wrap(void)
wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
ret++;
}
+#endif /* CONFIG_BORINGSSL */
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.5");
if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
@@ -732,6 +741,7 @@ static int test_key_wrap(void)
static int test_md5(void)
{
+#ifndef CONFIG_FIPS
struct {
char *data;
char *hash;
@@ -810,6 +820,10 @@ static int test_md5(void)
wpa_printf(MSG_INFO, "MD5 test cases passed");
return errors;
+#else /* CONFIG_FIPS */
+ wpa_printf(MSG_INFO, "MD5 test cases skipped due to CONFIG_FIPS");
+ return 0;
+#endif /* CONFIG_FIPS */
}
@@ -841,6 +855,7 @@ static int test_eap_fast(void)
0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
};
+#ifndef CONFIG_FIPS
const u8 key_block[] = {
0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
@@ -857,6 +872,7 @@ static int test_eap_fast(void)
0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
};
+#endif /* CONFIG_FIPS */
const u8 sks[] = {
0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
@@ -931,6 +947,7 @@ static int test_eap_fast(void)
errors++;
}
+#ifndef CONFIG_FIPS
wpa_printf(MSG_INFO, "- PRF (TLS, SHA1/MD5) test case / key_block");
if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
"key expansion", seed, sizeof(seed),
@@ -939,6 +956,7 @@ static int test_eap_fast(void)
wpa_printf(MSG_INFO, "PRF test - FAILED!");
errors++;
}
+#endif /* CONFIG_FIPS */
wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / IMCK");
if (sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
@@ -983,14 +1001,14 @@ static int test_eap_fast(void)
}
-static u8 key0[] =
+static const u8 key0[] =
{
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b
};
-static u8 data0[] = "Hi There";
-static u8 prf0[] =
+static const u8 data0[] = "Hi There";
+static const u8 prf0[] =
{
0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
@@ -1002,9 +1020,9 @@ static u8 prf0[] =
0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
};
-static u8 key1[] = "Jefe";
-static u8 data1[] = "what do ya want for nothing?";
-static u8 prf1[] =
+static const u8 key1[] = "Jefe";
+static const u8 data1[] = "what do ya want for nothing?";
+static const u8 prf1[] =
{
0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
@@ -1017,13 +1035,13 @@ static u8 prf1[] =
};
-static u8 key2[] =
+static const u8 key2[] =
{
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa
};
-static u8 data2[] =
+static const u8 data2[] =
{
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
@@ -1033,7 +1051,7 @@ static u8 data2[] =
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd
};
-static u8 prf2[] =
+static const u8 prf2[] =
{
0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
@@ -1052,7 +1070,7 @@ struct passphrase_test {
char psk[32];
};
-static struct passphrase_test passphrase_tests[] =
+static const struct passphrase_test passphrase_tests[] =
{
{
"password",
@@ -1097,7 +1115,7 @@ struct rfc6070_test {
size_t dk_len;
};
-static struct rfc6070_test rfc6070_tests[] =
+static const struct rfc6070_test rfc6070_tests[] =
{
{
"password",
@@ -1214,7 +1232,7 @@ static int test_sha1(void)
wpa_printf(MSG_INFO, "PBKDF2-SHA1 Passphrase test cases:");
for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
u8 psk[32];
- struct passphrase_test *test = &passphrase_tests[i];
+ const struct passphrase_test *test = &passphrase_tests[i];
if (pbkdf2_sha1(test->passphrase,
(const u8 *) test->ssid, strlen(test->ssid),
@@ -1230,7 +1248,7 @@ static int test_sha1(void)
wpa_printf(MSG_INFO, "PBKDF2-SHA1 test cases (RFC 6070):");
for (i = 0; i < NUM_RFC6070_TESTS; i++) {
u8 dk[25];
- struct rfc6070_test *test = &rfc6070_tests[i];
+ const struct rfc6070_test *test = &rfc6070_tests[i];
if (pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
test->c, dk, test->dk_len) == 0 &&
@@ -1248,7 +1266,7 @@ static int test_sha1(void)
}
-struct {
+const struct {
char *data;
u8 hash[32];
} tests[] = {
@@ -1272,7 +1290,7 @@ struct {
}
};
-struct hmac_test {
+const struct hmac_test {
u8 key[80];
size_t key_len;
u8 data[128];
@@ -1513,7 +1531,7 @@ static int test_sha256(void)
}
for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
- struct hmac_test *t = &hmac_tests[i];
+ const struct hmac_test *t = &hmac_tests[i];
wpa_printf(MSG_INFO, "HMAC-SHA256 test case %d:", i + 1);
@@ -1563,6 +1581,7 @@ static int test_sha256(void)
static int test_ms_funcs(void)
{
+#ifndef CONFIG_FIPS
/* Test vector from RFC2759 example */
char *username = "User";
char *password = "clientPass";
@@ -1655,6 +1674,10 @@ static int test_ms_funcs(void)
wpa_printf(MSG_INFO, "ms_funcs test cases passed");
return errors;
+#else /* CONFIG_FIPS */
+ wpa_printf(MSG_INFO, "ms_funcs test cases skipped due to CONFIG_FIPS");
+ return 0;
+#endif /* CONFIG_FIPS */
}
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index f158ef43a645..6cff75c64ae5 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -93,10 +93,12 @@ static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
}
+#ifndef CONFIG_FIPS
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
}
+#endif /* CONFIG_FIPS */
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
@@ -120,6 +122,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
}
+#ifndef CONFIG_NO_RC4
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
@@ -155,12 +158,15 @@ out:
return res;
#endif /* OPENSSL_NO_RC4 */
}
+#endif /* CONFIG_NO_RC4 */
+#ifndef CONFIG_FIPS
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
}
+#endif /* CONFIG_FIPS */
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
@@ -297,6 +303,9 @@ void aes_decrypt_deinit(void *ctx)
}
+#ifndef CONFIG_FIPS
+#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
+
int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
AES_KEY actx;
@@ -323,6 +332,59 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
return res <= 0 ? -1 : 0;
}
+#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
+#endif /* CONFIG_FIPS */
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ EVP_CIPHER_CTX ctx;
+ int clen, len;
+ u8 buf[16];
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ return -1;
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ clen = data_len;
+ if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
+ clen != (int) data_len)
+ return -1;
+
+ len = sizeof(buf);
+ if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ return -1;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ EVP_CIPHER_CTX ctx;
+ int plen, len;
+ u8 buf[16];
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ return -1;
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ plen = data_len;
+ if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
+ plen != (int) data_len)
+ return -1;
+
+ len = sizeof(buf);
+ if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ return -1;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return 0;
+}
+
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
@@ -380,11 +442,13 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
return NULL;
switch (alg) {
+#ifndef CONFIG_NO_RC4
#ifndef OPENSSL_NO_RC4
case CRYPTO_CIPHER_ALG_RC4:
cipher = EVP_rc4();
break;
#endif /* OPENSSL_NO_RC4 */
+#endif /* CONFIG_NO_RC4 */
#ifndef OPENSSL_NO_AES
case CRYPTO_CIPHER_ALG_AES:
switch (key_len) {
@@ -1057,6 +1121,42 @@ int crypto_bignum_is_one(const struct crypto_bignum *a)
}
+int crypto_bignum_legendre(const struct crypto_bignum *a,
+ const struct crypto_bignum *p)
+{
+ BN_CTX *bnctx;
+ BIGNUM *exp = NULL, *tmp = NULL;
+ int res = -2;
+
+ bnctx = BN_CTX_new();
+ if (bnctx == NULL)
+ return -2;
+
+ exp = BN_new();
+ tmp = BN_new();
+ if (!exp || !tmp ||
+ /* exp = (p-1) / 2 */
+ !BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
+ !BN_rshift1(exp, exp) ||
+ !BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
+ bnctx))
+ goto fail;
+
+ if (BN_is_word(tmp, 1))
+ res = 1;
+ else if (BN_is_zero(tmp))
+ res = 0;
+ else
+ res = -1;
+
+fail:
+ BN_clear_free(tmp);
+ BN_clear_free(exp);
+ BN_CTX_free(bnctx);
+ return res;
+}
+
+
#ifdef CONFIG_ECC
struct crypto_ec {
@@ -1064,6 +1164,8 @@ struct crypto_ec {
BN_CTX *bnctx;
BIGNUM *prime;
BIGNUM *order;
+ BIGNUM *a;
+ BIGNUM *b;
};
struct crypto_ec * crypto_ec_init(int group)
@@ -1088,6 +1190,26 @@ struct crypto_ec * crypto_ec_init(int group)
case 26:
nid = NID_secp224r1;
break;
+#ifdef NID_brainpoolP224r1
+ case 27:
+ nid = NID_brainpoolP224r1;
+ break;
+#endif /* NID_brainpoolP224r1 */
+#ifdef NID_brainpoolP256r1
+ case 28:
+ nid = NID_brainpoolP256r1;
+ break;
+#endif /* NID_brainpoolP256r1 */
+#ifdef NID_brainpoolP384r1
+ case 29:
+ nid = NID_brainpoolP384r1;
+ break;
+#endif /* NID_brainpoolP384r1 */
+#ifdef NID_brainpoolP512r1
+ case 30:
+ nid = NID_brainpoolP512r1;
+ break;
+#endif /* NID_brainpoolP512r1 */
default:
return NULL;
}
@@ -1100,9 +1222,11 @@ struct crypto_ec * crypto_ec_init(int group)
e->group = EC_GROUP_new_by_curve_name(nid);
e->prime = BN_new();
e->order = BN_new();
+ e->a = BN_new();
+ e->b = BN_new();
if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
- e->order == NULL ||
- !EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) ||
+ e->order == NULL || e->a == NULL || e->b == NULL ||
+ !EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) ||
!EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
crypto_ec_deinit(e);
e = NULL;
@@ -1116,6 +1240,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
{
if (e == NULL)
return;
+ BN_clear_free(e->b);
+ BN_clear_free(e->a);
BN_clear_free(e->order);
BN_clear_free(e->prime);
EC_GROUP_free(e->group);
@@ -1263,6 +1389,33 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
}
+struct crypto_bignum *
+crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
+ const struct crypto_bignum *x)
+{
+ BIGNUM *tmp, *tmp2, *y_sqr = NULL;
+
+ tmp = BN_new();
+ tmp2 = BN_new();
+
+ /* y^2 = x^3 + ax + b */
+ if (tmp && tmp2 &&
+ BN_mod_sqr(tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
+ BN_mod_mul(tmp, tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
+ BN_mod_mul(tmp2, e->a, (const BIGNUM *) x, e->prime, e->bnctx) &&
+ BN_mod_add_quick(tmp2, tmp2, tmp, e->prime) &&
+ BN_mod_add_quick(tmp2, tmp2, e->b, e->prime)) {
+ y_sqr = tmp2;
+ tmp2 = NULL;
+ }
+
+ BN_clear_free(tmp);
+ BN_clear_free(tmp2);
+
+ return (struct crypto_bignum *) y_sqr;
+}
+
+
int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
const struct crypto_ec_point *p)
{
@@ -1273,7 +1426,17 @@ int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
const struct crypto_ec_point *p)
{
- return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p, e->bnctx);
+ return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p,
+ e->bnctx) == 1;
+}
+
+
+int crypto_ec_point_cmp(const struct crypto_ec *e,
+ const struct crypto_ec_point *a,
+ const struct crypto_ec_point *b)
+{
+ return EC_POINT_cmp(e->group, (const EC_POINT *) a,
+ (const EC_POINT *) b, e->bnctx);
}
#endif /* CONFIG_ECC */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index d3b263196e2d..3aeb2bbc60af 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1153,7 +1153,7 @@ dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
-static struct dh_group dh_groups[] = {
+static const struct dh_group dh_groups[] = {
DH_GROUP(5, 1),
#ifdef ALL_DH_GROUPS
DH_GROUP(1, 1),
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index d69eceabff1c..fb03efcd4ffc 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -13,13 +13,21 @@
#include "crypto.h"
-static void sha1_transform(u8 *state, const u8 data[64])
+static void sha1_transform(u32 *state, const u8 data[64])
{
SHA_CTX context;
os_memset(&context, 0, sizeof(context));
- os_memcpy(&context.h0, state, 5 * 4);
+ context.h0 = state[0];
+ context.h1 = state[1];
+ context.h2 = state[2];
+ context.h3 = state[3];
+ context.h4 = state[4];
SHA1_Transform(&context, data);
- os_memcpy(state, &context.h0, 5 * 4);
+ state[0] = context.h0;
+ state[1] = context.h1;
+ state[2] = context.h2;
+ state[3] = context.h3;
+ state[4] = context.h4;
}
@@ -53,7 +61,7 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
/* w_i = G(t, XVAL) */
os_memcpy(_t, t, 20);
- sha1_transform((u8 *) _t, xkey);
+ sha1_transform(_t, xkey);
_t[0] = host_to_be32(_t[0]);
_t[1] = host_to_be32(_t[1]);
_t[2] = host_to_be32(_t[2]);
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index 49a5c1c245d6..053d203cb65b 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -78,9 +78,8 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
* @challenge: 8-octet Challenge (OUT)
* Returns: 0 on success, -1 on failure
*/
-static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
- const u8 *username, size_t username_len,
- u8 *challenge)
+int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+ const u8 *username, size_t username_len, u8 *challenge)
{
u8 hash[SHA1_MAC_LEN];
const unsigned char *addr[3];
@@ -175,9 +174,8 @@ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
u8 password_hash[16];
if (challenge_hash(peer_challenge, auth_challenge, username,
- username_len, challenge))
- return -1;
- if (nt_password_hash(password, password_len, password_hash))
+ username_len, challenge) ||
+ nt_password_hash(password, password_len, password_hash))
return -1;
challenge_response(challenge, password_hash, response);
return 0;
@@ -257,12 +255,9 @@ int generate_authenticator_response_pwhash(
addr2[1] = challenge;
addr2[2] = magic2;
- if (hash_nt_password_hash(password_hash, password_hash_hash))
- return -1;
- if (sha1_vector(3, addr1, len1, response))
- return -1;
-
- if (challenge_hash(peer_challenge, auth_challenge, username,
+ if (hash_nt_password_hash(password_hash, password_hash_hash) ||
+ sha1_vector(3, addr1, len1, response) ||
+ challenge_hash(peer_challenge, auth_challenge, username,
username_len, challenge))
return -1;
return sha1_vector(3, addr2, len2, response);
@@ -417,6 +412,8 @@ int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
}
+#ifndef CONFIG_NO_RC4
+
#define PWBLOCK_LEN 516
/**
@@ -436,10 +433,8 @@ int encrypt_pw_block_with_password_hash(
os_memset(pw_block, 0, PWBLOCK_LEN);
- if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
- return -1;
-
- if (ucs2_len > 256)
+ if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
+ || ucs2_len > 256)
return -1;
offset = (256 - ucs2_len) * 2;
@@ -484,6 +479,8 @@ int new_password_encrypted_with_old_nt_password_hash(
return 0;
}
+#endif /* CONFIG_NO_RC4 */
+
/**
* nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
diff --git a/src/crypto/ms_funcs.h b/src/crypto/ms_funcs.h
index bd9bfee95b7c..b5b5918e1a55 100644
--- a/src/crypto/ms_funcs.h
+++ b/src/crypto/ms_funcs.h
@@ -33,6 +33,8 @@ int nt_challenge_response(const u8 *challenge, const u8 *password,
void challenge_response(const u8 *challenge, const u8 *password_hash,
u8 *response);
+int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+ const u8 *username, size_t username_len, u8 *challenge);
int nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash);
int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
diff --git a/src/crypto/random.c b/src/crypto/random.c
index bc758aa57232..3a86a93a46a8 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -181,6 +181,7 @@ int random_get_bytes(void *buf, size_t len)
#ifdef CONFIG_FIPS
/* Mix in additional entropy from the crypto module */
+ bytes = buf;
left = len;
while (left) {
size_t siz, i;
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index 0effd9b76dd8..f9bc0ebf6e3d 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -95,5 +95,10 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
SHA1_pos++;
}
+ os_memset(A_MD5, 0, MD5_MAC_LEN);
+ os_memset(P_MD5, 0, MD5_MAC_LEN);
+ os_memset(A_SHA1, 0, SHA1_MAC_LEN);
+ os_memset(P_SHA1, 0, SHA1_MAC_LEN);
+
return 0;
}
diff --git a/src/crypto/sha1-tprf.c b/src/crypto/sha1-tprf.c
index a52949462f77..562510f8937d 100644
--- a/src/crypto/sha1-tprf.c
+++ b/src/crypto/sha1-tprf.c
@@ -66,5 +66,7 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
len[0] = SHA1_MAC_LEN;
}
+ os_memset(hash, 0, SHA1_MAC_LEN);
+
return 0;
}
diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c
index d8a1beb32e90..e7509ce41aba 100644
--- a/src/crypto/sha256-kdf.c
+++ b/src/crypto/sha256-kdf.c
@@ -61,6 +61,7 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (iter == 255) {
os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA256_MAC_LEN);
return -1;
}
iter++;
@@ -68,9 +69,11 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
+ os_memset(T, 0, SHA256_MAC_LEN);
return -1;
}
}
+ os_memset(T, 0, SHA256_MAC_LEN);
return 0;
}
diff --git a/src/crypto/sha384-prf.c b/src/crypto/sha384-prf.c
new file mode 100644
index 000000000000..653920ba283d
--- /dev/null
+++ b/src/crypto/sha384-prf.c
@@ -0,0 +1,100 @@
+/*
+ * SHA384-based KDF (IEEE 802.11ac)
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+#include "crypto.h"
+
+
+/**
+ * sha384_prf - SHA384-based Key derivation function (IEEE 802.11ac, 11.6.1.7.2)
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+void sha384_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ sha384_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
+}
+
+
+/**
+ * sha384_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bits of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key. If the requested buf_len is not divisible by eight, the least
+ * significant 1-7 bits of the last octet in the output are not part of the
+ * requested output.
+ */
+void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits)
+{
+ u16 counter = 1;
+ size_t pos, plen;
+ u8 hash[SHA384_MAC_LEN];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 counter_le[2], length_le[2];
+ size_t buf_len = (buf_len_bits + 7) / 8;
+
+ addr[0] = counter_le;
+ len[0] = 2;
+ addr[1] = (u8 *) label;
+ len[1] = os_strlen(label);
+ addr[2] = data;
+ len[2] = data_len;
+ addr[3] = length_le;
+ len[3] = sizeof(length_le);
+
+ WPA_PUT_LE16(length_le, buf_len_bits);
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ WPA_PUT_LE16(counter_le, counter);
+ if (plen >= SHA384_MAC_LEN) {
+ hmac_sha384_vector(key, key_len, 4, addr, len,
+ &buf[pos]);
+ pos += SHA384_MAC_LEN;
+ } else {
+ hmac_sha384_vector(key, key_len, 4, addr, len, hash);
+ os_memcpy(&buf[pos], hash, plen);
+ pos += plen;
+ break;
+ }
+ counter++;
+ }
+
+ /*
+ * Mask out unused bits in the last octet if it does not use all the
+ * bits.
+ */
+ if (buf_len_bits % 8) {
+ u8 mask = 0xff << (8 - buf_len_bits % 8);
+ buf[pos - 1] &= mask;
+ }
+
+ os_memset(hash, 0, sizeof(hash));
+}
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
index e6a1fe41e1a1..3deafa59ec29 100644
--- a/src/crypto/sha384.h
+++ b/src/crypto/sha384.h
@@ -15,5 +15,10 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
+void sha384_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf,
+ size_t buf_len_bits);
#endif /* SHA384_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 9ae95a66c9ed..2e562339cc5c 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -11,9 +11,7 @@
struct tls_connection;
-struct tls_keys {
- const u8 *master_key; /* TLS master secret */
- size_t master_key_len;
+struct tls_random {
const u8 *client_random;
size_t client_random_len;
const u8 *server_random;
@@ -81,6 +79,7 @@ struct tls_config {
int fips_mode;
int cert_in_cb;
const char *openssl_ciphers;
+ unsigned int tls_session_lifetime;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@@ -95,6 +94,7 @@ struct tls_config {
#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
#define TLS_CONN_EAP_FAST BIT(7)
+#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -255,6 +255,7 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
enum {
+ TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN = -4,
TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
};
@@ -265,10 +266,12 @@ enum {
* @conn: Connection context data from tls_connection_init()
* @params: Connection parameters
* Returns: 0 on success, -1 on failure,
- * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
- * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
+ * failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
- * PKCS#11 engine private key.
+ * PKCS#11 engine private key, or
+ * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
+ * failure.
*/
int __must_check
tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
@@ -279,10 +282,12 @@ tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
* @tls_ctx: TLS context data from tls_init()
* @params: Global TLS parameters
* Returns: 0 on success, -1 on failure,
- * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
- * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
+ * failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
- * PKCS#11 engine private key.
+ * PKCS#11 engine private key, or
+ * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
+ * failure.
*/
int __must_check tls_global_set_params(
void *tls_ctx, const struct tls_connection_params *params);
@@ -301,22 +306,28 @@ int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @verify_peer: 1 = verify peer certificate
+ * @flags: Connection flags (TLS_CONN_*)
+ * @session_ctx: Session caching context or %NULL to use default
+ * @session_ctx_len: Length of @session_ctx in bytes.
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_set_verify(void *tls_ctx,
struct tls_connection *conn,
- int verify_peer);
+ int verify_peer,
+ unsigned int flags,
+ const u8 *session_ctx,
+ size_t session_ctx_len);
/**
- * tls_connection_get_keys - Get master key and random data from TLS connection
+ * tls_connection_get_random - Get random data from TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- * @keys: Structure of key/random data (filled on success)
+ * @data: Structure of client/server random data (filled on success)
* Returns: 0 on success, -1 on failure
*/
-int __must_check tls_connection_get_keys(void *tls_ctx,
+int __must_check tls_connection_get_random(void *tls_ctx,
struct tls_connection *conn,
- struct tls_keys *keys);
+ struct tls_random *data);
/**
* tls_connection_prf - Use TLS-PRF to derive keying material
@@ -325,23 +336,22 @@ int __must_check tls_connection_get_keys(void *tls_ctx,
* @label: Label (e.g., description of the key) for PRF
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
+ * @skip_keyblock: Skip TLS key block from the beginning of PRF output
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
- * This function is optional to implement if tls_connection_get_keys() provides
- * access to master secret and server/client random values. If these values are
- * not exported from the TLS library, tls_connection_prf() is required so that
- * further keying material can be derived from the master secret. If not
- * implemented, the function will still need to be defined, but it can just
- * return -1. Example implementation of this function is in tls_prf_sha1_md5()
- * when it is called with seed set to client_random|server_random (or
- * server_random|client_random).
+ * tls_connection_prf() is required so that further keying material can be
+ * derived from the master secret. Example implementation of this function is in
+ * tls_prf_sha1_md5() when it is called with seed set to
+ * client_random|server_random (or server_random|client_random). For TLSv1.2 and
+ * newer, a different PRF is needed, though.
*/
int __must_check tls_connection_prf(void *tls_ctx,
struct tls_connection *conn,
const char *label,
int server_random_first,
+ int skip_keyblock,
u8 *out, size_t out_len);
/**
@@ -461,6 +471,19 @@ int __must_check tls_connection_set_cipher_list(void *tls_ctx,
u8 *ciphers);
/**
+ * tls_get_version - Get the current TLS version number
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for returning the TLS version number
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the currently used TLS version number.
+ */
+int __must_check tls_get_version(void *tls_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen);
+
+/**
* tls_get_cipher - Get current cipher name
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
@@ -527,23 +550,6 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn);
-/**
- * tls_connection_get_keyblock_size - Get TLS key_block size
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: Size of the key_block for the negotiated cipher suite or -1 on
- * failure
- */
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn);
-
-/**
- * tls_capabilities - Get supported TLS capabilities
- * @tls_ctx: TLS context data from tls_init()
- * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
- */
-unsigned int tls_capabilities(void *tls_ctx);
-
typedef int (*tls_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
const u8 *server_random, u8 *master_secret);
@@ -569,4 +575,14 @@ void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
int tls_get_library_version(char *buf, size_t buf_len);
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data);
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn);
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn);
+
+void tls_connection_remove_session(struct tls_connection *conn);
+
#endif /* TLS_H */
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index 65db6fcc2565..f994379b16b2 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -708,7 +708,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
if (conn == NULL || conn->session == NULL)
return -1;
@@ -722,8 +723,8 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
}
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_random *keys)
{
#if GNUTLS_VERSION_NUMBER >= 0x030012
gnutls_datum_t client, server;
@@ -747,9 +748,9 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
- u8 *out, size_t out_len)
+ int skip_keyblock, u8 *out, size_t out_len)
{
- if (conn == NULL || conn->session == NULL)
+ if (conn == NULL || conn->session == NULL || skip_keyblock)
return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
@@ -1426,6 +1427,14 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
}
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ /* TODO */
+ return -1;
+}
+
+
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -1476,30 +1485,39 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+ struct tls_connection *conn,
+ tls_session_ticket_cb cb, void *ctx)
{
- /* TODO */
return -1;
}
-unsigned int tls_capabilities(void *tls_ctx)
+int tls_get_library_version(char *buf, size_t buf_len)
{
- return 0;
+ return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
+ GNUTLS_VERSION, gnutls_check_version(NULL));
}
-int tls_connection_set_session_ticket_cb(void *tls_ctx,
- struct tls_connection *conn,
- tls_session_ticket_cb cb, void *ctx)
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
{
- return -1;
}
-int tls_get_library_version(char *buf, size_t buf_len)
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
{
- return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
- GNUTLS_VERSION, gnutls_check_version(NULL));
}
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 0c955da29f1d..704751d308fc 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -192,26 +192,31 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (params->subject_match) {
wpa_printf(MSG_INFO, "TLS: subject_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->altsubject_match) {
wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->suffix_match) {
wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->domain_match) {
wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ tlsv1_cred_free(cred);
return -1;
}
if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
+ wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported");
+ tlsv1_cred_free(cred);
return -1;
}
@@ -323,7 +328,8 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
@@ -333,16 +339,30 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
}
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
+ struct tls_random *data)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+ if (conn->client)
+ return tlsv1_client_get_random(conn->client, data);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+ if (conn->server)
+ return tlsv1_server_get_random(conn->server, data);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+ return -1;
+}
+
+
+static int tls_get_keyblock_size(struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
- return tlsv1_client_get_keys(conn->client, keys);
+ return tlsv1_client_get_keyblock_size(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
- return tlsv1_server_get_keys(conn->server, keys);
+ return tlsv1_server_get_keyblock_size(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
@@ -350,23 +370,41 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
- u8 *out, size_t out_len)
-{
+ int skip_keyblock, u8 *out, size_t out_len)
+{
+ int ret = -1, skip = 0;
+ u8 *tmp_out = NULL;
+ u8 *_out = out;
+
+ if (skip_keyblock) {
+ skip = tls_get_keyblock_size(conn);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
+ }
+
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
- return tlsv1_client_prf(conn->client, label,
- server_random_first,
- out, out_len);
+ ret = tlsv1_client_prf(conn->client, label,
+ server_random_first,
+ _out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
- return tlsv1_server_prf(conn->server, label,
- server_random_first,
- out, out_len);
+ ret = tlsv1_server_prf(conn->server, label,
+ server_random_first,
+ _out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
- return -1;
+ if (ret == 0 && skip_keyblock)
+ os_memcpy(out, _out + skip, out_len);
+ bin_clear_free(tmp_out, skip);
+
+ return ret;
}
@@ -580,6 +618,14 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
}
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ /* TODO */
+ return -1;
+}
+
+
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -637,27 +683,6 @@ int tls_connection_get_write_alerts(void *tls_ctx,
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
-{
-#ifdef CONFIG_TLS_INTERNAL_CLIENT
- if (conn->client)
- return tlsv1_client_get_keyblock_size(conn->client);
-#endif /* CONFIG_TLS_INTERNAL_CLIENT */
-#ifdef CONFIG_TLS_INTERNAL_SERVER
- if (conn->server)
- return tlsv1_server_get_keyblock_size(conn->server);
-#endif /* CONFIG_TLS_INTERNAL_SERVER */
- return -1;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
@@ -683,3 +708,26 @@ int tls_get_library_version(char *buf, size_t buf_len)
{
return os_snprintf(buf, buf_len, "internal");
}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+}
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index a6d210afcf0f..ae392ad8aa0f 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -72,14 +72,15 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
return -1;
}
-int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
+ struct tls_random *data)
{
return -1;
}
@@ -87,7 +88,7 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
- u8 *out, size_t out_len)
+ int skip_keyblock, u8 *out, size_t out_len)
{
return -1;
}
@@ -140,6 +141,13 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
}
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ return -1;
+}
+
+
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -181,20 +189,30 @@ int tls_connection_get_write_alerts(void *tls_ctx,
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
+int tls_get_library_version(char *buf, size_t buf_len)
{
- return -1;
+ return os_snprintf(buf, buf_len, "none");
}
-unsigned int tls_capabilities(void *tls_ctx)
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
{
- return 0;
}
-int tls_get_library_version(char *buf, size_t buf_len)
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ return NULL;
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
{
- return os_snprintf(buf, buf_len, "none");
}
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 52db8fc076ac..8b7b47bc256d 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1,6 +1,6 @@
/*
* SSL/TLS interface functions for OpenSSL
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,15 +23,19 @@
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif /* OPENSSL_NO_ENGINE */
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
#include "common.h"
#include "crypto.h"
+#include "sha1.h"
+#include "sha256.h"
#include "tls.h"
-#if defined(SSL_CTX_get_app_data) && defined(SSL_CTX_set_app_data)
-#define OPENSSL_SUPPORTS_CTX_APP_DATA
-#endif
-
#if OPENSSL_VERSION_NUMBER < 0x10000000L
/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
* deprecated. However, OpenSSL 0.9.8 doesn't include
@@ -70,6 +74,7 @@ static BIO * BIO_from_keystore(const char *key)
#endif /* ANDROID */
static int tls_openssl_ref_count = 0;
+static int tls_ex_idx_session = -1;
struct tls_context {
void (*event_cb)(void *ctx, enum tls_event ev,
@@ -82,6 +87,11 @@ struct tls_context {
static struct tls_context *tls_global = NULL;
+struct tls_data {
+ SSL_CTX *ssl;
+ unsigned int tls_session_lifetime;
+};
+
struct tls_connection {
struct tls_context *context;
SSL_CTX *ssl_ctx;
@@ -105,6 +115,7 @@ struct tls_connection {
unsigned int cert_probe:1;
unsigned int server_cert_only:1;
unsigned int invalid_hb_used:1;
+ unsigned int success_data:1;
u8 srv_cert_hash[32];
@@ -113,6 +124,11 @@ struct tls_connection {
X509 *peer_cert;
X509 *peer_issuer;
X509 *peer_issuer_issuer;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ unsigned char server_random[SSL3_RANDOM_SIZE];
+#endif
};
@@ -735,8 +751,27 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
#endif /* OPENSSL_NO_ENGINE */
+static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+ struct wpabuf *buf;
+
+ if (tls_ex_idx_session < 0)
+ return;
+ buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (!buf)
+ return;
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Free application session data %p (sess %p)",
+ buf, sess);
+ wpabuf_free(buf);
+
+ SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
+}
+
+
void * tls_init(const struct tls_config *conf)
{
+ struct tls_data *data;
SSL_CTX *ssl;
struct tls_context *context;
const char *ciphers;
@@ -748,7 +783,9 @@ void * tls_init(const struct tls_config *conf)
#ifdef CONFIG_FIPS
#ifdef OPENSSL_FIPS
if (conf && conf->fips_mode) {
- if (!FIPS_mode_set(1)) {
+ static int fips_enabled = 0;
+
+ if (!fips_enabled && !FIPS_mode_set(1)) {
wpa_printf(MSG_ERROR, "Failed to enable FIPS "
"mode");
ERR_load_crypto_strings();
@@ -756,8 +793,10 @@ void * tls_init(const struct tls_config *conf)
os_free(tls_global);
tls_global = NULL;
return NULL;
- } else
+ } else {
wpa_printf(MSG_INFO, "Running in FIPS mode");
+ fips_enabled = 1;
+ }
}
#else /* OPENSSL_FIPS */
if (conf && conf->fips_mode) {
@@ -791,38 +830,58 @@ void * tls_init(const struct tls_config *conf)
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
} else {
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
- /* Newer OpenSSL can store app-data per-SSL */
context = tls_context_new(conf);
if (context == NULL)
return NULL;
-#else /* OPENSSL_SUPPORTS_CTX_APP_DATA */
- context = tls_global;
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
}
tls_openssl_ref_count++;
- ssl = SSL_CTX_new(SSLv23_method());
+ data = os_zalloc(sizeof(*data));
+ if (data)
+ ssl = SSL_CTX_new(SSLv23_method());
+ else
+ ssl = NULL;
if (ssl == NULL) {
tls_openssl_ref_count--;
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
if (context != tls_global)
os_free(context);
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
if (tls_openssl_ref_count == 0) {
os_free(tls_global);
tls_global = NULL;
}
return NULL;
}
+ data->ssl = ssl;
+ if (conf)
+ data->tls_session_lifetime = conf->tls_session_lifetime;
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
SSL_CTX_set_app_data(ssl, context);
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
+ if (data->tls_session_lifetime > 0) {
+ SSL_CTX_set_quiet_shutdown(ssl, 1);
+ /*
+ * Set default context here. In practice, this will be replaced
+ * by the per-EAP method context in tls_connection_set_verify().
+ */
+ SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
+ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
+ SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
+ SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
+ } else {
+ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
+ }
+
+ if (tls_ex_idx_session < 0) {
+ tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
+ 0, NULL, NULL, NULL, NULL);
+ if (tls_ex_idx_session < 0) {
+ tls_deinit(data);
+ return NULL;
+ }
+ }
#ifndef OPENSSL_NO_ENGINE
wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
@@ -835,7 +894,7 @@ void * tls_init(const struct tls_config *conf)
if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
conf->pkcs11_module_path)) {
- tls_deinit(ssl);
+ tls_deinit(data);
return NULL;
}
}
@@ -849,22 +908,23 @@ void * tls_init(const struct tls_config *conf)
wpa_printf(MSG_ERROR,
"OpenSSL: Failed to set cipher string '%s'",
ciphers);
- tls_deinit(ssl);
+ tls_deinit(data);
return NULL;
}
- return ssl;
+ return data;
}
void tls_deinit(void *ssl_ctx)
{
- SSL_CTX *ssl = ssl_ctx;
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ struct tls_data *data = ssl_ctx;
+ SSL_CTX *ssl = data->ssl;
struct tls_context *context = SSL_CTX_get_app_data(ssl);
if (context != tls_global)
os_free(context);
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
+ if (data->tls_session_lifetime > 0)
+ SSL_CTX_flush_sessions(ssl, 0);
SSL_CTX_free(ssl);
tls_openssl_ref_count--;
@@ -881,8 +941,31 @@ void tls_deinit(void *ssl_ctx)
os_free(tls_global);
tls_global = NULL;
}
+
+ os_free(data);
+}
+
+
+#ifndef OPENSSL_NO_ENGINE
+
+/* Cryptoki return values */
+#define CKR_PIN_INCORRECT 0x000000a0
+#define CKR_PIN_INVALID 0x000000a1
+#define CKR_PIN_LEN_RANGE 0x000000a2
+
+/* libp11 */
+#define ERR_LIB_PKCS11 ERR_LIB_USER
+
+static int tls_is_pin_error(unsigned int err)
+{
+ return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
+ (ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
+ ERR_GET_REASON(err) == CKR_PIN_INVALID ||
+ ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
}
+#endif /* OPENSSL_NO_ENGINE */
+
static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
const char *pin, const char *key_id,
@@ -935,11 +1018,16 @@ static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
key_id, NULL,
&key_cb);
if (!conn->private_key) {
+ unsigned long err = ERR_get_error();
+
wpa_printf(MSG_ERROR,
"ENGINE: cannot load private key with id '%s' [%s]",
key_id,
- ERR_error_string(ERR_get_error(), NULL));
- ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ ERR_error_string(err, NULL));
+ if (tls_is_pin_error(err))
+ ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
+ else
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
goto err;
}
}
@@ -1030,19 +1118,16 @@ static void tls_msg_cb(int write_p, int version, int content_type,
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
- SSL_CTX *ssl = ssl_ctx;
+ struct tls_data *data = ssl_ctx;
+ SSL_CTX *ssl = data->ssl;
struct tls_connection *conn;
long options;
-#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
struct tls_context *context = SSL_CTX_get_app_data(ssl);
-#else /* OPENSSL_SUPPORTS_CTX_APP_DATA */
- struct tls_context *context = tls_global;
-#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
- conn->ssl_ctx = ssl_ctx;
+ conn->ssl_ctx = ssl;
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
tls_show_errors(MSG_INFO, __func__,
@@ -1091,6 +1176,14 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
+ if (conn->success_data) {
+ /*
+ * Make sure ssl_clear_bad_session() does not remove this
+ * session.
+ */
+ SSL_set_quiet_shutdown(conn->ssl, 1);
+ SSL_shutdown(conn->ssl);
+ }
SSL_free(conn->ssl);
tls_engine_deinit(conn);
os_free(conn->subject_match);
@@ -1118,7 +1211,7 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
* and "close notify" shutdown alert would confuse AS. */
SSL_set_quiet_shutdown(conn->ssl, 1);
SSL_shutdown(conn->ssl);
- return 0;
+ return SSL_clear(conn->ssl) == 1 ? 0 : -1;
}
@@ -1617,9 +1710,9 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
#ifndef OPENSSL_NO_STDIO
-static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
+static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_LOOKUP *lookup;
int ret = 0;
@@ -1649,11 +1742,12 @@ static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
#endif /* OPENSSL_NO_STDIO */
-static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+static int tls_connection_ca_cert(struct tls_data *data,
+ struct tls_connection *conn,
const char *ca_cert, const u8 *ca_cert_blob,
size_t ca_cert_blob_len, const char *ca_path)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
/*
@@ -1788,7 +1882,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
tls_show_errors(MSG_WARNING, __func__,
"Failed to load root certificates");
if (ca_cert &&
- tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+ tls_load_ca_der(data, ca_cert) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
"DER format CA certificate",
__func__);
@@ -1797,7 +1891,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
} else {
wpa_printf(MSG_DEBUG, "TLS: Trusted root "
"certificate(s) loaded");
- tls_get_errors(ssl_ctx);
+ tls_get_errors(data);
}
#else /* OPENSSL_NO_STDIO */
wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
@@ -1814,8 +1908,10 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
}
-static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
+static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
{
+ SSL_CTX *ssl_ctx = data->ssl;
+
if (ca_cert) {
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
{
@@ -1843,7 +1939,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
int flags;
if (check_crl) {
- X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+ struct tls_data *data = ssl_ctx;
+ X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
if (cs == NULL) {
tls_show_errors(MSG_INFO, __func__, "Failed to get "
"certificate store when enabling "
@@ -1901,10 +1998,44 @@ static int tls_connection_set_subject_match(struct tls_connection *conn,
}
+static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
+{
+#ifdef SSL_OP_NO_TICKET
+ if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
+ SSL_set_options(ssl, SSL_OP_NO_TICKET);
+#ifdef SSL_clear_options
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_clear_options */
+#endif /* SSL_OP_NO_TICKET */
+
+#ifdef SSL_OP_NO_TLSv1
+ if (flags & TLS_CONN_DISABLE_TLSv1_0)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
+#endif /* SSL_OP_NO_TLSv1 */
+#ifdef SSL_OP_NO_TLSv1_1
+ if (flags & TLS_CONN_DISABLE_TLSv1_1)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
+#endif /* SSL_OP_NO_TLSv1_1 */
+#ifdef SSL_OP_NO_TLSv1_2
+ if (flags & TLS_CONN_DISABLE_TLSv1_2)
+ SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
+ else
+ SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
+#endif /* SSL_OP_NO_TLSv1_2 */
+}
+
+
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
+ int verify_peer, unsigned int flags,
+ const u8 *session_ctx, size_t session_ctx_len)
{
static int counter = 0;
+ struct tls_data *data = ssl_ctx;
if (conn == NULL)
return -1;
@@ -1919,20 +2050,25 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
}
+ tls_set_conn_flags(conn->ssl, flags);
+ conn->flags = flags;
+
SSL_set_accept_state(conn->ssl);
- /*
- * Set session id context in order to avoid fatal errors when client
- * tries to resume a session. However, set the context to a unique
- * value in order to effectively disable session resumption for now
- * since not all areas of the server code are ready for it (e.g.,
- * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
- * handshake).
- */
- counter++;
- SSL_set_session_id_context(conn->ssl,
- (const unsigned char *) &counter,
- sizeof(counter));
+ if (data->tls_session_lifetime == 0) {
+ /*
+ * Set session id context to a unique value to make sure
+ * session resumption cannot be used either through session
+ * caching or TLS ticket extension.
+ */
+ counter++;
+ SSL_set_session_id_context(conn->ssl,
+ (const unsigned char *) &counter,
+ sizeof(counter));
+ } else if (session_ctx) {
+ SSL_set_session_id_context(conn->ssl, session_ctx,
+ session_ctx_len);
+ }
return 0;
}
@@ -2004,9 +2140,12 @@ static int tls_connection_client_cert(struct tls_connection *conn,
}
-static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
+static int tls_global_client_cert(struct tls_data *data,
+ const char *client_cert)
{
#ifndef OPENSSL_NO_STDIO
+ SSL_CTX *ssl_ctx = data->ssl;
+
if (client_cert == NULL)
return 0;
@@ -2040,7 +2179,7 @@ static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
#ifdef PKCS12_FUNCS
-static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
const char *passwd)
{
EVP_PKEY *pkey;
@@ -2052,6 +2191,8 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
pkey = NULL;
cert = NULL;
certs = NULL;
+ if (!passwd)
+ passwd = "";
if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
tls_show_errors(MSG_DEBUG, __func__,
"Failed to parse PKCS12 file");
@@ -2069,7 +2210,7 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
if (SSL_use_certificate(ssl, cert) != 1)
res = -1;
} else {
- if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
+ if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
res = -1;
}
X509_free(cert);
@@ -2081,13 +2222,52 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
if (SSL_use_PrivateKey(ssl, pkey) != 1)
res = -1;
} else {
- if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
+ if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
res = -1;
}
EVP_PKEY_free(pkey);
}
if (certs) {
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ SSL_clear_chain_certs(ssl);
+ while ((cert = sk_X509_pop(certs)) != NULL) {
+ X509_NAME_oneline(X509_get_subject_name(cert), buf,
+ sizeof(buf));
+ wpa_printf(MSG_DEBUG, "TLS: additional certificate"
+ " from PKCS12: subject='%s'", buf);
+ if (SSL_add1_chain_cert(ssl, cert) != 1) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "Failed to add additional certificate");
+ res = -1;
+ break;
+ }
+ }
+ if (!res) {
+ /* Try to continue anyway */
+ }
+ sk_X509_free(certs);
+#ifndef OPENSSL_IS_BORINGSSL
+ res = SSL_build_cert_chain(ssl,
+ SSL_BUILD_CHAIN_FLAG_CHECK |
+ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
+ if (!res) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "Failed to build certificate chain");
+ } else if (res == 2) {
+ wpa_printf(MSG_DEBUG,
+ "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
+ }
+#endif /* OPENSSL_IS_BORINGSSL */
+ /*
+ * Try to continue regardless of result since it is possible for
+ * the extra certificates not to be required.
+ */
+ res = 0;
+#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL_CTX_clear_extra_chain_certs(data->ssl);
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
while ((cert = sk_X509_pop(certs)) != NULL) {
X509_NAME_oneline(X509_get_subject_name(cert), buf,
sizeof(buf));
@@ -2097,26 +2277,28 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
* There is no SSL equivalent for the chain cert - so
* always add it to the context...
*/
- if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+ if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
+ {
res = -1;
break;
}
}
sk_X509_free(certs);
+#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
}
PKCS12_free(p12);
if (res < 0)
- tls_get_errors(ssl_ctx);
+ tls_get_errors(data);
return res;
}
#endif /* PKCS12_FUNCS */
-static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
- const char *passwd)
+static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
+ const char *private_key, const char *passwd)
{
#ifdef PKCS12_FUNCS
FILE *f;
@@ -2135,7 +2317,7 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
return -1;
}
- return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+ return tls_parse_pkcs12(data, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
@@ -2145,7 +2327,7 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
}
-static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
const u8 *blob, size_t len, const char *passwd)
{
#ifdef PKCS12_FUNCS
@@ -2158,7 +2340,7 @@ static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
return -1;
}
- return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+ return tls_parse_pkcs12(data, ssl, p12, passwd);
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
@@ -2183,9 +2365,13 @@ static int tls_engine_get_cert(struct tls_connection *conn,
if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
0, &params, NULL, 1)) {
+ unsigned long err = ERR_get_error();
+
wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
" '%s' [%s]", cert_id,
- ERR_error_string(ERR_get_error(), NULL));
+ ERR_error_string(err, NULL));
+ if (tls_is_pin_error(err))
+ return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
}
if (!params.cert) {
@@ -2225,13 +2411,13 @@ static int tls_connection_engine_client_cert(struct tls_connection *conn,
}
-static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+static int tls_connection_engine_ca_cert(struct tls_data *data,
struct tls_connection *conn,
const char *ca_cert_id)
{
#ifndef OPENSSL_NO_ENGINE
X509 *cert;
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
X509_STORE *store;
if (tls_engine_get_cert(conn, ca_cert_id, &cert))
@@ -2297,14 +2483,14 @@ static int tls_connection_engine_private_key(struct tls_connection *conn)
}
-static int tls_connection_private_key(void *_ssl_ctx,
+static int tls_connection_private_key(struct tls_data *data,
struct tls_connection *conn,
const char *private_key,
const char *private_key_passwd,
const u8 *private_key_blob,
size_t private_key_blob_len)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
char *passwd;
int ok;
@@ -2350,7 +2536,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
break;
}
- if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+ if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
private_key_blob_len, passwd) == 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
"OK");
@@ -2383,7 +2569,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
__func__);
#endif /* OPENSSL_NO_STDIO */
- if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+ if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
== 0) {
wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
"--> OK");
@@ -2422,9 +2608,11 @@ static int tls_connection_private_key(void *_ssl_ctx,
}
-static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+static int tls_global_private_key(struct tls_data *data,
+ const char *private_key,
const char *private_key_passwd)
{
+ SSL_CTX *ssl_ctx = data->ssl;
char *passwd;
if (private_key == NULL)
@@ -2446,7 +2634,7 @@ static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_PEM) != 1 &&
#endif /* OPENSSL_NO_STDIO */
- tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
+ tls_read_pkcs12(data, NULL, private_key, passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
os_free(passwd);
@@ -2541,7 +2729,7 @@ static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
}
-static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+static int tls_global_dh(struct tls_data *data, const char *dh_file)
{
#ifdef OPENSSL_NO_DH
if (dh_file == NULL)
@@ -2550,6 +2738,7 @@ static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
"dh_file specified");
return -1;
#else /* OPENSSL_NO_DH */
+ SSL_CTX *ssl_ctx = data->ssl;
DH *dh;
BIO *bio;
@@ -2615,45 +2804,275 @@ static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
}
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_random *keys)
{
-#ifdef CONFIG_FIPS
- wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
- "mode");
- return -1;
-#else /* CONFIG_FIPS */
SSL *ssl;
if (conn == NULL || keys == NULL)
return -1;
ssl = conn->ssl;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
return -1;
os_memset(keys, 0, sizeof(*keys));
- keys->master_key = ssl->session->master_key;
- keys->master_key_len = ssl->session->master_key_length;
keys->client_random = ssl->s3->client_random;
keys->client_random_len = SSL3_RANDOM_SIZE;
keys->server_random = ssl->s3->server_random;
keys->server_random_len = SSL3_RANDOM_SIZE;
+#else
+ if (ssl == NULL)
+ return -1;
+
+ os_memset(keys, 0, sizeof(*keys));
+ keys->client_random = conn->client_random;
+ keys->client_random_len = SSL_get_client_random(
+ ssl, conn->client_random, sizeof(conn->client_random));
+ keys->server_random = conn->server_random;
+ keys->server_random_len = SSL_get_server_random(
+ ssl, conn->server_random, sizeof(conn->server_random));
+#endif
return 0;
+}
+
+
+#ifndef CONFIG_FIPS
+static int openssl_get_keyblock_size(SSL *ssl)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ const EVP_CIPHER *c;
+ const EVP_MD *h;
+ int md_size;
+
+ if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
+ ssl->read_hash == NULL)
+ return -1;
+
+ c = ssl->enc_read_ctx->cipher;
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+ h = EVP_MD_CTX_md(ssl->read_hash);
+#else
+ h = ssl->read_hash;
+#endif
+ if (h)
+ md_size = EVP_MD_size(h);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ else if (ssl->s3)
+ md_size = ssl->s3->tmp.new_mac_secret_size;
+#endif
+ else
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
+ "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+ EVP_CIPHER_iv_length(c));
+ return 2 * (EVP_CIPHER_key_length(c) +
+ md_size +
+ EVP_CIPHER_iv_length(c));
+#else
+ const SSL_CIPHER *ssl_cipher;
+ int cipher, digest;
+ const EVP_CIPHER *c;
+ const EVP_MD *h;
+
+ ssl_cipher = SSL_get_current_cipher(ssl);
+ if (!ssl_cipher)
+ return -1;
+ cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
+ digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
+ wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
+ cipher, digest);
+ if (cipher < 0 || digest < 0)
+ return -1;
+ c = EVP_get_cipherbynid(cipher);
+ h = EVP_get_digestbynid(digest);
+ if (!c || !h)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
+ EVP_CIPHER_key_length(c), EVP_MD_size(h),
+ EVP_CIPHER_iv_length(c));
+ return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
+ EVP_CIPHER_iv_length(c));
+#endif
+}
+#endif /* CONFIG_FIPS */
+
+
+static int openssl_tls_prf(struct tls_connection *conn,
+ const char *label, int server_random_first,
+ int skip_keyblock, u8 *out, size_t out_len)
+{
+#ifdef CONFIG_FIPS
+ wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
+ "mode");
+ return -1;
+#else /* CONFIG_FIPS */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL *ssl;
+ u8 *rnd;
+ int ret = -1;
+ int skip = 0;
+ u8 *tmp_out = NULL;
+ u8 *_out = out;
+ const char *ver;
+
+ /*
+ * TLS library did not support key generation, so get the needed TLS
+ * session parameters and use an internal implementation of TLS PRF to
+ * derive the key.
+ */
+
+ if (conn == NULL)
+ return -1;
+ ssl = conn->ssl;
+ if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
+ ssl->session->master_key_length <= 0)
+ return -1;
+ ver = SSL_get_version(ssl);
+
+ if (skip_keyblock) {
+ skip = openssl_get_keyblock_size(ssl);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
+ }
+
+ rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
+ if (!rnd) {
+ os_free(tmp_out);
+ return -1;
+ }
+
+ if (server_random_first) {
+ os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
+ SSL3_RANDOM_SIZE);
+ } else {
+ os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
+ SSL3_RANDOM_SIZE);
+ }
+
+ if (os_strcmp(ver, "TLSv1.2") == 0) {
+ tls_prf_sha256(ssl->session->master_key,
+ ssl->session->master_key_length,
+ label, rnd, 2 * SSL3_RANDOM_SIZE,
+ _out, skip + out_len);
+ ret = 0;
+ } else if (tls_prf_sha1_md5(ssl->session->master_key,
+ ssl->session->master_key_length,
+ label, rnd, 2 * SSL3_RANDOM_SIZE,
+ _out, skip + out_len) == 0) {
+ ret = 0;
+ }
+ os_free(rnd);
+ if (ret == 0 && skip_keyblock)
+ os_memcpy(out, _out + skip, out_len);
+ bin_clear_free(tmp_out, skip);
+
+ return ret;
+#else
+ SSL *ssl;
+ SSL_SESSION *sess;
+ u8 *rnd;
+ int ret = -1;
+ int skip = 0;
+ u8 *tmp_out = NULL;
+ u8 *_out = out;
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ unsigned char server_random[SSL3_RANDOM_SIZE];
+ unsigned char master_key[64];
+ size_t master_key_len;
+ const char *ver;
+
+ /*
+ * TLS library did not support key generation, so get the needed TLS
+ * session parameters and use an internal implementation of TLS PRF to
+ * derive the key.
+ */
+
+ if (conn == NULL)
+ return -1;
+ ssl = conn->ssl;
+ if (ssl == NULL)
+ return -1;
+ ver = SSL_get_version(ssl);
+ sess = SSL_get_session(ssl);
+ if (!ver || !sess)
+ return -1;
+
+ if (skip_keyblock) {
+ skip = openssl_get_keyblock_size(ssl);
+ if (skip < 0)
+ return -1;
+ tmp_out = os_malloc(skip + out_len);
+ if (!tmp_out)
+ return -1;
+ _out = tmp_out;
+ }
+
+ rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
+ if (!rnd) {
+ os_free(tmp_out);
+ return -1;
+ }
+
+ SSL_get_client_random(ssl, client_random, sizeof(client_random));
+ SSL_get_server_random(ssl, server_random, sizeof(server_random));
+ master_key_len = SSL_SESSION_get_master_key(sess, master_key,
+ sizeof(master_key));
+
+ if (server_random_first) {
+ os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
+ SSL3_RANDOM_SIZE);
+ } else {
+ os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
+ os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
+ SSL3_RANDOM_SIZE);
+ }
+
+ if (os_strcmp(ver, "TLSv1.2") == 0) {
+ tls_prf_sha256(master_key, master_key_len,
+ label, rnd, 2 * SSL3_RANDOM_SIZE,
+ _out, skip + out_len);
+ ret = 0;
+ } else if (tls_prf_sha1_md5(master_key, master_key_len,
+ label, rnd, 2 * SSL3_RANDOM_SIZE,
+ _out, skip + out_len) == 0) {
+ ret = 0;
+ }
+ os_memset(master_key, 0, sizeof(master_key));
+ os_free(rnd);
+ if (ret == 0 && skip_keyblock)
+ os_memcpy(out, _out + skip, out_len);
+ bin_clear_free(tmp_out, skip);
+
+ return ret;
+#endif
#endif /* CONFIG_FIPS */
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
- u8 *out, size_t out_len)
+ int skip_keyblock, u8 *out, size_t out_len)
{
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
SSL *ssl;
if (conn == NULL)
return -1;
- if (server_random_first)
- return -1;
+ if (server_random_first || skip_keyblock)
+ return openssl_tls_prf(conn, label,
+ server_random_first, skip_keyblock,
+ out, out_len);
ssl = conn->ssl;
if (SSL_export_keying_material(ssl, out, out_len, label,
os_strlen(label), NULL, 0, 0) == 1) {
@@ -2661,7 +3080,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
return 0;
}
#endif
- return -1;
+ return openssl_tls_prf(conn, label, server_random_first,
+ skip_keyblock, out, out_len);
}
@@ -2676,7 +3096,7 @@ openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
* Give TLS handshake data from the server (if available) to OpenSSL
* for processing.
*/
- if (in_data &&
+ if (in_data && wpabuf_len(in_data) > 0 &&
BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
< 0) {
tls_show_errors(MSG_INFO, __func__,
@@ -2788,8 +3208,14 @@ openssl_connection_handshake(struct tls_connection *conn,
return NULL;
}
- if (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
- *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
+ if (SSL_is_init_finished(conn->ssl)) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Handshake finished - resumed=%d",
+ tls_connection_resumed(conn->ssl_ctx, conn));
+ if (appl_data && in_data)
+ *appl_data = openssl_get_appl_data(conn,
+ wpabuf_len(in_data));
+ }
if (conn->invalid_hb_used) {
wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
@@ -2968,6 +3394,21 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+ if (os_strstr(buf, ":ADH-")) {
+ /*
+ * Need to drop to security level 0 to allow anonymous
+ * cipher suites for EAP-FAST.
+ */
+ SSL_set_security_level(conn->ssl, 0);
+ } else if (SSL_get_security_level(conn->ssl) == 0) {
+ /* Force at least security level 1 */
+ SSL_set_security_level(conn->ssl, 1);
+ }
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+#endif
+
if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
tls_show_errors(MSG_INFO, __func__,
"Cipher suite configuration failed");
@@ -2978,6 +3419,22 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
}
+int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ const char *name;
+ if (conn == NULL || conn->ssl == NULL)
+ return -1;
+
+ name = SSL_get_version(conn->ssl);
+ if (name == NULL)
+ return -1;
+
+ os_strlcpy(buf, name, buflen);
+ return 0;
+}
+
+
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@@ -3300,6 +3757,7 @@ static int ocsp_status_cb(SSL *s, void *arg)
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
+ struct tls_data *data = tls_ctx;
int ret;
unsigned long err;
int can_pkcs11 = 0;
@@ -3341,6 +3799,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (can_pkcs11 == 2 && !engine_id)
engine_id = "pkcs11";
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (params->flags & TLS_CONN_EAP_FAST) {
wpa_printf(MSG_DEBUG,
"OpenSSL: Use TLSv1_method() for EAP-FAST");
@@ -3350,6 +3810,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
}
+#endif
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
while ((err = ERR_get_error())) {
wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
@@ -3371,10 +3833,9 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
if (engine_id && ca_cert_id) {
- if (tls_connection_engine_ca_cert(tls_ctx, conn,
- ca_cert_id))
+ if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
- } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
params->ca_cert_blob,
params->ca_cert_blob_len,
params->ca_path))
@@ -3392,7 +3853,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
- } else if (tls_connection_private_key(tls_ctx, conn,
+ } else if (tls_connection_private_key(data, conn,
params->private_key,
params->private_key_passwd,
params->private_key_blob,
@@ -3416,40 +3877,30 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
-#ifdef SSL_OP_NO_TICKET
- if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
- SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
-#ifdef SSL_clear_options
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
-#endif /* SSL_clear_options */
-#endif /* SSL_OP_NO_TICKET */
-
-#ifdef SSL_OP_NO_TLSv1_1
- if (params->flags & TLS_CONN_DISABLE_TLSv1_1)
- SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_1);
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_1);
-#endif /* SSL_OP_NO_TLSv1_1 */
-#ifdef SSL_OP_NO_TLSv1_2
- if (params->flags & TLS_CONN_DISABLE_TLSv1_2)
- SSL_set_options(conn->ssl, SSL_OP_NO_TLSv1_2);
- else
- SSL_clear_options(conn->ssl, SSL_OP_NO_TLSv1_2);
-#endif /* SSL_OP_NO_TLSv1_2 */
+ tls_set_conn_flags(conn->ssl, params->flags);
#ifdef HAVE_OCSP
if (params->flags & TLS_CONN_REQUEST_OCSP) {
- SSL_CTX *ssl_ctx = tls_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
}
+#else /* HAVE_OCSP */
+ if (params->flags & TLS_CONN_REQUIRE_OCSP) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: No OCSP support included - reject configuration");
+ return -1;
+ }
+ if (params->flags & TLS_CONN_REQUEST_OCSP) {
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
+ }
#endif /* HAVE_OCSP */
conn->flags = params->flags;
- tls_get_errors(tls_ctx);
+ tls_get_errors(data);
return 0;
}
@@ -3458,7 +3909,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
- SSL_CTX *ssl_ctx = tls_ctx;
+ struct tls_data *data = tls_ctx;
+ SSL_CTX *ssl_ctx = data->ssl;
unsigned long err;
while ((err = ERR_get_error())) {
@@ -3466,19 +3918,12 @@ int tls_global_set_params(void *tls_ctx,
__func__, ERR_error_string(err, NULL));
}
- if (tls_global_ca_cert(ssl_ctx, params->ca_cert))
- return -1;
-
- if (tls_global_client_cert(ssl_ctx, params->client_cert))
- return -1;
-
- if (tls_global_private_key(ssl_ctx, params->private_key,
- params->private_key_passwd))
- return -1;
-
- if (tls_global_dh(ssl_ctx, params->dh_file)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
- params->dh_file);
+ if (tls_global_ca_cert(data, params->ca_cert) ||
+ tls_global_client_cert(data, params->client_cert) ||
+ tls_global_private_key(data, params->private_key,
+ params->private_key_passwd) ||
+ tls_global_dh(data, params->dh_file)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
return -1;
}
@@ -3514,49 +3959,6 @@ int tls_global_set_params(void *tls_ctx,
}
-int tls_connection_get_keyblock_size(void *tls_ctx,
- struct tls_connection *conn)
-{
- const EVP_CIPHER *c;
- const EVP_MD *h;
- int md_size;
-
- if (conn == NULL || conn->ssl == NULL ||
- conn->ssl->enc_read_ctx == NULL ||
- conn->ssl->enc_read_ctx->cipher == NULL ||
- conn->ssl->read_hash == NULL)
- return -1;
-
- c = conn->ssl->enc_read_ctx->cipher;
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
- h = EVP_MD_CTX_md(conn->ssl->read_hash);
-#else
- h = conn->ssl->read_hash;
-#endif
- if (h)
- md_size = EVP_MD_size(h);
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
- else if (conn->ssl->s3)
- md_size = conn->ssl->s3->tmp.new_mac_secret_size;
-#endif
- else
- return -1;
-
- wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
- "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
- EVP_CIPHER_iv_length(c));
- return 2 * (EVP_CIPHER_key_length(c) +
- md_size +
- EVP_CIPHER_iv_length(c));
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
/* Pre-shared secred requires a patch to openssl, so this function is
* commented out unless explicitly needed for EAP-FAST in order to be able to
@@ -3575,6 +3977,7 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
struct tls_connection *conn = arg;
int ret;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (conn == NULL || conn->session_ticket_cb == NULL)
return 0;
@@ -3583,6 +3986,23 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
conn->session_ticket_len,
s->s3->client_random,
s->s3->server_random, secret);
+#else
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ unsigned char server_random[SSL3_RANDOM_SIZE];
+
+ if (conn == NULL || conn->session_ticket_cb == NULL)
+ return 0;
+
+ SSL_get_client_random(s, client_random, sizeof(client_random));
+ SSL_get_server_random(s, server_random, sizeof(server_random));
+
+ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+ conn->session_ticket,
+ conn->session_ticket_len,
+ client_random,
+ server_random, secret);
+#endif
+
os_free(conn->session_ticket);
conn->session_ticket = NULL;
@@ -3656,3 +4076,70 @@ int tls_get_library_version(char *buf, size_t buf_len)
OPENSSL_VERSION_TEXT,
SSLeay_version(SSLEAY_VERSION));
}
+
+
+void tls_connection_set_success_data(struct tls_connection *conn,
+ struct wpabuf *data)
+{
+ SSL_SESSION *sess;
+ struct wpabuf *old;
+
+ if (tls_ex_idx_session < 0)
+ goto fail;
+ sess = SSL_get_session(conn->ssl);
+ if (!sess)
+ goto fail;
+ old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+ if (old) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
+ old);
+ wpabuf_free(old);
+ }
+ if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
+ conn->success_data = 1;
+ return;
+
+fail:
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
+ wpabuf_free(data);
+}
+
+
+void tls_connection_set_success_data_resumed(struct tls_connection *conn)
+{
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Success data accepted for resumed session");
+ conn->success_data = 1;
+}
+
+
+const struct wpabuf *
+tls_connection_get_success_data(struct tls_connection *conn)
+{
+ SSL_SESSION *sess;
+
+ if (tls_ex_idx_session < 0 ||
+ !(sess = SSL_get_session(conn->ssl)))
+ return NULL;
+ return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
+}
+
+
+void tls_connection_remove_session(struct tls_connection *conn)
+{
+ SSL_SESSION *sess;
+
+ sess = SSL_get_session(conn->ssl);
+ if (!sess)
+ return;
+
+ if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Session was not cached");
+ else
+ wpa_printf(MSG_DEBUG,
+ "OpenSSL: Removed cached session to disable session resumption");
+}
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
deleted file mode 100644
index 31a2c946d047..000000000000
--- a/src/crypto/tls_schannel.c
+++ /dev/null
@@ -1,763 +0,0 @@
-/*
- * SSL/TLS interface functions for Microsoft Schannel
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-/*
- * FIX: Go through all SSPI functions and verify what needs to be freed
- * FIX: session resumption
- * TODO: add support for server cert chain validation
- * TODO: add support for CA cert validation
- * TODO: add support for EAP-TLS (client cert/key conf)
- */
-
-#include "includes.h"
-#include <windows.h>
-#include <wincrypt.h>
-#include <schannel.h>
-#define SECURITY_WIN32
-#include <security.h>
-#include <sspi.h>
-
-#include "common.h"
-#include "tls.h"
-
-
-struct tls_global {
- HMODULE hsecurity;
- PSecurityFunctionTable sspi;
- HCERTSTORE my_cert_store;
-};
-
-struct tls_connection {
- int established, start;
- int failed, read_alerts, write_alerts;
-
- SCHANNEL_CRED schannel_cred;
- CredHandle creds;
- CtxtHandle context;
-
- u8 eap_tls_prf[128];
- int eap_tls_prf_set;
-};
-
-
-static int schannel_load_lib(struct tls_global *global)
-{
- INIT_SECURITY_INTERFACE pInitSecurityInterface;
-
- global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
- if (global->hsecurity == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
- __func__, (unsigned int) GetLastError());
- return -1;
- }
-
- pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
- global->hsecurity, "InitSecurityInterfaceA");
- if (pInitSecurityInterface == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not find "
- "InitSecurityInterfaceA from Secur32.dll",
- __func__);
- FreeLibrary(global->hsecurity);
- global->hsecurity = NULL;
- return -1;
- }
-
- global->sspi = pInitSecurityInterface();
- if (global->sspi == NULL) {
- wpa_printf(MSG_ERROR, "%s: Could not read security "
- "interface - 0x%x",
- __func__, (unsigned int) GetLastError());
- FreeLibrary(global->hsecurity);
- global->hsecurity = NULL;
- return -1;
- }
-
- return 0;
-}
-
-
-void * tls_init(const struct tls_config *conf)
-{
- struct tls_global *global;
-
- global = os_zalloc(sizeof(*global));
- if (global == NULL)
- return NULL;
- if (schannel_load_lib(global)) {
- os_free(global);
- return NULL;
- }
- return global;
-}
-
-
-void tls_deinit(void *ssl_ctx)
-{
- struct tls_global *global = ssl_ctx;
-
- if (global->my_cert_store)
- CertCloseStore(global->my_cert_store, 0);
- FreeLibrary(global->hsecurity);
- os_free(global);
-}
-
-
-int tls_get_errors(void *ssl_ctx)
-{
- return 0;
-}
-
-
-struct tls_connection * tls_connection_init(void *ssl_ctx)
-{
- struct tls_connection *conn;
-
- conn = os_zalloc(sizeof(*conn));
- if (conn == NULL)
- return NULL;
- conn->start = 1;
-
- return conn;
-}
-
-
-void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return;
-
- os_free(conn);
-}
-
-
-int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
-{
- return conn ? conn->established : 0;
-}
-
-
-int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
-{
- struct tls_global *global = ssl_ctx;
- if (conn == NULL)
- return -1;
-
- conn->eap_tls_prf_set = 0;
- conn->established = conn->failed = 0;
- conn->read_alerts = conn->write_alerts = 0;
- global->sspi->DeleteSecurityContext(&conn->context);
- /* FIX: what else needs to be reseted? */
-
- return 0;
-}
-
-
-int tls_global_set_params(void *tls_ctx,
- const struct tls_connection_params *params)
-{
- return -1;
-}
-
-
-int tls_global_set_verify(void *ssl_ctx, int check_crl)
-{
- return -1;
-}
-
-
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer)
-{
- return -1;
-}
-
-
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
-{
- /* Schannel does not export master secret or client/server random. */
- return -1;
-}
-
-
-int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
- const char *label, int server_random_first,
- u8 *out, size_t out_len)
-{
- /*
- * Cannot get master_key from Schannel, but EapKeyBlock can be used to
- * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
- * EAP-TTLS cannot use this, though, since they are using different
- * labels. The only option could be to implement TLSv1 completely here
- * and just use Schannel or CryptoAPI for low-level crypto
- * functionality..
- */
-
- if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
- os_strcmp(label, "client EAP encryption") != 0 ||
- out_len > sizeof(conn->eap_tls_prf))
- return -1;
-
- os_memcpy(out, conn->eap_tls_prf, out_len);
-
- return 0;
-}
-
-
-static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
- struct tls_connection *conn)
-{
- DWORD sspi_flags, sspi_flags_out;
- SecBufferDesc outbuf;
- SecBuffer outbufs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
-
- sspi_flags = ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_MANUAL_CRED_VALIDATION;
-
- wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
-
- outbufs[0].pvBuffer = NULL;
- outbufs[0].BufferType = SECBUFFER_TOKEN;
- outbufs[0].cbBuffer = 0;
-
- outbuf.cBuffers = 1;
- outbuf.pBuffers = outbufs;
- outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
- status = global->sspi->InitializeSecurityContextW(
- &conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
- SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->InitializeSecurityContextA(
- &conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
- SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
- if (status != SEC_I_CONTINUE_NEEDED) {
- wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
- "failed - 0x%x",
- __func__, (unsigned int) status);
- return NULL;
- }
-
- if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
- struct wpabuf *buf;
- wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
- outbufs[0].pvBuffer, outbufs[0].cbBuffer);
- conn->start = 0;
- buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
- outbufs[0].cbBuffer);
- if (buf == NULL)
- return NULL;
- global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
- return buf;
- }
-
- wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
-
- return NULL;
-}
-
-
-#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
-#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
-
-typedef struct _SecPkgContext_EapKeyBlock {
- BYTE rgbKeys[128];
- BYTE rgbIVs[64];
-} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
-#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
-
-static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
-{
- SECURITY_STATUS status;
- SecPkgContext_EapKeyBlock kb;
-
- /* Note: Windows NT and Windows Me/98/95 do not support getting
- * EapKeyBlock */
-
- status = global->sspi->QueryContextAttributes(
- &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
- "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
- __func__, (int) status);
- return -1;
- }
-
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
- kb.rgbKeys, sizeof(kb.rgbKeys));
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
- kb.rgbIVs, sizeof(kb.rgbIVs));
-
- os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
- conn->eap_tls_prf_set = 1;
- return 0;
-}
-
-
-struct wpabuf * tls_connection_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- struct tls_global *global = tls_ctx;
- DWORD sspi_flags, sspi_flags_out;
- SecBufferDesc inbuf, outbuf;
- SecBuffer inbufs[2], outbufs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
- struct wpabuf *out_buf = NULL;
-
- if (appl_data)
- *appl_data = NULL;
-
- if (conn->start)
- return tls_conn_hs_clienthello(global, conn);
-
- wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
- (int) wpabuf_len(in_data));
-
- sspi_flags = ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONFIDENTIALITY |
- ISC_RET_EXTENDED_ERROR |
- ISC_REQ_ALLOCATE_MEMORY |
- ISC_REQ_MANUAL_CRED_VALIDATION;
-
- /* Input buffer for Schannel */
- inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
- inbufs[0].cbBuffer = wpabuf_len(in_data);
- inbufs[0].BufferType = SECBUFFER_TOKEN;
-
- /* Place for leftover data from Schannel */
- inbufs[1].pvBuffer = NULL;
- inbufs[1].cbBuffer = 0;
- inbufs[1].BufferType = SECBUFFER_EMPTY;
-
- inbuf.cBuffers = 2;
- inbuf.pBuffers = inbufs;
- inbuf.ulVersion = SECBUFFER_VERSION;
-
- /* Output buffer for Schannel */
- outbufs[0].pvBuffer = NULL;
- outbufs[0].cbBuffer = 0;
- outbufs[0].BufferType = SECBUFFER_TOKEN;
-
- outbuf.cBuffers = 1;
- outbuf.pBuffers = outbufs;
- outbuf.ulVersion = SECBUFFER_VERSION;
-
-#ifdef UNICODE
- status = global->sspi->InitializeSecurityContextW(
- &conn->creds, &conn->context, NULL, sspi_flags, 0,
- SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->InitializeSecurityContextA(
- &conn->creds, &conn->context, NULL, sspi_flags, 0,
- SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
- &outbuf, &sspi_flags_out, &ts_expiry);
-#endif /* UNICODE */
-
- wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
- "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
- "intype[1]=%d outlen[0]=%d",
- (int) status, (int) inbufs[0].cbBuffer,
- (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
- (int) inbufs[1].BufferType,
- (int) outbufs[0].cbBuffer);
- if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
- (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
- if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
- wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
- outbufs[0].pvBuffer, outbufs[0].cbBuffer);
- out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
- outbufs[0].cbBuffer);
- global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
- outbufs[0].pvBuffer = NULL;
- if (out_buf == NULL)
- return NULL;
- }
- }
-
- switch (status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
- break;
- case SEC_I_CONTINUE_NEEDED:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
- break;
- case SEC_E_OK:
- /* TODO: verify server certificate chain */
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
- "completed successfully");
- conn->established = 1;
- tls_get_eap(global, conn);
-
- /* Need to return something to get final TLS ACK. */
- if (out_buf == NULL)
- out_buf = wpabuf_alloc(0);
-
- if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
- wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
- "application data",
- inbufs[1].pvBuffer, inbufs[1].cbBuffer);
- if (appl_data) {
- *appl_data = wpabuf_alloc_copy(
- outbufs[1].pvBuffer,
- outbufs[1].cbBuffer);
- }
- global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
- inbufs[1].pvBuffer = NULL;
- }
- break;
- case SEC_I_INCOMPLETE_CREDENTIALS:
- wpa_printf(MSG_DEBUG,
- "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
- break;
- case SEC_E_WRONG_PRINCIPAL:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
- break;
- case SEC_E_INTERNAL_ERROR:
- wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
- break;
- }
-
- if (FAILED(status)) {
- wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
- "(out_buf=%p)", out_buf);
- conn->failed++;
- global->sspi->DeleteSecurityContext(&conn->context);
- return out_buf;
- }
-
- if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
- /* TODO: Can this happen? What to do with this data? */
- wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
- inbufs[1].pvBuffer, inbufs[1].cbBuffer);
- global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
- inbufs[1].pvBuffer = NULL;
- }
-
- return out_buf;
-}
-
-
-struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data,
- struct wpabuf **appl_data)
-{
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_encrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- struct tls_global *global = tls_ctx;
- SECURITY_STATUS status;
- SecBufferDesc buf;
- SecBuffer bufs[4];
- SecPkgContext_StreamSizes sizes;
- int i;
- struct wpabuf *out;
-
- status = global->sspi->QueryContextAttributes(&conn->context,
- SECPKG_ATTR_STREAM_SIZES,
- &sizes);
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
- __func__);
- return NULL;
- }
- wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
- __func__,
- (unsigned int) sizes.cbHeader,
- (unsigned int) sizes.cbTrailer);
-
- out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
- sizes.cbTrailer);
-
- os_memset(&bufs, 0, sizeof(bufs));
- bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
- bufs[0].cbBuffer = sizes.cbHeader;
- bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
-
- bufs[1].pvBuffer = wpabuf_put(out, 0);
- wpabuf_put_buf(out, in_data);
- bufs[1].cbBuffer = wpabuf_len(in_data);
- bufs[1].BufferType = SECBUFFER_DATA;
-
- bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
- bufs[2].cbBuffer = sizes.cbTrailer;
- bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
-
- buf.ulVersion = SECBUFFER_VERSION;
- buf.cBuffers = 3;
- buf.pBuffers = bufs;
-
- status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
-
- wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
- "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
- "len[2]=%d type[2]=%d",
- (int) status,
- (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
- (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
- (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
- wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
- "out_data=%p bufs %p %p %p",
- wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
- bufs[2].pvBuffer);
-
- for (i = 0; i < 3; i++) {
- if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
- {
- wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
- bufs[i].pvBuffer, bufs[i].cbBuffer);
- }
- }
-
- if (status == SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
- wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
- "from EncryptMessage", out);
- return out;
- }
-
- wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
- __func__, (int) status);
- wpabuf_free(out);
- return NULL;
-}
-
-
-struct wpabuf * tls_connection_decrypt(void *tls_ctx,
- struct tls_connection *conn,
- const struct wpabuf *in_data)
-{
- struct tls_global *global = tls_ctx;
- SECURITY_STATUS status;
- SecBufferDesc buf;
- SecBuffer bufs[4];
- int i;
- struct wpabuf *out, *tmp;
-
- wpa_hexdump_buf(MSG_MSGDUMP,
- "Schannel: Encrypted data to DecryptMessage", in_data);
- os_memset(&bufs, 0, sizeof(bufs));
- tmp = wpabuf_dup(in_data);
- if (tmp == NULL)
- return NULL;
- bufs[0].pvBuffer = wpabuf_mhead(tmp);
- bufs[0].cbBuffer = wpabuf_len(in_data);
- bufs[0].BufferType = SECBUFFER_DATA;
-
- bufs[1].BufferType = SECBUFFER_EMPTY;
- bufs[2].BufferType = SECBUFFER_EMPTY;
- bufs[3].BufferType = SECBUFFER_EMPTY;
-
- buf.ulVersion = SECBUFFER_VERSION;
- buf.cBuffers = 4;
- buf.pBuffers = bufs;
-
- status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
- NULL);
- wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
- "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
- "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
- (int) status,
- (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
- (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
- (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
- (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
- wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
- "out_data=%p bufs %p %p %p %p",
- wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
- bufs[2].pvBuffer, bufs[3].pvBuffer);
-
- switch (status) {
- case SEC_E_INCOMPLETE_MESSAGE:
- wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
- __func__);
- break;
- case SEC_E_OK:
- wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
- for (i = 0; i < 4; i++) {
- if (bufs[i].BufferType == SECBUFFER_DATA)
- break;
- }
- if (i == 4) {
- wpa_printf(MSG_DEBUG, "%s: No output data from "
- "DecryptMessage", __func__);
- wpabuf_free(tmp);
- return NULL;
- }
- wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
- "DecryptMessage",
- bufs[i].pvBuffer, bufs[i].cbBuffer);
- out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
- wpabuf_free(tmp);
- return out;
- }
-
- wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
- __func__, (int) status);
- wpabuf_free(tmp);
- return NULL;
-}
-
-
-int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
- u8 *ciphers)
-{
- return -1;
-}
-
-
-int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
- char *buf, size_t buflen)
-{
- return -1;
-}
-
-
-int tls_connection_enable_workaround(void *ssl_ctx,
- struct tls_connection *conn)
-{
- return 0;
-}
-
-
-int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
- int ext_type, const u8 *data,
- size_t data_len)
-{
- return -1;
-}
-
-
-int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->failed;
-}
-
-
-int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->read_alerts;
-}
-
-
-int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
-{
- if (conn == NULL)
- return -1;
- return conn->write_alerts;
-}
-
-
-int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
- const struct tls_connection_params *params)
-{
- struct tls_global *global = tls_ctx;
- ALG_ID algs[1];
- SECURITY_STATUS status;
- TimeStamp ts_expiry;
-
- if (conn == NULL)
- return -1;
-
- if (params->subject_match) {
- wpa_printf(MSG_INFO, "TLS: subject_match not supported");
- return -1;
- }
-
- if (params->altsubject_match) {
- wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
- return -1;
- }
-
- if (params->suffix_match) {
- wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
- return -1;
- }
-
- if (params->domain_match) {
- wpa_printf(MSG_INFO, "TLS: domain_match not supported");
- return -1;
- }
-
- if (params->openssl_ciphers) {
- wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
- return -1;
- }
-
- if (global->my_cert_store == NULL &&
- (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
- NULL) {
- wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
- __func__, (unsigned int) GetLastError());
- return -1;
- }
-
- os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
- conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
- conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
- algs[0] = CALG_RSA_KEYX;
- conn->schannel_cred.cSupportedAlgs = 1;
- conn->schannel_cred.palgSupportedAlgs = algs;
- conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
-#ifdef UNICODE
- status = global->sspi->AcquireCredentialsHandleW(
- NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
- &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#else /* UNICODE */
- status = global->sspi->AcquireCredentialsHandleA(
- NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
- &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
-#endif /* UNICODE */
- if (status != SEC_E_OK) {
- wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
- "0x%x", __func__, (unsigned int) status);
- return -1;
- }
-
- return 0;
-}
-
-
-unsigned int tls_capabilities(void *tls_ctx)
-{
- return 0;
-}
-
-
-int tls_get_library_version(char *buf, size_t buf_len)
-{
- return os_snprintf(buf, buf_len, "schannel");
-}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 03bd1a79a14c..3cdab5a7a87d 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -20,6 +20,7 @@
#define WPA_SUPPLICANT_DRIVER_VERSION 4
#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
@@ -341,7 +342,7 @@ struct wpa_driver_scan_params {
* is not needed anymore.
*/
struct wpa_driver_scan_filter {
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
} *filter_ssids;
@@ -1211,6 +1212,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL
/** Driver supports IBSS with VHT datarates */
#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
+/** Driver supports automatic band selection */
+#define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL
u64 flags;
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
@@ -1294,6 +1297,13 @@ struct wpa_driver_capa {
*/
#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
u32 rrm_flags;
+
+ /* Driver concurrency capabilities */
+ unsigned int conc_capab;
+ /* Maximum number of concurrent channels on 2.4 GHz */
+ unsigned int max_conc_chan_2_4;
+ /* Maximum number of concurrent channels on 5 GHz */
+ unsigned int max_conc_chan_5_0;
};
@@ -1394,6 +1404,16 @@ enum wpa_driver_if_type {
* WPA_IF_MESH - Mesh interface
*/
WPA_IF_MESH,
+
+ /*
+ * WPA_IF_TDLS - TDLS offchannel interface (used for pref freq only)
+ */
+ WPA_IF_TDLS,
+
+ /*
+ * WPA_IF_IBSS - IBSS interface (used for pref freq only)
+ */
+ WPA_IF_IBSS,
};
struct wpa_init_params {
@@ -1477,6 +1497,7 @@ struct wpa_signal_info {
int above_threshold;
int current_signal;
int avg_signal;
+ int avg_beacon_signal;
int current_noise;
int current_txrate;
enum chan_width chanwidth;
@@ -1576,6 +1597,7 @@ enum drv_br_port_attr {
enum drv_br_net_param {
DRV_BR_NET_PARAM_GARP_ACCEPT,
+ DRV_BR_MULTICAST_SNOOPING,
};
struct drv_acs_params {
@@ -1587,6 +1609,17 @@ struct drv_acs_params {
/* Indicates whether HT40 is enabled */
int ht40_enabled;
+
+ /* Indicates whether VHT is enabled */
+ int vht_enabled;
+
+ /* Configured ACS channel width */
+ u16 ch_width;
+
+ /* ACS channel list info */
+ unsigned int ch_list_len;
+ const u8 *ch_list;
+ const int *freq_list;
};
@@ -1925,10 +1958,12 @@ struct wpa_driver_ops {
* @data: IEEE 802.11 management frame with IEEE 802.11 header
* @data_len: Size of the management frame
* @noack: Do not wait for this frame to be acked (disable retries)
+ * @freq: Frequency (in MHz) to send the frame on, or 0 to let the
+ * driver decide
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
- int noack);
+ int noack, unsigned int freq);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2332,7 +2367,8 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure
*/
int (*sta_set_flags)(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and);
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and);
/**
* set_tx_queue_params - Set TX queue parameters
@@ -2656,18 +2692,6 @@ struct wpa_driver_ops {
int encrypt);
/**
- * shared_freq - Get operating frequency of shared interface(s)
- * @priv: Private driver interface data
- * Returns: Operating frequency in MHz, 0 if no shared operation in
- * use, or -1 on failure
- *
- * This command can be used to request the current operating frequency
- * of any virtual interface that shares the same radio to provide
- * information for channel selection for other virtual interfaces.
- */
- int (*shared_freq)(void *priv);
-
- /**
* get_noa - Get current Notice of Absence attribute payload
* @priv: Private driver interface data
* @buf: Buffer for returning NoA
@@ -3381,6 +3405,40 @@ struct wpa_driver_ops {
* indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD).
*/
int (*do_acs)(void *priv, struct drv_acs_params *params);
+
+ /**
+ * set_band - Notify driver of band selection
+ * @priv: Private driver interface data
+ * @band: The selected band(s)
+ * Returns 0 on success, -1 on failure
+ */
+ int (*set_band)(void *priv, enum set_band band);
+
+ /**
+ * get_pref_freq_list - Get preferred frequency list for an interface
+ * @priv: Private driver interface data
+ * @if_type: Interface type
+ * @num: Number of channels
+ * @freq_list: Preferred channel frequency list encoded in MHz values
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to query the preferred frequency list from
+ * the driver specific to a particular interface type.
+ */
+ int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type,
+ unsigned int *num, unsigned int *freq_list);
+
+ /**
+ * set_prob_oper_freq - Indicate probable P2P operating channel
+ * @priv: Private driver interface data
+ * @freq: Channel frequency in MHz
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to inform the driver of the operating
+ * frequency that an ongoing P2P group formation is likely to come up
+ * on. Local device is assuming P2P Client role.
+ */
+ int (*set_prob_oper_freq)(void *priv, unsigned int freq);
};
@@ -4557,10 +4615,20 @@ union wpa_event_data {
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
* @pri_channel: Selected primary channel
* @sec_channel: Selected secondary channel
+ * @vht_seg0_center_ch: VHT mode Segment0 center channel
+ * @vht_seg1_center_ch: VHT mode Segment1 center channel
+ * @ch_width: Selected Channel width by driver. Driver may choose to
+ * change hostapd configured ACS channel width due driver internal
+ * channel restrictions.
+ * hw_mode: Selected band (used with hw_mode=any)
*/
struct acs_selected_channels {
u8 pri_channel;
u8 sec_channel;
+ u8 vht_seg0_center_ch;
+ u8 vht_seg1_center_ch;
+ u16 ch_width;
+ enum hostapd_hw_mode hw_mode;
} acs_selected_channels;
};
@@ -4631,6 +4699,6 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers,
const struct wpa_driver_capa *capa);
/* NULL terminated array of linked in driver wrappers */
-extern struct wpa_driver_ops *wpa_drivers[];
+extern const struct wpa_driver_ops *const wpa_drivers[];
#endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index f46442163d93..ef140934973a 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -55,6 +55,10 @@
#include "netlink.h"
#include "linux_ioctl.h"
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS)
+#define ATHEROS_USE_RAW_RECEIVE
+#endif
+
struct atheros_driver_data {
struct hostapd_data *hapd; /* back pointer */
@@ -430,7 +434,8 @@ atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized)
static int
atheros_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and)
{
/* For now, only support setting Authorized flag */
if (flags_or & WPA_STA_AUTHORIZED)
@@ -823,7 +828,7 @@ static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
return 0;
}
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) || defined(CONFIG_HS20)
+#ifdef ATHEROS_USE_RAW_RECEIVE
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -911,7 +916,7 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
break;
}
}
-#endif
+#endif /* ATHEROS_USE_RAW_RECEIVE */
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -923,11 +928,11 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
#ifdef CONFIG_WPS
filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
IEEE80211_FILTER_TYPE_AUTH |
IEEE80211_FILTER_TYPE_ACTION);
-#endif
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
#endif /* CONFIG_WNM */
@@ -1026,7 +1031,7 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
#define atheros_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
static int
atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq,
u16 status_code, const u8 *ie, size_t len)
@@ -1102,7 +1107,7 @@ atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
}
return ret;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
static void
atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
@@ -1177,6 +1182,7 @@ static void
atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
char *custom, char *end)
{
+#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
@@ -1232,9 +1238,6 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
* so all are enabled for WPS... ugh.
*/
wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
-#endif /* CONFIG_WPS */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
-#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
} else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
/*
* Atheros driver uses a hack to pass Probe Request frames as a
@@ -1250,40 +1253,46 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
+#endif /* CONFIG_WPS */
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
} else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
int len = atoi(custom + 17);
if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
- wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
- "assoc_req/auth event length %d", len);
+ wpa_printf(MSG_DEBUG,
+ "Invalid Manage.assoc_req event length %d",
+ len);
return;
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
- } else if (strncmp(custom, "Manage.action ", 14) == 0) {
- /* Format: "Manage.assoc_req <frame len>" | zero padding |
- * frame */
- int len = atoi(custom + 14);
- if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
- wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
- "assoc_req/auth event length %d", len);
+ } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
+ /* Format: "Manage.auth <frame len>" | zero padding | frame */
+ int len = atoi(custom + 12);
+ if (len < 0 ||
+ custom + MGMT_FRAM_TAG_SIZE + len > end) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid Manage.auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
- } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
- /* Format: "Manage.auth <frame len>" | zero padding | frame
+#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
+#ifdef ATHEROS_USE_RAW_RECEIVE
+ } else if (strncmp(custom, "Manage.action ", 14) == 0) {
+ /* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
- int len = atoi(custom + 12);
+ int len = atoi(custom + 14);
if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
- wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
- "assoc_req/auth event length %d", len);
+ wpa_printf(MSG_DEBUG,
+ "Invalid Manage.action event length %d",
+ len);
return;
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
+#endif /* ATHEROS_USE_RAW_RECEIVE */
}
}
@@ -1682,8 +1691,7 @@ bad:
l2_packet_deinit(drv->sock_xmit);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
- if (drv != NULL)
- free(drv);
+ os_free(drv);
return NULL;
}
@@ -1694,6 +1702,13 @@ atheros_deinit(void *priv)
struct atheros_driver_data *drv = priv;
atheros_reset_appfilter(drv);
+
+ if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) {
+ wpabuf_free(drv->wpa_ie);
+ wpabuf_free(drv->wps_beacon_ie);
+ wpabuf_free(drv->wps_probe_resp_ie);
+ atheros_set_opt_ie(priv, NULL, 0);
+ }
netlink_deinit(drv->netlink);
(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
if (drv->ioctl_sock >= 0)
@@ -1704,10 +1719,7 @@ atheros_deinit(void *priv)
l2_packet_deinit(drv->sock_xmit);
if (drv->sock_raw)
l2_packet_deinit(drv->sock_raw);
- wpabuf_free(drv->wpa_ie);
- wpabuf_free(drv->wps_beacon_ie);
- wpabuf_free(drv->wps_probe_resp_ie);
- free(drv);
+ os_free(drv);
}
static int
@@ -1833,10 +1845,10 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
}
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
- int noack)
+ int noack, unsigned int freq)
{
struct atheros_driver_data *drv = priv;
u8 buf[1510];
@@ -1858,8 +1870,11 @@ static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
sizeof(struct ieee80211req_mgmtbuf) + data_len);
}
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+
static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie,
size_t tspec_ielen)
{
@@ -2139,10 +2154,12 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
.set_ap = atheros_set_ap,
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme = atheros_send_mgmt,
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
#endif /* CONFIG_IEEE80211R */
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 0f1a0f60f27d..bab1f031d24c 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -861,8 +861,7 @@ bad:
if (drv->sock >= 0)
close(drv->sock);
os_free(drv->event_buf);
- if (drv != NULL)
- os_free(drv);
+ os_free(drv);
return NULL;
}
@@ -895,7 +894,8 @@ bsd_commit(void *priv)
static int
bsd_set_sta_authorized(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and)
{
int authorized = -1;
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 84b98fb8c87f..a7aa5eff00bd 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -140,7 +140,7 @@ static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf,
static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
{
struct ieee80211_hdr *hdr;
- u16 fc, extra_len, type, stype;
+ u16 fc, type, stype;
size_t data_len = len;
int ver;
union wpa_event_data event;
@@ -165,19 +165,10 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
ver = fc & WLAN_FC_PVER;
- /* protocol version 3 is reserved for indicating extra data after the
- * payload, version 2 for indicating ACKed frame (TX callbacks), and
- * version 1 for indicating failed frame (no ACK, TX callbacks) */
- if (ver == 3) {
- u8 *pos = buf + len - 2;
- extra_len = WPA_GET_LE16(pos);
- printf("extra data in frame (elen=%d)\n", extra_len);
- if ((size_t) extra_len + 2 > len) {
- printf(" extra data overflow\n");
- return;
- }
- len -= extra_len + 2;
- } else if (ver == 1 || ver == 2) {
+ /* protocol version 2 is reserved for indicating ACKed frame (TX
+ * callbacks), and version 1 for indicating failed frame (no ACK, TX
+ * callbacks) */
+ if (ver == 1 || ver == 2) {
handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
return;
} else if (ver != 0) {
@@ -266,7 +257,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
}
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
+ unsigned int freq)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -315,20 +307,21 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
pos += 2;
memcpy(pos, data, data_len);
- res = hostap_send_mlme(drv, (u8 *) hdr, len, 0);
+ res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
"failed: %d (%s)",
(unsigned long) len, errno, strerror(errno));
}
- free(hdr);
+ os_free(hdr);
return res;
}
static int hostap_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param param;
@@ -470,18 +463,18 @@ static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr,
param = (struct prism2_hostapd_param *) buf;
param->cmd = PRISM2_GET_ENCRYPTION;
if (addr == NULL)
- memset(param->sta_addr, 0xff, ETH_ALEN);
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
else
- memcpy(param->sta_addr, addr, ETH_ALEN);
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
param->u.crypt.idx = idx;
if (hostapd_ioctl(drv, param, blen)) {
printf("Failed to get encryption.\n");
ret = -1;
} else {
- memcpy(seq, param->u.crypt.seq, 8);
+ os_memcpy(seq, param->u.crypt.seq, 8);
}
- free(buf);
+ os_free(buf);
return ret;
}
@@ -1052,7 +1045,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0);
+ sizeof(mgmt.u.deauth), 0, 0);
}
@@ -1090,7 +1083,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc), 0);
+ sizeof(mgmt.u.disassoc), 0, 0);
}
@@ -1168,7 +1161,7 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0);
+ hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0);
}
diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h
index a9d3e76cbe8f..4c1e6d69f0a7 100644
--- a/src/drivers/driver_hostap.h
+++ b/src/drivers/driver_hostap.h
@@ -192,7 +192,7 @@ struct prism2_hostapd_param {
} mlme;
struct {
u8 ssid_len;
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
} scan_req;
} u;
};
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 4953af6a16b2..669f1b813c43 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -709,11 +709,11 @@ static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
/* Disconnect by setting SSID to random (i.e., likely not used). */
static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
{
- char ssid[32];
+ char ssid[SSID_MAX_LEN];
int i;
- for (i = 0; i < 32; i++)
+ for (i = 0; i < SSID_MAX_LEN; i++)
ssid[i] = rand() & 0xff;
- return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
+ return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, SSID_MAX_LEN);
}
@@ -806,7 +806,7 @@ static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
if (wpa_scan_get_ie(r, WLAN_EID_SSID))
return r; /* SSID IE already present */
- if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
+ if (ssid->SsidLength == 0 || ssid->SsidLength > SSID_MAX_LEN)
return r; /* No valid SSID inside scan data */
nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index d7438683d8f0..00b173f3f85a 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -87,7 +87,6 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
#undef nl_socket_set_nonblocking
#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
-#define genl_ctrl_resolve android_genl_ctrl_resolve
#endif /* ANDROID */
@@ -1187,6 +1186,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
+ [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
};
struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1215,6 +1215,13 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
else
sig_change->avg_signal = 0;
+ if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
+ sig_change->avg_beacon_signal =
+ (s8)
+ nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
+ else
+ sig_change->avg_beacon_signal = 0;
+
if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -1871,6 +1878,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
ret = -1;
}
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_FST
+ /* FST Action frames */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
+ ret = -1;
+#endif /* CONFIG_FST */
/* FT Action frames */
if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
@@ -2493,7 +2505,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex;
- struct nl_msg *msg;
+ struct nl_msg *msg = NULL;
int ret;
int tdls = 0;
@@ -2526,11 +2538,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
if (!msg)
return -ENOBUFS;
} else {
+ u32 suite;
+
+ suite = wpa_alg_to_cipher_suite(alg, key_len);
+ if (!suite)
+ goto fail;
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
if (!msg ||
nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
- nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len)))
+ nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
goto fail;
wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
}
@@ -2632,9 +2648,15 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
const u8 *key, size_t key_len)
{
struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
+ u32 suite;
+
if (!key_attr)
return -1;
+ suite = wpa_alg_to_cipher_suite(alg, key_len);
+ if (!suite)
+ return -1;
+
if (defkey && alg == WPA_ALG_IGTK) {
if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
return -1;
@@ -2644,8 +2666,7 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
}
if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
- nla_put_u32(msg, NL80211_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len)) ||
+ nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
(seq && seq_len &&
nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
nla_put(msg, NL80211_KEY_DATA, key_len, key))
@@ -3237,7 +3258,7 @@ static int wpa_driver_nl80211_set_acl(void *priv,
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- struct nlattr *acl;
+ struct nl_msg *acl;
unsigned int i;
int ret;
@@ -3250,23 +3271,26 @@ static int wpa_driver_nl80211_set_acl(void *priv,
wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+ acl = nlmsg_alloc();
+ if (!acl)
+ return -ENOMEM;
+ for (i = 0; i < params->num_mac_acl; i++) {
+ if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
+ nlmsg_free(acl);
+ return -ENOMEM;
+ }
+ }
+
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
- (acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS)) == NULL) {
+ nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
nlmsg_free(msg);
+ nlmsg_free(acl);
return -ENOMEM;
}
-
- for (i = 0; i < params->num_mac_acl; i++) {
- if (nla_put(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
- nlmsg_free(msg);
- return -ENOMEM;
- }
- }
-
- nla_nest_end(msg, acl);
+ nlmsg_free(acl);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
@@ -4233,8 +4257,9 @@ static int wpa_driver_nl80211_hapd_send_eapol(
static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
- int total_flags,
- int flags_or, int flags_and)
+ unsigned int total_flags,
+ unsigned int flags_or,
+ unsigned int flags_and)
{
struct i802_bss *bss = priv;
struct nl_msg *msg;
@@ -5658,8 +5683,8 @@ static void *i802_init(struct hostapd_data *hapd,
struct wpa_driver_nl80211_data *drv;
struct i802_bss *bss;
size_t i;
- char brname[IFNAMSIZ];
- int ifindex, br_ifindex;
+ char master_ifname[IFNAMSIZ];
+ int ifindex, br_ifindex = 0;
int br_added = 0;
bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
@@ -5670,15 +5695,21 @@ static void *i802_init(struct hostapd_data *hapd,
drv = bss->drv;
- if (linux_br_get(brname, params->ifname) == 0) {
+ if (linux_br_get(master_ifname, params->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
- params->ifname, brname);
- br_ifindex = if_nametoindex(brname);
- os_strlcpy(bss->brname, brname, IFNAMSIZ);
+ params->ifname, master_ifname);
+ br_ifindex = if_nametoindex(master_ifname);
+ os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
+ } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
+ linux_master_get(master_ifname, params->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
+ params->ifname, master_ifname);
+ /* start listening for EAPOL on the master interface */
+ add_ifidx(drv, if_nametoindex(master_ifname));
} else {
- brname[0] = '\0';
- br_ifindex = 0;
+ master_ifname[0] = '\0';
}
+
bss->br_ifindex = br_ifindex;
for (i = 0; i < params->num_bridge; i++) {
@@ -5698,7 +5729,7 @@ static void *i802_init(struct hostapd_data *hapd,
if (i802_check_bridge(drv, bss, params->bridge[0],
params->ifname) < 0)
goto failed;
- if (os_strcmp(params->bridge[0], brname) != 0)
+ if (os_strcmp(params->bridge[0], master_ifname) != 0)
br_added = 1;
}
@@ -5776,13 +5807,12 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
return NL80211_IFTYPE_P2P_DEVICE;
case WPA_IF_MESH:
return NL80211_IFTYPE_MESH_POINT;
+ default:
+ return -1;
}
- return -1;
}
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
-
static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
{
struct wpa_driver_nl80211_data *drv;
@@ -5818,8 +5848,6 @@ static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
return 0;
}
-#endif /* CONFIG_P2P || CONFIG_MESH */
-
struct wdev_info {
u64 wdev_id;
@@ -5895,21 +5923,21 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
if (!addr) {
- if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
os_memcpy(if_addr, bss->addr, ETH_ALEN);
else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
- bss->ifname, if_addr) < 0) {
+ ifname, if_addr) < 0) {
if (added)
nl80211_remove_iface(drv, ifidx);
return -1;
}
}
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
if (!addr &&
(type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
- type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
- /* Enforce unique P2P Interface Address */
+ type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
+ type == WPA_IF_STATION)) {
+ /* Enforce unique address */
u8 new_addr[ETH_ALEN];
if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
@@ -5920,8 +5948,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
if (nl80211_addr_in_use(drv->global, new_addr)) {
wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
- "for %s interface", type == WPA_IF_MESH ?
- "mesh" : "P2P group");
+ "for interface %s type %d", ifname, type);
if (nl80211_vif_addr(drv, new_addr) < 0) {
if (added)
nl80211_remove_iface(drv, ifidx);
@@ -5936,7 +5963,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
os_memcpy(if_addr, new_addr, ETH_ALEN);
}
-#endif /* CONFIG_P2P || CONFIG_MESH */
if (type == WPA_IF_AP_BSS) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -6514,47 +6540,6 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
}
-static int wpa_driver_nl80211_shared_freq(void *priv)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct wpa_driver_nl80211_data *driver;
- int freq = 0;
-
- /*
- * If the same PHY is in connected state with some other interface,
- * then retrieve the assoc freq.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
- drv->phyname);
-
- dl_list_for_each(driver, &drv->global->interfaces,
- struct wpa_driver_nl80211_data, list) {
- if (drv == driver ||
- os_strcmp(drv->phyname, driver->phyname) != 0 ||
- !driver->associated)
- continue;
-
- wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
- MACSTR,
- driver->phyname, driver->first_bss->ifname,
- MAC2STR(driver->first_bss->addr));
- if (is_ap_interface(driver->nlmode))
- freq = driver->first_bss->freq;
- else
- freq = nl80211_get_assoc_freq(driver);
- wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
- drv->phyname, freq);
- }
-
- if (!freq)
- wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
- "PHY (%s) in associated state", drv->phyname);
-
- return freq;
-}
-
-
static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
int encrypt)
{
@@ -7275,11 +7260,12 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len, int noack)
+ size_t data_len, int noack,
+ unsigned int freq)
{
struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
- 0, 0, 0, 0);
+ freq, 0, 0, 0);
}
@@ -7506,7 +7492,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
"capa.max_acl_mac_addrs=%u\n"
"capa.num_multichan_concurrent=%u\n"
"capa.mac_addr_rand_sched_scan_supported=%d\n"
- "capa.mac_addr_rand_scan_supported=%d\n",
+ "capa.mac_addr_rand_scan_supported=%d\n"
+ "capa.conc_capab=%u\n"
+ "capa.max_conc_chan_2_4=%u\n"
+ "capa.max_conc_chan_5_0=%u\n",
drv->capa.key_mgmt,
drv->capa.enc,
drv->capa.auth,
@@ -7522,7 +7511,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
drv->capa.max_acl_mac_addrs,
drv->capa.num_multichan_concurrent,
drv->capa.mac_addr_rand_sched_scan_supported,
- drv->capa.mac_addr_rand_scan_supported);
+ drv->capa.mac_addr_rand_scan_supported,
+ drv->capa.conc_capab,
+ drv->capa.max_conc_chan_2_4,
+ drv->capa.max_conc_chan_5_0);
if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -7837,7 +7829,7 @@ static int nl80211_set_wowlan(void *priv,
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
!(wowlan_triggers = nla_nest_start(msg,
NL80211_ATTR_WOWLAN_TRIGGERS)) ||
(triggers->any &&
@@ -8340,9 +8332,9 @@ static const char * drv_br_net_param_str(enum drv_br_net_param param)
switch (param) {
case DRV_BR_NET_PARAM_GARP_ACCEPT:
return "arp_accept";
+ default:
+ return NULL;
}
-
- return NULL;
}
@@ -8354,6 +8346,13 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
const char *param_txt;
int ip_version = 4;
+ if (param == DRV_BR_MULTICAST_SNOOPING) {
+ os_snprintf(path, sizeof(path),
+ "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
+ bss->brname);
+ goto set_val;
+ }
+
param_txt = drv_br_net_param_str(param);
if (param_txt == NULL)
return -EINVAL;
@@ -8369,6 +8368,7 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
ip_version, bss->brname, param_txt);
+set_val:
if (linux_write_system_file(path, val))
return -1;
@@ -8387,12 +8387,34 @@ static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
return QCA_ACS_MODE_IEEE80211A;
case HOSTAPD_MODE_IEEE80211AD:
return QCA_ACS_MODE_IEEE80211AD;
+ case HOSTAPD_MODE_IEEE80211ANY:
+ return QCA_ACS_MODE_IEEE80211ANY;
default:
return -1;
}
}
+static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
+{
+ int i, len, ret;
+ u32 *freqs;
+
+ if (!freq_list)
+ return 0;
+ len = int_array_len(freq_list);
+ freqs = os_malloc(sizeof(u32) * len);
+ if (!freqs)
+ return -1;
+ for (i = 0; i < len; i++)
+ freqs[i] = freq_list[i];
+ ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
+ sizeof(u32) * len, freqs);
+ os_free(freqs);
+ return ret;
+}
+
+
static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
{
struct i802_bss *bss = priv;
@@ -8415,12 +8437,25 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
(params->ht_enabled &&
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
(params->ht40_enabled &&
- nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
+ (params->vht_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+ params->ch_width) ||
+ (params->ch_list_len &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
+ params->ch_list)) ||
+ add_acs_freq_list(msg, params->freq_list)) {
nlmsg_free(msg);
return -ENOBUFS;
}
nla_nest_end(msg, data);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
+ params->hw_mode, params->ht_enabled, params->ht40_enabled,
+ params->vht_enabled, params->ch_width, params->ch_list_len);
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -8431,6 +8466,240 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
}
+static int nl80211_set_band(void *priv, enum set_band band)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *data;
+ int ret;
+ enum qca_set_band qca_band;
+
+ if (!drv->setband_vendor_cmd_avail)
+ return -1;
+
+ switch (band) {
+ case WPA_SETBAND_AUTO:
+ qca_band = QCA_SETBAND_AUTO;
+ break;
+ case WPA_SETBAND_5G:
+ qca_band = QCA_SETBAND_5G;
+ break;
+ case WPA_SETBAND_2G:
+ qca_band = QCA_SETBAND_2G;
+ break;
+ default:
+ return -1;
+ }
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, data);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver setband function failed: %s",
+ strerror(errno));
+ }
+ return ret;
+}
+
+
+struct nl80211_pcl {
+ unsigned int num;
+ unsigned int *freq_list;
+};
+
+static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nl80211_pcl *param = arg;
+ struct nlattr *nl_vend, *attr;
+ enum qca_iface_type iface_type;
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ unsigned int num, max_num;
+ u32 *freqs;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ if (!nl_vend)
+ return NL_SKIP;
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
+ if (!attr) {
+ wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
+ param->num = 0;
+ return NL_SKIP;
+ }
+
+ iface_type = (enum qca_iface_type) nla_get_u32(attr);
+ wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
+ iface_type);
+
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
+ if (!attr) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: preferred_freq_list couldn't be found");
+ param->num = 0;
+ return NL_SKIP;
+ }
+
+ /*
+ * param->num has the maximum number of entries for which there
+ * is room in the freq_list provided by the caller.
+ */
+ freqs = nla_data(attr);
+ max_num = nla_len(attr) / sizeof(u32);
+ if (max_num > param->num)
+ max_num = param->num;
+ for (num = 0; num < max_num; num++)
+ param->freq_list[num] = freqs[num];
+ param->num = num;
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_pref_freq_list(void *priv,
+ enum wpa_driver_if_type if_type,
+ unsigned int *num,
+ unsigned int *freq_list)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ unsigned int i;
+ struct nlattr *params;
+ struct nl80211_pcl param;
+ enum qca_iface_type iface_type;
+
+ if (!drv->get_pref_freq_list)
+ return -1;
+
+ switch (if_type) {
+ case WPA_IF_STATION:
+ iface_type = QCA_IFACE_TYPE_STA;
+ break;
+ case WPA_IF_AP_BSS:
+ iface_type = QCA_IFACE_TYPE_AP;
+ break;
+ case WPA_IF_P2P_GO:
+ iface_type = QCA_IFACE_TYPE_P2P_GO;
+ break;
+ case WPA_IF_P2P_CLIENT:
+ iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
+ break;
+ case WPA_IF_IBSS:
+ iface_type = QCA_IFACE_TYPE_IBSS;
+ break;
+ case WPA_IF_TDLS:
+ iface_type = QCA_IFACE_TYPE_TDLS;
+ break;
+ default:
+ return -1;
+ }
+
+ param.num = *num;
+ param.freq_list = freq_list;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
+ iface_type)) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
+ ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in send_and_recv_msgs", __func__);
+ return ret;
+ }
+
+ *num = param.num;
+
+ for (i = 0; i < *num; i++) {
+ wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
+ i, freq_list[i]);
+ }
+
+ return 0;
+}
+
+
+static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ struct nlattr *params;
+
+ if (!drv->set_prob_oper_freq)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set P2P probable operating freq %u for ifindex %d",
+ freq, bss->ifindex);
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
+ QCA_IFACE_TYPE_P2P_CLIENT) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
+ freq)) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
+ __func__);
+ return ret;
+ }
+ nlmsg_free(msg);
+ return 0;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -8490,7 +8759,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.send_frame = nl80211_send_frame,
- .shared_freq = wpa_driver_nl80211_shared_freq,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
.add_pmkid = nl80211_add_pmkid,
@@ -8518,7 +8786,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
#endif /* ANDROID_P2P */
#ifdef ANDROID
+#ifndef ANDROID_LIB_STUB
.driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* !ANDROID_LIB_STUB */
#endif /* ANDROID */
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
@@ -8537,4 +8807,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.add_tx_ts = nl80211_add_ts,
.del_tx_ts = nl80211_del_ts,
.do_acs = wpa_driver_do_acs,
+ .set_band = nl80211_set_band,
+ .get_pref_freq_list = nl80211_get_pref_freq_list,
+ .set_prob_oper_freq = nl80211_set_prob_oper_freq,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 802589aa7581..5c21e0faf55c 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -110,7 +110,7 @@ struct wpa_driver_nl80211_data {
u8 bssid[ETH_ALEN];
u8 prev_bssid[ETH_ALEN];
int associated;
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
enum nl80211_iftype nlmode;
enum nl80211_iftype ap_scan_as_station;
@@ -145,6 +145,9 @@ struct wpa_driver_nl80211_data {
unsigned int get_features_vendor_cmd_avail:1;
unsigned int set_rekey_offload:1;
unsigned int p2p_go_ctwindow_supported:1;
+ unsigned int setband_vendor_cmd_avail:1;
+ unsigned int get_pref_freq_list:1;
+ unsigned int set_prob_oper_freq:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
@@ -169,7 +172,7 @@ struct wpa_driver_nl80211_data {
/* From failed authentication command */
int auth_freq;
u8 auth_bssid_[ETH_ALEN];
- u8 auth_ssid[32];
+ u8 auth_ssid[SSID_MAX_LEN];
size_t auth_ssid_len;
int auth_alg;
u8 *auth_ie;
@@ -232,7 +235,6 @@ int process_bss_event(struct nl_msg *msg, void *arg);
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int android_pno_stop(struct i802_bss *bss);
@@ -270,5 +272,6 @@ int wpa_driver_nl80211_sched_scan(void *priv,
int wpa_driver_nl80211_stop_sched_scan(void *priv);
struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie);
#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
index 3cc9a65867f6..ba47888843bb 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -151,7 +151,7 @@ int android_pno_stop(struct i802_bss *bss)
#ifdef ANDROID_P2P
-#ifdef ANDROID_P2P_STUB
+#ifdef ANDROID_LIB_STUB
int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
{
@@ -178,7 +178,7 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
return 0;
}
-#endif /* ANDROID_P2P_STUB */
+#endif /* ANDROID_LIB_STUB */
#endif /* ANDROID_P2P */
@@ -188,33 +188,3 @@ int android_nl_socket_set_nonblocking(struct nl_handle *handle)
}
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
-{
- /*
- * Android ICS has very minimal genl_ctrl_resolve() implementation, so
- * need to work around that.
- */
- struct nl_cache *cache = NULL;
- struct genl_family *nl80211 = NULL;
- int id = -1;
-
- if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache");
- goto fail;
- }
-
- nl80211 = genl_ctrl_search_by_name(cache, name);
- if (nl80211 == NULL)
- goto fail;
-
- id = genl_family_get_id(nl80211);
-
-fail:
- if (nl80211)
- genl_family_put(nl80211);
- if (cache)
- nl_cache_free(cache);
-
- return id;
-}
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index e0d1d233e2ad..4cf31238aeb7 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -335,6 +335,33 @@ static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
}
+static int ext_feature_isset(const u8 *ext_features, int ext_features_len,
+ enum nl80211_ext_feature_index ftidx)
+{
+ u8 ft_byte;
+
+ if ((int) ftidx / 8 >= ext_features_len)
+ return 0;
+
+ ft_byte = ext_features[ftidx / 8];
+ return (ft_byte & BIT(ftidx % 8)) != 0;
+}
+
+
+static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct wpa_driver_capa *capa = info->capa;
+
+ if (tb == NULL)
+ return;
+
+ if (ext_feature_isset(nla_data(tb), nla_len(tb),
+ NL80211_EXT_FEATURE_VHT_IBSS))
+ capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
+}
+
+
static void wiphy_info_feature_flags(struct wiphy_info_data *info,
struct nlattr *tb)
{
@@ -509,6 +536,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
info->device_ap_sme = 1;
wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]);
wiphy_info_probe_resp_offload(capa,
tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
@@ -547,22 +575,34 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
continue;
}
vinfo = nla_data(nl);
- switch (vinfo->subcmd) {
- case QCA_NL80211_VENDOR_SUBCMD_TEST:
- drv->vendor_cmd_test_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
- drv->roaming_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
- drv->dfs_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
- drv->get_features_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
- drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
- break;
+ if (vinfo->vendor_id == OUI_QCA) {
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_TEST:
+ drv->vendor_cmd_test_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+ drv->dfs_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+ drv->get_features_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST:
+ drv->get_pref_freq_list = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL:
+ drv->set_prob_oper_freq = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ drv->capa.flags |=
+ WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_SETBAND:
+ drv->setband_vendor_cmd_avail = 1;
+ break;
+ }
}
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
@@ -717,6 +757,7 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
struct features_info {
u8 *flags;
size_t flags_len;
+ struct wpa_driver_capa *capa;
};
@@ -742,6 +783,19 @@ static int features_info_handler(struct nl_msg *msg, void *arg)
info->flags = nla_data(attr);
info->flags_len = nla_len(attr);
}
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA];
+ if (attr)
+ info->capa->conc_capab = nla_get_u32(attr);
+
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND];
+ if (attr)
+ info->capa->max_conc_chan_2_4 = nla_get_u32(attr);
+
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND];
+ if (attr)
+ info->capa->max_conc_chan_5_0 = nla_get_u32(attr);
}
return NL_SKIP;
@@ -776,12 +830,16 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
}
os_memset(&info, 0, sizeof(info));
+ info.capa = &drv->capa;
ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
if (ret || !info.flags)
return;
if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
+
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 87e412dc596a..7b0f721e6584 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -271,6 +271,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
struct nlattr *ptk_kek)
{
union wpa_event_data event;
+ const u8 *ssid;
u16 status_code;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
@@ -331,6 +332,16 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
if (req_ie) {
event.assoc_info.req_ies = nla_data(req_ie);
event.assoc_info.req_ies_len = nla_len(req_ie);
+
+ if (cmd == NL80211_CMD_ROAM) {
+ ssid = nl80211_get_ie(event.assoc_info.req_ies,
+ event.assoc_info.req_ies_len,
+ WLAN_EID_SSID);
+ if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
+ drv->ssid_len = ssid[1];
+ os_memcpy(drv->ssid, ssid + 2, ssid[1]);
+ }
+ }
}
if (resp_ie) {
event.assoc_info.resp_ies = nla_data(resp_ie);
@@ -1480,6 +1491,25 @@ static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
}
+static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode)
+{
+ switch (hw_mode) {
+ case QCA_ACS_MODE_IEEE80211B:
+ return HOSTAPD_MODE_IEEE80211B;
+ case QCA_ACS_MODE_IEEE80211G:
+ return HOSTAPD_MODE_IEEE80211G;
+ case QCA_ACS_MODE_IEEE80211A:
+ return HOSTAPD_MODE_IEEE80211A;
+ case QCA_ACS_MODE_IEEE80211AD:
+ return HOSTAPD_MODE_IEEE80211AD;
+ case QCA_ACS_MODE_IEEE80211ANY:
+ return HOSTAPD_MODE_IEEE80211ANY;
+ default:
+ return NUM_HOSTAPD_MODES;
+ }
+}
+
+
static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
const u8 *data, size_t len)
{
@@ -1500,6 +1530,39 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
event.acs_selected_channels.sec_channel =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg0_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg1_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
+ event.acs_selected_channels.ch_width =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
+ u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
+
+ event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode);
+ if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES ||
+ event.acs_selected_channels.hw_mode ==
+ HOSTAPD_MODE_IEEE80211ANY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Invalid hw_mode %d in ACS selection event",
+ hw_mode);
+ return;
+ }
+ }
+
+ wpa_printf(MSG_INFO,
+ "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
+ event.acs_selected_channels.pri_channel,
+ event.acs_selected_channels.sec_channel,
+ event.acs_selected_channels.ch_width,
+ event.acs_selected_channels.vht_seg0_center_ch,
+ event.acs_selected_channels.vht_seg1_center_ch,
+ event.acs_selected_channels.hw_mode);
+
+ /* Ignore ACS channel list check for backwards compatibility */
wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 3911f485f72e..4b762eafbe8a 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -221,6 +221,9 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
drv->scan_for_auth = 0;
+ if (TEST_FAIL())
+ return -1;
+
msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
if (!msg)
return -1;
@@ -433,7 +436,7 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv)
}
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
{
const u8 *end, *pos;
@@ -583,6 +586,11 @@ int bss_info_handler(struct nl_msg *msg, void *arg)
r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
if (bss[NL80211_BSS_TSF])
r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ if (bss[NL80211_BSS_BEACON_TSF]) {
+ u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]);
+ if (tsf > r->tsf)
+ r->tsf = tsf;
+ }
if (bss[NL80211_BSS_SEEN_MS_AGO])
r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
r->ie_len = ie_len;
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index de23fbd2b9fe..1f1676a20ac5 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -220,6 +220,56 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
}
+static int wpa_driver_privsep_authenticate(
+ void *priv, struct wpa_driver_auth_params *params)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ struct privsep_cmd_authenticate *data;
+ int i, res;
+ size_t buflen;
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d bssid=" MACSTR
+ " auth_alg=%d local_state_change=%d p2p=%d",
+ __func__, priv, params->freq, MAC2STR(params->bssid),
+ params->auth_alg, params->local_state_change, params->p2p);
+
+ buflen = sizeof(*data) + params->ie_len + params->sae_data_len;
+ data = os_zalloc(buflen);
+ if (data == NULL)
+ return -1;
+
+ data->freq = params->freq;
+ os_memcpy(data->bssid, params->bssid, ETH_ALEN);
+ os_memcpy(data->ssid, params->ssid, params->ssid_len);
+ data->ssid_len = params->ssid_len;
+ data->auth_alg = params->auth_alg;
+ data->ie_len = params->ie_len;
+ for (i = 0; i < 4; i++) {
+ if (params->wep_key[i])
+ os_memcpy(data->wep_key[i], params->wep_key[i],
+ params->wep_key_len[i]);
+ data->wep_key_len[i] = params->wep_key_len[i];
+ }
+ data->wep_tx_keyidx = params->wep_tx_keyidx;
+ data->local_state_change = params->local_state_change;
+ data->p2p = params->p2p;
+ pos = (u8 *) (data + 1);
+ if (params->ie_len) {
+ os_memcpy(pos, params->ie, params->ie_len);
+ pos += params->ie_len;
+ }
+ if (params->sae_data_len)
+ os_memcpy(pos, params->sae_data, params->sae_data_len);
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_AUTHENTICATE, data, buflen,
+ NULL, NULL);
+ os_free(data);
+
+ return res;
+}
+
+
static int wpa_driver_privsep_associate(
void *priv, struct wpa_driver_associate_params *params)
{
@@ -281,14 +331,15 @@ static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
{
struct wpa_driver_privsep_data *drv = priv;
int res, ssid_len;
- u8 reply[sizeof(int) + 32];
+ u8 reply[sizeof(int) + SSID_MAX_LEN];
size_t len = sizeof(reply);
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
if (res < 0 || len < sizeof(int))
return -1;
os_memcpy(&ssid_len, reply, sizeof(int));
- if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
+ if (ssid_len < 0 || ssid_len > SSID_MAX_LEN ||
+ sizeof(int) + ssid_len > len) {
wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
return -1;
}
@@ -308,6 +359,32 @@ static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
}
+static void wpa_driver_privsep_event_auth(void *ctx, u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+ struct privsep_event_auth *auth;
+
+ os_memset(&data, 0, sizeof(data));
+ if (len < sizeof(*auth))
+ return;
+ auth = (struct privsep_event_auth *) buf;
+ if (len < sizeof(*auth) + auth->ies_len)
+ return;
+
+ os_memcpy(data.auth.peer, auth->peer, ETH_ALEN);
+ os_memcpy(data.auth.bssid, auth->bssid, ETH_ALEN);
+ data.auth.auth_type = auth->auth_type;
+ data.auth.auth_transaction = auth->auth_transaction;
+ data.auth.status_code = auth->status_code;
+ if (auth->ies_len) {
+ data.auth.ies = (u8 *) (auth + 1);
+ data.auth.ies_len = auth->ies_len;
+ }
+
+ wpa_supplicant_event(ctx, EVENT_AUTH, &data);
+}
+
+
static void wpa_driver_privsep_event_assoc(void *ctx,
enum wpa_event_type event,
u8 *buf, size_t len)
@@ -467,6 +544,9 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
case PRIVSEP_EVENT_SCAN_RESULTS:
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
break;
+ case PRIVSEP_EVENT_SCAN_STARTED:
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
+ break;
case PRIVSEP_EVENT_ASSOC:
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
event_buf, event_len);
@@ -502,6 +582,9 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
event_len);
break;
+ case PRIVSEP_EVENT_AUTH:
+ wpa_driver_privsep_event_auth(drv->ctx, event_buf, event_len);
+ break;
}
os_free(buf);
@@ -702,6 +785,10 @@ static int wpa_driver_privsep_get_capa(void *priv,
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
if (res < 0 || len != sizeof(*capa))
return -1;
+ /* For now, no support for passing extended_capa pointers */
+ capa->extended_capa = NULL;
+ capa->extended_capa_mask = NULL;
+ capa->extended_capa_len = 0;
return 0;
}
@@ -734,6 +821,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
.set_param = wpa_driver_privsep_set_param,
.scan2 = wpa_driver_privsep_scan,
.deauthenticate = wpa_driver_privsep_deauthenticate,
+ .authenticate = wpa_driver_privsep_authenticate,
.associate = wpa_driver_privsep_associate,
.get_capa = wpa_driver_privsep_get_capa,
.get_mac_addr = wpa_driver_privsep_get_mac_addr,
@@ -742,7 +830,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
};
-struct wpa_driver_ops *wpa_drivers[] =
+const struct wpa_driver_ops *const wpa_drivers[] =
{
&wpa_driver_privsep_ops,
NULL
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index a1581b8c9cb1..01defdff4f15 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1,6 +1,6 @@
/*
* Driver interaction with generic Linux Wireless Extensions
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,6 +18,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <net/if_arp.h>
+#include <dirent.h>
#include "linux_wext.h"
#include "common.h"
@@ -131,7 +132,7 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.essid.pointer = (caddr_t) ssid;
- iwr.u.essid.length = 32;
+ iwr.u.essid.length = SSID_MAX_LEN;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
@@ -139,8 +140,8 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
ret = -1;
} else {
ret = iwr.u.essid.length;
- if (ret > 32)
- ret = 32;
+ if (ret > SSID_MAX_LEN)
+ ret = SSID_MAX_LEN;
/* Some drivers include nul termination in the SSID, so let's
* remove it here before further processing. WE-21 changes this
* to explicitly require the length _not_ to include nul
@@ -168,7 +169,7 @@ int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
int ret = 0;
char buf[33];
- if (ssid_len > 32)
+ if (ssid_len > SSID_MAX_LEN)
return -1;
os_memset(&iwr, 0, sizeof(iwr));
@@ -874,6 +875,105 @@ static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
}
+static int wext_hostap_ifname(struct wpa_driver_wext_data *drv,
+ const char *ifname)
+{
+ char buf[200], *res;
+ int type;
+ FILE *f;
+
+ if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0)
+ return -1;
+
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
+ drv->ifname, ifname);
+
+ f = fopen(buf, "r");
+ if (!f)
+ return -1;
+ res = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ type = res ? atoi(res) : -1;
+ wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type);
+
+ if (type == ARPHRD_IEEE80211) {
+ wpa_printf(MSG_DEBUG,
+ "WEXT: Found hostap driver wifi# interface (%s)",
+ ifname);
+ wpa_driver_wext_alternative_ifindex(drv, ifname);
+ return 0;
+ }
+ return -1;
+}
+
+
+static int wext_add_hostap(struct wpa_driver_wext_data *drv)
+{
+ char buf[200];
+ int n;
+ struct dirent **names;
+ int ret = -1;
+
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname);
+ n = scandir(buf, &names, NULL, alphasort);
+ if (n < 0)
+ return -1;
+
+ while (n--) {
+ if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0)
+ ret = 0;
+ free(names[n]);
+ }
+ free(names);
+
+ return ret;
+}
+
+
+static void wext_check_hostap(struct wpa_driver_wext_data *drv)
+{
+ char buf[200], *pos;
+ ssize_t res;
+
+ /*
+ * Host AP driver may use both wlan# and wifi# interface in wireless
+ * events. Since some of the versions included WE-18 support, let's add
+ * the alternative ifindex also from driver_wext.c for the time being.
+ * This may be removed at some point once it is believed that old
+ * versions of the driver are not in use anymore. However, it looks like
+ * the wifi# interface is still used in the current kernel tree, so it
+ * may not really be possible to remove this before the Host AP driver
+ * gets removed from the kernel.
+ */
+
+ /* First, try to see if driver information is available from sysfs */
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
+ drv->ifname);
+ res = readlink(buf, buf, sizeof(buf) - 1);
+ if (res > 0) {
+ buf[res] = '\0';
+ pos = strrchr(buf, '/');
+ if (pos)
+ pos++;
+ else
+ pos = buf;
+ wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos);
+ if (os_strncmp(pos, "hostap", 6) == 0 &&
+ wext_add_hostap(drv) == 0)
+ return;
+ }
+
+ /* Second, use the old design with hardcoded ifname */
+ if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
+ char ifname2[IFNAMSIZ + 1];
+ os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
+ os_memcpy(ifname2, "wifi", 4);
+ wpa_driver_wext_alternative_ifindex(drv, ifname2);
+ }
+}
+
+
static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
{
int send_rfkill_event = 0;
@@ -914,20 +1014,7 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
drv->ifindex = if_nametoindex(drv->ifname);
- if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
- /*
- * Host AP driver may use both wlan# and wifi# interface in
- * wireless events. Since some of the versions included WE-18
- * support, let's add the alternative ifindex also from
- * driver_wext.c for the time being. This may be removed at
- * some point once it is believed that old versions of the
- * driver are not in use anymore.
- */
- char ifname2[IFNAMSIZ + 1];
- os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
- os_memcpy(ifname2, "wifi", 4);
- wpa_driver_wext_alternative_ifindex(drv, ifname2);
- }
+ wext_check_hostap(drv);
netlink_send_oper_ifla(drv->netlink, drv->ifindex,
1, IF_OPER_DORMANT);
@@ -1112,7 +1199,7 @@ struct wext_scan_data {
struct wpa_scan_res res;
u8 *ie;
size_t ie_len;
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int maxrate;
};
@@ -1865,7 +1952,7 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
{
struct iwreq iwr;
const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
int i;
/*
@@ -1907,9 +1994,9 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
* SIOCSIWMLME commands (or tries to associate automatically
* after deauth/disassoc).
*/
- for (i = 0; i < 32; i++)
+ for (i = 0; i < SSID_MAX_LEN; i++)
ssid[i] = rand() & 0xFF;
- if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+ if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) {
wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
"SSID to disconnect");
}
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index f0c3bb3c63ba..a98af9ac7d71 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -47,7 +47,7 @@ extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
#endif /* CONFIG_DRIVER_NONE */
-struct wpa_driver_ops *wpa_drivers[] =
+const struct wpa_driver_ops *const wpa_drivers[] =
{
#ifdef CONFIG_DRIVER_NL80211
&wpa_driver_nl80211_ops,
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 943407875701..3dd43c73803e 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -54,7 +54,9 @@ else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
else
- DRV_LIBS += -lnl
+ ifndef CONFIG_OSX
+ DRV_LIBS += -lnl
+ endif
endif
ifdef CONFIG_LIBNL20
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 837971d25c99..e21147af1bcd 100644
--- a/src/drivers/linux_ioctl.c
+++ b/